This commit is contained in:
gyq 2025-09-17 09:19:33 +08:00
commit 350a314feb
17 changed files with 2487 additions and 318 deletions

View File

@ -2,20 +2,42 @@
基于 Vue3 + Vite5+ TypeScript5 + Element-Plus + Pinia 等主流技术栈构建 基于 Vue3 + Vite5+ TypeScript5 + Element-Plus + Pinia 等主流技术栈构建
## ysk-utils 工具类包
安装
```
pnpm install ysk-utils
```
更新
```
pnpm update ysk-utils
```
vscode如果无代码提示
重启 VS Code 的 TypeScript 服务器
输入
```TypeScript: Restart TS Server```
## 正式宝塔 ## 正式宝塔
<https://121.40.128.145:38279/mianban/> [正式宝塔](https://121.40.128.145:38279/mianban/)
chaozg
chaozg123 账号 ***chaozg***
密码 ***chaozg123***
## 本地测试服务器192.168.1.31linux部署 ## 本地测试服务器192.168.1.31linux部署
映射地址 映射地址
<https://fv901fw8033.vicp.fun/> <https://fv901fw8033.vicp.fun/>
上传.zip文件解压到服务器的 /home/web下
cd到/home/web下 1. 上传.zip文件解压到服务器的 /home/web下
执行命令 2. cd到/home/web下
unzip -o dist.zip 3. 执行命令
```unzip -o dist.zip```
数据库 数据库
url: jdbc:mysql://192.168.1.31:3306/czg_cashier?useUnicode=true&characterEncoding=utf-8 url: jdbc:mysql://192.168.1.31:3306/czg_cashier?useUnicode=true&characterEncoding=utf-8

View File

@ -66,7 +66,8 @@
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",
"vue-i18n": "^11.1.0", "vue-i18n": "^11.1.0",
"vue-router": "^4.5.0" "vue-router": "^4.5.0",
"ysk-utils": "^1.0.12"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^19.7.1", "@commitlint/cli": "^19.7.1",

View File

@ -0,0 +1,21 @@
import request from "@/utils/request";
import { Market_BaseUrl } from "@/api/config";
const baseURL = Market_BaseUrl + "/admin/consumeDiscount";
const API = {
getConfig(params: any) {
return request<any>({
url: `${baseURL}`,
method: "get",
params
});
},
editConfig(data: any) {
return request<any>({
url: `${baseURL}`,
method: "post",
data
});
},
}
export default API;

View File

