p-honggang.li
9 天以前 bd125eecd57d2f4e559c6170d20157591300fe3d
src/views/productManage/price/index.vue
@@ -18,15 +18,15 @@
      </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="产品名称" label-width="10%">{{ productDetail.name }}</el-descriptions-item>
        <el-descriptions-item label="提报单位" label-width="10%">{{ productDetail.submissionUnit }}</el-descriptions-item>
        <el-descriptions-item label="提报人" label-width="10%">{{ productDetail.createBy }}</el-descriptions-item>
        <el-descriptions-item label="行业领域" label-width="10%">{{ productDetail.industrialChainName }}</el-descriptions-item>
        <el-descriptions-item label="单位工程" label-width="10%">{{ productDetail.importantAreaName }}</el-descriptions-item>
        <el-descriptions-item label="产业阶段" label-width="10%">{{ productDetail.businessProcessName }}</el-descriptions-item>
        <el-descriptions-item label="产品类型"label-width="10%">{{ productDetail.typeName }}</el-descriptions-item>
        <el-descriptions-item label="产品简介" :span="3">
          <div class="intro">{{ productDetail.description }}</div>
          <div class="intro">{{ productDetail.describe }}</div>
        </el-descriptions-item>
      </el-descriptions>
      <el-empty v-else description="未找到该产品的详情" />
@@ -43,9 +43,15 @@
          </div>
        </template>
        <div class="pricing-cards-container" v-if="priceList.length > 0">
          <div
            v-for="group in priceList"
            :key="group.suiteName"
            class="pricing-group"
          >
            <div class="group-header">{{ group.suiteName }}</div>
          <div class="pricing-cards-wrapper">
            <div
              v-for="pricing in priceList"
                v-for="pricing in group.items"
              :key="pricing.id"
              class="pricing-card"
              :class="{
@@ -71,19 +77,19 @@
                  <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>
                      <span class="method-value points">{{ pricing.priceSettings?.includes('POINTS') ? (pricing.pointsPrice || '-') + '/' + getPriceUnitText(pricing.priceUnit) : '-' }}</span>
                    </div>
                    <div class="method-item">
                    <div class="method-item" v-if="pricing.priceSettings?.includes('CURRENCY')">
                      <span class="method-label">货币:</span>
                      <span class="method-value currency">{{ pricing.priceSettings?.includes('CURRENCY') ? (pricing.currencyAmount || '-') + '/套' : '-' }}</span>
                      <span class="method-value currency">{{ (pricing.currencyPrice || '-') + '/' + getPriceUnitText(pricing.priceUnit) }}</span>
                    </div>
                    <div class="method-item">
                    <div class="method-item" v-if="pricing.priceSettings?.includes('AGREEMENT')">
                      <span class="method-label">协议:</span>
                      <span class="method-value agreement">{{ pricing.priceSettings?.includes('AGREEMENT') ? '每套' : '-' }}</span>
                      <span class="method-value agreement">{{ '/' + getPriceUnitText(pricing.priceUnit) }}</span>
                    </div>
                    <div class="method-item">
                    <div class="method-item" v-if="pricing.priceSettings?.includes('FREE')">
                      <span class="method-label">免费:</span>
                      <span class="method-value free">{{ pricing.priceSettings?.includes('FREE') ? '免费' : '-' }}</span>
                      <span class="method-value free">{{ '/' + getPriceUnitText(pricing.priceUnit) }}</span>
                    </div>
                  </div>
                </div>
@@ -109,6 +115,7 @@
                  </el-icon>
                  {{ pricing.enableStatus === 'ENABLED' ? '停用' : '启用' }}
                </span>
              </div>
              </div>
            </div>
          </div>
@@ -136,57 +143,48 @@
        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-select v-model="formData.productSuite" placeholder="请选择" style="width: 60%">
                <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" />
              <el-input-number v-if="formData.priceSettings.includes('POINTS')" v-model="formData.pointsPrice" :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" />
              <el-input-number v-if="formData.priceSettings.includes('CURRENCY')" v-model="formData.currencyPrice" :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>
