feat: 套餐分配生效条件选择
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 9m23s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 9m23s
This commit is contained in:
@@ -18,6 +18,7 @@ export { CarrierService } from './carrier'
|
||||
export { PackageSeriesService } from './packageSeries'
|
||||
export { PackageManageService } from './packageManage'
|
||||
export { ShopSeriesGrantService } from './shopSeriesGrant'
|
||||
export { ShopPackageAllocationService } from './shopPackageAllocation'
|
||||
export { OrderService } from './order'
|
||||
export { AssetService } from './asset'
|
||||
export { AgentRechargeService } from './agentRecharge'
|
||||
|
||||
40
src/api/modules/shopPackageAllocation.ts
Normal file
40
src/api/modules/shopPackageAllocation.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 店铺套餐分配 API 服务
|
||||
*/
|
||||
|
||||
import { BaseService } from '../BaseService'
|
||||
import type {
|
||||
BaseResponse,
|
||||
CreateShopPackageAllocationRequest,
|
||||
ShopPackageAllocationResponse,
|
||||
UpdateShopPackageAllocationExpiryBaseRequest
|
||||
} from '@/types/api'
|
||||
|
||||
export class ShopPackageAllocationService extends BaseService {
|
||||
/**
|
||||
* 创建店铺套餐分配
|
||||
* POST /api/admin/shop-package-allocations
|
||||
*/
|
||||
static createShopPackageAllocation(
|
||||
data: CreateShopPackageAllocationRequest
|
||||
): Promise<BaseResponse<ShopPackageAllocationResponse>> {
|
||||
return this.post<BaseResponse<ShopPackageAllocationResponse>>(
|
||||
'/api/admin/shop-package-allocations',
|
||||
data
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新店铺套餐分配生效条件
|
||||
* PATCH /api/admin/shop-package-allocations/{id}/expiry-base
|
||||
*/
|
||||
static updateShopPackageAllocationExpiryBase(
|
||||
id: number,
|
||||
data: UpdateShopPackageAllocationExpiryBaseRequest
|
||||
): Promise<BaseResponse<ShopPackageAllocationResponse>> {
|
||||
return this.patch<BaseResponse<ShopPackageAllocationResponse>>(
|
||||
`/api/admin/shop-package-allocations/${id}/expiry-base`,
|
||||
data
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,40 @@ export interface CommissionTierInfo {
|
||||
*/
|
||||
export type ExpiryBase = 'from_activation' | 'from_purchase'
|
||||
|
||||
// 套餐分配生效条件覆盖值
|
||||
export type PackageAllocationExpiryBaseOverride = 'from_purchase' | 'from_realname'
|
||||
|
||||
// 店铺套餐分配生效条件字段
|
||||
export interface PackageAllocationExpiryBaseFields {
|
||||
default_expiry_base?: string | null
|
||||
default_expiry_base_name?: string | null
|
||||
expiry_base_override?: PackageAllocationExpiryBaseOverride | null
|
||||
expiry_base_override_name?: string | null
|
||||
effective_expiry_base?: string | null
|
||||
effective_expiry_base_name?: string | null
|
||||
}
|
||||
|
||||
// 创建店铺套餐分配请求
|
||||
export interface CreateShopPackageAllocationRequest {
|
||||
shop_id: number
|
||||
package_id: number
|
||||
cost_price: number
|
||||
expiry_base_override: PackageAllocationExpiryBaseOverride | null
|
||||
}
|
||||
|
||||
// 更新店铺套餐分配生效条件请求
|
||||
export interface UpdateShopPackageAllocationExpiryBaseRequest {
|
||||
expiry_base_override: PackageAllocationExpiryBaseOverride | null
|
||||
}
|
||||
|
||||
// 店铺套餐分配响应
|
||||
export interface ShopPackageAllocationResponse extends PackageAllocationExpiryBaseFields {
|
||||
id: number
|
||||
shop_id: number
|
||||
package_id: number
|
||||
cost_price: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 套餐响应
|
||||
*/
|
||||
@@ -234,7 +268,8 @@ export interface CommissionTier {
|
||||
/**
|
||||
* 套餐信息(用于系列授权)
|
||||
*/
|
||||
export interface GrantPackageInfo {
|
||||
export interface GrantPackageInfo extends PackageAllocationExpiryBaseFields {
|
||||
allocation_id?: number
|
||||
package_id: number
|
||||
package_name?: string
|
||||
package_code?: string
|
||||
|
||||
1
src/types/auto-imports.d.ts
vendored
1
src/types/auto-imports.d.ts
vendored
@@ -8,6 +8,7 @@ export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const ElButton: (typeof import('element-plus/es'))['ElButton']
|
||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
|
||||
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||
|
||||
@@ -88,17 +88,8 @@
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="统计范围" width="120">
|
||||
<template #default="{ row }">
|
||||
<ElTag size="small" type="warning">
|
||||
仅自己
|
||||
<!--{{-->
|
||||
<!-- row.stat_scope === 'self'-->
|
||||
<!-- ? '仅自己'-->
|
||||
<!-- : row.stat_scope === 'self_and_sub'-->
|
||||
<!-- ? '自己+下级'-->
|
||||
<!-- : '-'-->
|
||||
<!--}}-->
|
||||
</ElTag>
|
||||
<template #default>
|
||||
<ElTag size="small" type="warning">仅自己</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="佣金金额" min-width="100">
|
||||
@@ -160,6 +151,21 @@
|
||||
<span class="amount-value">¥{{ (row.cost_price / 100).toFixed(2) }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="套餐默认生效条件">
|
||||
<template #default="{ row }">
|
||||
{{ row.default_expiry_base_name || '-' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="覆盖生效条件">
|
||||
<template #default="{ row }">
|
||||
{{ row.expiry_base_override_name || '-' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="最终生效条件">
|
||||
<template #default="{ row }">
|
||||
{{ row.effective_expiry_base_name || '-' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="上架状态" align="center">
|
||||
<template #default="{ row }">
|
||||
<ElTag v-if="row.shelf_status === 1" type="success" size="small">上架</ElTag>
|
||||
@@ -268,6 +274,25 @@
|
||||
}}
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="生效条件">
|
||||
<ElRadioGroup v-model="packageForm.expiry_base_override">
|
||||
<ElRadio value="default">跟随套餐默认</ElRadio>
|
||||
<ElRadio value="from_purchase">购买即生效</ElRadio>
|
||||
<ElRadio value="from_realname">实名即生效</ElRadio>
|
||||
</ElRadioGroup>
|
||||
<div class="form-tip">仅影响后续新订单,不影响已购买套餐</div>
|
||||
</ElFormItem>
|
||||
<template v-if="packageDialogType === 'edit'">
|
||||
<ElFormItem label="套餐默认生效条件">
|
||||
{{ packageForm.default_expiry_base_name || '-' }}
|
||||
</ElFormItem>
|
||||
<ElFormItem label="覆盖生效条件">
|
||||
{{ packageForm.expiry_base_override_name || '-' }}
|
||||
</ElFormItem>
|
||||
<ElFormItem label="最终生效条件">
|
||||
{{ packageForm.effective_expiry_base_name || '-' }}
|
||||
</ElFormItem>
|
||||
</template>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
@@ -304,16 +329,24 @@
|
||||
ElInputNumber,
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElRadioGroup,
|
||||
ElRadio,
|
||||
FormInstance,
|
||||
FormRules
|
||||
} from 'element-plus'
|
||||
import { ArrowLeft, Loading, Setting, List, Plus } from '@element-plus/icons-vue'
|
||||
import { ShopSeriesGrantService, PackageManageService, PackageSeriesService } from '@/api/modules'
|
||||
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
|
||||
import {
|
||||
ShopSeriesGrantService,
|
||||
ShopPackageAllocationService,
|
||||
PackageManageService,
|
||||
PackageSeriesService
|
||||
} from '@/api/modules'
|
||||
import type {
|
||||
ShopSeriesGrantResponse,
|
||||
PackageResponse,
|
||||
GrantPackageItem,
|
||||
GrantPackageInfo,
|
||||
PackageAllocationExpiryBaseOverride,
|
||||
PackageSeriesResponse
|
||||
} from '@/types/api'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
@@ -334,6 +367,8 @@
|
||||
const availablePackages = ref<PackageResponse[]>([])
|
||||
const packageFormRef = ref<FormInstance>()
|
||||
|
||||
type ExpiryBaseSelection = PackageAllocationExpiryBaseOverride | 'default'
|
||||
|
||||
// 套餐表单
|
||||
const packageForm = ref<{
|
||||
package_id?: number
|
||||
@@ -341,8 +376,16 @@
|
||||
package_code?: string
|
||||
original_cost_price?: number
|
||||
cost_price_yuan: number
|
||||
allocation_id?: number
|
||||
expiry_base_override: ExpiryBaseSelection
|
||||
initial_expiry_base_override: ExpiryBaseSelection
|
||||
default_expiry_base_name?: string | null
|
||||
expiry_base_override_name?: string | null
|
||||
effective_expiry_base_name?: string | null
|
||||
}>({
|
||||
cost_price_yuan: 0
|
||||
cost_price_yuan: 0,
|
||||
expiry_base_override: 'default',
|
||||
initial_expiry_base_override: 'default'
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
@@ -463,7 +506,9 @@
|
||||
package_name: undefined,
|
||||
package_code: undefined,
|
||||
original_cost_price: undefined,
|
||||
cost_price_yuan: 0
|
||||
cost_price_yuan: 0,
|
||||
expiry_base_override: 'default',
|
||||
initial_expiry_base_override: 'default'
|
||||
}
|
||||
|
||||
// 加载可用套餐
|
||||
@@ -482,7 +527,13 @@
|
||||
package_name: row.package_name,
|
||||
package_code: row.package_code,
|
||||
original_cost_price: row.cost_price / 100,
|
||||
cost_price_yuan: row.cost_price / 100
|
||||
cost_price_yuan: row.cost_price / 100,
|
||||
allocation_id: row.allocation_id,
|
||||
expiry_base_override: row.expiry_base_override ?? 'default',
|
||||
initial_expiry_base_override: row.expiry_base_override ?? 'default',
|
||||
default_expiry_base_name: row.default_expiry_base_name,
|
||||
expiry_base_override_name: row.expiry_base_override_name,
|
||||
effective_expiry_base_name: row.effective_expiry_base_name
|
||||
}
|
||||
|
||||
packageDialogVisible.value = true
|
||||
@@ -539,23 +590,48 @@
|
||||
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const packages: GrantPackageItem[] = []
|
||||
|
||||
if (packageDialogType.value === 'add') {
|
||||
// 添加模式:添加新套餐
|
||||
packages.push({
|
||||
package_id: packageForm.value.package_id,
|
||||
cost_price: Math.round(packageForm.value.cost_price_yuan * 100)
|
||||
await ShopPackageAllocationService.createShopPackageAllocation({
|
||||
shop_id: detailData.value!.shop_id,
|
||||
package_id: packageForm.value.package_id!,
|
||||
cost_price: Math.round(packageForm.value.cost_price_yuan * 100),
|
||||
expiry_base_override:
|
||||
packageForm.value.expiry_base_override === 'default'
|
||||
? null
|
||||
: packageForm.value.expiry_base_override
|
||||
})
|
||||
} else {
|
||||
// 编辑模式:更新套餐成本价
|
||||
packages.push({
|
||||
package_id: packageForm.value.package_id,
|
||||
cost_price: Math.round(packageForm.value.cost_price_yuan * 100)
|
||||
})
|
||||
}
|
||||
const expiryBaseChanged =
|
||||
packageForm.value.expiry_base_override !==
|
||||
packageForm.value.initial_expiry_base_override
|
||||
if (expiryBaseChanged && !packageForm.value.allocation_id) {
|
||||
ElMessage.error('该套餐分配记录缺少ID,无法更新生效条件')
|
||||
return
|
||||
}
|
||||
|
||||
await ShopSeriesGrantService.manageGrantPackages(grantId, { packages })
|
||||
const packages: GrantPackageItem[] = [
|
||||
{
|
||||
package_id: packageForm.value.package_id,
|
||||
cost_price: Math.round(packageForm.value.cost_price_yuan * 100)
|
||||
}
|
||||
]
|
||||
await Promise.all([
|
||||
ShopSeriesGrantService.manageGrantPackages(grantId, { packages }),
|
||||
...(expiryBaseChanged
|
||||
? [
|
||||
ShopPackageAllocationService.updateShopPackageAllocationExpiryBase(
|
||||
packageForm.value.allocation_id!,
|
||||
{
|
||||
expiry_base_override:
|
||||
packageForm.value.expiry_base_override === 'default'
|
||||
? null
|
||||
: packageForm.value.expiry_base_override
|
||||
}
|
||||
)
|
||||
]
|
||||
: [])
|
||||
])
|
||||
}
|
||||
ElMessage.success(packageDialogType.value === 'add' ? '添加成功' : '更新成功')
|
||||
packageDialogVisible.value = false
|
||||
|
||||
@@ -613,7 +689,9 @@
|
||||
package_name: undefined,
|
||||
package_code: undefined,
|
||||
original_cost_price: undefined,
|
||||
cost_price_yuan: 0
|
||||
cost_price_yuan: 0,
|
||||
expiry_base_override: 'default',
|
||||
initial_expiry_base_override: 'default'
|
||||
}
|
||||
availablePackages.value = []
|
||||
}
|
||||
|
||||
@@ -170,6 +170,13 @@
|
||||
{{ formatSuggestedRetailPrice(pkg.suggested_retail_price) }})
|
||||
</span>
|
||||
</div>
|
||||
<div class="expiry-base-input-wrapper">
|
||||
<ElRadioGroup v-model="pkg.expiry_base_override">
|
||||
<ElRadio value="default">跟随套餐默认</ElRadio>
|
||||
<ElRadio value="from_purchase">购买即生效</ElRadio>
|
||||
<ElRadio value="from_realname">实名即生效</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</div>
|
||||
<ElButton type="danger" size="small" @click="removePackage(index)"
|
||||
>删除</ElButton
|
||||
>
|
||||
@@ -178,6 +185,7 @@
|
||||
<div class="form-tip"
|
||||
>设置每个套餐的成本价(单位:元),不能低于成本价,不能高于建议售价的50%溢价</div
|
||||
>
|
||||
<div class="form-tip">生效条件仅影响后续新订单,不影响已购买套餐</div>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
</div>
|
||||
@@ -253,7 +261,7 @@
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="统计范围" width="140">
|
||||
<template #default="{ row }">
|
||||
<template #default>
|
||||
<ElTag size="small" type="warning"> 仅自己 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
@@ -427,7 +435,7 @@
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="统计范围" width="140">
|
||||
<template #default="{ row }">
|
||||
<template #default>
|
||||
<ElTag size="small" type="warning"> 仅自己 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
@@ -546,6 +554,7 @@
|
||||
import { useRouter } from 'vue-router'
|
||||
import {
|
||||
ShopSeriesGrantService,
|
||||
ShopPackageAllocationService,
|
||||
PackageSeriesService,
|
||||
ShopService,
|
||||
PackageManageService
|
||||
@@ -558,8 +567,7 @@
|
||||
ElRow,
|
||||
ElCol,
|
||||
ElSteps,
|
||||
ElStep,
|
||||
ElEmpty
|
||||
ElStep
|
||||
} from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type {
|
||||
@@ -567,7 +575,8 @@
|
||||
PackageSeriesResponse,
|
||||
ShopResponse,
|
||||
PackageResponse,
|
||||
CommissionTier
|
||||
CommissionTier,
|
||||
PackageAllocationExpiryBaseOverride
|
||||
} from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
@@ -604,8 +613,6 @@
|
||||
const currentStep = ref(0) // 当前步骤,0 为第一步,1 为第二步
|
||||
|
||||
const seriesOptions = ref<PackageSeriesResponse[]>([])
|
||||
const shopOptions = ref<ShopResponse[]>([])
|
||||
const shopTreeData = ref<ShopResponse[]>([])
|
||||
const packageOptions = ref<PackageResponse[]>([])
|
||||
const selectedPackageIds = ref<number[]>([])
|
||||
const searchSeriesOptions = ref<PackageSeriesResponse[]>([])
|
||||
@@ -777,6 +784,7 @@
|
||||
cost_price: number
|
||||
original_cost_price?: number
|
||||
suggested_retail_price?: number
|
||||
expiry_base_override: PackageAllocationExpiryBaseOverride | 'default'
|
||||
}> // 套餐配置
|
||||
})
|
||||
|
||||
@@ -1027,39 +1035,6 @@
|
||||
return actions
|
||||
}
|
||||
|
||||
// 构建树形结构数据
|
||||
const buildTreeData = (items: ShopResponse[]) => {
|
||||
const map = new Map<number, ShopResponse & { children?: ShopResponse[] }>()
|
||||
const tree: ShopResponse[] = []
|
||||
|
||||
// 先将所有项放入 map
|
||||
items.forEach((item) => {
|
||||
map.set(item.id, { ...item, children: [] })
|
||||
})
|
||||
|
||||
// 构建树形结构
|
||||
items.forEach((item) => {
|
||||
const node = map.get(item.id)!
|
||||
if (item.parent_id && map.has(item.parent_id)) {
|
||||
// 有父节点,添加到父节点的 children 中
|
||||
const parent = map.get(item.parent_id)!
|
||||
if (!parent.children) parent.children = []
|
||||
parent.children.push(node)
|
||||
} else {
|
||||
// 没有父节点或父节点不存在,作为根节点
|
||||
tree.push(node)
|
||||
}
|
||||
})
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
// 店铺树节点过滤方法
|
||||
const filterShopNode = (value: string, data: any) => {
|
||||
if (!value) return true
|
||||
return data.shop_name.toLowerCase().includes(value.toLowerCase())
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
})
|
||||
@@ -1170,7 +1145,8 @@
|
||||
suggested_retail_price:
|
||||
pkg?.suggested_retail_price !== undefined && pkg?.suggested_retail_price !== null
|
||||
? pkg.suggested_retail_price / 100
|
||||
: undefined
|
||||
: undefined,
|
||||
expiry_base_override: 'default'
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1597,7 +1573,8 @@
|
||||
pkgOption?.suggested_retail_price !== undefined &&
|
||||
pkgOption?.suggested_retail_price !== null
|
||||
? pkgOption.suggested_retail_price / 100
|
||||
: undefined
|
||||
: undefined,
|
||||
expiry_base_override: pkg.expiry_base_override ?? 'default'
|
||||
}
|
||||
})
|
||||
selectedPackageIds.value = detail.packages.map((pkg) => pkg.package_id)
|
||||
@@ -1745,8 +1722,15 @@
|
||||
data.force_recharge_amount = 0
|
||||
}
|
||||
|
||||
// 可选:套餐配置(将元转换为分)
|
||||
if (form.packages.length > 0) {
|
||||
// 新增系列授权后,套餐通过独立分配接口创建,确保显式传递生效条件覆盖值。
|
||||
const packageAllocations = form.packages.map((pkg: any) => ({
|
||||
package_id: pkg.package_id,
|
||||
cost_price: Math.round((pkg.cost_price ?? 0) * 100),
|
||||
expiry_base_override:
|
||||
pkg.expiry_base_override === 'default' ? null : pkg.expiry_base_override
|
||||
}))
|
||||
|
||||
if (packageAllocations.length > 0) {
|
||||
// 验证是否包含赠送套餐
|
||||
for (const pkg of form.packages) {
|
||||
const pkgInfo = packageOptions.value.find((p) => p.id === pkg.package_id)
|
||||
@@ -1778,11 +1762,6 @@
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
data.packages = form.packages.map((pkg: any) => ({
|
||||
package_id: pkg.package_id,
|
||||
cost_price: Math.round((pkg.cost_price ?? 0) * 100) // 将元转换为分
|
||||
}))
|
||||
}
|
||||
|
||||
if (dialogType.value === 'add') {
|
||||
@@ -1790,6 +1769,19 @@
|
||||
data.series_id = form.series_id
|
||||
data.shop_id = form.shop_id
|
||||
await ShopSeriesGrantService.createShopSeriesGrant(data)
|
||||
await Promise.all(
|
||||
packageAllocations.map(
|
||||
(pkg: {
|
||||
package_id: number
|
||||
cost_price: number
|
||||
expiry_base_override: PackageAllocationExpiryBaseOverride | null
|
||||
}) =>
|
||||
ShopPackageAllocationService.createShopPackageAllocation({
|
||||
shop_id: data.shop_id,
|
||||
...pkg
|
||||
})
|
||||
)
|
||||
)
|
||||
ElMessage.success('新增成功')
|
||||
} else {
|
||||
// 编辑时调用更新接口
|
||||
|
||||
@@ -40,6 +40,21 @@
|
||||
<span class="amount-value">¥{{ (row.cost_price / 100).toFixed(2) }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="套餐默认生效条件" minWidth="150">
|
||||
<template #default="{ row }">
|
||||
{{ row.default_expiry_base_name || '-' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="覆盖生效条件" minWidth="150">
|
||||
<template #default="{ row }">
|
||||
{{ row.expiry_base_override_name || '-' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="最终生效条件" minWidth="150">
|
||||
<template #default="{ row }">
|
||||
{{ row.effective_expiry_base_name || '-' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="上架状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<ElTag v-if="row.shelf_status === 1" type="success" size="small">上架</ElTag>
|
||||
@@ -112,6 +127,25 @@
|
||||
}}
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="生效条件">
|
||||
<ElRadioGroup v-model="packageForm.expiry_base_override">
|
||||
<ElRadio value="default">跟随套餐默认</ElRadio>
|
||||
<ElRadio value="from_purchase">购买即生效</ElRadio>
|
||||
<ElRadio value="from_realname">实名即生效</ElRadio>
|
||||
</ElRadioGroup>
|
||||
<div class="form-tip">仅影响后续新订单,不影响已购买套餐</div>
|
||||
</ElFormItem>
|
||||
<template v-if="packageDialogType === 'edit'">
|
||||
<ElFormItem label="套餐默认生效条件">
|
||||
{{ packageForm.default_expiry_base_name || '-' }}
|
||||
</ElFormItem>
|
||||
<ElFormItem label="覆盖生效条件">
|
||||
{{ packageForm.expiry_base_override_name || '-' }}
|
||||
</ElFormItem>
|
||||
<ElFormItem label="最终生效条件">
|
||||
{{ packageForm.effective_expiry_base_name || '-' }}
|
||||
</ElFormItem>
|
||||
</template>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
@@ -142,12 +176,24 @@
|
||||
ElInputNumber,
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElRadioGroup,
|
||||
ElRadio,
|
||||
ElMessage,
|
||||
FormInstance,
|
||||
FormRules
|
||||
} from 'element-plus'
|
||||
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||
import { ShopSeriesGrantService, PackageManageService } from '@/api/modules'
|
||||
import type { GrantPackageInfo, GrantPackageItem, PackageResponse } from '@/types/api'
|
||||
import {
|
||||
ShopSeriesGrantService,
|
||||
ShopPackageAllocationService,
|
||||
PackageManageService
|
||||
} from '@/api/modules'
|
||||
import type {
|
||||
GrantPackageInfo,
|
||||
GrantPackageItem,
|
||||
PackageAllocationExpiryBaseOverride,
|
||||
PackageResponse
|
||||
} from '@/types/api'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
|
||||
defineOptions({ name: 'SeriesGrantPackages' })
|
||||
@@ -163,6 +209,7 @@
|
||||
|
||||
const grantId = computed(() => Number(route.params.id))
|
||||
const seriesId = ref<number>(0)
|
||||
const shopId = ref<number>(0)
|
||||
const grantName = ref<string>('')
|
||||
const packageList = ref<GrantPackageInfo[]>([])
|
||||
const availablePackages = ref<PackageResponse[]>([])
|
||||
@@ -171,6 +218,8 @@
|
||||
const packageDialogVisible = ref(false)
|
||||
const packageDialogType = ref<'add' | 'edit'>('add')
|
||||
|
||||
type ExpiryBaseSelection = PackageAllocationExpiryBaseOverride | 'default'
|
||||
|
||||
type PackageFormState = {
|
||||
package_id?: number
|
||||
package_name?: string
|
||||
@@ -178,13 +227,21 @@
|
||||
cost_price_yuan: number
|
||||
original_cost_price?: number
|
||||
suggested_retail_price?: number
|
||||
allocation_id?: number
|
||||
expiry_base_override: ExpiryBaseSelection
|
||||
initial_expiry_base_override: ExpiryBaseSelection
|
||||
default_expiry_base_name?: string | null
|
||||
expiry_base_override_name?: string | null
|
||||
effective_expiry_base_name?: string | null
|
||||
}
|
||||
|
||||
const createDefaultPackageForm = (): PackageFormState => ({
|
||||
package_id: undefined,
|
||||
package_name: undefined,
|
||||
package_code: undefined,
|
||||
cost_price_yuan: 0
|
||||
cost_price_yuan: 0,
|
||||
expiry_base_override: 'default',
|
||||
initial_expiry_base_override: 'default'
|
||||
})
|
||||
const packageForm = ref<PackageFormState>(createDefaultPackageForm())
|
||||
|
||||
@@ -266,6 +323,7 @@
|
||||
if (res.code === 0) {
|
||||
packageList.value = res.data.packages || []
|
||||
seriesId.value = res.data.series_id
|
||||
shopId.value = res.data.shop_id
|
||||
grantName.value = `${res.data.series_name} - ${res.data.shop_name}`
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -293,7 +351,13 @@
|
||||
package_code: row.package_code,
|
||||
cost_price_yuan: row.cost_price / 100,
|
||||
original_cost_price: packagePricing.original_cost_price,
|
||||
suggested_retail_price: packagePricing.suggested_retail_price
|
||||
suggested_retail_price: packagePricing.suggested_retail_price,
|
||||
allocation_id: row.allocation_id,
|
||||
expiry_base_override: row.expiry_base_override ?? 'default',
|
||||
initial_expiry_base_override: row.expiry_base_override ?? 'default',
|
||||
default_expiry_base_name: row.default_expiry_base_name,
|
||||
expiry_base_override_name: row.expiry_base_override_name,
|
||||
effective_expiry_base_name: row.effective_expiry_base_name
|
||||
})
|
||||
packageDialogVisible.value = true
|
||||
nextTick(() => packageFormRef.value?.clearValidate())
|
||||
@@ -369,14 +433,46 @@
|
||||
if (Number.isNaN(currentCostPriceYuan)) {
|
||||
throw new Error('当前成本价无效,无法保存')
|
||||
}
|
||||
const packages: GrantPackageItem[] = [
|
||||
{
|
||||
package_id: packageForm.value.package_id,
|
||||
cost_price: Math.round(currentCostPriceYuan * 100)
|
||||
const costPrice = Math.round(currentCostPriceYuan * 100)
|
||||
if (packageDialogType.value === 'add') {
|
||||
await ShopPackageAllocationService.createShopPackageAllocation({
|
||||
shop_id: shopId.value,
|
||||
package_id: packageForm.value.package_id!,
|
||||
cost_price: costPrice,
|
||||
expiry_base_override:
|
||||
packageForm.value.expiry_base_override === 'default'
|
||||
? null
|
||||
: packageForm.value.expiry_base_override
|
||||
})
|
||||
} else {
|
||||
const expiryBaseChanged =
|
||||
packageForm.value.expiry_base_override !==
|
||||
packageForm.value.initial_expiry_base_override
|
||||
if (expiryBaseChanged && !packageForm.value.allocation_id) {
|
||||
ElMessage.error('该套餐分配记录缺少ID,无法更新生效条件')
|
||||
return
|
||||
}
|
||||
]
|
||||
|
||||
await ShopSeriesGrantService.manageGrantPackages(grantId.value, { packages })
|
||||
const packages: GrantPackageItem[] = [
|
||||
{ package_id: packageForm.value.package_id, cost_price: costPrice }
|
||||
]
|
||||
await Promise.all([
|
||||
ShopSeriesGrantService.manageGrantPackages(grantId.value, { packages }),
|
||||
...(expiryBaseChanged
|
||||
? [
|
||||
ShopPackageAllocationService.updateShopPackageAllocationExpiryBase(
|
||||
packageForm.value.allocation_id!,
|
||||
{
|
||||
expiry_base_override:
|
||||
packageForm.value.expiry_base_override === 'default'
|
||||
? null
|
||||
: packageForm.value.expiry_base_override
|
||||
}
|
||||
)
|
||||
]
|
||||
: [])
|
||||
])
|
||||
}
|
||||
packageDialogVisible.value = false
|
||||
await fetchPackageList()
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user