瀏覽代碼

refactor(order): 重构订单详情页面

- 新增订单详情状态管理
- 优化订单详情展示逻辑
- 分离协议信息展示和编辑功能
- 改进发票信息展示
- 移除不必要的组件引用

Signed-off-by: tangshizhe <48740614+tangshizhe@users.noreply.github.com>
tangshizhe 2 月之前
父節點
當前提交
ab62e1c75a
共有 19 個文件被更改,包括 1342 次插入874 次删除
  1. 25 0
      src/store/order.js
  2. 3 3
      src/views/create-order/components/newDetailModel.vue
  3. 6 8
      src/views/create-order/components/order-detail-submodule/AuditRecords.vue
  4. 4 8
      src/views/create-order/components/order-detail-submodule/ChangeRecord.vue
  5. 14 152
      src/views/create-order/components/order-detail-submodule/ContractInfo.vue
  6. 231 0
      src/views/create-order/components/order-detail-submodule/ContractInfoElectronModule.vue
  7. 136 0
      src/views/create-order/components/order-detail-submodule/ContractInfoSignModule.vue
  8. 6 9
      src/views/create-order/components/order-detail-submodule/InvoiceInfo.vue
  9. 11 582
      src/views/create-order/components/order-detail-submodule/OrderDetailCard.vue
  10. 97 0
      src/views/create-order/components/order-detail-submodule/OrderDetailCardBase.vue
  11. 626 0
      src/views/create-order/components/order-detail-submodule/OrderDetailCardProduct.vue
  12. 4 8
      src/views/create-order/components/order-detail-submodule/PaymentInfo.vue
  13. 10 29
      src/views/create-order/components/order-detail-submodule/PaymentPlan.vue
  14. 74 0
      src/views/create-order/components/order-detail-submodule/PaymentPlanModule.vue
  15. 8 47
      src/views/create-order/components/order-detail-submodule/PerformanceBelongs.vue
  16. 71 0
      src/views/create-order/components/order-detail-submodule/PerformanceBelongsModule.vue
  17. 4 8
      src/views/create-order/components/order-detail-submodule/RefundInfo.vue
  18. 4 8
      src/views/create-order/components/order-detail-submodule/StampRecord.vue
  19. 8 12
      src/views/create-order/order-detail.vue

+ 25 - 0
src/store/order.js

@@ -6,6 +6,7 @@ import {
   ajaxCreateOrder,
   ajaxEditOrder,
   ajaxGetBigMemberService,
+  ajaxGetOrderDetail
 } from "../api/modules"
 import { findProductInThreeLevel } from '@/views/create-order/hooks'
 import { orderParams, createOrderParams } from '@/views/create-order/components/schema-form/params'
@@ -51,6 +52,8 @@ export default {
     // 页面表单数据
     pageForm: cloneDeep(defaultPageFormValue),
     orderInfo: cloneDeep(defaultOrderInfo),
+    // 订单详情
+    orderDetail: {},
   },
   getters: {
     currentUserInfo(state) {
@@ -161,6 +164,9 @@ export default {
     },
   },
   mutations: {
+    setOrderDetail(state, payload = {}) {
+      state.orderDetail = payload
+    },
     refreshSchema(state) {
       state.schemaKey = Date.now()
     },
@@ -257,6 +263,25 @@ export default {
     },
   },
   actions: {
+    // 获取订单详情
+    async getOrderDetail({ commit }, payload = {}) {
+        const { id } = payload
+        if (!id) return console.error('缺少订单ID')
+        commit('setLoadingState', { key: 'orderDetail', value: true })
+        try {
+          const { error_code: code, error_msg: msg, data } = await ajaxGetOrderDetail({ orderCode: id })
+          if (code === 0 && data) {
+            commit('setOrderDetail', data)
+            return data
+          } else {
+            showNotify({ message: msg })
+          }
+        } catch (error) {
+          console.log(error)
+        } finally {
+           commit('setLoadingState', { key: 'orderDetail', value: false }) 
+        }
+    },
     // 获取产品备选项信息
     async getProductList ({ commit, dispatch, state }, payload) {
       // 此处不能用缓存,需要实时查询subject=1/2的数据

+ 3 - 3
src/views/create-order/components/newDetailModel.vue

@@ -210,7 +210,7 @@
       <Form ref="performance" :model="performanceFrom" :label-width="120">
         <FormItem label="请输入变更后业绩归属情况" class="formTitle" :label-width="230"></FormItem>
         <FormItem label="销售人员">
-          <sale-select ref="saleRef" :saleType="'1'" @salePerson="salePerson" transfer></sale-select>
+          <!-- <sale-select ref="saleRef" :saleType="'1'" @salePerson="salePerson" transfer></sale-select> -->
         </FormItem>
         <FormItem class="table-order1" v-show="saleTableData.length > 0">
           <Table border :columns="saleTable" :data="saleTableData">
@@ -284,7 +284,7 @@ import html2canvas from 'html2canvas'
 import { mapGetters } from 'vuex'
 import dateSigle from '@/components/dateSigle.vue'
 import bUpload from '@/components/uploadFile.vue'
-import saleSelect from '@/views/order/components/salesSelect.vue'
+// import saleSelect from '@/views/order/components/salesSelect.vue'
 import { dateFormatter } from '@/assets/js/date'
 import { copyImage } from '@/utils/copy'
 // import { Loading } from 'element-ui';
@@ -307,7 +307,7 @@ export default {
   components: {
     dateSigle,
     bUpload,
-    saleSelect,
+    // saleSelect,
     vCascader
   },
   methods: {

+ 6 - 8
src/views/create-order/components/order-detail-submodule/AuditRecords.vue

@@ -17,20 +17,13 @@
 <script>
 import InfoCard from '../../ui/InfoCard.vue';
 import AuditRecordsColumns from './AuditRecordsColumns.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'AuditRecords',
   components: {
     InfoCard,
     AuditRecordsColumns
   },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {}
-      }
-    }
-  },
   data() {
     return {
       tableData: [
@@ -44,6 +37,11 @@ export default {
       ]
     }
   },
+  computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    })
+  },
   mounted() {
     this.tableData = this.orderDetail?.audit || []
   }

+ 4 - 8
src/views/create-order/components/order-detail-submodule/ChangeRecord.vue

@@ -14,20 +14,13 @@
 <script>
 import InfoCard from '../../ui/InfoCard.vue';
 import TableCard from '../../ui/TableCard.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'ChangeRecord',
   components: {
     InfoCard,
     TableCard
   },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {}
-      }
-    }
-  },
   data() {
     return {
       columns: [
@@ -95,6 +88,9 @@ export default {
     }
   },
   computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    }),
     changeRecordList () {
       return this.orderDetail?.redPunchData?.moneyCorrectionData || [];
     }

+ 14 - 152
src/views/create-order/components/order-detail-submodule/ContractInfo.vue

@@ -1,27 +1,13 @@
 <template>
   <div class="contract-info">
     <InfoCard title="协议签订信息">
-      <div class="contract-info-card">
-        <div class="contract-info-card-item">
-          协议签订状态:{{contractRes?.contract_status === 1 ? '签协议' : '不签协议'}}
-        </div>
-        <div class="contract-info-card-item">
-          签约主体:{{ setSigningSubject || '-' }}
-          <span class="red-chong" v-if="setRedPunchDisplay('签约主体')">(红冲过)</span>
-        </div>
-        <div class="contract-info-card-item" v-if="contractResStatus">
-          协议签订时间:{{ formatDate(contractRes?.contract_time) }}
-        </div>
-        <div class="contract-info-card-item" v-if="contractResStatus">
-          协议编号:{{ contractRes?.contract_code || '-'  }}
-        </div>
-      </div>
+      <ContractInfoSignModule></ContractInfoSignModule>
     </InfoCard>
     <InfoCard v-if="contractResStatus">
       <template #title>
         <div class="contract-info-card-title">
           <span>协议归档信息</span>
-          <button @click="editContractArchive('1')" v-if="contractRes?.contract_archive_status === 1" class="edit-btn">编辑</button>
+          <button @click="editContractArchive" v-if="contractRes?.contract_archive_status === 1" class="edit-btn">编辑</button>
         </div>
       </template>
       <div class="contract-info-card">
@@ -39,91 +25,29 @@
         </div>
       </div>
     </InfoCard>
-    <InfoCard v-if="showContract">
-      <template #title>
-        <div class="contract-info-card-title">
-          <span>电子协议信息</span>
-          <button @click="editContractArchive('2')" class="edit-btn">编辑</button>
-        </div>
-      </template>
-      <div class="contract-info-card card-noflex">
-        <div class="contract-info-card-item">
-          电子协议备注:{{ contractRes?.remark || '-'  }}
-        </div>
-        <div class="arow">
-          <div class="contract-info-card-item">
-            电子协议类型:{{ contractRes?.seal_type === 1 ? '有电子章' : '无电子章'}}
-          </div>
-          <div class="contract-info-card-item">
-            协议甲方类型:{{ contractRes?.partyA_type === 2 ? '企业' : '个人' }}
-          </div>
-        </div>
-        <div class="contract-info-card-item">
-          协议甲方:{{ contractRes?.partyA_name || '-' }}
-        </div>
-        <div class="arow">
-          <div class="contract-info-card-item">
-            协议甲方联系人:{{ contractRes?.partyA_person || '-'}}
-          </div>
-          <div class="contract-info-card-item">
-            协议乙方联系人:{{ contractRes?.partyB_person || '-'}}
-          </div>
-        </div>
-        <div class="contract-info-card-item">
-          协议甲方地址:{{ contractRes?.partyA_address || '-' }}
-        </div>
-      </div>
-    </InfoCard>
-    <Dialog
-      ref="editContractArchiveDialog"
-      class="edit-contract-archive-dialog"
-      :visible="editContractArchiveDialogVisible"
-      title="编辑电子协议信息"
-      width="70%"
-      @cancel="editContractArchiveDialogVisible = false"
-      @confirm="editContractArchiveConfirm"
-    >
-      <EditContractInfo
-        ref="editContractArchiveModule"
-        :orderDetail="orderDetail"
-        :isAdmin="isAdmin"
-        :contractFeedbackInfo="contractFeedbackInfo"
-      ></EditContractInfo>
-    </Dialog>
+    <ContractInfoElectronModule @refresh="doRefresh"></ContractInfoElectronModule>
     <new-d-model :data="orderDetail"  ref="detailModelContract" @refresh="doRefresh"></new-d-model>
   </div>
 </template>
 
 <script>
 import InfoCard from '../../ui/InfoCard.vue';
-import { signUnitOptions } from '@/views/create-order/data/index.js'
-import EditContractInfo from './EditContractInfo.vue';
-import Dialog from '@/components/Dialog.vue';
-import { sortOrderInfo } from '@/views/create-order/components/schema-form/resort/'
-import { dateFormatter } from '@/assets/js/date'
-import { calcShowOnlineContractForm } from "@/views/create-order/hooks/utils"
-import { ajaxEditOrderContract } from '@/api/modules/'
 import NewDModel from "@/views/order/components/new-detailModel.vue";
