fetch(modify):修改套餐接口
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m40s

This commit is contained in:
sexygoat
2026-02-04 18:14:52 +08:00
parent 20e8c13e61
commit d97dc5f007
12 changed files with 979 additions and 452 deletions

View File

@@ -611,89 +611,98 @@ export const asyncRoutes: AppRouteRecord[] = [
// }
// },
// 物联网卡管理系统模块
// {
// path: '/card-management',
// name: 'CardManagement',
// component: RoutesAlias.Home,
// meta: {
// title: 'menus.cardManagement.title',
// icon: ''
// },
// children: [
// // {
// // path: 'card-detail',
// // name: 'CardDetail',
// // component: RoutesAlias.CardDetail,
// // meta: {
// // title: 'menus.cardManagement.cardDetail',
// // keepAlive: true
// // }
// // },
// {
// path: 'card-assign',
// name: 'CardAssign',
// component: RoutesAlias.CardAssign,
// meta: {
// title: 'menus.cardManagement.cardAssign',
// keepAlive: true
// }
// },
// {
// path: 'card-shutdown',
// name: 'CardShutdown',
// component: RoutesAlias.CardShutdown,
// meta: {
// title: 'menus.cardManagement.cardShutdown',
// keepAlive: true
// }
// },
// {
// path: 'my-cards',
// name: 'MyCards',
// component: RoutesAlias.MyCards,
// meta: {
// title: 'menus.cardManagement.myCards',
// keepAlive: true
// }
// },
// {
// path: 'card-transfer',
// name: 'CardTransfer',
// component: RoutesAlias.CardTransfer,
// meta: {
// title: 'menus.cardManagement.cardTransfer',
// keepAlive: true
// }
// },
// {
// path: 'card-replacement',
// name: 'CardReplacement',
// component: RoutesAlias.CardReplacement,
// meta: {
// title: 'menus.cardManagement.cardReplacement',
// keepAlive: true
// }
// },
// {
// path: 'package-gift',
// name: 'PackageGift',
// component: RoutesAlias.PackageGift,
// meta: {
// title: 'menus.cardManagement.packageGift',
// keepAlive: true
// }
// },
// {
// path: 'card-change-card',
// name: 'CardChangeCard',
// component: RoutesAlias.CardChangeCard,
// meta: {
// title: 'menus.cardManagement.cardChange',
// keepAlive: true
// }
// }
// ]
// },
{
path: '/card-management',
name: 'CardManagement',
component: RoutesAlias.Home,
meta: {
title: 'menus.cardManagement.title',
icon: ''
},
children: [
// {
// path: 'card-detail',
// name: 'CardDetail',
// component: RoutesAlias.CardDetail,
// meta: {
// title: 'menus.cardManagement.cardDetail',
// keepAlive: true
// }
// },
{
path: 'single-card',
name: 'SingleCard',
component: RoutesAlias.SingleCard,
meta: {
title: 'menus.cardManagement.singleCard',
keepAlive: true
}
},
// {
// path: 'card-assign',
// name: 'CardAssign',
// component: RoutesAlias.CardAssign,
// meta: {
// title: 'menus.cardManagement.cardAssign',
// keepAlive: true
// }
// },
// {
// path: 'card-shutdown',
// name: 'CardShutdown',
// component: RoutesAlias.CardShutdown,
// meta: {
// title: 'menus.cardManagement.cardShutdown',
// keepAlive: true
// }
// },
// {
// path: 'my-cards',
// name: 'MyCards',
// component: RoutesAlias.MyCards,
// meta: {
// title: 'menus.cardManagement.myCards',
// keepAlive: true
// }
// },
// {
// path: 'card-transfer',
// name: 'CardTransfer',
// component: RoutesAlias.CardTransfer,
// meta: {
// title: 'menus.cardManagement.cardTransfer',
// keepAlive: true
// }
// },
// {
// path: 'card-replacement',
// name: 'CardReplacement',
// component: RoutesAlias.CardReplacement,
// meta: {
// title: 'menus.cardManagement.cardReplacement',
// keepAlive: true
// }
// },
// {
// path: 'package-gift',
// name: 'PackageGift',
// component: RoutesAlias.PackageGift,
// meta: {
// title: 'menus.cardManagement.packageGift',
// keepAlive: true
// }
// },
// {
// path: 'card-change-card',
// name: 'CardChangeCard',
// component: RoutesAlias.CardChangeCard,
// meta: {
// title: 'menus.cardManagement.cardChange',
// keepAlive: true
// }
// }
]
},
{
path: '/package-management',
name: 'PackageManagement',

View File

@@ -349,6 +349,7 @@ export interface StandaloneIotCard {
created_at: string // 创建时间
updated_at: string // 更新时间
series_id?: number | null // 套餐系列ID
series_name?: string // 套餐系列名称
}
// ========== 单卡批量分配和回收相关 ==========

View File

@@ -7,6 +7,33 @@ import { PaginationParams } from './common'
// ==================== 套餐系列管理 ====================
/**
* 一次性佣金梯度档位配置(套餐系列级别)
*/
export interface OneTimeCommissionTier {
threshold: number // 达标阈值
dimension: 'sales_count' | 'sales_amount' // 统计维度:销量或销售额
amount: number // 佣金金额(分)
stat_scope?: 'self' | 'self_and_sub' // 统计范围:仅自己或自己+下级
}
/**
* 套餐系列一次性佣金配置
*/
export interface SeriesOneTimeCommissionConfig {
enable: boolean // 是否启用一次性佣金
commission_type: 'fixed' | 'tiered' // 佣金类型:固定或梯度
commission_amount?: number // 固定佣金金额commission_type=fixed时使用
threshold: number // 触发阈值(分)
trigger_type: 'first_recharge' | 'accumulated_recharge' // 触发类型:首次充值或累计充值
tiers?: OneTimeCommissionTier[] | null // 梯度配置列表commission_type=tiered时使用
enable_force_recharge: boolean // 是否启用强充
force_amount?: number // 强充金额(分)
force_calc_type?: 'fixed' | 'dynamic' // 强充计算类型:固定或动态
validity_type: 'permanent' | 'fixed_date' | 'relative' // 时效类型:永久、固定日期或相对时长
validity_value?: string // 时效值(日期字符串或月数)
}
/**
* 套餐系列响应
*/
@@ -15,6 +42,8 @@ export interface PackageSeriesResponse {
series_code: string
series_name: string
description?: string
enable_one_time_commission: boolean // 是否启用一次性佣金
one_time_commission_config?: SeriesOneTimeCommissionConfig // 一次性佣金配置
status: number // 1:启用, 2:禁用
created_at: string
updated_at: string
@@ -26,6 +55,7 @@ export interface PackageSeriesResponse {
export interface PackageSeriesQueryParams extends PaginationParams {
series_name?: string // 系列名称(模糊搜索)
status?: number // 状态筛选
enable_one_time_commission?: boolean // 是否启用一次性佣金筛选
}
/**
@@ -35,15 +65,16 @@ export interface CreatePackageSeriesRequest {
series_code: string // 系列编码,必填
series_name: string // 系列名称,必填
description?: string // 描述,可选
one_time_commission_config?: SeriesOneTimeCommissionConfig // 一次性佣金配置,可选
}
/**
* 更新套餐系列请求
*/
export interface UpdatePackageSeriesRequest {
series_code?: string
series_name?: string
description?: string
one_time_commission_config?: SeriesOneTimeCommissionConfig // 一次性佣金配置,可选
}
/**
@@ -70,6 +101,9 @@ export interface PackageResponse {
virtual_data_mb: number // 虚流量额度MB
duration_months: number // 有效期(月)
price: number // 价格(分)
cost_price: number // 成本价(分)
suggested_retail_price: number // 建议零售价(分)
enable_virtual_data: boolean // 是否启用虚流量
shelf_status: number // 上架状态 (1:上架, 2:下架)
status: number // 状态 (1:启用, 2:禁用)
description?: string
@@ -154,11 +188,14 @@ export interface ShopPackageAllocationResponse {
package_id: number
package_code: string
package_name: string
series_id: number // 套餐系列ID
series_name: string // 套餐系列名称
shop_id: number
shop_name: string
cost_price: number // 覆盖的成本价(分)
calculated_cost_price: number // 原计算成本价(分,供参考)
allocation_id?: number // 关联的系列分配ID
allocator_shop_id: number // 分配者店铺ID0表示平台分配
allocator_shop_name: string // 分配者店铺名称
series_allocation_id?: number | null // 关联的系列分配ID(可空)
cost_price: number // 该代理的成本价(分)
status: number // 1:启用, 2:禁用
created_at: string
updated_at: string
@@ -170,6 +207,8 @@ export interface ShopPackageAllocationResponse {
export interface ShopPackageAllocationQueryParams extends PaginationParams {
shop_id?: number // 店铺ID筛选
package_id?: number // 套餐ID筛选
series_allocation_id?: number // 系列分配ID筛选
allocator_shop_id?: number // 分配者店铺ID筛选
status?: number // 状态筛选
}
@@ -198,54 +237,6 @@ export interface UpdateShopPackageAllocationStatusRequest {
// ==================== 套餐系列分配 ====================
/**
* 基础返佣配置
*/
export interface BaseCommissionConfig {
mode: 'fixed' | 'percent' // 返佣模式:'fixed':固定金额, 'percent':百分比
value: number // 返佣值:固定金额(分)或百分比的千分比(如200表示20%)
}
/**
* 梯度档位配置
*/
export interface TierEntry {
threshold: number // 阈值(销量或销售额)
mode: 'fixed' | 'percent' // 返佣模式
value: number // 返佣值
}
/**
* 梯度返佣配置
*/
export interface TierCommissionConfig {
period_type: 'monthly' | 'quarterly' | 'yearly' // 周期类型
tier_type: 'sales_count' | 'sales_amount' // 梯度类型:销量或销售额
tiers: TierEntry[] // 梯度档位数组
}
/**
* 一次性佣金梯度档位配置
*/
export interface OneTimeCommissionTierEntry {
tier_type: 'sales_count' | 'sales_amount' // 梯度类型:销量或销售额
threshold: number // 阈值
mode: 'fixed' | 'percent' // 返佣模式
value: number // 返佣值
}
/**
* 一次性佣金配置
*/
export interface OneTimeCommissionConfig {
type: 'fixed' | 'tiered' // 佣金类型:'fixed':固定佣金, 'tiered':梯度佣金
trigger: 'single_recharge' | 'accumulated_recharge' // 触发方式:'single_recharge':单笔充值, 'accumulated_recharge':累计充值
threshold: number // 最低阈值(分)
mode?: 'fixed' | 'percent' // 返佣模式(固定佣金时必填)
value?: number // 返佣值(固定佣金时必填)
tiers?: OneTimeCommissionTierEntry[] | null // 梯度档位数组(梯度佣金时必填)
}
/**
* 套餐系列分配响应
*/
@@ -253,13 +244,18 @@ export interface ShopSeriesAllocationResponse {
id: number
series_id: number
series_name: string
series_code: string // 套餐系列编码
shop_id: number
shop_name: string
allocator_shop_id: number // 分配者店铺ID
allocator_shop_id: number // 分配者店铺ID0表示平台分配
allocator_shop_name: string // 分配者店铺名称
base_commission: BaseCommissionConfig // 基础返佣配置
enable_one_time_commission: boolean // 是否启用一次性佣金
one_time_commission_config?: OneTimeCommissionConfig // 一次性佣金配置(可选
one_time_commission_amount: number // 该代理能拿的一次性佣金金额上限(分
one_time_commission_threshold?: number // 一次性佣金触发阈值(分)
one_time_commission_trigger?: 'first_recharge' | 'accumulated_recharge' // 一次性佣金触发类型
enable_force_recharge: boolean // 是否启用强制充值
force_recharge_amount?: number // 强制充值金额(分)
force_recharge_trigger_type?: 1 | 2 // 强充触发类型1(单次充值)、2(累计充值)
status: number // 1:启用, 2:禁用
created_at: string
updated_at: string
@@ -271,6 +267,7 @@ export interface ShopSeriesAllocationResponse {
export interface ShopSeriesAllocationQueryParams extends PaginationParams {
shop_id?: number // 店铺ID筛选
series_id?: number // 系列ID筛选
allocator_shop_id?: number // 分配者店铺ID筛选
status?: number // 状态筛选
}
@@ -280,18 +277,27 @@ export interface ShopSeriesAllocationQueryParams extends PaginationParams {
export interface CreateShopSeriesAllocationRequest {
series_id: number // 套餐系列ID必填
shop_id: number // 店铺ID必填
base_commission: BaseCommissionConfig // 基础返佣配置,必填
enable_one_time_commission?: boolean // 是否启用一次性佣金,可选默认false
one_time_commission_config?: OneTimeCommissionConfig // 一次性佣金配置当enable_one_time_commission为true时必填
one_time_commission_amount: number // 一次性佣金金额上限(分),必填
enable_one_time_commission?: boolean // 是否启用一次性佣金,可选
one_time_commission_threshold?: number // 一次性佣金触发阈值(分),可选
one_time_commission_trigger?: 'first_recharge' | 'accumulated_recharge' // 一次性佣金触发类型,可选
enable_force_recharge?: boolean // 是否启用强制充值,可选
force_recharge_amount?: number // 强制充值金额(分),可选
force_recharge_trigger_type?: 1 | 2 // 强充触发类型,可选
}
/**
* 更新套餐系列分配请求
*/
export interface UpdateShopSeriesAllocationRequest {
base_commission?: BaseCommissionConfig // 基础返佣配置
enable_one_time_commission?: boolean // 是否启用一次性佣金
one_time_commission_config?: OneTimeCommissionConfig // 一次性佣金配置
one_time_commission_amount?: number // 一次性佣金金额上限(分)
one_time_commission_threshold?: number // 一次性佣金触发阈值(分)
one_time_commission_trigger?: 'first_recharge' | 'accumulated_recharge' // 一次性佣金触发类型
enable_force_recharge?: boolean // 是否启用强制充值
force_recharge_amount?: number // 强制充值金额(分)
force_recharge_trigger_type?: 1 | 2 // 强充触发类型
status?: number // 状态
}
/**

View File

@@ -874,6 +874,7 @@
{ label: '卡业务类型', prop: 'card_category' },
{ label: '运营商', prop: 'carrier_name' },
{ label: '店铺名称', prop: 'shop_name' },
{ label: '套餐系列', prop: 'series_name' },
{ label: '成本价', prop: 'cost_price' },
{ label: '分销价', prop: 'distribute_price' },
{ label: '状态', prop: 'status' },
@@ -1025,6 +1026,12 @@
minWidth: 150,
formatter: (row: StandaloneIotCard) => row.shop_name || '-'
},
{
prop: 'series_name',
label: '套餐系列',
width: 150,
formatter: (row: StandaloneIotCard) => row.series_name || '-'
},
{
prop: 'cost_price',
label: '成本价',

View File

@@ -58,34 +58,6 @@
<ElOption :label="t('orderManagement.orderType.device')" value="device" />
</ElSelect>
</ElFormItem>
<ElFormItem :label="t('orderManagement.createForm.packageIds')" prop="package_ids">
<ElSelect
v-model="createForm.package_ids"
:placeholder="t('orderManagement.createForm.packageIdsPlaceholder')"
multiple
filterable
remote
reserve-keyword
:remote-method="searchPackages"
:loading="packageSearchLoading"
clearable
style="width: 100%"
>
<ElOption
v-for="pkg in packageOptions"
:key="pkg.id"
:label="`${pkg.package_name} (¥${(pkg.price / 100).toFixed(2)})`"
:value="pkg.id"
>
<div style="display: flex; justify-content: space-between">
<span>{{ pkg.package_name }}</span>
<span style="color: var(--el-text-color-secondary); font-size: 12px">
¥{{ (pkg.price / 100).toFixed(2) }}
</span>
</div>
</ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem
v-if="createForm.order_type === 'single_card'"
:label="t('orderManagement.createForm.iotCardId')"
@@ -148,6 +120,35 @@
</ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem :label="t('orderManagement.createForm.packageIds')" prop="package_ids">
<ElSelect
v-model="createForm.package_ids"
:placeholder="t('orderManagement.createForm.packageIdsPlaceholder')"
multiple
filterable
remote
reserve-keyword
:remote-method="handlePackageSearch"
:loading="packageSearchLoading"
:disabled="(!createForm.iot_card_id && !createForm.device_id) || (createForm.order_type === 'single_card' && !createForm.iot_card_id) || (createForm.order_type === 'device' && !createForm.device_id)"
clearable
style="width: 100%"
>
<ElOption
v-for="pkg in packageOptions"
:key="pkg.id"
:label="`${pkg.package_name} (¥${(pkg.cost_price / 100).toFixed(2)})`"
:value="pkg.id"
>
<div style="display: flex; justify-content: space-between">
<span>{{ pkg.package_name }}</span>
<span style="color: var(--el-text-color-secondary); font-size: 12px">
¥{{ (pkg.cost_price / 100).toFixed(2) }}
</span>
</div>
</ElOption>
</ElSelect>
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
@@ -416,12 +417,13 @@
const deviceOptions = ref<Device[]>([])
const deviceSearchLoading = ref(false)
// 搜索套餐(根据套餐名称)
const searchPackages = async (query: string) => {
// 搜索套餐(根据套餐名称可选按series_id筛选
const searchPackages = async (query: string, seriesId?: number) => {
packageSearchLoading.value = true
try {
const res = await PackageManageService.getPackages({
package_name: query || undefined,
series_id: seriesId,
page: 1,
page_size: 20,
status: 1, // 只获取启用的套餐
@@ -438,6 +440,25 @@
}
}
// 套餐远程搜索方法自动使用当前选中的IOT卡/设备的series_id
const handlePackageSearch = (query: string) => {
let seriesId: number | undefined
// 如果是单卡订单并且已选择IOT卡使用该卡的series_id筛选
if (createForm.order_type === 'single_card' && createForm.iot_card_id) {
const selectedCard = iotCardOptions.value.find((card) => card.id === createForm.iot_card_id)
if (selectedCard && selectedCard.series_id) {
seriesId = selectedCard.series_id
}
} else if (createForm.order_type === 'device' && createForm.device_id) {
// 如果是设备订单并且已选择设备使用设备的series_id筛选
const selectedDevice = deviceOptions.value.find((dev) => dev.id === createForm.device_id)
if (selectedDevice && selectedDevice.series_id) {
seriesId = selectedDevice.series_id
}
}
searchPackages(query, seriesId)
}
// 搜索IoT卡根据ICCID
const searchIotCards = async (query: string) => {
cardSearchLoading.value = true
@@ -623,6 +644,42 @@
}
])
// 当选择IOT卡时根据series_id筛选套餐
watch(
() => createForm.iot_card_id,
(newCardId) => {
if (newCardId && createForm.order_type === 'single_card') {
// 找到选中的IOT卡
const selectedCard = iotCardOptions.value.find((card) => card.id === newCardId)
if (selectedCard && selectedCard.series_id) {
// 根据series_id重新加载套餐列表
loadDefaultPackages(selectedCard.series_id)
} else {
// 如果没有series_id加载所有套餐
loadDefaultPackages()
}
}
}
)
// 当选择设备时根据series_id筛选套餐
watch(
() => createForm.device_id,
(newDeviceId) => {
if (newDeviceId && createForm.order_type === 'device') {
// 找到选中的设备
const selectedDevice = deviceOptions.value.find((dev) => dev.id === newDeviceId)
if (selectedDevice && selectedDevice.series_id) {
// 根据series_id重新加载套餐列表
loadDefaultPackages(selectedDevice.series_id)
} else {
// 如果没有series_id加载所有套餐
loadDefaultPackages()
}
}
}
)
onMounted(() => {
getTableData()
})
@@ -642,7 +699,7 @@
}
const res = await OrderService.getOrders(params)
if (res.code === 0) {
orderList.value = res.data.items || []
orderList.value = res.data.list || []
pagination.total = res.data.total || 0
}
} catch (error) {
@@ -692,15 +749,16 @@
// 显示创建订单对话框
const showCreateDialog = async () => {
createDialogVisible.value = true
// 默认加载20条套餐、IoT卡设备数据
await Promise.all([loadDefaultPackages(), loadDefaultIotCards(), loadDefaultDevices()])
// 加载IoT卡和设备列表套餐列表在选择IoT卡/设备后才加载
await Promise.all([loadDefaultIotCards(), loadDefaultDevices()])
}
// 加载默认套餐列表
const loadDefaultPackages = async () => {
// 加载默认套餐列表可选按series_id筛选
const loadDefaultPackages = async (seriesId?: number) => {
packageSearchLoading.value = true
try {
const res = await PackageManageService.getPackages({
series_id: seriesId,
page: 1,
page_size: 20,
status: 1, // 只获取启用的套餐

View File

@@ -283,7 +283,6 @@
{ label: '套餐名称', prop: 'package_name' },
{ label: '店铺名称', prop: 'shop_name' },
{ label: '成本价', prop: 'cost_price' },
{ label: '原计算成本价', prop: 'calculated_cost_price' },
{ label: '状态', prop: 'status' },
{ label: '创建时间', prop: 'created_at' },
{ label: '操作', prop: 'operation' }
@@ -372,13 +371,6 @@
)
}
},
{
prop: 'calculated_cost_price',
label: '原计算成本价',
width: 120,
formatter: (row: ShopPackageAllocationResponse) =>
`¥${(row.calculated_cost_price / 100).toFixed(2)}`
},
{
prop: 'status',
label: '状态',

View File

@@ -103,141 +103,69 @@
</ElSelect>
</ElFormItem>
<!-- 基础返佣配置 -->
<ElDivider content-position="left">基础返佣配置</ElDivider>
<ElFormItem label="返佣模式" prop="base_commission.mode">
<ElRadioGroup v-model="form.base_commission.mode">
<ElRadio value="fixed">固定金额</ElRadio>
<ElRadio value="percent">百分比</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem
:label="form.base_commission.mode === 'fixed' ? '返佣金额(分)' : '返佣百分比(千分比)'"
prop="base_commission.value"
>
<!-- 一次性佣金配置 -->
<ElDivider content-position="left">一次性佣金配置</ElDivider>
<ElFormItem label="佣金金额上限(分)" prop="one_time_commission_amount">
<ElInputNumber
v-model="form.base_commission.value"
v-model="form.one_time_commission_amount"
:min="0"
:controls="false"
style="width: 100%"
:placeholder="
form.base_commission.mode === 'fixed'
? '请输入固定返佣金额(分)'
: '请输入返佣百分比的千分比(如200表示20%)'
"
placeholder="请输入该代理能拿的一次性佣金金额上限(分)"
/>
<div class="form-tip">
{{
form.base_commission.mode === 'fixed'
? '每笔交易返佣该固定金额(单位:分)'
: '返佣百分比的千分比如200表示20%,即每笔交易返佣 = 交易金额 × 20%'
}}
</div>
<div class="form-tip">该代理在此系列分配下能获得的一次性佣金金额上限单位</div>
</ElFormItem>
<!-- 一次性佣金配置 -->
<ElDivider content-position="left">一次性佣金设置可选</ElDivider>
<ElFormItem label="启用一次性佣金">
<ElSwitch v-model="form.enable_one_time_commission" />
</ElFormItem>
<template v-if="form.enable_one_time_commission">
<ElFormItem label="一次性佣金类型" prop="one_time_commission_config.type">
<ElRadioGroup v-model="form.one_time_commission_config.type">
<ElRadio value="fixed">固定</ElRadio>
<ElRadio value="tiered">梯度</ElRadio>
</ElRadioGroup>
<ElFormItem label="触发阈值(分)" prop="one_time_commission_threshold">
<ElInputNumber
v-model="form.one_time_commission_threshold"
:min="0"
:controls="false"
style="width: 100%"
placeholder="请输入触发阈值(分)"
/>
<div class="form-tip">达到此充值金额后触发一次性佣金</div>
</ElFormItem>
<ElFormItem label="触发条件" prop="one_time_commission_config.trigger">
<ElRadioGroup v-model="form.one_time_commission_config.trigger">
<ElRadio value="single_recharge">次充值</ElRadio>
<ElFormItem label="触发类型" prop="one_time_commission_trigger">
<ElRadioGroup v-model="form.one_time_commission_trigger">
<ElRadio value="first_recharge">次充值</ElRadio>
<ElRadio value="accumulated_recharge">累计充值</ElRadio>
</ElRadioGroup>
</ElFormItem>
</template>
<ElFormItem label="最低阈值(分)" prop="one_time_commission_config.threshold">
<!-- 强制充值配置 -->
<ElDivider content-position="left">强制充值配置可选</ElDivider>
<ElFormItem label="启用强制充值">
<ElSwitch v-model="form.enable_force_recharge" />
</ElFormItem>
<template v-if="form.enable_force_recharge">
<ElFormItem label="强充金额(分)" prop="force_recharge_amount">
<ElInputNumber
v-model="form.one_time_commission_config.threshold"
:min="1"
v-model="form.force_recharge_amount"
:min="0"
:controls="false"
style="width: 100%"
placeholder="请输入最低阈值(分)"
placeholder="请输入强制充值金额(分)"
/>
<div class="form-tip">用户需要达到的强制充值金额</div>
</ElFormItem>
<!-- 固定类型配置 -->
<template v-if="form.one_time_commission_config.type === 'fixed'">
<ElFormItem label="返佣模式" prop="one_time_commission_config.mode">
<ElRadioGroup v-model="form.one_time_commission_config.mode">
<ElRadio value="fixed">固定金额</ElRadio>
<ElRadio value="percent">百分比</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem
:label="
form.one_time_commission_config.mode === 'fixed'
? '佣金金额(分)'
: '佣金比例(千分比)'
"
prop="one_time_commission_config.value"
>
<ElInputNumber
v-model="form.one_time_commission_config.value"
:min="1"
:controls="false"
style="width: 100%"
:placeholder="
form.one_time_commission_config.mode === 'fixed'
? '请输入佣金金额(分)'
: '请输入佣金比例的千分比(如200表示20%)'
"
/>
</ElFormItem>
</template>
<!-- 梯度类型配置 -->
<template v-if="form.one_time_commission_config.type === 'tiered'">
<ElFormItem label="梯度档位">
<div class="tier-list">
<div
v-for="(tier, index) in form.one_time_commission_config.tiers"
:key="index"
class="tier-item"
>
<ElSelect
v-model="tier.tier_type"
placeholder="梯度类型"
style="width: 120px"
>
<ElOption label="销量" value="sales_count" />
<ElOption label="销售额" value="sales_amount" />
</ElSelect>
<ElInputNumber
v-model="tier.threshold"
:min="1"
:controls="false"
placeholder="阈值"
style="width: 120px"
/>
<ElSelect v-model="tier.mode" placeholder="返佣模式" style="width: 120px">
<ElOption label="固定金额" value="fixed" />
<ElOption label="百分比" value="percent" />
</ElSelect>
<ElInputNumber
v-model="tier.value"
:min="1"
:controls="false"
placeholder="返佣值"
style="width: 120px"
/>
<ElButton type="danger" @click="removeTier(index)">删除</ElButton>
</div>
<ElButton type="primary" @click="addTier">添加档位</ElButton>
</div>
</ElFormItem>
</template>
<ElFormItem label="强充触发类型" prop="force_recharge_trigger_type">
<ElRadioGroup v-model="form.force_recharge_trigger_type">
<ElRadio :value="1">单次充值</ElRadio>
<ElRadio :value="2">累计充值</ElRadio>
</ElRadioGroup>
</ElFormItem>
</template>
</ElForm>
<template #footer>
@@ -368,8 +296,9 @@
{ label: '系列名称', prop: 'series_name' },
{ label: '店铺名称', prop: 'shop_name' },
{ label: '分配者店铺', prop: 'allocator_shop_name' },
{ label: '基础返佣', prop: 'base_commission' },
{ label: '一次性佣金', prop: 'enable_one_time_commission' },
{ label: '一次性佣金金额', prop: 'one_time_commission_amount' },
{ label: '一次性佣金状态', prop: 'enable_one_time_commission' },
{ label: '强制充值', prop: 'enable_force_recharge' },
{ label: '状态', prop: 'status' },
{ label: '创建时间', prop: 'created_at' },
{ label: '操作', prop: 'operation' }
@@ -383,19 +312,13 @@
series_name: '',
shop_name: '',
allocator_shop_name: '',
base_commission: {
mode: 'fixed',
value: 0
},
enable_one_time_commission: false,
one_time_commission_config: {
type: 'fixed',
trigger: 'single_recharge',
threshold: 0,
mode: 'fixed',
value: 0,
tiers: []
}
one_time_commission_amount: 0,
one_time_commission_threshold: undefined,
one_time_commission_trigger: 'first_recharge' as 'first_recharge' | 'accumulated_recharge',
enable_force_recharge: false,
force_recharge_amount: undefined,
force_recharge_trigger_type: undefined as 1 | 2 | undefined
})
// 动态验证规则
@@ -403,15 +326,14 @@
const baseRules: FormRules = {
series_id: [{ required: true, message: '请选择套餐系列', trigger: 'change' }],
shop_id: [{ required: true, message: '请选择店铺', trigger: 'change' }],
'base_commission.mode': [{ required: true, message: '请选择返佣模式', trigger: 'change' }],
'base_commission.value': [
{ required: true, message: '请输入返佣值', trigger: 'blur' },
one_time_commission_amount: [
{ required: true, message: '请输入一次性佣金金额上限', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value === undefined || value === null || value === '') {
callback(new Error('请输入返佣值'))
callback(new Error('请输入一次性佣金金额上限'))
} else if (value < 0) {
callback(new Error('返佣值不能小于0'))
callback(new Error('一次性佣金金额不能小于0'))
} else {
callback()
}
@@ -421,27 +343,24 @@
]
}
// 如果启用了一次性佣金,添加验证规则
// 如果启用了一次性佣金,添加额外验证规则
if (form.enable_one_time_commission) {
baseRules['one_time_commission_config.type'] = [
{ required: true, message: '请选择一次性佣金类型', trigger: 'change' }
baseRules.one_time_commission_threshold = [
{ required: true, message: '请输入触发阈值', trigger: 'blur' }
]
baseRules['one_time_commission_config.trigger'] = [
{ required: true, message: '请选择触发条件', trigger: 'change' }
]
baseRules['one_time_commission_config.threshold'] = [
{ required: true, message: '请输入最低阈值', trigger: 'blur' }
baseRules.one_time_commission_trigger = [
{ required: true, message: '请选择触发类型', trigger: 'change' }
]
}
// 固定类型验证
if (form.one_time_commission_config.type === 'fixed') {
baseRules['one_time_commission_config.mode'] = [
{ required: true, message: '请选择返佣模式', trigger: 'change' }
]
baseRules['one_time_commission_config.value'] = [
{ required: true, message: '请输入佣金值', trigger: 'blur' }
]
}
// 如果启用了强制充值,添加验证规则
if (form.enable_force_recharge) {
baseRules.force_recharge_amount = [
{ required: true, message: '请输入强制充值金额', trigger: 'blur' }
]
baseRules.force_recharge_trigger_type = [
{ required: true, message: '请选择强充触发类型', trigger: 'change' }
]
}
return baseRules
@@ -476,23 +395,21 @@
}
},
{
prop: 'base_commission',
label: '基础返佣',
prop: 'one_time_commission_amount',
label: '一次性佣金金额',
width: 150,
formatter: (row: ShopSeriesAllocationResponse) => {
if (!row.base_commission) return '-'
const { mode, value } = row.base_commission
if (mode === 'fixed') {
return `固定 ¥${(value / 100).toFixed(2)}`
} else {
return `百分比 ${(value / 10).toFixed(1)}%`
}
return h(
'span',
{ style: 'color: #f56c6c; font-weight: bold' },
`¥${(row.one_time_commission_amount / 100).toFixed(2)}`
)
}
},
{
prop: 'enable_one_time_commission',
label: '一次性佣金',
width: 120,
label: '一次性佣金状态',
width: 130,
formatter: (row: ShopSeriesAllocationResponse) => {
return h(
ElTag,
@@ -501,6 +418,18 @@
)
}
},
{
prop: 'enable_force_recharge',
label: '强制充值',
width: 100,
formatter: (row: ShopSeriesAllocationResponse) => {
return h(
ElTag,
{ type: row.enable_force_recharge ? 'warning' : 'info', size: 'small' },
() => (row.enable_force_recharge ? '已启用' : '未启用')
)
}
},
{
prop: 'status',
label: '状态',
@@ -750,21 +679,6 @@
getTableData()
}
// 添加档位
const addTier = () => {
form.one_time_commission_config.tiers.push({
tier_type: 'sales_count',
threshold: 0,
mode: 'fixed',
value: 0
})
}
// 删除档位
const removeTier = (index: number) => {
form.one_time_commission_config.tiers.splice(index, 1)
}
// 显示新增/编辑对话框
const showDialog = (type: string, row?: ShopSeriesAllocationResponse) => {
dialogVisible.value = true
@@ -777,30 +691,13 @@
form.series_name = row.series_name
form.shop_name = row.shop_name
form.allocator_shop_name = row.allocator_shop_name
form.base_commission = {
mode: row.base_commission.mode,
value: row.base_commission.value
}
form.enable_one_time_commission = row.enable_one_time_commission
if (row.enable_one_time_commission && row.one_time_commission_config) {
form.one_time_commission_config = {
type: row.one_time_commission_config.type,
trigger: row.one_time_commission_config.trigger,
threshold: row.one_time_commission_config.threshold,
mode: row.one_time_commission_config.mode || 'fixed',
value: row.one_time_commission_config.value || 0,
tiers: row.one_time_commission_config.tiers?.map((t) => ({ ...t })) || []
}
} else {
form.one_time_commission_config = {
type: 'fixed',
trigger: 'single_recharge',
threshold: 0,
mode: 'fixed',
value: 0,
tiers: []
}
}
form.one_time_commission_amount = row.one_time_commission_amount
form.one_time_commission_threshold = row.one_time_commission_threshold
form.one_time_commission_trigger = row.one_time_commission_trigger || 'first_recharge'
form.enable_force_recharge = row.enable_force_recharge
form.force_recharge_amount = row.force_recharge_amount
form.force_recharge_trigger_type = row.force_recharge_trigger_type
} else {
form.id = 0
form.series_id = undefined
@@ -808,19 +705,13 @@
form.series_name = ''
form.shop_name = ''
form.allocator_shop_name = ''
form.base_commission = {
mode: 'fixed',
value: 0
}
form.enable_one_time_commission = false
form.one_time_commission_config = {
type: 'fixed',
trigger: 'single_recharge',
threshold: 0,
mode: 'fixed',
value: 0,
tiers: []
}
form.one_time_commission_amount = 0
form.one_time_commission_threshold = undefined
form.one_time_commission_trigger = 'first_recharge'
form.enable_force_recharge = false
form.force_recharge_amount = undefined
form.force_recharge_trigger_type = undefined
}
// 重置表单验证状态
@@ -840,19 +731,13 @@
form.series_name = ''
form.shop_name = ''
form.allocator_shop_name = ''
form.base_commission = {
mode: 'fixed',
value: 0
}
form.enable_one_time_commission = false
form.one_time_commission_config = {
type: 'fixed',
trigger: 'single_recharge',
threshold: 0,
mode: 'fixed',
value: 0,
tiers: []
}
form.one_time_commission_amount = 0
form.one_time_commission_threshold = undefined
form.one_time_commission_trigger = 'first_recharge'
form.enable_force_recharge = false
form.force_recharge_amount = undefined
form.force_recharge_trigger_type = undefined
}
// 删除分配
@@ -886,59 +771,24 @@
await formEl.validate(async (valid) => {
if (valid) {
// 验证一次性佣金配置
if (form.enable_one_time_commission) {
if (form.one_time_commission_config.type === 'tiered') {
if (form.one_time_commission_config.tiers.length === 0) {
ElMessage.warning('启用梯度类型时至少需要添加一个档位')
return
}
// 验证档位阈值递增
const thresholds = form.one_time_commission_config.tiers.map((t: any) => t.threshold)
for (let i = 1; i < thresholds.length; i++) {
if (thresholds[i] <= thresholds[i - 1]) {
ElMessage.warning('档位阈值必须递增')
return
}
}
}
}
submitLoading.value = true
try {
const data: any = {
base_commission: {
mode: form.base_commission.mode,
value: form.base_commission.value
},
enable_one_time_commission: form.enable_one_time_commission
one_time_commission_amount: form.one_time_commission_amount,
enable_one_time_commission: form.enable_one_time_commission,
enable_force_recharge: form.enable_force_recharge
}
// 如果启用了一次性佣金,加入配置
// 如果启用了一次性佣金,加入相关字段
if (form.enable_one_time_commission) {
data.one_time_commission_config = {
type: form.one_time_commission_config.type,
trigger: form.one_time_commission_config.trigger,
threshold: form.one_time_commission_config.threshold
}
data.one_time_commission_threshold = form.one_time_commission_threshold
data.one_time_commission_trigger = form.one_time_commission_trigger
}
// 固定类型配置
if (form.one_time_commission_config.type === 'fixed') {
data.one_time_commission_config.mode = form.one_time_commission_config.mode
data.one_time_commission_config.value = form.one_time_commission_config.value
}
// 梯度类型配置
else if (form.one_time_commission_config.type === 'tiered') {
data.one_time_commission_config.tiers = form.one_time_commission_config.tiers.map(
(t: any) => ({
tier_type: t.tier_type,
threshold: t.threshold,
mode: t.mode,
value: t.value
})
)
}
// 如果启用了强制充值,加入相关字段
if (form.enable_force_recharge) {
data.force_recharge_amount = form.force_recharge_amount
data.force_recharge_trigger_type = form.force_recharge_trigger_type
}
if (dialogType.value === 'add') {