feat: 等级设置页面改动

This commit is contained in:
lzhizhao 2025-08-07 23:34:38 +08:00
parent c20de1f827
commit 28e887552e
5 changed files with 993 additions and 392 deletions

View File

@ -49,7 +49,7 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -62,7 +62,7 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -75,7 +75,7 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -88,7 +88,7 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -101,7 +101,7 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -114,7 +114,7 @@ export default {
elIcon: "el-icon-menu",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -128,7 +128,7 @@ export default {
orderNum: 0,
open: null,
list: [],
hideInMenu: true,
hideInMenu: true
},
{
menuId: getUUID(),
@ -141,7 +141,7 @@ export default {
elIcon: "el-icon-menu",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -154,7 +154,7 @@ export default {
elIcon: "el-icon-menu",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -167,7 +167,7 @@ export default {
elIcon: "el-icon-menu",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -180,7 +180,7 @@ export default {
elIcon: "el-icon-menu",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -193,7 +193,7 @@ export default {
elIcon: "el-icon-menu",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -206,7 +206,7 @@ export default {
elIcon: "el-icon-menu",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -219,9 +219,9 @@ export default {
elIcon: "el-icon-user",
orderNum: 0,
open: null,
list: [],
},
],
list: []
}
]
},
{
menuId: getUUID(),
@ -246,7 +246,7 @@ export default {
elIcon: "el-icon-user",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -259,7 +259,7 @@ export default {
elIcon: "el-icon-data-analysis",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -272,9 +272,9 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
},
],
list: []
}
]
},
{
menuId: getUUID(),
@ -288,7 +288,7 @@ export default {
orderNum: 0,
open: null,
list: [],
hideInMenu: true,
hideInMenu: true
},
{
menuId: getUUID(),
@ -313,9 +313,9 @@ export default {
elIcon: "el-icon-postcard",
orderNum: 0,
open: null,
list: [],
},
],
list: []
}
]
},
{
menuId: getUUID(),
@ -328,7 +328,7 @@ export default {
elIcon: "el-icon-document-remove",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -353,7 +353,7 @@ export default {
elIcon: "el-icon-postcard",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -366,9 +366,9 @@ export default {
elIcon: "el-icon-postcard",
orderNum: 0,
open: null,
list: [],
},
],
list: []
}
]
},
{
menuId: getUUID(),
@ -386,14 +386,14 @@ export default {
menuId: getUUID(),
parentId: 0,
parentName: null,
name: "会员等级管理",
name: "等级设置",
url: "marketing/level/index",
perms: "",
type: 1,
elIcon: "el-icon-user",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -406,7 +406,7 @@ export default {
elIcon: "el-icon-data-analysis",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -419,7 +419,7 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -432,7 +432,7 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -445,9 +445,9 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
},
],
list: []
}
]
},
{
menuId: getUUID(),
@ -472,7 +472,7 @@ export default {
elIcon: "el-icon-user",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -485,7 +485,7 @@ export default {
elIcon: "el-icon-data-analysis",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -498,7 +498,7 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
list: []
},
{
menuId: getUUID(),
@ -511,10 +511,10 @@ export default {
elIcon: "el-icon-shopping-cart-full",
orderNum: 0,
open: null,
list: [],
},
list: []
}
],
hideInMenu: true,
hideInMenu: true
},
{
menuId: getUUID(),
@ -539,9 +539,9 @@ export default {
elIcon: "el-icon-menu",
orderNum: 0,
open: null,
list: [],
},
],
list: []
}
]
},
{
menuId: getUUID(),
@ -566,11 +566,65 @@ export default {
elIcon: "el-icon-postcard",
orderNum: 0,
open: null,
list: [],
},
],
},
list: []
}
]
}
// {
// menuId: getUUID(),
// parentId: 0,
// parentName: null,
// name: "会员管理",
// url: "member-management",
// perms: "",
// type: 0,
// elIcon: "el-icon-user-solid",
// orderNum: 0,
// open: null,
// list: [
// {
// menuId: getUUID(),
// parentId: 0,
// parentName: null,
// name: "等级设置",
// url: "member-management/level-setting/index",
// perms: "",
// type: 1,
// elIcon: "el-icon-star-on",
// orderNum: 0,
// open: null,
// list: []
// }
// ]
// },
// {
// menuId: getUUID(),
// parentId: 0,
// parentName: null,
// name: "会员列表",
// url: "member-list",
// perms: "",
// type: 0,
// elIcon: "el-icon-user",
// orderNum: 0,
// open: null,
// list: [
// {
// menuId: getUUID(),
// parentId: 0,
// parentName: null,
// name: "会员列表",
// url: "member-list/member-list/index",
// perms: "",
// type: 1,
// elIcon: "el-icon-user",
// orderNum: 0,
// open: null,
// list: []
// }
// ]
// }
],
code: 0,
permissions: [],
permissions: []
};

