feat: 积分商品管理模块

This commit is contained in:
lzhizhao 2025-08-11 23:15:49 +08:00
parent 0aca35bf65
commit f0bc66d982
6 changed files with 279 additions and 184 deletions

View File

@ -185,5 +185,42 @@ export const marketing = {
method: "get", method: "get",
params params
}); });
},
// 新增积分商品相关接口
// 获取积分商品分页信息
membershipPointsProductPage: data => {
return $http.request({
url: `/merchant-api/membershipPointsProduct/page`,
method: "post",
data
});
},
// 添加积分商品
addMembershipPointsProduct: data => {
return $http.request({
url: `/merchant-api/membershipPointsProduct/add`,
method: "post",
data
});
},
// 删除积分商品
deleteMembershipPointsProduct: data => {
return $http.request({
url: `/merchant-api/membershipPointsProduct/delete`,
method: "post",
data
});
},
// 修改积分商品
updateMembershipPointsProduct: data => {
return $http.request({
url: `/merchant-api/membershipPointsProduct/update`,
method: "post",
data
});
} }
}; };

View File

@ -13,7 +13,13 @@
<template slot="tableTop"> <template slot="tableTop">
<el-form :inline="true" :model="formInline" class="demo-form-inline"> <el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item v-if="storeList.length > 1" label="商铺"> <el-form-item v-if="storeList.length > 1" label="商铺">
<el-select v-model="formInline.shopId" placeholder="请选择"> <el-select
v-model="formInline.shopIdList"
placeholder="请选择商铺"
multiple
collapse-tags
style="width: 200px"
>
<el-option <el-option
v-for="item in storeList" v-for="item in storeList"
:key="item.shopId" :key="item.shopId"
@ -79,10 +85,12 @@ export default {
formInline: { formInline: {
marketId: "", marketId: "",
shopId: "", shopId: "",
shopIdList: [],
unitType: "", unitType: "",
productId: "", productId: "",
productName: "", productName: "",
redeemEnable: "" productSpecId: "",
productSpecName: ""
}, },
tableProp: { tableProp: {
"auto-resize": true, "auto-resize": true,
@ -103,7 +111,8 @@ export default {
? 3 ? 3
: 2, : 2,
marketId: this.marketId, marketId: this.marketId,
shopId: this.shopId shopId: this.shopId,
shopIdList: this.shopId ? [this.shopId] : []
}; };
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.oTable.reload(); this.$refs.oTable.reload();
@ -111,25 +120,38 @@ export default {
}, },
methods: { methods: {
queryList(pageNo, pageSize) { queryList(pageNo, pageSize) {
// 使
const queryParams = {
shopIdList: this.formInline.shopIdList || [],
productId: this.formInline.productId || 0,
productName: this.formInline.productName || "",
productSpecId: this.formInline.productSpecId || 0,
productSpecName: this.formInline.productSpecName || "",
// 使
pageNumber: pageNo,
pageSize: pageSize
};
this.$api.marketing this.$api.marketing
.PointsProductPage({ .membershipPointsProductPage(queryParams)
pageNumber: pageNo,
pageSize: pageSize,
...this.formInline
})
.then(res => { .then(res => {
console.log(res); console.log(res);
this.$refs.oTable.complete( this.$refs.oTable.complete(res.data || [], Number(res.total || 0));
res.data.data.data,
Number(res.data.data.total)
);
}) })
.catch(err => { .catch(err => {
console.error("查询积分商品失败:", err);
this.$refs.oTable.complete(false); this.$refs.oTable.complete(false);
}); });
}, },
add() { add() {
this.$refs.productSelector.show(this.formInline.shopId); // shopId
const shopIdList =
this.formInline.shopIdList && this.formInline.shopIdList.length > 0
? this.formInline.shopIdList
: this.formInline.shopId
? [this.formInline.shopId]
: [];
this.$refs.productSelector.show(shopIdList);
}, },
reset() { reset() {
this.formInline = { this.formInline = {
@ -138,7 +160,12 @@ export default {
? 3 ? 3
: 2, : 2,
marketId: this.marketId, marketId: this.marketId,
shopId: this.shopId shopId: this.shopId,
shopIdList: this.shopId ? [this.shopId] : [],
productId: "",
productName: "",
productSpecId: "",
productSpecName: ""
}; };
this.$refs.oTable.reload(); this.$refs.oTable.reload();
} }
@ -158,37 +185,63 @@ export default {
align: "center", align: "center",
field: "productName" field: "productName"
}, },
{
title: "商品规格ID",
align: "center",
field: "productSpecId"
},
{
title: "商品规格名称",
align: "center",
field: "productSpecName"
},
{ {
title: "所属店铺", title: "所属店铺",
align: "center", align: "center",
field: "shopName" field: "shopName"
}, },
{ {
title: "兑换积分", title: "兑换所需积分",
align: "center", align: "center",
field: "maxPoints", field: "exchangeRequiredPoints"
},
{
title: "兑换库存",
align: "center",
field: "exchangeInventory"
},
{
title: "剩余库存",
align: "center",
field: "surplusInventory"
},
{
title: "已兑换数量",
align: "center",
field: "totalExchangeQuantity"
},
{
title: "兑换限制",
align: "center",
field: "exchangeRestrictions"
},
{
title: "限制类型",
align: "center",
field: "exchangeRestrictionsType",
type: "jsx", type: "jsx",
render: ({ row }) => { render: ({ row }) => {
if (row.minPoints == row.maxPoints) { return (
return <span>{row.minPoints}</span>; <span>
} else { {row.exchangeRestrictionsType === 1 ? "每日" : "永久"}
return ( </span>
<span> );
{row.minPoints}-{row.maxPoints}
</span>
);
}
} }
}, },
{ {
title: "剩余兑换库存", title: "创建时间",
align: "center", align: "center",
field: "totalInventory" field: "createTime"
},
{
title: "已兑换数",
align: "center",
field: "totalRedeemQuantity"
}, },
{ {
title: "操作", title: "操作",
@ -217,12 +270,15 @@ export default {
}; };
let deleteProduct = () => { let deleteProduct = () => {
this.$api.marketing this.$api.marketing
.deletePointsProduct({ id: row.id }) .deleteMembershipPointsProduct({ id: row.id })
.then(res => { .then(res => {
this.$message.success("删除成功"); this.$message.success("删除成功");
this.$refs.oTable.reload(); this.$refs.oTable.reload();
}) })
.catch(err => {}); .catch(err => {
console.error("删除积分商品失败:", err);
this.$message.error("删除失败");
});
}; };
return ( return (
<div> <div>

View File

@ -75,11 +75,11 @@ export default {
modalConfig: { modalConfig: {
title: "请点击选择商品 (提示最多选择5个商品)", title: "请点击选择商品 (提示最多选择5个商品)",
show: false, show: false,
width: "1000px", width: "1000px"
}, },
query: { query: {
pageNumber: 1, pageNumber: 1,
pageSize: 10, pageSize: 10
}, },
total: 0, total: 0,
modalData: {}, modalData: {},
@ -87,8 +87,8 @@ export default {
selectList: [], selectList: [],
formInline: {}, formInline: {},
formList: { formList: {
name: "", name: ""
}, }
}; };
}, },
methods: { methods: {
@ -97,20 +97,20 @@ export default {
.getProductPage({ .getProductPage({
p: { p: {
pageNumber: this.query.pageNumber, pageNumber: this.query.pageNumber,
pageSize: this.query.pageSize, pageSize: this.query.pageSize
}, },
...this.formInline, ...this.formInline,
...this.formList, ...this.formList,
productFilterType: "SALE", productFilterType: "SALE",
merchantId: JSON.parse(sessionStorage.getItem("userInfo")).merchantId, merchantId: JSON.parse(sessionStorage.getItem("userInfo")).merchantId,
productQuerySortParam: [], productQuerySortParam: []
}) })
.then((res) => { .then(res => {
console.log(res); console.log(res);
this.dataList = res.data.data.data; this.dataList = res.data.data;
this.total = Number(res.data.data.total); this.total = Number(res.data.data.total);
}) })
.catch((err) => { .catch(err => {
this.dataList = []; this.dataList = [];
}); });
}, },
@ -124,7 +124,7 @@ export default {
this.init(cloneDeep(e)); this.init(cloneDeep(e));
} }
return { return {
add: (row) => { add: row => {
console.log(row); console.log(row);
this.formInline = row; this.formInline = row;
this.isAdd = true; this.isAdd = true;
@ -134,13 +134,13 @@ export default {
}, },
update: () => { update: () => {
this.isAdd = false; this.isAdd = false;
}, }
}; };
}, },
init(row) {}, init(row) {},
toggleSelection(rows) { toggleSelection(rows) {
if (rows) { if (rows) {
rows.forEach((row) => { rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row); this.$refs.multipleTable.toggleRowSelection(row);
}); });
} else { } else {
@ -183,7 +183,7 @@ export default {
Reset() { Reset() {
this.formList = {}; this.formList = {};
this.queryList(); this.queryList();
}, }
}, },
computed: { computed: {
modalHandles() { modalHandles() {
@ -192,7 +192,7 @@ export default {
label: "取消", label: "取消",
handle: () => { handle: () => {
this.toggle(); this.toggle();
}, }
}, },
{ {
label: "确认", label: "确认",
@ -200,8 +200,8 @@ export default {
handle: () => { handle: () => {
this.$emit("getProduct", this.selectList); this.$emit("getProduct", this.selectList);
this.toggle(); this.toggle();
}, }
}, }
]; ];
}, },
tableEvent() { tableEvent() {
@ -217,10 +217,10 @@ export default {
return; return;
} }
this.selectList = [...records, ...reserves]; this.selectList = [...records, ...reserves];
}, }
}; };
}, }
}, }
}; };
</script> </script>