+import ContractInfoSignModule from './ContractInfoSignModule.vue';
+import ContractInfoElectronModule from './ContractInfoElectronModule.vue';
+import { mapState } from 'vuex'
 export default {
   name: 'ContractInfo',
   components: {
     NewDModel,
     InfoCard,
-    EditContractInfo,
-    Dialog,
-  },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {}
-      }
-    }
+    ContractInfoSignModule,
+    ContractInfoElectronModule
   },
   computed: {
-    setSigningSubject() {
-      return signUnitOptions.find(item => item.value === this.orderDetail?.orderData?.signing_subject)?.label || '-';
-    },
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    }),
     contractResStatus() {
       return this.contractRes?.contract_status === 1
     },
@@ -131,44 +55,25 @@ export default {
       const list = this.orderDetail?.userIdentity || [];
       return list.includes(1) || list.includes(2);
     },
-    isUpEntRed() {
-      return this.orderDetail?.redPunchData?.isUpEnt || false;
-    },
     contractRes () {
       return this.orderDetail?.contractRes || {}
     }
   },
   data() {
     return {
-      editContractArchiveDialogVisible: false,
-      protocolArchivingDialogVisible: false,
-      contractFeedbackInfo: {},
-      showContract: false,
     }
   },
   mounted() {
-    this.contractFeedbackInfo = sortOrderInfo(this.orderDetail)
-    const res = this.getOnlineContractFormShow(this.contractFeedbackInfo.pageFormValue, this.contractFeedbackInfo.productArr)
-    this.showContract = res || false
   },
   methods: {
     doRefresh (type = '') {
       this.$emit('refresh', type)
     },
-    // 是否显示电子协议订单
-    getOnlineContractFormShow(pageForm, pList) {
-      return calcShowOnlineContractForm(pageForm, pList)
-    },
-    editContractArchive(type) {
+    editContractArchive() {
       // userIdentity 1超级管理员 2销管
       if(this.isAdmin) {
-        if(type === '1') {
-          // 协议归档信息
+        // 协议归档信息
           this.$refs.detailModelContract.pShow = true;
-        } else if(type === '2') {
-          // 电子归档信息
-          this.editContractArchiveDialogVisible = true;
-        }
       } else {
         this.$message.error('暂无权限')
       }
@@ -178,38 +83,6 @@ export default {
       // 只取空格前的日期部分
       return timeString.split(' ')[0];
     },
-    async editContractArchiveConfirm() {
-      const {
-        signTime,
-        e_contract_type,
-        e_contract_userA_type,
-        e_contract_userA_name,
-        e_contract_userA_contacts_name,
-        e_contract_userA_contacts_tel,
-        e_contract_userA_contacts_address,
-        e_contract_userB_contacts_name,
-        e_contract_remark,
-      } = this.$refs.editContractArchiveModule.pageForm
-      const params = {
-        contractTime: dateFormatter(signTime, 'yyyy-MM-dd'),
-        e_contract_type: e_contract_type,
-        e_contract_userA_type: e_contract_userA_type,
-        e_contract_userA_name: e_contract_userA_name,
-        e_contract_userA_contacts_name: e_contract_userA_contacts_name,
-        e_contract_userA_contacts_tel: e_contract_userA_contacts_tel,
-        e_contract_userA_contacts_address: e_contract_userA_contacts_address,
-        e_contract_userB_contacts_name: e_contract_userB_contacts_name,
-        e_contract_remark: e_contract_remark,
-      }
-      const { error_code: code, error_msg: msg } = await ajaxEditOrderContract(params)
-      if(code === 0) {
-        this.$message.success('电子协议信息编辑成功')
-        this.$emit('refresh', '协议信息')
-        this.editContractArchiveDialogVisible = false;
-      } else {
-        this.$message.error(msg || '电子协议信息编辑失败')
-      }
-    },
     // 查看归档协议
     viewfileEvent() {
       const url = this.contractRes?.contract_file_url;
@@ -224,18 +97,7 @@ export default {
           a1.click()
         })
       }
-    },
-    // 设置红冲标识显示字段
-    setRedPunchDisplay(product) {
-      const { isUpCommission, isUpEnt, isUpCash } = this.orderDetail?.redPunchData || {};
-      const RETURN_BOOL = {
-        '合同金额': isUpCash,
-        '渠道佣金': isUpCommission,
-        '签约主体': isUpEnt,
-        '折扣率': isUpCash
-      }
-      return RETURN_BOOL[product] || false;
-    },
+    }
   }
 }
 

+ 231 - 0
src/views/create-order/components/order-detail-submodule/ContractInfoElectronModule.vue

@@ -0,0 +1,231 @@
+<template>
+  <div class="contract-info">
+    <InfoCard v-if="showContract">
+      <template #title>
+        <div class="contract-info-card-title">
+          <span>电子协议信息</span>
+          <button @click="editContractArchive" class="edit-btn">编辑</button>
+        </div>
+      </template>
+      <div class="contract-info-card card-noflex">
+        <div class="contract-info-card-item">
+          电子协议备注:{{ contractRes?.remark || '-'  }}
+        </div>
+        <div class="arow">
+          <div class="contract-info-card-item">
+            电子协议类型:{{ contractRes?.seal_type === 1 ? '有电子章' : '无电子章'}}
+          </div>
+          <div class="contract-info-card-item">
+            协议甲方类型:{{ contractRes?.partyA_type === 2 ? '企业' : '个人' }}
+          </div>
+        </div>
+        <div class="contract-info-card-item">
+          协议甲方:{{ contractRes?.partyA_name || '-' }}
+        </div>
+        <div class="arow">
+          <div class="contract-info-card-item">
+            协议甲方联系人:{{ contractRes?.partyA_person || '-'}}
+          </div>
+          <div class="contract-info-card-item">
+            协议乙方联系人:{{ contractRes?.partyB_person || '-'}}
+          </div>
+        </div>
+        <div class="contract-info-card-item">
+          协议甲方地址:{{ contractRes?.partyA_address || '-' }}
+        </div>
+      </div>
+    </InfoCard>
+    <Dialog
+      ref="editContractArchiveDialog"
+      class="edit-contract-archive-dialog"
+      :visible="editContractArchiveDialogVisible"
+      title="编辑电子协议信息"
+      width="70%"
+      @cancel="editContractArchiveDialogVisible = false"
+      @confirm="editContractArchiveConfirm"
+    >
+      <EditContractInfo
+        ref="editContractArchiveModule"
+        :orderDetail="orderDetail"
+        :isAdmin="isAdmin"
+        :contractFeedbackInfo="contractFeedbackInfo"
+      ></EditContractInfo>
+    </Dialog>
+    <new-d-model :data="orderDetail"  ref="detailModelContract" @refresh="doRefresh"></new-d-model>
+  </div>
+</template>
+
+<script>
+import InfoCard from '../../ui/InfoCard.vue';
+import { signUnitOptions } from '@/views/create-order/data/index.js'
+import EditContractInfo from './EditContractInfo.vue';
+import Dialog from '@/components/Dialog.vue';
+import { sortOrderInfo } from '@/views/create-order/components/schema-form/resort/'
+import { dateFormatter } from '@/assets/js/date'
+import { calcShowOnlineContractForm } from "@/views/create-order/hooks/utils"
+import { ajaxEditOrderContract } from '@/api/modules/'
+import NewDModel from "@/views/order/components/new-detailModel.vue";
+import { mapState } from 'vuex'
+export default {
+  name: 'ContractInfo',
+  components: {
+    NewDModel,
+    InfoCard,
+    EditContractInfo,
+    Dialog
+  },
+  computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    }),
+    setSigningSubject() {
+      return signUnitOptions.find(item => item.value === this.orderDetail?.orderData?.signing_subject)?.label || '-';
+    },
+    isAdmin() {
+      const list = this.orderDetail?.userIdentity || [];
+      return list.includes(1) || list.includes(2);
+    },
+    isUpEntRed() {
+      return this.orderDetail?.redPunchData?.isUpEnt || false;
+    },
+    contractRes () {
+      return this.orderDetail?.contractRes || {}
+    }
+  },
+  data() {
+    return {
+      editContractArchiveDialogVisible: false,
+      contractFeedbackInfo: {},
+      showContract: false,
+    }
+  },
+  mounted() {
+    this.contractFeedbackInfo = sortOrderInfo(this.orderDetail)
+    const res = this.getOnlineContractFormShow(this.contractFeedbackInfo.pageFormValue, this.contractFeedbackInfo.productArr)
+    this.showContract = res || false
+  },
+  methods: {
+    doRefresh (type = '') {
+      this.$emit('refresh', type)
+    },
+    // 是否显示电子协议订单
+    getOnlineContractFormShow(pageForm, pList) {
+      return calcShowOnlineContractForm(pageForm, pList)
+    },
+    editContractArchive() {
+      // userIdentity 1超级管理员 2销管
+      if(this.isAdmin) {
+        // 电子归档信息
+        this.editContractArchiveDialogVisible = true;
+      } else {
+        this.$message.error('暂无权限')
+      }
+    },
+    async editContractArchiveConfirm() {
+      const {
+        signTime,
+        e_contract_type,
+        e_contract_userA_type,
+        e_contract_userA_name,
+        e_contract_userA_contacts_name,
+        e_contract_userA_contacts_tel,
+        e_contract_userA_contacts_address,
+        e_contract_userB_contacts_name,
+        e_contract_remark,
+      } = this.$refs.editContractArchiveModule.pageForm
+      const params = {
+        contractTime: dateFormatter(signTime, 'yyyy-MM-dd'),
+        e_contract_type: e_contract_type,
+        e_contract_userA_type: e_contract_userA_type,
+        e_contract_userA_name: e_contract_userA_name,
+        e_contract_userA_contacts_name: e_contract_userA_contacts_name,
+        e_contract_userA_contacts_tel: e_contract_userA_contacts_tel,
+        e_contract_userA_contacts_address: e_contract_userA_contacts_address,
+        e_contract_userB_contacts_name: e_contract_userB_contacts_name,
+        e_contract_remark: e_contract_remark,
+      }
+      const { error_code: code, error_msg: msg } = await ajaxEditOrderContract(params)
+      if(code === 0) {
+        this.$message.success('电子协议信息编辑成功')
+        this.$emit('refresh', '协议信息')
+        this.editContractArchiveDialogVisible = false;
+      } else {
+        this.$message.error(msg || '电子协议信息编辑失败')
+      }
+    }
+  }
+}
+
+</script>
+
+<style lang="scss" scoped>
+.contract-info {
+  background: #f5f7f9;
+  ::v-deep {
+    .info-card {
+      margin-bottom: 16px;
+    }
+  }
+}
+.contract-info-card-title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  .edit-btn {
+    padding: 4px 31px;
+    background: $color_main;
+    color: $white;
+    border-radius: 4px;
+    font-size: 14px;
+    line-height: 22px;
+    border: none;
+    cursor: pointer;
+  }
+}
+.contract-info-card {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  &.card-noflex {
+    display: block;
+  }
+  &-item {
+    display: flex;
+    align-items: center;
+    margin-right: 32px;
+    min-width: 255px;
+    font-size: 14px;
+    line-height: 22px;
+    color: $gray_10;
+    .red-chong {
+      color: $red_light;
+    }
+  }
+  .arow {
+    display: flex;
+    align-items: center;
+    margin: 10px 0;
+  }
+}
+.edit-contract-archive-dialog {
+    width: 100%;
+    ::v-deep {
+      .el-dialog {
+        width: 100%;
+        .dialog-footer {
+          justify-content: center;
+        }
+        .action-button {
+          flex: none;
+          width: 132px;
+        }
+      }
+    }
+
+  }
+.column-cell {
+  color: $color_main;
+  cursor: pointer;
+  text-decoration: underline;
+}
+</style>