View File

@ -1,14 +1,16 @@
import Vue from 'vue'
import router from '@/router'
import store from '@/store'
import Vue from "vue";
import router from "@/router";
import store from "@/store";
/**
* 获取uuid
*/
export function getUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
return (c === 'x' ? (Math.random() * 16) | 0 : 'r&0x3' | '0x8').toString(16)
})
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
return (c === "x" ? (Math.random() * 16) | 0 : "r&0x3" | "0x8").toString(
16
);
});
}
/**
@ -17,9 +19,9 @@ export function getUUID() {
*/
export function isAuth(key) {
return (
JSON.parse(sessionStorage.getItem('permissions') || '[]').indexOf(key) !==
JSON.parse(sessionStorage.getItem("permissions") || "[]").indexOf(key) !==
-1 || false
)
);
}
/**
@ -28,87 +30,87 @@ export function isAuth(key) {
* @param {*} id
* @param {*} pid
*/
export function treeDataTranslate(data, id = 'id', pid = 'parentId') {
var res = []
var temp = {}
export function treeDataTranslate(data, id = "id", pid = "parentId") {
var res = [];
var temp = {};
for (var i = 0; i < data.length; i++) {
temp[data[i][id]] = data[i]
temp[data[i][id]] = data[i];
}
for (var k = 0; k < data.length; k++) {
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
if (!temp[data[k][pid]]['children']) {
temp[data[k][pid]]['children'] = []
if (!temp[data[k][pid]]["children"]) {
temp[data[k][pid]]["children"] = [];
}
if (!temp[data[k][pid]]['_level']) {
temp[data[k][pid]]['_level'] = 1
if (!temp[data[k][pid]]["_level"]) {
temp[data[k][pid]]["_level"] = 1;
}
data[k]['_level'] = temp[data[k][pid]]._level + 1
temp[data[k][pid]]['children'].push(data[k])
data[k]["_level"] = temp[data[k][pid]]._level + 1;
temp[data[k][pid]]["children"].push(data[k]);
} else {
res.push(data[k])
res.push(data[k]);
}
}
return res
return res;
}
/**
* 清除登录信息
*/
export function clearLoginInfo() {
Vue.cookie.delete('token')
store.commit('resetStore')
sessionStorage.removeItem('password')
sessionStorage.removeItem('role')
sessionStorage.removeItem('userInfo')
router.options.isAddDynamicMenuRoutes = false
Vue.cookie.delete("token");
store.commit("resetStore");
sessionStorage.removeItem("password");
sessionStorage.removeItem("role");
sessionStorage.removeItem("userInfo");
router.options.isAddDynamicMenuRoutes = false;
}
// 深拷贝对象
export function deepClone(obj) {
const _toString = Object.prototype.toString
const _toString = Object.prototype.toString;
// null, undefined, non-object, function
if (!obj || typeof obj !== 'object') {
return obj
if (!obj || typeof obj !== "object") {
return obj;
}
// DOM Node
if (obj.nodeType && 'cloneNode' in obj) {
return obj.cloneNode(true)
if (obj.nodeType && "cloneNode" in obj) {
return obj.cloneNode(true);
}
// Date
if (_toString.call(obj) === '[object Date]') {
return new Date(obj.getTime())
if (_toString.call(obj) === "[object Date]") {
return new Date(obj.getTime());
}
// RegExp
if (_toString.call(obj) === '[object RegExp]') {
const flags = []
if (_toString.call(obj) === "[object RegExp]") {
const flags = [];
if (obj.global) {
flags.push('g')
flags.push("g");
}
if (obj.multiline) {
flags.push('m')
flags.push("m");
}
if (obj.ignoreCase) {
flags.push('i')
flags.push("i");
}
return new RegExp(obj.source, flags.join(''))
return new RegExp(obj.source, flags.join(""));
}
const result = Array.isArray(obj)
? []
: obj.constructor
? new obj.constructor()
: {}
: {};
for (const key in obj) {
result[key] = deepClone(obj[key])
result[key] = deepClone(obj[key]);
}
return result
return result;
}
/**
@ -117,22 +119,22 @@ export function deepClone(obj) {
* @param {*} max
*/
export function getDay(day) {
let today = new Date()
let targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * day
today.setTime(targetday_milliseconds) //注意,这行是关键代码
let tYear = today.getFullYear()
let tMonth = today.getMonth()
let tDate = today.getDate()
tMonth = doHandleMonth(tMonth + 1)
tDate = doHandleMonth(tDate)
return tYear + '-' + tMonth + '-' + tDate
let today = new Date();
let targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * day;
today.setTime(targetday_milliseconds); //注意,这行是关键代码
let tYear = today.getFullYear();
let tMonth = today.getMonth();
let tDate = today.getDate();
tMonth = doHandleMonth(tMonth + 1);
tDate = doHandleMonth(tDate);
return tYear + "-" + tMonth + "-" + tDate;
}
function doHandleMonth(month) {
let m = month
let m = month;
if (month.toString().length === 1) {
m = '0' + month
m = "0" + month;
}
return m
return m;
}
/**
* 权限
@ -140,142 +142,151 @@ function doHandleMonth(month) {
* @param {*} max
*/
export function getMenu(role, manageMode) {
if (role == 'ROLE_MANAGER') {
if (role == "ROLE_MANAGER") {
return [
'operation-management',
'operation-management/commodity/index',
'operation-management/order/index',
'operation-management/banner/index',
'operation-management/notice/index',
'operation-management/paynotice/index',
'operation-management/role/index',
'datacenter',
'datacenter/customer-analysis/index',
'datacenter/product-analysis/index',
'datacenter/order-analysis/index',
'coupon/index',
'presale',
'presale/products/index',
'presale/order/index',
'marketing',
'marketing/level/index',
'marketing/user/index',
'marketing/points-setting/index',
'marketing/points-mall/index',
'marketing/points-order/index',
'local-course/resources',
'wallet/index',
'ogistics-fare',
'logistics-fare/logistics-template/index',
'bank-card/index',
'operation-management/total-order/index',
'operation-management/accountNumber/index'
]
} else if (role == 'ROLE_MERCHANT') {
"operation-management",
"operation-management/commodity/index",
"operation-management/order/index",
"operation-management/banner/index",
"operation-management/notice/index",
"operation-management/paynotice/index",
"operation-management/role/index",
"datacenter",
"datacenter/customer-analysis/index",
"datacenter/product-analysis/index",
"datacenter/order-analysis/index",
"coupon/index",
"presale",
"presale/products/index",
"presale/order/index",
"marketing",
"marketing/level/index",
"marketing/user/index",
"marketing/points-setting/index",
"marketing/points-mall/index",
"marketing/points-order/index",
// "member-management",
// "member-management/level-setting/index",
// "member-list",
// "member-list/member-list/index",
"local-course/resources",
"wallet/index",
"ogistics-fare",
"logistics-fare/logistics-template/index",
"bank-card/index",
"operation-management/total-order/index",
"operation-management/accountNumber/index"
];
} else if (role == "ROLE_MERCHANT") {
if (manageMode === 1) {
return [
'operation-management',
'operation-management/commodity/index',
'operation-management/order/index',
'operation-management/banner/index',
'operation-management/notice/index',
'operation-management/paynotice/index',
'operation-management/role/index',
'datacenter',
'datacenter/customer-analysis/index',
'datacenter/product-analysis/index',
'datacenter/order-analysis/index',
'coupon/index',
'presale',
'presale/products/index',
'presale/order/index',
'marketing',
// 'marketing/level/index',
// 'marketing/user/index',
// 'marketing/points-setting/index',
'marketing/points-mall/index',
'marketing/points-order/index',
'local-course/resources',
'wallet/index',
'ogistics-fare',
'logistics-fare/logistics-template/index',
'bank-card/index',
'operation-management/total-order/index',
'operation-management/accountNumber/index'
]
"operation-management",
"operation-management/commodity/index",
"operation-management/order/index",
"operation-management/banner/index",
"operation-management/notice/index",
"operation-management/paynotice/index",
"operation-management/role/index",
"datacenter",
"datacenter/customer-analysis/index",
"datacenter/product-analysis/index",
"datacenter/order-analysis/index",
"coupon/index",
"presale",
"presale/products/index",
"presale/order/index",
"marketing",
"marketing/points-mall/index",
"marketing/points-order/index",
// "member-management",
// "member-management/level-setting/index",
// "member-list",
// "member-list/member-list/index",
"local-course/resources",
"wallet/index",
"ogistics-fare",
"logistics-fare/logistics-template/index",
"bank-card/index",
"operation-management/total-order/index",
"operation-management/accountNumber/index"
];
} else {
return [
'operation-management',
'operation-management/commodity/index',
'operation-management/order/index',
'operation-management/banner/index',
'operation-management/notice/index',
'operation-management/paynotice/index',
'operation-management/role/index',
'datacenter',
'datacenter/customer-analysis/index',
'datacenter/product-analysis/index',
'datacenter/order-analysis/index',
'coupon/index',
'presale',
'presale/products/index',
'presale/order/index',
'marketing',
'marketing/level/index',
'marketing/user/index',
'marketing/points-setting/index',
'marketing/points-mall/index',
'marketing/points-order/index',
'local-course/resources',
'wallet/index',
'ogistics-fare',
'logistics-fare/logistics-template/index',
'bank-card/index',
'operation-management/total-order/index',
'operation-management/accountNumber/index'
]
"operation-management",
"operation-management/commodity/index",
"operation-management/order/index",
"operation-management/banner/index",
"operation-management/notice/index",
"operation-management/paynotice/index",
"operation-management/role/index",
"datacenter",
"datacenter/customer-analysis/index",
"datacenter/product-analysis/index",
"datacenter/order-analysis/index",
"coupon/index",
"presale",
"presale/products/index",
"presale/order/index",
"marketing",
"marketing/level/index",
"marketing/user/index",
"marketing/points-setting/index",
"marketing/points-mall/index",
"marketing/points-order/index",
// "member-management",
// "member-management/level-setting/index",
// "member-list",
// "member-list/member-list/index",
"local-course/resources",
"wallet/index",
"ogistics-fare",
"logistics-fare/logistics-template/index",
"bank-card/index",
"operation-management/total-order/index",
"operation-management/accountNumber/index"
];
}
} else if (role == 'ROLE_BRAND_MANAGER') {
} else if (role == "ROLE_BRAND_MANAGER") {
return [
'operation-management',
"operation-management",
// "operation-management/shop-list/index",
'operation-management/brand-market/index',
'operation-management/brand-store/index',
'operation-management/distributor/index',
"operation-management/brand-market/index",
"operation-management/brand-store/index",
"operation-management/distributor/index",
// "operation-management/order/index",
'operation-management/brand-order/index',
"operation-management/brand-order/index",
// "operation-management/role/index",
'datacenter',
'datacenter/customer-analysis/index',
'datacenter/product-analysis/index',
'datacenter/order-analysis/index',
'brand',
'brand/config/index',
'local-course/resources',
'wallet/index'
"datacenter",
"datacenter/customer-analysis/index",
"datacenter/product-analysis/index",
"datacenter/order-analysis/index",
"brand",
"brand/config/index",
"local-course/resources",
"wallet/index"
// "operation-management/accountNumber/index",
]
} else if (role == 'ROLE_AGENT') {
];
} else if (role == "ROLE_AGENT") {
return [
'operation-management',
'operation-management/shop-list/index',
'operation-management/market-list/index',
"operation-management",
"operation-management/shop-list/index",
"operation-management/market-list/index",
// "operation-management/order/index",
'operation-management/brand-order/index',
"operation-management/brand-order/index",
// "operation-management/role/index",
'datacenter',
'datacenter/customer-analysis/index',
'datacenter/product-analysis/index',
'datacenter/order-analysis/index',
'local-course/resources',
'wallet/index'
"datacenter",
"datacenter/customer-analysis/index",
"datacenter/product-analysis/index",
"datacenter/order-analysis/index",
"local-course/resources",
"wallet/index"
// "operation-management/accountNumber/index",
]
];
} else {
return null
return null;
}
}
export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str);
}

