Merge remote-tracking branch 'origin/send_coupon' into send_coupon
| New file |
| | |
| | | import service from "@/libs/axios"; |
| | | |
| | | |
| | | export const getPageList = (data) =>{ |
| | | return service({ |
| | | url: "/lmk/store-tag/page", |
| | | method: "GET", |
| | | params: data |
| | | }) |
| | | } |
| | | export const getTag = (data) =>{ |
| | | return service({ |
| | | url: "/lmk/store-tag/list", |
| | | method: "GET", |
| | | params: data |
| | | }) |
| | | } |
| | | export const addStoreTag =(data) =>{ |
| | | return service({ |
| | | url: "/lmk/store-tag", |
| | | method: "POST", |
| | | data: data |
| | | }) |
| | | } |
| | | export const bind =(data) =>{ |
| | | return service({ |
| | | url: "/lmk/store-tag/bind", |
| | | method: "POST", |
| | | data: data |
| | | }) |
| | | } |
| | | export const editTag = (data)=>{ |
| | | return service({ |
| | | url: "/lmk/store-tag", |
| | | method: "PUT", |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | export const delTag = (data)=>{ |
| | | return service({ |
| | | url: "/lmk/store-tag/" + data, |
| | | method: "DELETE", |
| | | }) |
| | | } |
| | | export const removeBatch = (data) =>{ |
| | | return service({ |
| | | url: "/lmk/store-tag/batch", |
| | | method: "DELETE", |
| | | data:data |
| | | }) |
| | | } |
| | | |
| | | export const getStoreTagsById =(data) =>{ |
| | | return service({ |
| | | url: "/lmk/store-tag/storeTags/" + data, |
| | | method: "GET", |
| | | }) |
| | | } |
| | | |
| | | export const delTagByStoreTagRefId = (data)=>{ |
| | | return service({ |
| | | url: "/lmk/store-tag/delTagByStoreTagRefId/" + data, |
| | | method: "DELETE", |
| | | }) |
| | | } |
| | |
| | | </span> |
| | | </p> |
| | | <p class="item"> |
| | | <span class="label">店铺标签:</span> |
| | | <span class="info"> |
| | | <template v-if="tagList?.length > 0"> |
| | | <!-- 遍历标签列表 --> |
| | | <span v-for="(tag, index) in tagList" :key="tag.id"> |
| | | {{ tag.tagName }} |
| | | <button |
| | | style="width: 20px; height: 20px; line-height: 1; border: none; background: #f0f0f0; border-radius: 50%; cursor: pointer; margin-left: 4px; font-size: 12px; display: inline-flex; align-items: center; justify-content: center;" |
| | | @click.stop="handleDeleteTag(tag.id, index)" |
| | | title="删除标签" |
| | | > |
| | | × |
| | | </button> |
| | | <template v-if="index !== tagList.length - 1">、</template> |
| | | </span> |
| | | </template> |
| | | <template v-else>暂无标签</template> |
| | | </span> |
| | | </p> |
| | | <div style="display: flex;align-items: center;justify-content: center;"> |
| | | <Button type="primary" @click="addStoreTag(storeInfo)">新增标签</Button> |
| | | </div> |
| | | <p class="item"> |
| | | <span class="label">店铺简介:</span> |
| | | <span class="info"> |
| | | {{storeInfo.storeDesc?storeInfo.storeDesc:'暂未完善'}} |
| | |
| | | </Row> |
| | | </div> |
| | | </TabPane> |
| | | |
| | | <Modal |
| | | v-model="showModal" |
| | | title="新增标签" |
| | | width="800" |
| | | :mask-closable="false" |
| | | > |
| | | <Select v-model="tagForm.storeTagId" placeholder="请选择" @on-query-change="searchChange" filterable |
| | | clearable style="width: 150px"> |
| | | <Option v-for="item in tagOptions" :value="item.id" :key="item.id">{{ item.tagName }}</Option> |
| | | </Select> |
| | | <div slot="footer"> |
| | | <Button @click="showModal = false">取消</Button> |
| | | <Button type="primary" @click="handleSubmit" :loading="submitLoading">确定</Button> |
| | | </div> |
| | | </Modal> |
| | | </Tabs> |
| | | </Card> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | |
| | | import { getTag,bind,getStoreTagsById,delTagByStoreTagRefId } from "@/api/store-tag" |
| | | import ossManage from "@/views/sys/oss-manage/ossManage"; |
| | | import * as RegExp from '@/libs/RegExp.js'; |
| | | import {getCategoryTree} from "@/api/goods"; |
| | |
| | | export default { |
| | | name: "member", |
| | | components: { |
| | | |
| | | ossManage, |
| | | }, |
| | | data() { |
| | | return { |
| | | tagOptions:[], |
| | | submitLoading:false, |
| | | tagForm:{ |
| | | storeId:null, |
| | | storeTagId:"", |
| | | }, |
| | | showModal:false, |
| | | id: "",//店铺id |
| | | categories: [], //店铺静音范围 |
| | | loading: true, // 表单加载状态 |
| | | storeInfo: {},//店铺信息 |
| | | storeInfo: { |
| | | },//店铺信息 |
| | | tagList:[], |
| | | checkAllGroup: [], //选中的经营分类 |
| | | selectDate: null, // 申请时间 |
| | | |
| | |
| | | }; |
| | | }, |
| | | methods: { |
| | | handleDeleteTag(storeTagRefId){ |
| | | console.log(storeTagRefId) |
| | | delTagByStoreTagRefId(storeTagRefId).then(res=>{ |
| | | if (res.code === 200){ |
| | | this.$Message.success("删除成功") |
| | | } |
| | | this.getStoreTags(); |
| | | }) |
| | | |
| | | }, |
| | | |
| | | getStoreTags(){ |
| | | getStoreTagsById(this.id).then(res =>{ |
| | | if (res.code === 200){ |
| | | this.$set(this, "tagList", res.data); |
| | | } |
| | | }) |
| | | |
| | | }, |
| | | |
| | | searchChange(val){ |
| | | this.getStoreTag(val) |
| | | }, |
| | | getStoreTag(val){ |
| | | const params = { |
| | | tagName: '' |
| | | } |
| | | if (val) { |
| | | params.tagName = val; |
| | | } else { |
| | | params.tagName = '' |
| | | } |
| | | getTag(params).then(res =>{ |
| | | if (res.code ===200){ |
| | | this.tagOptions = res.data |
| | | } |
| | | }) |
| | | }, |
| | | handleSubmit(){ |
| | | if (this.tagForm.storeTagId === null || this.tagForm.storeTagId ===""){ |
| | | this.$Message.error("请选择标签") |
| | | return |
| | | } |
| | | this.showModal = false; |
| | | bind(this.tagForm).then(res =>{ |
| | | if (res.code === 200){ |
| | | |
| | | } |
| | | this.getStoreTags(); |
| | | this.getStoreTag(); |
| | | }) |
| | | |
| | | }, |
| | | addStoreTag(info){ |
| | | console.log(info) |
| | | this.tagForm.storeId = info.storeId; |
| | | this.tagForm.storeTagId = ""; |
| | | this.showModal = true; |
| | | }, |
| | | init() { |
| | | this.getStoreTags(); |
| | | |
| | | this.getStoreTag(); |
| | | //查店铺基本信息 |
| | | this.getStoreInfo(); |
| | | //查询店铺分类 |
| New file |
| | |
| | | <template> |
| | | <div> |
| | | <card> |
| | | <Form |
| | | ref="searchForm" |
| | | @keydown.enter.native="handleSearch" |
| | | :model="searchForm" |
| | | inline |
| | | :label-width="70" |
| | | class="search-form" |
| | | > |
| | | <Form-item label="标签名称" prop="tagName"> |
| | | <Input |
| | | type="text" |
| | | v-model="searchForm.tagName" |
| | | clearable |
| | | @on-clear="handleSearch" |
| | | @on-change="handleSearch" |
| | | style="width: 160px" |
| | | /> |
| | | </Form-item> |
| | | <Button |
| | | @click="handleSearch" |
| | | type="primary" |
| | | icon="ios-search" |
| | | class="search-btn" |
| | | >搜索</Button |
| | | > |
| | | </Form> |
| | | <Row class="operation padding-row"> |
| | | <Button @click="openAdd" type="info">添加</Button> |
| | | <Button @click="delBatch" type="error">批量删除</Button> |
| | | </Row> |
| | | <Table |
| | | :loading="loading" |
| | | border |
| | | :columns="columns" |
| | | :data="tagList" |
| | | ref="table" |
| | | sortable="custom" |
| | | @on-sort-change="changeSort" |
| | | @on-selection-change="showSelect" |
| | | > |
| | | <template slot-scope="{ row, index }" slot="action"> |
| | | <Button type="info" size="small" style="margin-right: 5px" @click="openEdit(row)">编辑标签</Button> |
| | | <Button type="error" size="small" style="margin-right: 5px" @click="del(row)">删除标签</Button> |
| | | </template> |
| | | </Table> |
| | | |
| | | <Row type="flex" justify="end" class="mt_10"> |
| | | <Page |
| | | :current="searchForm.pageNumber" |
| | | :total="total" |
| | | :page-size="searchForm.pageSize" |
| | | @on-change="changePage" |
| | | @on-page-size-change="changePageSize" |
| | | :page-size-opts="[10, 20, 50]" |
| | | size="small" |
| | | show-total |
| | | show-elevator |
| | | show-sizer |
| | | ></Page> |
| | | </Row> |
| | | |
| | | <Modal |
| | | v-model="modelShow" |
| | | :title="modelTitle" |
| | | > |
| | | <Form ref="form" :model="form" :label-width="70" :rules="rules"> |
| | | <FormItem label="标签名称" prop="tagName"> |
| | | <Input v-model="form.tagName" autocomplete="off"/> |
| | | </FormItem> |
| | | </Form> |
| | | <div slot="footer"> |
| | | <Button type="text" @click="modelClose">取消</Button> |
| | | <Button type="primary" :loading="submitLoading" @click="saveOrUpdate">提交</Button> |
| | | </div> |
| | | </Modal> |
| | | </card> |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import { getPageList,addStoreTag,editTag,delTag,removeBatch } from "@/api/store-tag" |
| | | export default { |
| | | name: "store-tag", |
| | | data(){ |
| | | return{ |
| | | loading:false, |
| | | columns:[ |
| | | { |
| | | type: 'selection', |
| | | width: 60, |
| | | align: 'center' |
| | | }, |
| | | { |
| | | title:'标签名称', |
| | | key: 'tagName', |
| | | minWidth: 60, |
| | | tooltip: true, |
| | | }, |
| | | { |
| | | title: '操作', |
| | | key: 'action', |
| | | slot: 'action', |
| | | minWidth: 150, |
| | | align: 'center' |
| | | } |
| | | ], |
| | | total:0, |
| | | tagList:[], |
| | | searchForm: { |
| | | // 搜索框初始化对象 |
| | | pageNumber: 1, // 当前页数 |
| | | pageSize: 10, // 页面大小 |
| | | tagName: '', // 标签名称 |
| | | }, |
| | | // 对话框标题 |
| | | modelTitle:'', |
| | | modelShow:false, |
| | | submitLoading:false, |
| | | // 表单 |
| | | form: { |
| | | id: '', |
| | | tagName: '', |
| | | }, |
| | | rules: { |
| | | tagName: [ |
| | | {required: true, message: "标签名称不能为空", trigger: "blur"} |
| | | ], |
| | | }, |
| | | //多选 |
| | | selectCount: 0, // 已选数量 |
| | | selectList: [], // 已选数据列表 |
| | | } |
| | | |
| | | }, |
| | | mounted(){ |
| | | this.init(); |
| | | }, |
| | | methods:{ |
| | | init(){ |
| | | this.getTagList() |
| | | }, |
| | | openAdd(){ |
| | | this.modelTitle = "新增标签"; |
| | | this.modelShow = true; |
| | | this.form={ |
| | | id: '', |
| | | tagName: '', |
| | | } |
| | | }, |
| | | openEdit(row){ |
| | | this.form.id = row.id; |
| | | this.form.tagName = row.tagName; |
| | | this.modelTitle= "修改标签"; |
| | | this.modelShow = true; |
| | | }, |
| | | saveOrUpdate() { |
| | | this.$refs.form.validate(valid => { |
| | | if (valid) { |
| | | this.submitLoading = true |
| | | if (this.form.id) { |
| | | // 修改 |
| | | editTag(this.form).then(res => { |
| | | if (res.code === 200) { |
| | | this.$Message.success("修改成功"); |
| | | this.modelClose() |
| | | this.getTagList() |
| | | } |
| | | }) |
| | | } else { |
| | | // 新增 |
| | | addStoreTag(this.form).then(res => { |
| | | if (res.code === 200) { |
| | | this.$Message.success("添加成功"); |
| | | this.modelClose() |
| | | this.getTagList() |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | del(row){ |
| | | delTag(row.id).then(res =>{ |
| | | if (res.code === 200){ |
| | | this.$Message.success("删除成功") |
| | | } |
| | | this.getTagList(); |
| | | }) |
| | | }, |
| | | delBatch() { |
| | | if (this.selectCount <= 0) { |
| | | this.$Message.warning("您还未选择要删除的数据"); |
| | | return; |
| | | } |
| | | |
| | | // 显示确认对话框 |
| | | this.$Modal.confirm({ |
| | | title: '确认删除', |
| | | content: `您确定要删除选中的 ${this.selectCount} 条数据吗?`, |
| | | onOk: () => { |
| | | // 用户点击确认后执行删除 |
| | | this.removeBatch(); |
| | | }, |
| | | onCancel: () => { |
| | | this.$Message.info('已取消删除'); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | async removeBatch() { |
| | | try { |
| | | const res = await removeBatch(this.selectList); |
| | | if (res.code === 200) { |
| | | this.getTagList(); |
| | | this.selectedRows = []; |
| | | this.selectCount = 0; |
| | | this.$Message.success('删除成功'); |
| | | } else { |
| | | this.$Message.error(res.message || '删除失败'); |
| | | } |
| | | } catch (err) { |
| | | console.log(err); |
| | | this.$Message.error('请求失败,请重试'); |
| | | } |
| | | }, |
| | | // 关闭弹窗 |
| | | modelClose() { |
| | | this.submitLoading = false |
| | | this.modelShow = false |
| | | }, |
| | | getTagList(){ |
| | | this.loading = true; |
| | | getPageList(this.searchForm).then((res) => { |
| | | this.loading = false; |
| | | if (res.code === 200) { |
| | | this.tagList = res.data; |
| | | this.total = res.total; |
| | | } |
| | | }); |
| | | this.loading = false; |
| | | }, |
| | | handleSearch(){ |
| | | this.searchForm.pageNumber = 1; |
| | | this.searchForm.pageSize = 10; |
| | | this.getTagList(); |
| | | }, |
| | | // 分页 改变页码 |
| | | changePage(v) { |
| | | this.searchForm.pageNumber = v; |
| | | this.getTagList(); |
| | | }, |
| | | // 分页 改变页数 |
| | | changePageSize(v) { |
| | | this.searchForm.pageNumber = 1; |
| | | this.searchForm.pageSize = v; |
| | | this.getTagList(); |
| | | }, |
| | | changeSort(){ |
| | | |
| | | }, |
| | | showSelect(e){ |
| | | this.selectList = e.map(d => d.id); |
| | | this.selectCount = e.length; |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | |
| | | </style> |
| New file |
| | |
| | | import service from "../libs/axios"; |
| | | |
| | | export const getPage = (params) =>{ |
| | | return service({ |
| | | url: "/lmk/goodsCustomizeTemplate", |
| | | method: "GET", |
| | | params: params |
| | | }) |
| | | } |
| | | |
| | | export const edit = (params) =>{ |
| | | return service({ |
| | | url: "/lmk/goodsCustomizeTemplate", |
| | | method: "PUT", |
| | | data: params |
| | | }) |
| | | } |
| | | |
| | | export const add = (params) =>{ |
| | | return service({ |
| | | url: "/lmk/goodsCustomizeTemplate", |
| | | method: "POST", |
| | | data: params |
| | | }) |
| | | } |
| | | |
| | | |
| | | export const del = (params) =>{ |
| | | return service({ |
| | | url: "/lmk/goodsCustomizeTemplate/" +params, |
| | | method: "DELETE", |
| | | }) |
| | | } |
| | | |
| | | export const changeStatus = (params) =>{ |
| | | return service({ |
| | | url: "/lmk/goodsCustomizeTemplate/changeStatus/" +params, |
| | | method: "PUT", |
| | | }) |
| | | } |
| | | |
| | | export const detail = (params) =>{ |
| | | return service({ |
| | | url: "/lmk/goodsCustomizeTemplate/" +params, |
| | | method: "GET", |
| | | }) |
| | | } |
| | |
| | | <Option value="GENERATE">生成</Option> |
| | | </Select> |
| | | </FormItem> |
| | | <FormItem label="启用状态:"> |
| | | <Select |
| | | v-model="listQuery.status" |
| | | placeholder="全部状态" |
| | | clearable |
| | | style="width: 180px" |
| | | > |
| | | <Option value="ENABLE">启用</Option> |
| | | <Option value="DISABLE">禁用</Option> |
| | | </Select> |
| | | </FormItem> |
| | | </Form> |
| | | </div> |
| | | </Card> |
| New file |
| | |
| | | <template> |
| | | <div class="coupon-management"> |
| | | <!-- 搜索区域 --> |
| | | <Card class="filter-container"> |
| | | <div class="filter-header"> |
| | | <Icon type="ios-search" size="18" /> |
| | | <span class="filter-title">筛选搜索</span> |
| | | <div class="filter-actions"> |
| | | <Button type="primary" @click="getList" size="small">查询搜索</Button> |
| | | <Button @click="handleResetSearch" size="small" style="margin-left: 10px;">重置</Button> |
| | | <Button type="primary" @click="addModal" size="small" style="margin-left: 10px;">新增</Button> |
| | | </div> |
| | | </div> |
| | | <div class="filter-content"> |
| | | <Form |
| | | :model="listQuery" |
| | | :label-width="90" |
| | | class="search-form" |
| | | inline |
| | | > |
| | | <FormItem label="模板名称"> |
| | | <Input |
| | | v-model="listQuery.templateName" |
| | | style="width: 180px;" |
| | | clearable |
| | | placeholder="请输入模板名称" |
| | | > |
| | | </Input> |
| | | </FormItem> |
| | | <FormItem label="启用状态:"> |
| | | <Select |
| | | v-model="listQuery.status" |
| | | placeholder="全部状态" |
| | | clearable |
| | | style="width: 180px" |
| | | > |
| | | <Option value="DISABLE">未启用</Option> |
| | | <Option value="ENABLE">已起用</Option> |
| | | </Select> |
| | | </FormItem> |
| | | |
| | | |
| | | </Form> |
| | | </div> |
| | | </Card> |
| | | |
| | | <!-- 表格区域 --> |
| | | <Card class="table-container"> |
| | | <Table |
| | | :loading="listLoading" |
| | | border |
| | | :columns="tableColumns" |
| | | :data="list" |
| | | ref="table" |
| | | class="coupon-table" |
| | | > |
| | | <template slot-scope="{ row }" slot="action"> |
| | | <Button |
| | | type="primary" |
| | | size="small" |
| | | style="margin-right: 5px" |
| | | @click="delTemplate(row)" |
| | | >删除</Button |
| | | > |
| | | <Button |
| | | type="primary" |
| | | size="small" |
| | | style="margin-right: 5px" |
| | | @click="updateTemplate(row)" |
| | | >修改</Button |
| | | > |
| | | <Button |
| | | type="primary" |
| | | size="small" |
| | | style="margin-right: 5px" |
| | | @click="changeStatus(row)" |
| | | >{{ row.status ==='ENABLE' ? '禁用':'开启'}}</Button |
| | | > |
| | | </template> |
| | | </Table> |
| | | </Card> |
| | | |
| | | <!-- 分页区域 --> |
| | | <div class="pagination-container"> |
| | | <Page |
| | | :current="listQuery.pageNumber" |
| | | :page-size="listQuery.pageSize" |
| | | :total="total" |
| | | :page-size-opts="[10, 20, 30, 50]" |
| | | show-elevator |
| | | show-sizer |
| | | show-total |
| | | @on-change="handleCurrentChange" |
| | | @on-page-size-change="handleSizeChange" |
| | | /> |
| | | </div> |
| | | |
| | | <Modal |
| | | v-model="showModal" |
| | | :title="modalTitle" |
| | | width="800" |
| | | :mask-closable="false" |
| | | > |
| | | <Form |
| | | ref="form" |
| | | :model="form" |
| | | :label-width="90" |
| | | class="search-form" |
| | | :rules="formRules" |
| | | inline> |
| | | <Row> |
| | | <Col :span="24"> |
| | | <FormItem label="模板名称" prop="templateName"> |
| | | <Input v-model="form.templateName" autocomplete="off"/> |
| | | </FormItem> |
| | | </Col> |
| | | <Col :span="24"> |
| | | <FormItem label="选择新增标题"> |
| | | <Button type="primary" @click="addTitle('TEXT')">添加文字标题</Button> |
| | | <Button type="primary" style="margin-left: 10px" @click="addTitle('IMAGE')">添加图片标题</Button> |
| | | </FormItem> |
| | | </Col> |
| | | |
| | | <Col :span="24"> |
| | | |
| | | <!-- 已添加的标题列表 --> |
| | | <div v-for="(title, index) in form.titles" :key="index" class="title-item"> |
| | | <card class="title-text"> |
| | | <Input v-model="title.templateTitle" placeholder="请输入文本标题" style="width: 300px; margin-top: 8px;"/> |
| | | <Button class="delete-btn" type="text" @click="removeTitle(index)" style="color: #ff4d4f;">删除</Button> |
| | | </card> |
| | | <!-- <card v-if="title.contentType === 'IMAGE'" class="title-image">--> |
| | | <!-- <Upload--> |
| | | <!-- v-if="!title.imgTempUrl"--> |
| | | <!-- :before-upload="(file) => handleBeforeUpload(file,title)"--> |
| | | <!-- :format="['jpg','jpeg','png','gif']"--> |
| | | <!-- :max-size="20480"--> |
| | | <!-- action=""--> |
| | | <!-- accept="image/*"--> |
| | | <!-- >--> |
| | | <!-- <Button icon="ios-cloud-upload-outline">上传封面图片</Button>--> |
| | | <!-- </Upload>--> |
| | | <!-- <div v-else class="upload-file-info">--> |
| | | |
| | | <!-- <Col :span="24">--> |
| | | <!-- <img :src="title.imgTempUrl" alt="活动图片" class="preview-image-limit">--> |
| | | <!-- </Col>--> |
| | | <!-- <Button type="text" @click="handleRemoveImage(title)">删除</Button>--> |
| | | <!-- </div>--> |
| | | |
| | | <!-- <Button class="delete-btn" type="text" @click="removeTitle(index)" style="color: #ff4d4f;">删除</Button>--> |
| | | <!-- </card>--> |
| | | </div> |
| | | </Col> |
| | | <Col :span="24"> |
| | | <FormItem label="模板图片" > |
| | | <div style="display: flex; flex-wrap: wrap;"> |
| | | <vuedraggable :animation="200" :list="showListImages"> |
| | | <div v-for="(item, __index) in showListImages" :key="__index" |
| | | class="demo-upload-list"> |
| | | <template> |
| | | <img :src="item"/> |
| | | <div class="demo-upload-list-cover"> |
| | | <div> |
| | | <Icon size="30" type="md-search" @click.native="handleViewGoodsPicture(item)"></Icon> |
| | | <Icon size="30" type="md-trash" @click.native="handleRemoveGoodsPicture(item)"></Icon> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </div> |
| | | </vuedraggable> |
| | | </div> |
| | | <div style="width: 100%;display: flex;justify-content: start;margin-top: 10px;"> |
| | | <Button @click="handleCLickImg('goodsGalleryFiles')" type="primary">上传图片</Button> |
| | | </div> |
| | | <Modal v-model="goodsPictureVisible" title="View Image"> |
| | | <img v-if="goodsPictureVisible" :src="previewGoodsPicture" style="width: 100%"/> |
| | | </Modal> |
| | | </FormItem> |
| | | </Col> |
| | | |
| | | </Row> |
| | | |
| | | |
| | | </Form> |
| | | <div slot="footer"> |
| | | <Button type="text" @click="showModal = false">关闭</Button> |
| | | <Button type="primary" :loading="submitLoading" @click="saveOrUpdate">确认</Button> |
| | | </div> |
| | | </Modal> |
| | | |
| | | <Modal v-model="picModelFlag" width="1200px"> |
| | | <div class="demo-upload-list" v-for="(item,index) in showListImages"> |
| | | <template> |
| | | <img :src="item"> |
| | | <div class="demo-upload-list-cover"> |
| | | <Icon type="ios-eye-outline" @click.native="handleView(item)"></Icon> |
| | | <Icon type="ios-trash-outline" @click.native="handleRemove(null,index)"></Icon> |
| | | </div> |
| | | </template> |
| | | </div> |
| | | <div class="demo-upload-list"> |
| | | <Upload |
| | | :before-upload="upLoadImg" |
| | | accept="image/*" |
| | | action="-" |
| | | type="drag" |
| | | style=" display: inline-block;width: 58px" |
| | | > |
| | | <div style="width: 58px;height:58px;line-height: 58px;"> |
| | | <Icon type="ios-camera" size="20"></Icon> |
| | | </div> |
| | | </Upload> |
| | | </div> |
| | | </Modal> |
| | | <Modal v-model="visible" title="预览图片"> |
| | | <img v-if="visible" :src="previewPicture" style="width: 100%"> |
| | | </Modal> |
| | | |
| | | </div> |
| | | </template> |
| | | <script> |
| | | |
| | | import { getPage,edit,add,del,changeStatus,detail } from "@/api/goods-customeize-template.js" |
| | | import vuedraggable from "vuedraggable"; |
| | | import COS from "cos-js-sdk-v5"; |
| | | import {getFileKey} from "@/utils/file.js"; |
| | | import {getFilePreview, getSts} from "@/api/file"; |
| | | |
| | | export default { |
| | | name: 'GoodsCustomizeTemplate', |
| | | components: {vuedraggable}, |
| | | data() { |
| | | return { |
| | | // 预览图片路径 |
| | | previewPicture: "", |
| | | visible:false, |
| | | picModelFlag: false, // 图片选择器 |
| | | goodsPictureVisible: false, |
| | | showListImages: [], |
| | | listImages: [], |
| | | previewGoodsPicture: "", |
| | | selectedFormBtnName: "", // 点击图片绑定form |
| | | |
| | | //新增 |
| | | modalTitle:"", |
| | | showModal:false, |
| | | |
| | | list: [], |
| | | total: 0, |
| | | listLoading: false, |
| | | submitLoading: false, |
| | | |
| | | listQuery: { |
| | | pageNumber: 1, |
| | | pageSize: 10, |
| | | templateName:"", |
| | | status:"", |
| | | }, |
| | | form:{ |
| | | titles: [] |
| | | }, |
| | | // 表单验证规则 |
| | | formRules: { |
| | | templateName:[ |
| | | {required:true,message:"模板名不能为空",trigger:"blur"} |
| | | ] |
| | | }, |
| | | |
| | | // 表头配置 |
| | | tableColumns: [ |
| | | { |
| | | type: 'selection', |
| | | width: 60, |
| | | align: 'center' |
| | | }, |
| | | { |
| | | title: '模板名称', |
| | | key: 'templateName', |
| | | align: 'center', |
| | | ellipsis: true, |
| | | tooltip: true |
| | | }, |
| | | { |
| | | title: '启用状态', |
| | | key: 'status', |
| | | width: 120, |
| | | align: 'center', |
| | | render: (h, params) => { |
| | | const status = params.row.status; |
| | | const color = status === 'ENABLE' ? 'success' : status === 'DISABLE' ? 'default' : 'warning'; |
| | | const text = status === 'ENABLE' ? '启用' : status === 'DISABLE' ? '未启用' : '未知'; |
| | | |
| | | return h('Tag', { |
| | | props: { |
| | | color: color |
| | | } |
| | | }, text); |
| | | } |
| | | }, |
| | | { |
| | | title: '操作', |
| | | slot: 'action', |
| | | width: 200, |
| | | align: 'center' |
| | | }, |
| | | ] |
| | | } |
| | | }, |
| | | methods: { |
| | | changeStatus(row){ |
| | | changeStatus(row.id).then(res =>{ |
| | | if (res.code ===200 ){ |
| | | this.$Message.success(res.msg) |
| | | } |
| | | this.getList() |
| | | }) |
| | | |
| | | }, |
| | | async updateTemplate(row){ |
| | | this.showModal = true; |
| | | this.modalTitle = "修改模板"; |
| | | |
| | | await detail(row.id).then(res =>{ |
| | | if (res.code === 200){ |
| | | this.form = { |
| | | id: res.data.id, |
| | | templateName: res.data.templateName || '', // 确保不为undefined |
| | | titles: res.data.titles || [] // 标题列表 |
| | | }; |
| | | this.form.titles.map((i) =>{ |
| | | i.id = null; |
| | | return i |
| | | }) |
| | | this.listImages = res.data.listImages.map((i) => { |
| | | return i.imgUrl |
| | | }); |
| | | |
| | | } |
| | | }) |
| | | const stsInfo = await getSts(); |
| | | const endpoint = stsInfo.data.endpoint; |
| | | console.log() |
| | | this.showListImages = this.listImages.map((i) => { |
| | | if (i!=null&&i.indexOf('http')===-1) |
| | | return endpoint+'/'+i; |
| | | else return i; |
| | | }) |
| | | |
| | | }, |
| | | delTemplate(row){ |
| | | del(row.id).then(res =>{ |
| | | if (res.code === 200){ |
| | | this.$Message.success(res.msg) |
| | | } |
| | | this.getList() |
| | | }) |
| | | }, |
| | | async upLoadImg(file) { |
| | | console.log("打印上传1") |
| | | if (this.listImages.length >= 10) { |
| | | this.$Message.error("图片上传不能超过10个"); |
| | | return; |
| | | } |
| | | console.log("打印上传2") |
| | | try { |
| | | // 获取文件上传临时密钥 |
| | | const sts = await getSts(); |
| | | const cos = new COS({ |
| | | getAuthorization: async function (options, callback) { |
| | | callback({ |
| | | TmpSecretId: sts.data.tmpSecretId, |
| | | TmpSecretKey: sts.data.tmpSecretKey, |
| | | SecurityToken: sts.data.sessionToken, |
| | | // 建议返回服务器时间作为签名的开始时间,避免客户端本地时间偏差过大导致签名错误 |
| | | StartTime: sts.data.stsStartTime, // 时间戳,单位秒,如:1580000000 |
| | | ExpiredTime: sts.data.stsEndTime,// 时间戳,单位秒,如:1580000000 |
| | | ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用 |
| | | }); |
| | | } |
| | | }) |
| | | const fileKey = getFileKey(file.name) |
| | | const upData = await cos.uploadFile({ |
| | | Bucket: sts.data.bucket, |
| | | Region: sts.data.region, |
| | | Key: fileKey, |
| | | Body: file, // 要上传的文件对象。 |
| | | SliceSize: 1024 * 1024 * 5, |
| | | onProgress: function (progressData) { |
| | | console.log('上传进度:', progressData); |
| | | }, |
| | | }); |
| | | console.log("上传成功", upData) |
| | | this.$nextTick(() => { |
| | | this.listImages.push(fileKey); |
| | | this.showListImages.push(sts.data.endpoint + "/" + fileKey); |
| | | |
| | | }) |
| | | |
| | | } catch (e) { |
| | | console.log("上传失败", upData) |
| | | return false; |
| | | } finally { |
| | | |
| | | } |
| | | return false; |
| | | }, |
| | | handleView(url) { |
| | | this.previewPicture = url; |
| | | this.visible = true; |
| | | }, |
| | | handleRemove(item, index) { |
| | | if (!item) { |
| | | this.listImages.splice(index, 1); |
| | | this.showListImages.splice(index, 1); |
| | | |
| | | } else { |
| | | console.log('移除测试',item, index); |
| | | item.splice(index, 1) |
| | | } |
| | | this.previewPicture = ""; |
| | | }, |
| | | |
| | | handleCLickImg(val, index) { |
| | | this.picModelFlag = true; |
| | | this.selectedFormBtnName = val; |
| | | }, |
| | | handleViewGoodsPicture(url) { |
| | | this.previewGoodsPicture = url; |
| | | this.goodsPictureVisible = true; |
| | | }, |
| | | // 移除商品图片 |
| | | handleRemoveGoodsPicture(file) { |
| | | // this.baseInfoForm.goodsGalleryFiles = |
| | | // this.baseInfoForm.goodsGalleryFiles.filter((i) => i !== file); |
| | | }, |
| | | |
| | | addTitle(type){ |
| | | this.form.titles.push( |
| | | { |
| | | contentType: type, |
| | | templateTitle: '', |
| | | imgTempUrl:null,//图片临时地址 |
| | | file:null, |
| | | }); |
| | | }, |
| | | // 移除标题 |
| | | removeTitle(index) { |
| | | this.form.titles.splice(index, 1); |
| | | }, |
| | | |
| | | saveOrUpdate() { |
| | | const submitData = { |
| | | ...this.form, |
| | | listImages: this.listImages, |
| | | }; |
| | | |
| | | console.log(submitData) |
| | | |
| | | const isTitlesValid = (titles) => { |
| | | console.log("进入判断") |
| | | // 数组本身为null/undefined或空数组 |
| | | if (!titles || titles.length === 0) return false; |
| | | // 检查每个元素的有效性 |
| | | return titles.every(title => { |
| | | // 基础校验:必须是对象且包含contentType |
| | | if (!title || typeof title !== 'object' || !title.contentType) return false; |
| | | |
| | | return title.templateTitle !== null |
| | | && title.templateTitle !== undefined |
| | | && title.templateTitle.trim() !== ''; |
| | | // 未知类型 |
| | | return false; |
| | | }); |
| | | }; |
| | | |
| | | const isImagesValid = (images) => { |
| | | if (!images || images.length === 0) return false; |
| | | return images.some(img => img && (typeof img === 'string' ? img.trim() !== '' : true)); |
| | | }; |
| | | |
| | | this.$refs.form.validate(async (valid) => { |
| | | if (valid) { |
| | | try { |
| | | // 先处理所有图片上传(等待异步完成) |
| | | this.submitLoading = true; |
| | | |
| | | // 上传完成后再验证 |
| | | if (!isTitlesValid(submitData.titles)) { |
| | | this.$Message.error('请确保所有标题都填写完整(文本标题不能为空,图片标题需上传成功)'); |
| | | this.submitLoading = false; |
| | | return; |
| | | } |
| | | |
| | | if (!isImagesValid(submitData.listImages)) { |
| | | this.$Message.error('请添加有效的图片(至少一张图片)'); |
| | | this.submitLoading = false; |
| | | return; |
| | | } |
| | | |
| | | // 验证通过,提交数据 |
| | | const api = this.form.id ? edit : add; |
| | | const res = await api(submitData); |
| | | |
| | | if (res.code === 200) { |
| | | this.$Message.success(res.msg); |
| | | this.modelShow = false; |
| | | this.getList(); |
| | | } else { |
| | | this.$Message.error(res.msg); |
| | | } |
| | | } catch (error) { |
| | | this.$Message.error('提交失败,请重试'); |
| | | console.error(error); |
| | | } finally { |
| | | this.submitLoading = false; |
| | | this.showModal = false; |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | addModal(){ |
| | | this.form = { |
| | | titles: [] |
| | | }; |
| | | this.showModal = true; |
| | | this.modalTitle = "新增模板"; |
| | | this.showListImages =[]; |
| | | this.listImages =[]; |
| | | }, |
| | | detail(row){ |
| | | console.log(row) |
| | | }, |
| | | |
| | | // 获取列表数据 |
| | | getList() { |
| | | this.listLoading = true; |
| | | // 模拟API调用 |
| | | getPage(this.listQuery).then(res =>{ |
| | | this.listLoading = false; |
| | | this.list = res.data; |
| | | this.total = res.total; |
| | | }) |
| | | }, |
| | | |
| | | // 重置搜索条件 |
| | | handleResetSearch() { |
| | | this.listQuery = { |
| | | pageNumber: 1, |
| | | pageSize: 10, |
| | | storeName: "", |
| | | couponName: "", |
| | | generateStatus: "", |
| | | status: "" |
| | | }; |
| | | this.getList(); |
| | | }, |
| | | |
| | | // 分页大小改变 |
| | | handleSizeChange(size) { |
| | | this.listQuery.pageSize = size; |
| | | this.listQuery.pageNumber = 1; |
| | | this.getList(); |
| | | }, |
| | | |
| | | // 当前页码改变 |
| | | handleCurrentChange(pageNumber) { |
| | | this.listQuery.pageNumber = pageNumber; |
| | | this.getList(); |
| | | }, |
| | | |
| | | // 提交表单 |
| | | handleSubmit() { |
| | | this.$refs.dataForm.validate((valid) => { |
| | | if (valid) { |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.getList(); |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .preview-image-limit{ |
| | | max-width: 100%; |
| | | max-height: 200px; |
| | | object-fit: contain; |
| | | border-radius: 4px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | display: block; |
| | | } |
| | | .delete-btn { |
| | | position: absolute; /* 绝对定位 */ |
| | | top: 12px; /* 距离顶部的距离 */ |
| | | right: 12px; /* 距离右侧的距离 */ |
| | | padding: 4px 8px; /* 调整按钮大小 */ |
| | | line-height: 1; /* 调整行高 */ |
| | | } |
| | | .title-item { |
| | | margin-bottom: 12px; |
| | | padding-bottom: 12px; |
| | | border-bottom: 1px dashed #e9e9e9; |
| | | } |
| | | |
| | | .title-type-selector { |
| | | display: flex; |
| | | justify-content: center; |
| | | padding: 20px 0; |
| | | } |
| | | |
| | | .type-option { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | margin: 0 20px; |
| | | cursor: pointer; |
| | | padding: 15px; |
| | | border-radius: 4px; |
| | | transition: all 0.3s; |
| | | |
| | | &:hover { |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | span { |
| | | margin-top: 10px; |
| | | } |
| | | } |
| | | .coupon-management { |
| | | padding: 16px; |
| | | background: #f5f7f9; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .filter-container { |
| | | margin-bottom: 16px; |
| | | |
| | | .filter-header { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 16px; |
| | | |
| | | .filter-title { |
| | | margin-left: 8px; |
| | | font-weight: 600; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .filter-actions { |
| | | margin-left: auto; |
| | | } |
| | | } |
| | | |
| | | .filter-content { |
| | | .search-form { |
| | | /deep/ .ivu-form-item { |
| | | margin-bottom: 16px; |
| | | margin-right: 16px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .operation-container { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 16px; |
| | | padding: 12px 16px; |
| | | background: #fff; |
| | | border-radius: 4px; |
| | | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); |
| | | |
| | | .operation-info { |
| | | color: #999; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | |
| | | .table-container { |
| | | margin-bottom: 16px; |
| | | |
| | | .coupon-table { |
| | | /deep/ .ivu-table-cell { |
| | | padding: 8px 12px; |
| | | } |
| | | |
| | | .action-btns { |
| | | display: flex; |
| | | justify-content: center; |
| | | |
| | | button { |
| | | margin: 0 2px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | background: #fff; |
| | | padding: 12px 16px; |
| | | border-radius: 4px; |
| | | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | // 响应式调整 |
| | | @media (max-width: 768px) { |
| | | .coupon-management { |
| | | padding: 8px; |
| | | } |
| | | |
| | | .filter-content .search-form { |
| | | /deep/ .ivu-form-item { |
| | | width: 100%; |
| | | margin-right: 0; |
| | | |
| | | .ivu-form-item-content { |
| | | width: 100%; |
| | | |
| | | .ivu-input, .ivu-select { |
| | | width: 100% !important; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .operation-container { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | |
| | | .add-btn { |
| | | margin-bottom: 8px; |
| | | } |
| | | } |
| | | |
| | | .action-btns { |
| | | flex-direction: column; |
| | | |
| | | button { |
| | | margin: 2px 0 !important; |
| | | width: 100%; |
| | | } |
| | | } |
| | | } |
| | | .demo-upload-list { |
| | | display: inline-block; |
| | | width: 60px; |
| | | height: 60px; |
| | | text-align: center; |
| | | line-height: 60px; |
| | | border: 1px solid transparent; |
| | | border-radius: 4px; |
| | | overflow: hidden; |
| | | background: #fff; |
| | | position: relative; |
| | | box-shadow: 0 1px 1px rgba(0, 0, 0, .2); |
| | | margin-right: 4px; |
| | | } |
| | | |
| | | .demo-upload-list img { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .demo-upload-list-cover { |
| | | display: none; |
| | | position: absolute; |
| | | top: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | background: rgba(0, 0, 0, .6); |
| | | } |
| | | |
| | | .demo-upload-list:hover .demo-upload-list-cover { |
| | | display: block; |
| | | } |
| | | |
| | | .demo-upload-list-cover i { |
| | | color: #fff; |
| | | font-size: 20px; |
| | | cursor: pointer; |
| | | margin: 0 2px; |
| | | } |
| | | </style> |