+ 136 - 0
src/views/create-order/components/order-detail-submodule/ContractInfoSignModule.vue

@@ -0,0 +1,136 @@
+<template>
+  <div class="contract-info-sign-module">
+    <div class="contract-info-card">
+      <div class="contract-info-card-item">
+        协议签订状态:{{contractRes?.contract_status === 1 ? '签协议' : '不签协议'}}
+      </div>
+      <div class="contract-info-card-item">
+        签约主体:{{ setSigningSubject || '-' }}
+        <span class="red-chong" v-if="setRedPunchDisplay('签约主体')">(红冲过)</span>
+      </div>
+      <div class="contract-info-card-item" v-if="contractResStatus">
+        协议签订时间:{{ formatDate(contractRes?.contract_time) }}
+      </div>
+      <div class="contract-info-card-item" v-if="contractResStatus">
+        协议编号:{{ contractRes?.contract_code || '-'  }}
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { signUnitOptions } from '@/views/create-order/data/index.js'
+import { mapState } from 'vuex'
+export default {
+  name: 'ContractInfoSignModule',
+  computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    }),
+    setSigningSubject() {
+      return signUnitOptions.find(item => item.value === this.orderDetail?.orderData?.signing_subject)?.label || '-';
+    },
+    contractResStatus() {
+      return this.contractRes?.contract_status === 1
+    },
+    contractRes () {
+      return this.orderDetail?.contractRes || {}
+    }
+  },
+  data() {
+    return {
+    }
+  },
+  methods: {
+    formatDate(timeString) {
+      if (!timeString) return '-';
+      // 只取空格前的日期部分
+      return timeString.split(' ')[0];
+    },
+    // 设置红冲标识显示字段
+    setRedPunchDisplay(product) {
+      const { isUpCommission, isUpEnt, isUpCash } = this.orderDetail?.redPunchData || {};
+      const RETURN_BOOL = {
+        '合同金额': isUpCash,
+        '渠道佣金': isUpCommission,
+        '签约主体': isUpEnt,
+        '折扣率': isUpCash
+      }
+      return RETURN_BOOL[product] || false;
+    },
+  }
+}
+
+</script>
+
+<style lang="scss" scoped>
+.contract-info {
+  background: #f5f7f9;
+  ::v-deep {
+    .info-card {
+      margin-bottom: 16px;
+    }
+  }
+}
+.contract-info-card-title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  .edit-btn {
+    padding: 4px 31px;
+    background: $color_main;
+    color: $white;
+    border-radius: 4px;
+    font-size: 14px;
+    line-height: 22px;
+    border: none;
+    cursor: pointer;
+  }
+}
+.contract-info-card {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  &.card-noflex {
+    display: block;
+  }
+  &-item {
+    display: flex;
+    align-items: center;
+    margin-right: 32px;
+    min-width: 255px;
+    font-size: 14px;
+    line-height: 22px;
+    color: $gray_10;
+    .red-chong {
+      color: $red_light;
+    }
+  }
+  .arow {
+    display: flex;
+    align-items: center;
+    margin: 10px 0;
+  }
+}
+.edit-contract-archive-dialog {
+    width: 100%;
+    ::v-deep {
+      .el-dialog {
+        width: 100%;
+        .dialog-footer {
+          justify-content: center;
+        }
+        .action-button {
+          flex: none;
+          width: 132px;
+        }
+      }
+    }
+
+  }
+.column-cell {
+  color: $color_main;
+  cursor: pointer;
+  text-decoration: underline;
+}
+</style>

+ 6 - 9
src/views/create-order/components/order-detail-submodule/InvoiceInfo.vue

@@ -4,7 +4,6 @@
       <div class="invoice-info-content">
         <div class="invoice-info-item">
           开票状态:{{ getInvoiceStatus(orderDetail?.orderData?.invoiced_status) }}
-
         </div>
         <div class="invoice-info-item">
           已开票金额:¥{{ formatNumber(invoiceData?.invoiceMoney || 0) }}