@ -9,6 +9,14 @@ const API = {
params params
}); });
}, },
//优惠券列表/已领取详情
getDetail(params: any) {
return request<any>({
url: `${baseURL}/record`,
method: "get",
params
});
},
} }
export default API; export default API;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -4,7 +4,9 @@ import orderApi from "@/api/order/order";
import { useUserStoreHook } from "@/store/modules/user"; import { useUserStoreHook } from "@/store/modules/user";
import { customTruncateToTwoDecimals } from '@/utils/tools' import { customTruncateToTwoDecimals } from '@/utils/tools'
import productApi from "@/api/product/index"; import productApi from "@/api/product/index";
import yskUtils from 'ysk-utils'
const { OrderPriceCalculator } = yskUtils
console.log(OrderPriceCalculator)
const shopUser = useUserStoreHook(); const shopUser = useUserStoreHook();
export interface CartsState { export interface CartsState {
id: string | number; id: string | number;
@ -22,11 +24,6 @@ export const useCartsStore = defineStore("carts", () => {
let dinnerType = ref<string>('dine-in'); let dinnerType = ref<string>('dine-in');
//就餐模式 先付 后付
const isPayBefore = computed(() => {
return shopUser.userInfo.registerType == 'before' ? true : false;
});
//是否启用会员价 //是否启用会员价
const useVipPrice = computed(() => { const useVipPrice = computed(() => {
@ -42,22 +39,21 @@ export const useCartsStore = defineStore("carts", () => {
//当前购物车数据 //当前购物车数据
const list = useStorage<any[]>("carts", []); const list = useStorage<any[]>("carts", []);
//历史订单数据 //历史订单数据
// const oldOrder = useStorage<any>("Instead_olold_order", { const oldOrder = useStorage<any>("Instead_olold_order", {
// detailMap: [],
// originAmount: 0
// });
const oldOrder = ref({
detailMap: [], detailMap: [],
originAmount: 0 originAmount: 0
}) });
//代客下单页面商品缓存 //代客下单页面商品缓存
const goods = useStorage<any[]>("Instead_goods", []); const goods = useStorage<any[]>("Instead_goods", []);
async function getGoods(query: any) { async function getGoods(query: any) {
const res = await productApi.list({ const res = await productApi.getPage({
page: 1,
size: 999,
status: "on_sale",
...query, ...query,
}); });
goods.value = res.filter((v: { type: string }) => v.type != 'coupon'); goods.value = res.records;
setGoodsMap(goods.value) setGoodsMap(goods.value)
} }
@ -135,11 +131,9 @@ export const useCartsStore = defineStore("carts", () => {
}) })
//返回打包数量称重商品打包数量最大为1 //返回打包数量称重商品打包数量最大为1
function returnCartPackNumber(cur: any) { function returnCartPackNumber(cur: any) {
const maxReturnNum = cur.number - (cur.returnNum || 0); console.log(cur)
let pack_number = (dinnerType.value == 'take-out' ? cur.number : cur.pack_number * 1); let pack_number = (dinnerType.value == 'take-out' ? cur.number : cur.pack_number * 1)
pack_number = (cur.product_type == 'weight' && pack_number > 1) ? 1 : pack_number; pack_number = (cur.product_type == 'weight' && pack_number > 1) ? 1 : pack_number;
pack_number = Math.min(maxReturnNum, pack_number);
pack_number = pack_number <= 0 ? 0 : pack_number
return pack_number * 1 return pack_number * 1
} }
//打包数量 //打包数量
@ -247,7 +241,7 @@ export const useCartsStore = defineStore("carts", () => {
const price = (cur.discount_sale_amount * 1 || cur.salePrice || 0) const price = (cur.discount_sale_amount * 1 || cur.salePrice || 0)
return acc + cur.number * (discount_sale_amount || (useVipPrice.value ? memberPrice : price)) return acc + cur.number * (discount_sale_amount || (useVipPrice.value ? memberPrice : price))
}, 0) }, 0)
return (money + packFee.value * 1 + oldOrderMoney.value * 1).toFixed(2) return (money + packFee.value + oldOrderMoney.value * 1).toFixed(2)
}) })
//只算商品的总价 //只算商品的总价
const goodsTotal = computed(() => { const goodsTotal = computed(() => {
@ -264,7 +258,7 @@ export const useCartsStore = defineStore("carts", () => {
const cartNumber = list.value.reduce((acc: number, cur: any) => { const cartNumber = list.value.reduce((acc: number, cur: any) => {
return acc + cur.number * 1 return acc + cur.number * 1
}, 0) }, 0)
const giftNumber = giftList.value.reduce((acc: number, cur: any) => { const giftNumber = list.value.reduce((acc: number, cur: any) => {
return acc + cur.number * 1 return acc + cur.number * 1
}, 0) }, 0)
let oldNumber = 0 let oldNumber = 0
@ -284,11 +278,11 @@ export const useCartsStore = defineStore("carts", () => {
return; return;
} }
const newNumber = item.number * 1 + step * 1; const newNumber = item.number * 1 + step * 1;
let pack_number = newNumber < item.pack_number ? (item.pack_number * 1 + step * 1) : item.pack_number * 1; let pack_number = newNumber < item.pack_number ? (item.pack_number * 1 + step * 1) : item.pack_number;
if (dinnerType.value == 'take-out') { if (dinnerType.value == 'take-out') {
pack_number = newNumber pack_number = newNumber
} }
if (item.product_type == 'weight' && item.pack_number * 1 >= 1) { if (item.product_type == 'weight') {
pack_number = 1 pack_number = 1
} }
update({ ...item, number: newNumber, pack_number }); update({ ...item, number: newNumber, pack_number });
@ -308,8 +302,11 @@ export const useCartsStore = defineStore("carts", () => {
}) })
return return
} }
selPlaceNum.value = -1; if (cart.is_gift) {
isOldOrder.value = false; isSelGift.value = true
} else {
isSelGift.value = false
}
if (cart.is_gift) { if (cart.is_gift) {
isSelGift.value = true isSelGift.value = true
@ -320,7 +317,6 @@ export const useCartsStore = defineStore("carts", () => {
isSelGift.value = false isSelGift.value = false
selListIndex.value = list.value.findIndex((item: CartsState) => item.id === cart.id); selListIndex.value = list.value.findIndex((item: CartsState) => item.id === cart.id);
} }
} }
@ -336,8 +332,7 @@ export const useCartsStore = defineStore("carts", () => {
product_name: "", product_name: "",
remark: "", remark: "",
sku_id: '', sku_id: '',
product_type: '', product_type: ''
suitNum: 1
} }
//当前购物车直接添加 //当前购物车直接添加
function cartsPush(data: any) { function cartsPush(data: any) {
@ -377,10 +372,6 @@ export const useCartsStore = defineStore("carts", () => {
cart_id cart_id
}); });
} }
//清空历史订单
function clearHistory() {
sendMessage('clearOrder', {});
}
function del(data: any) { function del(data: any) {
@ -394,7 +385,7 @@ export const useCartsStore = defineStore("carts", () => {
return sendMessage('del', data); return sendMessage('del', data);
} }
const pack_number = dinnerType.value == 'take-out' ? data.number : data.pack_number const pack_number = dinnerType.value == 'take-out' ? data.number : data.pack_number
sendMessage('edit', { ...data, suitNum, pack_number }); sendMessage('edit', { ...data, pack_number });
} }
function updateTag(key: string, val: any, cart: CartsState = selCart.value) { function updateTag(key: string, val: any, cart: CartsState = selCart.value) {
const skuData = cart.skuData || { suitNum: 1 } const skuData = cart.skuData || { suitNum: 1 }
@ -408,7 +399,6 @@ export const useCartsStore = defineStore("carts", () => {
const msg = { ...cart, [key]: val } const msg = { ...cart, [key]: val }
if (key == 'number' && dinnerType.value == 'take-out') { if (key == 'number' && dinnerType.value == 'take-out') {
msg.pack_number == val msg.pack_number == val
msg.suitNum == skuData.suitNum
} }
sendMessage('edit', msg); sendMessage('edit', msg);
@ -462,15 +452,8 @@ export const useCartsStore = defineStore("carts", () => {
//获取历史订单 //获取历史订单
async function getOldOrder(table_code: string | number) { async function getOldOrder(table_code: string | number) {
const res = await orderApi.getHistoryList({ tableCode: table_code }) const res = await orderApi.getHistoryList({ tableCode: table_code })
console.log('getOldOrder');
console.log(res);
if (res) { if (res) {
setOldOrder(res) setOldOrder(res)
} else {
oldOrder.value = {
detailMap: [],
originAmount: 0
}
} }
} }
@ -512,22 +495,12 @@ export const useCartsStore = defineStore("carts", () => {
for (let i in data) { for (let i in data) {
newData[i] = data[i].map((v: any) => { newData[i] = data[i].map((v: any) => {
const skuData = getProductDetails({ product_id: v.productId, sku_id: v.skuId }) const skuData = getProductDetails({ product_id: v.productId, sku_id: v.skuId })
console.log(skuData)
console.log(v)
return { return {
...v, ...v,
...skuData, ...skuData,
skuData: {
...skuData,
salePrice: v.price,
memberPrice: v.memberPrice
},
placeNum: v.placeNum, placeNum: v.placeNum,
number: v.num, number: v.num,
id: v.id, id: v.id,
salePrice: v.price,
memberPrice: v.memberPrice,
pack_number: v.packNumber, pack_number: v.packNumber,
discount_sale_amount: v.discountSaleAmount * 1 || 0, discount_sale_amount: v.discountSaleAmount * 1 || 0,
is_print: v.isPrint, is_print: v.isPrint,
@ -538,12 +511,10 @@ export const useCartsStore = defineStore("carts", () => {
product_name: v.productName, product_name: v.productName,
sku_name: v.skuName, sku_name: v.skuName,
sku_id: v.skuId, sku_id: v.skuId,
product_type: v.productType, product_type: v.productType
packFee: v.packAmount,
} }
}) })
} }
console.log('newData', newData)
return newData return newData
} }
@ -573,7 +544,7 @@ export const useCartsStore = defineStore("carts", () => {
if ($oldOrder) { if ($oldOrder) {
setOldOrder($oldOrder) setOldOrder($oldOrder)
} else { } else {
oldOrder.value = { detailMap: [], originAmount: 0 } oldOrder.value = { detailMap: [] }
} }
// console.log('oldOrder.detailMap', oldOrder.value.detailMap) // console.log('oldOrder.detailMap', oldOrder.value.detailMap)
@ -593,19 +564,9 @@ export const useCartsStore = defineStore("carts", () => {
console.log("初始化参数", initParams); console.log("初始化参数", initParams);
WebSocketManager.subscribeToTopic(initParams, (msg) => { WebSocketManager.subscribeToTopic(initParams, (msg) => {
console.log("收到消息:", msg); console.log("收到消息:", msg);
console.log([...list.value, ...giftList.value])
if (msg.hasOwnProperty('status') && msg.status != 1) { if (msg.hasOwnProperty('status') && msg.status != 1) {
if (msg.type === 'no_suit_num' && selListIndex.value != -1) { return ElMessage.error(msg.message || '操作失败')
return ElMessageBox.confirm(`${list.value[selListIndex.value].name}库存不足`, '提示', {
confirmButtonText: '确定',
callback: (action: string) => {
if (action == 'confirm') {
list.value.splice(selListIndex.value, 1)
}
}
});
}
return ElMessage.error(msg.message || msg.msg || '操作失败')
} }
if (msg && msg.data) { if (msg && msg.data) {
if (Array.isArray(msg.data) && msg.data.length && msg.data[0].table_code) { if (Array.isArray(msg.data) && msg.data.length && msg.data[0].table_code) {
@ -636,7 +597,7 @@ export const useCartsStore = defineStore("carts", () => {
v[key] = skuData[key]; v[key] = skuData[key];
}); });
} else { } else {
// del({ id: v.id }) del({ id: v.id })
return false return false
} }
return !v.is_gift return !v.is_gift
@ -666,13 +627,10 @@ export const useCartsStore = defineStore("carts", () => {
return ElMessage.warning(msg.message || '该商品已存在') return ElMessage.warning(msg.message || '该商品已存在')
} }
const skuData = getProductDetails({ product_id: msg.data.product_id, sku_id: msg.data.sku_id }) const skuData = getProductDetails({ product_id: msg.data.product_id, sku_id: msg.data.sku_id })
if (skuData || msg.data.is_temporary) { const newGoods = { ...skuData, ...msg.data }
const newGoods = { ...skuData, ...msg.data } console.log('newGoods', newGoods)
console.log('newGoods', newGoods) list.value.push(newGoods)
list.value.push(newGoods) return ElMessage.success(msg.message || '添加成功')
return ElMessage.success(msg.message || '添加成功')
}
} }
if (msg.operate_type === "manage_edit") { if (msg.operate_type === "manage_edit") {
@ -723,9 +681,6 @@ export const useCartsStore = defineStore("carts", () => {
if (msg.operate_type === "batch") { if (msg.operate_type === "batch") {
concocatSocket({ ...$initParams, table_code: table_code.value }) concocatSocket({ ...$initParams, table_code: table_code.value })
} }
if (msg.operate_type === "manage_clearOrder") {
getOldOrder(msg.data.table_code)
}
if (msg.operate_type === "product_update") { if (msg.operate_type === "product_update") {
console.log('商品更新') console.log('商品更新')
init($initParams, oldOrder.value) init($initParams, oldOrder.value)
@ -747,7 +702,6 @@ export const useCartsStore = defineStore("carts", () => {
WebSocketManager.sendMessage(msg); WebSocketManager.sendMessage(msg);
} }
return { return {
clearHistory,
disconnect, disconnect,
dinnerType, dinnerType,
changePack, changePack,
@ -781,7 +735,7 @@ export const useCartsStore = defineStore("carts", () => {
changeTable, changeTable,
rotTable, rotTable,
getGoods, getGoods,
setGoodsMap, isPayBefore setGoodsMap
}; };
}); });

1357
src/utils/goods.ts Normal file

File diff suppressed because it is too large Load Diff

210
src/utils/test.ts Normal file
View File

@ -0,0 +1,210 @@
import { OrderPriceCalculator, GoodsType, BackendCoupon, ActivityConfig, CouponType } from "./goods";
// 修正后的测试数据严格匹配BaseCartItem类型
const testGoodsList = [
{
// 核心修正1product_type使用GoodsType枚举替代原product_type字符串
product_type: GoodsType.NORMAL, // "sku"类型归类为普通商品
// 核心修正2isTemporary/isGift从数字转为布尔值
isTemporary: false,
isGift: false,
// 核心修正3discountSaleAmount从字符串转为数字
discountSaleAmount: 0,
// 原有字段(保持不变)
salePrice: 2,
memberPrice: 2,
coverImg: "https://czg-oss.oss-cn-hangzhou.aliyuncs.com/catering/store/9660.png",
name: "多规格起售3",
specInfo: "常温",
packFee: 1,
type: "sku",
skuData: {
barCode: "88888888888888888888",
costPrice: 2,
coverImg: "",
createTime: "2025-03-27 16:23:49",
id: "2451",
isDel: 0,
isGrounding: 1,
isPauseSale: 0,
isSale: 1,
isSoldStock: 0,
lowPrice: 2,
memberPrice: 2,
name: "常温",
originPrice: 2,
productId: "946",
realSalesNumber: 0,
salePrice: 2,
shopId: "29",
specInfo: "常温",
suitNum: 3,
updateTime: "2025-03-27 16:23:49",
weight: 0,
},
id: 18264,
shop_id: 29,
table_code: "APC36217948",
sku_id: 2451,
product_id: 946,
product_name: "",
sku_name: "",
number: 4,
pack_number: 0,
discount_sale_note: "",
is_print: 1,
is_wait_call: 0,
pro_group_info: "",
remark: "",
create_time: "2025-09-16 16:00:25",
update_time: null,
},
{
// 核心修正1package类型映射为GoodsType.PACKAGE
product_type: GoodsType.PACKAGE,
// 核心修正2布尔值转换
isTemporary: false,
isGift: false,
// 核心修正3字符串转数字
discountSaleAmount: 5,
// 原有字段
salePrice: 11,
memberPrice: 22,
coverImg: "https://czg-oss.oss-cn-hangzhou.aliyuncs.com/catering/store/8351.png",
name: "蜜雪冰城",
specInfo: "",
packFee: 555,
type: "package",
skuData: {
barCode: "291739694712255",
costPrice: 0,
coverImg: "",
createTime: "2025-02-16 16:36:46",
id: "2383",
isDel: 0,
isGrounding: 1,
isPauseSale: 0,
isSale: 1,
isSoldStock: 0,
lowPrice: 11,
memberPrice: 22,
name: "",
originPrice: 11,
productId: "943",
realSalesNumber: 0,
salePrice: 11,
shopId: "29",
specInfo: "",
suitNum: 33,
updateTime: null,
weight: 0,
},
id: 18263,
shop_id: 29,
table_code: "APC36217948",
sku_id: 2383,
product_id: 943,
product_name: "",
sku_name: "",
number: 35,
pack_number: 1,
discount_sale_note: "",
is_print: 1,
is_wait_call: 0,
pro_group_info: "",
remark: "",
create_time: "2025-09-16 15:59:59",
update_time: "2025-09-16 16:00:48",
},
{
// 核心修正1空字符串product_type映射为GoodsType.EMPTY
product_type: GoodsType.EMPTY,
// 核心修正2临时菜标记为true
isTemporary: true,
isGift: false,
// 核心修正3折扣金额为数字
discountSaleAmount: 1,
// 补充必需字段salePrice临时菜原价
salePrice: 1,
// 原有字段
id: 18265,
shop_id: 29,
table_code: "APC36217948",
sku_id: -999,
product_id: -18293045,
product_name: "临时菜",
sku_name: "",
number: 1,
pack_number: 0,
discount_sale_note: "",
is_print: 1,
is_wait_call: 0,
pro_group_info: "",
remark: "",
create_time: "2025-09-16 16:00:57",
update_time: null,
},
];
// 修正testCartOrder的key与商品id匹配确保排序正确
const testCartOrder = {
"18264": 1717200000000, // 对应第一个商品id
"18263": 1717200100000, // 对应第二个商品id
"18265": 1717200200000, // 对应第三个商品id
};
// 其他配置保持不变
const testBackendCoupons: BackendCoupon[] = [
{
id: 1,
title: "满减券",
couponType: 1,
fullAmount: 2,
discountAmount: 1,
foods: '946',
useType: 'dine-in,pickup',
useShopType: 'all',
validType: 'custom',
validStartTime: '2025-09-16 16:00:00',
validEndTime: '2025-09-30 16:00:00',
useDays: '周一,周二,周三,周四,周五',
useTimeType: 'all',
},
];
const testOrderConfig = {
currentStoreId: "101",
isMember: false,
memberDiscountRate: 0.95,
userPoints: 0,
pointDeductionRule: {
pointsPerYuan: 100,
maxDeductionAmount: 50,
},
seatFeeConfig: {
isEnabled: false,
pricePerPerson: 3,
personCount: 2,
},
merchantReduction: 10,
additionalFee: 0,
};
const testActivities: ActivityConfig[] = [];
const testCurrentTime = new Date("2024-06-01 12:00:00");
// 调用函数(此时类型完全匹配)
const result = OrderPriceCalculator.calculateOrderCostSummary(
testGoodsList,
"dine-in",
testBackendCoupons,
testActivities,
testOrderConfig,
testCartOrder,
testCurrentTime
);
console.log("计算结果:", result);
export default {}

View File

@ -1,13 +1,15 @@
<template> <template>
<div class="item"> <div class="flex justify-between box">
<img :src="getIconPath(props.icon)" class="icon" /> <div class="item">
<div class="info"> <img :src="getIconPath(props.icon)" class="icon" />
<div class="name">{{ props.name }}</div> <div class="info">
<div class="intro"> <div class="name">{{ props.name }}</div>
{{ props.intro }} <div class="intro">
{{ props.intro }}
</div>
</div> </div>
</div> </div>
<div class="ml-30"> <div>
<el-switch v-model="isOpen" v-if="props.showSwitch" /> <el-switch v-model="isOpen" v-if="props.showSwitch" />
</div> </div>
</div> </div>
@ -53,13 +55,15 @@ const getIconPath = (iconName) => {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.box {
padding: 10px;
border-radius: 4px;
background-color: #f8f8f8;
transition: all 0.1s ease-in-out;
}
.item { .item {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 10px;
background-color: #f8f8f8;
border-radius: 4px;
transition: all 0.1s ease-in-out;
// &:hover { // &:hover {
// cursor: pointer; // cursor: pointer;

View File

@ -1,24 +1,24 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="card"> <div class="card">
<div class="row" v-for="(item, index) in menus" :key="index"> <div class="row" v-for="(item, index) in menus" :key="index">
<div class="title"> <div class="title">
{{ item.label }} {{ item.label }}
</div> </div>
<div class="menus_wrap"> <div class="menus_wrap">
<div class="item" v-for="(val, i) in item.list" :key="i" @click="to(val)"> <div class="item" v-for="(val, i) in item.list" :key="i" @click="to(val)">
<img :src="getIconPath(val.icon)" class="icon" @error="handleImageError(val)" /> <img :src="getIconPath(val.icon)" class="icon" @error="handleImageError(val)" />
<div class="info"> <div class="info">
<div class="name">{{ val.name }}</div> <div class="name">{{ val.name }}</div>
<div class="intro"> <div class="intro">
{{ val.intro }} {{ val.intro }}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
@ -27,228 +27,231 @@ import { ElMessage } from "element-plus";
const router = useRouter(); const router = useRouter();
const to = (item) => { const to = (item) => {
if (!item.pathName) { if (!item.pathName) {
ElMessage.warning("暂未开放"); ElMessage.warning("暂未开放");
return; return;
} }
router.push({ router.push({
name: item.pathName, name: item.pathName,
}); });
}; };
const menus = ref([ const menus = ref([
{ {
label: "营销", label: "营销",
list: [ list: [
{ {
name: "霸王餐", name: "霸王餐",
icon: "bwc", icon: "bwc",
pathName: "bwc", pathName: "bwc",
intro: "设置充值消费的N倍当前订单立即免单", intro: "设置充值消费的N倍当前订单立即免单",
}, },
{ name: "邀请列表", icon: "yqlb", pathName: "invite", intro: "邀请好友领券" }, { name: "邀请列表", icon: "yqlb", pathName: "invite", intro: "邀请好友领券" },
{ {
name: "积分锁客", name: "积分锁客",
icon: "jfsk", icon: "jfsk",
pathName: "points", pathName: "points",
intro: "设置充值消费的N倍当前订单立即免单", intro: "设置充值消费的N倍当前订单立即免单",
}, },
{ name: "充值活动", icon: "czhd", pathName: "", intro: "允许客户充值并使用余额支付" }, { name: "充值活动", icon: "czhd", pathName: "", intro: "允许客户充值并使用余额支付" },
{ name: "弹窗广告", icon: "tcgg", pathName: "", intro: "设置弹窗广告" }, { name: "弹窗广告", icon: "tcgg", pathName: "", intro: "设置弹窗广告" },
{ name: "超级会员", icon: "cjhy", pathName: "superVip", intro: "用户会员管理设置" }, { name: "超级会员", icon: "cjhy", pathName: "superVip", intro: "用户会员管理设置" },
{ name: "新客立减", icon: "xklj", pathName: "", intro: "首单下单减免金额" }, { name: "新客立减", icon: "xklj", pathName: "newUserDiscount", intro: "首单下单减免金额" },
{ name: "智慧充值", icon: "zhcz", pathName: "", intro: "允许客户充值并使用余额支付" }, { name: "智慧充值", icon: "zhcz", pathName: "", intro: "允许客户充值并使用余额支付" },
{ name: "分销", icon: "zhcz", pathName: "", intro: "允许客户充值并使用余额支付" }, { name: "分销", icon: "zhcz", pathName: "", intro: "允许客户充值并使用余额支付" },
{ {
name: "消费返现", name: "消费返现",
icon: "xffx", icon: "xffx",
pathName: "", pathName: "",
intro: "用户下单后返现一定的金额到余额,可促进复购", intro: "用户下单后返现一定的金额到余额,可促进复购",
}, },
{ {
name: "私域引流", name: "私域引流",
icon: "syyl", icon: "syyl",
pathName: "", pathName: "",
intro: "可设置用户下单成功后的群二维码", intro: "可设置用户下单成功后的群二维码",
}, },
{ name: "满减活动", icon: "mjhd", pathName: "", intro: "达到指定支付金额享受减价" }, { name: "满减活动", icon: "mjhd", pathName: "", intro: "达到指定支付金额享受减价" },
{ name: "生日有礼", icon: "sryl", pathName: "", intro: "用户生日管理设置" }, { name: "生日有礼", icon: "sryl", pathName: "", intro: "用户生日管理设置" },
{ {
name: "点餐智能推荐", name: "点餐智能推荐",
icon: "dczntj", icon: "dczntj",
pathName: "", pathName: "",
intro: "进入点单页X秒未点自动推荐商品此推荐设置启用即生效", intro: "进入点单页X秒未点自动推荐商品此推荐设置启用即生效",
}, },
{ name: "超值券包", icon: "czqb", pathName: "", intro: "下单加购" }, { name: "超值券包", icon: "czqb", pathName: "", intro: "下单加购" },
{ {
name: "套餐推广", name: "套餐推广",
icon: "tctg", icon: "tctg",
pathName: "", pathName: "",
intro: "下单通过用户邀请好友减免金额的方式裂变宣传套餐加购", intro: "下单通过用户邀请好友减免金额的方式裂变宣传套餐加购",
}, },
{ {
name: "充值兑换码", name: "充值兑换码",
icon: "czdhm", icon: "czdhm",
pathName: "", pathName: "",
intro: "兑换码直充余额,可当作礼品赠送", intro: "兑换码直充余额,可当作礼品赠送",
}, },
{ name: "券兑换码", icon: "qdhm", pathName: "", intro: "可添加多券组合兑换" }, { name: "券兑换码", icon: "qdhm", pathName: "", intro: "可添加多券组合兑换" },
{ name: "限时折扣", icon: "xszk", pathName: "", intro: "批量设置商品折扣" }, { name: "限时折扣", icon: "xszk", pathName: "", intro: "批量设置商品折扣" },
{ name: "商品拼团", icon: "sppt", pathName: "", intro: "拼团" }, { name: "商品拼团", icon: "sppt", pathName: "", intro: "拼团" },
], ],
}, },
{ {
label: "优惠券", label: "优惠券",
list: [ list: [
{ {
name: "满减券", name: "满减券",
icon: "mjq", icon: "mjq",
pathName: "discount_coupon", pathName: "discount_coupon",
intro: "用户满足指定金额后可使用优惠券立减相应金额设置满100-50券符合要求的订单满100元后立减50元。", intro:
}, "用户满足指定金额后可使用优惠券立减相应金额设置满100-50券符合要求的订单满100元后立减50元。",
{ },
name: "商品兑换券", {
icon: "spdhq", name: "商品兑换券",
pathName: "product_redemption", icon: "spdhq",
intro: "设置可兑换成商品的券", pathName: "product_redemption",
}, intro: "设置可兑换成商品的券",
{ },
name: "折扣券", {
icon: "zkq", name: "折扣券",
pathName: "rebate_coupon", icon: "zkq",
intro: "下单享折扣但折扣的金额将在券中抵扣。", pathName: "rebate_coupon",
}, intro: "下单享折扣但折扣的金额将在券中抵扣。",
{ },
name: "第二件半价券", {
icon: "dejbjq", name: "第二件半价券",
pathName: "half_price", icon: "dejbjq",
intro: "设置第二件半价券", pathName: "half_price",
}, intro: "设置第二件半价券",
{ },
name: "消费赠券", {
icon: "xfzq", name: "消费赠券",
pathName: "consume_ticket", icon: "xfzq",
intro: "达到指定消费金额赠送优惠券", pathName: "consume_ticket",
}, intro: "达到指定消费金额赠送优惠券",
{ },
name: "买一送一券", {
icon: "myzy", name: "买一送一券",
pathName: "buy_one", icon: "myzy",
intro: "针对营销活动买一送一设置券品", pathName: "buy_one",
}, intro: "针对营销活动买一送一设置券品",
{ },
name: "固定价格券", {
icon: "gdjkq", name: "固定价格券",
pathName: "", icon: "gdjkq",
intro: "设置该券后允许用户以固定价格兑换指定商品设置一个固定价格9.9的券商品20元用户使用券后只需要9.9元兑换该商品。", pathName: "",
}, intro:
{ "设置该券后允许用户以固定价格兑换指定商品设置一个固定价格9.9的券商品20元用户使用券后只需要9.9元兑换该商品。",
name: "免配送费券", },
icon: "mfpsq", {
pathName: "", name: "免配送费券",
intro: "可设置一张免除订单配送费的券", icon: "mfpsq",
}, pathName: "",
], intro: "可设置一张免除订单配送费的券",
}, },
{ ],
label: "推送功能", },
list: [ {
{ name: "推送活动消息", icon: "tshdxx", pathName: "", intro: "给用户推送服务通知" }, label: "推送功能",
{ name: "短信推送", icon: "dxts", pathName: "", intro: "给用户推送服务通知" }, list: [
], { name: "推送活动消息", icon: "tshdxx", pathName: "", intro: "给用户推送服务通知" },
}, { name: "短信推送", icon: "dxts", pathName: "", intro: "给用户推送服务通知" },
{ ],
label: "扩展功能", },
list: [ {
{ label: "扩展功能",
name: "微信公众号", list: [
icon: "wxgzh", {
pathName: "", name: "微信公众号",
intro: "授权微信公众号后,让你能够在后台查看和维护公众号的粉丝;同时你的店铺也有出现关注公众号的入口。", icon: "wxgzh",
}, pathName: "",
], intro:
}, "授权微信公众号后,让你能够在后台查看和维护公众号的粉丝;同时你的店铺也有出现关注公众号的入口。",
},
],
},
]); ]);
// PNG // PNG
const getIconPath = (iconName) => { const getIconPath = (iconName) => {
try { try {
// PNG // PNG
return new URL(`/src/assets/applocation/${iconName}.png`, import.meta.url).href; return new URL(`/src/assets/applocation/${iconName}.png`, import.meta.url).href;
} catch (error) { } catch (error) {
console.warn(`图标 ${iconName}.png 不存在`); console.warn(`图标 ${iconName}.png 不存在`);
return defaultIcon; // 使 return defaultIcon; // 使
} }
}; };
// //
const handleImageError = (item) => { const handleImageError = (item) => {
console.error(`图标 ${item.icon}.png 加载失败`); console.error(`图标 ${item.icon}.png 加载失败`);
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container { .app-container {
padding: 14px; padding: 14px;
.card { .card {
padding: 14px; padding: 14px;
background-color: #fff; background-color: #fff;
.row { .row {
padding-bottom: 14px; padding-bottom: 14px;
.title { .title {
font-size: 16px; font-size: 16px;
} }
.menus_wrap { .menus_wrap {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
gap: 14px; gap: 14px;
margin-top: 14px; margin-top: 14px;
.item { .item {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 10px; padding: 10px;
background-color: #f8f8f8; background-color: #f8f8f8;
border-radius: 4px; border-radius: 4px;
transition: all 0.1s ease-in-out; transition: all 0.1s ease-in-out;
&:hover { &:hover {
cursor: pointer; cursor: pointer;
background-color: #d5ebff; background-color: #d5ebff;
} }
.icon { .icon {
width: 48px; width: 48px;
height: 48px; height: 48px;
margin-right: 10px; margin-right: 10px;
} }
.info { .info {
.name { .name {
font-size: 14px; font-size: 14px;
} }
.intro { .intro {
margin-top: 4px; margin-top: 4px;
font-size: 14px; font-size: 14px;
color: #666; color: #666;
line-height: 1.4em; line-height: 1.4em;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 1; -webkit-line-clamp: 1;
line-clamp: 1; line-clamp: 1;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
word-break: break-all; word-break: break-all;
white-space: normal; white-space: normal;
} }
} }
} }
} }
} }
} }
} }
</style> </style>

View File

@ -0,0 +1,149 @@
<template>
<div>
<el-dialog title="购买会员方案" v-model="show" @close="reset" width="60%">
<el-form :model="form" label-width="120px">
<el-form-item label="周期名称" required>
<el-input v-model="form.name" placeholder="周期名称" />
</el-form-item>
<el-form-item label="周期价格" required>
<el-input v-model="form.price" placeholder="周期价格" type="number" />
</el-form-item>
<el-form-item label="赠送成长值" required>
<el-input v-model="form.reward" placeholder="开通后立刻获得经验" type="number" />
</el-form-item>
<el-form-item label="周期时间" required>
<div class="flex">
<el-input-number
style="width: 300px"
v-model="form.circleTime"
placeholder="周期时间"
type="number"
/>
<el-select class="ml-2" v-model="form.circleUnit" placeholder="">
<el-option label="年" value="年" />
<el-option label="月" value="月" />
<el-option label="周" value="周" />
<el-option label="天" value="天" />
</el-select>
</div>
</el-form-item>
</el-form>
<div style="text-align: right; margin-top: 20px">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="submit">{{ isedit ? "更新" : "提交" }}</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, toRaw } from "vue";
import { ElMessage } from "element-plus";
//
const show = ref(false);
//
const couponDialogVisible = ref(false);
//
const form = ref({
name: "",
price: 0,
reward: 0,
couponList: [], //
circleTime: 1, //
circleUnit: "月", //
});
//
const couponList = ref([
{ id: 1, name: "满100减10", value: "10元" },
{ id: 2, name: "满200减30", value: "30元" },
{ id: 3, name: "满500减100", value: "100元" },
]);
//
const selectedCoupons = ref([]);
//
function openCouponDialog() {
couponDialogVisible.value = true;
}
//
function closeCouponDialog() {
couponDialogVisible.value = false;
}
//
function confirmCouponSelection() {
form.value.couponList = [...selectedCoupons.value];
closeCouponDialog();
}
//
function handleCouponSelection(selection) {
selectedCoupons.value = selection;
}
//
function reset() {
form.value = {
name: "",
price: 0,
reward: 0,
couponList: [],
circleTime: "",
};
}
const emits = defineEmits(["submitSuccess"]);
//
function submit() {
if (!form.value.name) {
ElMessage.error("请输入方案名称");
return;
}
if (form.value.price <= 0) {
ElMessage.error("请输入有效的价格");
return;
}
if (!form.value.circleTime) {
ElMessage.error("请选择会员周期");
return;
}
const ispass = form.value.couponList.every((item) => item.num && item.coupon.id);
if (!ispass) {
ElMessage.error("请选择优惠券并输入数量");
return;
}
console.log("提交表单数据:", form.value);
emits("submitSuccess", form.value, dataIndex);
// API
close();
}
let isedit = ref(false);
let dataIndex = null;
function open(data, index) {
data = toRaw(data);
console.log("data", data);
console.log("index", index);
if (data) {
form.value = data;
isedit.value = true;
dataIndex = index;
} else {
isedit.value = false;
dataIndex = null;
}
console.log(data);
show.value = true;
}
function close() {
show.value = false;
reset();
}
defineExpose({ open, close, reset, submit });
</script>

View File

@ -0,0 +1,290 @@
<template>
<div class="m-4 bg-white p-4">
<HeaderCard
name="新客立减"
intro="首单下单减免金额"
icon="new_user_discount"
showSwitch
v-model:isOpen="isEnable"
></HeaderCard>
<el-form ref="form" :model="basicForm">
<el-form-item label="减免方式">
<div>
<el-radio-group v-model="basicForm.discountType">
<el-radio value="FIXED">固定金额</el-radio>
<el-radio value="RANDOM">随机立减</el-radio>
</el-radio-group>
<div v-if="basicForm.discountType === 'FIXED'">
<el-input type="number" v-model="basicForm.discountValue" placeholder="请输入金额">
<template #append></template>
</el-input>
</div>
</div>
</el-form-item>
<!-- 随机立减 -->
<div v-if="basicForm.discountType == 'RANDOM'">
<el-form-item label="会员周期列表">
<el-button type="primary" @click="refDialogPlans.open()">添加方案</el-button>
</el-form-item>
<el-form-item label="">
<el-table :data="basicForm.randomDiscountList" border style="width: 60%">
<el-table-column prop="amount" label="减免金融(元)" align="center" />
<el-table-column prop="probability" label="概率(%" align="center" />
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button type="text" @click="refDialogPlans.open(scope.row, scope.$index)">
编辑
</el-button>
<el-button type="text" style="color: red" @click="deletePlan(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</div>
<div>
<el-form-item label="可使用类型">
<el-checkbox-group v-model="basicForm.useType">
<el-checkbox
v-model="item.value"
:label="item.value"
v-for="item in useTypeList"
:key="item.value"
>
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
</div>
</el-form>
<div class="flex mt-10 justify-center gap-10">
<el-button style="width: 100px" type="primary" @click="basicSubmit" size="large">
保存
</el-button>
<el-button @click="close" style="width: 100px" size="large">取消</el-button>
</div>
<DialogPlans ref="refDialogPlans" @submitSuccess="submitSuccess"></DialogPlans>
</div>
</template>
<script setup>
import shopApi from "@/api/account/shop";
import consumeDiscountApi from "@/api/market/consumeDiscount";
import HeaderCard from "../components/headerCard.vue";
import DialogPlans from "./components/dialog-plans.vue";
import { ref, reactive, watch, toRaw, getCurrentInstance, onMounted } from "vue";
import { ElMessage } from "element-plus";
import { useRouter } from "vue-router";
const inputStyle = {
width: "340px",
};
const router = useRouter();
//
const isEnable = ref(false);
const refDialogPlans = ref();
const configs = [
{ name: "basic", label: "会员基础设置" },
{ name: "lv", label: "会员等级设置" },
{ name: "order", label: "购买会员订单" },
];
const activeTab = ref("basic");
const useTypeList = ref([
{ label: "堂食", value: "dine-in" },
{ label: "外带", value: "take-out" },
{ label: "外卖", value: "take-away" },
]);
const basicForm = reactive({
isEnable: 0,
discountType: "RANDOM",
discountAmount: 0.0,
randomDiscountList: [],
useType: [],
shopId: 0,
});
function deletePlan(row) {
const index = basicForm.configList.indexOf(row);
if (index > -1) {
basicForm.configList.splice(index, 1);
}
}
function submitSuccess(plans, index) {
if (!basicForm.configList) {
basicForm.configList = [];
}
if (index !== null && index !== undefined) {
basicForm.configList[index] = plans;
return;
}
basicForm.configList.push(plans);
}
//
function basicSubmit() {
const data = toRaw(basicForm);
// if (data.openType == "PAY") {
// data.conditionList = null;
// }
// if (data.openType == "CONDITION") {
// data.configList = null;
// }
data.conditionList = useTypes.value
.filter((v) => v.checked)
.map((v) => {
return {
code: v.code,
value: v.value,
};
});
consumeDiscountApi.editConfig(data).then((res) => {
ElMessage.success("保存成功");
});
// ElMessage.success("");
}
//
const levels = ref([]);
//
const selectedLevel = ref(null);
//
const couponList = ref([
{ id: 1, name: "满100减10" },
{ id: 2, name: "满200减30" },
]);
let activeLevelId = ref(null);
//
function addLevel() {
const nowLastVip = levels.value[levels.value.length - 1];
let name = "VIP1";
if (levels.value.length) {
name = "VIP" + (levels.value.length + 1);
}
if (nowLastVip && !nowLastVip.id) {
ElMessage.error("请先保存当前等级");
return;
}
const newLevel = {
name,
experienceValue: 0,
discount: 1,
logo: "",
costRewardPoints: 1,
isCostRewardPoints: 1,
isCycleReward: 0,
cycleTime: 1,
cycleUnit: "月",
cycleRewardPoints: 1,
cycleRewardCouponList: [],
};
console.log(newLevel);
levels.value.push(newLevel);
selectedLevel.value = newLevel;
activeLevelId.value = levels.value.length - 1;
}
//
function editLevel(level) {
selectedLevel.value = level;
}
//
async function removeLevel(index) {
const item = levels.value[index];
const { id } = item;
if (!id) {
//
levels.value.splice(index, 1);
const newLevel = levels.value[index - 1];
selectedLevel.value = newLevel;
activeLevelId.value = index - 1;
ElMessage.success("删除成功");
return;
}
ElMessageBox.confirm("确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(async () => {
const res = await consumeDiscountApi.levelDel({ id: id });
if (res) {
levels.value.splice(index, 1);
ElMessage.success("删除成功");
}
const newLevel = levels.value[index - 1];
selectedLevel.value = newLevel;
activeLevelId.value = index - 1;
});
}
//
async function saveLevel(level) {
const isPass = level.cycleRewardCouponList.every((item) => item.num && item.coupon.id);
if (!isPass) {
ElMessage.error("请选择优惠券并输入数量");
return;
}
const res = level.id
? await consumeDiscountApi.levelEdit(level)
: await consumeDiscountApi.levelAdd(level);
if (res) {
ElMessage.success("保存成功");
}
levelRefresh();
}
const shops = ref([]);
async function levelRefresh() {
consumeDiscountApi.levelList().then((res) => {
if (res && res.length) {
levels.value = res;
if (res.length != 0) {
selectedLevel.value = res[activeLevelId.value];
}
}
});
}
async function init() {
consumeDiscountApi.getConfig().then((res) => {
Object.assign(basicForm, res);
});
}
onMounted(() => {
init();
});
//
function totalCount(arr) {
return arr.reduce((total, item) => {
return total + item.num * 1;
}, 0);
}
//
function close() {
router.back();
}
</script>
<style lang="scss" scoped>
:deep(.el-tabs--border-card) {
border: none;
}
:deep(.el-tabs--border-card > .el-tabs__header) {
border: none;
padding: 4px;
}
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item) {
border: none;
}
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active) {
border: none;
}
</style>

View File

@ -324,6 +324,7 @@ import CouponLists from "./components/coup-lists.vue";
import { ref, reactive, watch, toRaw, getCurrentInstance, onMounted } from "vue"; import { ref, reactive, watch, toRaw, getCurrentInstance, onMounted } from "vue";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import a from "@/utils/test";
const inputStyle = { const inputStyle = {
width: "340px", width: "340px",
@ -344,7 +345,7 @@ const activeTab = ref("basic");
const conditionLists = ref([ const conditionLists = ref([
{ label: "绑定手机号", checked: false, code: "BIND_PHONE" }, { label: "绑定手机号", checked: false, code: "BIND_PHONE" },
{ label: "订单达成指定次数", checked: false, value: "", code: "ORDER" }, { label: "订单达成指定次数", checked: false, value: "", code: "ORDER" },
{ label: "消费达到指定金额", checked: false, value: "", cpde: "COST_AMOUNT" }, { label: "消费达到指定金额", checked: false, value: "", code: "COST_AMOUNT" },
{ label: "充值达到指定金额", checked: false, value: "", code: "RECHARGE_AMOUNT" }, { label: "充值达到指定金额", checked: false, value: "", code: "RECHARGE_AMOUNT" },
]); ]);
const basicForm = reactive({ const basicForm = reactive({
@ -383,6 +384,14 @@ function basicSubmit() {
// if (data.openType == "CONDITION") { // if (data.openType == "CONDITION") {
// data.configList = null; // data.configList = null;
// } // }
data.conditionList = conditionLists.value
.filter((v) => v.checked)
.map((v) => {
return {
code: v.code,
value: v.value,
};
});
memberApi.editConfig(data).then((res) => { memberApi.editConfig(data).then((res) => {
ElMessage.success("保存成功"); ElMessage.success("保存成功");
}); });

View File

@ -0,0 +1,114 @@
<template>
<div>
<el-dialog title="优惠券" v-model="visible" width="80%">
<el-form :inline="true" :model="form">
<el-form-item label="券名称">
<el-input v-model="form.name" placeholder="请输入券名称"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="form.status" placeholder="请选择" style="width: 140px">
<el-option
v-for="item in status"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="领取时间">
<el-date-picker
v-model="form.date"
type="daterange"
value-format="yyyy-MM-dd"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
</el-form-item>
</el-form>
<el-table
style="width: 100%"
:data="tableData"
:columns="columns"
:pagination="pagination"
:row-key="getRowKey"
>
<el-table-column prop="id" label="券ID" />
<el-table-column prop="name" label="券名称" />
<!-- <el-table-column prop="type" label="券类型" /> -->
<el-table-column prop="createTime" label="领取时间" />
<el-table-column prop="useTime" label="使用时间" />
<el-table-column prop="source" label="领取来源" />
<el-table-column label="操作">
<template #default="scope">
<el-link :underline="false" type="primary" size="mini">查看</el-link>
<el-button :underline="false" type="danger" size="mini">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="pagination.currentPage"
v-model:page-size="pagination.pageSize"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@current-change="getList"
@size-change="getList"
/>
</el-dialog>
</div>
</template>
<script setup>
import couponApi from "@/api/market/coupon";
import { ref, reactive } from "vue";
const status = [
{ label: "全部", value: "" },
{ label: "未使用", value: 0 },
{ label: "已使用", value: 1 },
{ label: "已过期", value: 2 },
];
const visible = ref(false);
const form = reactive({
status: 0,
name: "",
date: "",
userId: "",
page: 1,
});
function open(data) {
console.log(data);
data.userId = form.userId;
form.page = 1;
visible.value = true;
getList();
}
function close() {
visible.value = false;
}
function getList() {
couponApi.getDetail(form).then((res) => {
console.log(res);
tableData.value = res.records;
pagination.total = res.totalRow;
});
}
const tableData = ref([]);
const pagination = ref({
total: 0,
pageSize: 10,
currentPage: 1,
});
defineExpose({
open,
close,
});
</script>

View File

@ -56,6 +56,14 @@ const contentConfig: IContentConfig<any> = {
templet: "custom", templet: "custom",
slotName: "mobile", slotName: "mobile",
}, },
{
label: "优惠券",
align: "center",
prop: "coupon",
width: 140,
templet: "custom",
slotName: "coupon",
},
{ {
label: "余额", label: "余额",
align: "center", align: "center",

View File

@ -86,6 +86,15 @@
style="margin-left: 2px" style="margin-left: 2px"
/> />
</template> </template>
<template #coupon="scope">
<div>
1
<el-link :underline="false" type="primary" @click="handleViewCoupon(scope.row)">
查看详情
</el-link>
</div>
</template>
</page-content> </page-content>
<!-- 新增 --> <!-- 新增 -->
@ -108,10 +117,14 @@
@formDataChange="formDataChange" @formDataChange="formDataChange"
@submit-click="handleSubmitClick" @submit-click="handleSubmitClick"
></page-modal> ></page-modal>
<!-- 用户优惠券详情 -->
<UserCouponDialog ref="userCouponDialogRef"></UserCouponDialog>
</div> </div>
</template> </template>
<script setup > <script setup >
import UserCouponDialog from "./components/user-coupon-dialog.vue";
import usePage from "@/components/CURD/usePage"; import usePage from "@/components/CURD/usePage";
import addModalConfig from "./config/add"; import addModalConfig from "./config/add";
import contentConfig from "./config/content"; import contentConfig from "./config/content";
@ -121,6 +134,12 @@ import searchConfig from "./config/search";
import { returnOptionsLabel } from "./config/config"; import { returnOptionsLabel } from "./config/config";
import shopUserApi from "@/api/account/shopUser"; import shopUserApi from "@/api/account/shopUser";
const editMoneyModalRef = ref(null); const editMoneyModalRef = ref(null);
const userCouponDialogRef = ref(null);
//
function handleViewCoupon(row) {
userCouponDialogRef.value.open(row);
}
const { const {
searchRef, searchRef,
contentRef, contentRef,