From 6496b3f36d38f3196c4e41d0b9c329de646a2415 Mon Sep 17 00:00:00 2001 From: peng <peng.com> Date: 星期六, 27 九月 2025 17:38:04 +0800 Subject: [PATCH] 店铺优惠卷功能使用 --- manager/src/views/promotions/coupon/coupon_store.vue | 882 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 882 insertions(+), 0 deletions(-) diff --git a/manager/src/views/promotions/coupon/coupon_store.vue b/manager/src/views/promotions/coupon/coupon_store.vue new file mode 100644 index 0000000..8350cb8 --- /dev/null +++ b/manager/src/views/promotions/coupon/coupon_store.vue @@ -0,0 +1,882 @@ +<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> + </div> + </div> + <div class="filter-content"> + <Form + :model="listQuery" + :label-width="90" + class="search-form" + inline + > + <FormItem label="搴楅摵"> + <Select + v-model="listQuery.storeId" + placeholder="璇烽�夋嫨" + clearable + style="width: 160px" + filterable + > + <Option + v-for="store in storeSelectList" + :key="store.id" + :label="store.label" + :value="store.id" + > + {{ store.label }} + </Option> + </Select> + </FormItem> + <FormItem label="鐢熸垚鐘舵��:"> + <Select + v-model="listQuery.generateStatus" + placeholder="鍏ㄩ儴鐘舵��" + clearable + style="width: 180px" + > + <Option value="NOT_GENERATE">娌℃湁鐢熸垚</Option> + <Option value="GENERATE">鐢熸垚</Option> + </Select> + </FormItem> + <FormItem label="鍚敤鐘舵��:"> + <Select + v-model="listQuery.status" + placeholder="鍏ㄩ儴鐘舵��" + clearable + style="width: 180px" + > + <Option value="ENABLE">鍚敤</Option> + <Option value="DISABLED">绂佺敤</Option> + </Select> + </FormItem> + </Form> + </div> + </Card> + + <!-- 鎿嶄綔鎸夐挳鍖哄煙 --> + <div class="operation-container"> + <Button + @click="handleAdd" + type="primary" + icon="md-add" + class="add-btn" + >娣诲姞浼樻儬鍒�</Button> + </div> + + <!-- 琛ㄦ牸鍖哄煙 --> + <Card class="table-container"> + <Table + :loading="listLoading" + border + :columns="tableColumns" + :data="list" + ref="table" + class="coupon-table" + > + <!-- 鐢熸垚鐘舵�佸垪 --> + <template slot-scope="{ row }" slot="generateStatus"> + <Tag :color="getStatusColor(row.generateStatus)"> + {{ formatGenerateStatus(row.generateStatus) }} + </Tag> + </template> + + <!-- 鍚敤鐘舵�佸垪 --> + <template slot-scope="{ row }" slot="status"> + <i-switch + v-model="row.status" + true-value="ENABLE" + false-value="DISABLED" + @on-change="(status) => handleStatusChange(row, status)" + > + <span slot="open">鍚敤</span> + <span slot="close">绂佺敤</span> + </i-switch> + </template> + + <template slot-scope="{ row }" slot="action"> + <Button + @click="generalCoupon(row)" + type="primary" + class="add-btn" + v-if="row.generateStatus ==='NOT_GENERATE'" + >鐢熸垚浼樻儬鍗�</Button> + <Button + @click="detail(row)" + style="margin-left: 10px;" + type="primary" + class="add-btn" + :disabled="row.generateStatus === 'NOT_GENERATE'" + >鏌ョ湅</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="showGeneralQrCode" + title="浜岀淮鐮�" + width="800" + :mask-closable="false" + :loading="codeLoading" + > + <vue-qr + :text="QRCodeUrl" + :margin="0" + colorDark="#000" + colorLight="#fff" + :size="150" + ></vue-qr> + <div slot="footer"> + <Button type="text" @click="closeGeneralQrCode">鍏抽棴</Button> + <!-- <Button type="primary" @click="generalQrCode">纭</Button>--> + </div> + </Modal> + + <Modal + v-model="showCouponStore" + width="1200" + :mask-closable="false" + @on-cancel="handleCancelCouponStore" + > + <Table + :loading="couponStoreLoading" + border + :columns="couponStoreColumns" + :data="couponStoreData" + ref="table" + > + <template slot-scope="{ row }" slot="action"> + <Button + @click="generalQrCode(row)" + type="primary" + class="add-btn" + v-if="row.claimStatus === 'NOT_CLAIM'" + >鏌ョ湅浜岀淮鐮�</Button> + </template> + </Table> + <Row type="flex" justify="center" class="mt_10"> + <Page + :current="storeCouponSingleQuery.pageNumber" + :total="couponStoreTotal" + :page-size="storeCouponSingleQuery.pageSize" + @on-change="couponStoreChangePage" + @on-page-size-change="couponStoreChangePageSize" + :page-size-opts="[10, 20, 50]" + size="small" + show-total + show-elevator + show-sizer + ></Page> + </Row> + </Modal> + <!-- 娣诲姞/缂栬緫寮圭獥 --> + <Modal + v-model="dialogVisible" + :title="dialogTitle" + width="1200" + :mask-closable="false" + @on-cancel="handleCancel" + > + <Form + ref="dataForm" + :model="temp" + :label-width="100" + :rules="formRules" + > + <Form-item label="搴楅摵" prop="storeId"> + <Select + v-model="temp.storeId" + placeholder="璇烽�夋嫨" + clearable + style="width: 160px" + filterable + @on-change="handleStoreChange" + > + <Option + v-for="store in storeSelectList" + :key="store.id" + :label="store.label" + :value="store.id" + > + {{ store.label }} + </Option> + </Select> + </Form-item> + <FormItem label="宸查�変紭鎯犲姷" prop="couponId" style="margin-bottom: 20px"> + <Input :disabled="true" style="width: 30%;margin-bottom: 20px" v-model="showCoupon" placeholder="璇风偣鍑婚�夋嫨琛ㄦ牸鍐呬紭鎯犲姷"></Input> + + </FormItem> + <Table + :loading="couponLoading" + border + :columns="couponColumns" + :data="couponData" + ref="table" + @on-current-change="handleRowClick" + highlight-row + ></Table> + <Row type="flex" justify="center" class="mt_10"> + <Page + :current="couponSearchForm.pageNumber" + :total="couponTotal" + :page-size="couponSearchForm.pageSize" + @on-change="couponChangePage" + @on-page-size-change="couponChangePageSize" + :page-size-opts="[10, 20, 50]" + size="small" + show-total + show-elevator + show-sizer + ></Page> + </Row> + <FormItem label="鐢熸垚鏁伴噺" prop="couponNum"> + <InputNumber + v-model="temp.couponNum" + :min="1" + :max="99999" + placeholder="璇疯緭鍏ョ敓鎴愭暟閲�" + style="width: 100%" + ></InputNumber> + </FormItem> + + </Form> + <div slot="footer"> + <Button @click="dialogVisible = false">鍙栨秷</Button> + <Button type="primary" @click="handleSubmit" :loading="submitLoading">纭畾</Button> + </div> + </Modal> + </div> +</template> + +<script> +import vueQr from "vue-qr"; +import {addStoreCoupon, getPage, getPageByStoreCoupon,changeStatus} from "../../../api/coupon-store"; +import * as API_Order from "@/api/order"; +import {promotionsScopeTypeRender, promotionsStatusRender} from "../../../utils/promotions"; +import {getPlatformCouponList,generateStoreCoupon} from "../../../api/promotion"; +export default { + components:{ + "vue-qr": vueQr, + }, + name: 'CouponManagement', + data() { + return { + QRCodeUrl:"", + showGeneralQrCode:false, + codeLoading:false, + + codeUrl: this.QRcodeBaseUrl+ '/scanpage/couponStore', + + showCouponStore:false, + couponStoreTotal:0, + couponStoreData:[], + couponStoreLoading:false, + couponStoreColumns: [ + { + title: "浼樻儬鍒稿悕绉�", + key: "couponName", + width: 200, + align: "center", + tooltip: true + }, + { + title: "浼樻儬鍒哥紪鍙�", + key: "couponNo", + width: 200, + align: "center", + tooltip: true + }, + { + title: "棰嗗彇鐘舵��", + key: "claimStatus", + width: 200, + align: "center", + tooltip: true, + render: (h, params) => { + const status = params.row.claimStatus; + const color = status === 'CLAIM' ? 'success' : status === 'NOT_CLAIM' ? 'default' : 'warning'; + const text = status === 'CLAIM' ? '宸查鍙�' : status === 'NOT_CLAIM' ? '鏈鍙�' : '鏈煡'; + + return h('Tag', { + props: { + color: color + } + }, text); + } + }, + { + title: "鎿嶄綔", + slot: "action", + align: "center", + width: 200, + fixed: "right" + } + ], + + + couponSearchForm: { + // 鎼滅储妗嗗垵濮嬪寲瀵硅薄 + pageNumber: 1, // 褰撳墠椤垫暟 + pageSize: 10, // 椤甸潰澶у皬 + sort: "create_time", // 榛樿鎺掑簭瀛楁 + order: "desc", // 榛樿鎺掑簭鏂瑰紡 + getType: "", // 榛樿鎺掑簭鏂瑰紡 + promotionStatus:"START", + }, + storeSelectList:[], + showCoupon:'', + selectedRowId:'', + couponTotal:0, + couponData:[], + couponLoading:false, + couponColumns: [ + // 琛ㄥご + { + title: "浼樻儬鍒稿悕绉�", + key: "couponName", + width: 180, + tooltip: true, + }, + { + title: "闈㈤/鎶樻墸", + key: "price", + width: 150, + render: (h, params) => { + if (params.row.price) { + return h("priceColorScheme", {props:{value:params.row.price,color:this.$mainColor}} ); + + } else { + return h("div", params.row.couponDiscount + "鎶�"); + } + }, + }, + + { + title: "鑾峰彇鏂瑰紡", + width: 120, + key: "getType", + render: (h, params) => { + if (params.row.getType === "FREE") { + return h("Tag", { props: { color: "red" } }, "鍏嶈垂鑾峰彇"); + } else if (params.row.getType === "ACTIVITY") { + return h("Tag", { props: { color: "volcano" } }, "娲诲姩鑾峰彇"); + } else if (params.row.getType === "INSIDE") { + return h("Tag", { props: { color: "lime" } }, "鍐呰喘"); + } else if (params.row.getType === "IGAME") { + return h("Tag", { props: { color: "lime" } }, "娓告垙浜虹敓"); + } else { + return h("Tag", { props: { color: "purple" } }, "鏈煡"); + } + }, + }, + { + title: "浼樻儬鍒哥被鍨�", + key: "couponType", + width: 150, + render: (h, params) => { + let text = ""; + if (params.row.couponType === "DISCOUNT") { + return h("Tag", { props: { color: "blue" } }, "鎵撴姌"); + } else if (params.row.couponType === "PRICE") { + return h("Tag", { props: { color: "geekblue" } }, "鍑忓厤鐜伴噾"); + } else { + return h("Tag", { props: { color: "purple" } }, "鏈煡"); + } + }, + }, + { + title: "鍝佺被鎻忚堪", + key: "scopeType", + width: 120, + render: (h, params) => { + return promotionsScopeTypeRender(h, params); + }, + }, + { + title: "娲诲姩鏃堕棿", + render: (h, params) => { + if ( + params?.row?.getType === "ACTIVITY" && + params?.row?.rangeDayType === "DYNAMICTIME" + ) { + return h("div", "闀挎湡鏈夋晥"); + } else if (params?.row?.startTime && params?.row?.endTime) { + return h("div", { + domProps: { + innerHTML: + params.row.startTime + "<br/>" + params.row.endTime, + }, + }); + } + }, + }, + { + title: "鐘舵��", + width: 100, + key: "promotionStatus", + align: "center", + fixed: "right", + render: (h, params) => { + return promotionsStatusRender(h, params); + }, + }, + ], + + list: [], + total: 0, + listLoading: false, + submitLoading: false, + storeCouponSingleQuery:{ + pageNumber: 1, + pageSize: 10, + refId:"" + }, + + listQuery: { + pageNumber: 1, + pageSize: 10, + storeId: "", + generateStatus: "", + status: "" + }, + temp: { + storeId: '', + storeName: '', + couponId: '', + couponNum: 1, + couponName: '', + }, + dialogVisible: false, + dialogStatus: '', + dialogTitle: '', + + // 琛ㄥ崟楠岃瘉瑙勫垯 + formRules: { + storeId: [ + { required: true, message: '搴楅摵ID涓嶈兘涓虹┖', trigger: 'blur' } + ], + storeName: [ + { required: true, message: '搴楅摵鍚嶇О涓嶈兘涓虹┖', trigger: 'blur' } + ], + couponId: [ + { required: true, message: '浼樻儬鍒窱D涓嶈兘涓虹┖', trigger: 'blur' } + ], + couponName: [ + { required: true, message: '浼樻儬鍒稿悕绉颁笉鑳戒负绌�', trigger: 'blur' } + ], + couponNum: [ + { required: true, type: 'number', message: '鐢熸垚鏁伴噺涓嶈兘涓虹┖', trigger: 'blur' } + ], + }, + + // 琛ㄥご閰嶇疆 + tableColumns: [ + { + type: 'selection', + width: 60, + align: 'center' + }, + { + title: '搴楅摵鍚嶇О', + key: 'storeName', + align: 'center', + ellipsis: true, + tooltip: true + }, + { + title: '浼樻儬鍒稿悕绉�', + key: 'couponName', + align: 'center', + ellipsis: true, + tooltip: true + }, + { + title: '鐢熸垚鏁伴噺', + key: 'couponNum', + width: 100, + align: 'center' + }, + { + title: '宸查鍙栨暟閲�', + key: 'couponClaimNum', + width: 120, + align: 'center' + }, + { + title: '鐢熸垚鐘舵��', + slot: 'generateStatus', + width: 120, + align: 'center' + }, + { + title: '鍚敤鐘舵��', + slot: 'status', + width: 120, + align: 'center' + }, + { + title: '鎿嶄綔', + slot: 'action', + width: 200, + align: 'center' + }, + ] + } + }, + methods: { + closeGeneralQrCode(){ + this.showGeneralQrCode = false; + this.QRCodeUrl = ''; + }, + generalQrCode(row){ + this.QRCodeUrl = ''; + this.showGeneralQrCode = true + this.codeLoading = true; + + this.QRCodeUrl = this.codeUrl + "?id="+ row.id; + + }, + detail(row){ + console.log(row) + this.showCouponStore = true; + this.storeCouponSingleQuery.refId = row.id + this.storeCouponSingleQuery.pageSize = 10 + this.storeCouponSingleQuery.pageNumber = 1 + this.getCouponStoreDataList(); + }, + generalCoupon(row){ + generateStoreCoupon(row.id).then(response => { + this.getList(); + }) + }, + handleStoreChange(storeId) { + if (storeId) { + const selectedStore = this.storeSelectList.find(store => store.id === storeId); + if (selectedStore) { + this.temp.storeName = selectedStore.label; + } + } else { + this.temp.storeName = ''; + } + console.log('褰撳墠閫夋嫨:', this.temp.storeId, this.temp.storeName); + }, + couponChangePage(v) { + // 鏀瑰彉椤电爜 + this.couponSearchForm.pageNumber = v; + this.getCouponDataList(); + }, + couponChangePageSize(v) { + // 鏀瑰彉椤垫暟 + this.couponSearchForm.pageNumber = 1; + this.couponSearchForm.pageSize = v; + this.getCouponDataList(); + }, + + couponStoreChangePage(v) { + // 鏀瑰彉椤电爜 + this.storeCouponSingleQuery.pageNumber = v; + this.getCouponStoreDataList(); + }, + couponStoreChangePageSize(v) { + // 鏀瑰彉椤垫暟 + this.storeCouponSingleQuery.pageNumber = 1; + this.storeCouponSingleQuery.pageSize = v; + this.getCouponStoreDataList(); + }, + handleRowClick(currentRow ,oldCurrentRow){ + this.temp.couponId = currentRow.id; + this.temp.couponName = currentRow.couponName; + this.showCoupon = currentRow.couponName; + + console.log(this.temp.couponId) + }, + + getCouponStoreDataList(){ + this.couponStoreLoading = true; + getPageByStoreCoupon(this.storeCouponSingleQuery).then((res) =>{ + this.couponStoreLoading =false; + if (res.code === 200){ + this.couponStoreData = res.data; + this.couponStoreTotal = res.total; + } + }) + + }, + getCouponDataList() { + // 鑾峰彇鏁版嵁 + this.couponLoading = true; + getPlatformCouponList(this.couponSearchForm).then((res) => { + this.couponLoading = false; + if (res.success) { + this.couponData = res.result.records; + this.couponTotal = res.result.total; + } + }); + this.couponTotal = this.couponData.length; + this.couponLoading = false; + }, + + getStoreSelect(){ + API_Order.getStoreSelect().then(res =>{ + if (res.result){ + this.storeSelectList = res.result; + } + }) + }, + // 鑾峰彇鍒楄〃鏁版嵁 + 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(); + }, + + // 娣诲姞浼樻儬鍒� + handleAdd() { + this.dialogStatus = 'create'; + this.dialogTitle = '娣诲姞浼樻儬鍒�'; + this.dialogVisible = true; + this.showCoupon=""; + this.temp = { + storeId: '', + storeName: '', + couponId: '', + couponNum: 1, + couponName: '', + }; + this.getCouponDataList(); + + this.$nextTick(() => { + this.$refs.dataForm.resetFields(); + }); + }, + + // 鐘舵�佹敼鍙� + handleStatusChange(row, status) { + const action = status === 'ENABLE' ? '鍚敤' : '绂佺敤'; + changeStatus(row.id).then(response => { + this.getList(); + this.$Message.success(`宸�${action}浼樻儬鍒�"${row.couponName}"`); + }) + // 杩欓噷鍙互娣诲姞API璋冪敤 + }, + + // 鏍煎紡鍖栫敓鎴愮姸鎬� + formatGenerateStatus(status) { + const statusMap = { + 'NOT_GENERATE': '娌℃湁鐢熸垚', + 'GENERATE': '鐢熸垚', + }; + return statusMap[status] || '鏈煡鐘舵��'; + }, + + // 鑾峰彇鐘舵�侀鑹� + getStatusColor(status) { + const colorMap = { + 'GENERATE': 'success', + 'NOT_GENERATE': 'warning' + }; + return colorMap[status] || 'default'; + }, + handleCancelCouponStore(){ + this.showCouponStore = false; + }, + // 寮圭獥鍙栨秷 + handleCancel() { + this.dialogVisible = false; + }, + + // 鎻愪氦琛ㄥ崟 + handleSubmit() { + this.$refs.dataForm.validate((valid) => { + if (valid) { + let form = {...this.temp}; + addStoreCoupon(form).then(res=>{ + if (res.code === 200 ){ + this.$Message.success(res.msg) + } + this.dialogVisible = false; + this.getList(); + }) + + } + }); + } + }, + mounted() { + this.getStoreSelect(); + this.getList(); + } +} +</script> + +<style scoped lang="less"> +.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%; + } + } +} +</style> -- Gitblit v1.8.0