@@ -59,6 +58,7 @@
 import InfoCard from '../../ui/InfoCard.vue';
 import TableCard from '../../ui/TableCard.vue';
 import newSetOrderInfo from '../newSetOrderInfo.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'InvoiceInfo',
   components: {
@@ -66,14 +66,6 @@ export default {
     TableCard,
     newSetOrderInfo
   },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {}
-      }
-    }
-  },
   data() {
     return {
       invoiceColumns: [
@@ -105,6 +97,11 @@ export default {
       orderData: {}
     }
   },
+  computed: {
+     ...mapState({
+      orderDetail: state => state.order.orderDetail
+    })
+  },
   mounted() {
     this.invoiceData = this.orderDetail?.invoiceData || {}
     this.invoiceList = this.invoiceData?.invoiceInfo || []

+ 11 - 582
src/views/create-order/components/order-detail-submodule/OrderDetailCard.vue

@@ -1,128 +1,9 @@
 <template>
   <div class="order-detail-card-container">
     <InfoCard title="基本信息">
-      <div class="order-detail-card-content">
-        <div class="order-detail-card-item" v-for="(item, index) in basicInfoItems" :key="index">
-          {{ item.label }}:{{ getFilteredValue(orderData[item.key], item.filter) || '-' }}
-        </div>
-      </div>
-    </InfoCard>
-    <InfoCard title="产品信息">
-      <div class="order-detail-card-content">
-        <div class="order-detail-card-item" v-for="(item, index) in productInfoTotalItems" :key="index">
-          <div v-if="item.key === 'pure_amount'">
-            {{ item.label }}:¥{{ formatNumber(orderData[item.key]) || '-' }}
-            <span class="red-chong" v-if="setRedPunchDisplay('合同金额')">(红冲过)</span>
-          </div>
-          <div v-else-if="item.key === 'final_price_total'">
-            {{ item.label }}:¥{{ orderData[item.key] || '-' }}
-            <span class="red-chong" v-if="setRedPunchDisplay('合同金额')">(红冲过)</span>
-          </div>
-          <div v-else-if="item.key === 'commission'">
-            {{ item.label }}:¥{{ formatNumber(orderData[item.key]) || '0.00' }}
-            <span class="red-chong" v-if="setRedPunchDisplay('销售费用')">(红冲过)</span>
-          </div>
-          <div v-else-if="item.key === 'rate_total'">
-            {{ item.label }}:<span :class="{'red-chong': orderData[item.key] === '无法计算'}">{{ orderData[item.key] || '-' }}</span>
-            <span class="red-chong" v-if="setRedPunchDisplay('折扣率')">(红冲过)</span>
-          </div>
-          <div v-else-if="item.key === 'zero_type'">
-            <span v-if="shouldRenderItem(item)">
-              {{ item.label }}:{{ getFilteredValue(orderData[item.key], item.filter) || '-' }}
-            </span>
-          </div>
-          <div v-else>{{ item.label }}:{{ getFilteredValue(orderData[item.key], item.filter ) || '-' }}</div>
-        </div>
-      </div>
-      <div class="order-detail-product-list">
-        <ProductCard
-          v-for="(product, index) in productData"
-          :key="product.id"
-          :title="setProductTitle(product, index)"
-          :subtitle="product.auto !== 1 ? '该产品暂不支持系统自动开通权限,请联系运维开通': ''"
-          >
-          <template #actions>
-            <button @click="openPermissionActivation(product)" class="order-detail-product-actions-btn" v-if="isShowPermission(product)">权限开通</button>
-          </template>
-          <div class="order-detail-product-content">
-            <div class="grouped-items">
-              <div
-                v-for="(item, index) in productInfoItems"
-                :key="index"
-                :class="`item-span-${item.span}`"
-                >
-                <div
-                  class="order-detail-card-item"
-                  v-if="shouldRenderItem(item, product)"
-                  >
-                  <div v-if="item.key === 'linkedOrder'" class="linkedOrder">
-                    {{ item.label }}:
-                    <TableCard :span-method="objectSpanMethod" v-if="product[item.key].length" :table-data="product[item.key]" :columns="linkOrderColumns">
-                    </TableCard>
-                    <span v-else>-</span>
-                  </div>
-                  <div v-else-if="item.key === 'subAccountCount'">
-                    <span v-html="getValidityPeriodHtml(product, item)"></span>
-                  </div>
-                  <div v-else-if="item.key === 'mainAccountCount'">
-                    <span v-html="getValidityPeriodHtml(product, item)"></span>
-                  </div>
-                  <div v-else-if="item.key ==='rate'">
-                    {{ item.label }}:
-                    <span :class="{'no_open_root': product.original_price === '0.00'}">{{ getFilteredValue(product[item.key], item.filter) || '-' }}</span>
-                    <span class="red-chong" v-if="setRedPunchDisplay('折扣率')">(红冲过)</span>
-                  </div>
-                  <div v-else-if="item.key === 'final_price' || item.key === 'original_price'">
-                    {{ item.label }}:¥{{ getFilteredValue(product[item.key], item.filter) || '-' }}
-                    <span class="red-chong" v-if="setRedPunchDisplay('合同金额') && item.key === 'final_price'">(红冲过)</span>
-                  </div>
-                  <div v-else-if="item.key === 'validity_period'">
-                    <span v-html="getValidityPeriodHtml(product, item)"></span>
-                  </div>
-                  <div v-else-if="item.key === 'supServicelds'">
-                    {{ item.label }}:{{ getFilteredValue(product[item.key], item.filter) || '-' }}
-                  </div>
-                  <div v-else-if="item.key === 'service_starttime'">
-                    {{ item.label }}:
-                    <span :class="{'no_open_root':!product.is_service_open}" >{{ product.is_service_open? (product.service_starttime || '-') : '暂未开通' }}</span>
-                  </div>
-                  <div v-else-if="item.key === 'service_endtime'">
-                    {{ item.label }}:
-                    <span :class="{'no_open_root': !product.is_service_open}" >{{ product.is_service_open ? (product.service_endtime || '-') : '暂未开通' }}</span>
-                  </div>
-                  <div v-else-if="item.key ==='phone'">
-                    {{ item.label }}:{{ orderData.user_phone || '-' }}
-                  </div>
-                  <div v-else>{{ item.label }}:{{ getFilteredValue(product[item.key], item.filter) || '-' }}</div>
-                </div>
-              </div>
-            </div>
-          </div>
-          <template #activity>
-            <div v-if="product.activity_code" class="order-detail-product-activity">
-              <div class="order-detail-product-activity-title">
-                <span>活动商品:</span>
-                <span>{{ product.activity_code || '买2年大会员送:1年大会员+人脉管理+阳光直采+1000条数据流量包高级字段包+腾讯视频年卡' }}</span>
-              </div>
-              <div class="order-detail-product-activity-item">
-                <div class="order-detail-product-activity-item-title">
-                  <span>合同金额合计:</span>
-                  <span>¥{{ product.final_price }}</span>
-                </div>
-                <div class="order-detail-product-activity-item-title">
-                  <span>标准售价合计:</span>
-                  <span>¥{{ product.original_price }}</span>
-                </div>
-                <div class="order-detail-product-activity-item-title">
-                  <span>折扣率:</span>
-                  <span>{{ product.rate }}</span>
-                </div>
-              </div>
-            </div>
-          </template>
-        </ProductCard>
-      </div>
+      <OrderDetailCardBase></OrderDetailCardBase>
     </InfoCard>
+    <OrderDetailCardProduct></OrderDetailCardProduct>
     <InfoCard title="其他信息">
       <div class="order-detail-card-content">
         <div class="order-detail-card-item" v-for="(item, index) in otherInfoItems" :key="index">
@@ -130,116 +11,32 @@
         </div>
       </div>
     </InfoCard>
-    <newDetailModel ref="newDetailModel" :data="orderDetail"></newDetailModel>
-    <ServiceList v-show="false" ref="serviceListRef"></ServiceList>
   </div>
 </template>
 
 <script>
 import InfoCard from '../../ui/InfoCard.vue';
-import ProductCard from '../../ui/ProductCard.vue';
-import { paymentTypeOptions } from '../../data/options.js';
-import { div, calcDiscountRate, roundToTwoDecimals } from '@/utils/number/';
-import TableCard from '../../ui/TableCard.vue';
-import newDetailModel from '@/views/order/components/new-detailModel.vue';
-import ServiceList from '../product-info-submodule/ServiceList.vue';
+import { roundToTwoDecimals } from '@/utils/number/';
+import OrderDetailCardBase from './OrderDetailCardBase.vue';
+import OrderDetailCardProduct from './OrderDetailCardProduct.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'OrderDetailCard',
   components: {
     InfoCard,
-    ProductCard,
-    TableCard,
-    newDetailModel,
-    ServiceList
-  },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {} 
-    }
+    OrderDetailCardBase,
+    OrderDetailCardProduct
   },
   data() {
     return {
       orderDetailInfo: {},
-      basicInfoItems: [
-        { label: '创建人', key: 'create_person' },
-        { label: '创建时间', key: 'create_time' },
-        { label: '最近更新人', key: 'last_update_person' },
-        { label: '最近更新时间', key: 'autoUpdate' },
-        { label: '订单审核状态', key: 'audit_status', filter: 'orderCoursed' },
-        { label: '订单状态', key: 'order_status', filter: 'orderStatus' }
-      ],
       otherInfoItems: [
         { label: '约定支付方式', key: 'pay_way' },
         { label: '下单渠道', key: 'order_channel_new' },
         { label: '付款户名', key: 'payment_user'},
         { label: '订单备注', key: 'remark' },
       ],
-      productInfoTotalItems: [
-        { label: '合同金额合计', key: 'final_price_total' },
-        { label: '标准售价合计', key: 'original_price_total'},
-        { label: '折扣率', key: 'rate_total' },
-        { label: '销售费用', key: 'commission'},
-        { label: '净合同金额合计', key: 'pure_amount'},
-        { label: '0元订单类型', key: 'zero_type', condition: () => this.orderData.final_price_total === '0.00' },
-      ],
-      productInfoItems: [
-        { label: '活动产品', key: 'activity_code', span: 1, condition: (product) => product.activity_code },
-        { label: '付费类型', key: 'service_type', filter: 'orderServiceType', span: 3},
-        { label: '升级内容', key: 'supServicelds', span: 3, condition: (product) => product.supServicelds },
-        { label: '产品规格', key: 'productName', span: 3},
-        { label: '服务列表', key: 'bigServiceNames', span: 1, condition: (product) => product.productName && product.productName.includes('自定义') &&  product.product_code === 'dyh001'},
-        { label: '有效周期', key: 'validity_period', span: 1},
-        { label: '合同金额', key: 'final_price', span: 3},
-        { label: '标准售价', key: 'original_price', span: 3},
-        { label: '折扣率', key: 'rate', span: 3},
-        { label: '子账号数量', key: 'subAccountCount', span: 1, condition: () => this.parsedFilter.buyAccountCount && this.parsedFilter.giftAccountCount },
-        { label: '主账号数量', key: 'mainAccountCount', span: 1, condition: (product) => product.product_type === 'VIP订阅' },
-        { label: '关联订单', key: 'linkedOrder', span: 1},
-        { label: '开通权益手机号', key: 'phone', span: 3},
-        { label: '服务开始时间', key: 'service_starttime', span: 3},
-        { label: '服务结束时间', key: 'service_endtime', span: 3}
-      ],
       orderData: {},
-      productData: [],
-      linkOrderColumns: [
-        {
-          prop: 'name',
-          label: '产品类型及规格',
-          width: 154
-        },
-        {
-          prop: 'empowerCount',
-          label: '账号数量',
-          width: 80 
-        },
-        {
-          prop: 'serviceEndTime',
-          label: '到期时间',
-          width: 102
-        },
-        {
-          prop: 'buySubject',
-          label: '购买主体',
-          width: 80
-        },
-        { 
-          prop:'order_code',
-          label: '订单编号',
-          width: 154
-        },
-        { 
-          prop:'service_type',
-          label: '付费类型',
-          width: 80
-        },
-        { 
-          prop:'create_time',
-          label: '创建时间', 
-          width: 102
-        } 
-      ],
-      parsedFilter: {}
     }
   },
   watch: {
@@ -252,259 +49,14 @@ export default {
       immediate: true
     }
   },
-  // async mounted() {
-  //   this.orderDetailInfo =  await this.orderDetail || {}
-  //   this.init()
-  // },
   computed: {
-    isUpEntRed() {
-      return this.orderDetailInfo?.redPunchData?.isUpEnt || false
-    }
+    ...mapState({
+      orderDetail: state => state.order.orderDetail,
+    })
   },
   methods: {
     async init() {
       this.orderData = this.orderDetailInfo?.orderData || {};
-      let productData = this.orderDetailInfo?.productData || [];
-
-      if (productData.length > 0) {
-        // 使用 Promise.all 来并行处理每个 product 的异步操作
-        productData = await Promise.all(
-          productData.map(async (product) => {
-            try {
-              const parsedFilter = this.parseProductFilter(product);
-              const serviceIds = parsedFilter.serviceIds || [];
-
-              // 等待异步方法完成
-              const bigServiceNames = await this.buildBigServiceNames(serviceIds);
-              const rate = this.calculateDiscountRate(product);
-              const validityPeriod = this.calculateValidityPeriod(
-                parsedFilter.buy_cycle,
-                parsedFilter.buy_type,
-                parsedFilter.give_cycle,
-                parsedFilter.give_type,
-                product
-              );
-              const subAccountCount = this.buildSubAccountCount(product, parsedFilter);
-              const mainAccountCount = this.buildMainAccountCount(product);
-              const linkedOrder = this.processLinkedOrder(product);
-              const finalPrice = this.formatNumber(product.final_price);
-              const originalPrice = this.formatNumber(product.original_price);
-
-              return {
-                ...product,
-                filter: parsedFilter,
-                rate,
-                validity_period: validityPeriod,
-                subAccountCount,
-                mainAccountCount,
-                linkedOrder,
-                bigServiceNames,
-                final_price: finalPrice,
-                original_price: originalPrice
-              };
-            } catch (error) {
-              console.error('产品信息初始化失败:', error);
-              return product;
-            }
-          })
-        );
-      }
-
-      this.setTotalAmounts(productData);
-      this.productData = productData;
-    },
-    // 权限开通
-    openPermissionActivation() {
-      this.$refs.newDetailModel.permissionActivationShow = true;
-    },
-    isShowPermission (product) {
-      const { auto, attribute } = product
-      const { return_status } = this.orderData?.return_status || 0
-      // 仅当该产品类型支持系统自动开通权限,且产品属性为会员服务或资源包,且“回款状态”为“全额回款”才展示,否则不展示;
-      return auto === 1 && (attribute === 1 || attribute === 2) && return_status === 1
-    },
-    // 设置红冲标识显示字段
-    setRedPunchDisplay(product) { 
-      const { isUpCommission, isUpEnt, isUpCash } = this.orderDetailInfo?.redPunchData || {};
-      const RETURN_BOOL = {
-        '合同金额': isUpCash,
-        '销售费用': isUpCommission,
-        '签约主体': isUpEnt,
-        '折扣率': isUpCash
-      }
-      return RETURN_BOOL[product] || false;
-    },
-    buildBigServiceNames(serviceIds) {
-      return new Promise((resolve) => {
-        if (!serviceIds || serviceIds.length === 0) {
-          resolve('');
-          return;
-        }
-
-        // 避免修改原始数组,创建新的整型数组
-        const numericServiceIds = serviceIds.map(id => parseInt(id));
-
-        this.$nextTick(() => {
-          try {
-            const serviceListRef = this.$refs.serviceListRef;
-            if (!serviceListRef || typeof serviceListRef.calcAlreadyBuyServiceNamesArr !== 'function') {
-              resolve('');
-              return;
-            }
-
-            const res = serviceListRef.calcAlreadyBuyServiceNamesArr(numericServiceIds);
-            const serviceData = Array.isArray(res) ? res.join('、') : '';
-            resolve(serviceData);
-          } catch (error) {
-            console.error('Error calculating service names:', error);
-            resolve('');
-          }
-        });
-      });
-    },
-    parseProductFilter(product) {
-      let parsedFilter = {};
-      if (typeof product.filter === 'string') {
-        try {
-          parsedFilter = JSON.parse(product.filter || '{}');
-        } catch {
-          parsedFilter = {};
-        }
-      } else {
-        parsedFilter = product.filter || {};
-      }
-      return parsedFilter;
-    },
-
-    // 计算折扣率
-    calculateDiscountRate(product) {
-      let rate = '无法计算';
-      if (product.original_price && Number(product.original_price) >= 0) {
-        rate = (calcDiscountRate(product.final_price, product.original_price)) + '%';
-      }
-      return rate;
-    },
-
-    // 构造子账号数量字符串。
-    buildSubAccountCount(product, filter) {
-
-      if (product.product_type === 'VIP订阅' || product.product_type === '大会员') {
-        const buyCount = Number(filter?.buyAccountCount) || 0;
-        const giftCount = Number(filter?.giftAccountCount) || 0;
-        const countTotal = buyCount + giftCount;
-        return `付费${buyCount}个,赠送${giftCount}个,合计:<span class="color_main">${countTotal}</span>个`;
-      }
-      return '';
-    },
-
-    // 构造主账号数量字符串。
-    buildMainAccountCount(product) {
-      if (product.product_type === 'VIP订阅') {
-        return `付费1个,合计<span class="color_main">1</span>个`;
-      }
-      return '';
-    },
-
-    // 处理关联订单数据。
-    processLinkedOrder(product) {
-      if (product.linkedOrder && Object.keys(product.linkedOrder).length > 0) {
-        const orderList = [product.linkedOrder];
-        return this.flattenLinkOrderList(orderList);
-      }
-      return [];
-    },
-
-    // 设置合同金额合计和标准售价合计,以及计算折扣率总和。
-    setTotalAmounts(productData) {
-      const totalFinalPrice = productData.reduce((acc, cur) => acc + Number(cur.final_price), 0).toFixed(2);
-      const totalOriginalPrice = productData.reduce((acc, cur) => acc + Number(cur.original_price), 0).toFixed(2);
-      const rateTotal = div(totalFinalPrice, totalOriginalPrice) ? (div(totalFinalPrice, totalOriginalPrice) * 100).toFixed(2) + '%' : '无法计算';
-
-      this.orderData.final_price_total = totalFinalPrice;
-      this.orderData.original_price_total = '¥' + totalOriginalPrice;
-      this.orderData.rate_total = Number(totalOriginalPrice) ? rateTotal : '无法计算';
-    },
-
-    flattenLinkOrderList(linkOrderList) {
-      const result = [];
-      if (!linkOrderList || linkOrderList.length === 0) return result;
-      linkOrderList.forEach(item => {
-        const { orderArr, ...rest } = item; // 拆分 orderArr 和其他字段
-        if (!orderArr || orderArr.length === 0) return;
-        orderArr.forEach(order => {
-          result.push({
-            ...rest,           // 非 orderArr 的字段(如 name, empowerCount 等)
-            ...order          // orderArr 中的字段(如 order_code, service_type 等)
-          });
-        });
-      });
-      return result;
-    },
-
-    shouldRenderItem(item, product) {
-      if (item.condition && typeof item.condition === 'function') {
-        const conditionResult = item.condition(product)
-        if(!conditionResult) {
-          // item.span = 0
-        }
-        return conditionResult
-      }
-      return true;
-    },
-
-    calculateValidityPeriod(buyCycle, buyType, giveCycle, giveType, product) {
-      let totalMonths = 0;
-      let buyText = '';
-      let giveText = '';
-      const TIME_MAP = {
-        '1': '天',
-        '2': '月',
-        '3': '年',
-        '4': '季度'
-      }
-      // 安全地将字符串转为整数,默认为 0
-      const parseCycle = (cycle) => {
-        const num = parseInt(cycle);
-        return isNaN(num) ? 0 : num;
-      };
-      // 计算周期并返回文本和月份数
-      const processCycle = (cycle, type) => {
-        const textValue = TIME_MAP[type] || '';
-        const value = parseCycle(cycle);
-
-        let months = 0;
-        let text = '';
-
-        if (textValue.includes('月')) {
-          months += value;
-          text = `${value}个月`;
-        } else if (textValue.includes('年')) {
-          months += value * 12;
-          text = `${value}年`;
-        } else if (textValue.includes('季度')) {
-          months += value * 3;
-          text = `${value}季度`;
-        } else if (textValue.includes('天')) {
-          months += value / 30; // 注意:此处为近似值
-          text = `${value}天`;
-        }
-
-        return { months, text };
-      };
-      const buyResult = processCycle(buyCycle, buyType);
-      const giveResult = processCycle(giveCycle, giveType);
-      totalMonths = buyResult.months + giveResult.months;
-      buyText = buyResult.text;
-      giveText = giveResult.text;
-      const returned_open = product.returned_open === '1' ? '(全额回款当日开通)' : '';
-      if(totalMonths === 0) return '-'
-      return `付费${buyText},赠送${giveText},合计<span class="color_main">${totalMonths.toFixed(0)}</span>个月${returned_open}`;
-    },
-
-    getValidityPeriodHtml(product, item) {
-      const label = item.label;
-      const value = product[item.key] || '-';
-      return `${label}:${value}`;
     },
 
     // 替代过滤器的通用方法
@@ -512,67 +64,11 @@ export default {
       if (!filterName) return value || '-';
       return this[filterName](value);
     },
-    setProductTitle(product, index) {
-      const tactics = product.tactics === '2' ? '【赠送】' : '【售卖】';
-      if(product.product_type === 'VIP订阅') {
-        return `${index + 1}.${tactics}超级订阅`;
-      }
-      return `${index + 1}.${tactics}${product.product_type}`;
-    },
     // 格式化数字,保留两位小数
     formatNumber(num, x = 2) {
       if(!num) return 0.00
       const newnum = Number(num) / 100;
       return roundToTwoDecimals(newnum, x)
-    },
-    orderCoursed(val) {
-        if (val == 0) {
-            return '待提交'
-        } else if (val == 1) {
-            return '待一审'
-        } else if (val == 2) {
-            return '待二审'
-        } else if (val == 4) {
-            return '待三审'
-        } else if (val == 3) {
-            return '已通过'
-        } else if (val == -2 || val == -3 || val == -4) {
-            return '已退回'
-        }
-    },
-    orderServiceType(val) {
-      const matchedOption = paymentTypeOptions.find(option => option.value === val);
-      return matchedOption ? matchedOption.label : val; // 如果未找到匹配项,返回原始值
-    },
-    orderStatus(val) {
-        if (!val || val == 0) {
-            return '未完成'
-        } else if (val == 1) {
-            return '已完成'
-        } else if (val == -1) {
-            return '逻辑删除'
-        } else if (val == -2) {
-            return '已取消'
-        } else if (val == -3) {
-            return '已退款'
-        } else if (val == -3) {
-            return '已退款'
-        }
-    },
-    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
-      if (columnIndex <= 3) {
-        if (rowIndex % 2 === 0) {
-          return {
-            rowspan: 2,
-            colspan: 1
-          };
-        } else {
-          return {
-            rowspan: 0,
-            colspan: 0
-          };
-        }
-      }
     }
   }
 }