@@ -197,23 +195,19 @@
          </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="备注">
@@ -229,12 +223,6 @@
      </template>
    </el-dialog>
    <!-- 价格查看器 -->
    <ProductPriceViewer
      v-model="showPriceViewer"
      :product-id="currentProductId"
      @order="handleOrderResult"
    />
  </div>
</template>
@@ -244,18 +232,22 @@
import { useRoute } from 'vue-router'
import { Goods, Lock, Unlock } from '@element-plus/icons-vue'
import ProductPriceViewer from '@/views/productManage/productPriceViewer/index.vue'
import productPricingApi from '@/api/productPricingApi'
import productApi from '@/api/productApi'
interface ProductDetail {
  id: string
  name: string
  submitUnit: string
  submitter: string
  industry: string
  projectUnit: string
  industryStage: string
  productType: string
  description: string
  submissionUnit: string
  createBy: string
  industrialChainName: string
  importantAreaName: string
  businessProcessName: string
  typeName: string
  describe: string
  shelfStatus?: '待上架' | '已上架' | '已下架'
  listingStatusName?: ''
}
interface PriceItem {
@@ -269,8 +261,8 @@
  concurrentNodeQuantity: number | ''
  concurrentNodeQuantityUnlimited: boolean
  priceSettings: Array<'POINTS' | 'CURRENCY' | 'AGREEMENT' | 'FREE'>
  pointsAmount: number | ''
  currencyAmount: number | ''
  pointsPrice: number | ''
  currencyPrice: number | ''
  priceUnit: '' | 'SET' | 'SET_PER_YEAR' | 'YEAR'
  enableStatus: 'ENABLED' | 'DISABLED'
  authorizationStartTime?: string
@@ -286,7 +278,7 @@
})
const productDetail = ref<ProductDetail | null>(null)
const shelfStatus = computed(() => productDetail.value?.shelfStatus || '待上架')
const shelfStatus = computed(() => productDetail.value?.listingStatusName || '待上架')
const statusClass = computed(() => {
  switch (shelfStatus.value) {
    case '已上架':
@@ -301,32 +293,32 @@
})
// 模拟产品详情数据源
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 mockProductMap: Record<string, ProductDetail> = {
//   '1': {
//     id: '1',
//     name: '数字化产品A',
//     submitUnit: '中交一公局',
//     submitter: '张三',
//     industry: '交通基础设施',
//     projectUnit: '某高速公路工程',
//     industryStage: '应用阶段',
//     productType: '软件/平台',
//     description: '本产品定位为以建设期BIM数字资产作为数字底盘,结合项目运营维保需求的实时性、交互性、便捷性的三维可视化运维管理系统。系统提供项目数字化、智能化运维管理功能,能够解决建筑运行维护管理中的实际问题,实现信息快速整合与查询、信息有效共享与传递,提升项目综合管理与维护水平。',
//     shelfStatus: '待上架'
//   },
//   '2': {
//     id: '2',
//     name: '数字化产品B',
//     submitUnit: '中交二航局',
//     submitter: '李四',
//     industry: '市政工程',
//     projectUnit: '智慧管廊项目',
//     industryStage: '研发阶段',
//     productType: '硬件/传感',
//     description: '面向城市管廊监测的传感设备与采集网关,支持边缘计算与远程运维。',
//     shelfStatus: '已上架'
//   }
// }
const loading = ref(false)
const priceList = ref<any[]>([])
@@ -343,13 +335,13 @@
  productSuite: '',
  salesForm: 'BUYOUT',
  customerObject: 'ENTERPRISE',
  accountQuantity: '',
  accountQuantity: 1,
  accountQuantityUnlimited: false,
  concurrentNodeQuantity: '',
  concurrentNodeQuantity: 1,
  concurrentNodeQuantityUnlimited: false,
  priceSettings: [],
  pointsAmount: '',
  currencyAmount: '',
  pointsPrice: '',
  currencyPrice: '',
  priceUnit: '',
  enableStatus: 'ENABLED',
  authorizationStartTime: undefined,
@@ -359,15 +351,15 @@
// 选项
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' }
  { label: '企业私有SaaS版许可', value: '企业私有SaaS版许可' },
  { label: '企业私有SaaS版OTA服务', value: '企业私有SaaS版OTA服务' },
  { label: '企业私有SaaS版用户增量包', value: '企业私有SaaS版用户增量包' },
  { label: '企业公有SaaS版许可', value: '企业公有SaaS版许可' },
  { label: '企业公有SaaS版OTA服务', value: '企业公有SaaS版OTA服务' },
  { label: '企业公有SaaS版用户增量包', value: '企业公有SaaS版用户增量包' },
  { label: '个人公有SaaS化许可', value: '个人公有SaaS化许可' },
  { label: 'web软件', value: 'web软件' },
  { label: '桌面软件', value: '桌面软件' }
]
const salesFormOptions = [
  { label: '买断', value: 'BUYOUT' },
@@ -418,8 +410,8 @@
    // 若选择 FREE,清空其他
    if (key === 'FREE') {
      formData.priceSettings = ['FREE']
      formData.pointsAmount = ''
      formData.currencyAmount = ''
      formData.pointsPrice = ''
      formData.currencyPrice = ''
      return
    }
    // 若此前有 FREE,去掉 FREE
@@ -456,8 +448,8 @@
    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('请输入货币金额'))
      if (value.includes('POINTS') && (formData.pointsPrice === '' || formData.pointsPrice === undefined)) return cb(new Error('请输入积分金额'))
      if (value.includes('CURRENCY') && (formData.currencyPrice === '' || formData.currencyPrice === undefined)) return cb(new Error('请输入货币金额'))
      cb()
    },
    trigger: 'change'