View File

@ -33,21 +33,15 @@
label-width="140px" label-width="140px"
style="margin-top: 20px" style="margin-top: 20px"
> >
<el-form-item label="SKU-ID" prop="skuId"> <el-form-item label="兑换所需积分" prop="exchangeRequiredPoints" required>
<el-input
v-model="configForm.skuId"
placeholder="请输入SKU-ID"
:disabled="isEdit"
></el-input>
</el-form-item>
<el-form-item label="兑换所需积分设置" prop="points" required>
<div class="points-input"> <div class="points-input">
<el-button @click="decreasePoints" :disabled="configForm.points <= 1" <el-button
@click="decreasePoints"
:disabled="configForm.exchangeRequiredPoints <= 1"
>-</el-button >-</el-button
> >
<el-input-number <el-input-number
v-model="configForm.points" v-model="configForm.exchangeRequiredPoints"
:min="1" :min="1"
:max="99999" :max="99999"
controls-position="right" controls-position="right"
@ -57,15 +51,15 @@
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="兑换库存设置" prop="inventory" required> <el-form-item label="兑换库存" prop="exchangeInventory" required>
<div class="inventory-input"> <div class="inventory-input">
<el-button <el-button
@click="decreaseInventory" @click="decreaseInventory"
:disabled="configForm.inventory <= 1" :disabled="configForm.exchangeInventory <= 1"
>-</el-button >-</el-button
> >
<el-input-number <el-input-number
v-model="configForm.inventory" v-model="configForm.exchangeInventory"
:min="1" :min="1"
:max="99999" :max="99999"
controls-position="right" controls-position="right"
@ -75,35 +69,38 @@
</div> </div>
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="兑换限制" prop="exchangeRestrictions" required>
label="限制兑换(每人购买不超)"
prop="limitQuantity"
required
>
<div class="limit-input"> <div class="limit-input">
<el-button <el-button
@click="decreaseLimitQuantity" @click="decreaseLimitQuantity"
:disabled="configForm.limitQuantity <= 0" :disabled="configForm.exchangeRestrictions <= 0"
>-</el-button >-</el-button
> >
<el-input-number <el-input-number
v-model="configForm.limitQuantity" v-model="configForm.exchangeRestrictions"
:min="0" :min="0"
:max="99999" :max="99999"
controls-position="right" controls-position="right"
style="width: 200px; margin: 0 10px" style="width: 200px; margin: 0 10px"
></el-input-number> ></el-input-number>
<el-button @click="increaseLimitQuantity">+</el-button> <el-button @click="increaseLimitQuantity">+</el-button>
<el-select
v-model="configForm.limitPeriod"
style="width: 100px; margin-left: 10px"
>
<el-option label="每天" value="DAY"></el-option>
<el-option label="每周" value="WEEK"></el-option>
<el-option label="每月" value="MONTH"></el-option>
</el-select>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item
label="兑换限制类型"
prop="exchangeRestrictionsType"
required
>
<el-select
v-model="configForm.exchangeRestrictionsType"
placeholder="请选择限制类型"
style="width: 200px"
>
<el-option label="每日" :value="1"></el-option>
<el-option label="永久" :value="2"></el-option>
</el-select>
</el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
@ -125,22 +122,27 @@ export default {
submitting: false, submitting: false,
productData: {}, productData: {},
configForm: { configForm: {
skuId: "", id: 0,
points: 1, shopId: 0,
inventory: 10, productId: 0,
limitQuantity: 0, productSpecId: 0,
limitPeriod: "DAY" exchangeRequiredPoints: 1,
exchangeInventory: 10,
exchangeRestrictions: 0,
exchangeRestrictionsType: 1
}, },
configRules: { configRules: {
skuId: [{ required: true, message: "请输入SKU-ID", trigger: "blur" }], exchangeRequiredPoints: [
points: [ { required: true, message: "请设置兑换所需积分", trigger: "blur" }
{ required: true, message: "请设置兑换积分", trigger: "blur" }
], ],
inventory: [ exchangeInventory: [
{ required: true, message: "请设置兑换库存", trigger: "blur" } { required: true, message: "请设置兑换库存", trigger: "blur" }
], ],
limitQuantity: [ exchangeRestrictions: [
{ required: true, message: "请设置限制数量", trigger: "blur" } { required: true, message: "请设置兑换限制", trigger: "blur" }
],
exchangeRestrictionsType: [
{ required: true, message: "请选择兑换限制类型", trigger: "change" }
] ]
} }
}; };
@ -154,20 +156,26 @@ export default {
if (editData) { if (editData) {
// //
this.configForm = { this.configForm = {
skuId: editData.skuId || "", id: editData.id || 0,
points: editData.minPoints || 1, shopId: editData.shopId || 0,
inventory: editData.totalInventory || 10, productId: editData.productId || 0,
limitQuantity: editData.limitQuantity || 0, productSpecId: editData.productSpecId || 0,
limitPeriod: editData.limitPeriod || "DAY" exchangeRequiredPoints: editData.exchangeRequiredPoints || 1,
exchangeInventory: editData.exchangeInventory || 10,
exchangeRestrictions: editData.exchangeRestrictions || 0,
exchangeRestrictionsType: editData.exchangeRestrictionsType || 1
}; };
} else { } else {
// 使 // 使
this.configForm = { this.configForm = {
skuId: productData.skuId || "", id: 0,
points: 1, shopId: productData.shopId || 0,
inventory: 10, productId: productData.productId || 0,
limitQuantity: 0, productSpecId: productData.productSpecId || 0,
limitPeriod: "DAY" exchangeRequiredPoints: 1,
exchangeInventory: 10,
exchangeRestrictions: 0,
exchangeRestrictionsType: 1
}; };
} }
}, },
@ -178,11 +186,14 @@ export default {
resetForm() { resetForm() {
this.productData = {}; this.productData = {};
this.configForm = { this.configForm = {
skuId: "", id: 0,
points: 1, shopId: 0,
inventory: 10, productId: 0,
limitQuantity: 0, productSpecId: 0,
limitPeriod: "DAY" exchangeRequiredPoints: 1,
exchangeInventory: 10,
exchangeRestrictions: 0,
exchangeRestrictionsType: 1
}; };
this.isEdit = false; this.isEdit = false;
this.$refs.configForm && this.$refs.configForm.clearValidate(); this.$refs.configForm && this.$refs.configForm.clearValidate();
@ -193,46 +204,52 @@ export default {
this.submitting = true; this.submitting = true;
const submitData = { const submitData = {
...this.productData, ...this.configForm
...this.configForm,
minPoints: this.configForm.points,
maxPoints: this.configForm.points,
totalInventory: this.configForm.inventory
}; };
// API // API
setTimeout(() => { const apiCall = this.isEdit
this.$message.success(this.isEdit ? "编辑成功" : "添加成功"); ? this.$api.marketing.updateMembershipPointsProduct(submitData)
this.submitting = false; : this.$api.marketing.addMembershipPointsProduct(submitData);
this.$emit("success", submitData);
this.handleClose(); apiCall
}, 1000); .then(res => {
this.$message.success(this.isEdit ? "编辑成功" : "添加成功");
this.submitting = false;
this.$emit("success", submitData);
this.handleClose();
})
.catch(err => {
console.error("提交积分商品配置失败:", err);
this.$message.error(this.isEdit ? "编辑失败" : "添加失败");
this.submitting = false;
});
} }
}); });
}, },
decreasePoints() { decreasePoints() {
if (this.configForm.points > 1) { if (this.configForm.exchangeRequiredPoints > 1) {
this.configForm.points--; this.configForm.exchangeRequiredPoints--;
} }
}, },
increasePoints() { increasePoints() {
this.configForm.points++; this.configForm.exchangeRequiredPoints++;
}, },
decreaseInventory() { decreaseInventory() {
if (this.configForm.inventory > 1) { if (this.configForm.exchangeInventory > 1) {
this.configForm.inventory--; this.configForm.exchangeInventory--;
} }
}, },
increaseInventory() { increaseInventory() {
this.configForm.inventory++; this.configForm.exchangeInventory++;
}, },
decreaseLimitQuantity() { decreaseLimitQuantity() {
if (this.configForm.limitQuantity > 0) { if (this.configForm.exchangeRestrictions > 0) {
this.configForm.limitQuantity--; this.configForm.exchangeRestrictions--;
} }
}, },
increaseLimitQuantity() { increaseLimitQuantity() {
this.configForm.limitQuantity++; this.configForm.exchangeRestrictions++;
} }
} }
}; };