@@ -592,35 +88,6 @@ export default {
     align-items: center;
     margin-bottom: 6px;
   }
-  .order-detail-product-actions-btn {
-    padding: 4px 17px;
-    background: $color_main;
-    font-size: 14px;
-    line-height: 22px;
-    color: $white;
-    border-radius: 4px;
-    border: none;
-    cursor: pointer;
-  }
-  .grouped-items {
-    display: flex;
-    flex-wrap: wrap;
-    margin-bottom: 10px;
-    .item-span-1 {
-      width: 100%;
-    }
-
-    .item-span-3 {
-      min-width: 255px;
-    }
-  }
-  .order-detail-product-content {
-    display: flex;
-    flex-wrap: wrap;
-    align-items: center;
-    margin-bottom: 6px;
-    padding: 0 24px;
-  }
   .order-detail-card-item {
     min-width: 255px;
     margin-right: 32px;
@@ -633,43 +100,5 @@ export default {
       align-items: flex-start;
     }
   }
-  .red-chong {
-    color: $red_light;
-  }
-  .no_open_root {
-    color: $red_light;
-  }
-  ::v-deep {
-    .color_main {
-      color: #2ABED1;
-    }
-  }
-  .order-detail-product-activity {
-    padding: 14px 20px;
-    border: 1px solid $color_main;
-    background: rgba(42, 190, 209, 0.08);
-    border-radius: 8px;
-    &-title {
-      font-size: 14px;
-      line-height: 22px;
-      color: $color_main;
-    }
-    &-item {
-      display: flex;
-      align-items: center;
-      margin-top: 8px;
-    }
-    &-item-title {
-      margin-right: 24px;
-      &>span {
-        font-size: 14px;
-        line-height: 22px;
-        color: #686868;
-      }
-      &>span:last-child {
-        color: #1D1D1D; 
-      }
-    }
-  }
 }
 </style>

+ 97 - 0
src/views/create-order/components/order-detail-submodule/OrderDetailCardBase.vue

