sc
This commit is contained in:
@@ -2,8 +2,17 @@ import request from '@/utils/request';
|
|||||||
|
|
||||||
export const getRulesInfo = params => {
|
export const getRulesInfo = params => {
|
||||||
return request({
|
return request({
|
||||||
url: '/applet/xunjia/tenant/get',
|
url: '/applet/xunjia/profit/rule/person/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 保存规则
|
||||||
|
export const saveRulesInfo = data => {
|
||||||
|
return request({
|
||||||
|
url: '/applet/xunjia/profit/rule/batch/save',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
19
src/api/member/code.js
Normal file
19
src/api/member/code.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 生成会员码
|
||||||
|
export const createVipCode = async data => {
|
||||||
|
return await request({
|
||||||
|
url: '/applet/xunjia/member/code/create',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取会员码列表
|
||||||
|
export const getVipCodeList = async params => {
|
||||||
|
return await request({
|
||||||
|
url: '/applet/xunjia/member/code/page',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
};
|
||||||
37
src/api/member/quota.js
Normal file
37
src/api/member/quota.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 获得租户每月会员额度配置
|
||||||
|
export const getQuotaInfoWithMonth = async params => {
|
||||||
|
return await request({
|
||||||
|
url: '/applet/xunjia/tenant/get-memberNum',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存会员额度分配
|
||||||
|
export const saveQuotaInfo = async data => {
|
||||||
|
return await request({
|
||||||
|
url: '/applet/xunjia/member/quota/save',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获得个人会员额度分配
|
||||||
|
export const getQuotaInfoWithUser = async params => {
|
||||||
|
return await request({
|
||||||
|
url: '/applet/xunjia/member/quota/person/get',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获得会员额度分配列表
|
||||||
|
export const getQuotaList = async params => {
|
||||||
|
return await request({
|
||||||
|
url: '/applet/xunjia/member/quota/list',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -40,14 +40,7 @@
|
|||||||
<view class="quota-item">
|
<view class="quota-item">
|
||||||
<view class="quota-label">月度赠会员总额度</view>
|
<view class="quota-label">月度赠会员总额度</view>
|
||||||
<view class="quota-control">
|
<view class="quota-control">
|
||||||
<input
|
<view class="quota-value">{{ totalQuota }}</view>
|
||||||
v-model="totalQuota"
|
|
||||||
type="number"
|
|
||||||
class="quota-input"
|
|
||||||
placeholder="请输入总额度"
|
|
||||||
min="0"
|
|
||||||
max="1000"
|
|
||||||
/>
|
|
||||||
<view class="quota-unit">个</view>
|
<view class="quota-unit">个</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -68,17 +61,17 @@
|
|||||||
class="quota-item"
|
class="quota-item"
|
||||||
>
|
>
|
||||||
<view class="distributor-info">
|
<view class="distributor-info">
|
||||||
<view class="distributor-name">{{ distributor.name }}</view>
|
<view class="distributor-name">{{ distributor.distributorName }}</view>
|
||||||
<view class="distributor-id">ID: {{ distributor.id }}</view>
|
<view class="distributor-id">ID: {{ distributor.distributorId }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="quota-control">
|
<view class="quota-control">
|
||||||
<input
|
<input
|
||||||
v-model="distributor.quota"
|
v-model="distributor.num"
|
||||||
type="number"
|
type="number"
|
||||||
class="quota-input"
|
class="quota-input"
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
min="0"
|
min="0"
|
||||||
:max="maxDistributorQuota"
|
:max="maxDistributorQuota(distributor.num)"
|
||||||
/>
|
/>
|
||||||
<view class="quota-unit">个</view>
|
<view class="quota-unit">个</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -104,10 +97,11 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from "vue"
|
import { ref, computed, onMounted } from "vue"
|
||||||
|
import { getQuotaInfoWithUser, saveQuotaInfo, getQuotaList } from "@/api/member/quota"
|
||||||
|
|
||||||
// 当前月份
|
// 当前月份
|
||||||
const currentMonth = ref('2026-01')
|
const currentMonth = ref(new Date().toISOString().substring(0, 7))
|
||||||
const currentMonthDisplay = ref('2026年01月')
|
const currentMonthDisplay = ref(new Date().toISOString().substring(0, 7))
|
||||||
|
|
||||||
// 总额度
|
// 总额度
|
||||||
const totalQuota = ref(100)
|
const totalQuota = ref(100)
|
||||||
@@ -136,15 +130,26 @@
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
// 计算单个分销员最大可分配额度
|
const loadCurrentMonthQuota = () => {
|
||||||
const maxDistributorQuota = computed(() => {
|
getQuotaInfoWithUser({
|
||||||
return Math.floor(totalQuota.value * 0.5)
|
year: currentMonth.value.split('-')[0],
|
||||||
|
month: currentMonth.value.split('-')[1]
|
||||||
|
}).then(res => {
|
||||||
|
totalQuota.value = res.data.num || 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
getQuotaList({
|
||||||
|
year: currentMonth.value.split('-')[0],
|
||||||
|
month: currentMonth.value.split('-')[1]
|
||||||
|
}).then(res => {
|
||||||
|
distributors.value = res.data || []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 计算已分配额度
|
// 计算已分配额度
|
||||||
const allocatedQuota = computed(() => {
|
const allocatedQuota = computed(() => {
|
||||||
return distributors.value.reduce((sum, distributor) => {
|
return distributors.value.reduce((sum, distributor) => {
|
||||||
return sum + parseInt(distributor.quota || 0)
|
return sum + parseInt(distributor.num || 0)
|
||||||
}, 0)
|
}, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -153,6 +158,10 @@
|
|||||||
return totalQuota.value - allocatedQuota.value
|
return totalQuota.value - allocatedQuota.value
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const maxDistributorQuota = (count) => {
|
||||||
|
return remainingQuota.value ? count + remainingQuota.value : count
|
||||||
|
}
|
||||||
|
|
||||||
// 返回上一页
|
// 返回上一页
|
||||||
function goBack() {
|
function goBack() {
|
||||||
uni.navigateBack({ delta: 1 })
|
uni.navigateBack({ delta: 1 })
|
||||||
@@ -162,9 +171,8 @@
|
|||||||
function onMonthChange(e) {
|
function onMonthChange(e) {
|
||||||
currentMonth.value = e.detail.value
|
currentMonth.value = e.detail.value
|
||||||
const date = new Date(e.detail.value)
|
const date = new Date(e.detail.value)
|
||||||
currentMonthDisplay.value = `${date.getFullYear()}年${String(date.getMonth() + 1).padStart(2, '0')}月`
|
currentMonthDisplay.value = new Date(date).toISOString().substring(0, 7)
|
||||||
// 实际项目中应根据选择的月份加载对应的额度配置
|
loadCurrentMonthQuota()
|
||||||
// loadQuotaByMonth(currentMonth.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存配额
|
// 保存配额
|
||||||
@@ -187,22 +195,26 @@
|
|||||||
|
|
||||||
uni.showLoading({ title: '保存中...' })
|
uni.showLoading({ title: '保存中...' })
|
||||||
|
|
||||||
setTimeout(() => {
|
saveQuotaInfo({
|
||||||
|
year: currentMonth.value.split('-')[0],
|
||||||
|
month: currentMonth.value.split('-')[1],
|
||||||
|
nums: distributors.value.map(distributor => {
|
||||||
|
return {
|
||||||
|
distributorId: distributor.distributorId,
|
||||||
|
num: distributor.num
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).then(() => {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '保存成功',
|
title: '保存成功',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
|
})
|
||||||
// 实际项目中应调用接口保存配额配置
|
|
||||||
// saveQuotaConfig()
|
|
||||||
}, 1500)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 实际项目中应从接口获取分销员列表和当前月份的配额配置
|
loadCurrentMonthQuota()
|
||||||
// loadDistributors()
|
|
||||||
// loadCurrentMonthQuota()
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,11 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="rule-card">
|
<view class="rule-card">
|
||||||
<!-- 注册分润 -->
|
<!-- 注册分润 -->
|
||||||
<view class="rule-item" v-for="(rule, idx) in profitRules" :key="rule.id || idx">
|
<view class="rule-item" v-for="(rule, idx) in profitRules" :key="idx">
|
||||||
<view class="rule-header">
|
<view class="rule-header">
|
||||||
<view class="rule-title">
|
<view class="rule-title">
|
||||||
{{ rule.type === 'register' ? '注册分润' : '消费分润' }}
|
{{ rule.profitScene== '1' ? '注册分润' : '消费分润' }}
|
||||||
<view v-if="rule.type === 'consume'" class="rule-actions">
|
<view v-if="rule.profitScene== '2'" class="rule-actions">
|
||||||
<view class="delete-btn" @click="deleteConsumeRule(idx)">
|
<view class="delete-btn" @click="deleteConsumeRule(idx)">
|
||||||
<text style="color: #f56c6c; font-size: 24rpx;">删除</text>
|
<text style="color: #f56c6c; font-size: 24rpx;">删除</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -44,9 +44,13 @@
|
|||||||
<view class="rule-toggle">
|
<view class="rule-toggle">
|
||||||
<view class="rule-control">
|
<view class="rule-control">
|
||||||
<radio-group @change="e => onProfitTypeChange(idx, e.detail.value)">
|
<radio-group @change="e => onProfitTypeChange(idx, e.detail.value)">
|
||||||
<label v-for="(option, index) in profitTypeOptions" :key="index" class="radio-item">
|
<label class="radio-item">
|
||||||
<radio :value="option.value" :checked="rule.profitType === option.value" />
|
<radio value="1" :checked="rule.profitType== '1'" />
|
||||||
<text class="radio-label">{{ option.label }}</text>
|
<text class="radio-label">固定金额</text>
|
||||||
|
</label>
|
||||||
|
<label class="radio-item" v-if="rule.profitScene== '2'">
|
||||||
|
<radio value="2" :checked="rule.profitType== '2'" />
|
||||||
|
<text class="radio-label">比例分润</text>
|
||||||
</label>
|
</label>
|
||||||
</radio-group>
|
</radio-group>
|
||||||
</view>
|
</view>
|
||||||
@@ -57,7 +61,7 @@
|
|||||||
<view class="rule-label">分润金额</view>
|
<view class="rule-label">分润金额</view>
|
||||||
<view class="rule-control">
|
<view class="rule-control">
|
||||||
<input
|
<input
|
||||||
v-model="rule.amount"
|
v-model="rule.profitValue"
|
||||||
type="number"
|
type="number"
|
||||||
class="rule-input"
|
class="rule-input"
|
||||||
placeholder="请输入分润金额"
|
placeholder="请输入分润金额"
|
||||||
@@ -72,7 +76,7 @@
|
|||||||
<view class="rule-label">分润比例</view>
|
<view class="rule-label">分润比例</view>
|
||||||
<view class="rule-control">
|
<view class="rule-control">
|
||||||
<input
|
<input
|
||||||
v-model="rule.percentage"
|
v-model="rule.profitValue"
|
||||||
type="number"
|
type="number"
|
||||||
class="rule-input"
|
class="rule-input"
|
||||||
placeholder="请输入分润比例"
|
placeholder="请输入分润比例"
|
||||||
@@ -85,13 +89,13 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 消费分润VIP选择 -->
|
<!-- 消费分润VIP选择 -->
|
||||||
<view v-if="rule.type === 'consume'">
|
<view v-if="rule.profitScene == '2'">
|
||||||
<view class="rule-label" style="margin-bottom: 10rpx;">选择会员类型</view>
|
<view class="rule-label" style="margin-bottom: 10rpx;">选择会员类型</view>
|
||||||
<view class="rule-control">
|
<view class="rule-control">
|
||||||
<view class="vip-list">
|
<view class="vip-list">
|
||||||
<label v-for="vip in vipList" :key="vip.memberId" class="vip-item checkbox-item"
|
<label v-for="vip in vipList" :key="vip.memberId" class="vip-item checkbox-item"
|
||||||
@click="onVipChange(idx, vip.memberId)">
|
@click="onVipChange(idx, vip.memberId)">
|
||||||
<view class="custom-checkbox" :class="{ 'checked': rule.selectedVips && rule.selectedVips.includes(vip.memberId), 'disabled': isVipSelectedInOtherRules(idx, vip.memberId) }"></view>
|
<view class="custom-checkbox" :class="{ 'checked': rule.memberIds && rule.memberIds.includes(vip.memberId), 'disabled': isVipSelectedInOtherRules(idx, vip.memberId) }"></view>
|
||||||
<view class="checkbox-label" :class="{ 'disabled': isVipSelectedInOtherRules(idx, vip.memberId) }">
|
<view class="checkbox-label" :class="{ 'disabled': isVipSelectedInOtherRules(idx, vip.memberId) }">
|
||||||
<view v-if="vip.carName" class="car-tag">{{ vip.carName }}</view>
|
<view v-if="vip.carName" class="car-tag">{{ vip.carName }}</view>
|
||||||
<text>{{ vip.memberName || '' }}</text>
|
<text>{{ vip.memberName || '' }}</text>
|
||||||
@@ -115,41 +119,50 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from "vue"
|
import { ref } from "vue"
|
||||||
|
import { onLoad } from "@dcloudio/uni-app"
|
||||||
import { getVipTypeList } from "@/api/member"
|
import { getVipTypeList } from "@/api/member"
|
||||||
|
import { getRulesInfo, saveRulesInfo } from "@/api/distribution"
|
||||||
|
|
||||||
// 分润规则数组
|
// 分润规则数组
|
||||||
const profitRules = ref([
|
const profitRules = ref([
|
||||||
{
|
{
|
||||||
type: 'register', // 注册分润
|
profitScene: '1', // 注册分润
|
||||||
profitType: '1', // 固定金额
|
profitType: '1', // 固定金额
|
||||||
amount: 10,
|
profitValue: 0
|
||||||
percentage: 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: Date.now(), // 唯一标识
|
profitScene: '2', // 消费分润
|
||||||
type: 'consume', // 消费分润
|
|
||||||
profitType: '2', // 比例分润
|
profitType: '2', // 比例分润
|
||||||
amount: 0,
|
profitValue: 20,
|
||||||
percentage: 20,
|
memberIds: [] // 选中的VIP
|
||||||
selectedVips: [] // 选中的VIP
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const vipList = ref([])
|
const vipList = ref([])
|
||||||
|
|
||||||
// 分润方式选项
|
const distributorId = ref('')
|
||||||
const profitTypeOptions = [{ label: '固定金额', value: '1' }, { label: '比例分润', value: '2' }]
|
|
||||||
|
|
||||||
onMounted(() => {
|
onLoad((options) => {
|
||||||
// 实际项目中应从接口获取分润规则配置
|
distributorId.value = options.id
|
||||||
// loadProfitRules()
|
loadProfitRules(distributorId.value )
|
||||||
|
|
||||||
getVipTypeList().then(res => {
|
getVipTypeList().then(res => {
|
||||||
vipList.value = res.data?.list?.filter(item => item.useTypes.includes(1)) || []
|
vipList.value = res.data?.list?.filter(item => item.useTypes.includes(1)) || []
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 加载规则
|
||||||
|
function loadProfitRules() {
|
||||||
|
getRulesInfo({
|
||||||
|
distributorId: distributorId.value
|
||||||
|
}).then(res => {
|
||||||
|
profitRules.value = res.data || []
|
||||||
|
// 初始化消费分润的会员选中状态
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 返回上一页
|
// 返回上一页
|
||||||
function goBack() {
|
function goBack() {
|
||||||
uni.navigateBack({ delta: 1 })
|
uni.navigateBack({ delta: 1 })
|
||||||
@@ -162,17 +175,16 @@ const vipList = ref([])
|
|||||||
content: '确定要保存分润规则配置吗?',
|
content: '确定要保存分润规则配置吗?',
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
uni.showLoading({ title: '保存中...' })
|
saveRulesInfo({
|
||||||
|
distributorId: distributorId.value,
|
||||||
setTimeout(() => {
|
ruleList: profitRules.value
|
||||||
uni.hideLoading()
|
}).then(res => {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '保存成功',
|
title: '保存成功',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
// 实际项目中应调用接口保存分润规则
|
goBack()
|
||||||
// saveProfitRules()
|
})
|
||||||
}, 1500)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -184,10 +196,10 @@ const vipList = ref([])
|
|||||||
if (rule) {
|
if (rule) {
|
||||||
rule.profitType = profitType
|
rule.profitType = profitType
|
||||||
// 重置对应的值
|
// 重置对应的值
|
||||||
if (profitType === '1') {
|
if (profitType== '1') {
|
||||||
rule.percentage = 0
|
rule.profitValue = 0
|
||||||
} else if (profitType === '2') {
|
} else if (profitType== '2') {
|
||||||
rule.amount = 0
|
rule.profitValue = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,15 +210,15 @@ const vipList = ref([])
|
|||||||
id: Date.now(), // 唯一标识
|
id: Date.now(), // 唯一标识
|
||||||
type: 'consume', // 消费分润
|
type: 'consume', // 消费分润
|
||||||
profitType: '2', // 比例分润
|
profitType: '2', // 比例分润
|
||||||
amount: 0,
|
profitValue: 0,
|
||||||
percentage: 20,
|
profitValue: 20,
|
||||||
selectedVips: [] // 选中的VIP
|
memberIds: [] // 选中的VIP
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除消费分润规则
|
// 删除消费分润规则
|
||||||
function deleteConsumeRule(idx) {
|
function deleteConsumeRule(idx) {
|
||||||
if (profitRules.value[idx].type === 'consume') {
|
if (profitRules.value[idx].type== 'consume') {
|
||||||
profitRules.value.splice(idx, 1)
|
profitRules.value.splice(idx, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,9 +226,9 @@ const vipList = ref([])
|
|||||||
// 检查会员类型是否在其他消费分润规则中被选中
|
// 检查会员类型是否在其他消费分润规则中被选中
|
||||||
function isVipSelectedInOtherRules(currentIdx, vipId) {
|
function isVipSelectedInOtherRules(currentIdx, vipId) {
|
||||||
return profitRules.value.some((otherRule, otherIdx) => {
|
return profitRules.value.some((otherRule, otherIdx) => {
|
||||||
return otherIdx !== currentIdx &&
|
return otherIdx != currentIdx &&
|
||||||
otherRule.type === 'consume' &&
|
otherRule.profitScene == '2' &&
|
||||||
otherRule.selectedVips.includes(vipId)
|
otherRule.memberIds.includes(vipId)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,20 +237,20 @@ const vipList = ref([])
|
|||||||
if (profitRules.value[idx]) {
|
if (profitRules.value[idx]) {
|
||||||
const rule = profitRules.value[idx]
|
const rule = profitRules.value[idx]
|
||||||
// 确保selectedVips存在
|
// 确保selectedVips存在
|
||||||
if (!rule.selectedVips) {
|
if (!rule.memberIds) {
|
||||||
rule.selectedVips = []
|
rule.memberIds = []
|
||||||
}
|
}
|
||||||
|
|
||||||
const vipIndex = rule.selectedVips.indexOf(vipId)
|
const vipIndex = rule.memberIds.indexOf(vipId)
|
||||||
if (vipIndex > -1) {
|
if (vipIndex > -1) {
|
||||||
// 取消选择
|
// 取消选择
|
||||||
rule.selectedVips.splice(vipIndex, 1)
|
rule.memberIds.splice(vipIndex, 1)
|
||||||
} else {
|
} else {
|
||||||
// 检查是否在其他消费分润规则中已选中
|
// 检查是否在其他消费分润规则中已选中
|
||||||
const isDuplicate = isVipSelectedInOtherRules(idx, vipId)
|
const isDuplicate = isVipSelectedInOtherRules(idx, vipId)
|
||||||
|
|
||||||
if (!isDuplicate) {
|
if (!isDuplicate) {
|
||||||
rule.selectedVips.push(vipId)
|
rule.memberIds.push(vipId)
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '该会员类型已在其他规则中选中',
|
title: '该会员类型已在其他规则中选中',
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
<view class="back-icon">←</view>
|
<view class="back-icon">←</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="header-title">赠送会员管理</view>
|
<view class="header-title">赠送会员管理</view>
|
||||||
<view class="header-right" @click="generateBatchCode">
|
<view class="header-right">
|
||||||
<view class="batch-btn">批量生成</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -20,11 +19,12 @@
|
|||||||
<view class="generate-control">
|
<view class="generate-control">
|
||||||
<picker
|
<picker
|
||||||
:range="memberTypeOptions"
|
:range="memberTypeOptions"
|
||||||
|
:range-key="'memberName'"
|
||||||
:value="memberTypeIndex"
|
:value="memberTypeIndex"
|
||||||
@change="onMemberTypeChange"
|
@change="onMemberTypeChange"
|
||||||
class="picker"
|
class="picker"
|
||||||
>
|
>
|
||||||
<view class="picker-text">{{ memberTypeOptions[memberTypeIndex] }}</view>
|
<view class="picker-text">{{ memberTypeOptions[memberTypeIndex]?.memberName || '请选择' }}</view>
|
||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -41,17 +41,6 @@
|
|||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="generate-row">
|
|
||||||
<view class="generate-label">有效期</view>
|
|
||||||
<view class="generate-control">
|
|
||||||
<input
|
|
||||||
v-model="validityPeriod"
|
|
||||||
class="period-input"
|
|
||||||
placeholder="请选择有效期"
|
|
||||||
@click="showDatePicker"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="generate-action">
|
<view class="generate-action">
|
||||||
<view class="action-btn primary-btn" @click="generateCode">
|
<view class="action-btn primary-btn" @click="generateCode">
|
||||||
生成核验码
|
生成核验码
|
||||||
@@ -71,25 +60,25 @@
|
|||||||
>
|
>
|
||||||
<view class="code-header">
|
<view class="code-header">
|
||||||
<view class="code-value">{{ code.code }}</view>
|
<view class="code-value">{{ code.code }}</view>
|
||||||
<view class="code-status" :class="code.statusClass">{{ code.status }}</view>
|
<view class="code-status" :class="getStatusClass(code)">{{ getStatusText(code) }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="code-body">
|
<view class="code-body">
|
||||||
<view class="code-info">
|
<view class="code-info">
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<view class="info-label">会员类型:</view>
|
<view class="info-label">会员类型:</view>
|
||||||
<view class="info-value">{{ code.memberType }}</view>
|
<view class="info-value">{{ getMemberName(code.memberId) }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<view class="info-label">生成时间:</view>
|
<view class="info-label">生成时间:</view>
|
||||||
<view class="info-value">{{ code.createTime }}</view>
|
<view class="info-value">{{ new Date(code.createTime).toLocaleString() }}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="info-item">
|
<view class="info-item" v-if="code.writeOffTime">
|
||||||
<view class="info-label">有效期至:</view>
|
|
||||||
<view class="info-value">{{ code.validUntil }}</view>
|
|
||||||
</view>
|
|
||||||
<view class="info-item" v-if="code.usedTime">
|
|
||||||
<view class="info-label">使用时间:</view>
|
<view class="info-label">使用时间:</view>
|
||||||
<view class="info-value">{{ code.usedTime }}</view>
|
<view class="info-value">{{ new Date(code.writeOffTime).toLocaleString() }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="info-item" v-if="code.writeOffUser">
|
||||||
|
<view class="info-label">使用人:</view>
|
||||||
|
<view class="info-value">{{ code.writeOffUser }}</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -98,9 +87,6 @@
|
|||||||
<view class="action-btn copy-btn" @click="copyCode(code.code)">
|
<view class="action-btn copy-btn" @click="copyCode(code.code)">
|
||||||
复制
|
复制
|
||||||
</view>
|
</view>
|
||||||
<view class="action-btn delete-btn" @click="deleteCode(code.id)">
|
|
||||||
删除
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -108,7 +94,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
<view v-if="codeList.length === 0" class="empty-state">
|
<view v-if="codeList.length == 0" class="empty-state">
|
||||||
<view class="empty-icon">🎁</view>
|
<view class="empty-icon">🎁</view>
|
||||||
<view class="empty-text">暂无核验码数据</view>
|
<view class="empty-text">暂无核验码数据</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -121,14 +107,14 @@
|
|||||||
<view class="page-controls">
|
<view class="page-controls">
|
||||||
<view
|
<view
|
||||||
class="page-btn"
|
class="page-btn"
|
||||||
:class="{ disabled: currentPage === 1 }"
|
:class="{ disabled: currentPage == 1 }"
|
||||||
@click="goToPage(currentPage - 1)"
|
@click="goToPage(currentPage - 1)"
|
||||||
>
|
>
|
||||||
上一页
|
上一页
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
class="page-btn"
|
class="page-btn"
|
||||||
:class="{ disabled: currentPage === totalPages }"
|
:class="{ disabled: currentPage == totalPages }"
|
||||||
@click="goToPage(currentPage + 1)"
|
@click="goToPage(currentPage + 1)"
|
||||||
>
|
>
|
||||||
下一页
|
下一页
|
||||||
@@ -140,52 +126,23 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from "vue"
|
import { ref, computed, onMounted } from "vue"
|
||||||
|
import { createVipCode, getVipCodeList } from "@/api/member/code"
|
||||||
|
import { getVipTypeList } from "@/api/member"
|
||||||
|
|
||||||
// 会员类型选项
|
// 会员类型选项
|
||||||
const memberTypeOptions = ['月度会员', '季度会员', '年度会员']
|
const memberTypeOptions = ref([])
|
||||||
const memberTypeIndex = ref(0)
|
const memberTypeIndex = ref(0)
|
||||||
|
|
||||||
// 生成数量
|
// 生成数量
|
||||||
const generateCount = ref('1')
|
const generateCount = ref('1')
|
||||||
|
|
||||||
// 有效期
|
|
||||||
const validityPeriod = ref('')
|
|
||||||
|
|
||||||
// 核验码列表数据
|
// 核验码列表数据
|
||||||
const codeList = ref([
|
const codeList = ref([])
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
code: 'GC20260129001',
|
|
||||||
memberType: '月度会员',
|
|
||||||
createTime: '2026-01-29 15:30:00',
|
|
||||||
validUntil: '2026-02-29 23:59:59',
|
|
||||||
status: '未使用',
|
|
||||||
statusClass: 'status-unused'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
code: 'GC20260129002',
|
|
||||||
memberType: '季度会员',
|
|
||||||
createTime: '2026-01-29 14:20:00',
|
|
||||||
validUntil: '2026-04-29 23:59:59',
|
|
||||||
status: '已使用',
|
|
||||||
statusClass: 'status-used',
|
|
||||||
usedTime: '2026-01-29 14:30:00'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
code: 'GC20260129003',
|
|
||||||
memberType: '年度会员',
|
|
||||||
createTime: '2026-01-29 13:10:00',
|
|
||||||
validUntil: '2027-01-29 23:59:59',
|
|
||||||
status: '已过期',
|
|
||||||
statusClass: 'status-expired'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
// 分页信息
|
// 分页信息
|
||||||
const currentPage = ref(1)
|
const currentPage = ref(1)
|
||||||
const totalCodes = ref(100)
|
const totalCodes = ref(0)
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(10)
|
||||||
|
|
||||||
// 计算总页数
|
// 计算总页数
|
||||||
@@ -194,67 +151,39 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 实际项目中应从接口获取核验码列表
|
getVipTypeList().then(res => {
|
||||||
// loadCodeList()
|
if (res.code == 0) {
|
||||||
|
memberTypeOptions.value = res.data.list
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
loadCodeList()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 加载核验码列表
|
||||||
|
function loadCodeList() {
|
||||||
|
getVipCodeList({
|
||||||
|
pageNo: currentPage.value,
|
||||||
|
pageSize: pageSize.value
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code == 0) {
|
||||||
|
codeList.value = res.data.list
|
||||||
|
totalCodes.value = res.data.total
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 返回上一页
|
// 返回上一页
|
||||||
function goBack() {
|
function goBack() {
|
||||||
uni.navigateBack({ delta: 1 })
|
uni.navigateBack({ delta: 1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量生成
|
|
||||||
function generateBatchCode() {
|
|
||||||
uni.showModal({
|
|
||||||
title: '批量生成核验码',
|
|
||||||
content: '请输入要生成的核验码数量',
|
|
||||||
editable: true,
|
|
||||||
placeholderText: '请输入数量',
|
|
||||||
success: function(res) {
|
|
||||||
if (res.confirm && res.content) {
|
|
||||||
const count = parseInt(res.content)
|
|
||||||
if (isNaN(count) || count <= 0 || count > 100) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '请输入1-100之间的数字',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.showLoading({ title: '生成中...' })
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
|
||||||
title: `成功生成${count}个核验码`,
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
// 实际项目中应调用接口批量生成核验码
|
|
||||||
// generateBatchCodes(count)
|
|
||||||
}, 1500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 会员类型变更
|
// 会员类型变更
|
||||||
function onMemberTypeChange(e) {
|
function onMemberTypeChange(e) {
|
||||||
const value = e.detail.value
|
const value = e.detail.value
|
||||||
memberTypeIndex.value = value
|
memberTypeIndex.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示日期选择器
|
|
||||||
function showDatePicker() {
|
|
||||||
const now = new Date()
|
|
||||||
uni.showDatePicker({
|
|
||||||
year: now.getFullYear(),
|
|
||||||
month: now.getMonth(),
|
|
||||||
day: now.getDate(),
|
|
||||||
success: function(res) {
|
|
||||||
validityPeriod.value = `${res.year}-${res.month + 1}-${res.day}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成核验码
|
// 生成核验码
|
||||||
function generateCode() {
|
function generateCode() {
|
||||||
@@ -266,25 +195,22 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validityPeriod.value) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '请选择有效期',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.showLoading({ title: '生成中...' })
|
uni.showLoading({ title: '生成中...' })
|
||||||
|
|
||||||
setTimeout(() => {
|
createVipCode({
|
||||||
|
memberId: memberTypeOptions.value[memberTypeIndex.value].memberId,
|
||||||
|
num: parseInt(generateCount.value),
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code == 0) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '核验码生成成功',
|
title: '核验码生成成功',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
// 实际项目中应调用接口生成核验码
|
loadCodeList()
|
||||||
// generateVerificationCode()
|
}
|
||||||
}, 1500)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制核验码
|
// 复制核验码
|
||||||
@@ -308,7 +234,7 @@
|
|||||||
success: function(res) {
|
success: function(res) {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
// 实际项目中应调用接口删除核验码
|
// 实际项目中应调用接口删除核验码
|
||||||
const index = codeList.value.findIndex(item => item.id === id)
|
const index = codeList.value.findIndex(item => item.id == id)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
codeList.value.splice(index, 1)
|
codeList.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
@@ -330,6 +256,34 @@
|
|||||||
// 实际项目中应加载指定页码的核验码
|
// 实际项目中应加载指定页码的核验码
|
||||||
// loadCodePage(page)
|
// loadCodePage(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取状态文本
|
||||||
|
function getStatusText(code) {
|
||||||
|
if (code.isExpired == 1) {
|
||||||
|
return '已过期'
|
||||||
|
} else if (code.isWrittenOff == 1) {
|
||||||
|
return '已使用'
|
||||||
|
} else {
|
||||||
|
return '未使用'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取状态样式类
|
||||||
|
function getStatusClass(code) {
|
||||||
|
if (code.isExpired == 1) {
|
||||||
|
return 'status-expired'
|
||||||
|
} else if (code.isWrittenOff == 1) {
|
||||||
|
return 'status-used'
|
||||||
|
} else {
|
||||||
|
return 'status-unused'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据memberId获取会员类型名称
|
||||||
|
function getMemberName(memberId) {
|
||||||
|
const memberType = memberTypeOptions.value.find(item => item.memberId == memberId)
|
||||||
|
return memberType?.memberName || '未知'
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -363,6 +317,7 @@
|
|||||||
height: 120rpx;
|
height: 120rpx;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 0 32rpx;
|
padding: 0 32rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,7 +502,7 @@
|
|||||||
|
|
||||||
.info-label {
|
.info-label {
|
||||||
color: #606266;
|
color: #606266;
|
||||||
width: 120rpx;
|
width: 140rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-value {
|
.info-value {
|
||||||
|
|||||||
Reference in New Issue
Block a user