From 95cb69b9f79893d7cd1319d754064c93e3fa4e2f Mon Sep 17 00:00:00 2001
From: seatonwan9
Date: 星期二, 19 八月 2025 18:15:56 +0800
Subject: [PATCH] 提交源码

---
 src/views/productManage/productPriceViewer/index.vue |  300 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 256 insertions(+), 44 deletions(-)

diff --git a/src/views/productManage/productPriceViewer/index.vue b/src/views/productManage/productPriceViewer/index.vue
index fb0bd06..a559117 100644
--- a/src/views/productManage/productPriceViewer/index.vue
+++ b/src/views/productManage/productPriceViewer/index.vue
@@ -249,10 +249,25 @@
                     </div>
                   </td>
                   <td class="th-center">
-                    <el-input-number v-model="suite.quantity" :min="1" :max="999" :controls="false" size="small" />
+                    <el-input-number 
+                      v-model="suite.quantity" 
+                      :min="1" 
+                      :max="999" 
+                      :controls="true" 
+                      size="large"
+                      @change="(value) => handleQuantityChange(suite.id, value?value:1)"
+                    />
                   </td>
                   <td class="th-center">
-                    <el-input-number v-model="suite.duration" :min="1" :max="10" :controls="false" size="small" />
+                      <el-input-number 
+                        v-model="suite.duration" 
+                        :min="1" 
+                        :max="100" 
+                        :controls="true" 
+                        size="large"
+                        :disabled="suite.priceType === 'FREE'"
+                        @change="(value) => handleDurationChange(suite.id, value?value:1)"
+                      />
                   </td>
                   <td class="th-center">
                     <el-button type="danger" link @click="removeSuite(idx)">鍒犻櫎</el-button>
@@ -331,7 +346,7 @@
         <el-button type="primary" @click="handleOrder">绔嬪嵆璁㈣喘</el-button>
         </template>
         <template v-else>
-          <el-button @click="showOrderPanel = false">杩斿洖浠锋牸瀵规瘮</el-button>
+          <el-button @click="returnPricePanel">杩斿洖浠锋牸瀵规瘮</el-button>
           <el-button type="primary" @click="submitOrder">鎻愪氦鐢宠</el-button>
         </template>
       </span>
@@ -346,6 +361,8 @@
 import { ElMessage } from 'element-plus'
 import { useRoute } from 'vue-router'
 import productPricingApi from '@/api/productPricingApi'
+import cartApi from '@/api/cartApi'
+import orderApi from '@/api/orderApi'
 import { ShoppingCart, Coin, Money } from '@element-plus/icons-vue'
 
 const route = useRoute()
@@ -406,6 +423,9 @@
 const showOrderPanel = ref(false)
 const showPricePanel = ref(true)
 const showOrderStatus = ref(false)
+// 妯℃嫙鐢ㄦ埛淇℃伅锛堝疄闄呭簲浠庣敤鎴风姸鎬佽幏鍙栵級
+const currentUserId = ref(1)
+const currentUnitId = ref(1)
 type PriceTypeKey = 'POINTS' | 'CURRENCY' | 'AGREEMENT' | 'FREE'
 interface OrderSuite extends PriceItem {
   selected: boolean
@@ -414,6 +434,11 @@
   priceType?: PriceTypeKey
 }
 const orderSuites = ref<OrderSuite[]>([])
+
+// 璐墿杞︾浉鍏崇姸鎬�
+const cartItems = ref<any[]>([])
+const cartLoading = ref(false)
+const idempotencyToken = ref<string>('')
 
 // 璁㈠崟鐘舵�佺浉鍏�
 type OrderStatus = 'SUBMITTED' | 'AUTHORIZED' | 'CONFIRMED' | 'EVALUATED'
@@ -522,7 +547,25 @@
   const map: Record<string, string> = { SET: '/濂�', SET_PER_YEAR: '/濂�/骞�', YEAR: '/骞�' }
   return map[unit || ''] || ''
 }