@@ -0,0 +1,97 @@
+<template>
+  <div class="order-detail-card-base">
+    <div class="order-detail-card-content">
+      <div class="order-detail-card-item" v-for="(item, index) in basicInfoItems" :key="index">
+        {{ item.label }}:{{ getFilteredValue(orderData[item.key], item.filter) || '-' }}
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+export default {
+  name: 'OrderDetailCardBase',
+  data() {
+    return {
+      basicInfoItems: [
+        { label: '创建人', key: 'create_person' },
+        { label: '创建时间', key: 'create_time' },
+        { label: '最近更新人', key: 'last_update_person' },
+        { label: '最近更新时间', key: 'autoUpdate' },
+        { label: '订单审核状态', key: 'audit_status', filter: 'orderCoursed' },
+        { label: '订单状态', key: 'order_status', filter: 'orderStatus' }
+      ],
+      orderData: {}
+    }
+  },
+  computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail,
+    }), 
+  },
+  mounted() {
+    this.orderData = this.orderDetail?.orderData || {};
+  },
+  methods: {
+    // 替代过滤器的通用方法
+    getFilteredValue(value, filterName) {
+      if (!filterName) return value || '-';
+      return this[filterName](value);
+    },
+    orderCoursed(val) {
+      if (val == 0) {
+          return '待提交'
+      } else if (val == 1) {
+          return '待一审'
+      } else if (val == 2) {
+          return '待二审'
+      } else if (val == 4) {
+          return '待三审'
+      } else if (val == 3) {
+          return '已通过'
+      } else if (val == -2 || val == -3 || val == -4) {
+          return '已退回'
+      }
+    },
+    orderStatus(val) {
+      if (!val || val == 0) {
+          return '未完成'
+      } else if (val == 1) {
+          return '已完成'
+      } else if (val == -1) {
+          return '逻辑删除'
+      } else if (val == -2) {
+          return '已取消'
+      } else if (val == -3) {
+          return '已退款'
+      } else if (val == -3) {
+          return '已退款'
+      }
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.order-detail-card-base {
+  .order-detail-card-content {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    margin-bottom: 6px;
+  }
+  .order-detail-card-item {
+    min-width: 255px;
+    margin-right: 32px;
+    margin-bottom: 10px;
+    font-size: 14px;
+    line-height: 22px;
+    color: $gray_10;
+    .linkedOrder {
+      display: flex;
+      align-items: flex-start;
+    }
+  }
+}
+</style>

+ 626 - 0
src/views/create-order/components/order-detail-submodule/OrderDetailCardProduct.vue

@@ -0,0 +1,626 @@
+<template>
+  <div class="order-detail-card-product">
+    <InfoCard title="产品信息">
+      <div class="order-detail-card-content">
+        <div class="order-detail-card-item" v-for="(item, index) in productInfoTotalItems" :key="index">
+          <div v-if="item.key === 'pure_amount'">
+            {{ item.label }}:¥{{ formatNumber(orderData[item.key]) || '-' }}
+            <span class="red-chong" v-if="setRedPunchDisplay('合同金额')">(红冲过)</span>
+          </div>
+          <div v-else-if="item.key === 'final_price_total'">
+            {{ item.label }}:¥{{ orderData[item.key] || '-' }}
+            <span class="red-chong" v-if="setRedPunchDisplay('合同金额')">(红冲过)</span>
+          </div>
+          <div v-else-if="item.key === 'original_price_total'">
+            {{ item.label }}:<span :class="{'no_open_root': orderData[item.key] === '无法计算'}">{{ orderData[item.key] || '-' }}</span>
+          </div>
+          <div v-else-if="item.key === 'commission'">
+            {{ item.label }}:¥{{ formatNumber(orderData[item.key]) || '0.00' }}
+            <span class="red-chong" v-if="setRedPunchDisplay('销售费用')">(红冲过)</span>
+          </div>
+          <div v-else-if="item.key === 'rate_total'">
+            {{ item.label }}:<span :class="{'red-chong': orderData[item.key] === '无法计算'}">{{ orderData[item.key] || '-' }}</span>
+            <span class="red-chong" v-if="setRedPunchDisplay('折扣率')">(红冲过)</span>
+          </div>
+          <div v-else-if="item.key === 'zero_type'">
+            <span v-if="shouldRenderItem(item)">
+              {{ item.label }}:{{ getFilteredValue(orderData[item.key], item.filter) || '-' }}
+            </span>
+          </div>
+          <div v-else>{{ item.label }}:{{ getFilteredValue(orderData[item.key], item.filter ) || '-' }}</div>
+        </div>
+      </div>
+      <div class="order-detail-product-list">
+        <ProductCard
+          v-for="(product, index) in productData"
+          :key="product.id"
+          :title="setProductTitle(product, index)"
+          :subtitle="product.auto !== 1 ? '该产品暂不支持系统自动开通权限,请联系运维开通': ''"
+          >
+          <template #actions>
+            <button @click="openPermissionActivation(product)" class="order-detail-product-actions-btn" v-if="isShowPermission(product)">权限开通</button>
+          </template>
+          <div class="order-detail-product-content">
+            <div class="grouped-items">
+              <div
+                v-for="(item, index) in productInfoItems"
+                :key="index"
+                :class="`item-span-${item.span}`"
+                >
+                <div
+                  class="order-detail-card-item"
+                  v-if="shouldRenderItem(item, product)"
+                  >
+                  <div v-if="item.key === 'linkedOrder'" class="linkedOrder">
+                    {{ item.label }}:
+                    <TableCard :span-method="objectSpanMethod" v-if="product[item.key].length" :table-data="product[item.key]" :columns="linkOrderColumns">
+                    </TableCard>
+                    <span v-else>-</span>
+                  </div>
+                  <div v-else-if="item.key === 'subAccountCount'">
+                    <span v-html="getValidityPeriodHtml(product, item)"></span>
+                  </div>
+                  <div v-else-if="item.key === 'mainAccountCount'">
+                    <span v-html="getValidityPeriodHtml(product, item)"></span>
+                  </div>
+                  <div v-else-if="item.key ==='rate'">
+                    {{ item.label }}:
+                    <span :class="{'no_open_root': product.original_price === 0}">{{ getFilteredValue(product[item.key], item.filter) || '-' }}</span>
+                    <span class="red-chong" v-if="setRedPunchDisplay('折扣率')">(红冲过)</span>
+                  </div>
+                  <div v-else-if="item.key === 'final_price'">
+                    {{ item.label }}:¥{{ getFilteredValue(product[item.key], item.filter) || '-' }}
+                    <span class="red-chong" v-if="setRedPunchDisplay('合同金额')">(红冲过)</span>
+                  </div>
+                  <div v-else-if="item.key === 'original_price'">
+                    {{ item.label }}:
+                    <span v-if="!product.original_price" class="no_open_root">该产品暂无法计算标准售价</span>
+                    <span v-else>{{ getFilteredValue(product[item.key], item.filter) || '-' }}</span>
+                  </div>
+                  <div v-else-if="item.key === 'validity_period'">
+                    <span v-html="getValidityPeriodHtml(product, item)"></span>
+                  </div>
+                  <div v-else-if="item.key === 'supServicelds'">
+                    {{ item.label }}:{{ getFilteredValue(product[item.key], item.filter) || '-' }}
+                  </div>
+                  <div v-else-if="item.key === 'service_starttime'">
+                    {{ item.label }}:
+                    <span :class="{'no_open_root':!product.is_service_open}" >{{ product.is_service_open? (product.service_starttime || '-') : '暂未开通' }}</span>
+                  </div>
+                  <div v-else-if="item.key === 'service_endtime'">
+                    {{ item.label }}:
+                    <span :class="{'no_open_root': !product.is_service_open}" >{{ product.is_service_open ? (product.service_endtime || '-') : '暂未开通' }}</span>
+                  </div>
+                  <div v-else-if="item.key ==='phone'">
+                    {{ item.label }}:{{ orderData.user_phone || '-' }}
+                  </div>
+                  <div v-else>{{ item.label }}:{{ getFilteredValue(product[item.key], item.filter) || '-' }}</div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <template #activity>
+            <div v-if="product.activity_code" class="order-detail-product-activity">
+              <div class="order-detail-product-activity-title">
+                <span>活动商品:</span>
+                <span>{{ product.activity_code || '买2年大会员送:1年大会员+人脉管理+阳光直采+1000条数据流量包高级字段包+腾讯视频年卡' }}</span>
+              </div>
+              <div class="order-detail-product-activity-item">
+                <div class="order-detail-product-activity-item-title">
+                  <span>合同金额合计:</span>
+                  <span>¥{{ product.final_price }}</span>
+                </div>
+                <div class="order-detail-product-activity-item-title">
+                  <span>标准售价合计:</span>
+                  <span>¥{{ product.original_price }}</span>
+                </div>
+                <div class="order-detail-product-activity-item-title">
+                  <span>折扣率:</span>
+                  <span>{{ product.rate }}</span>
+                </div>
+              </div>
+            </div>
+          </template>
+        </ProductCard>
+      </div>
+    </InfoCard>
+    <newDetailModel ref="newDetailModel" :data="orderDetail"></newDetailModel>
+    <ServiceList v-show="false" ref="serviceListRef"></ServiceList>
+  </div>
+</template>
+
+<script>
+import InfoCard from '../../ui/InfoCard.vue';
+import ProductCard from '../../ui/ProductCard.vue';
+import { paymentTypeOptions } from '../../data/options.js';
+import { div, calcDiscountRate, roundToTwoDecimals } from '@/utils/number/';
+import TableCard from '../../ui/TableCard.vue';
+import newDetailModel from '@/views/order/components/new-detailModel.vue';
+import ServiceList from '../product-info-submodule/ServiceList.vue';
+import { mapState } from 'vuex';
+export default {
+  name: 'OrderDetailCardProduct',
+  components: {
+    InfoCard,
+    ProductCard,
+    TableCard,
+    newDetailModel,
+    ServiceList,
+  },
+  props: {
+    // orderDetail: {
+    //   type: Object,
+    //   default: () => {} 
+    // }
+  },
+  data() {
+    return {
+      orderDetailInfo: {},
+      productInfoTotalItems: [
+        { label: '合同金额合计', key: 'final_price_total' },
+        { label: '标准售价合计', key: 'original_price_total'},
+        { label: '折扣率', key: 'rate_total' },
+        { label: '销售费用', key: 'commission'},
+        { label: '净合同金额合计', key: 'pure_amount'},
+        { label: '0元订单类型', key: 'zero_type', condition: () => this.orderData.final_price_total === '0.00' },
+      ],
+      productInfoItems: [
+        { label: '活动产品', key: 'activity_code', span: 1, condition: (product) => product.activity_code },
+        { label: '付费类型', key: 'service_type', filter: 'orderServiceType', span: 3},
+        { label: '升级内容', key: 'supServicelds', span: 3, condition: (product) => product.supServicelds },
+        { label: '产品规格', key: 'productName', span: 3},
+        { label: '服务列表', key: 'bigServiceNames', span: 1, condition: (product) => product.productName && product.productName.includes('自定义') &&  product.product_code === 'dyh001'},
+        { label: '有效周期', key: 'validity_period', span: 1},
+        { label: '合同金额', key: 'final_price', span: 3},
+        { label: '标准售价', key: 'original_price', span: 3},
+        { label: '折扣率', key: 'rate', span: 3},
+        { label: '子账号数量', key: 'subAccountCount', span: 1, condition: () => this.parsedFilter.buyAccountCount && this.parsedFilter.giftAccountCount },
+        { label: '主账号数量', key: 'mainAccountCount', span: 1, condition: (product) => product.product_type === 'VIP订阅' },
+        { label: '关联订单', key: 'linkedOrder', span: 1},
+        { label: '开通权益手机号', key: 'phone', span: 3},
+        { label: '服务开始时间', key: 'service_starttime', span: 3},
+        { label: '服务结束时间', key: 'service_endtime', span: 3}
+      ],
+      orderData: {},
+      productData: [],
+      linkOrderColumns: [
+        {
+          prop: 'name',
+          label: '产品类型及规格',
+          width: 154
+        },
+        {
+          prop: 'empowerCount',
+          label: '账号数量',
+          width: 80 
+        },
+        {
+          prop: 'serviceEndTime',
+          label: '到期时间',
+          width: 102
+        },
+        {
+          prop: 'buySubject',
+          label: '购买主体',
+          width: 80
+        },
+        { 
+          prop:'order_code',
+          label: '订单编号',
+          width: 154
+        },
+        { 
+          prop:'service_type',
+          label: '付费类型',
+          width: 80
+        },
+        { 
+          prop:'create_time',
+          label: '创建时间', 
+          width: 102
+        } 
+      ],
+      parsedFilter: {}
+    }
+  },
+  watch: {
+    orderDetail: {
+      async handler(newVal) {
+        this.orderDetailInfo = newVal || {};
+        await this.init();
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail,
+    }),
+    
+    isUpEntRed() {
+      return this.orderDetailInfo?.redPunchData?.isUpEnt || false
+    }
+  },
+  methods: {
+    async init() {
+      this.orderData = this.orderDetailInfo?.orderData || {};
+      let productData = this.orderDetailInfo?.productData || [];
+
+      if (productData.length > 0) {
+        // 使用 Promise.all 来并行处理每个 product 的异步操作
+        productData = await Promise.all(
+          productData.map(async (product) => {
+            try {
+              const parsedFilter = this.parseProductFilter(product);
+              const serviceIds = parsedFilter.serviceIds || [];
+
+              // 等待异步方法完成
+              const bigServiceNames = await this.buildBigServiceNames(serviceIds);
+              const rate = this.calculateDiscountRate(product);
+              const validityPeriod = this.calculateValidityPeriod(
+                parsedFilter.buy_cycle,
+                parsedFilter.buy_type,
+                parsedFilter.give_cycle,
+                parsedFilter.give_type,
+                product
+              );
+              const subAccountCount = this.buildSubAccountCount(product, parsedFilter);
+              const mainAccountCount = this.buildMainAccountCount(product);
+              const linkedOrder = this.processLinkedOrder(product);
+              const finalPrice = this.formatNumber(product.final_price);
+              let originalPrice = this.formatNumber(product.original_price);
+              return {
+                ...product,
+                filter: parsedFilter,
+                rate,
+                validity_period: validityPeriod,
+                subAccountCount,
+                mainAccountCount,
+                linkedOrder,
+                bigServiceNames,
+                final_price: finalPrice,
+                original_price: originalPrice
+              };
+            } catch (error) {
+              console.error('产品信息初始化失败:', error);
+              return product;
+            }
+          })
+        );
+      }
+
+      this.setTotalAmounts(productData);
+      this.productData = productData;
+    },
+    // 权限开通
+    openPermissionActivation() {
+      this.$refs.newDetailModel.permissionActivationShow = true;
+    },
+    isShowPermission (product) {
+      const { auto, attribute } = product
+      const { return_status } = this.orderData?.return_status || 0
+      // 仅当该产品类型支持系统自动开通权限,且产品属性为会员服务或资源包,且“回款状态”为“全额回款”才展示,否则不展示;
+      return auto === 1 && (attribute === 1 || attribute === 2) && return_status === 1
+    },
+    // 设置红冲标识显示字段
+    setRedPunchDisplay(product) { 
+      const { isUpCommission, isUpEnt, isUpCash } = this.orderDetailInfo?.redPunchData || {};
+      const RETURN_BOOL = {
+        '合同金额': isUpCash,
+        '销售费用': isUpCommission,
+        '签约主体': isUpEnt,
+        '折扣率': isUpCash
+      }
+      return RETURN_BOOL[product] || false;
+    },
+    buildBigServiceNames(serviceIds) {
+      return new Promise((resolve) => {
+        if (!serviceIds || serviceIds.length === 0) {
+          resolve('');
+          return;
+        }
+
+        // 避免修改原始数组,创建新的整型数组
+        const numericServiceIds = serviceIds.map(id => parseInt(id));
+
+        this.$nextTick(() => {
+          try {
+            const serviceListRef = this.$refs.serviceListRef;
+            if (!serviceListRef || typeof serviceListRef.calcAlreadyBuyServiceNamesArr !== 'function') {
+              resolve('');
+              return;
+            }
+
+            const res = serviceListRef.calcAlreadyBuyServiceNamesArr(numericServiceIds);
+            const serviceData = Array.isArray(res) ? res.join('、') : '';
+            resolve(serviceData);
+          } catch (error) {
+            console.error('Error calculating service names:', error);
+            resolve('');
+          }
+        });
+      });
+    },
+    parseProductFilter(product) {
+      let parsedFilter = {};
+      if (typeof product.filter === 'string') {
+        try {
+          parsedFilter = JSON.parse(product.filter || '{}');
+        } catch {
+          parsedFilter = {};
+        }
+      } else {
+        parsedFilter = product.filter || {};
+      }
+      return parsedFilter;
+    },
+
+    // 计算折扣率
+    calculateDiscountRate(product) {
+      let rate = '无法计算';
+      if (product.original_price && Number(product.original_price) >= 0) {
+        rate = (calcDiscountRate(product.final_price, product.original_price)) + '%';
+      }
+      return rate;
+    },
+
+    // 构造子账号数量字符串。
+    buildSubAccountCount(product, filter) {
+
+      if (product.product_type === 'VIP订阅' || product.product_type === '大会员') {
+        const buyCount = Number(filter?.buyAccountCount) || 0;
+        const giftCount = Number(filter?.giftAccountCount) || 0;
+        const countTotal = buyCount + giftCount;
+        return `付费${buyCount}个,赠送${giftCount}个,合计:<span class="color_main">${countTotal}</span>个`;
+      }
+      return '';
+    },
+
+    // 构造主账号数量字符串。
+    buildMainAccountCount(product) {
+      if (product.product_type === 'VIP订阅') {
+        return `付费1个,合计<span class="color_main">1</span>个`;
+      }
+      return '';
+    },
+
+    // 处理关联订单数据。
+    processLinkedOrder(product) {
+      if (product.linkedOrder && Object.keys(product.linkedOrder).length > 0) {
+        const orderList = [product.linkedOrder];
+        return this.flattenLinkOrderList(orderList);
+      }
+      return [];
+    },
+
+    // 设置合同金额合计和标准售价合计,以及计算折扣率总和。
+    setTotalAmounts(productData) {
+      const totalFinalPrice = productData.reduce((acc, cur) => acc + Number(cur.final_price), 0).toFixed(2);
+      const totalOriginalPrice = productData.reduce((acc, cur) => acc + Number(cur.original_price), 0).toFixed(2);
+      const rateTotal = div(totalFinalPrice, totalOriginalPrice) ? (div(totalFinalPrice, totalOriginalPrice) * 100).toFixed(2) + '%' : '无法计算';
+
+      this.orderData.final_price_total = totalFinalPrice;
+      this.orderData.original_price_total = Number(totalOriginalPrice) ? '¥' + totalOriginalPrice : '无法计算';
+      this.orderData.rate_total = Number(totalOriginalPrice) ? rateTotal : '无法计算';
+    },
+
+    flattenLinkOrderList(linkOrderList) {
+      const result = [];
+      if (!linkOrderList || linkOrderList.length === 0) return result;
+      linkOrderList.forEach(item => {
+        const { orderArr, ...rest } = item; // 拆分 orderArr 和其他字段
+        if (!orderArr || orderArr.length === 0) return;
+        orderArr.forEach(order => {
+          result.push({
+            ...rest,           // 非 orderArr 的字段(如 name, empowerCount 等)
+            ...order          // orderArr 中的字段(如 order_code, service_type 等)
+          });
+        });
+      });
+      return result;
+    },
+
+    shouldRenderItem(item, product) {
+      if (item.condition && typeof item.condition === 'function') {
+        const conditionResult = item.condition(product)
+        if(!conditionResult) {
+          // item.span = 0
+        }
+        return conditionResult
+      }
+      return true;
+    },
+
+    calculateValidityPeriod(buyCycle, buyType, giveCycle, giveType, product) {
+      let totalMonths = 0;
+      let buyText = '';
+      let giveText = '';
+      const TIME_MAP = {
+        '1': '天',
+        '2': '月',
+        '3': '年',
+        '4': '季度'
+      }
+      // 安全地将字符串转为整数,默认为 0
+      const parseCycle = (cycle) => {
+        const num = parseInt(cycle);
+        return isNaN(num) ? 0 : num;
+      };
+      // 计算周期并返回文本和月份数
+      const processCycle = (cycle, type) => {
+        const textValue = TIME_MAP[type] || '';
+        const value = parseCycle(cycle);
+
+        let months = 0;
+        let text = '';
+
+        if (textValue.includes('月')) {
+          months += value;
+          text = `${value}个月`;
+        } else if (textValue.includes('年')) {
+          months += value * 12;
+          text = `${value}年`;
+        } else if (textValue.includes('季度')) {
+          months += value * 3;
+          text = `${value}季度`;
+        } else if (textValue.includes('天')) {
+          months += value / 30; // 注意:此处为近似值
+          text = `${value}天`;
+        }
+
+        return { months, text };
+      };
+      const buyResult = processCycle(buyCycle, buyType);
+      const giveResult = processCycle(giveCycle, giveType);
+      totalMonths = buyResult.months + giveResult.months;
+      buyText = buyResult.text;
+      giveText = giveResult.text;
+      const returned_open = product.returned_open === '1' ? '(全额回款当日开通)' : '';
+      if(totalMonths === 0) return '-'
+      return `付费${buyText},赠送${giveText},合计<span class="color_main">${totalMonths.toFixed(0)}</span>个月${returned_open}`;
+    },
+
+    getValidityPeriodHtml(product, item) {
+      const label = item.label;
+      const value = product[item.key] || '-';
+      return `${label}:${value}`;
+    },
+
+    // 替代过滤器的通用方法
+    getFilteredValue(value, filterName) {
+      if (!filterName) return value || '-';
+      return this[filterName](value);
+    },
+    setProductTitle(product, index) {
+      const tactics = product.tactics === '2' ? '【赠送】' : '【售卖】';
+      if(product.product_type === 'VIP订阅') {
+        return `${index + 1}.${tactics}超级订阅`;
+      }
+      return `${index + 1}.${tactics}${product.product_type}`;
+    },
+    // 格式化数字,保留两位小数
+    formatNumber(num, x = 2) {
+      if(!num) return 0.00
+      const newnum = Number(num) / 100;
+      return roundToTwoDecimals(newnum, x)
+    },
+    
+    orderServiceType(val) {
+      const matchedOption = paymentTypeOptions.find(option => option.value === val);
+      return matchedOption ? matchedOption.label : val; // 如果未找到匹配项,返回原始值
+    },
+    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
+      if (columnIndex <= 3) {
+        if (rowIndex % 2 === 0) {
+          return {
+            rowspan: 2,
+            colspan: 1
+          };
+        } else {
+          return {
+            rowspan: 0,
+            colspan: 0
+          };
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.order-detail-card-product {
+  background: #F2F2F4;
+  ::v-deep {
+    .info-card {
+      margin-bottom: 16px;
+    }
+  }
+  .order-detail-card-content {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    margin-bottom: 6px;
+  }
+  .order-detail-product-actions-btn {
+    padding: 4px 17px;
+    background: $color_main;
+    font-size: 14px;
+    line-height: 22px;
+    color: $white;
+    border-radius: 4px;
+    border: none;
+    cursor: pointer;
+  }
+  .grouped-items {
+    display: flex;
+    flex-wrap: wrap;
+    margin-bottom: 10px;
+    .item-span-1 {
+      width: 100%;
+    }
+
+    .item-span-3 {
+      min-width: 255px;
+    }
+  }
+  .order-detail-product-content {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    margin-bottom: 6px;
+    padding: 0 24px;
+  }
+  .order-detail-card-item {
+    min-width: 255px;
+    margin-right: 32px;
+    margin-bottom: 10px;
+    font-size: 14px;
+    line-height: 22px;
+    color: $gray_10;
+    .linkedOrder {
+      display: flex;
+      align-items: flex-start;
+    }
+  }
+  .red-chong {
+    color: $red_light;
+  }
+  .no_open_root {
+    color: $red_light;
+  }
+  ::v-deep {
+    .color_main {
+      color: #2ABED1;
+    }
+  }
+  .order-detail-product-activity {
+    padding: 14px 20px;
+    border: 1px solid $color_main;
+    background: rgba(42, 190, 209, 0.08);
+    border-radius: 8px;
+    &-title {
+      font-size: 14px;
+      line-height: 22px;
+      color: $color_main;
+    }
+    &-item {
+      display: flex;
+      align-items: center;
+      margin-top: 8px;
+    }
+    &-item-title {
+      margin-right: 24px;
+      &>span {
+        font-size: 14px;
+        line-height: 22px;
+        color: #686868;
+      }
+      &>span:last-child {
+        color: #1D1D1D; 
+      }
+    }
+  }
+}
+</style>

+ 4 - 8
src/views/create-order/components/order-detail-submodule/PaymentInfo.vue

@@ -56,6 +56,7 @@
 import InfoCard from '../../ui/InfoCard.vue';
 import TableCard from '../../ui/TableCard.vue';
 import newDetailModel from '../newDetailModel.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'PaymentInfo',
   components: {
@@ -63,14 +64,6 @@ export default {
     TableCard,
     newDetailModel
   },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {}
-      }
-    }
-  },
   data() {
     const defaultRender = (val) => val || '-';
     return {
@@ -235,6 +228,9 @@ export default {
     }
   },
   computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail 
+    }),
     returnStatus() {
       const val = this.orderDetail?.orderData?.return_status || 0;
       if (val == 0) {

+ 10 - 29
src/views/create-order/components/order-detail-submodule/PaymentPlan.vue

@@ -12,51 +12,32 @@
         </span>
       </template>
       <div class="payment-plan-content">
-        <TableCard
-          :tableData="paymentPlanList"
-          :columns="[
-            {label: '序号', prop: 'code', width: '280'},
-            {label: '预计回款时间', prop: 'time'},
-            {label: '预计回款金额', prop: 'money'}
-          ]"
-          :width="'1108px'"
-          :cellClass="'payment-plan-content-table'"
-        >
-          <template v-slot:money="{row}">
-            <span>¥{{ formatNumber(row.row.money) }}</span>
-          </template>
-        </TableCard>
+        <paymentPlanModule></paymentPlanModule>
       </div>
     </InfoCard>
   </div>
 </template>
 <script>
 import InfoCard from '../../ui/InfoCard.vue'
-import TableCard from '../../ui/TableCard.vue'
+import paymentPlanModule from './PaymentPlanModule.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'PaymentPlan',
   components: {
     InfoCard,
-    TableCard
-  },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {}
-      }
-    }
+    paymentPlanModule
   },
   data() {
     return {
-      paymentPlanList: [
-        {"code":1,"money":999,"time":"2025-04-22"},
-        {"code":2,"money":7000,"time":"2025-04-23"},
-        {"code":"合计","money":7999,"time":"-"}
-      ],
+      paymentPlanList: [],
       returnMoneyPlant: {}
     } 
   },
+  computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    }) 
+  },
   mounted() {
     this.getPaymentPlanList()
   },