View File

@ -10,11 +10,7 @@
<div class="search-form"> <div class="search-form">
<el-form :inline="true" :model="searchForm" class="demo-form-inline"> <el-form :inline="true" :model="searchForm" class="demo-form-inline">
<el-form-item label="店铺"> <el-form-item label="店铺">
<el-select <el-select v-model="searchForm.shopId" placeholder="请选择店铺">
v-model="searchForm.shopId"
placeholder="请选择店铺"
disabled
>
<el-option <el-option
v-for="item in storeList" v-for="item in storeList"
:key="item.shopId" :key="item.shopId"
@ -53,29 +49,14 @@
style="width: 100%" style="width: 100%"
v-loading="loading" v-loading="loading"
> >
<el-table-column <el-table-column prop="shopId" label="商品店铺" align="center">
prop="shopName"
label="商品店铺"
align="center"
width="150"
>
</el-table-column> </el-table-column>
<el-table-column prop="productName" label="商品名称" align="center"> <el-table-column prop="name" label="商品名称" align="center">
</el-table-column> </el-table-column>
<el-table-column <el-table-column prop="id" label="商品ID" align="center">
prop="productId"
label="商品ID"
align="center"
width="120"
>
</el-table-column> </el-table-column>
<el-table-column <el-table-column prop="salePrice" label="商品价格" align="center">
prop="price" <template slot-scope="scope"> ¥{{ scope.row.salePrice }} </template>
label="商品价格"
align="center"
width="100"
>
<template slot-scope="scope"> ¥{{ scope.row.price }} </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="150"> <el-table-column label="操作" align="center" width="150">
<template slot-scope="scope"> <template slot-scope="scope">
@ -148,9 +129,14 @@ export default {
}; };
}, },
methods: { methods: {
show(shopId) { show(shopIdList) {
this.visible = true; this.visible = true;
this.searchForm.shopId = shopId; // 使
if (Array.isArray(shopIdList) && shopIdList.length > 0) {
this.searchForm.shopId = shopIdList[0];
} else if (shopIdList) {
this.searchForm.shopId = shopIdList;
}
this.loadProducts(); this.loadProducts();
}, },
handleClose() { handleClose() {
@ -181,34 +167,33 @@ export default {
}, },
loadProducts() { loadProducts() {
this.loading = true; this.loading = true;
// API - API // API
setTimeout(() => { this.$api.mer_admin
this.productList = [ .getProductPage({
{ p: {
productId: "1212", pageNumber: this.pagination.currentPage,
productName: "猪肉", pageSize: this.pagination.pageSize
shopName: "猪肉铺",
price: "2.00",
skuId: "194105142774503836"
}, },
{ shopId: this.searchForm.shopId,
productId: "1213", productName: this.searchForm.productName,
productName: "牛肉", productId: this.searchForm.productId,
shopName: "牛肉铺", productFilterType: "SALE",
price: "5.00", merchantId: JSON.parse(sessionStorage.getItem("userInfo")).merchantId,
skuId: "194105142774503837" productQuerySortParam: []
}, })
{ .then(res => {
productId: "1214", console.log("商品列表:", res);
productName: "鸡肉", this.productList = res.data.data.data || [];
shopName: "鸡肉铺", this.pagination.total = Number(res.data.data.total || 0);
price: "3.00", this.loading = false;
skuId: "194105142774503838" })
} .catch(err => {
]; console.error("获取商品列表失败:", err);
this.pagination.total = 3; this.productList = [];
this.loading = false; this.pagination.total = 0;
}, 500); this.loading = false;
this.$message.error("获取商品列表失败");
});
}, },
handleSizeChange(val) { handleSizeChange(val) {
this.pagination.pageSize = val; this.pagination.pageSize = val;

View File

@ -19,7 +19,7 @@
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="label">系统编号</span> <span class="label">系统编号</span>
<span class="value">{{ modalData.userId || "-" }}</span> <span class="value">{{ modalData.id || "-" }}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="label">手机号</span> <span class="label">手机号</span>