This commit is contained in:
@@ -121,7 +121,13 @@ export interface PackageResponse {
|
|||||||
enable_virtual_data?: boolean // 是否启用虚流量
|
enable_virtual_data?: boolean // 是否启用虚流量
|
||||||
expiry_base?: ExpiryBase // 到期计时基准: from_activation(实名激活时起算) / from_purchase(购买时起算)
|
expiry_base?: ExpiryBase // 到期计时基准: from_activation(实名激活时起算) / from_purchase(购买时起算)
|
||||||
cost_price?: number // 成本价(分)
|
cost_price?: number // 成本价(分)
|
||||||
suggested_retail_price?: number // 建议零售价(分)
|
suggested_retail_price?: number | null // 建议零售价(分),可能为 null 表示"未配置"
|
||||||
|
retail_price?: number | null // 原始代理零售价(分),可能为 null
|
||||||
|
is_gift?: boolean // 是否为赠送套餐
|
||||||
|
price_config_status?: string // 价格配置状态
|
||||||
|
price_config_status_name?: string // 价格配置状态名称
|
||||||
|
effective_retail_price?: number | null // 有效零售价(分)
|
||||||
|
retail_price_config_status?: string // 零售价配置状态(代理视角)
|
||||||
current_commission_rate?: string // 当前返佣比例(仅代理用户可见)
|
current_commission_rate?: string // 当前返佣比例(仅代理用户可见)
|
||||||
one_time_commission_amount?: number | null // 一次性佣金金额(分,代理视角)
|
one_time_commission_amount?: number | null // 一次性佣金金额(分,代理视角)
|
||||||
profit_margin?: number | null // 利润空间(分,仅代理用户可见)
|
profit_margin?: number | null // 利润空间(分,仅代理用户可见)
|
||||||
@@ -162,7 +168,8 @@ export interface CreatePackageRequest {
|
|||||||
enable_virtual_data?: boolean // 是否启用虚流量,可选
|
enable_virtual_data?: boolean // 是否启用虚流量,可选
|
||||||
expiry_base?: ExpiryBase | null // 到期计时基准: from_activation(实名激活时起算) / from_purchase(购买时起算),可选
|
expiry_base?: ExpiryBase | null // 到期计时基准: from_activation(实名激活时起算) / from_purchase(购买时起算),可选
|
||||||
cost_price: number // 成本价(分),必填
|
cost_price: number // 成本价(分),必填
|
||||||
suggested_retail_price?: number | null // 建议零售价(分),可选
|
suggested_retail_price?: number | null // 建议零售价(分),普通套餐可不传或为null表示"未配置",赠送套餐必须传0
|
||||||
|
is_gift?: boolean // 是否为赠送套餐
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,7 +188,9 @@ export interface UpdatePackageRequest {
|
|||||||
enable_virtual_data?: boolean | null // 是否启用虚流量,可选
|
enable_virtual_data?: boolean | null // 是否启用虚流量,可选
|
||||||
expiry_base?: ExpiryBase | null // 到期计时基准,可选
|
expiry_base?: ExpiryBase | null // 到期计时基准,可选
|
||||||
cost_price?: number | null // 成本价(分),可选
|
cost_price?: number | null // 成本价(分),可选
|
||||||
suggested_retail_price?: number | null // 建议零售价(分),可选
|
suggested_retail_price?: number | null // 建议零售价(分),不能再用0表示"清空",清空要用 clear_suggested_retail_price
|
||||||
|
is_gift?: boolean // 是否为赠送套餐
|
||||||
|
clear_suggested_retail_price?: boolean // 清空建议零售价(当需要将价格设为null时使用)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -139,11 +139,17 @@
|
|||||||
:key="pkg.id"
|
:key="pkg.id"
|
||||||
:label="`${pkg.package_name} (¥${((pkg.cost_price || 0) / 100).toFixed(2)})`"
|
:label="`${pkg.package_name} (¥${((pkg.cost_price || 0) / 100).toFixed(2)})`"
|
||||||
:value="pkg.id"
|
:value="pkg.id"
|
||||||
|
:disabled="pkg.is_gift"
|
||||||
>
|
>
|
||||||
<div style="display: flex; justify-content: space-between">
|
<div style="display: flex; justify-content: space-between">
|
||||||
<span>{{ pkg.package_name }}</span>
|
<span>{{ pkg.package_name }}</span>
|
||||||
<span style="font-size: 12px; color: var(--el-text-color-secondary)">
|
<span style="font-size: 12px; color: var(--el-text-color-secondary)">
|
||||||
¥{{ ((pkg.cost_price || 0) / 100).toFixed(2) }}
|
<template v-if="pkg.is_gift">
|
||||||
|
<el-tag type="warning" size="small">赠送</el-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
¥{{ ((pkg.cost_price || 0) / 100).toFixed(2) }}
|
||||||
|
</template>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</ElOption>
|
</ElOption>
|
||||||
@@ -158,14 +164,24 @@
|
|||||||
该系列暂无可用套餐
|
该系列暂无可用套餐
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="selectedPackageIsGift">
|
||||||
|
<div style="color: var(--el-color-warning); font-size: 12px; margin-top: 4px">
|
||||||
|
提示: 赠送套餐只能使用线下支付方式
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem label="支付方式" prop="payment_method">
|
<ElFormItem label="支付方式" prop="payment_method">
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="createForm.payment_method"
|
v-model="createForm.payment_method"
|
||||||
placeholder="请选择支付方式"
|
placeholder="请选择支付方式"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
|
:disabled="selectedPackageIsGift"
|
||||||
>
|
>
|
||||||
<ElOption label="钱包支付" value="wallet" />
|
<ElOption
|
||||||
|
v-if="!selectedPackageIsGift"
|
||||||
|
label="钱包支付"
|
||||||
|
value="wallet"
|
||||||
|
/>
|
||||||
<!-- 只有平台用户(user_type 1:超级管理员, 2:平台用户)才显示线下支付选项 -->
|
<!-- 只有平台用户(user_type 1:超级管理员, 2:平台用户)才显示线下支付选项 -->
|
||||||
<ElOption
|
<ElOption
|
||||||
v-if="userStore.info.user_type === 1 || userStore.info.user_type === 2"
|
v-if="userStore.info.user_type === 1 || userStore.info.user_type === 2"
|
||||||
@@ -713,6 +729,13 @@
|
|||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 检查是否选择了赠送套餐
|
||||||
|
const selectedPackageIsGift = computed(() => {
|
||||||
|
if (!createForm.package_id) return false
|
||||||
|
const selectedPackage = packageOptions.value.find((pkg) => pkg.id === createForm.package_id)
|
||||||
|
return selectedPackage?.is_gift || false
|
||||||
|
})
|
||||||
|
|
||||||
// IoT卡选择变化时,根据series_id加载套餐列表
|
// IoT卡选择变化时,根据series_id加载套餐列表
|
||||||
const handleIotCardChange = (cardId: number | null) => {
|
const handleIotCardChange = (cardId: number | null) => {
|
||||||
if (!cardId) {
|
if (!cardId) {
|
||||||
@@ -997,6 +1020,19 @@
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 当套餐切换时,如果选择的是赠送套餐,自动切换到线下支付
|
||||||
|
watch(
|
||||||
|
() => createForm.package_id,
|
||||||
|
(packageId) => {
|
||||||
|
if (packageId) {
|
||||||
|
const selectedPackage = packageOptions.value.find((pkg) => pkg.id === packageId)
|
||||||
|
if (selectedPackage?.is_gift) {
|
||||||
|
createForm.payment_method = 'offline'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTableData()
|
getTableData()
|
||||||
})
|
})
|
||||||
@@ -1170,6 +1206,18 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否是赠送套餐
|
||||||
|
const selectedPackage = packageOptions.value.find(
|
||||||
|
(pkg) => pkg.id === createForm.package_id
|
||||||
|
)
|
||||||
|
const isGiftPackage = selectedPackage?.is_gift || false
|
||||||
|
|
||||||
|
// 线下支付时,支付凭证为必填
|
||||||
|
if (createForm.payment_method === 'offline' && !createForm.payment_voucher_key) {
|
||||||
|
ElMessage.error('线下支付必须上传支付凭证')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 创建订单(后端接收数组,前端单选转为单元素数组)
|
// 创建订单(后端接收数组,前端单选转为单元素数组)
|
||||||
const data: CreateOrderRequest = {
|
const data: CreateOrderRequest = {
|
||||||
identifier,
|
identifier,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { ElCard, ElButton, ElIcon, ElMessage } from 'element-plus'
|
import { ElCard, ElButton, ElIcon, ElMessage } from 'element-plus'
|
||||||
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
|
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
|
||||||
@@ -35,11 +35,15 @@
|
|||||||
import type { PackageResponse } from '@/types/api'
|
import type { PackageResponse } from '@/types/api'
|
||||||
import { formatDateTime } from '@/utils/business/format'
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
import { getStatusLabel, getShelfStatusText } from '@/config/constants'
|
import { getStatusLabel, getShelfStatusText } from '@/config/constants'
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
|
||||||
defineOptions({ name: 'PackageDetail' })
|
defineOptions({ name: 'PackageDetail' })
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
const isAgentAccount = computed(() => userStore.info.user_type === 3)
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const detailData = ref<PackageResponse | null>(null)
|
const detailData = ref<PackageResponse | null>(null)
|
||||||
@@ -62,6 +66,62 @@
|
|||||||
return typeMap[data.package_type] || data.package_type
|
return typeMap[data.package_type] || data.package_type
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '成本价',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
return `¥${(data.cost_price / 100).toFixed(2)}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '建议售价',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
if (data.suggested_retail_price === null || data.suggested_retail_price === undefined)
|
||||||
|
return '-'
|
||||||
|
return `¥${(data.suggested_retail_price / 100).toFixed(2)}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...(isAgentAccount.value
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: '代理零售价',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
if (data.retail_price === null || data.retail_price === undefined) return '-'
|
||||||
|
return `¥${(data.retail_price / 100).toFixed(2)}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '利润空间',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
if (data.profit_margin === null || data.profit_margin === undefined) return '-'
|
||||||
|
return `¥${(data.profit_margin / 100).toFixed(2)}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
label: '价格配置状态',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
return data.price_config_status_name || '-'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '生效零售价',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
if (
|
||||||
|
data.effective_retail_price === null ||
|
||||||
|
data.effective_retail_price === undefined
|
||||||
|
)
|
||||||
|
return '-'
|
||||||
|
return `¥${(data.effective_retail_price / 100).toFixed(2)}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否赠送',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
return data.is_gift ? '是' : '否'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]),
|
||||||
{
|
{
|
||||||
label: '套餐时长',
|
label: '套餐时长',
|
||||||
formatter: (_, data) => {
|
formatter: (_, data) => {
|
||||||
@@ -152,30 +212,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: '价格信息',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: '成本价',
|
|
||||||
formatter: (_, data) => {
|
|
||||||
return `¥${(data.cost_price / 100).toFixed(2)}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '建议售价',
|
|
||||||
formatter: (_, data) => {
|
|
||||||
return `¥${(data.suggested_retail_price / 100).toFixed(2)}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '利润空间',
|
|
||||||
formatter: (_, data) => {
|
|
||||||
if (data.profit_margin === null || data.profit_margin === undefined) return '-'
|
|
||||||
return `¥${(data.profit_margin / 100).toFixed(2)}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '佣金配置',
|
title: '佣金配置',
|
||||||
fields: [
|
fields: [
|
||||||
|
|||||||
@@ -35,7 +35,8 @@
|
|||||||
:total="pagination.total"
|
:total="pagination.total"
|
||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
:actions="getActions"
|
:actions="getActions"
|
||||||
:inlineActionsCount="2"
|
:actionsWidth="120"
|
||||||
|
:inlineActionsCount="1"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
>
|
>
|
||||||
@@ -282,11 +283,30 @@
|
|||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="请输入建议零售价"
|
placeholder="请输入建议零售价"
|
||||||
|
:disabled="form.is_gift"
|
||||||
/>
|
/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
</ElCol>
|
</ElCol>
|
||||||
</ElRow>
|
</ElRow>
|
||||||
|
|
||||||
|
<ElRow :gutter="20">
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="设为赠送套餐">
|
||||||
|
<div class="gift-switch-wrapper">
|
||||||
|
<ElSwitch v-model="form.is_gift" @change="handleIsGiftChange" />
|
||||||
|
<div v-if="form.is_gift" class="gift-hint">
|
||||||
|
<el-icon class="gift-hint-icon"><WarningFilled /></el-icon>
|
||||||
|
<span>赠送套餐的建议零售价将自动设为 0</span>
|
||||||
|
</div>
|
||||||
|
<div v-else class="gift-hint gift-hint--info">
|
||||||
|
<el-icon class="gift-hint-icon"><InfoFilled /></el-icon>
|
||||||
|
<span>开启后该套餐将作为赠送套餐,无法用于常规销售</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
|
||||||
<ElRow :gutter="20">
|
<ElRow :gutter="20">
|
||||||
<ElCol :span="24">
|
<ElCol :span="24">
|
||||||
<ElFormItem label="套餐描述" prop="description">
|
<ElFormItem label="套餐描述" prop="description">
|
||||||
@@ -368,6 +388,7 @@
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { PackageManageService, PackageSeriesService } from '@/api/modules'
|
import { PackageManageService, PackageSeriesService } from '@/api/modules'
|
||||||
import { ElMessage, ElMessageBox, ElTag, ElSwitch, ElInputNumber } from 'element-plus'
|
import { ElMessage, ElMessageBox, ElTag, ElSwitch, ElInputNumber } from 'element-plus'
|
||||||
|
import { WarningFilled, InfoFilled } from '@element-plus/icons-vue'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import type { PackageResponse, SeriesSelectOption } from '@/types/api'
|
import type { PackageResponse, SeriesSelectOption } from '@/types/api'
|
||||||
import type { SearchFormItem } from '@/types'
|
import type { SearchFormItem } from '@/types'
|
||||||
@@ -396,6 +417,8 @@
|
|||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
const isAgentAccount = computed(() => userStore.info.user_type === 3)
|
||||||
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const submitLoading = ref(false)
|
const submitLoading = ref(false)
|
||||||
@@ -512,6 +535,18 @@
|
|||||||
{ label: '套餐名称', prop: 'package_name' },
|
{ label: '套餐名称', prop: 'package_name' },
|
||||||
{ label: '所属系列', prop: 'series_name' },
|
{ label: '所属系列', prop: 'series_name' },
|
||||||
{ label: '套餐类型', prop: 'package_type' },
|
{ label: '套餐类型', prop: 'package_type' },
|
||||||
|
{ label: '成本价', prop: 'cost_price' },
|
||||||
|
{ label: '建议售价', prop: 'suggested_retail_price' },
|
||||||
|
...(isAgentAccount.value
|
||||||
|
? [
|
||||||
|
{ label: '代理零售价', prop: 'retail_price' },
|
||||||
|
{ label: '利润空间', prop: 'profit_margin' }
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{ label: '价格配置状态', prop: 'price_config_status_name' },
|
||||||
|
{ label: '生效零售价', prop: 'effective_retail_price' },
|
||||||
|
{ label: '是否赠送', prop: 'is_gift' }
|
||||||
|
]),
|
||||||
{ label: '套餐周期类型', prop: 'calendar_type' },
|
{ label: '套餐周期类型', prop: 'calendar_type' },
|
||||||
{ label: '有效期', prop: 'duration_months' },
|
{ label: '有效期', prop: 'duration_months' },
|
||||||
{ label: '真流量', prop: 'real_data_mb' },
|
{ label: '真流量', prop: 'real_data_mb' },
|
||||||
@@ -546,8 +581,6 @@
|
|||||||
return map[row.expiry_base] || row.expiry_base || '-'
|
return map[row.expiry_base] || row.expiry_base || '-'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ label: '成本价', prop: 'cost_price' },
|
|
||||||
{ label: '建议售价', prop: 'suggested_retail_price' },
|
|
||||||
{ label: '上架状态', prop: 'shelf_status' },
|
{ label: '上架状态', prop: 'shelf_status' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '创建时间', prop: 'created_at' },
|
{ label: '创建时间', prop: 'created_at' },
|
||||||
@@ -571,7 +604,27 @@
|
|||||||
{ required: true, message: '请输入有效期', trigger: 'blur' },
|
{ required: true, message: '请输入有效期', trigger: 'blur' },
|
||||||
{ type: 'number', min: 1, max: 120, message: '有效期范围 1-120 月', trigger: 'blur' }
|
{ type: 'number', min: 1, max: 120, message: '有效期范围 1-120 月', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
cost_price: [{ required: true, message: '请输入成本价', trigger: 'blur' }]
|
cost_price: [{ required: true, message: '请输入成本价', trigger: 'blur' }],
|
||||||
|
suggested_retail_price: [
|
||||||
|
{
|
||||||
|
validator: (_rule: any, value: any, callback: any) => {
|
||||||
|
if (form.is_gift) {
|
||||||
|
if (value !== 0 && value !== undefined && value !== null) {
|
||||||
|
callback(new Error('赠送套餐的建议零售价必须为0'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value === 0) {
|
||||||
|
callback(new Error('普通套餐的建议零售价不能为0'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果启用虚流量,则虚流量额度为必填,并且不能超过真流量额度
|
// 如果启用虚流量,则虚流量额度为必填,并且不能超过真流量额度
|
||||||
@@ -619,12 +672,14 @@
|
|||||||
virtual_data_mb: 0,
|
virtual_data_mb: 0,
|
||||||
cost_price: 0,
|
cost_price: 0,
|
||||||
suggested_retail_price: undefined,
|
suggested_retail_price: undefined,
|
||||||
|
is_gift: false,
|
||||||
description: ''
|
description: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
// GB 输入值(用于界面显示)
|
// GB 输入值(用于界面显示)
|
||||||
const realDataGb = ref<number>(0)
|
const realDataGb = ref<number>(0)
|
||||||
const virtualRatioPercent = ref<number | null>(null) // 虚流量比例(百分比)
|
const virtualRatioPercent = ref<number | null>(null) // 虚流量比例(百分比)
|
||||||
|
const originalSuggestedRetailPrice = ref<number | null>(null) // 编辑时原始建议零售价
|
||||||
|
|
||||||
// 计算得出的虚流量GB值
|
// 计算得出的虚流量GB值
|
||||||
const calculatedVirtualDataGb = computed(() => {
|
const calculatedVirtualDataGb = computed(() => {
|
||||||
@@ -709,6 +764,68 @@
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prop: 'cost_price',
|
||||||
|
label: '成本价',
|
||||||
|
width: 100,
|
||||||
|
formatter: (row: PackageResponse) => `¥${((row.cost_price ?? 0) / 100).toFixed(2)}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'suggested_retail_price',
|
||||||
|
label: '建议售价',
|
||||||
|
width: 100,
|
||||||
|
formatter: (row: PackageResponse) =>
|
||||||
|
row.suggested_retail_price !== null && row.suggested_retail_price !== undefined
|
||||||
|
? `¥${((row.suggested_retail_price ?? 0) / 100).toFixed(2)}`
|
||||||
|
: '-'
|
||||||
|
},
|
||||||
|
...(isAgentAccount.value
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
prop: 'retail_price',
|
||||||
|
label: '代理零售价',
|
||||||
|
width: 100,
|
||||||
|
formatter: (row: PackageResponse) =>
|
||||||
|
row.retail_price !== null && row.retail_price !== undefined
|
||||||
|
? `¥${((row.retail_price ?? 0) / 100).toFixed(2)}`
|
||||||
|
: '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'profit_margin',
|
||||||
|
label: '利润空间',
|
||||||
|
width: 100,
|
||||||
|
formatter: (row: PackageResponse) =>
|
||||||
|
row.profit_margin !== null && row.profit_margin !== undefined
|
||||||
|
? `¥${((row.profit_margin ?? 0) / 100).toFixed(2)}`
|
||||||
|
: '-'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
prop: 'price_config_status_name',
|
||||||
|
label: '价格配置状态',
|
||||||
|
width: 120,
|
||||||
|
formatter: (row: PackageResponse) => row.price_config_status_name || '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'effective_retail_price',
|
||||||
|
label: '生效零售价',
|
||||||
|
width: 100,
|
||||||
|
formatter: (row: PackageResponse) =>
|
||||||
|
row.effective_retail_price !== null && row.effective_retail_price !== undefined
|
||||||
|
? `¥${((row.effective_retail_price ?? 0) / 100).toFixed(2)}`
|
||||||
|
: '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'is_gift',
|
||||||
|
label: '是否赠送',
|
||||||
|
width: 100,
|
||||||
|
formatter: (row: PackageResponse) =>
|
||||||
|
h(ElTag, { type: row.is_gift ? 'warning' : 'info', size: 'small' }, () =>
|
||||||
|
row.is_gift ? '是' : '否'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]),
|
||||||
{
|
{
|
||||||
prop: 'shelf_status',
|
prop: 'shelf_status',
|
||||||
label: '上架状态',
|
label: '上架状态',
|
||||||
@@ -834,21 +951,6 @@
|
|||||||
return map[row.expiry_base] || row.expiry_base || '-'
|
return map[row.expiry_base] || row.expiry_base || '-'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
prop: 'cost_price',
|
|
||||||
label: '成本价',
|
|
||||||
width: 100,
|
|
||||||
formatter: (row: PackageResponse) => `¥${((row.cost_price ?? 0) / 100).toFixed(2)}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'suggested_retail_price',
|
|
||||||
label: '建议售价',
|
|
||||||
width: 100,
|
|
||||||
formatter: (row: PackageResponse) =>
|
|
||||||
row.suggested_retail_price
|
|
||||||
? `¥${((row.suggested_retail_price ?? 0) / 100).toFixed(2)}`
|
|
||||||
: '-'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
prop: 'created_at',
|
prop: 'created_at',
|
||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
@@ -919,6 +1021,15 @@
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 监听 is_gift 变化,自动设置 suggested_retail_price
|
||||||
|
const handleIsGiftChange = (isGift: boolean) => {
|
||||||
|
if (isGift) {
|
||||||
|
form.suggested_retail_price = 0
|
||||||
|
} else {
|
||||||
|
form.suggested_retail_price = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTableData()
|
getTableData()
|
||||||
})
|
})
|
||||||
@@ -1048,7 +1159,6 @@
|
|||||||
|
|
||||||
// 显示新增/编辑对话框
|
// 显示新增/编辑对话框
|
||||||
const showDialog = async (type: string, row?: PackageResponse) => {
|
const showDialog = async (type: string, row?: PackageResponse) => {
|
||||||
dialogVisible.value = true
|
|
||||||
dialogType.value = type
|
dialogType.value = type
|
||||||
|
|
||||||
if (type === 'edit' && row) {
|
if (type === 'edit' && row) {
|
||||||
@@ -1082,7 +1192,12 @@
|
|||||||
form.suggested_retail_price = data.suggested_retail_price
|
form.suggested_retail_price = data.suggested_retail_price
|
||||||
? data.suggested_retail_price / 100
|
? data.suggested_retail_price / 100
|
||||||
: undefined
|
: undefined
|
||||||
|
originalSuggestedRetailPrice.value = data.suggested_retail_price
|
||||||
|
form.is_gift = data.is_gift || false
|
||||||
form.description = data.description || ''
|
form.description = data.description || ''
|
||||||
|
|
||||||
|
// 数据填充完成后再显示对话框
|
||||||
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取套餐详情失败:', error)
|
console.error('获取套餐详情失败:', error)
|
||||||
@@ -1108,6 +1223,8 @@
|
|||||||
form.cost_price = 0
|
form.cost_price = 0
|
||||||
form.suggested_retail_price = undefined
|
form.suggested_retail_price = undefined
|
||||||
form.description = ''
|
form.description = ''
|
||||||
|
|
||||||
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置表单验证状态
|
// 重置表单验证状态
|
||||||
@@ -1149,6 +1266,8 @@
|
|||||||
virtualRatioPercent.value = null
|
virtualRatioPercent.value = null
|
||||||
form.cost_price = 0
|
form.cost_price = 0
|
||||||
form.suggested_retail_price = undefined
|
form.suggested_retail_price = undefined
|
||||||
|
originalSuggestedRetailPrice.value = null
|
||||||
|
form.is_gift = false
|
||||||
form.description = ''
|
form.description = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1183,16 +1302,14 @@
|
|||||||
try {
|
try {
|
||||||
// 将元转换为分提交给后端
|
// 将元转换为分提交给后端
|
||||||
const costPriceInCents = Math.round(form.cost_price * 100)
|
const costPriceInCents = Math.round(form.cost_price * 100)
|
||||||
const suggestedRetailPriceInCents = form.suggested_retail_price
|
|
||||||
? Math.round(form.suggested_retail_price * 100)
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const data: any = {
|
const data: any = {
|
||||||
package_code: form.package_code,
|
package_code: form.package_code,
|
||||||
package_name: form.package_name,
|
package_name: form.package_name,
|
||||||
package_type: form.package_type,
|
package_type: form.package_type,
|
||||||
duration_months: form.duration_months,
|
duration_months: form.duration_months,
|
||||||
cost_price: costPriceInCents
|
cost_price: costPriceInCents,
|
||||||
|
is_gift: form.is_gift
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可选字段
|
// 可选字段
|
||||||
@@ -1215,8 +1332,18 @@
|
|||||||
if (form.expiry_base) {
|
if (form.expiry_base) {
|
||||||
data.expiry_base = form.expiry_base
|
data.expiry_base = form.expiry_base
|
||||||
}
|
}
|
||||||
if (suggestedRetailPriceInCents !== undefined && suggestedRetailPriceInCents !== null) {
|
// 处理建议零售价
|
||||||
data.suggested_retail_price = suggestedRetailPriceInCents
|
if (form.suggested_retail_price !== undefined && form.suggested_retail_price !== null) {
|
||||||
|
data.suggested_retail_price = Math.round(form.suggested_retail_price * 100)
|
||||||
|
}
|
||||||
|
// 编辑模式下,如果清空了建议零售价,使用 clear_suggested_retail_price
|
||||||
|
if (dialogType.value === 'edit') {
|
||||||
|
const wasNull = originalSuggestedRetailPrice.value === null
|
||||||
|
const isNowNull =
|
||||||
|
form.suggested_retail_price === undefined || form.suggested_retail_price === null
|
||||||
|
if (!wasNull && isNowNull) {
|
||||||
|
data.clear_suggested_retail_price = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (form.real_data_mb !== undefined && form.real_data_mb !== null) {
|
if (form.real_data_mb !== undefined && form.real_data_mb !== null) {
|
||||||
data.real_data_mb = form.real_data_mb
|
data.real_data_mb = form.real_data_mb
|
||||||
@@ -1290,8 +1417,8 @@
|
|||||||
const showRetailPriceDialog = (row: PackageResponse) => {
|
const showRetailPriceDialog = (row: PackageResponse) => {
|
||||||
retailPriceForm.id = row.id
|
retailPriceForm.id = row.id
|
||||||
retailPriceForm.package_name = row.package_name
|
retailPriceForm.package_name = row.package_name
|
||||||
// 将分转换为元显示
|
// 零售价值来自代理零售价
|
||||||
retailPriceForm.retail_price = row.suggested_retail_price ? row.suggested_retail_price / 100 : 0
|
retailPriceForm.retail_price = row.retail_price ? row.retail_price / 100 : 0
|
||||||
retailPriceDialogVisible.value = true
|
retailPriceDialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1329,4 +1456,32 @@
|
|||||||
.dialog-footer {
|
.dialog-footer {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gift-switch-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gift-hint {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
white-space: nowrap;
|
||||||
|
background-color: var(--el-color-warning-light-9);
|
||||||
|
color: var(--el-color-warning);
|
||||||
|
|
||||||
|
&--info {
|
||||||
|
background-color: var(--el-fill-color-light);
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gift-hint-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1359,7 +1359,8 @@
|
|||||||
|
|
||||||
const res = await PackageManageService.getPackages(params)
|
const res = await PackageManageService.getPackages(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
packageOptions.value = res.data.items
|
// 过滤掉赠送套餐
|
||||||
|
packageOptions.value = res.data.items.filter((pkg) => !pkg.is_gift)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载套餐选项失败:', error)
|
console.error('加载套餐选项失败:', error)
|
||||||
@@ -1999,6 +2000,16 @@
|
|||||||
|
|
||||||
// 可选:套餐配置(将元转换为分)
|
// 可选:套餐配置(将元转换为分)
|
||||||
if (form.packages.length > 0) {
|
if (form.packages.length > 0) {
|
||||||
|
// 验证是否包含赠送套餐
|
||||||
|
for (const pkg of form.packages) {
|
||||||
|
const pkgInfo = packageOptions.value.find((p) => p.id === pkg.package_id)
|
||||||
|
if (pkgInfo?.is_gift) {
|
||||||
|
ElMessage.error(`套餐 ${getPackageName(pkg.package_id)} 是赠送套餐,不能参与授权`)
|
||||||
|
submitLoading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 验证成本价是否在允许范围内
|
// 验证成本价是否在允许范围内
|
||||||
for (const pkg of form.packages) {
|
for (const pkg of form.packages) {
|
||||||
const costPrice = pkg.cost_price ?? 0
|
const costPrice = pkg.cost_price ?? 0
|
||||||
@@ -2138,7 +2149,8 @@
|
|||||||
|
|
||||||
const res = await PackageManageService.getPackages(params)
|
const res = await PackageManageService.getPackages(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
availablePackages.value = res.data.items
|
// 过滤掉赠送套餐
|
||||||
|
availablePackages.value = res.data.items.filter((pkg) => !pkg.is_gift)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载套餐选项失败:', error)
|
console.error('加载套餐选项失败:', error)
|
||||||
|
|||||||
Reference in New Issue
Block a user