+ 74 - 0
src/views/create-order/components/order-detail-submodule/PaymentPlanModule.vue

@@ -0,0 +1,74 @@
+<template>
+  <div class="payment-plan-module">
+    <TableCard
+      :tableData="paymentPlanList"
+      :columns="[
+        {label: '序号', prop: 'code', width: '280'},
+        {label: '预计回款时间', prop: 'time'},
+        {label: '预计回款金额', prop: 'money'}
+      ]"
+      :width="'1108px'"
+      :cellClass="'payment-plan-content-table'"
+    >
+      <template v-slot:money="{row}">
+        <span>¥{{ formatNumber(row.row.money) }}</span>
+      </template>
+    </TableCard>
+  </div>
+</template>
+<script>
+import TableCard from '../../ui/TableCard.vue'
+import { mapState } from 'vuex'
+export default {
+  name: 'PaymentPlanModule',
+  components: {
+    TableCard
+  },
+  data() {
+    return {
+      paymentPlanList: [
+        {"code":1,"money":999,"time":"2025-04-22"},
+        {"code":2,"money":7000,"time":"2025-04-23"},
+        {"code":"合计","money":7999,"time":"-"}
+      ],
+      returnMoneyPlant: {}
+    } 
+  },
+  mounted() {
+    this.getPaymentPlanList()
+  },
+  computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    })
+  },
+  methods: {
+    getPaymentPlanList() {
+      this.returnMoneyPlant = this.orderDetail?.returnMoneyPlant || {};
+      const listMap = this.orderDetail?.returnMoneyPlant?.list || {};
+
+      let plantList = listMap.plantList;
+
+      if (!plantList) {
+        this.paymentPlanList = [];
+        return;
+      }
+
+      try {
+        plantList = JSON.parse(plantList);
+      } catch (error) {
+        console.error('Failed to parse plantList JSON:', error);
+        plantList = [];
+      }
+
+      this.paymentPlanList = Array.isArray(plantList) ? plantList : [];
+    },
+    setState(state) {
+      this.paymentPlanList = state;
+    },
+    formatNumber(num, x = 2) {
+      return (num / 100).toFixed(x)
+    }
+  }
+}
+</script>