@@ -499,61 +491,167 @@
  return map[unit || ''] || unit || ''
}
function fetchProductDetail(productId?: string) {
async 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: '演示数据'
          }
        ]
      : []
  try {
    // productDetail.value = mockProductMap[productId] || null
    const data = {
      id: productId
    }
    const detailRes: any = await productApi.getProductById(data)
    if (detailRes?.code === 200) {
      productDetail.value = detailRes.data || null
    } else {
      productDetail.value = null
      ElMessage.error(detailRes?.msg || '获取产品详情失败')
    }
    await loadPricingList(productId)
  } catch (e) {
    productDetail.value = null
    ElMessage.error('获取产品详情失败')
  } finally {
    loading.value = false
  }, 300)
  }
}
function mapSalesFormToCN(val: string) {
  const map: Record<string, string> = {
    BUYOUT: '买断',
    LEASE: '租赁',
    PRIVATE_INCREMENT: '私有增包量',
    PUBLIC_INCREMENT: '公有增包量',
    OTA: 'OTA服务',
    CLOUD: '云服务',
    RESOURCE_PACKAGE: '资源包',
    PERSONAL: '个人',
  }
  return map[val] || val
}
function mapSalesFormFromCN(val: string) {
  const map: Record<string, string> = {
    '买断': 'BUYOUT',
    '租赁': 'LEASE',
    '私有增包量': 'PRIVATE_INCREMENT',
    '公有增包量': 'PUBLIC_INCREMENT',
    'OTA服务': 'OTA',
    '云服务': 'CLOUD',
    '资源包': 'RESOURCE_PACKAGE',
    '个人': 'PERSONAL',
  }
  return (map[val] as any) || val
}
function mapCustomerToCN(val: string) {
  const map: Record<string, string> = { ENTERPRISE: '企业', PERSONAL: '个人', PROJECT_DEPARTMENT: '项目部' }
  return map[val] || val
}
function mapCustomerFromCN(val: string) {
  const map: Record<string, string> = { '企业': 'ENTERPRISE', '个人': 'PERSONAL', '项目部': 'PROJECT_DEPARTMENT' }
  return (map[val] as any) || val
}
function mapUnitToCN(val: string) {
  const map: Record<string, string> = { SET: '套', SET_PER_YEAR: '套/年', YEAR: '年' }
  return map[val] || val
}
function mapUnitFromCN(val: string) {
  const map: Record<string, string> = { '套': 'SET', '套/年': 'SET_PER_YEAR', '年': 'YEAR' }
  return (map[val] as any) || val
}
function mapPriceTypeToCN(key: 'POINTS' | 'CURRENCY' | 'AGREEMENT' | 'FREE') {
  const map: Record<string, string> = { POINTS: '积分', CURRENCY: '货币', AGREEMENT: '协议', FREE: '免费' }
  return map[key]
}
function mapPriceTypeFromCN(val: string): 'POINTS' | 'CURRENCY' | 'AGREEMENT' | 'FREE' | undefined {
  const map: Record<string, any> = { '积分': 'POINTS', '货币': 'CURRENCY', '协议': 'AGREEMENT', '免费': 'FREE' }
  return map[val]
}
async function loadPricingList(productId: string) {
  try {
    const res: any = await productPricingApi.listByProductId(productId)
    if (res?.code === 200) {
      const list = Array.isArray(res.data) ? res.data : []
      const newList = list.map((it: any) => {
        const priceSettings =  it.priceType.split(',').map((t:string) => mapPriceTypeFromCN(t))
        const pointsPrice = priceSettings.includes('POINTS') ? Number(it.pointsPrice || 0) : 0
        const currencyPrice = priceSettings.includes('CURRENCY') ? Number(it.currencyPrice || 0) : 0
        return {
          id: it.id,
          productId: String(it.productId || productId),
          productSuite: it.suiteName || '',
          salesForm: mapSalesFormFromCN(it.salesForm) as any,
          customerObject: mapCustomerFromCN(it.customerType) as any,
          accountQuantityUnlimited: (it.accountLimit === '不限'),
          accountQuantity: it.accountLimit === '不限' ? '' : Number(it.accountLimit || ''),
          concurrentNodeQuantityUnlimited: (it.concurrentNodes === '不限'),
          concurrentNodeQuantity: it.concurrentNodes === '不限' ? '' : Number(it.concurrentNodes || ''),
          priceSettings: priceSettings,
          pointsPrice,
          currencyPrice,
          priceUnit: mapUnitFromCN(it.priceUnit) as any,
          enableStatus: it.isActive ? 'ENABLED' : 'DISABLED',
          authorizationStartTime: undefined,
          authorizationEndTime: undefined,
          remark: it.description || '',
        }
      })
      const groupedList = newList.reduce((acc: any[], it: any) => {
        // 按productSuite分组
        const productSuite = it.productSuite
        if (!acc[productSuite]) {
          acc[productSuite] = []
        }
        acc[productSuite].push(it)
        return acc
      }, {})
      const newGroupedList:any  = []
      Object.entries(groupedList).forEach(([k,v]) =>{
        newGroupedList.push({
          suiteName: k,
          items: v
        })
      })
      priceList.value = newGroupedList
      console.log(priceList.value)
      console.log(groupedList)
    } else {
      priceList.value = []
    }
  } catch (e) {
    priceList.value = []
  }
}
function buildPayloadFromRow(row: any, overrides: Partial<any> = {}) {const priceTypeCN = row.priceSettings?.[0] ? mapPriceTypeToCN(row.priceSettings[0]) : undefined
  return {
    id: row.id,
    productId: row.productId,
    productName: productDetail.value?.name,
    suiteName: row.productSuite,
    salesForm: mapSalesFormToCN(row.salesForm),
    customerType: mapCustomerToCN(row.customerObject),
    accountLimit: row.accountQuantityUnlimited ? '不限' : String(row.accountQuantity || ''),
    concurrentNodes: row.concurrentNodeQuantityUnlimited ? '不限' : String(row.concurrentNodeQuantity || ''),
    priceType: row.priceSettings.map((t:string)=>mapPriceTypeToCN(t as any)).join(','),
    priceUnit: mapUnitToCN(row.priceUnit || ''),
    pointsPrice:  row.priceSettings.includes('POINTS') ? row.pointsPrice : '',
    currencyPrice:  row.priceSettings.includes('CURRENCY') ? row.currencyPrice : '',
    isActive: row.enableStatus === 'ENABLED',
    description: row.remark || '',
    ...overrides,
  }
}
// 查看价格
@@ -570,7 +668,6 @@
  isEditMode.value = false
  resetForm()
  formData.productId = currentProductId.value
  formData.id = generateId()
  dialogVisible.value = true
}
@@ -579,7 +676,7 @@
  isEditMode.value = true
  resetForm()
  Object.assign(formData, {
    id: row.id ?? generateId(),
    id: row.id,
    productId: currentProductId.value,
    productSuite: row.productSuite || '',
    salesForm: row.salesForm || 'BUYOUT',
@@ -589,8 +686,8 @@
    concurrentNodeQuantity: row.concurrentNodeQuantity ?? '',
    concurrentNodeQuantityUnlimited: !!row.concurrentNodeQuantityUnlimited,
    priceSettings: Array.isArray(row.priceSettings) ? row.priceSettings : [],
    pointsAmount: row.pointsAmount ?? '',
    currencyAmount: row.currencyAmount ?? '',
    pointsPrice: row.pointsPrice ?? '',
    currencyPrice: row.currencyPrice ?? '',
    priceUnit: row.priceUnit || '',
    enableStatus: row.enableStatus || 'ENABLED',
    authorizationStartTime: row.authorizationStartTime,
@@ -611,10 +708,10 @@
      type: 'warning'
    }
  )
    .then(() => {
      const idx = priceList.value.findIndex((p: any) => p.id === row.id)
      if (idx !== -1) priceList.value.splice(idx, 1)
    .then(async () => {
      await productPricingApi.remove(row.id)
      ElMessage.success('删除成功')
      if (currentProductId.value) await loadPricingList(currentProductId.value)
    })
    .catch(() => {
      ElMessage.info('已取消删除')
@@ -637,13 +734,13 @@
    productSuite: '',
    salesForm: 'BUYOUT',
    customerObject: 'ENTERPRISE',
    accountQuantity: '',
    accountQuantity: 1,
    accountQuantityUnlimited: false,
    concurrentNodeQuantity: '',
    concurrentNodeQuantity: 1,
    concurrentNodeQuantityUnlimited: false,
    priceSettings: [],
    pointsAmount: '',
    currencyAmount: '',
    pointsPrice: '',
    currencyPrice: '',
    priceUnit: '',
    enableStatus: 'ENABLED',
    authorizationStartTime: undefined,
@@ -653,10 +750,6 @@
  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 {
@@ -665,17 +758,89 @@
    return
  }
  if (!currentProductId.value) {
    ElMessage.warning('未提供产品ID,无法保存定价')
    return
  }
  const selectedTypes = formData.priceSettings
  if (!selectedTypes || selectedTypes.length === 0) {
    ElMessage.warning('请至少选择一种价格设置')
    return
  }
  const mapSalesFormToCN = (val: string) => ({
    BUYOUT: '买断',
    LEASE: '租赁',
    PRIVATE_INCREMENT: '私有增包量',
    PUBLIC_INCREMENT: '公有增包量',
    OTA: 'OTA服务',
    CLOUD: '云服务',
    RESOURCE_PACKAGE: '资源包',
    PERSONAL: '个人',
  } as any)[val] || val
  const mapCustomerToCN = (val: string) => ({ ENTERPRISE: '企业', PERSONAL: '个人', PROJECT_DEPARTMENT: '项目部' } as any)[val] || val
  const mapUnitToCN = (val: string) => ({ SET: '套', SET_PER_YEAR: '套/年', YEAR: '年' } as any)[val] || val
  const mapPriceTypeToCN = (key: 'POINTS' | 'CURRENCY' | 'AGREEMENT' | 'FREE') => ({ POINTS: '积分', CURRENCY: '货币', AGREEMENT: '协议', FREE: '免费' } as any)[key]
  const buildPayload = () => {
    return {
      id: isEditMode.value && formData.id  ? formData.id : undefined,
      productId: currentProductId.value,
      productName: productDetail.value?.name,
      suiteName: formData.productSuite,
      salesForm: mapSalesFormToCN(formData.salesForm),
      customerType: mapCustomerToCN(formData.customerObject),
      accountLimit: formData.accountQuantityUnlimited ? '不限' : String(formData.accountQuantity || ''),
      concurrentNodes: formData.concurrentNodeQuantityUnlimited ? '不限' : String(formData.concurrentNodeQuantity || ''),
      priceType: formData.priceSettings.map(t=>mapPriceTypeToCN(t)).join(','),
      priceUnit: mapUnitToCN(formData.priceUnit || ''),
      pointsPrice: formData.pointsPrice,
      currencyPrice: formData.currencyPrice,
      isActive: formData.enableStatus === 'ENABLED',
      description: formData.remark || '',
    }
  }
  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)
    if (isEditMode.value && formData.id) {
      const payload = buildPayload()
      const res: any = await productPricingApi.update(payload)
      if (res?.code === 200) {
        ElMessage.success('修改成功')
    } else {
      priceList.value.splice(idx, 1, record)
        ElMessage.error(res?.msg || '修改失败')
        return
      }
    } else {
      // const tasks = selectedTypes.map(t => productPricingApi.add(buildPayload(t)))
      // const results: any[] = await Promise.all(tasks)
      // const ok = results.every(r => r && r.code === 200)
      const results: any = await productPricingApi.add(buildPayload())
      if (results?.code !== 200) {
        ElMessage.error('部分定价保存失败')
        return
      }
      ElMessage.success('新建成功')
      // 修改产品状态为已订价
      // 判断 产品定价列表是否为空,为空则更新状态,不为空则说明更新过了,不需要在此更新
      if (priceList.value.length === 0) {
        const updateParams = {
          id: currentProductId.value,
          listingStatus: 'PRICED'
        }
        const res: any = await productApi.updateProductStatus(updateParams)
        if (res?.code !== 200) {
          console.log('产品状态更新失败!!')
        }
      }
    }
    ElMessage.success(isEditMode.value ? '修改成功' : '新建成功')
    dialogVisible.value = false
    await loadPricingList(currentProductId.value)
  } finally {
    saving.value = false
  }
@@ -695,11 +860,10 @@
    '状态变更',
    { 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 }
      }
    .then(async () => {
      const payload = buildPayloadFromRow(row, { isActive: newStatus === 'ENABLED' })
      await productPricingApi.update(payload)
      await loadPricingList(currentProductId.value as string)
      ElMessage.success(newStatus === 'ENABLED' ? '启用成功' : '停用成功')
    })
    .catch(() => {})
@@ -741,6 +905,11 @@
  .content-area {
    .price-card {
      /* 让价格列表可滚动 */
      :deep(.el-card__body) {
        max-height: 600px;
        overflow-y: auto;
      }
      .card-header {
        display: flex;
        justify-content: space-between;
@@ -801,7 +970,7 @@
.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; }
.price-form :deep(.el-form-item) { margin-bottom: 20px; }
/* 上架状态颜色 */
.status-online { color: #67C23A; }
.status-pending { color: #E6A23C; }