View File

@ -1,202 +1,342 @@
<template>
<div>
<div class="tips">
<div>请谨慎操作此页面数据避免频繁修改导致会员流失等不必要的损失</div>
<div style="margin-top: 10px">
请注意用户一旦达到某会员等级后续修改会员等级要求不会影响用户已达到的会员等级但可享有该等级对应的会员权益
</div>
<div style="margin-top: 20px">
举例24年2月用户在本商铺的成长值达到500升级为VIP2,此时,VIP2会员权益享有的生日优惠卷1
</div>
<div style="margin-top: 10px">
24年3月本商铺修改VIP2所需成长值为700并新增会员生日优惠卷2修改提交后,该用户会员等级保持VIP2不变且享有会员优惠卷1和会员优惠卷2
</div>
</div>
<div v-if="storeList.length > 1">
<div class="level-setting">
<!-- 摊铺选择 -->
<div class="shop-selector" v-if="storeList.length > 1">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="摊铺:">
<el-select v-model="formInline.shopId" placeholder="请选择摊铺::">
<el-form-item label="摊铺名称">
<el-select
v-model="formInline.shopIds"
placeholder="请选择摊铺位名称..."
style="width: 300px"
multiple
collapse-tags
@change="handleShopChange"
>
<el-option
v-for="item in storeList"
:key="item.shopId"
:label="item.shopName"
:value="item.shopId"
></el-option>
>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="getList" type="primary">查询</el-button>
<el-button type="primary" @click="getList">查询</el-button>
<el-button @click="handleBatchLevelSetting"
>批量会员等级编辑</el-button
>
</el-form-item>
</el-form>
</div>
<div class="tipsLevel">
<div>
<span style="margin-right: 30px">全部等级({{ list.length }})</span
><el-button @click="add" type="primary">+新增等级</el-button>
</div>
<div>
<span v-if="!form.effective" style="margin-right: 30px"
>未开通会员</span
>
<span v-if="form.effective" style="margin-right: 30px"
>会员到期时间 {{ form.effectiveEndTime }}</span
>
<el-button @click="addSetMenu" type="primary">购买工具</el-button>
</div>
</div>
<el-table :data="list" :border="true" style="width: 100%">
<el-table-column
width="140"
align="center"
label="等级名称"
prop="levelName"
/>
<el-table-column
width="140"
align="center"
label="所需成长值"
prop="requiredGrowthValue"
/>
<el-table-column
width="140"
align="center"
label="会员人数"
prop="memberCount"
>
</el-table-column>
<el-table-column
align="center"
label="会员权益"
prop="packageEffectiveTimeQuantity"
>
<template slot-scope="scope">
<div>
<span>{{ scope.row.enableMemberDiscount ? "会员折扣," : "" }}</span>
<span>{{
scope.row.enablePointsRedemption ? "积分兑换," : ""
}}</span>
<span>{{
scope.row.enableBirthdayCoupons ? "生日优惠卷," : ""
}}</span>
<span>{{
scope.row.enableBirthdayReward ? "生日双倍积分" : ""
}}</span>
</div>
</template>
</el-table-column>
<!-- <el-table-column align="center" label="操作" fixed="right" width="240"> -->
<!-- <template v-slot="scope">
<el-button @click="add(scope.row)" type="primary">编辑</el-button>
<el-button @click="add(scope.row)" type="primary">转移</el-button>
<el-popconfirm
confirm-button-text="确定"
cancel-button-text="取消"
icon-color="#626AEF"
title="确定删除吗?"
@confirm="confirmEvent(scope.row)"
@cancel="cancelEvent"
<!-- 数据表格 -->
<div class="table-container">
<el-table :data="tableData" border style="width: 100%">
<el-table-column
prop="shopName"
label="摊铺名称"
width="140"
align="center"
>
</el-table-column>
<el-table-column label="是否启用会员" width="140" align="center">
<template slot-scope="scope">
<el-switch
v-model="scope.row.enableMember"
@change="handleMemberToggle(scope.row)"
>
</el-switch>
</template>
</el-table-column>
<el-table-column prop="memberLevels" label="会员等级" align="center">
<template slot-scope="scope">
<span
v-if="scope.row.memberLevels && scope.row.memberLevels.length > 0"
>
{{ scope.row.memberLevels.join(", ") }}
</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="140" align="center">
<template slot-scope="scope">
<el-button
type="primary"
size="mini"
@click="handleLevelSetting(scope.row)"
>
设置等级明细
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 会员等级明细弹窗 -->
<el-dialog
title="会员等级明细"
:visible.sync="levelDialogVisible"
width="80%"
:before-close="handleDialogClose"
>
<div class="level-detail-dialog">
<div class="dialog-header">
<div class="shop-info">
<span>摊铺{{ currentShop.shopName }}</span>
</div>
<div class="dialog-actions">
<el-button type="primary" size="small" @click="handleEditLevel"
>等级编辑</el-button
>
<el-button type="success" size="small" @click="handleSaveLevel"
>提交</el-button
>
</div>
</div>
<!-- 会员等级明细表格 -->
<el-table
:data="levelDetailData"
border
style="width: 100%; margin-top: 20px;"
>
<el-table-column
prop="levelName"
label="等级名称"
width="100"
align="center"
>
<template #reference>
<el-button type="danger">删除</el-button>
<template slot-scope="scope">
<span :style="{ color: getLevelColor(scope.row.levelName) }">
{{ scope.row.levelName }}
</span>
</template>
</el-popconfirm>
</template> -->
<!-- </el-table-column> -->
</el-table>
<!-- 添加 -->
<addOrUpdate @getList="getList" ref="addOrUpdate"></addOrUpdate>
<!-- 添加套餐 -->
<set-menu @getList="getList" ref="setMenu"></set-menu>
</el-table-column>
<el-table-column
prop="requiredGrowthValue"
label="所需成长值"
width="120"
align="center"
>
<template slot-scope="scope">
<span style="color: #1890ff;">{{
scope.row.requiredGrowthValue
}}</span>
</template>
</el-table-column>
<el-table-column
prop="memberCount"
label="会员人数"
width="100"
align="center"
>
<template slot-scope="scope">
<span style="color: #52c41a;">{{ scope.row.memberCount }}</span>
</template>
</el-table-column>
<el-table-column
prop="memberBenefits"
label="会员权益"
align="center"
>
<template slot-scope="scope">
<span style="color: #666;">{{ scope.row.memberBenefits }}</span>
</template>
</el-table-column>
</el-table>
</div>
</el-dialog>
</div>
</template>
<script>
import setMenu from "./popup/set-menu.vue";
import addOrUpdate from "./popup/add-or-update.vue";
import { mapState } from "vuex";
export default {
components: {
addOrUpdate,
setMenu,
},
name: "LevelSetting",
data() {
return {
list: [],
formInline: {
unitType: "",
marketId: "",
shopId: "",
shopIds: []
},
form: {},
tableData: [],
levelDialogVisible: false,
currentShop: {},
levelDetailData: [
{
levelName: "LV1",
requiredGrowthValue: "100",
memberCount: "1,250",
memberBenefits: "新会员双倍积分,享受基础会员价格优惠"
},
{
levelName: "LV2",
requiredGrowthValue: "500",
memberCount: "850",
memberBenefits: "享受9.5折优惠,每月专属优惠券,生日礼品"
},
{
levelName: "LV3",
requiredGrowthValue: "1,200",
memberCount: "450",
memberBenefits: "享受9折优惠免费配送服务专属客服支持"
},
{
levelName: "LV4",
requiredGrowthValue: "2,500",
memberCount: "180",
memberBenefits: "享受8.5折优惠,优先配送,专属活动邀请,年度礼品"
}
]
};
},
created() {
this.formInline = {
unitType:
JSON.parse(sessionStorage.getItem("userInfo")).role == "ROLE_MERCHANT"
? 3
: 2,
marketId: this.marketId,
shopId: this.shopId,
};
this.getList();
},
methods: {
// getData() {
// this.$api.mer_admin
// .storeList({ marketId: this.formInline.marketId })
// .then((res) => {
// this.storeList = res.data.data;
// this.formInline.shopId = res.data.data[0].shopId;
// this.$nextTick(() => {
// this.getList();
// });
// });
// },
getList() {
this.$api.marketing.marketingLevelPage(this.formInline).then((res) => {
this.list = res.data.data ? res.data.data : [];
});
this.$api.marketing.getEffective(this.formInline).then((res) => {
console.log(res);
this.form = res.data.data;
});
},
add() {
this.$refs.addOrUpdate.toggle().add(this.formInline);
},
addSetMenu() {
this.$refs.setMenu.toggle().add(this.formInline);
},
confirmEvent() {},
cancelEvent() {},
},
computed: {
...mapState("userData", [
"isMerchant",
"marketList",
"storeList",
"marketId",
"shopId",
]),
...mapState("userData", ["storeList", "shopId", "marketId"])
},
created() {
this.initData();
},
methods: {
initData() {
//
this.formInline.shopIds = this.storeList.map(store => store.shopId);
this.getList();
},
getList() {
// ID
if (this.formInline.shopIds.length === 0) {
this.tableData = [];
return;
}
const selectedStores = this.storeList.filter(store =>
this.formInline.shopIds.includes(store.shopId)
);
this.tableData = selectedStores.map(store => ({
shopId: store.shopId,
shopName: store.shopName,
enableMember: Math.random() > 0.5, //
memberLevels: this.generateRandomLevels()
}));
},
generateRandomLevels() {
const levels = ["lv1", "lv2", "lv3", "lv4"];
const count = Math.floor(Math.random() * 4) + 1;
return levels.slice(0, count);
},
handleShopChange() {
this.getList();
},
handleMemberToggle(row) {
// /
console.log(
"Toggle member for shop:",
row.shopName,
"Enable:",
row.enableMember
);
// API
},
handleLevelSetting(row) {
this.currentShop = row;
this.levelDialogVisible = true;
},
handleBatchLevelSetting() {
//
this.$message.info("批量会员等级编辑功能待实现");
},
handleDialogClose() {
this.levelDialogVisible = false;
this.currentShop = {};
},
handleEditLevel() {
//
this.$message.info("等级编辑功能待实现");
},
handleSaveLevel() {
//
this.$message.success("等级明细保存成功");
this.handleDialogClose();
},
getLevelColor(levelName) {
const colorMap = {
LV1: "#52c41a",
LV2: "#1890ff",
LV3: "#fa8c16",
LV4: "#f5222d"
};
return colorMap[levelName] || "#666";
}
}
};
</script>
<style scoped lang="scss" >
.tips {
padding: 15px;
margin-bottom: 20px;
border-radius: 10px;
width: 100%;
font-size: 16px;
background: #e5e5e5;
color: #faa639;
}
.tipsLevel {
margin: 20px 0;
display: flex;
justify-content: space-between;
<style lang="scss" scoped>
.level-setting {
.shop-selector {
margin-bottom: 20px;
padding: 15px;
background: #f5f5f5;
border-radius: 4px;
}
.table-container {
.el-table {
.el-switch {
margin: 0;
}
}
}
.level-detail-dialog {
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
.shop-info {
padding: 8px 12px;
background: #f0f9ff;
border-radius: 4px;
color: #1890ff;
font-weight: 500;
}
.dialog-actions {
.el-button {
margin-left: 8px;
}
}
}
.el-table {
.el-table__header {
th {
background-color: #fafafa;
color: #333;
font-weight: 600;
}
}
.el-table__body {
td {
padding: 12px 0;
}
}
}
}
}
</style>