+ 8 - 47
src/views/create-order/components/order-detail-submodule/PerformanceBelongs.vue

@@ -2,11 +2,7 @@
   <div class="performmace-belongs">
     <InfoCard title="最新业绩归属">
       <div class="performmace-belongs-content">
-        <TableCard
-          :table-data="newPerformmaceBelongsList"
-          :columns="newPerformmaceBelongsColumns"
-          width="1108px"
-        ></TableCard>
+        <PerformanceBelongsModule></PerformanceBelongsModule>
       </div>
     </InfoCard>
     <InfoCard title="业绩变更记录" :is-show-length="true" :length="performanceChangeList.length || 0">
@@ -23,53 +19,18 @@
 <script>
 import InfoCard from '../../ui/InfoCard.vue';
 import TableCard from '../../ui/TableCard.vue';
+import PerformanceBelongsModule from './PerformanceBelongsModule.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'PerformmaceBelongs',
   components: {
     InfoCard,
-    TableCard
-  },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {};
-      },
-    },
+    TableCard,
+    PerformanceBelongsModule
   },
   data() {
     const defaultRender = (val) => val || '-';
     return {
-      newPerformmaceBelongsColumns: [
-        {
-          label: '销售人员',
-          prop: 'name',
-          render: (row) => {
-            return defaultRender(row.name);
-          }
-        },
-        {
-          label: '业绩归属部门',
-          prop: 'saler_dept',
-          render: (row) => {
-            return defaultRender(row.saler_dept);
-          }
-        },
-        {
-          label: '销售业绩',
-          prop: 'money',
-          render: (row) => {
-            return this.formatNumber(row.money) ? '¥' + this.formatNumber(row.money) : '-'; 
-          }
-        },
-        {
-          label: '销售渠道',
-          prop: 'order_channel_new',
-          render: (row) => {
-            return defaultRender(row.order_channel_new); 
-          }
-        }
-      ],
       performanceChangeColumns: [
         {
           label: '操作人',
@@ -147,9 +108,9 @@ export default {
     }
   },
   computed: {
-    newPerformmaceBelongsList () {
-      return this.orderDetail?.saleDataRes?.saleFinal?.list || []
-    },
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    }),
     performanceChangeList () {
       return this.orderDetail?.saleDataRes?.saleRecord || []
     }

+ 71 - 0
src/views/create-order/components/order-detail-submodule/PerformanceBelongsModule.vue

@@ -0,0 +1,71 @@
+<template>
+  <div class="performmace-belongs-module">
+    <TableCard
+      :table-data="newPerformmaceBelongsList"
+      :columns="newPerformmaceBelongsColumns"
+      width="1108px"
+    ></TableCard>
+  </div>
+</template>
+<script>
+import TableCard from '../../ui/TableCard.vue';
+import { mapState } from 'vuex';
+export default {
+  name: 'PerformmaceBelongs',
+  components: {
+    TableCard
+  },
+  data() {
+    const defaultRender = (val) => val || '-';
+    return {
+      newPerformmaceBelongsColumns: [
+        {
+          label: '销售人员',
+          prop: 'name',
+          render: (row) => {
+            return defaultRender(row.name);
+          }
+        },
+        {
+          label: '业绩归属部门',
+          prop: 'saler_dept',
+          render: (row) => {
+            return defaultRender(row.saler_dept);
+          }
+        },
+        {
+          label: '销售业绩',
+          prop: 'money',
+          render: (row) => {
+            return this.formatNumber(row.money) ? '¥' + this.formatNumber(row.money) : '-'; 
+          }
+        },
+        {
+          label: '销售渠道',
+          prop: 'order_channel_new',
+          render: (row) => {
+            return defaultRender(row.order_channel_new); 
+          }
+        }
+      ]
+    }
+  },
+  computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    }),
+    newPerformmaceBelongsList () {
+      return this.orderDetail?.saleDataRes?.saleFinal?.list || []
+    }
+  },
+  methods: {
+    formatNumber(num, x = 2) {
+      if(!Number(num)) return false;
+      return (num / 100).toFixed(x)
+    },
+    setState(state) {
+      this.newPerformmaceBelongsList = state
+    }
+  }
+}
+</script>

+ 4 - 8
src/views/create-order/components/order-detail-submodule/RefundInfo.vue

@@ -27,20 +27,13 @@
 <script>
 import InfoCard from '../../ui/InfoCard.vue';
 import TableCard from '../../ui/TableCard.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'RefundInfo',
   components: {
     InfoCard,
     TableCard
   },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {}
-      }
-    }
-  },
   data() {
     const defaultRender = (val) => val || '-';
     return {
@@ -61,6 +54,9 @@ export default {
     }
   },
   computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail 
+    }),
     refundStatus() {
       const val = this.orderDetail?.orderData?.refund_status || 0;
       if (val == 0) {

+ 4 - 8
src/views/create-order/components/order-detail-submodule/StampRecord.vue

@@ -18,20 +18,13 @@
 <script>
 import InfoCard from '../../ui/InfoCard.vue';
 import TableCard from '../../ui/TableCard.vue';
+import { mapState } from 'vuex';
 export default {
   name: 'ChangeRecord',
   components: {
     InfoCard,
     TableCard
   },
-  props: {
-    orderDetail: {
-      type: Object,
-      default: () => {
-        return {}
-      }
-    }
-  },
   data() {
     return {
       columns: [
@@ -63,6 +56,9 @@ export default {
     }
   },
   computed: {
+    ...mapState({
+      orderDetail: state => state.order.orderDetail
+    }),
     stampRecordList () {
       return this.orderDetail?.sealArr|| []
     }

+ 8 - 12
src/views/create-order/order-detail.vue

@@ -38,7 +38,7 @@ import PerformanceBelongs from './components/order-detail-submodule/PerformanceB
 import PaymentPlan from './components/order-detail-submodule/PaymentPlan.vue'
 import ChangeRecord from './components/order-detail-submodule/ChangeRecord.vue'
 import StampRecord from './components/order-detail-submodule/StampRecord.vue'
-import { ajaxGetOrderDetail } from '@/api/modules/index'
+import { mapActions } from 'vuex'
 
 export default {
   name: 'OrderDetail',
@@ -135,25 +135,21 @@ export default {
 
   },
   created() {
-    this.loading = true
-    this.getOrderDetail()
+    this.getOrderDetailFun()
   },
   methods: {
-    async getOrderDetail() {
+    ...mapActions('order', ['getOrderDetail']),
+    getOrderDetailFun() {
       const { id } = this.$route.params
-      const { error_code: code, data } = await ajaxGetOrderDetail({ orderCode: id })
-      if (code === 0 && data) {
-        this.orderDetail = data
-      } else {
-        this.$message.error('获取订单详情失败')
-      }
-      this.loading = false
+      this.getOrderDetail({ id }).then(res => {
+        this.orderDetail = res || {}
+      })
     },
     setLoading(val) {
       this.loading = val
     },
     doRefresh (type) {
-      this.getOrderDetail()
+      this.getOrderDetailFun()
       this.doSelectTabName(type || '订单详情')
     },
     doSelectTabName (name = '订单详情') {