Files
one-pipe-system/src/views/package-management/package-series/index.vue
sexygoat 4470a4ef04
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m47s
修改: bug
2026-02-27 17:40:02 +08:00

1095 lines
37 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<ArtTableFullScreen>
<div class="package-series-page" id="table-full-screen">
<!-- 搜索栏 -->
<ArtSearchBar
v-model:filter="searchForm"
:items="searchFormItems"
:show-expand="false"
label-width="85"
@reset="handleReset"
@search="handleSearch"
></ArtSearchBar>
<ElCard shadow="never" class="art-table-card">
<!-- 表格头部 -->
<ArtTableHeader
:columnList="columnOptions"
v-model:columns="columnChecks"
@refresh="handleRefresh"
>
<template #left>
<ElButton type="primary" @click="showDialog('add')" v-permission="'package_series:add'"
>新增套餐系列</ElButton
>
</template>
</ArtTableHeader>
<!-- 表格 -->
<ArtTable
ref="tableRef"
row-key="id"
:loading="loading"
:data="seriesList"
:currentPage="pagination.page"
:pageSize="pagination.page_size"
:total="pagination.total"
:marginTop="10"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@row-contextmenu="handleRowContextMenu"
>
<template #default>
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
</template>
</ArtTable>
<!-- 套餐系列操作右键菜单 -->
<ArtMenuRight
ref="seriesOperationMenuRef"
:menu-items="seriesOperationMenuItems"
:menu-width="140"
@select="handleSeriesOperationMenuSelect"
/>
<!-- 新增/编辑对话框 -->
<ElDialog
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增套餐系列' : '编辑套餐系列'"
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">
<ElInput
v-model="form.series_code"
placeholder="请输入系列编码或点击生成"
:disabled="dialogType === 'edit'"
clearable
style="flex: 1"
/>
<ElButton v-if="dialogType === 'add'" @click="handleGenerateSeriesCode">
生成编码
</ElButton>
</div>
</ElFormItem>
<ElFormItem label="系列名称" prop="series_name">
<ElInput v-model="form.series_name" placeholder="请输入系列名称" clearable />
</ElFormItem>
<ElFormItem label="系列描述" prop="description">
<ElInput
v-model="form.description"
type="textarea"
:rows="3"
placeholder="请输入系列描述(可选)"
maxlength="500"
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">
<ElButton @click="dialogVisible = false">取消</ElButton>
<ElButton type="primary" @click="handleSubmit(formRef)" :loading="submitLoading">
提交
</ElButton>
</div>
</template>
</ElDialog>
</ElCard>
</div>
</ArtTableFullScreen>
</template>
<script setup lang="ts">
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'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
import { formatDateTime } from '@/utils/business/format'
import {
CommonStatus,
getStatusText,
frontendStatusToApi,
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)
const submitLoading = ref(false)
const tableRef = ref()
const formRef = ref<FormInstance>()
// 右键菜单
const seriesOperationMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
const currentOperatingSeries = ref<PackageSeriesResponse | null>(null)
// 搜索表单初始值
const initialSearchState = {
series_name: '',
status: undefined as number | undefined,
enable_one_time_commission: undefined as boolean | undefined
}
// 搜索表单
const searchForm = reactive({ ...initialSearchState })
// 搜索表单配置
const searchFormItems: SearchFormItem[] = [
{
label: '系列名称',
prop: 'series_name',
type: 'input',
config: {
clearable: true,
placeholder: '请输入系列名称'
}
},
{
label: '状态',
prop: 'status',
type: 'select',
config: {
clearable: true,
placeholder: '请选择状态'
},
options: () => [
{ 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 }
]
}
]
// 分页
const pagination = reactive({
page: 1,
page_size: 20,
total: 0
})
// 列配置
const columnOptions = [
{ 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' }
]
// 表单验证规则
const rules = reactive<FormRules>({
series_code: [
{ required: true, message: '请输入系列编码', trigger: 'blur' },
{ min: 1, max: 100, message: '长度在 1 到 100 个字符', trigger: 'blur' }
],
series_name: [
{ required: true, message: '请输入系列名称', trigger: 'blur' },
{ min: 1, max: 255, message: '长度在 1 到 255 个字符', trigger: 'blur' }
],
description: [{ max: 500, message: '描述不能超过 500 个字符', trigger: 'blur' }]
})
// 表单数据
const form = reactive<any>({
id: 0,
series_code: '',
series_name: '',
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[]>([])
const dialogType = ref('add')
// 动态列配置
const { columnChecks, columns } = useCheckedColumns(() => [
{
prop: 'series_code',
label: '系列编码',
width: 200,
showOverflowTooltip: true
},
{
prop: 'series_name',
label: '系列名称',
minWidth: 150
},
{
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',
label: '状态',
width: 100,
formatter: (row: PackageSeriesResponse) => {
const frontendStatus = apiStatusToFrontend(row.status)
return h(ElSwitch, {
modelValue: frontendStatus,
activeValue: CommonStatus.ENABLED,
inactiveValue: CommonStatus.DISABLED,
activeText: getStatusText(CommonStatus.ENABLED),
inactiveText: getStatusText(CommonStatus.DISABLED),
inlinePrompt: true,
disabled: !hasAuth('package_series:update_status'),
'onUpdate:modelValue': (val: string | number | boolean) =>
handleStatusChange(row, val as number)
})
}
},
{
prop: 'description',
label: '描述',
minWidth: 200,
showOverflowTooltip: true
},
{
prop: 'created_at',
label: '创建时间',
width: 180,
formatter: (row: PackageSeriesResponse) => formatDateTime(row.created_at)
}
])
onMounted(() => {
getTableData()
})
// 套餐系列操作菜单项配置
const seriesOperationMenuItems = computed((): MenuItemType[] => {
const items: MenuItemType[] = []
// 详情
if (hasAuth('package_series:detail')) {
items.push({
key: 'detail',
label: '详情'
})
}
// 编辑
if (hasAuth('package_series:edit')) {
items.push({
key: 'edit',
label: '编辑'
})
}
// 删除
if (hasAuth('package_series:delete')) {
items.push({
key: 'delete',
label: '删除'
})
}
return items
})
// 显示套餐系列操作右键菜单
const showSeriesOperationMenu = (e: MouseEvent, row: PackageSeriesResponse) => {
e.preventDefault()
e.stopPropagation()
currentOperatingSeries.value = row
seriesOperationMenuRef.value?.show(e)
}
// 处理表格行右键菜单
const handleRowContextMenu = (row: PackageSeriesResponse, column: any, event: MouseEvent) => {
// 如果用户有编辑或删除权限,显示右键菜单
if (
hasAuth('package_series:edit') ||
hasAuth('package_series:delete') ||
hasAuth('package_series:detail')
) {
showSeriesOperationMenu(event, row)
}
}
// 处理套餐系列操作菜单选择
const handleSeriesOperationMenuSelect = (item: MenuItemType) => {
if (!currentOperatingSeries.value) return
switch (item.key) {
case 'detail':
handleViewDetail(currentOperatingSeries.value)
break
case 'edit':
showDialog('edit', currentOperatingSeries.value)
break
case 'delete':
deleteSeries(currentOperatingSeries.value)
break
}
}
// 获取套餐系列列表
const getTableData = async () => {
loading.value = true
try {
const params = {
page: pagination.page,
page_size: pagination.page_size,
series_name: searchForm.series_name || 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) {
seriesList.value = res.data.items
pagination.total = res.data.total
}
} catch (error) {
console.error(error)
ElMessage.error('获取套餐系列列表失败')
} finally {
loading.value = false
}
}
// 重置搜索
const handleReset = () => {
Object.assign(searchForm, { ...initialSearchState })
pagination.page = 1
getTableData()
}
// 搜索
const handleSearch = () => {
pagination.page = 1
getTableData()
}
// 刷新表格
const handleRefresh = () => {
getTableData()
}
// 处理表格分页变化
const handleSizeChange = (newPageSize: number) => {
pagination.page_size = newPageSize
getTableData()
}
const handleCurrentChange = (newCurrentPage: number) => {
pagination.page = newCurrentPage
getTableData()
}
// 显示新增/编辑对话框
const showDialog = (type: string, row?: PackageSeriesResponse) => {
dialogVisible.value = true
dialogType.value = type
if (type === 'edit' && row) {
form.id = row.id
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
}
}
// 重置表单验证状态
nextTick(() => {
formRef.value?.clearValidate()
})
}
// 生成系列编码
const handleGenerateSeriesCode = () => {
form.series_code = generateSeriesCode()
// 清除该字段的验证错误提示
nextTick(() => {
formRef.value?.clearValidate('series_code')
})
ElMessage.success('编码生成成功')
}
// 删除套餐系列
const deleteSeries = (row: PackageSeriesResponse) => {
ElMessageBox.confirm(`确定删除套餐系列 ${row.series_name} 吗?`, '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
})
.then(async () => {
try {
await PackageSeriesService.deletePackageSeries(row.id)
ElMessage.success('删除成功')
await getTableData()
} catch (error) {
console.error(error)
}
})
.catch(() => {
// 用户取消删除
})
}
// 提交表单
const handleSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
submitLoading.value = true
try {
// 构建请求数据
const data: any = {
series_name: form.series_name,
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('新增成功')
} else {
await PackageSeriesService.updatePackageSeries(form.id, data)
ElMessage.success('修改成功')
}
dialogVisible.value = false
formEl.resetFields()
await getTableData()
} catch (error) {
console.error(error)
} finally {
submitLoading.value = false
}
}
})
}
// 状态切换
const handleStatusChange = async (row: PackageSeriesResponse, newFrontendStatus: number) => {
const oldStatus = row.status
const newApiStatus = frontendStatusToApi(newFrontendStatus)
// 先更新UI将后端状态转换
row.status = newApiStatus
try {
await PackageSeriesService.updatePackageSeriesStatus(row.id, newApiStatus)
ElMessage.success('状态切换成功')
} catch (error) {
// 切换失败,恢复原状态
row.status = oldStatus
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>
.package-series-page {
// 可以添加特定样式
}
.dialog-footer {
text-align: right;
}
</style>