-const removeSuite = (index: number) => { orderSuites.value.splice(index, 1) }
+const removeSuite = async (index: number) => {
+  const suite = orderSuites.value[index]
+  if (!suite) return
+  try {
+    await removeFromCart(suite.id)
+    orderSuites.value.splice(index, 1)
+  } catch (e) {
+  }
+}
+
+// 璁㈣喘鎴愬姛鍥炶皟
+const handleOrderSuccess = (orderData: any) => {
+  console.log('璁㈣喘鎴愬姛:', orderData)
+  ElMessage.success('璁㈣喘鐢宠鎻愪氦鎴愬姛锛�')
+  // 娓呯┖閫夋嫨鐘舵��
+  selectedSuiteIds.value.clear()
+  // 鍏抽棴浠锋牸鏌ョ湅鍣�
+  visible.value = false
+}
 
 // 寮圭獥鏍囬
 const dialogTitle = computed(() => {
@@ -689,26 +732,28 @@
   const isChecked = Boolean(checked)
   if (isChecked) {
     selectedSuiteIds.value.add(suiteId)
+    // 娣诲姞鍒拌喘鐗╄溅
+    const priceItem = priceList.value.find(item => item.id === suiteId)
+    if (priceItem) {
+      addToCart(priceItem)
+    }
   } else {
     selectedSuiteIds.value.delete(suiteId)
+    // 浠庤喘鐗╄溅绉婚櫎
+    removeFromCart(suiteId)
   }
 }
 
 // 绔嬪嵆璁㈣喘
 const handleOrder = () => {
-  if (selectedSuiteIds.value.size === 0) {
-    ElMessage.warning('璇烽�夋嫨瑕佽璐殑杞欢濂椾欢')
-    return
-  }
-  const selectedItems = priceList.value.filter(item => selectedSuiteIds.value.has(item.id))
-  // 鏋勫缓鍐呭祵璁㈣喘鍒楄〃
-  orderSuites.value = selectedItems.map(it => ({
-    ...it,
-    selected: true,
-    quantity: 1,
-    duration: 1,
-    priceType: getDefaultPriceType(it as any)
-  })) as any
+  // 鏌ヨ璐墿杞︿俊鎭繘琛屽睍绀�
+  fetchCartItems()
+  // 鑾峰彇涓�娆℃�ч槻閲嶅鎻愪氦token
+  orderApi.getIdempotencyToken(currentUserId.value).then((res: any) => {
+    if (res?.code === 200) {
+      idempotencyToken.value = res.data as string
+    }
+  }).catch(() => {})
   showOrderPanel.value = true
   showPricePanel.value = false
 }
@@ -719,6 +764,12 @@
 // 鍚敤/鍋滅敤鎸夐挳
 function handleToggleEnableStatus(row: any) {
   // ... existing code ...
+}
+
+function returnPricePanel() {
+  showOrderPanel.value = false
+  showOrderStatus.value = false
+  showPricePanel.value = true
 }
 
 async function submitOrder() {
@@ -733,34 +784,195 @@
     ElMessage.error('鏆備笉鏀寔璐у竵浜ゆ槗锛岃閫夋嫨绉垎鎴栧崗璁敮浠樻柟寮�')
     return
   }
-  
-  // 杩欓噷鍙鎺ュ疄闄呬笅鍗曟帴鍙o紱鍏堝仛鍓嶇鎻愮ず
-  // emit('order', items as any)
-  
-  // 妯℃嫙璁㈠崟鐘舵�佹暟鎹�
-  orderStatus.value = {
-    id: '4348442557619205545',
-    productName: productHeader.value.name,
-    provider: productHeader.value.provider,
-    status: 'SUBMITTED',
-    submitTime: new Date().toLocaleString(),
-    applyTime: new Date().toLocaleString()
+
+  if (!idempotencyToken.value) {
+    ElMessage.error('涓嬪崟Token鑾峰彇澶辫触锛岃杩斿洖閲嶈瘯')
+    return
   }
-  
-  // 鏄剧ず璁㈠崟鐘舵�侀潰鏉�
-  showOrderPanel.value = false
-  showPricePanel.value = false
-  showOrderStatus.value = true
+
+  // 缁勮鍒涘缓璁㈠崟鍙傛暟锛圕reateOrderDTO锛�
+  const payload = {
+    userId: currentUserId.value,
+    unitId: currentUnitId.value,
+    productName: productHeader.value.name,
+    providerName: productHeader.value.provider,
+    providerId: 3,
+    paymentType: '绉垎',
+    buyerRemarks: '',
+    items: items.map(it => ({
+      pricingId: it.id,
+      productId: Number(it.productId),
+      suiteName: getProductSuiteText(it.productSuite),
+      salesForm: getSalesFormText(it.salesForm),
+      customerType: getCustomerObjectText(it.customerObject),
+      accountLimit: it.accountQuantityUnlimited ? '涓嶉檺' : String(it.accountQuantity),
+      concurrentNodes: it.concurrentNodeQuantityUnlimited ? '涓嶉檺' : String(it.concurrentNodeQuantity),
+      priceType: (it.priceType === 'POINTS' ? '绉垎' : it.priceType === 'CURRENCY' ? '璐у竵' : it.priceType === 'AGREEMENT' ? '鍗忚' : '鍏嶈垂'),
+      priceUnit: getPriceUnitText(it.priceUnit),
+      unitPrice: (it.priceType === 'POINTS' ? it.pointsAmount : it.currencyAmount) || 0,
+      quantity: it.quantity,
+      duration: it.duration,
+      totalPrice: undefined,
+      providerId: 3,
+      providerName: productHeader.value.provider,
+      remarks: ''
+    }))
+  }
+
+  try {
+    const res: any = await orderApi.createOrder(payload, idempotencyToken.value)
+    if (res?.code === 200) {
+      ElMessage.success('璁㈠崟鍒涘缓鎴愬姛')
+      const data = res.data || {}
+      orderStatus.value = {
+        id: data.orderId || '鈥�',
+        productName: data.productName || productHeader.value.name,
+        provider: data.providerName || productHeader.value.provider,
+        status: 'SUBMITTED',
+        submitTime: data.applyTime ? String(data.applyTime) : new Date().toLocaleString(),
+        applyTime: data.applyTime ? String(data.applyTime) : new Date().toLocaleString()
+      }
+      // 娓呯┖璐墿杞︼紙鍚庣 + 鏈湴鐘舵�侊級
+      try {
+        const clearRes: any = await cartApi.clearCart(currentUserId.value, currentUnitId.value)
+        if (clearRes?.code === 200) {
+          cartItems.value = []
+          orderSuites.value = []
+          selectedSuiteIds.value.clear()
+          selectAllChecked.value = false
+        }
+      } catch (e) { /* ignore */ }
+      // 鏄剧ず璁㈠崟鐘舵�侀潰鏉�
+      showOrderPanel.value = false
+      showPricePanel.value = false
+      showOrderStatus.value = true
+    } else {
+      ElMessage.error(res?.msg || '鍒涘缓璁㈠崟澶辫触')
+    }
+  } catch (e) {
+    ElMessage.error('鍒涘缓璁㈠崟澶辫触')
+  }
 }
 
-// 璁㈣喘鎴愬姛鍥炶皟
-const handleOrderSuccess = (orderData: any) => {
-  console.log('璁㈣喘鎴愬姛:', orderData)
-  ElMessage.success('璁㈣喘鐢宠鎻愪氦鎴愬姛锛�')
-  // 娓呯┖閫夋嫨鐘舵��
-  selectedSuiteIds.value.clear()
-  // 鍏抽棴浠锋牸鏌ョ湅鍣�
-  visible.value = false
+// 璐墿杞︾浉鍏虫柟娉�
+const addToCart = async (priceItem: PriceItem) => {
+  try {
+    const cartData = {
+      pricingId: priceItem.id,
+      productId: Number(priceItem.productId),
+      productName: productName.value,
+      suiteName: getProductSuiteText(priceItem.productSuite),
+      salesForm: getSalesFormText(priceItem.salesForm),
+      customerType: getCustomerObjectText(priceItem.customerObject),
+      accountLimit: priceItem.accountQuantityUnlimited ? '涓嶉檺' : String(priceItem.accountQuantity),
+      concurrentNodes: priceItem.concurrentNodeQuantityUnlimited ? '涓嶉檺' : String(priceItem.concurrentNodeQuantity),
+      priceType: priceItem.priceSettings.map(item => getPriceSettingText(item)).join(','),
+      priceUnit: getPriceUnitText(priceItem.priceUnit),
+      unitPrice: priceItem.pointsAmount || priceItem.currencyAmount || 0,
+      quantity: 1,
+      duration: 1
+    }
+    
+    const res: any = await cartApi.addToCart(cartData, currentUserId.value, currentUnitId.value)
+    if (res?.code === 200) {
+      ElMessage.success('宸叉坊鍔犲埌璐墿杞�')
+    } else {
+      ElMessage.error(res?.msg || '娣诲姞鍒拌喘鐗╄溅澶辫触')
+    }
+  } catch (error) {
+    console.error('娣诲姞鍒拌喘鐗╄溅澶辫触:', error)
+    ElMessage.error('娣诲姞鍒拌喘鐗╄溅澶辫触')
+  }
+}
+
+const removeFromCart = async (pricingId: number) => {
+  try {
+    const res: any = await cartApi.removeFromCart(currentUserId.value, currentUnitId.value, pricingId)
+    if (res?.code === 200) {
+      ElMessage.success('宸蹭粠璐墿杞︾Щ闄�')
+    } else {
+      ElMessage.error(res?.msg || '浠庤喘鐗╄溅绉婚櫎澶辫触')
+    }
+  } catch (error) {
+    console.error('浠庤喘鐗╄溅绉婚櫎澶辫触:', error)
+    ElMessage.error('浠庤喘鐗╄溅绉婚櫎澶辫触')
+  }
+}
+
+const updateCartItem = async (pricingId: number, quantity: number, duration: number) => {
+  try {
+    // 杩欓噷闇�瑕佹牴鎹疄闄呮帴鍙h皟鏁达紝鍙兘闇�瑕佷紶閫掓洿澶氬弬鏁�
+    const res: any = await cartApi.updateCartItem(currentUserId.value, currentUnitId.value, pricingId, quantity)
+    if (res?.code === 200) {
+      ElMessage.success('璐墿杞﹀凡鏇存柊')
+    } else {
+      ElMessage.error(res?.msg || '鏇存柊璐墿杞﹀け璐�')
+    }
+  } catch (error) {
+    console.error('鏇存柊璐墿杞﹀け璐�:', error)
+    ElMessage.error('鏇存柊璐墿杞﹀け璐�')
+  }
+}
+
+const fetchCartItems = async () => {
+  cartLoading.value = true
+  try {
+    const res: any = await cartApi.getCartItems(currentUserId.value, currentUnitId.value)
+    if (res?.code === 200) {
+      cartItems.value = res.data || []
+      // 灏嗚喘鐗╄溅鏁版嵁杞崲涓鸿鍗曞浠舵牸寮�
+      orderSuites.value = cartItems.value.map((item: any) => ({
+        id: item.pricingId,
+        productId: String(item.productId),
+        productSuite: item.suiteName,
+        salesForm: mapSalesFormFromCN(item.salesForm),
+        customerObject: mapCustomerFromCN(item.customerType),
+        accountQuantity: item.accountLimit === '涓嶉檺' ? 0 : Number(item.accountLimit),
+        accountQuantityUnlimited: item.accountLimit === '涓嶉檺',
+        concurrentNodeQuantity: item.concurrentNodes === '涓嶉檺' ? 0 : Number(item.concurrentNodes),
+        concurrentNodeQuantityUnlimited: item.concurrentNodes === '涓嶉檺',
+        priceSettings: item.priceType.split(',').map((t: string) => mapPriceTypeFromCN(t)).filter(Boolean),
+        pointsAmount: item.priceType.includes('绉垎') ? item.unitPrice : 0,
+        currencyAmount: item.priceType.includes('璐у竵') ? item.unitPrice : 0,
+        priceUnit: mapUnitFromCN(item.priceUnit),
+        enableStatus: 'ENABLED',
+        selected: true,
+        quantity: item.quantity || 1,
+        duration: item.duration || 1,
+        priceType: getDefaultPriceType({
+          priceSettings: item.priceType.split(',').map((t: string) => mapPriceTypeFromCN(t)).filter(Boolean)
+        } as any)
+      })) as any
+    } else {
+      orderSuites.value = []
+      ElMessage.error(res?.msg || '鑾峰彇璐墿杞︿俊鎭け璐�')
+    }
+  } catch (error) {
+    console.error('鑾峰彇璐墿杞︿俊鎭け璐�:', error)
+    orderSuites.value = []
+    ElMessage.error('鑾峰彇璐墿杞︿俊鎭け璐�')
+  } finally {
+    cartLoading.value = false
+  }
+}
+
+// 澶勭悊鏁伴噺鍙樺寲
+const handleQuantityChange = async (pricingId: number, quantity: number) => {
+  try {
+    await updateCartItem(pricingId, quantity, 1) // 鏆傛椂浼犻�掗粯璁uration涓�1
+  } catch (error) {
+    console.error('鏇存柊鏁伴噺澶辫触:', error)
+  }
+}
+
+// 澶勭悊骞撮檺鍙樺寲
+const handleDurationChange = async (pricingId: number, duration: number) => {
+  try {
+    // 杩欓噷鍙兘闇�瑕佹牴鎹疄闄呮帴鍙h皟鏁达紝浼犻�抎uration鍙傛暟
+    await updateCartItem(pricingId, 1, duration) // 鏆傛椂浼犻�掗粯璁uantity涓�1
+  } catch (error) {
+    console.error('鏇存柊骞撮檺澶辫触:', error)
+  }
 }
 
 // 鑾峰彇閿�鍞舰寮忔枃鏈�
@@ -973,7 +1185,7 @@
               }
               
               &.currency {
-                color: #f56c6c;
+                color: #e7900d;
               }
               
               &.free {
@@ -981,7 +1193,7 @@
               }
             }
             .price-icon.points { color: #e6a23c; }
-            .price-icon.currency { color: #f56c6c; }
+            .price-icon.currency { color: #e7900d; }
           }
           
                      .add-checkbox {

--
Gitblit v1.8.0