View File

@ -0,0 +1,29 @@
<template>
<div class="mod-config">
<h2>会员列表</h2>
<p>这里是会员列表页面内容</p>
</div>
</template>
<script>
export default {
name: "MemberList",
data() {
return {
//
};
},
created() {
//
},
methods: {
//
}
};
</script>
<style lang="scss" scoped>
.mod-config {
padding: 20px;
}
</style>

View File

@ -0,0 +1,367 @@
<template>
<div class="level-setting">
<!-- 等级设置标题 -->
<div class="header">
<h3>等级设置</h3>
</div>
<!-- 摊铺选择 -->
<div class="shop-selector" v-if="storeList.length > 1">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="摊铺名称">
<el-select
v-model="formInline.shopIds"
placeholder="请选择摊铺位名称..."
style="width: 300px"
multiple
collapse-tags
@change="handleShopChange"
>
<el-option
v-for="item in storeList"
:key="item.shopId"
:label="item.shopName"
:value="item.shopId"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getList">查询</el-button>
<el-button @click="handleBatchLevelSetting"
>批量会员等级编辑</el-button
>
</el-form-item>
</el-form>
</div>
<!-- 数据表格 -->
<div class="table-container">
<el-table :data="tableData" border style="width: 100%">
<el-table-column
prop="shopName"
label="摊铺名称"
width="140"
align="center"
>
</el-table-column>
<el-table-column label="是否启用会员" width="140" align="center">
<template slot-scope="scope">
<el-switch
v-model="scope.row.enableMember"
@change="handleMemberToggle(scope.row)"
>
</el-switch>
</template>
</el-table-column>
<el-table-column prop="memberLevels" label="会员等级" align="center">
<template slot-scope="scope">
<span
v-if="scope.row.memberLevels && scope.row.memberLevels.length > 0"
>
{{ scope.row.memberLevels.join(", ") }}
</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="140" align="center">
<template slot-scope="scope">
<el-button
type="primary"
size="mini"
@click="handleLevelSetting(scope.row)"
>
设置等级明细
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 会员等级明细弹窗 -->
<el-dialog
title="会员等级明细"
:visible.sync="levelDialogVisible"
width="80%"
:before-close="handleDialogClose"
>
<div class="level-detail-dialog">
<div class="dialog-header">
<div class="shop-info">
<span>摊铺{{ currentShop.shopName }}</span>
</div>
<div class="dialog-actions">
<el-button type="primary" size="small" @click="handleEditLevel"
>等级编辑</el-button
>
<el-button type="success" size="small" @click="handleSaveLevel"
>提交</el-button
>
</div>
</div>
<!-- 会员等级明细表格 -->
<el-table
:data="levelDetailData"
border
style="width: 100%; margin-top: 20px;"
>
<el-table-column
prop="levelName"
label="等级名称"
width="100"
align="center"
>
<template slot-scope="scope">
<span :style="{ color: getLevelColor(scope.row.levelName) }">
{{ scope.row.levelName }}
</span>
</template>
</el-table-column>
<el-table-column
prop="requiredGrowthValue"
label="所需成长值"
width="120"
align="center"
>
<template slot-scope="scope">
<span style="color: #1890ff;">{{
scope.row.requiredGrowthValue
}}</span>
</template>
</el-table-column>
<el-table-column
prop="memberCount"
label="会员人数"
width="100"
align="center"
>
<template slot-scope="scope">
<span style="color: #52c41a;">{{ scope.row.memberCount }}</span>
</template>
</el-table-column>
<el-table-column
prop="memberBenefits"
label="会员权益"
align="center"
>
<template slot-scope="scope">
<span style="color: #666;">{{ scope.row.memberBenefits }}</span>
</template>
</el-table-column>
</el-table>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "LevelSetting",
data() {
return {
formInline: {
shopIds: []
},
tableData: [],
levelDialogVisible: false,
currentShop: {},
levelDetailData: [
{
levelName: "LV1",
requiredGrowthValue: "100",
memberCount: "1,250",
memberBenefits: "新会员双倍积分,享受基础会员价格优惠"
},
{
levelName: "LV2",
requiredGrowthValue: "500",
memberCount: "850",
memberBenefits: "享受9.5折优惠,每月专属优惠券,生日礼品"
},
{
levelName: "LV3",
requiredGrowthValue: "1,200",
memberCount: "450",
memberBenefits: "享受9折优惠免费配送服务专属客服支持"
},
{
levelName: "LV4",
requiredGrowthValue: "2,500",
memberCount: "180",
memberBenefits: "享受8.5折优惠,优先配送,专属活动邀请,年度礼品"
}
]
};
},
computed: {
...mapState("userData", ["storeList", "shopId", "marketId"])
},
created() {
this.initData();
},
methods: {
initData() {
//
this.formInline.shopIds = this.storeList.map(store => store.shopId);
this.getList();
},
getList() {
// ID
if (this.formInline.shopIds.length === 0) {
this.tableData = [];
return;
}
const selectedStores = this.storeList.filter(store =>
this.formInline.shopIds.includes(store.shopId)
);
this.tableData = selectedStores.map(store => ({
shopId: store.shopId,
shopName: store.shopName,
enableMember: Math.random() > 0.5, //
memberLevels: this.generateRandomLevels()
}));
},
generateRandomLevels() {
const levels = ["lv1", "lv2", "lv3", "lv4"];
const count = Math.floor(Math.random() * 4) + 1;
return levels.slice(0, count);
},
handleShopChange() {
this.getList();
},
handleMemberToggle(row) {
// /
console.log(
"Toggle member for shop:",
row.shopName,
"Enable:",
row.enableMember
);
// API
},
handleLevelSetting(row) {
this.currentShop = row;
this.levelDialogVisible = true;
},
handleBatchLevelSetting() {
//
this.$message.info("批量会员等级编辑功能待实现");
},
handleDialogClose() {
this.levelDialogVisible = false;
this.currentShop = {};
},
handleEditLevel() {
//
this.$message.info("等级编辑功能待实现");
},
handleSaveLevel() {
//
this.$message.success("等级明细保存成功");
this.handleDialogClose();
},
getLevelColor(levelName) {
const colorMap = {
LV1: "#52c41a",
LV2: "#1890ff",
LV3: "#fa8c16",
LV4: "#f5222d"
};
return colorMap[levelName] || "#666";
}
}
};
</script>
<style lang="scss" scoped>
.level-setting {
padding: 20px;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
}
.dropdown-container {
color: #999;
font-size: 14px;
}
}
.shop-selector {
margin-bottom: 20px;
padding: 15px;
background: #f5f5f5;
border-radius: 4px;
}
.table-container {
.el-table {
.el-switch {
margin: 0;
}
}
}
.level-detail-dialog {
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
.shop-info {
padding: 8px 12px;
background: #f0f9ff;
border-radius: 4px;
color: #1890ff;
font-weight: 500;
}
.dialog-actions {
.el-button {
margin-left: 8px;
}
}
}
.el-table {
.el-table__header {
th {
background-color: #fafafa;
color: #333;
font-weight: 600;
}
}
.el-table__body {
td {
padding: 12px 0;
}
}
}
}
}
</style>