<template>
|
<div class="price-manage-container">
|
<div class="page-header">
|
<div class="bar-title">
|
{{ productDetail?.name || '-' }} <span class="status" :class="statusClass">【{{ shelfStatus }}】</span>
|
</div>
|
</div>
|
|
<el-card class="detail-card" shadow="never">
|
<template #header>
|
<div class="card-header">
|
<div class="header-left">
|
<el-icon class="section-icon"><Goods /></el-icon>
|
<span>产品基本信息</span>
|
</div>
|
<div class="id-info">产品ID:{{ currentProductId || '未提供' }}</div>
|
</div>
|
</template>
|
|
<el-descriptions v-if="productDetail" :column="2" border>
|
<el-descriptions-item label="产品名称">{{ productDetail.name }}</el-descriptions-item>
|
<el-descriptions-item label="提报单位">{{ productDetail.submitUnit }}</el-descriptions-item>
|
<el-descriptions-item label="提报人">{{ productDetail.submitter }}</el-descriptions-item>
|
<el-descriptions-item label="行业领域">{{ productDetail.industry }}</el-descriptions-item>
|
<el-descriptions-item label="单位工程">{{ productDetail.projectUnit }}</el-descriptions-item>
|
<el-descriptions-item label="产业阶段">{{ productDetail.industryStage }}</el-descriptions-item>
|
<el-descriptions-item label="产品类型">{{ productDetail.productType }}</el-descriptions-item>
|
<el-descriptions-item label="产品简介" :span="3">
|
<div class="intro">{{ productDetail.description }}</div>
|
</el-descriptions-item>
|
</el-descriptions>
|
<el-empty v-else description="未找到该产品的详情" />
|
</el-card>
|
|
<div class="content-area">
|
<el-card class="price-card" shadow="never">
|
<template #header>
|
<div class="card-header">
|
<span>价格列表</span>
|
<div class="header-actions">
|
<el-button type="primary" @click="handleAddPrice">添加价格</el-button>
|
</div>
|
</div>
|
</template>
|
<div class="pricing-cards-container" v-if="priceList.length > 0">
|
<div class="pricing-cards-wrapper">
|
<div
|
v-for="pricing in priceList"
|
:key="pricing.id"
|
class="pricing-card"
|
:class="{
|
'pricing-card-enabled': pricing.enableStatus === 'ENABLED',
|
'pricing-card-disabled': pricing.enableStatus === 'DISABLED'
|
}"
|
>
|
<div class="pricing-card-table">
|
<div class="pricing-row">
|
<div class="pricing-cell label-cell">销售形式</div>
|
<div class="pricing-cell value-cell">{{ getSalesFormText(pricing.salesForm) || '-' }}</div>
|
<div class="pricing-cell label-cell">客户对象</div>
|
<div class="pricing-cell value-cell">{{ getCustomerObjectText(pricing.customerObject) || '-' }}</div>
|
</div>
|
<div class="pricing-row">
|
<div class="pricing-cell label-cell">账户数量</div>
|
<div class="pricing-cell value-cell">{{ pricing.accountQuantityUnlimited ? '不限' : (pricing.accountQuantity || '-') }}</div>
|
<div class="pricing-cell label-cell">并发节点数</div>
|
<div class="pricing-cell value-cell">{{ pricing.concurrentNodeQuantityUnlimited ? '不限' : (pricing.concurrentNodeQuantity || '-') }}</div>
|
</div>
|
<div class="pricing-row">
|
<div class="pricing-cell label-cell">购买方式</div>
|
<div class="pricing-cell value-cell purchase-methods-cell">
|
<div class="method-item">
|
<span class="method-label">积分:</span>
|
<span class="method-value points">{{ pricing.priceSettings?.includes('POINTS') ? (pricing.pointsAmount || '-') + '/套' : '-' }}</span>
|
</div>
|
<div class="method-item">
|
<span class="method-label">货币:</span>
|
<span class="method-value currency">{{ pricing.priceSettings?.includes('CURRENCY') ? (pricing.currencyAmount || '-') + '/套' : '-' }}</span>
|
</div>
|
<div class="method-item">
|
<span class="method-label">协议:</span>
|
<span class="method-value agreement">{{ pricing.priceSettings?.includes('AGREEMENT') ? '每套' : '-' }}</span>
|
</div>
|
<div class="method-item">
|
<span class="method-label">免费:</span>
|
<span class="method-value free">{{ pricing.priceSettings?.includes('FREE') ? '免费' : '-' }}</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<div class="pricing-status-tag">
|
<el-tag :type="pricing.enableStatus === 'ENABLED' ? 'success' : 'danger'" size="small" effect="dark">
|
当前状态:{{ getEnableStatusText(pricing.enableStatus) }}
|
</el-tag>
|
</div>
|
|
<div class="pricing-card-actions">
|
<span class="action-link edit-link" @click="handleEdit(pricing)">编辑</span>
|
<span class="action-link delete-link" @click="handleDelete(pricing)">删除</span>
|
<span
|
class="action-link"
|
:class="pricing.enableStatus === 'ENABLED' ? 'disable-link' : 'enable-link'"
|
@click="handleToggleEnableStatus(pricing)"
|
>
|
<el-icon>
|
<Lock v-if="pricing.enableStatus === 'ENABLED'" />
|
<Unlock v-else />
|
</el-icon>
|
{{ pricing.enableStatus === 'ENABLED' ? '停用' : '启用' }}
|
</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
<div v-else class="empty-pricing">
|
<el-empty description="暂无定价信息" />
|
</div>
|
</el-card>
|
</div>
|
|
<!-- 新增/编辑价格弹窗 -->
|
<el-dialog
|
v-model="dialogVisible"
|
:title="isEditMode ? '编辑价格' : '新增价格'"
|
width="960px"
|
destroy-on-close
|
>
|
<el-form
|
ref="formRef"
|
:model="formData"
|
:rules="formRules"
|
label-width="80px"
|
label-position="left"
|
status-icon
|
size="large"
|
class="price-form"
|
>
|
<el-row :gutter="8">
|
<el-col :span="12">
|
<el-form-item label="产品套件" prop="productSuite">
|
<el-select v-model="formData.productSuite" placeholder="请选择" style="width: 100%">
|
<el-option v-for="opt in productSuiteOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="客户对象" prop="customerObject">
|
<el-radio-group v-model="formData.customerObject">
|
<el-radio v-for="opt in customerObjectOptions" :key="opt.value" :label="opt.value">{{ opt.label }}</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-form-item label="销售形式" prop="salesForm" class="sales-form-item">
|
<el-radio-group v-model="formData.salesForm" class="sales-form-group">
|
<el-radio v-for="opt in salesFormOptions" :key="opt.value" :label="opt.value">{{ opt.label }}</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
|
<el-row :gutter="8">
|
<el-col :span="12">
|
<el-form-item label="账户数量" prop="accountQuantity">
|
<div class="quantity-input-group">
|
<el-input-number v-model="formData.accountQuantity" :min="1" :controls="false" style="width: 180px" :disabled="formData.accountQuantityUnlimited" />
|
<el-checkbox v-model="formData.accountQuantityUnlimited" style="margin-left: 6px">不限</el-checkbox>
|
</div>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="并发节点" prop="concurrentNodeQuantity">
|
<div class="quantity-input-group">
|
<el-input-number v-model="formData.concurrentNodeQuantity" :min="1" :controls="false" style="width: 180px" :disabled="formData.concurrentNodeQuantityUnlimited" />
|
<el-checkbox v-model="formData.concurrentNodeQuantityUnlimited" style="margin-left: 6px">不限</el-checkbox>
|
</div>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-form-item label="价格设置" prop="priceSettings">
|
<div class="price-settings">
|
<div class="price-setting-item">
|
<el-checkbox label="POINTS" :disabled="formData.priceSettings.includes('FREE')" v-model="checkboxPoints">积分</el-checkbox>
|
<el-input-number v-if="formData.priceSettings.includes('POINTS')" v-model="formData.pointsAmount" :min="0" :precision="2" :controls="false" placeholder="积分金额" style="width: 120px; margin-left: 6px" />
|
</div>
|
<div class="price-setting-item">
|
<el-checkbox label="CURRENCY" :disabled="formData.priceSettings.includes('FREE')" v-model="checkboxCurrency">货币</el-checkbox>
|
<el-input-number v-if="formData.priceSettings.includes('CURRENCY')" v-model="formData.currencyAmount" :min="0" :precision="2" :controls="false" placeholder="货币金额" style="width: 120px; margin-left: 6px" />
|
</div>
|
<div class="price-setting-item">
|
<el-checkbox label="AGREEMENT" :disabled="formData.priceSettings.includes('FREE')" v-model="checkboxAgreement">协议</el-checkbox>
|
</div>
|
<div class="price-setting-item">
|
<el-checkbox label="FREE" :disabled="formData.priceSettings.length > 0 && !formData.priceSettings.includes('FREE')" v-model="checkboxFree">免费</el-checkbox>
|
</div>
|
</div>
|
</el-form-item>
|
|
<el-row :gutter="8">
|
<el-col :span="12">
|
<el-form-item label="价格单位" prop="priceUnit">
|
<el-select v-model="formData.priceUnit" placeholder="请选择" style="width: 100%">
|
<el-option v-for="opt in priceUnitOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="启用状态" prop="enableStatus">
|
<el-radio-group v-model="formData.enableStatus">
|
<el-radio v-for="opt in enableStatusOptions" :key="opt.value" :label="opt.value">{{ opt.label }}</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
|
|
<el-form-item label="备注">
|
<el-input type="textarea" v-model="formData.remark" :rows="3" placeholder="请输入备注" />
|
</el-form-item>
|
</el-form>
|
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button type="primary" :loading="saving" @click="handleSave">保 存</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
|
<!-- 价格查看器 -->
|
<ProductPriceViewer
|
v-model="showPriceViewer"
|
:product-id="currentProductId"
|
@order="handleOrderResult"
|
/>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { ref, onMounted, watch, computed, reactive } from 'vue'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { useRoute } from 'vue-router'
|
import { Goods, Lock, Unlock } from '@element-plus/icons-vue'
|
import ProductPriceViewer from '@/views/productManage/productPriceViewer/index.vue'
|
|
interface ProductDetail {
|
id: string
|
name: string
|
submitUnit: string
|
submitter: string
|
industry: string
|
projectUnit: string
|
industryStage: string
|
productType: string
|
description: string
|
shelfStatus?: '待上架' | '已上架' | '已下架'
|
}
|
|
interface PriceItem {
|
id: number | null
|
productId: string | undefined
|
productSuite: string
|
salesForm: 'BUYOUT' | 'LEASE' | 'PRIVATE_INCREMENT' | 'PUBLIC_INCREMENT' | 'OTA' | 'CLOUD' | 'RESOURCE_PACKAGE' | 'PERSONAL'
|
customerObject: 'ENTERPRISE' | 'PERSONAL' | 'PROJECT_DEPARTMENT'
|
accountQuantity: number | ''
|
accountQuantityUnlimited: boolean
|
concurrentNodeQuantity: number | ''
|
concurrentNodeQuantityUnlimited: boolean
|
priceSettings: Array<'POINTS' | 'CURRENCY' | 'AGREEMENT' | 'FREE'>
|
pointsAmount: number | ''
|
currencyAmount: number | ''
|
priceUnit: '' | 'SET' | 'SET_PER_YEAR' | 'YEAR'
|
enableStatus: 'ENABLED' | 'DISABLED'
|
authorizationStartTime?: string
|
authorizationEndTime?: string
|
remark?: string
|
}
|
|
const route = useRoute()
|
|
// 兼容 path 参数 productId 与 query 参数 id/productId
|
const currentProductId = computed<string | undefined>(() => {
|
return (route.params.productId as string) || (route.query.productId as string) || (route.query.id as string)
|
})
|
|
const productDetail = ref<ProductDetail | null>(null)
|
const shelfStatus = computed(() => productDetail.value?.shelfStatus || '待上架')
|
const statusClass = computed(() => {
|
switch (shelfStatus.value) {
|
case '已上架':
|
return 'status-online'
|
case '待上架':
|
return 'status-pending'
|
case '已下架':
|
return 'status-offline'
|
default:
|
return 'status-default'
|
}
|
})
|
|
// 模拟产品详情数据源
|
const mockProductMap: Record<string, ProductDetail> = {
|
'10001': {
|
id: '10001',
|
name: '数字化产品A',
|
submitUnit: '中交一公局',
|
submitter: '张三',
|
industry: '交通基础设施',
|
projectUnit: '某高速公路工程',
|
industryStage: '应用阶段',
|
productType: '软件/平台',
|
description: '本产品定位为以建设期BIM数字资产作为数字底盘,结合项目运营维保需求的实时性、交互性、便捷性的三维可视化运维管理系统。系统提供项目数字化、智能化运维管理功能,能够解决建筑运行维护管理中的实际问题,实现信息快速整合与查询、信息有效共享与传递,提升项目综合管理与维护水平。',
|
shelfStatus: '待上架'
|
},
|
'10002': {
|
id: '10002',
|
name: '数字化产品B',
|
submitUnit: '中交二航局',
|
submitter: '李四',
|
industry: '市政工程',
|
projectUnit: '智慧管廊项目',
|
industryStage: '研发阶段',
|
productType: '硬件/传感',
|
description: '面向城市管廊监测的传感设备与采集网关,支持边缘计算与远程运维。',
|
shelfStatus: '已上架'
|
}
|
}
|
|
const loading = ref(false)
|
const priceList = ref<any[]>([])
|
|
// 弹窗与表单
|
const dialogVisible = ref(false)
|
const showPriceViewer = ref(false)
|
const isEditMode = ref(false)
|
const saving = ref(false)
|
const formRef = ref()
|
const formData = reactive<PriceItem>({
|
id: null,
|
productId: undefined,
|
productSuite: '',
|
salesForm: 'BUYOUT',
|
customerObject: 'ENTERPRISE',
|
accountQuantity: '',
|
accountQuantityUnlimited: false,
|
concurrentNodeQuantity: '',
|
concurrentNodeQuantityUnlimited: false,
|
priceSettings: [],
|
pointsAmount: '',
|
currencyAmount: '',
|
priceUnit: '',
|
enableStatus: 'ENABLED',
|
authorizationStartTime: undefined,
|
authorizationEndTime: undefined,
|
remark: ''
|
})
|
|
// 选项
|
const productSuiteOptions = [
|
{ label: '企业私有SaaS版许可', value: 'ENTERPRISE_PRIVATE_SAAS_LICENSE' },
|
{ label: '企业私有SaaS版OTA服务', value: 'ENTERPRISE_PRIVATE_SAAS_OTA' },
|
{ label: '企业私有SaaS版用户增量包', value: 'ENTERPRISE_PRIVATE_SAAS_USER_INCREMENT' },
|
{ label: '企业公有SaaS版许可', value: 'ENTERPRISE_PUBLIC_SAAS_LICENSE' },
|
{ label: '企业公有SaaS版OTA服务', value: 'ENTERPRISE_PUBLIC_SAAS_OTA' },
|
{ label: '企业公有SaaS版用户增量包', value: 'ENTERPRISE_PUBLIC_SAAS_USER_INCREMENT' },
|
{ label: '个人公有SaaS化许可', value: 'PERSONAL_PUBLIC_SAAS_LICENSE' },
|
{ label: 'web软件', value: 'WEB_SOFTWARE' },
|
{ label: '桌面软件', value: 'DESKTOP_SOFTWARE' }
|
]
|
const salesFormOptions = [
|
{ label: '买断', value: 'BUYOUT' },
|
{ label: '租赁', value: 'LEASE' },
|
{ label: '私有增量包', value: 'PRIVATE_INCREMENT' },
|
{ label: '共有增量包', value: 'PUBLIC_INCREMENT' },
|
{ label: 'OTA服务', value: 'OTA' },
|
{ label: '云服务', value: 'CLOUD' },
|
{ label: '资源包', value: 'RESOURCE_PACKAGE' },
|
{ label: '个人', value: 'PERSONAL' }
|
]
|
const customerObjectOptions = [
|
{ label: '企业', value: 'ENTERPRISE' },
|
{ label: '个人', value: 'PERSONAL' },
|
{ label: '项目部', value: 'PROJECT_DEPARTMENT' }
|
]
|
const priceUnitOptions = [
|
{ label: '套', value: 'SET' },
|
{ label: '套/年', value: 'SET_PER_YEAR' },
|
{ label: '年', value: 'YEAR' }
|
]
|
const enableStatusOptions = [
|
{ label: '启用', value: 'ENABLED' },
|
{ label: '停用', value: 'DISABLED' }
|
]
|
|
// 价格设置复选框的双向绑定辅助(方便互斥逻辑)
|
const checkboxPoints = computed({
|
get: () => formData.priceSettings.includes('POINTS'),
|
set: (val: boolean) => updatePriceSettings('POINTS', val)
|
})
|
const checkboxCurrency = computed({
|
get: () => formData.priceSettings.includes('CURRENCY'),
|
set: (val: boolean) => updatePriceSettings('CURRENCY', val)
|
})
|
const checkboxAgreement = computed({
|
get: () => formData.priceSettings.includes('AGREEMENT'),
|
set: (val: boolean) => updatePriceSettings('AGREEMENT', val)
|
})
|
const checkboxFree = computed({
|
get: () => formData.priceSettings.includes('FREE'),
|
set: (val: boolean) => updatePriceSettings('FREE', val)
|
})
|
|
function updatePriceSettings(key: 'POINTS' | 'CURRENCY' | 'AGREEMENT' | 'FREE', checked: boolean) {
|
const has = formData.priceSettings.includes(key)
|
if (checked && !has) {
|
// 若选择 FREE,清空其他
|
if (key === 'FREE') {
|
formData.priceSettings = ['FREE']
|
formData.pointsAmount = ''
|
formData.currencyAmount = ''
|
return
|
}
|
// 若此前有 FREE,去掉 FREE
|
formData.priceSettings = formData.priceSettings.filter(k => k !== 'FREE')
|
formData.priceSettings.push(key)
|
} else if (!checked && has) {
|
formData.priceSettings = formData.priceSettings.filter(k => k !== key)
|
}
|
}
|
|
// 校验规则
|
const formRules = {
|
productSuite: [{ required: true, message: '请选择产品套件', trigger: 'change' }],
|
salesForm: [{ required: true, message: '请选择销售形式', trigger: 'change' }],
|
customerObject: [{ required: true, message: '请选择客户对象', trigger: 'change' }],
|
accountQuantity: [{
|
required: true,
|
validator: (_: any, value: any, cb: any) => {
|
if (!formData.accountQuantityUnlimited && (!value || value <= 0)) cb(new Error('请输入账户数量'))
|
else cb()
|
},
|
trigger: 'blur'
|
}],
|
concurrentNodeQuantity: [{
|
required: true,
|
validator: (_: any, value: any, cb: any) => {
|
if (!formData.concurrentNodeQuantityUnlimited && (!value || value <= 0)) cb(new Error('请输入并发节点数量'))
|
else cb()
|
},
|
trigger: 'blur'
|
}],
|
priceSettings: [{
|
required: true,
|
validator: (_: any, value: any[], cb: any) => {
|
if (!value || value.length === 0) return cb(new Error('请至少选择一种价格设置'))
|
if (value.includes('FREE') && value.length > 1) return cb(new Error('免费选项不能与其他选项同时选择'))
|
if (value.includes('POINTS') && (formData.pointsAmount === '' || formData.pointsAmount === undefined)) return cb(new Error('请输入积分金额'))
|
if (value.includes('CURRENCY') && (formData.currencyAmount === '' || formData.currencyAmount === undefined)) return cb(new Error('请输入货币金额'))
|
cb()
|
},
|
trigger: 'change'
|
}],
|
priceUnit: [{ required: true, message: '请选择价格单位', trigger: 'change' }],
|
enableStatus: [{ required: true, message: '请选择启用状态', trigger: 'change' }],
|
// 已移除开始/结束时间字段的设置与校验
|
} as any
|
|
// 下列函数仅用于演示卡片视图标签文本
|
const getSalesFormText = (salesForm?: string) => {
|
const map: Record<string, string> = {
|
BUYOUT: '买断',
|
LEASE: '租赁',
|
PRIVATE_INCREMENT: '私有增量包',
|
PUBLIC_INCREMENT: '共有增量包',
|
OTA: 'OTA服务',
|
CLOUD: '云服务',
|
RESOURCE_PACKAGE: '资源包',
|
PERSONAL: '个人',
|
}
|
return map[salesForm || ''] || salesForm || '-'
|
}
|
const getCustomerObjectText = (customerObject?: string) => {
|
const map: Record<string, string> = { ENTERPRISE: '企业', PERSONAL: '个人', PROJECT_DEPARTMENT: '项目部' }
|
return map[customerObject || ''] || customerObject || '-'
|
}
|
const getEnableStatusText = (status?: string) => {
|
const map: Record<string, string> = { ENABLED: '启用', DISABLED: '停用' }
|
return map[status || ''] || status || '-'
|
}
|
|
const getPriceUnitText = (unit?: string) => {
|
const map: Record<string, string> = {
|
SET: '套',
|
SET_PER_YEAR: '套/年',
|
YEAR: '年'
|
}
|
return map[unit || ''] || unit || ''
|
}
|
|
function fetchProductDetail(productId?: string) {
|
if (!productId) {
|
productDetail.value = null
|
ElMessage.warning('未提供产品ID,无法加载产品详情')
|
return
|
}
|
// 模拟异步
|
loading.value = true
|
setTimeout(() => {
|
productDetail.value = mockProductMap[productId] || null
|
// 构造卡片所需的演示定价数据
|
priceList.value = productDetail.value
|
? [
|
{
|
id: 1,
|
productId: productId,
|
productSuite: 'STANDARD',
|
salesForm: 'BUYOUT',
|
customerObject: 'ENTERPRISE',
|
accountQuantity: 50,
|
accountQuantityUnlimited: false,
|
concurrentNodeQuantity: 50,
|
concurrentNodeQuantityUnlimited: false,
|
priceSettings: ['POINTS'],
|
pointsAmount: 50000,
|
currencyAmount: 0,
|
priceUnit: 'SET_PER_YEAR',
|
enableStatus: 'ENABLED',
|
authorizationStartTime: '2025-01-01',
|
authorizationEndTime: '2025-12-31',
|
remark: '演示数据'
|
},
|
{
|
id: 2,
|
productId: productId,
|
productSuite: 'PRO',
|
salesForm: 'PRIVATE_INCREMENT',
|
customerObject: 'ENTERPRISE',
|
accountQuantity: 100,
|
accountQuantityUnlimited: false,
|
concurrentNodeQuantity: 100,
|
concurrentNodeQuantityUnlimited: false,
|
priceSettings: ['CURRENCY'],
|
pointsAmount: 0,
|
currencyAmount: 7500,
|
priceUnit: 'SET',
|
enableStatus: 'DISABLED',
|
authorizationStartTime: '2025-01-01',
|
authorizationEndTime: '2025-06-30',
|
remark: '演示数据'
|
}
|
]
|
: []
|
loading.value = false
|
}, 300)
|
}
|
|
// 查看价格
|
const handleViewPricing = () => {
|
if (!currentProductId.value) {
|
ElMessage.warning('请先选择产品')
|
return
|
}
|
showPriceViewer.value = true
|
}
|
|
// 添加价格
|
const handleAddPrice = () => {
|
isEditMode.value = false
|
resetForm()
|
formData.productId = currentProductId.value
|
formData.id = generateId()
|
dialogVisible.value = true
|
}
|
|
// 编辑价格
|
const handleEdit = (row: any) => {
|
isEditMode.value = true
|
resetForm()
|
Object.assign(formData, {
|
id: row.id ?? generateId(),
|
productId: currentProductId.value,
|
productSuite: row.productSuite || '',
|
salesForm: row.salesForm || 'BUYOUT',
|
customerObject: row.customerObject || 'ENTERPRISE',
|
accountQuantity: row.accountQuantity ?? '',
|
accountQuantityUnlimited: !!row.accountQuantityUnlimited,
|
concurrentNodeQuantity: row.concurrentNodeQuantity ?? '',
|
concurrentNodeQuantityUnlimited: !!row.concurrentNodeQuantityUnlimited,
|
priceSettings: Array.isArray(row.priceSettings) ? row.priceSettings : [],
|
pointsAmount: row.pointsAmount ?? '',
|
currencyAmount: row.currencyAmount ?? '',
|
priceUnit: row.priceUnit || '',
|
enableStatus: row.enableStatus || 'ENABLED',
|
authorizationStartTime: row.authorizationStartTime,
|
authorizationEndTime: row.authorizationEndTime,
|
remark: row.remark || ''
|
})
|
dialogVisible.value = true
|
}
|
|
// 删除价格
|
const handleDelete = (row: any) => {
|
ElMessageBox.confirm(
|
`确定要删除该价格(ID: ${row.id})吗?`,
|
'确认删除',
|
{
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
}
|
)
|
.then(() => {
|
const idx = priceList.value.findIndex((p: any) => p.id === row.id)
|
if (idx !== -1) priceList.value.splice(idx, 1)
|
ElMessage.success('删除成功')
|
})
|
.catch(() => {
|
ElMessage.info('已取消删除')
|
})
|
}
|
|
onMounted(() => {
|
fetchProductDetail(currentProductId.value)
|
})
|
|
watch(
|
() => [route.params.productId, route.query.productId, route.query.id],
|
() => fetchProductDetail(currentProductId.value)
|
)
|
|
function resetForm() {
|
Object.assign(formData, {
|
id: null,
|
productId: currentProductId.value,
|
productSuite: '',
|
salesForm: 'BUYOUT',
|
customerObject: 'ENTERPRISE',
|
accountQuantity: '',
|
accountQuantityUnlimited: false,
|
concurrentNodeQuantity: '',
|
concurrentNodeQuantityUnlimited: false,
|
priceSettings: [],
|
pointsAmount: '',
|
currencyAmount: '',
|
priceUnit: '',
|
enableStatus: 'ENABLED',
|
authorizationStartTime: undefined,
|
authorizationEndTime: undefined,
|
remark: ''
|
})
|
if (formRef.value) formRef.value.clearValidate()
|
}
|
|
function generateId() {
|
const maxId = priceList.value.reduce((m: number, it: any) => Math.max(m, Number(it.id || 0)), 0)
|
return maxId + 1
|
}
|
|
async function handleSave() {
|
try {
|
await formRef.value.validate()
|
} catch (e) {
|
return
|
}
|
|
saving.value = true
|
try {
|
const record: PriceItem = JSON.parse(JSON.stringify(formData))
|
const idx = priceList.value.findIndex((p: any) => p.id === record.id)
|
if (idx === -1) {
|
priceList.value.push(record)
|
} else {
|
priceList.value.splice(idx, 1, record)
|
}
|
ElMessage.success(isEditMode.value ? '修改成功' : '新建成功')
|
dialogVisible.value = false
|
} finally {
|
saving.value = false
|
}
|
}
|
|
// 处理订购结果
|
const handleOrderResult = (selectedItems: any[]) => {
|
console.log('用户选择的价格项:', selectedItems)
|
ElMessage.success(`已选择 ${selectedItems.length} 个价格套件进入订购流程`)
|
}
|
|
// 启用/停用按钮
|
function handleToggleEnableStatus(row: any) {
|
const newStatus = row.enableStatus === 'ENABLED' ? 'DISABLED' : 'ENABLED'
|
ElMessageBox.confirm(
|
`确认要${newStatus === 'ENABLED' ? '启用' : '停用'}该价格(ID: ${row.id})吗?`,
|
'状态变更',
|
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
)
|
.then(() => {
|
const idx = priceList.value.findIndex((p: any) => p.id === row.id)
|
if (idx !== -1) {
|
priceList.value[idx] = { ...priceList.value[idx], enableStatus: newStatus }
|
}
|
ElMessage.success(newStatus === 'ENABLED' ? '启用成功' : '停用成功')
|
})
|
.catch(() => {})
|
}
|
</script>
|
|
<style scoped lang="scss">
|
.price-manage-container {
|
padding: 20px;
|
|
.page-header {
|
margin-bottom: 16px;
|
background: #e6eef9;
|
border-radius: 2px;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
padding: 10px 0;
|
.bar-title { font-size: 16px; font-weight: 600; color: #5e6b85; }
|
}
|
|
.detail-card { margin-bottom: 16px; }
|
/* 仅控制产品信息卡片的内间距 */
|
.detail-card :deep(.el-card__body) {
|
padding: 2px !important;
|
}
|
|
/* 关键:让描述列表6个单元格等分,从而每条信息(2格)等宽 */
|
.detail-card :deep(.el-descriptions__table) {
|
table-layout: fixed;
|
width: 100%;
|
}
|
.detail-card :deep(.el-descriptions__label),
|
.detail-card :deep(.el-descriptions__content) {
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
}
|
|
.content-area {
|
.price-card {
|
.card-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
span { font-size: 14px; font-weight: 700; }
|
}
|
.price-value { color: #e6a23c; font-weight: 500; }
|
}
|
}
|
}
|
|
.card-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.header-actions {
|
display: flex;
|
gap: 8px;
|
}
|
}
|
.header-left { display: inline-flex; align-items: center; }
|
.section-icon { margin-right: 6px; color: #409eff; }
|
.detail-card .card-header span { font-size: 14px; font-weight: 700; }
|
.id-info { color: #909399; font-size: 12px; }
|
.intro { white-space: pre-wrap; }
|
/* ---------- 定价卡片样式(参考 PricingManagement.vue,做精简) ---------- */
|
.pricing-cards-container { position: relative; display: block; }
|
.pricing-cards-wrapper { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; padding: 10px 0; }
|
.pricing-card { width: 100%; border: 1px solid #e4e7ed; border-radius: 8px; padding: 16px; background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.1); transition: all 0.3s ease; position: relative; }
|
.pricing-card:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.15); transform: translateY(-2px); }
|
.pricing-card-enabled { border: 2px solid #67c23a; box-shadow: 0 2px 8px rgba(103,194,58,0.2); }
|
.pricing-card-disabled { border: 2px solid #f56c6c; box-shadow: 0 2px 8px rgba(245,108,108,0.2); opacity: 0.9; }
|
.pricing-card-table { width: 100%; border-collapse: collapse; margin-bottom: 16px; border: 1px solid #e4e7ed; }
|
.pricing-row { display: flex; border-bottom: 1px solid #e4e7ed; }
|
.pricing-row:last-child { border-bottom: none; }
|
.pricing-cell { padding: 10px 8px; font-size: 14px; display: flex; align-items: center; border-right: 1px solid #e4e7ed; }
|
.pricing-cell:last-child { border-right: none; }
|
.label-cell { width: 25%; color: #606266; font-weight: 500; background-color: #f5f7fa; justify-content: center; }
|
.value-cell { width: 25%; color: #303133; font-weight: 400; justify-content: center; }
|
.purchase-methods-cell { width: 75%; flex-direction: column; align-items: flex-start; gap: 6px; justify-content: flex-start; }
|
.method-item { display: flex; align-items: center; gap: 8px; width: 100%; }
|
.method-label { font-size: 14px; color: #606266; min-width: 40px; }
|
.method-value { font-size: 14px; font-weight: 500; }
|
.method-value.points,.method-value.currency { color: #f56c6c; }
|
.method-value.free { color: #67c23a; }
|
.pricing-card-actions { display: flex; justify-content: center; gap: 20px; padding-top: 12px; border-top: 1px solid #f0f0f0; }
|
.action-link { cursor: pointer; font-size: 14px; transition: all 0.3s ease; }
|
.action-link.edit-link { color: #409eff; }
|
.action-link.delete-link { color: #f56c6c; }
|
.action-link.disable-link { color: #e6a23c; }
|
.action-link.enable-link { color: #67c23a; }
|
.pricing-status-tag { position: absolute; top: 8px; left: 8px; z-index: 10; }
|
.empty-pricing { text-align: center; padding: 40px 0; }
|
/* 表单局部样式 */
|
.price-settings { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
|
.price-setting-item { display: inline-flex; align-items: center; gap: 8px; }
|
.quantity-input-group { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
|
.sales-form-item :deep(.el-form-item__content) { white-space: nowrap; }
|
.sales-form-group { display: inline-flex; gap: 12px; flex-wrap: nowrap; }
|
.price-form :deep(.el-form-item) { margin-bottom: 12px; }
|
/* 上架状态颜色 */
|
.status-online { color: #67C23A; }
|
.status-pending { color: #E6A23C; }
|
.status-offline { color: #F56C6C; }
|
.status-default { color: #909399; }
|
</style>
|