fetch(modify):修改bug
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m45s

This commit is contained in:
sexygoat
2026-02-05 17:22:41 +08:00
parent d97dc5f007
commit b94c043a56
24 changed files with 2734 additions and 446 deletions

View File

@@ -6,6 +6,7 @@
v-model:filter="searchForm"
:items="searchFormItems"
:show-expand="false"
label-width="85"
@reset="handleReset"
@search="handleSearch"
></ArtSearchBar>
@@ -18,7 +19,9 @@
@refresh="handleRefresh"
>
<template #left>
<ElButton type="primary" @click="showDialog('add')" v-permission="'package_series:add'">新增套餐系列</ElButton>
<ElButton type="primary" @click="showDialog('add')" v-permission="'package_series:add'"
>新增套餐系列</ElButton
>
</template>
</ArtTableHeader>
@@ -44,18 +47,18 @@
<ElDialog
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增套餐系列' : '编辑套餐系列'"
width="500px"
width="45%"
:close-on-click-modal="false"
>
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
<ElFormItem label="系列编码" prop="series_code">
<div style="display: flex; gap: 8px;">
<div style="display: flex; gap: 8px">
<ElInput
v-model="form.series_code"
placeholder="请输入系列编码或点击生成"
:disabled="dialogType === 'edit'"
clearable
style="flex: 1;"
style="flex: 1"
/>
<ElButton v-if="dialogType === 'add'" @click="handleGenerateSeriesCode">
生成编码
@@ -75,6 +78,261 @@
show-word-limit
/>
</ElFormItem>
<!-- 一次性佣金配置 -->
<div class="form-section-title">
<span class="title-text">一次性佣金配置</span>
</div>
<ElFormItem label="启用一次性佣金">
<ElSwitch
v-model="form.one_time_commission_config.enable"
active-text="启用"
inactive-text="不启用"
/>
</ElFormItem>
<template v-if="form.one_time_commission_config.enable">
<!-- 佣金类型 -->
<ElFormItem label="佣金类型">
<ElRadioGroup v-model="form.one_time_commission_config.commission_type">
<ElRadio value="fixed">固定佣金</ElRadio>
<ElRadio value="tiered">梯度佣金</ElRadio>
</ElRadioGroup>
</ElFormItem>
<!-- 触发阈值 -->
<ElFormItem label="触发阈值">
<ElInputNumber
v-model="form.one_time_commission_config.threshold"
:min="0"
:precision="2"
placeholder="触发阈值(元)"
style="width: 100%"
/>
<span
style="color: var(--el-text-color-secondary); font-size: 12px; margin-left: 8px"
>单位</span
>
</ElFormItem>
<!-- 触发类型 -->
<ElFormItem label="触发类型">
<ElRadioGroup v-model="form.one_time_commission_config.trigger_type">
<ElRadio value="first_recharge">首次充值</ElRadio>
<ElRadio value="accumulated_recharge">累计充值</ElRadio>
</ElRadioGroup>
</ElFormItem>
<!-- 固定佣金金额 -->
<ElFormItem
v-if="form.one_time_commission_config.commission_type === 'fixed'"
label="佣金金额"
>
<ElInputNumber
v-model="form.one_time_commission_config.commission_amount"
:min="0"
:precision="2"
placeholder="佣金金额(元)"
style="width: 100%"
/>
<span
style="color: var(--el-text-color-secondary); font-size: 12px; margin-left: 8px"
>单位</span
>
</ElFormItem>
<!-- 梯度佣金配置 -->
<ElFormItem
v-if="form.one_time_commission_config.commission_type === 'tiered'"
label="梯度配置"
>
<div style="width: 100%">
<div
v-for="(tier, index) in form.one_time_commission_config.tiers"
:key="index"
style="margin-bottom: 12px"
>
<ElCard shadow="hover">
<div style="display: flex; gap: 12px; align-items: flex-start">
<div style="flex: 1; display: flex; flex-direction: column; gap: 12px">
<!-- 第一行阈值和维度 -->
<div style="display: flex; gap: 12px">
<div style="flex: 1">
<div
style="
margin-bottom: 4px;
font-size: 12px;
color: var(--el-text-color-regular);
"
>
达标阈值{{ tier.dimension === 'sales_amount' ? '(元)' : '' }}
</div>
<ElInputNumber
v-model="tier.threshold"
:min="0"
:precision="tier.dimension === 'sales_amount' ? 2 : 0"
:placeholder="
tier.dimension === 'sales_amount'
? '达标阈值(元)'
: '达标阈值(数量)'
"
style="width: 100%"
/>
</div>
<div style="flex: 1">
<div
style="
margin-bottom: 4px;
font-size: 12px;
color: var(--el-text-color-regular);
"
>统计维度</div
>
<ElSelect
v-model="tier.dimension"
placeholder="统计维度"
style="width: 100%"
>
<ElOption label="销量" value="sales_count" />
<ElOption label="销售额" value="sales_amount" />
</ElSelect>
</div>
</div>
<!-- 第二行佣金金额和统计范围 -->
<div style="display: flex; gap: 12px">
<div style="flex: 1">
<div
style="
margin-bottom: 4px;
font-size: 12px;
color: var(--el-text-color-regular);
"
>佣金金额</div
>
<ElInputNumber
v-model="tier.amount"
:min="0"
:precision="2"
placeholder="佣金金额"
style="width: 100%"
/>
</div>
<div style="flex: 1">
<div
style="
margin-bottom: 4px;
font-size: 12px;
color: var(--el-text-color-regular);
"
>统计范围</div
>
<ElSelect
v-model="tier.stat_scope"
placeholder="统计范围"
style="width: 100%"
>
<ElOption label="仅自己" value="self" />
<ElOption label="自己+下级" value="self_and_sub" />
</ElSelect>
</div>
</div>
</div>
<ElButton
type="danger"
:icon="Delete"
circle
@click="removeTier(index)"
style="flex-shrink: 0; margin-top: 28px; width: 32px; height: 32px; padding: 0"
/>
</div>
</ElCard>
</div>
<ElButton type="primary" :icon="Plus" @click="addTier" style="width: 100%">
添加梯度
</ElButton>
</div>
</ElFormItem>
<!-- 强充配置 -->
<div class="form-section-title">
<span class="title-text">强充配置</span>
</div>
<ElFormItem label="启用强充">
<ElSwitch
v-model="form.one_time_commission_config.enable_force_recharge"
active-text="启用"
inactive-text="不启用"
/>
</ElFormItem>
<template v-if="form.one_time_commission_config.enable_force_recharge">
<ElFormItem label="强充金额">
<ElInputNumber
v-model="form.one_time_commission_config.force_amount"
:min="0"
:precision="2"
placeholder="强充金额(元)"
style="width: 100%"
/>
<span
style="color: var(--el-text-color-secondary); font-size: 12px; margin-left: 8px"
>单位</span
>
</ElFormItem>
<ElFormItem label="强充计算类型">
<ElRadioGroup v-model="form.one_time_commission_config.force_calc_type">
<ElRadio value="fixed">固定</ElRadio>
<ElRadio value="dynamic">动态</ElRadio>
</ElRadioGroup>
</ElFormItem>
</template>
<!-- 时效配置 -->
<div class="form-section-title">
<span class="title-text">时效配置</span>
</div>
<ElFormItem label="时效类型">
<ElRadioGroup v-model="form.one_time_commission_config.validity_type">
<ElRadio value="permanent">永久</ElRadio>
<ElRadio value="fixed_date">固定日期</ElRadio>
<ElRadio value="relative">相对时长</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem
v-if="form.one_time_commission_config.validity_type === 'fixed_date'"
label="有效期至"
>
<ElDatePicker
v-model="form.one_time_commission_config.validity_value"
type="date"
placeholder="选择日期"
style="width: 100%"
value-format="YYYY-MM-DD"
/>
</ElFormItem>
<ElFormItem
v-if="form.one_time_commission_config.validity_type === 'relative'"
label="有效月数"
>
<ElInputNumber
v-model="form.one_time_commission_config.validity_value"
:min="1"
:precision="0"
placeholder="有效月数"
style="width: 100%"
/>
<span
style="color: var(--el-text-color-secondary); font-size: 12px; margin-left: 8px"
>单位</span
>
</ElFormItem>
</template>
</ElForm>
<template #footer>
<div class="dialog-footer">
@@ -94,6 +352,7 @@
import { h } from 'vue'
import { PackageSeriesService } from '@/api/modules'
import { ElMessage, ElMessageBox, ElTag, ElSwitch, ElButton } from 'element-plus'
import { Plus, Delete } from '@element-plus/icons-vue'
import type { FormInstance, FormRules } from 'element-plus'
import type { PackageSeriesResponse } from '@/types/api'
import type { SearchFormItem } from '@/types'
@@ -108,10 +367,12 @@
apiStatusToFrontend
} from '@/config/constants'
import { generateSeriesCode } from '@/utils/codeGenerator'
import { useRouter } from 'vue-router'
defineOptions({ name: 'PackageSeries' })
const { hasAuth } = useAuth()
const router = useRouter()
const dialogVisible = ref(false)
const loading = ref(false)
@@ -122,7 +383,8 @@
// 搜索表单初始值
const initialSearchState = {
series_name: '',
status: undefined as number | undefined
status: undefined as number | undefined,
enable_one_time_commission: undefined as boolean | undefined
}
// 搜索表单
@@ -151,6 +413,19 @@
{ label: '启用', value: 1 },
{ label: '禁用', value: 2 }
]
},
{
label: '一次性佣金',
prop: 'enable_one_time_commission',
type: 'select',
config: {
clearable: true,
placeholder: '请选择'
},
options: () => [
{ label: '已启用', value: true },
{ label: '未启用', value: false }
]
}
]
@@ -163,13 +438,19 @@
// 列配置
const columnOptions = [
{ label: 'ID', prop: 'id' },
{ label: '系列编码', prop: 'series_code' },
{ label: '系列名称', prop: 'series_name' },
{ label: '描述', prop: 'description' },
{ label: '一次性佣金', prop: 'enable_one_time_commission' },
{ label: '佣金类型', prop: 'commission_type' },
{ label: '触发阈值', prop: 'commission_threshold' },
{ label: '触发类型', prop: 'trigger_type' },
{ label: '强充状态', prop: 'enable_force_recharge' },
{ label: '强充金额', prop: 'force_amount' },
{ label: '强充计算类型', prop: 'force_calc_type' },
{ label: '时效类型', prop: 'validity_type' },
{ label: '状态', prop: 'status' },
{ label: '创建时间', prop: 'created_at' },
{ label: '更新时间', prop: 'updated_at' },
{ label: '操作', prop: 'operation' }
]
@@ -191,7 +472,20 @@
id: 0,
series_code: '',
series_name: '',
description: ''
description: '',
one_time_commission_config: {
enable: false,
commission_type: 'fixed',
commission_amount: undefined,
threshold: undefined,
trigger_type: 'first_recharge',
tiers: [],
enable_force_recharge: false,
force_amount: undefined,
force_calc_type: 'fixed',
validity_type: 'permanent',
validity_value: undefined
}
})
const seriesList = ref<PackageSeriesResponse[]>([])
@@ -199,25 +493,151 @@
// 动态列配置
const { columnChecks, columns } = useCheckedColumns(() => [
{
prop: 'id',
label: 'ID',
width: 80
},
{
prop: 'series_code',
label: '系列编码',
minWidth: 150
width: 200,
showOverflowTooltip: true
},
{
prop: 'series_name',
label: '系列名称',
minWidth: 150
},
{
prop: 'description',
label: '描述',
minWidth: 200
prop: 'enable_one_time_commission',
label: '一次性佣金',
width: 110,
formatter: (row: PackageSeriesResponse) => {
if (!row.one_time_commission_config) {
return h(ElTag, { type: 'info', size: 'small' }, () => '未配置')
}
return h(
ElTag,
{
type: row.one_time_commission_config.enable ? 'success' : 'info',
size: 'small'
},
() => (row.one_time_commission_config.enable ? '已启用' : '未启用')
)
}
},
{
prop: 'commission_type',
label: '佣金类型',
width: 100,
formatter: (row: PackageSeriesResponse) => {
if (!row.one_time_commission_config?.commission_type) {
return '-'
}
const typeMap = {
fixed: '固定',
tiered: '梯度'
}
return typeMap[row.one_time_commission_config.commission_type] || '-'
}
},
{
prop: 'commission_threshold',
label: '触发阈值',
width: 120,
formatter: (row: PackageSeriesResponse) => {
if (!row.one_time_commission_config?.threshold) {
return '-'
}
return `¥${(row.one_time_commission_config.threshold / 100).toFixed(2)}`
}
},
{
prop: 'trigger_type',
label: '触发类型',
width: 110,
formatter: (row: PackageSeriesResponse) => {
if (!row.one_time_commission_config?.trigger_type) {
return '-'
}
const typeMap = {
first_recharge: '首次充值',
accumulated_recharge: '累计充值'
}
return typeMap[row.one_time_commission_config.trigger_type] || '-'
}
},
{
prop: 'enable_force_recharge',
label: '强充状态',
width: 100,
formatter: (row: PackageSeriesResponse) => {
if (!row.one_time_commission_config) {
return '-'
}
return h(
ElTag,
{
type: row.one_time_commission_config.enable_force_recharge ? 'warning' : 'info',
size: 'small'
},
() => (row.one_time_commission_config.enable_force_recharge ? '已启用' : '未启用')
)
}
},
{
prop: 'force_amount',
label: '强充金额',
width: 120,
formatter: (row: PackageSeriesResponse) => {
if (!row.one_time_commission_config?.force_amount) {
return '-'
}
return h(
'span',
{ style: 'color: #f56c6c; font-weight: bold;' },
`¥${(row.one_time_commission_config.force_amount / 100).toFixed(2)}`
)
}
},
{
prop: 'force_calc_type',
label: '强充计算类型',
width: 120,
formatter: (row: PackageSeriesResponse) => {
if (!row.one_time_commission_config?.force_calc_type) {
return '-'
}
const typeMap = {
fixed: '固定',
dynamic: '动态'
}
return typeMap[row.one_time_commission_config.force_calc_type] || '-'
}
},
{
prop: 'validity_type',
label: '时效类型',
width: 180,
formatter: (row: PackageSeriesResponse) => {
if (!row.one_time_commission_config?.validity_type) {
return '-'
}
const typeMap = {
permanent: '永久',
fixed_date: '固定日期',
relative: '相对时长'
}
const validityType = typeMap[row.one_time_commission_config.validity_type] || '-'
// 如果有时效值,显示详情
if (row.one_time_commission_config.validity_value) {
if (row.one_time_commission_config.validity_type === 'relative') {
return `${validityType}(${row.one_time_commission_config.validity_value}月)`
} else if (row.one_time_commission_config.validity_type === 'fixed_date') {
return `${validityType}(${row.one_time_commission_config.validity_value})`
}
}
return validityType
}
},
{
prop: 'status',
@@ -238,26 +658,34 @@
})
}
},
{
prop: 'description',
label: '描述',
minWidth: 200,
showOverflowTooltip: true
},
{
prop: 'created_at',
label: '创建时间',
width: 180,
formatter: (row: PackageSeriesResponse) => formatDateTime(row.created_at)
},
{
prop: 'updated_at',
label: '更新时间',
width: 180,
formatter: (row: PackageSeriesResponse) => formatDateTime(row.updated_at)
},
{
prop: 'operation',
label: '操作',
width: 150,
width: 200,
fixed: 'right',
formatter: (row: PackageSeriesResponse) => {
const buttons = []
// 详情按钮
buttons.push(
h(ArtButtonTable, {
type: 'view',
onClick: () => handleViewDetail(row)
})
)
if (hasAuth('package_series:edit')) {
buttons.push(
h(ArtButtonTable, {
@@ -293,7 +721,8 @@
page: pagination.page,
page_size: pagination.page_size,
series_name: searchForm.series_name || undefined,
status: searchForm.status || undefined
status: searchForm.status || undefined,
enable_one_time_commission: searchForm.enable_one_time_commission ?? undefined
}
const res = await PackageSeriesService.getPackageSeries(params)
if (res.code === 0) {
@@ -347,11 +776,80 @@
form.series_code = row.series_code
form.series_name = row.series_name
form.description = row.description || ''
// 填充佣金配置
if (row.one_time_commission_config) {
// 转换梯度配置:分 -> 元
const convertedTiers = (row.one_time_commission_config.tiers || []).map((tier: any) => ({
...tier,
// 只有销售额维度的阈值需要转换
threshold:
tier.dimension === 'sales_amount' && tier.threshold != null
? tier.threshold / 100
: tier.threshold,
// 佣金金额转换
amount: tier.amount != null ? tier.amount / 100 : tier.amount
}))
form.one_time_commission_config = {
enable: row.one_time_commission_config.enable || false,
commission_type: row.one_time_commission_config.commission_type || 'fixed',
// 固定佣金金额:分 -> 元
commission_amount:
row.one_time_commission_config.commission_amount != null
? row.one_time_commission_config.commission_amount / 100
: undefined,
// 触发阈值:分 -> 元
threshold:
row.one_time_commission_config.threshold != null
? row.one_time_commission_config.threshold / 100
: undefined,
trigger_type: row.one_time_commission_config.trigger_type || 'first_recharge',
tiers: convertedTiers,
enable_force_recharge: row.one_time_commission_config.enable_force_recharge || false,
// 强充金额:分 -> 元
force_amount:
row.one_time_commission_config.force_amount != null
? row.one_time_commission_config.force_amount / 100
: undefined,
force_calc_type: row.one_time_commission_config.force_calc_type || 'fixed',
validity_type: row.one_time_commission_config.validity_type || 'permanent',
validity_value: row.one_time_commission_config.validity_value
}
} else {
// 重置为默认值
form.one_time_commission_config = {
enable: false,
commission_type: 'fixed',
commission_amount: undefined,
threshold: undefined,
trigger_type: 'first_recharge',
tiers: [],
enable_force_recharge: false,
force_amount: undefined,
force_calc_type: 'fixed',
validity_type: 'permanent',
validity_value: undefined
}
}
} else {
form.id = 0
form.series_code = ''
form.series_name = ''
form.description = ''
form.one_time_commission_config = {
enable: false,
commission_type: 'fixed',
commission_amount: undefined,
threshold: undefined,
trigger_type: 'first_recharge',
tiers: [],
enable_force_recharge: false,
force_amount: undefined,
force_calc_type: 'fixed',
validity_type: 'permanent',
validity_value: undefined
}
}
// 重置表单验证状态
@@ -363,6 +861,10 @@
// 生成系列编码
const handleGenerateSeriesCode = () => {
form.series_code = generateSeriesCode()
// 清除该字段的验证错误提示
nextTick(() => {
formRef.value?.clearValidate('series_code')
})
ElMessage.success('编码生成成功')
}
@@ -395,12 +897,84 @@
if (valid) {
submitLoading.value = true
try {
const data = {
series_code: form.series_code,
// 构建请求数据
const data: any = {
series_name: form.series_name,
description: form.description || undefined
description: form.description || undefined,
enable_one_time_commission: form.one_time_commission_config.enable
}
// 新增模式下才包含 series_code
if (dialogType.value === 'add') {
data.series_code = form.series_code
}
// 构建佣金配置对象
const commissionConfig: any = {
enable: form.one_time_commission_config.enable
}
// 只有启用时才添加其他配置
if (form.one_time_commission_config.enable) {
commissionConfig.commission_type = form.one_time_commission_config.commission_type
// 触发阈值:元 -> 分
commissionConfig.threshold =
form.one_time_commission_config.threshold != null
? Math.round(form.one_time_commission_config.threshold * 100)
: undefined
commissionConfig.trigger_type = form.one_time_commission_config.trigger_type
// 添加固定佣金金额:元 -> 分
if (form.one_time_commission_config.commission_type === 'fixed') {
commissionConfig.commission_amount =
form.one_time_commission_config.commission_amount != null
? Math.round(form.one_time_commission_config.commission_amount * 100)
: undefined
}
// 添加梯度配置:元 -> 分
if (form.one_time_commission_config.commission_type === 'tiered') {
const convertedTiers = form.one_time_commission_config.tiers.map((tier: any) => ({
...tier,
// 只有销售额维度的阈值需要转换
threshold:
tier.dimension === 'sales_amount' && tier.threshold != null
? Math.round(tier.threshold * 100)
: tier.threshold,
// 佣金金额转换:元 -> 分
amount: tier.amount != null ? Math.round(tier.amount * 100) : tier.amount
}))
commissionConfig.tiers = convertedTiers.length > 0 ? convertedTiers : null
}
// 添加强充配置:元 -> 分
if (form.one_time_commission_config.enable_force_recharge) {
commissionConfig.enable_force_recharge = true
commissionConfig.force_amount =
form.one_time_commission_config.force_amount != null
? Math.round(form.one_time_commission_config.force_amount * 100)
: undefined
commissionConfig.force_calc_type = form.one_time_commission_config.force_calc_type
}
// 添加时效配置
commissionConfig.validity_type = form.one_time_commission_config.validity_type
if (form.one_time_commission_config.validity_type !== 'permanent') {
// relative 类型的 validity_value 需要转换为字符串
if (form.one_time_commission_config.validity_type === 'relative') {
commissionConfig.validity_value = String(
form.one_time_commission_config.validity_value
)
} else {
commissionConfig.validity_value = form.one_time_commission_config.validity_value
}
}
}
// 添加佣金配置到请求数据
data.one_time_commission_config = commissionConfig
if (dialogType.value === 'add') {
await PackageSeriesService.createPackageSeries(data)
ElMessage.success('新增成功')
@@ -436,6 +1010,26 @@
console.error(error)
}
}
// 添加梯度
const addTier = () => {
form.one_time_commission_config.tiers.push({
threshold: undefined,
dimension: 'sales_count',
amount: undefined,
stat_scope: 'self'
})
}
// 删除梯度
const removeTier = (index: number) => {
form.one_time_commission_config.tiers.splice(index, 1)
}
// 查看详情
const handleViewDetail = (row: PackageSeriesResponse) => {
router.push(`/package-management/package-series/detail/${row.id}`)
}
</script>
<style lang="scss" scoped>