From bd125eecd57d2f4e559c6170d20157591300fe3d Mon Sep 17 00:00:00 2001 From: p-honggang.li <p-honggang.li@pcitc.com> Date: 星期四, 04 九月 2025 20:57:44 +0800 Subject: [PATCH] 修改购物车等BUG --- src/views/productManage/price/index.vue | 517 ++++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 343 insertions(+), 174 deletions(-) diff --git a/src/views/productManage/price/index.vue b/src/views/productManage/price/index.vue index 1aad86e..6c6701c 100644 --- a/src/views/productManage/price/index.vue +++ b/src/views/productManage/price/index.vue @@ -17,16 +17,16 @@ </div> </template> - <el-descriptions v-if="productDetail" :column="3" 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 v-if="productDetail" :column="2" border> + <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: '鏁板瓧鍖栦骇鍝丄', - submitUnit: '涓氦涓�鍏眬', - submitter: '寮犱笁', - industry: '浜ら�氬熀纭�璁炬柦', - projectUnit: '鏌愰珮閫熷叕璺伐绋�', - industryStage: '搴旂敤闃舵', - productType: '杞欢/骞冲彴', - description: '鏈骇鍝佸畾浣嶄负浠ュ缓璁炬湡BIM鏁板瓧璧勪骇浣滀负鏁板瓧搴曠洏锛岀粨鍚堥」鐩繍钀ョ淮淇濋渶姹傜殑瀹炴椂鎬с�佷氦浜掓�с�佷究鎹锋�х殑涓夌淮鍙鍖栬繍缁寸鐞嗙郴缁熴�傜郴缁熸彁渚涢」鐩暟瀛楀寲銆佹櫤鑳藉寲杩愮淮绠$悊鍔熻兘锛岃兘澶熻В鍐冲缓绛戣繍琛岀淮鎶ょ鐞嗕腑鐨勫疄闄呴棶棰橈紝瀹炵幇淇℃伅蹇�熸暣鍚堜笌鏌ヨ銆佷俊鎭湁鏁堝叡浜笌浼犻�掞紝鎻愬崌椤圭洰缁煎悎绠$悊涓庣淮鎶ゆ按骞炽��', - shelfStatus: '寰呬笂鏋�' - }, - '10002': { - id: '10002', - name: '鏁板瓧鍖栦骇鍝丅', - submitUnit: '涓氦浜岃埅灞�', - submitter: '鏉庡洓', - industry: '甯傛斂宸ョ▼', - projectUnit: '鏅烘収绠″粖椤圭洰', - industryStage: '鐮斿彂闃舵', - productType: '纭欢/浼犳劅', - description: '闈㈠悜鍩庡競绠″粖鐩戞祴鐨勪紶鎰熻澶囦笌閲囬泦缃戝叧锛屾敮鎸佽竟缂樿绠椾笌杩滅▼杩愮淮銆�', - shelfStatus: '宸蹭笂鏋�' - } -} +// const mockProductMap: Record<string, ProductDetail> = { +// '1': { +// id: '1', +// name: '鏁板瓧鍖栦骇鍝丄', +// submitUnit: '涓氦涓�鍏眬', +// submitter: '寮犱笁', +// industry: '浜ら�氬熀纭�璁炬柦', +// projectUnit: '鏌愰珮閫熷叕璺伐绋�', +// industryStage: '搴旂敤闃舵', +// productType: '杞欢/骞冲彴', +// description: '鏈骇鍝佸畾浣嶄负浠ュ缓璁炬湡BIM鏁板瓧璧勪骇浣滀负鏁板瓧搴曠洏锛岀粨鍚堥」鐩繍钀ョ淮淇濋渶姹傜殑瀹炴椂鎬с�佷氦浜掓�с�佷究鎹锋�х殑涓夌淮鍙鍖栬繍缁寸鐞嗙郴缁熴�傜郴缁熸彁渚涢」鐩暟瀛楀寲銆佹櫤鑳藉寲杩愮淮绠$悊鍔熻兘锛岃兘澶熻В鍐冲缓绛戣繍琛岀淮鎶ょ鐞嗕腑鐨勫疄闄呴棶棰橈紝瀹炵幇淇℃伅蹇�熸暣鍚堜笌鏌ヨ銆佷俊鎭湁鏁堝叡浜笌浼犻�掞紝鎻愬崌椤圭洰缁煎悎绠$悊涓庣淮鎶ゆ按骞炽��', +// shelfStatus: '寰呬笂鏋�' +// }, +// '2': { +// id: '2', +// name: '鏁板瓧鍖栦骇鍝丅', +// 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鐗圤TA鏈嶅姟', value: 'ENTERPRISE_PRIVATE_SAAS_OTA' }, - { label: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘', value: 'ENTERPRISE_PRIVATE_SAAS_USER_INCREMENT' }, - { label: '浼佷笟鍏湁SaaS鐗堣鍙�', value: 'ENTERPRISE_PUBLIC_SAAS_LICENSE' }, - { label: '浼佷笟鍏湁SaaS鐗圤TA鏈嶅姟', 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鐗圤TA鏈嶅姟', value: '浼佷笟绉佹湁SaaS鐗圤TA鏈嶅姟' }, + { label: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘', value: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘' }, + { label: '浼佷笟鍏湁SaaS鐗堣鍙�', value: '浼佷笟鍏湁SaaS鐗堣鍙�' }, + { label: '浼佷笟鍏湁SaaS鐗圤TA鏈嶅姟', value: '浼佷笟鍏湁SaaS鐗圤TA鏈嶅姟' }, + { 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('鏈彁渚涗骇鍝両D锛屾棤娉曞姞杞戒骇鍝佽鎯�') 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) => { + // 鎸塸roductSuite鍒嗙粍 + 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('鏈彁渚涗骇鍝両D锛屾棤娉曚繚瀛樺畾浠�') + 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; } -- Gitblit v1.8.0