Forráskód Böngészése

Merge branch 'whr_card'

wanghairong 5 hónapja
szülő
commit
76e4a2a658

+ 1 - 0
package.json

@@ -13,6 +13,7 @@
     "axios": "^1.7.2",
     "axios": "^1.7.2",
     "crypto-js": "^4.2.0",
     "crypto-js": "^4.2.0",
     "dayjs": "^1.11.11",
     "dayjs": "^1.11.11",
+    "echarts": "^5.5.1",
     "less": "^4.2.0",
     "less": "^4.2.0",
     "less-loader": "^12.2.0",
     "less-loader": "^12.2.0",
     "lodash": "^4.17.21",
     "lodash": "^4.17.21",

+ 18 - 6
src/App.vue

@@ -1,13 +1,11 @@
 <template>
 <template>
-  <a-config-provider 
-    :locale="locale"
-  >
+  <a-config-provider :locale="locale">
     <div class="public_local_loading" :class="{ 'hidden-loading': !systemStore.getLocalLoading }">
     <div class="public_local_loading" :class="{ 'hidden-loading': !systemStore.getLocalLoading }">
       <div class="public_local_loading_bg">
       <div class="public_local_loading_bg">
         <a-spin class="public_local_loading_logo" dot />
         <a-spin class="public_local_loading_logo" dot />
       </div>
       </div>
     </div>
     </div>
-    <router-view  v-if="isRouterActive"/>
+    <router-view v-if="isRouterActive" />
   </a-config-provider>
   </a-config-provider>
 </template>
 </template>
 
 
@@ -15,6 +13,7 @@
 import { ref, onMounted, nextTick, provide } from "vue"
 import { ref, onMounted, nextTick, provide } from "vue"
 import { useDarkThemeHook, useLang } from '@/hooks'
 import { useDarkThemeHook, useLang } from '@/hooks'
 import { useSystemStore } from '@/store/modules/systemStore'
 import { useSystemStore } from '@/store/modules/systemStore'
+import { dictionaryList } from "@/api/path/dict"
 
 
 const isRouterActive = ref(true)
 const isRouterActive = ref(true)
 // 全局语言
 // 全局语言
@@ -32,19 +31,30 @@ provide('reloadRoutePage', () => {
 })
 })
 
 
 
 
-onMounted(() => {
+onMounted(async () => {
   const getLoadingNode = document.getElementById('Loading')
   const getLoadingNode = document.getElementById('Loading')
   const { body } = document
   const { body } = document
   if (getLoadingNode) {
   if (getLoadingNode) {
     body.removeChild(getLoadingNode)
     body.removeChild(getLoadingNode)
   }
   }
+
+  if (systemStore?.token) {
+    const { code, data } = await dictionaryList({
+      size: 99999,
+      current: 1,
+    })
+    if (code == 200) {
+      window.localStorage.setItem('dictList', JSON.stringify(data.records))
+    }
+  }
 })
 })
 </script>
 </script>
 
 
-<style  lang="less" >
+<style lang="less">
 body {
 body {
   overflow: hidden;
   overflow: hidden;
 }
 }
+
 // 加载loading css
 // 加载loading css
 .public_local_loading {
 .public_local_loading {
   position: fixed;
   position: fixed;
@@ -75,11 +85,13 @@ body {
     user-select: none;
     user-select: none;
   }
   }
 }
 }
+
 .hidden-loading.public_local_loading {
 .hidden-loading.public_local_loading {
   opacity: 0;
   opacity: 0;
   z-index: -10 !important;
   z-index: -10 !important;
   cursor: auto !important;
   cursor: auto !important;
 }
 }
+
 @keyframes r-loading {
 @keyframes r-loading {
   0% {
   0% {
     transform: rotate(0deg);
     transform: rotate(0deg);

+ 41 - 0
src/api/customer.js

@@ -0,0 +1,41 @@
+import service from './axios'
+
+export function getCustomerList(data) {
+    return service({
+        url: '/app/user/getCustomerList',
+        method: 'post',
+        data
+    })
+}
+
+export function addCustomer(data) {
+    return service({
+        url: '/app/user/addCustomer',
+        method: 'post',
+        data
+    })
+}
+
+export function updateCustomer(data) {
+    return service({
+        url: "/app/user/updateCustomer",
+        method: "post",
+        data,
+    });
+}
+
+export function deleteCustomer(data) {
+    return service({
+        url: '/customer/delete',
+        method: 'post',
+        data
+    })
+}
+
+export function getCustomer(data) {
+    return service({
+        url: "/app/user/getCustomer",
+        method: "post",
+        data,
+    });
+}

+ 22 - 0
src/api/path/tariffManagement.api.js

@@ -0,0 +1,22 @@
+
+import service from '../axios'
+
+// 查询资费计划
+export function tariffList(param) {
+    return service.post('/admin/platform/tariffList', param)
+}
+
+// 添加资费计划
+export function addTariff(param) {
+    return service.post('/admin/platform/addTariff', param)
+}
+
+// 更新资费计划
+export function updateTariff(param) {
+    return service.post('/admin/platform/updateTariff', param)
+}
+
+// 更新资费计划
+export function deleteTariff(param) {
+    return service.post('/admin/platform/deleteTariff', param)
+}

+ 14 - 0
src/hooks/enum.js

@@ -0,0 +1,14 @@
+// 字典类型枚举值
+export const enum_dict = {
+    TRAFFIC_PACKET_STATUS: "traffic_packet _status", // 流量包状态
+    SUBSCRIPTION_RELATIONSHIP_STATUS: "subscription _relationship_status", // 订阅关系状态
+    MAIN_CARD_STATUS: "main_card_status", // 主卡状态
+    PACKAGE_TRIFF_PLAN_STATUS: "package_tariff_plan_status", // 套餐资费计划判断状态
+    SUPPLIER_SOURCE: "supplier_source", // 来源(订单管理列表)
+    TRAFFICTYPE: "TrafficType", // 流量类型
+    SOURCE: "source", // 来源(资费列表)
+    BILLINGCYCLE: "Billingcycle", // 计费周期
+    BILLINGTYPE: "BillingType", // 计费分类
+    BILLINGMETHOD: "billingMethod", // 计费方式
+    SETTLEMENTCYCLE: "settlementCycle", // 结算周期
+};

+ 3 - 1
src/i18n/zh/index.js

@@ -7,6 +7,7 @@ import dataPackage from './dataPackage'
 import customer from './customer'
 import customer from './customer'
 import customerPackage from './customerPackage'
 import customerPackage from './customerPackage'
 import lotCard from './lotCard'
 import lotCard from './lotCard'
+import tariffManagement from './tariffManagement'
 
 
 export default {
 export default {
   login,
   login,
@@ -17,5 +18,6 @@ export default {
   dataPackage,
   dataPackage,
   customer,
   customer,
   customerPackage,
   customerPackage,
-  lotCard
+  lotCard,
+  tariffManagement
 }
 }

+ 19 - 0
src/i18n/zh/tariffManagement.js

@@ -0,0 +1,19 @@
+export default {
+    // 资费计划
+    simDataPlanId: "流量包ID",
+    label: "资费名称",
+    userId: "用户ID",
+    source: "来源",
+    trafficType: "流量类型",
+    billingType: "计费类型",
+    bagSize: "流量包大小",
+    billingCycle: "计费周期",
+    billingMethod: "计费方式",
+    settlementCycle: "结算周期",
+    sourcePrice: "来源价格",
+    pricing: "价格",
+    currency: "币种",
+
+    // 按钮
+    addPlanBtn: "添加资费计划"
+}

+ 666 - 0
src/views/customer/NewCustomerForm.vue

@@ -0,0 +1,666 @@
+<template>
+    <a-modal :visible="visible" :title="editMode ? $t('customer.editCustomer') : $t('customer.addCustomer')"
+        :loading="loading" @ok="handleSubmit" @cancel="handleCancel" :width="720">
+        <a-tabs>
+            <a-tab-pane key="1" :title="$t('customer.basicInfo')">
+                <a-form :model="formData" :rules="rules" ref="formRef" :label-col-props="{ span: 6 }"
+                    :wrapper-col-props="{ span: 18 }">
+                    <a-divider>{{ $t('customer.basicInfoSection') }}</a-divider>
+                    <a-form-item field="customerInfo.customerCode" :label="$t('customer.customerCode')" required>
+                        <a-input v-model="formData.customerInfo.customerCode"
+                            :placeholder="$t('customer.enterCustomerCode')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.name" :label="$t('customer.customerName')" required>
+                        <a-input v-model="formData.customerInfo.name" :placeholder="$t('customer.enterCustomerName')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="userInfo.username" :label="$t('customer.accountNumber')" required>
+                        <a-input v-model="formData.userInfo.username" :placeholder="$t('customer.enterAccountNumber')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="userInfo.password" :label="$t('customer.password')" required>
+                        <a-input-password v-model="formData.userInfo.password"
+                            :placeholder="$t('customer.enterPassword')" :max-length="60" show-word-limit />
+                        <a-button type="primary" @click="generatePassword">{{ $t('customer.generatePassword')
+                            }}</a-button>
+                    </a-form-item>
+                    <a-form-item field="customerInfo.remark" :label="$t('customer.remark')">
+                        <a-input v-model="formData.customerInfo.remark" :placeholder="$t('customer.enterRemark')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.exTime" :label="$t('customer.validPeriod')" required>
+                        <a-date-picker v-model="formData.customerInfo.exTime"
+                            :placeholder="$t('customer.selectValidPeriod')" value-format="YYYY-MM-DD" />
+                    </a-form-item>
+                    <a-form-item field="userInfo.state" :label="$t('customer.statusName')" required>
+                        <a-radio-group v-model="formData.userInfo.state">
+                            <a-radio value="1">{{ $t('customer.status.normal') }}</a-radio>
+                            <a-radio value="2">{{ $t('customer.status.disabled') }}</a-radio>
+                            <a-radio value="3">{{ $t('customer.status.pending') }}</a-radio>
+                            <a-radio value="4">{{ $t('customer.status.suspended') }}</a-radio>
+                        </a-radio-group>
+                    </a-form-item>
+
+                    <a-divider>{{ $t('customer.smsInfoSection') }}</a-divider>
+                    <a-form-item field="customerInfo.smsSubCode" :label="$t('customer.smsSubCode')">
+                        <a-input v-model="formData.customerInfo.smsSubCode"
+                            :placeholder="$t('customer.enterSmsSubCode')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.smsName" :label="$t('customer.smsName')">
+                        <a-input v-model="formData.customerInfo.smsName" :placeholder="$t('customer.enterSmsName')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.loginSmsTemplate" :label="$t('customer.loginSmsTemplate')">
+                        <a-input v-model="formData.customerInfo.loginSmsTemplate"
+                            :placeholder="$t('customer.enterLoginSmsTemplate')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.alarmSmsTemplate" :label="$t('customer.alarmSmsTemplate')">
+                        <a-input v-model="formData.customerInfo.alarmSmsTemplate"
+                            :placeholder="$t('customer.enterAlarmSmsTemplate')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                </a-form>
+            </a-tab-pane>
+            <a-tab-pane key="2" :title="$t('customer.accountManagement')">
+                <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
+                    <a-form-item field="customerProperty.amount" :label="$t('customer.accountBalance')">
+                        <a-input-number v-model="formData.customerProperty.amount" :min="0" :precision="2" :step="100"
+                            :suffix="$t('customer.currency')" />
+                    </a-form-item>
+                    <a-form-item field="customerProperty.rechargeLimit" :label="$t('customer.rechargeLimit')">
+                        <a-input-number v-model="formData.customerProperty.rechargeLimit" :min="0" :precision="2"
+                            :step="1" :suffix="$t('customer.currencyPerTime')" />
+                    </a-form-item>
+                    <a-form-item field="customerProperty.lineOfCredit" :label="$t('customer.creditLimit')">
+                        <a-input-number v-model="formData.customerProperty.lineOfCredit" :min="0" :precision="2"
+                            :step="100" :suffix="$t('customer.currency')" />
+                    </a-form-item>
+                    <a-form-item field="customerProperty.smsUnitPrice" :label="$t('customer.mobileSmsPrice')">
+                        <a-input-number v-model="formData.customerProperty.smsUnitPrice" :min="0" :precision="2"
+                            :step="0.1" :suffix="$t('customer.currencyPerMessage')" />
+                    </a-form-item>
+                    <a-form-item field="customerProperty.iotSmsUnitPrice" :label="$t('customer.iotSmsPrice')">
+                        <a-input-number v-model="formData.customerProperty.iotSmsUnitPrice" :min="0" :precision="2"
+                            :step="0.1" :suffix="$t('customer.currencyPerMessage')" />
+                    </a-form-item>
+                    <a-form-item field="customerProperty.paymentMethod" :label="$t('customer.paymentMethodName')"
+                        required>
+                        <a-radio-group v-model="formData.customerProperty.paymentMethod">
+                            <a-radio value="prepaid">{{ $t('customer.paymentMethod.prepaid') }}</a-radio>
+                            <a-radio value="postpaid">{{ $t('customer.paymentMethod.postpaid') }}</a-radio>
+                        </a-radio-group>
+                    </a-form-item>
+                </a-form>
+            </a-tab-pane>
+            <a-tab-pane key="3" :title="$t('customer.customerData')">
+                <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
+                    <a-divider>{{ $t('customer.basicInfoSection') }}</a-divider>
+                    <a-form-item field="customerInfo.platformName" :label="$t('customer.platformName')" required>
+                        <a-input v-model="formData.customerInfo.platformName"
+                            :placeholder="$t('customer.enterPlatformName')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.companyName" :label="$t('customer.companyName')">
+                        <a-input v-model="formData.customerInfo.companyName"
+                            :placeholder="$t('customer.enterCompanyName')" :max-length="60" show-word-limit />
+                    </a-form-item>
+
+                    <a-form-item field="customerInfo.servicePhone" :label="$t('customer.servicePhone')">
+                        <a-input v-model="formData.customerInfo.servicePhone"
+                            :placeholder="$t('customer.enterServicePhone')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.domain" :label="$t('customer.domain')">
+                        <a-input v-model="formData.customerInfo.domain" :placeholder="$t('customer.enterDomain')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+
+                    <a-form-item field="customerInfo.homepageLicenseCode" :label="$t('customer.homepageLicenseCode')">
+                        <a-input v-model="formData.customerInfo.homepageLicenseCode"
+                            :placeholder="$t('customer.enterHomepageLicenseCode')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.companyAddress" :label="$t('customer.companyAddress')">
+                        <a-textarea v-model="formData.customerInfo.companyAddress"
+                            :placeholder="$t('customer.enterCompanyAddress')" :max-length="200" show-word-limit />
+                    </a-form-item>
+
+                    <a-divider>{{ $t('customer.contactPerson') }}</a-divider>
+                    <a-form-item field="customerInfo.contactName" :label="$t('customer.contactName')">
+                        <a-input v-model="formData.customerInfo.contactName"
+                            :placeholder="$t('customer.enterContactName')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.phone" :label="$t('customer.contactPhone')">
+                        <a-input v-model="formData.customerInfo.phone" :placeholder="$t('customer.enterContactPhone')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.email" :label="$t('customer.contactEmail')">
+                        <a-input v-model="formData.customerInfo.email" :placeholder="$t('customer.enterContactEmail')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.qq" :label="$t('customer.contactQQ')">
+                        <a-input v-model="formData.customerInfo.qq" :placeholder="$t('customer.enterContactQQ')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+
+                    <a-divider>{{ $t('customer.deliveryInfo') }}</a-divider>
+                    <a-form-item field="customerInfo.deliveryAddress" :label="$t('customer.deliveryAddress')">
+                        <a-textarea v-model="formData.customerInfo.deliveryAddress"
+                            :placeholder="$t('customer.enterDeliveryAddress')" :max-length="200" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.deliveryPhone" :label="$t('customer.deliveryPhone')">
+                        <a-input v-model="formData.customerInfo.deliveryPhone"
+                            :placeholder="$t('customer.enterDeliveryPhone')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInfo.deliveryName" :label="$t('customer.deliveryName')">
+                        <a-input v-model="formData.customerInfo.deliveryName"
+                            :placeholder="$t('customer.enterDeliveryName')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                </a-form>
+            </a-tab-pane>
+            <a-tab-pane key="4" :title="$t('customer.interfaceParams')">
+                <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
+                    <a-divider>{{ $t('customer.basicInfoSection') }}</a-divider>
+                    <a-form-item field="customerInterfaceParams.smsStatusReportUrl"
+                        :label="$t('customer.smsStatusReportUrl')">
+                        <a-input v-model="formData.customerInterfaceParams.smsStatusReportUrl"
+                            :placeholder="$t('customer.enterSmsStatusReportUrl')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInterfaceParams.reportIp" :label="$t('customer.reportIp')">
+                        <a-input v-model="formData.customerInterfaceParams.reportIp"
+                            :placeholder="$t('customer.enterReportIp')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInterfaceParams.deliveryPriority"
+                        :label="$t('customer.deliveryPriorityName')">
+                        <a-select v-model="formData.customerInterfaceParams.deliveryPriority"
+                            :placeholder="$t('customer.selectDeliveryPriority')">
+                            <a-option value="high">{{ $t('customer.deliveryPriority.high') }}</a-option>
+                            <a-option value="medium">{{ $t('customer.deliveryPriority.medium') }}</a-option>
+                            <a-option value="low">{{ $t('customer.deliveryPriority.low') }}</a-option>
+                        </a-select>
+                    </a-form-item>
+                    <a-form-item field="customerInterfaceParams.dataReportUrl" :label="$t('customer.dataReportUrl')">
+                        <a-input v-model="formData.customerInterfaceParams.dataReportUrl"
+                            :placeholder="$t('customer.enterDataReportUrl')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                </a-form>
+            </a-tab-pane>
+            <a-tab-pane key="5" :title="$t('customer.billingInfo')">
+                <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
+                    <a-form-item field="customerInvoice.invoiceTitle" :label="$t('customer.invoiceTitle')">
+                        <a-input v-model="formData.customerInvoice.invoiceTitle"
+                            :placeholder="$t('customer.enterInvoiceTitle')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.taxRegistrationNumber"
+                        :label="$t('customer.taxRegistrationNumber')">
+                        <a-input v-model="formData.customerInvoice.taxRegistrationNumber"
+                            :placeholder="$t('customer.enterTaxRegistrationNumber')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.registeredAddress" :label="$t('customer.registeredAddress')">
+                        <a-input v-model="formData.customerInvoice.registeredAddress"
+                            :placeholder="$t('customer.enterRegisteredAddress')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.registeredPhone" :label="$t('customer.registeredPhone')">
+                        <a-input v-model="formData.customerInvoice.registeredPhone"
+                            :placeholder="$t('customer.enterRegisteredPhone')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.bankName" :label="$t('customer.bankName')">
+                        <a-input v-model="formData.customerInvoice.bankName" :placeholder="$t('customer.enterBankName')"
+                            :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.bankAccountName" :label="$t('customer.bankAccountName')">
+                        <a-input v-model="formData.customerInvoice.bankAccountName"
+                            :placeholder="$t('customer.enterBankAccountName')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.bankAccountNumber" :label="$t('customer.bankAccountNumber')">
+                        <a-input v-model="formData.customerInvoice.bankAccountNumber"
+                            :placeholder="$t('customer.enterBankAccountNumber')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.taxIdentificationNumber"
+                        :label="$t('customer.taxIdentificationNumber')">
+                        <a-input v-model="formData.customerInvoice.taxIdentificationNumber"
+                            :placeholder="$t('customer.enterTaxIdentificationNumber')" :max-length="60"
+                            show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.invoiceRecipient" :label="$t('customer.invoiceRecipient')">
+                        <a-input v-model="formData.customerInvoice.invoiceRecipient"
+                            :placeholder="$t('customer.enterInvoiceRecipient')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.recipientPhone" :label="$t('customer.recipientPhone')">
+                        <a-input v-model="formData.customerInvoice.recipientPhone"
+                            :placeholder="$t('customer.enterRecipientPhone')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.invoiceAddress" :label="$t('customer.invoiceAddress')">
+                        <a-input v-model="formData.customerInvoice.invoiceAddress"
+                            :placeholder="$t('customer.enterInvoiceAddress')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.invoiceEmail" :label="$t('customer.invoiceEmail')">
+                        <a-input v-model="formData.customerInvoice.invoiceEmail"
+                            :placeholder="$t('customer.enterInvoiceEmail')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.businessLicenseFile"
+                        :label="$t('customer.businessLicenseFile')">
+                        <a-upload :show-file-list="false"
+                            :custom-request="(option) => handleUpload(option, 'business_license')">
+                            <template #upload-button>
+                                <a-button>{{ $t('customer.uploadFile') }}</a-button>
+                            </template>
+                        </a-upload>
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.taxRegistrationFile"
+                        :label="$t('customer.taxRegistrationFile')">
+                        <a-upload :show-file-list="false"
+                            :custom-request="(option) => handleUpload(option, 'tax_registration')">
+                            <template #upload-button>
+                                <a-button>{{ $t('customer.uploadFile') }}</a-button>
+                            </template>
+                        </a-upload>
+                    </a-form-item>
+                    <a-form-item field="customerInvoice.generalTaxpayerFile"
+                        :label="$t('customer.generalTaxpayerFile')">
+                        <a-upload :show-file-list="false"
+                            :custom-request="(option) => handleUpload(option, 'general_taxpayer')">
+                            <template #upload-button>
+                                <a-button>{{ $t('customer.uploadFile') }}</a-button>
+                            </template>
+                        </a-upload>
+                    </a-form-item>
+                </a-form>
+            </a-tab-pane>
+            <a-tab-pane key="6" :title="$t('customer.purchaseQuality')">
+                <a-form :model="formData" :label-col-props="{ span: 8 }" :wrapper-col-props="{ span: 16 }">
+                    <template v-for="(field, index) in imageUploadFields" :key="field">
+                        <a-form-item :field="field" :label="$t(`customer.${field}`)">
+                            <a-upload action="/" :file-list="formData[field] ? [formData[field]] : []"
+                                :show-file-list="false" @change="(_, file) => handleFileUpload(field, file)"
+                                @progress="(file) => handleFileProgress(field, file)">
+                                <template #upload-button>
+                                    <div :class="`arco-upload-list-item${formData[field] && formData[field].status === 'error' ? ' arco-upload-list-item-error' : ''
+                                        }`">
+                                        <div class="arco-upload-list-picture custom-upload-avatar"
+                                            v-if="formData[field] && formData[field].url">
+                                            <img :src="formData[field].url" />
+                                            <div class="arco-upload-list-picture-mask">
+                                                <icon-edit />
+                                            </div>
+                                            <a-progress
+                                                v-if="formData[field].status === 'uploading' && formData[field].percent < 100"
+                                                :percent="formData[field].percent" type="circle" size="mini" :style="{
+                                                    position: 'absolute',
+                                                    left: '50%',
+                                                    top: '50%',
+                                                    transform: 'translateX(-50%) translateY(-50%)',
+                                                }" />
+                                        </div>
+                                        <div class="arco-upload-picture-card" v-else>
+                                            <div class="arco-upload-picture-card-text">
+                                                <icon-plus />
+                                                <div style="margin-top: 10px; font-weight: 600">{{
+                                                    $t('customer.uploadFile') }}</div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </template>
+                            </a-upload>
+                            <div class="upload-description">
+                                {{ $t('customer.imageUploadDescription') }}
+                            </div>
+                        </a-form-item>
+                    </template>
+
+                    <a-form-item field="customerCardQualification.obtainMethod" :label="$t('customer.obtainMethod')">
+                        <a-upload action="/" :file-list="formData.customerCardQualification.obtainMethod"
+                            @change="handleObtainMethodUpload" multiple>
+                            <template #upload-button>
+                                <a-button>{{ $t('customer.uploadFile') }}</a-button>
+                            </template>
+                        </a-upload>
+                        <div class="upload-description">
+                            {{ $t('customer.obtainMethodDescription') }}
+                        </div>
+                    </a-form-item>
+
+                    <a-form-item field="customerCardQualification.telephoneApplicationForm"
+                        :label="$t('customer.telephoneApplicationForm')">
+                        <a-upload action="/" :file-list="formData.customerCardQualification.telephoneApplicationForm"
+                            @change="handleTelephoneApplicationFormUpload" multiple>
+                            <template #upload-button>
+                                <a-button>{{ $t('customer.uploadFile') }}</a-button>
+                            </template>
+                        </a-upload>
+                        <div class="upload-description">
+                            {{ $t('customer.telephoneApplicationFormDescription') }}
+                        </div>
+                    </a-form-item>
+
+                    <a-form-item field="customerCardQualification.otherDocuments"
+                        :label="$t('customer.otherDocuments')">
+                        <a-upload action="/" :file-list="formData.customerCardQualification.otherDocuments"
+                            @change="handleOtherDocumentsUpload" multiple>
+                            <template #upload-button>
+                                <a-button>{{ $t('customer.uploadFile') }}</a-button>
+                            </template>
+                        </a-upload>
+                        <div class="upload-description">
+                            {{ $t('customer.otherDocumentsDescription') }}
+                        </div>
+                    </a-form-item>
+                </a-form>
+            </a-tab-pane>
+            <a-tab-pane key="7" :title="$t('customer.warningNumbers')">
+                <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
+                    <a-form-item field="customerWarningParameter.accountBalanceWarning"
+                        :label="$t('customer.accountBalanceWarning')">
+                        <a-input-number v-model="formData.customerWarningParameter.accountBalanceWarning" :min="0"
+                            :precision="2" :step="100" :style="{ width: '100%' }" />
+                    </a-form-item>
+                    <a-form-item field="customerWarningParameter.reachWarning" :label="$t('customer.reachWarning')">
+                        <a-input-number v-model="formData.customerWarningParameter.reachWarning" :min="0" :max="100"
+                            :precision="0" :step="1" :style="{ width: '100%' }">
+                            <template #append>%</template>
+                        </a-input-number>
+                    </a-form-item>
+                    <a-form-item field="customerWarningParameter.stopSending" :label="$t('customer.stopSending')">
+                        <a-space>
+                            <a-input-number v-model="formData.customerWarningParameter.stopSending" :min="0" :max="100"
+                                :precision="0" :step="1" :style="{ width: '100px' }">
+                                <template #append>%</template>
+                            </a-input-number>
+                            <a-radio-group v-model="formData.customerWarningParameter.stopSendingAction">
+                                <a-radio value="noRecovery">{{ $t('customer.noRecovery') }}</a-radio>
+                                <a-radio value="manualRecovery">{{ $t('customer.manualRecovery') }}</a-radio>
+                                <a-radio value="autoRecovery">{{ $t('customer.autoRecovery') }}</a-radio>
+                            </a-radio-group>
+                        </a-space>
+                    </a-form-item>
+                    <a-form-item field="customerWarningParameter.networkDisconnection"
+                        :label="$t('customer.networkDisconnection')">
+                        <a-space>
+                            <a-input-number v-model="formData.customerWarningParameter.networkDisconnection" :min="0"
+                                :max="100" :precision="0" :step="1" :style="{ width: '100px' }">
+                                <template #append>%</template>
+                            </a-input-number>
+                            <a-radio-group v-model="formData.customerWarningParameter.networkDisconnectionAction">
+                                <a-radio value="noRecovery">{{ $t('customer.noRecovery') }}</a-radio>
+                                <a-radio value="manualRecovery">{{ $t('customer.manualRecovery') }}</a-radio>
+                                <a-radio value="autoRecovery">{{ $t('customer.autoRecovery') }}</a-radio>
+                            </a-radio-group>
+                        </a-space>
+                    </a-form-item>
+                    <a-form-item field="customerWarningParameter.warningPhones" :label="$t('customer.warningPhones')">
+                        <a-input v-model="formData.customerWarningParameter.warningPhones"
+                            :placeholder="$t('customer.enterWarningPhones')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                    <a-form-item field="customerWarningParameter.warningEmails" :label="$t('customer.warningEmails')">
+                        <a-input v-model="formData.customerWarningParameter.warningEmails"
+                            :placeholder="$t('customer.enterWarningEmails')" :max-length="60" show-word-limit />
+                    </a-form-item>
+                </a-form>
+            </a-tab-pane>
+        </a-tabs>
+    </a-modal>
+</template>
+
+<script setup>
+import { ref, reactive, watch } from 'vue';
+import { Message } from '@arco-design/web-vue';
+import { useI18n } from 'vue-i18n';
+import { IconEdit, IconPlus } from '@arco-design/web-vue/es/icon';
+import dayjs from 'dayjs';
+import { useSystemStore } from '@/store/modules/systemStore'
+
+const { t } = useI18n();
+const systemStore = useSystemStore()
+
+const props = defineProps({
+    visible: Boolean,
+    editMode: Boolean,
+    editData: Object,
+    loading: Boolean,
+});
+
+watch(
+    () => props.editData,
+    (newVal) => {
+        if (newVal && props.editMode) {
+            // 深拷贝编辑数据
+            const editDataCopy = JSON.parse(JSON.stringify(newVal));
+
+            // 处理日期格式
+            if (editDataCopy.customerInfo?.exTime) {
+                editDataCopy.customerInfo.exTime = dayjs(editDataCopy.customerInfo.exTime).format('YYYY-MM-DD');
+            }
+
+            // 使用 Object.assign 更新每个子对象
+            Object.keys(formData).forEach(key => {
+                if (editDataCopy[key]) {
+                    Object.assign(formData[key], editDataCopy[key]);
+                }
+            });
+        }
+    },
+    { deep: true, immediate: true }
+);
+
+const emit = defineEmits(['update:visible', 'submit']);
+
+const formRef = ref(null);
+const formData = reactive({
+    userInfo: {
+        username: '',
+        password: '',
+        state: '1',
+        name: '',
+        id: null
+    },
+    customerInfo: {
+        customerCode: '',
+        name: '',
+        platformName: '',
+        companyName: '',
+        servicePhone: '',
+        phone: '',
+        email: '',
+        domain: '',
+        smsName: '',
+        exTime: null,
+        remark: '',
+        homepageLicenseCode: '',
+        companyAddress: '',
+        contactName: '',
+        qq: '',
+        deliveryAddress: '',
+        deliveryPhone: '',
+        deliveryName: '',
+        smsSubCode: '',
+    },
+    customerProperty: {
+        amount: 0,
+        rechargeLimit: 0,
+        lineOfCredit: 0,
+        smsUnitPrice: 0,
+        iotSmsUnitPrice: 0,
+        paymentMethod: 'prepaid',
+    },
+    customerInvoice: {
+        invoiceTitle: '',
+        taxRegistrationNumber: '',
+        registeredAddress: '',
+        registeredPhone: '',
+        bankName: '',
+        bankAccountName: '',
+        bankAccountNumber: '',
+        taxIdentificationNumber: '',
+        invoiceRecipient: '',
+        recipientPhone: '',
+        invoiceAddress: '',
+        invoiceEmail: '',
+        businessLicenseNumber: '',
+        taxRegistrationFile: '',
+        businessLicenseFile: '',
+        generalTaxpayerFile: '',
+    },
+    customerCardQualification: {
+        blImg: null,
+        legalPersonIdCardImgUp: null,
+        legalPersonIdCardImgDown: null,
+        iotImg: null,
+        contractImg: null,
+        commitmentImg: null,
+        customerForm: null,
+        getCustomerText: '',
+        phoneForm: null,
+        otherFile: null,
+    },
+    customerWarningParameter: {
+        accountBalanceWarning: 0,
+        reachWarning: 0,
+        stopSending: 0,
+        stopSendingAction: 'noRecovery',
+        networkDisconnection: 0,
+        networkDisconnectionAction: 'noRecovery',
+        warningPhones: '',
+        warningEmails: '',
+    },
+    customerInterfaceParams: {
+        smsStatusReportUrl: '',
+        reportIp: '',
+        deliveryPriority: '',
+        dataReportUrl: '',
+    },
+});
+
+const rules = {
+    'userInfo.username': [{ required: true, message: t('customer.accountNumberRequired') }],
+    'userInfo.password': [{ required: true, message: t('customer.passwordRequired') }],
+    'customerInfo.customerCode': [{ required: true, message: t('customer.customerCodeRequired') }],
+    'customerInfo.name': [{ required: true, message: t('customer.customerNameRequired') }],
+    'customerInfo.exTime': [{ required: true, message: t('customer.validPeriodRequired') }],
+    'userInfo.state': [{ required: true, message: t('customer.statusRequired') }],
+    'customerInfo.platformName': [{ required: true, message: t('customer.platformNameRequired') }],
+    'customerInfo.servicePhone': [{ required: true, message: t('customer.servicePhoneRequired') }],
+};
+
+const handleSubmit = () => {
+    formRef.value.validate((errors) => {
+        if (!errors) {
+            // 处理文件字段
+            const processedInvoice = {
+                ...formData.customerInvoice,
+                // 将数组转换为字符串或null
+                taxRegistrationFile: formData.customerInvoice.taxRegistrationFile?.length ?
+                    formData.customerInvoice.taxRegistrationFile[0]?.url || null : null,
+                businessLicenseFile: formData.customerInvoice.businessLicenseFile?.length ?
+                    formData.customerInvoice.businessLicenseFile[0]?.url || null : null,
+                generalTaxpayerFile: formData.customerInvoice.generalTaxpayerFile?.length ?
+                    formData.customerInvoice.generalTaxpayerFile[0]?.url || null : null,
+            };
+            const submitData = {
+                userInfo: {
+                    ...formData.userInfo,
+                    // 设置userInfo.name为customerInfo.name
+                    name: formData.customerInfo.name,
+                    id: props.editMode ? props.editData.userInfo.id : undefined,
+                },
+
+                customerInfo: {
+                    ...formData.customerInfo,
+                    exTime: formData.customerInfo.exTime ?
+                        dayjs(formData.customerInfo.exTime).format('YYYY-MM-DD') :
+                        null
+                },
+                customerProperty: formData.customerProperty,
+                customerInvoice: processedInvoice,
+                customerCardQualification: formData.customerCardQualification,
+                customerWarningParameter: formData.customerWarningParameter,
+                customerInterfaceParams: formData.customerInterfaceParams,
+            };
+
+            emit('submit', submitData);
+            emit('update:visible', false);
+        }
+    });
+};
+
+const handleCancel = () => {
+    emit('update:visible', false);
+};
+
+const handleUpload = async (option, directory) => {
+    const { file } = option.fileItem;
+    const timestamp = Date.now(); // Get the current timestamp
+    const fileName = `${directory}/${timestamp}_${file.name}`;
+    const key = `customer_uploads/${fileName}`; // Base directory for customer uploads
+
+    const client = await systemStore.getSTSClient();
+    const resClient = await client.putObject({
+        key: key,
+        body: file
+    });
+
+    if (resClient.statusCode === 200) {
+        console.log('File uploaded successfully to', key);
+        formData.customerInvoice[directory + 'File'] = { url: key, name: file.name };
+    }
+};
+
+const generatePassword = () => {
+    formData.userInfo.password = Math.random().toString(36).slice(-8);
+    Message.success(t('customer.passwordGenerated'));
+};
+
+// 文件上传的处理函数
+const handleBusinessLicenseUpload = (fileList) => {
+    formData.customerInvoice.businessLicenseFile = fileList;
+};
+
+const handleTaxRegistrationUpload = (fileList) => {
+    formData.customerInvoice.taxRegistrationFile = fileList;
+};
+
+const handleGeneralTaxpayerUpload = (fileList) => {
+    formData.customerInvoice.generalTaxpayerFile = fileList;
+};
+
+// 文件上传的 action,需要根据实际的后端 API 进行设置
+const uploadAction = 'url';
+
+const imageUploadFields = [
+    'customerInvoice.businessLicenseFile',
+    'customerCardQualification.legalPersonIdCardFrontFile',
+    'customerCardQualification.legalPersonIdCardBackFile',
+    'customerCardQualification.equipmentPurchaseFile',
+    'customerCardQualification.businessContractFile',
+    'customerCardQualification.informationSecurityFile',
+    'customerCardQualification.customerInformationFile',
+];
+
+const handleFileUpload = (field, file) => {
+    formData.customerCardQualification[field] = {
+        ...file,
+        url: URL.createObjectURL(file.file),
+    };
+};
+
+const handleFileProgress = (field, file) => {
+    formData.customerCardQualification[field] = file;
+};
+
+const handleObtainMethodUpload = (fileList) => {
+    formData.customerCardQualification.obtainMethod = fileList;
+};
+
+const handleTelephoneApplicationFormUpload = (fileList) => {
+    formData.customerCardQualification.telephoneApplicationForm = fileList;
+};
+
+const handleOtherDocumentsUpload = (fileList) => {
+    formData.customerCardQualification.otherDocuments = fileList;
+};
+
+
+</script>
+
+<style scoped>
+.upload-description {
+    font-size: 12px;
+    color: #999;
+    margin-top: 4px;
+}
+</style>

+ 316 - 0
src/views/customer/index.vue

@@ -0,0 +1,316 @@
+<!-- 客户管理-用户管理 -->
+<template>
+    <div class="customer-management">
+        <!-- 搜索条件区 -->
+        <div class="search-section">
+            <a-form :model="searchForm" layout="inline">
+                <a-form-item field="customerName" :label="$t('customer.customerName')">
+                    <a-input v-model="searchForm.customerName" :placeholder="$t('customer.enterCustomerName')"
+                        allow-clear />
+                </a-form-item>
+                <a-form-item field="operatorType" :label="$t('customer.operatorType')">
+                    <a-select v-model="searchForm.operatorType" :placeholder="$t('customer.selectOperatorType')"
+                        allow-clear style="width: 160px">
+                        <a-option v-for="op in operatorTypeOptions" :key="op.value" :value="op.value">
+                            {{ $t(`customer.operatorTypes.${op.value}`) }}
+                        </a-option>
+                    </a-select>
+                </a-form-item>
+                <a-form-item>
+                    <a-button type="primary" @click="handleSearch">{{ $t('global.common.search') }}</a-button>
+                </a-form-item>
+                <a-form-item>
+                    <a-button @click="resetSearch">{{ $t('global.common.reset') }}</a-button>
+                </a-form-item>
+            </a-form>
+        </div>
+
+        <!-- 顶部操作区 -->
+        <div class="top-actions">
+            <a-space>
+                <a-button type="primary" @click="showNewCustomerForm">{{ $t('customer.addCustomer') }}</a-button>
+                <a-button @click="handleBatchDelete">{{ $t('customer.batchDelete') }}</a-button>
+            </a-space>
+        </div>
+
+        <!-- 数据表格 -->
+        <a-table row-key="id" :columns="columns" :data="tableData" :pagination="pagination"
+            :scroll="{ x: '100%', y: '650px' }" :row-selection="{ type: 'checkbox', showCheckedAll: true }"
+            @page-change="onPageChange">
+            <template #state="{ record }">
+                <a-tag :color="getStatusColor(record.state)">
+                    {{ $t(`customer.status.${getStatusText(record.state)}`) }}
+                </a-tag>
+            </template>
+            <template #operation="{ record }">
+                <a-space>
+                    <a-button type="text" size="small" @click="handleRecharge(record)">{{ $t('customer.recharge')
+                        }}</a-button>
+                    <a-button type="text" size="small" @click="handlePackageManagement(record)">{{
+                        $t('customer.packageManagement') }}</a-button>
+                    <a-button type="text" size="small" @click="handleEdit(record)">{{ $t('global.common.edit')
+                        }}</a-button>
+                </a-space>
+            </template>
+        </a-table>
+
+        <!-- 新客户表单对话框 -->
+        <new-customer-form v-model:visible="newCustomerFormVisible" :editMode="editMode" :editData="editData"
+            :loading="loading" @submit="handleNewCustomerSubmit" />
+    </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted } from 'vue';
+import { Message } from '@arco-design/web-vue';
+import { useI18n } from 'vue-i18n';
+import NewCustomerForm from './NewCustomerForm.vue';
+import { getCustomerList, addCustomer, getCustomer, updateCustomer } from '@/api/customer';
+
+const { t } = useI18n();
+
+const loading = ref(false);
+
+const columns = computed(() => [
+    { title: t('customer.id'), dataIndex: 'id' },
+    { title: t('customer.customerCode'), dataIndex: 'customerCode' },
+    { title: t('customer.customerName'), dataIndex: 'customerName' },
+    { title: t('customer.accountNumber'), dataIndex: 'accountNumber' },
+    { title: t('customer.accountBalance'), dataIndex: 'accountBalance' },
+    { title: t('customer.paymentMethodName'), dataIndex: 'paymentMethod' },
+    { title: t('customer.customerStatus'), slotName: 'state' },
+    { title: t('customer.validPeriod'), dataIndex: 'validPeriod' },
+    { title: t('customer.activeCards'), dataIndex: 'activeCards' },
+    { title: t('customer.updateTime'), dataIndex: 'updateTime' },
+    { title: t('global.common.operations'), slotName: 'operation', width: 250 },
+]);
+
+onMounted(() => {
+    fetchCustomerList();
+});
+
+const tableData = ref([]);
+
+// const pagination = reactive({
+//   // total: 100,
+//   current: 1,
+//   pageSize: 10,
+// });
+const pagination = { pageSize: 10 }
+const fetchCustomerList = async () => {
+    try {
+        const response = await getCustomerList({
+            current: pagination.current,
+            pageSize: pagination.pageSize,
+            customerName: searchForm.customerName,
+            operatorType: searchForm.operatorType,
+        });
+        if (response.code === 200 && response.data) {
+            tableData.value = response.data.records;
+            pagination.total = response.data.total;
+            pagination.current = response.data.current;
+            pagination.pageSize = response.data.size;
+        } else {
+            Message.error(response.message || 'Failed to fetch customer list');
+        }
+    } catch (error) {
+        Message.error('Failed to fetch customer list');
+        console.error(error);
+    }
+};
+
+const onPageChange = (page) => {
+    pagination.current = page;
+    fetchCustomerList();
+};
+
+const newCustomerFormVisible = ref(false);
+const editMode = ref(false);
+const editData = ref(null);
+
+const searchForm = reactive({
+    customerName: '',
+    operatorType: '',
+});
+
+const operatorTypeOptions = [
+    { value: 'domestic', label: t('customer.operatorTypes.domestic') },
+    { value: 'international', label: t('customer.operatorTypes.international') },
+];
+
+const showNewCustomerForm = () => {
+    editMode.value = false;
+    editData.value = null;
+    newCustomerFormVisible.value = true;
+};
+
+const handleEdit = async (record) => {
+    try {
+        loading.value = true;
+        const response = await getCustomer({ id: record.id });
+        if (response.code === 200) {
+            // 处理返回的数据,确保数据结构匹配表单
+            const formattedData = {
+                userInfo: {
+                    ...response.data.userInfo,
+                    password: '', // 清空密码字段
+                    passwordState: true // 添加密码状态控制
+                },
+                customerInfo: {
+                    ...response.data.customerInfo,
+                    // 确保日期格式正确
+                    exTime: response.data.customerInfo.exTime ? new Date(response.data.customerInfo.exTime) : null
+                },
+                customerProperty: {
+                    ...response.data.customerProperty,
+                    // 确保数值类型正确
+                    amount: Number(response.data.customerProperty?.amount || 0),
+                    rechargeLimit: Number(response.data.customerProperty?.rechargeLimit || 0),
+                    lineOfCredit: Number(response.data.customerProperty?.lineOfCredit || 0),
+                    smsUnitPrice: Number(response.data.customerProperty?.smsUnitPrice || 0),
+                    iotSmsUnitPrice: Number(response.data.customerProperty?.iotSmsUnitPrice || 0),
+                    paymentMethod: response.data.customerProperty?.paymentMethod || 'prepaid'
+                },
+                customerInvoice: {
+                    ...response.data.customerInvoice,
+                    // 处理文件列表
+                    businessLicenseFile: response.data.customerInvoice?.businessLicenseFile ? [response.data.customerInvoice.businessLicenseFile] : [],
+                    taxRegistrationFile: response.data.customerInvoice?.taxRegistrationFile ? [response.data.customerInvoice.taxRegistrationFile] : [],
+                    generalTaxpayerFile: response.data.customerInvoice?.generalTaxpayerFile ? [response.data.customerInvoice.generalTaxpayerFile] : []
+                },
+                customerCardQualification: {
+                    ...response.data.customerCardQualification,
+                    // 处理图片和文件字段
+                    blImg: response.data.customerCardQualification?.blImg || null,
+                    legalPersonIdCardImgUp: response.data.customerCardQualification?.legalPersonIdCardImgUp || null,
+                    legalPersonIdCardImgDown: response.data.customerCardQualification?.legalPersonIdCardImgDown || null,
+                    iotImg: response.data.customerCardQualification?.iotImg || null,
+                    contractImg: response.data.customerCardQualification?.contractImg || null,
+                    commitmentImg: response.data.customerCardQualification?.commitmentImg || null,
+                    customerForm: response.data.customerCardQualification?.customerForm || null,
+                    phoneForm: response.data.customerCardQualification?.phoneForm || null,
+                    otherFile: response.data.customerCardQualification?.otherFile || null
+                },
+                customerWarningParameter: {
+                    ...response.data.customerWarningParameter,
+                    // 确保数值类型正确
+                    accountBalanceWarning: Number(response.data.customerWarningParameter?.accountBalanceWarning || 0),
+                    reachWarning: Number(response.data.customerWarningParameter?.reachWarning || 0),
+                    stopSending: Number(response.data.customerWarningParameter?.stopSending || 0),
+                    networkDisconnection: Number(response.data.customerWarningParameter?.networkDisconnection || 0),
+                    // 设置默认值
+                    stopSendingAction: response.data.customerWarningParameter?.stopSendingAction || 'noRecovery',
+                    networkDisconnectionAction: response.data.customerWarningParameter?.networkDisconnectionAction || 'noRecovery'
+                },
+                customerInterfaceParams: {
+                    ...(response.data.customerInterfaceParams || {}),
+                    // 设置默认值
+                    smsStatusReportUrl: response.data.customerInterfaceParams?.smsStatusReportUrl || '',
+                    reportIp: response.data.customerInterfaceParams?.reportIp || '',
+                    deliveryPriority: response.data.customerInterfaceParams?.deliveryPriority || '',
+                    dataReportUrl: response.data.customerInterfaceParams?.dataReportUrl || ''
+                }
+            };
+
+            editMode.value = true;
+            editData.value = formattedData;
+            newCustomerFormVisible.value = true;
+        } else {
+            Message.error(response.message || t('customer.fetchFailed'));
+        }
+    } catch (error) {
+        console.error('获取客户详情时发生错误:', error);
+        Message.error(t('customer.fetchError'));
+    } finally {
+        loading.value = false;
+    }
+};
+
+const handleRecharge = (record) => {
+    Message.success(`为客户 ${record.customerName} 充值`);
+};
+
+const handlePackageManagement = (record) => {
+    Message.success(`管理客户 ${record.customerName} 的套餐`);
+};
+
+const handleNewCustomerSubmit = async (formData) => {
+    try {
+        loading.value = true;
+        let response;
+        if (editMode.value) {
+            response = await updateCustomer(formData);
+        } else {
+            response = await addCustomer(formData);
+        }
+
+        if (response.code === 200) {
+            Message.success(editMode.value ? t('customer.updateSuccess') : t('customer.addSuccess'));
+            newCustomerFormVisible.value = false;
+            fetchCustomerList();
+        } else {
+            Message.error(response.message || (editMode.value ? t('customer.updateFailed') : t('customer.addFailed')));
+        }
+    } catch (error) {
+        console.error(editMode.value ? '更新客户时发生错误:' : '添加客户时发生错误:', error);
+        Message.error(editMode.value ? t('customer.updateError') : t('customer.addError'));
+    } finally {
+        loading.value = false;
+    }
+};
+
+const handleSearch = () => {
+    pagination.current = 1;
+    fetchCustomerList();
+};
+
+const resetSearch = () => {
+    Object.keys(searchForm).forEach(key => {
+        searchForm[key] = '';
+    });
+    pagination.current = 1;
+    fetchCustomerList();
+};
+
+const handleBatchDelete = () => {
+    Message.warning(t('customer.batchDeleteWarning'));
+};
+
+const getStatusColor = (state) => {
+    const stateColors = {
+        '1': 'green',    // 正常 - 绿色
+        '2': 'red',      // 禁用 - 红色
+        '3': 'orange',   // 待审 - 橙色
+        '4': 'gray'      // 暂停 - 灰色
+    };
+    return stateColors[state] || 'default';
+};
+
+const getStatusText = (state) => {
+    const stateTexts = {
+        '1': 'normal',     // 正常
+        '2': 'disabled',   // 禁用
+        '3': 'pending',    // 待审
+        '4': 'suspended'   // 暂停
+    };
+    return stateTexts[state] || 'undefined';
+};
+</script>
+
+<style scoped>
+.customer-management {
+    padding: 20px;
+}
+
+.top-actions {
+    margin-bottom: 20px;
+}
+
+.search-section {
+    margin-bottom: 20px;
+}
+
+.customer-management .arco-table-th {
+    white-space: nowrap;
+}
+</style>

+ 463 - 0
src/views/financialManagement/accountBalance/index.vue

@@ -0,0 +1,463 @@
+<!-- 账户余额-总览界面 -->
+<template>
+    <div class="customer-top-up">
+        <div class="item-box">
+            <div class="item-title">总览</div>
+            <div class="item-grid-box">
+                <div class="grid-item" v-for="item in 5" :key="item">
+                    <div class="grid-item-title">客户消费总金额/人名币</div>
+                    <div class="grid-item-num">
+                        <div class="item-num">48000</div>
+                        <div class="item-dw">元</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="item-box">
+            <div class="item-title">账单明细</div>
+            <!-- 搜索条件区 -->
+            <div class="search-section">
+                <a-form :model="searchForm" layout="inline">
+                    <a-form-item field="startTime" label="开始时间">
+                        <a-date-picker style="width: 220px; margin: 0 24px 24px 0;" show-time
+                            v-model="searchForm.startTime" :time-picker-props="{ defaultValue: '09:09:06' }"
+                            format="YYYY-MM-DD HH:mm:ss" @ok="onOkStart" />
+                    </a-form-item>
+                    <a-form-item field="endTime" label="结束时间">
+                        <a-date-picker style="width: 220px; margin: 0 24px 24px 0;" show-time
+                            v-model="searchForm.endTime" :time-picker-props="{ defaultValue: '09:09:06' }"
+                            format="YYYY-MM-DD HH:mm:ss" @ok="onOkEnd" />
+                    </a-form-item>
+                    <a-form-item>
+                        <a-space>
+                            <a-button type="primary" @click="handleSearch">搜索</a-button>
+                            <a-button @click="resetSearch">重置</a-button>
+                        </a-space>
+                    </a-form-item>
+                </a-form>
+            </div>
+            <div class="audit-btn">
+                <a-button @click="openTopsUp" type="text">
+                    <template #icon>
+                        <icon-plus-circle />
+                    </template>
+                    <template #default>充值</template>
+                </a-button>
+            </div>
+            <!-- 数据表格 -->
+            <a-table row-key="customerName" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection"
+                :columns="columns" :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '400px' }">
+                <template #detail="{ record }">
+                    <a-button @click="openDetail(record)" type="text">查看</a-button>
+                    <a-button @click="openTopsUp(record)" type="text">结算</a-button>
+                </template>
+                <template #status="{ record }">
+                    <div v-if="record.status == 1" class="status-table" style="color:rgba(43, 164, 113, 1);">
+                        <div class="status-icon" style="background-color: rgba(43, 164, 113, 1);"></div>
+                        已出账
+                    </div>
+                    <div v-if="record.status == 2" class="status-table">
+                        <div class="status-icon"></div>
+                        欠费中
+                    </div>
+                </template>
+            </a-table>
+        </div>
+        <a-modal v-model:visible="showAdd" title="结算" @cancel="showAdd = false" @before-ok="submitAdd" okText="确定"
+            width="800px" cancelText="关闭">
+            <a-form :model="formAdd" auto-label-width>
+                <a-form-item field="customerName" label="客户名称">
+                    <!-- <a-input v-model="formAdd.customerName" placeholder="请输入客户" /> -->
+                    泰国栗
+                </a-form-item>
+                <a-form-item field="money" label="当前帐单应收金额">
+                    <!-- <a-input-number v-model="formAdd.money" placeholder="请输入金额" class="input-demo" :min="10"
+                        :max="100" /> -->
+                    1242113.00元
+                </a-form-item>
+                <a-form-item field="topsUpOpinion" label="结算金额">
+                    <!-- <a-textarea placeholder="请输入" v-model="formAdd.topsUpOpinion" allow-clear /> -->
+                    123111.00元
+                </a-form-item>
+                <a-form-item field="fileList" label="打款凭证">
+                    <a-upload action="/" :default-file-list="formAdd.fileList" style="width: auto;max-width: 400px;" />
+                    <div class="text-box">
+                        <div class="text">
+                            1.请上传客户银行转账等同等性质的支付凭证文件
+                        </div>
+                        <div class="text">
+                            2.图片仅支持jpg或png格式
+                        </div>
+                        <div class="text">
+                            3.图片不得大于2M
+                        </div>
+                    </div>
+                </a-form-item>
+            </a-form>
+        </a-modal>
+        <a-modal v-model:visible="showDetail" width="1000px" title="订单详情" :hide-cancel="true" @cancel="detailCancel">
+            <div class="detail">
+                <div class="detail-box">
+                    <div class="detail-title">账单信息(泰国李总)</div>
+                    <div class="detail-item-box">
+                        <div class="detail-item">
+                            <div class="item-label">订单状态</div>
+                            <div class="item-content" style="color:rgba(253, 63, 90, 1);">欠款中</div>
+                        </div>
+                        <div class="detail-item">
+                            <div class="item-label">账单单号</div>
+                            <div class="item-content">1223423422435343</div>
+                        </div>
+                    </div>
+                    <div class="detail-item-box">
+                        <div class="detail-item">
+                            <div class="item-label">订单结算周期</div>
+                            <div class="item-content">2024-10-24~2025-10-23</div>
+                        </div>
+                        <div class="detail-item">
+                            <div class="item-label">出账日期</div>
+                            <div class="item-content">2024-10-24</div>
+                        </div>
+                    </div>
+                    <div class="detail-item-box">
+                        <div class="detail-item">
+                            <div class="item-label">结算时间</div>
+                            <div class="item-content">2024-10-24</div>
+                        </div>
+                        <div class="detail-item">
+                            <div class="item-label">账单结算金额</div>
+                            <div class="item-content">103849美金</div>
+                        </div>
+                    </div>
+                    <div class="detail-title">结算详情</div>
+                    <div class="js-detail" v-for="item in 4" :key="item">
+                        <div class="detail-item-box">
+                            <div class="detail-item">
+                                <div class="item-label">运营商</div>
+                                <div class="item-content" style="color:rgba(43, 164, 113, 1);">泰国AIS</div>
+                            </div>
+                        </div>
+                        <div class="detail-item-box">
+                            <div class="detail-item">
+                                <div class="item-label">套餐流量消耗</div>
+                                <div class="item-content">7129.76G</div>
+                            </div>
+                            <div class="detail-item">
+                                <div class="item-label">套餐流量计费方式</div>
+                                <div class="item-content">按单流量消耗计费</div>
+                            </div>
+                        </div>
+                        <div class="detail-item-box">
+                            <div class="detail-item">
+                                <div class="item-label">套餐流量价格</div>
+                                <div class="item-content">0.65美金/G</div>
+                            </div>
+                            <div class="detail-item">
+                                <div class="item-label">结算周期</div>
+                                <div class="item-content">月</div>
+                            </div>
+                        </div>
+                        <div class="detail-item-box">
+                            <div class="detail-item">
+                                <div class="item-label">叠加流量消耗</div>
+                                <div class="item-content">11244G</div>
+                            </div>
+                            <div class="detail-item">
+                                <div class="item-label">叠加流量计费方式</div>
+                                <div class="item-content">按周期计算</div>
+                            </div>
+                        </div>
+                        <div class="detail-item-box">
+                            <div class="detail-item">
+                                <div class="item-label">叠加流量价格</div>
+                                <div class="item-content">0.8美金/月</div>
+                            </div>
+                            <div class="detail-item">
+                                <div class="item-label">结算周期</div>
+                                <div class="item-content">月</div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="detail-table">
+                    <a-table :columns="columnsDetail" :data="dataDetail" />
+                </div>
+            </div>
+        </a-modal>
+    </div>
+</template>
+<script setup>
+import { ref, reactive } from 'vue';
+import { Message } from '@arco-design/web-vue';
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const searchForm = reactive({
+    startTime: '',
+    endTime: ''
+});
+
+const columns = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+    {
+        title: '账单号', dataIndex: 'accountNumber', ellipsis: true,
+        tooltip: true,
+        width: 100
+    },
+    { title: '客户名称', dataIndex: 'customerName' },
+    { title: '结算金额(元)', dataIndex: 'money' },
+    { title: '消耗流量', dataIndex: 'deplete' },
+    { title: '账单生成时间', dataIndex: 'createTime' },
+    { title: '结算周期时间段', dataIndex: 'createTime' },
+    { title: '状态', slotName: 'status' },
+    { title: '详情', slotName: 'detail', align: 'center' },
+];
+const tableData = ref([
+    {
+        accountNumber: '13800138000',
+        customerName: '张三',
+        status: '1',
+        customerAccountNumber: 'jhl001',
+        money: '100美金',
+        deplete: '100G',
+        createTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        accountNumber: '13800138000',
+        customerName: '李四',
+        status: '2',
+        customerAccountNumber: 'jhl001',
+        money: '100美金',
+        deplete: '100G',
+        createTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        accountNumber: '13800138000',
+        customerName: '王五',
+        status: '2',
+        customerAccountNumber: 'jhl001',
+        money: '100美金',
+        deplete: '100G',
+        createTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        accountNumber: '13800138000',
+        customerName: '赵六',
+        status: '1',
+        customerAccountNumber: 'jhl001',
+        money: '100美金',
+        deplete: '100G',
+        createTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+
+]);
+const pagination = reactive({
+    total: tableData.value.length,
+    current: 1,
+    pageSize: 10,
+});
+const handleSearch = () => {
+    console.log('Search form data:', searchForm);
+    Message.success('执行搜索操作');
+};
+
+const resetSearch = () => {
+    Object.keys(searchForm).forEach(key => {
+        if (Array.isArray(searchForm[key])) {
+            searchForm[key] = [];
+        } else {
+            searchForm[key] = null;
+        }
+    });
+    Message.success('搜索条件已重置');
+};
+const options = [
+    { label: '充值', value: '1' },
+    { label: '抵充', value: '2' },
+    { label: '消费扣除', value: '3' },
+];
+const openTopsUp = () => {
+    showAdd.value = true;
+}
+const showAdd = ref(false);
+const formAdd = reactive({
+    customerName: '',
+    cardType: '',
+    money: '',
+    status: '',
+    topsUpOpinion: '',
+    fileList: []
+})
+const submitAdd = () => {
+    window.setTimeout(() => {
+        showAdd.value = false;
+    }, 1000)
+}
+// 选择时间
+const onOkStart = () => {
+    console.log(searchForm.startTime, '开始时间')
+};
+const onOkEnd = () => {
+    console.log(searchForm.endTime, '结束时间')
+};
+const showDetail = ref(false);
+const openDetail = () => {
+    showDetail.value = true;
+}
+const detailCancel = () => {
+}
+</script>
+<style scoped lang="less">
+.customer-top-up {
+    .search-section {
+        margin-bottom: 20px;
+    }
+
+    .audit-btn {
+        margin-bottom: 10px;
+    }
+}
+
+.text-box {
+    width: 100%;
+    margin-left: 10px;
+
+    .text {
+        font-family: PingFang SC;
+        font-size: 12px;
+        font-weight: 400;
+        line-height: 19px;
+        color: rgba(153, 153, 153, 1);
+        text-align: left;
+    }
+}
+
+.item-box {
+    margin-bottom: 20px;
+
+    .item-title {
+        font-family: PingFang SC;
+        font-size: 20px;
+        font-weight: 400;
+        line-height: 28px;
+        color: rgba(0, 0, 0, 0.9);
+        margin-bottom: 10px;
+    }
+
+    .item-grid-box {
+        display: grid;
+        grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
+        grid-gap: 20px;
+
+        .grid-item {
+            background: rgba(247, 247, 247, 1);
+            padding: 20px;
+            box-sizing: border-box;
+            border-radius: 6px;
+            box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.1);
+
+            .grid-item-title {
+                font-family: PingFang SC;
+                font-size: 14px;
+                font-weight: 400;
+                line-height: 22px;
+                text-align: left;
+                color: rgba(0, 0, 0, 0.6);
+            }
+
+            .grid-item-num {
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                font-family: PingFang SC;
+                font-size: 28px;
+                font-weight: 400;
+                line-height: 36px;
+                color: rgba(0, 0, 0, 0.9);
+
+                .item-num {}
+
+                .item-dw {}
+            }
+        }
+    }
+}
+
+.status-table {
+    display: flex;
+    align-items: center;
+    //styleName: Body/Medium;
+    font-family: PingFang SC;
+    font-size: 14px;
+    font-weight: 400;
+    line-height: 22px;
+    text-align: left;
+    color: rgba(253, 63, 90, 1);
+
+    .status-icon {
+        width: 6px;
+        height: 6px;
+        border-radius: 50%;
+        margin-right: 5px;
+        background: rgba(253, 63, 90, 1);
+    }
+}
+
+.detail {
+    height: 600px;
+    overflow-y: auto;
+
+    .detail-box {
+        .detail-title {
+            font-family: PingFang SC;
+            font-size: 20px;
+            font-weight: 400;
+            line-height: 28px;
+            text-align: left;
+            color: rgba(0, 0, 0, 0.9);
+            margin-bottom: 20px;
+        }
+
+        .detail-item-box {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 20px;
+
+            .detail-item {
+                //styleName: Body/Medium;
+                font-family: PingFang SC;
+                font-size: 14px;
+                font-weight: 400;
+                line-height: 22px;
+                text-align: left;
+                display: flex;
+                align-items: center;
+                min-width: 350px;
+
+                .item-label {
+                    color: rgba(0, 0, 0, 0.4);
+                    width: 120px;
+                    text-align: right;
+                    margin-right: 10px;
+                }
+
+                .item-content {
+                    color: rgba(51, 51, 51, 1);
+                }
+            }
+        }
+    }
+
+    .detail-table {
+        margin-top: 20px;
+    }
+}
+</style>

+ 226 - 0
src/views/financialManagement/trafficDetails/index.vue

@@ -0,0 +1,226 @@
+<!-- 流量明细 客户充值界面 -->
+<template>
+    <div class="customer-top-up">
+        <!-- 搜索条件区 -->
+        <div class="search-section">
+            <a-form :model="searchForm" layout="inline">
+                <a-form-item field="ICCID" label="ICCID">
+                    <a-input v-model="searchForm.ICCID" placeholder="请输入ICCID" allow-clear />
+                </a-form-item>
+                <a-form-item field="exportTime" label="卡导入时间">
+                    <a-range-picker v-model="searchForm.exportTime" style="width: 254px; marginBottom: 20px;" />
+                </a-form-item>
+                <a-form-item>
+                    <a-space>
+                        <a-button type="primary" @click="handleSearch">搜索</a-button>
+                        <a-button @click="resetSearch">重置</a-button>
+                    </a-space>
+                </a-form-item>
+            </a-form>
+        </div>
+        <!-- 数据表格 -->
+        <a-table row-key="customerName" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection"
+            :columns="columns" :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '400px' }">
+            <template #detail="{ record }">
+                <a-button @click="openDetail(record)" type="text">查看</a-button>
+            </template>
+        </a-table>
+        <a-modal v-model:visible="showDetail" title="流量消耗明细" @cancel="showDetail = false" @before-ok="submitDetail"
+            okText="确定" width="1000px" cancelText="关闭">
+            <a-table row-key="ICCID" v-model:selectedKeys="selectedKeysDetail" :row-selection="rowSelectionDetail"
+                :columns="columnsDetail" :data="tableDataDetail" :pagination="paginationDetail"
+                :scroll="{ x: '100%', y: '400px' }">
+            </a-table>
+        </a-modal>
+    </div>
+</template>
+<script setup>
+import { ref, reactive } from 'vue';
+import { Message } from '@arco-design/web-vue';
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const selectedKeysDetail = ref([]);
+const rowSelectionDetail = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const searchForm = reactive({
+    exportTime: '',
+    ICCID: ''
+});
+
+const columns = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+    { title: '客户', dataIndex: 'customerName' },
+    { title: '运营商', dataIndex: 'operators' },
+    { title: '统计时间', dataIndex: 'updateTime' },
+    { title: '卡套餐', dataIndex: 'cardPackages' },
+    { title: '已用流量套餐', dataIndex: 'usedData' },
+    { title: '已用加油包流量', dataIndex: 'fuelPacketUsed' },
+    { title: '计算周期', dataIndex: 'updateTime' },
+    { title: '详情', slotName: 'detail', align: 'center' },
+];
+const columnsDetail = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+    { title: 'ICCID/MSISDN', dataIndex: 'ICCID' },
+    { title: '客户', dataIndex: 'customerName' },
+    { title: '运营商', dataIndex: 'operators' },
+    { title: '统计时间', dataIndex: 'updateTime' },
+    { title: '用户名称/编号', dataIndex: 'userName' },
+    { title: '卡套餐', dataIndex: 'cardPackages' },
+    { title: '已用/可用(套餐流量)', dataIndex: 'usedData' },
+    { title: '已用/可用(加油包流量)', dataIndex: 'fuelPacketUsed' },
+];
+const tableData = ref([
+    {
+        customerNumber: '13800138000',
+        customerName: '张三',
+        fuelPacketUsed: '1',
+        operators: 'jhl001',
+        cardPackages: '100',
+        usedData: '100',
+        updateTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        customerNumber: '13800138000',
+        customerName: '李四',
+        fuelPacketUsed: '2',
+        operators: 'jhl001',
+        cardPackages: '100',
+        usedData: '100',
+        updateTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        customerNumber: '13800138000',
+        customerName: '王五',
+        fuelPacketUsed: '3',
+        operators: 'jhl001',
+        cardPackages: '100',
+        usedData: '100',
+        updateTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        customerNumber: '13800138000',
+        customerName: '赵六',
+        fuelPacketUsed: '1',
+        operators: 'jhl001',
+        cardPackages: '100',
+        usedData: '100',
+        updateTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+
+]);
+const tableDataDetail = ref([{
+    ICCID: '1210938748329018',
+    customerName: '泰国李总',
+    operators: '泰国AIS',
+    updateTime: '2024-10-24 08:10:34',
+    userName: 'Jay/010211',
+    cardPackages: '100M每月',
+    usedData: '28M/100M',
+    fuelPacketUsed: '28M/30M'
+},
+{
+    ICCID: '1210938748329019',
+    customerName: '泰国李总',
+    operators: '泰国AIS',
+    updateTime: '2024-10-24 08:10:34',
+    userName: 'Jay/010211',
+    cardPackages: '100M每月',
+    usedData: '28M/100M',
+    fuelPacketUsed: '28M/30M'
+},
+{
+    ICCID: '12109387483290110',
+    customerName: '泰国李总',
+    operators: '泰国AIS',
+    updateTime: '2024-10-24 08:10:34',
+    userName: 'Jay/010211',
+    cardPackages: '100M每月',
+    usedData: '28M/100M',
+    fuelPacketUsed: '28M/30M'
+},
+{
+    ICCID: '12109387483290111',
+    customerName: '泰国李总',
+    operators: '泰国AIS',
+    updateTime: '2024-10-24 08:10:34',
+    userName: 'Jay/010211',
+    cardPackages: '100M每月',
+    usedData: '28M/100M',
+    fuelPacketUsed: '28M/30M'
+},
+{
+    ICCID: '12109387483290112',
+    customerName: '泰国李总',
+    operators: '泰国AIS',
+    updateTime: '2024-10-24 08:10:34',
+    userName: 'Jay/010211',
+    cardPackages: '100M每月',
+    usedData: '28M/100M',
+    fuelPacketUsed: '28M/30M'
+},])
+const pagination = reactive({
+    total: tableData.value.length,
+    current: 1,
+    pageSize: 10,
+});
+const handleSearch = () => {
+    console.log('Search form data:', searchForm);
+    Message.success('执行搜索操作');
+};
+
+const resetSearch = () => {
+    Object.keys(searchForm).forEach(key => {
+        if (Array.isArray(searchForm[key])) {
+            searchForm[key] = [];
+        } else {
+            searchForm[key] = null;
+        }
+    });
+    Message.success('搜索条件已重置');
+};
+const showDetail = ref(false);
+const submitDetail = () => {
+    window.setTimeout(() => {
+        showDetail.value = false;
+    }, 1000)
+}
+const openDetail = () => {
+    showDetail.value = true;
+}
+</script>
+<style scoped lang="less">
+.customer-top-up {
+    .search-section {
+        margin-bottom: 20px;
+    }
+
+    .audit-btn {
+        margin-bottom: 10px;
+    }
+}
+
+.text-box {
+    width: 100%;
+    margin-left: 10px;
+
+    .text {
+        font-family: PingFang SC;
+        font-size: 12px;
+        font-weight: 400;
+        line-height: 19px;
+        color: rgba(153, 153, 153, 1);
+        text-align: left;
+    }
+}
+</style>

+ 669 - 0
src/views/flowPool/index.vue

@@ -0,0 +1,669 @@
+<!-- 流量池 -->
+<template>
+    <div class="silent-expire-alarm">
+        <!-- 搜索条件区 -->
+        <div class="search-section">
+            <a-form :model="searchForm" layout="inline">
+                <a-form-item field="poolNumber" label="ICCID">
+                    <a-input v-model="searchForm.poolNumber" placeholder="请输入流量池编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="poolNumber" label="IMSI">
+                    <a-input v-model="searchForm.poolNumber" placeholder="请输入流量池编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="poolNumber" label="IMEI">
+                    <a-input v-model="searchForm.poolNumber" placeholder="请输入流量池编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="poolNumber" label="MSISDN">
+                    <a-input v-model="searchForm.poolNumber" placeholder="请输入流量池编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="poolNumber" label=" 用户">
+                    <a-input v-model="searchForm.poolNumber" placeholder="请输入流量池编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="poolNumber" label="订单编号">
+                    <a-input v-model="searchForm.poolNumber" placeholder="请输入流量池编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="customerName" label="运营商">
+                    <a-select v-model="value" :style="{ width: '200px' }" placeholder="Please select ...">
+                        <a-option v-for="item of poolUser" :value="item.value" :label="item.label" :key="item.value" />
+                    </a-select>
+                </a-form-item>
+                <a-form-item field="customerName" label="卡套餐">
+                    <a-select v-model="value" :style="{ width: '200px' }" placeholder="Please select ...">
+                        <a-option v-for="item of poolUser" :value="item.value" :label="item.label" :key="item.value" />
+                    </a-select>
+                </a-form-item>
+                <a-form-item field="customerName" label="流量状态">
+                    <a-select v-model="value" :style="{ width: '200px' }" placeholder="Please select ...">
+                        <a-option v-for="item of poolUser" :value="item.value" :label="item.label" :key="item.value" />
+                    </a-select>
+                </a-form-item>
+                <a-form-item field="customerName" label="卡状态">
+                    <a-select v-model="value" :style="{ width: '200px' }" placeholder="Please select ...">
+                        <a-option v-for="item of poolUser" :value="item.value" :label="item.label" :key="item.value" />
+                    </a-select>
+                </a-form-item>
+                <a-form-item field="customerName" label="预警状态">
+                    <a-select v-model="value" :style="{ width: '200px' }" placeholder="Please select ...">
+                        <a-option v-for="item of poolUser" :value="item.value" :label="item.label" :key="item.value" />
+                    </a-select>
+                </a-form-item>
+                <a-form-item field="customerName" label="沉默期时间">
+                    <a-date-picker style="width: 200px;" />
+                </a-form-item>
+                <a-form-item field="customerName" label="卡导入时间">
+                    <a-range-picker @change="onChange" @select="onSelect" style="width: 254px;" />
+                </a-form-item>
+                <a-form-item field="customerName" label="卡到期时间">
+                    <a-range-picker @change="onChange" @select="onSelect" style="width: 254px;" />
+                </a-form-item>
+                <a-form-item>
+                    <a-space>
+                        <a-button type="primary" @click="handleSearch">搜索</a-button>
+                        <a-button @click="resetSearch">重置</a-button>
+                    </a-space>
+                </a-form-item>
+            </a-form>
+        </div>
+        <!-- 数据表格 -->
+        <a-table row-key="poolNumber" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection"
+            :columns="columns" :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '650px' }">
+            <template #operate="{ record }">
+                <a-button @click="openContract(record)" type="text">卡操作</a-button>
+                <a-button @click="openContract(record)" type="text">换卡</a-button>
+                <a-button @click="openContract(record)" type="text">充值二维码</a-button>
+                <a-button @click="exportCard(record)" type="text">卡详情</a-button>
+            </template>
+        </a-table>
+        <a-modal v-model:visible="openExport" @ok="handleOk" @cancel="handleCancel" width="1400px">
+            <template #title>
+                卡详情
+            </template>
+            <div class="export-box">
+                <div class="box-item">
+                    <div class="export-box-item">
+                        <div class="box-item-title">
+                            <div class="title-icon"></div>
+                            基本信息
+                        </div>
+                        <div class="box-item-content">
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">ICCID</div>
+                                    <div class="item-txt-text">0989719841741478635014818</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">MSISDN</div>
+                                    <div class="item-txt-text">0989719841741478635014818</div>
+                                </div>
+                            </div>
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">IMSI</div>
+                                    <div class="item-txt-text">0989719841741478635014818</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">IMEI</div>
+                                    <div class="item-txt-text">0989719841741478635014818</div>
+                                </div>
+                            </div>
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">激活日期</div>
+                                    <div class="item-txt-text">2024-09-20 00:18:37</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">卡到期日期</div>
+                                    <div class="item-txt-text">2024-09-20 00:18:37</div>
+                                </div>
+                            </div>
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">沉默到期日期</div>
+                                    <div class="item-txt-text">2024-09-20 00:18:37</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">网络类型</div>
+                                    <div class="item-txt-text">4G</div>
+                                </div>
+                            </div>
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">订单编号</div>
+                                    <div class="item-txt-text">12322327776754</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">池名称/编号</div>
+                                    <div class="item-txt-text">泰国5万共享池/00170</div>
+                                </div>
+                            </div>
+                            <div class="item-txt"
+                                style="padding-top:20px;border-top:1px solid rgba(0, 0, 0, 0.1);margin-top: 20px;">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">订单编号</div>
+                                    <div class="item-txt-text">12322327776754</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">池名称/编号</div>
+                                    <div class="item-txt-text">泰国5万共享池/00170</div>
+                                </div>
+                            </div>
+                            <div class="item-txt"
+                                style="padding-bottom:20px;border-bottom:1px solid rgba(0, 0, 0, 0.1);margin-bottom: 20px">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">订单编号</div>
+                                    <div class="item-txt-text">12322327776754</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">池名称/编号</div>
+                                    <div class="item-txt-text">泰国5万共享池/00170</div>
+                                </div>
+                            </div>
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">运营商类型</div>
+                                    <div class="item-txt-text">国际本地</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">运营商名称</div>
+                                    <div class="item-txt-text">泰国AIS</div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="export-box-item" style="margin-top:20px;">
+                        <div class="box-item-title">
+                            <div class="title-icon"></div>
+                            当前套餐信息
+                        </div>
+                        <div class="box-item-content">
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">当前套餐</div>
+                                    <div class="item-txt-text">100M每月</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">套餐计费周期</div>
+                                    <div class="item-txt-text">按月</div>
+                                </div>
+                            </div>
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">最短订购周期</div>
+                                    <div class="item-txt-text">36个月</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">最长订购周期</div>
+                                    <div class="item-txt-text">--</div>
+                                </div>
+                            </div>
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">套餐开始时间</div>
+                                    <div class="item-txt-text">2024-09-20 10:00:13</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">套餐结束时间</div>
+                                    <div class="item-txt-text">2024-09-20 10:00:13</div>
+                                </div>
+                            </div>
+                            <div class="item-txt"
+                                style="padding-top:20px;border-top:1px solid rgba(0, 0, 0, 0.1);margin-top: 20px;">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">已用套餐流量</div>
+                                    <div class="item-txt-text">28M</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">剩余套餐流量</div>
+                                    <div class="item-txt-text">72M</div>
+                                </div>
+                            </div>
+                            <div class="item-txt">
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">已用加油包流量</div>
+                                    <div class="item-txt-text">8M</div>
+                                </div>
+                                <div class="item-txt-box">
+                                    <div class="item-txt-title">剩余加油包流量</div>
+                                    <div class="item-txt-text">--</div>
+                                </div>
+                            </div>
+                            <div class="item-txt" style="margin-top:20px;">
+                                <div class="item-txt-box" v-for="item in 5" :key="item">
+                                    <a-button type="primary">同步卡信息</a-button>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="box-item" style="padding-left:40px;box-sizing:border-box;">
+                    <a-tabs default-active-key="1">
+                        <a-tab-pane key="1" title="月用量">
+                            <div class="echarts-box">
+                                <div ref="chartDom" class="chart-dom"></div>
+                            </div>
+                        </a-tab-pane>
+                        <a-tab-pane key="2" title="卡套餐信息">
+                            <a-table :columns="columnsExport" :data="dataExport">
+                                <template #operate="{ record }">
+                                    <a-button @click="openContract(record)" type="text">下载</a-button>
+                                </template>
+                                <template #status="{ record }">
+                                    <div class="export-status" v-if="record.status == 1">
+                                        <div class="status-icon" style="background: rgba(82, 196, 27, 1);"></div>
+                                        导入成功
+                                    </div>
+                                    <div class="export-status" v-if="record.status == 2">
+                                        <div class="status-icon" style="background: rgba(250, 173, 20, 1);"></div>
+                                        部分成功
+                                    </div>
+                                    <div class="export-status" v-if="record.status == 3">
+                                        <div class="status-icon" style="background: rgba(247, 66, 75, 1);"></div>
+                                        校验失败
+                                    </div>
+                                </template>
+                            </a-table>
+                        </a-tab-pane>
+                        <a-tab-pane key="3" title="预警信息">
+                            Content of Tab Panel 3
+                        </a-tab-pane>
+                        <a-tab-pane key="4" title="充值记录">
+                            Content of Tab Panel 3
+                        </a-tab-pane>
+                        <a-tab-pane key="5" title="使用量记录">
+                            Content of Tab Panel 3
+                        </a-tab-pane>
+                        <a-tab-pane key="6" title="操作记录">
+                            Content of Tab Panel 3
+                        </a-tab-pane>
+                        <a-tab-pane key="7" title="售后">
+                            Content of Tab Panel 3
+                        </a-tab-pane>
+                    </a-tabs>
+                </div>
+            </div>
+        </a-modal>
+    </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue';
+import { Message } from '@arco-design/web-vue';
+import * as echarts from 'echarts'
+// 创造一个响应式对象来保存echarts对象
+const chartDom = ref(null);
+let chartInstance = null;
+
+// 初始化ECharts实例并设置配置项(这里以折线图为例,但可灵活替换)
+onMounted(async () => {
+    await nextTick(); // 确保DOM已经渲染完成
+    chartInstance = echarts.init(chartDom.value);
+    const option = {
+        xAxis: {
+            type: 'category',
+            data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
+        },
+        yAxis: {
+            type: 'value'
+        },
+        series: [
+            {
+                data: [120, 200, 150, 80, 70, 110, 130, 20, 28, 100, 123, 134],
+                type: 'bar'
+            }
+        ]
+    };
+    chartInstance.setOption(option);
+});
+
+// 销毁ECharts实例
+onUnmounted(() => {
+    if (chartInstance != null && chartInstance.dispose) {
+        chartInstance.dispose();
+    }
+});
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const searchForm = reactive({
+    cardNumber: '',
+    customerName: '',
+});
+// 流量池用户选项
+const poolUser = [
+    { value: 1, label: '阿里巴巴' },
+    { value: 2, label: '腾讯' },
+    { value: 3, label: '字节跳动' },
+    { value: 4, label: '百度' },
+    { value: 5, label: '小红书' },
+
+];
+const customerNameOpt = [
+    { value: 1, label: '广州联通' },
+    { value: 2, label: '湖北移动' },
+    { value: 3, label: '浙江电信' },
+    { value: 4, label: '湖北联通' },
+    { value: 5, label: '湖北电信' },
+
+];
+const moneyNameOpt = [
+    { value: 1, label: '移动20G' },
+    { value: 2, label: '监控1G月租' },
+    { value: 3, label: '联通100G' },
+    { value: 4, label: '电信200G' },
+    { value: 5, label: '监控2G月租' },
+
+];
+const columns = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1, width: 80 },
+    { title: '流量池编号', dataIndex: 'poolNumber', width: 150, align: 'center' },
+    { title: '流量池名称', dataIndex: 'poolName', width: 120, align: 'center' },
+    { title: '供应商名称', dataIndex: 'customerName', width: 120, align: 'center' },
+    { title: '资费名称', dataIndex: 'moneyName', width: 120, align: 'center' },
+    { title: '已激活卡数/总卡数量', dataIndex: 'cardMsg', width: 200, align: 'center' },
+    { title: '已使用流量/总流量(G)', dataIndex: 'trafficMsg', width: 200, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime', width: 120, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime', width: 120, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime', width: 120, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime', width: 120, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime', width: 120, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime', width: 120, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime', width: 120, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime', width: 120, align: 'center' },
+    { title: '更新日期', dataIndex: 'updateTime' },
+    { title: '操作', slotName: 'operate', align: 'center', width: 400, fixed: 'right' },
+];
+const tableData = ref([
+    {
+        poolNumber: '13800138001',
+        poolName: '广州移动',
+        customerName: '泰国True',
+        moneyName: '移动200G',
+        cardMsg: '11/100',
+        trafficMsg: '20/200',
+        updateTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        poolNumber: '13800138002',
+        poolName: '广州移动',
+        customerName: '泰国True',
+        moneyName: '移动200G',
+        cardMsg: '11/100',
+        trafficMsg: '20/200',
+        updateTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        poolNumber: '13800138003',
+        poolName: '广州移动',
+        customerName: '泰国True',
+        moneyName: '移动200G',
+        cardMsg: '11/100',
+        trafficMsg: '20/200',
+        updateTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        poolNumber: '13800138004',
+        poolName: '广州移动',
+        customerName: '泰国True',
+        moneyName: '移动200G',
+        cardMsg: '11/100',
+        trafficMsg: '20/200',
+        updateTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    // 可以添加更多模拟数据...
+]);
+// 上传合同的弹框
+const pagination = reactive({
+    total: tableData.value.length,
+    current: 1,
+    pageSize: 10,
+});
+const openContract = (item) => {
+    console.log(item, '???')
+};
+const handleSearch = () => {
+    console.log('Search form data:', searchForm);
+    Message.success('执行搜索操作');
+};
+const resetSearch = () => {
+    Object.keys(searchForm).forEach(key => {
+        if (Array.isArray(searchForm[key])) {
+            searchForm[key] = [];
+        } else {
+            searchForm[key] = null;
+        }
+    });
+    Message.success('搜索条件已重置');
+};
+// 新增流量池时的基本信息
+const formPool = reactive({
+    poolNumber: '',
+    poolName: '',
+    customerName: '',
+    moneyName: '',
+    user: ''
+})
+const formWarning = reactive({
+    // 总用量占比
+    totalDosage: '',
+    // 总用量占比达量预警
+    totalDosageCheck: '',
+    // 达量停机
+    stoppagePool: '',
+    stoppagePoolCheck: '',
+    stopNetworkPool: '',
+    stopNetworkPoolCheck: '',
+    remindTotal: '',
+    oneCardWarning: '',
+    outTotalCheck: '',
+    stoppageCard: '',
+    stoppageCardCheck: '',
+    stopNetworkCard: '',
+    stopNetworkCardCheck: '',
+    poolUsedWarning: '',
+    poolUsedCheck: '',
+    stoppageManagement: '',
+    stoppageManagementCheck: '',
+    stopNetworkManagement: '',
+    stopNetworkManagementCheck: '',
+})
+const openExport = ref(false);
+const columnsExport = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+    {
+        title: '操作人',
+        dataIndex: 'name',
+    },
+    {
+        title: '导入时间',
+        dataIndex: 'exportTime',
+    },
+    {
+        title: '完成时间',
+        dataIndex: 'successTime',
+    },
+    {
+        title: '状态',
+        slotName: 'status',
+        align: 'center'
+    },
+    { title: '操作', slotName: 'operate', align: 'center' },
+];
+const dataExport = reactive([{
+    key: '1',
+    name: 'Jane Doe',
+    exportTime: '2024-10-13 22:20:01',
+    successTime: '2024-10-13 22:20:01',
+    status: 1
+}, {
+    key: '2',
+    name: 'Alisa Ross',
+    exportTime: '2024-10-13 22:20:01',
+    successTime: '2024-10-13 22:20:01',
+    status: 2
+}, {
+    key: '3',
+    name: 'Kevin Sandra',
+    exportTime: '2024-10-13 22:20:01',
+    successTime: '2024-10-13 22:20:01',
+    status: 3
+}, {
+    key: '4',
+    name: 'Ed Hellen',
+    exportTime: '2024-10-13 22:20:01',
+    successTime: '2024-10-13 22:20:01',
+    status: 2
+}, {
+    key: '5',
+    name: 'William Smith',
+    exportTime: '2024-10-13 22:20:01',
+    successTime: '2024-10-13 22:20:01',
+    status: 3
+}]);
+// 点击导卡按钮
+const exportCard = () => {
+    openExport.value = true;
+};
+const onChange = () => {
+}
+const handleOk = () => {
+}
+const handleCancel = () => {
+}
+</script>
+
+<style scoped lang="less">
+.silent-expire-alarm {
+    padding: 20px !important;
+    // background: #fcf;
+}
+
+.search-section {
+    margin-bottom: 20px;
+}
+
+.arco-table-th {
+    white-space: nowrap;
+}
+
+.form-pool-tit {
+    display: flex;
+    align-items: center;
+    margin-bottom: 10px;
+
+    .pool-icon {
+        margin-right: 10px;
+        width: 4px;
+        height: 16px;
+        background: #1B5DF8;
+        font-size: 14px;
+        color: #6C6E70;
+        font-family: PingFang SC;
+
+    }
+}
+
+.export-box {
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    // align-items: center;
+    overflow: hidden;
+
+    .box-item {
+        width: 100%;
+        overflow: hidden;
+
+        .export-box-item {
+            .box-item-title {
+                display: flex;
+                // align-items: center;
+                font-family: PingFang SC;
+                font-size: 16px;
+                font-weight: 600;
+                line-height: 24px;
+                color: rgba(0, 0, 0, 0.85);
+                margin-bottom: 10px;
+
+                .title-icon {
+                    margin-right: 10px;
+                    width: 4px;
+                    height: 16px;
+                    background: #1B5DF8;
+
+                }
+            }
+
+            .box-item-content {
+                .item-txt {
+                    display: flex;
+                    justify-content: space-between;
+                    align-items: center;
+                    margin-bottom: 10px;
+
+                    .item-txt-box {
+                        width: 100%;
+                        display: flex;
+                        align-items: center;
+
+                        .item-txt-title {
+                            margin-right: 10px;
+                            //styleName: Body/Medium;
+                            font-family: PingFang SC;
+                            font-size: 14px;
+                            font-weight: 400;
+                            line-height: 22px;
+                            color: rgba(0, 0, 0, 0.4);
+                        }
+
+                        .item-txt-text {
+                            font-family: PingFang SC;
+                            font-size: 14px;
+                            font-weight: 400;
+                            line-height: 22px;
+                            text-align: left;
+                            color: rgba(51, 51, 51, 1);
+                        }
+                    }
+                }
+
+                .export-status {
+                    font-family: PingFang SC;
+                    font-size: 14px;
+                    font-weight: 400;
+                    line-height: 22px;
+                    text-align: left;
+                    color: rgba(51, 51, 51, 1);
+                    display: flex;
+                    align-items: center;
+
+                    .status-icon {
+                        width: 6px;
+                        height: 6px;
+                        border-radius: 50%;
+                        margin-right: 10px;
+                    }
+                }
+            }
+        }
+    }
+}
+
+.echarts-box {
+    // width: 100%;
+    display: flex;
+    justify-content: center;
+    overflow: hidden;
+
+    .chart-dom {
+        width: 700px !important;
+        height: 400px !important;
+    }
+}
+</style>

+ 1 - 2
src/views/lotCard/cardList/config.js

@@ -1,11 +1,10 @@
 export const columns = [
 export const columns = [
   { title: window.$t('lotCard.iccid'), dataIndex: 'iccid', align: 'center', width: 200 },
   { title: window.$t('lotCard.iccid'), dataIndex: 'iccid', align: 'center', width: 200 },
-  { title: window.$t('lotCard.himsi'), dataIndex: 'hImsi', align: 'center', width: 200 },
   { title: window.$t('lotCard.status'), dataIndex: 'status', align: 'center', width: 100 },
   { title: window.$t('lotCard.status'), dataIndex: 'status', align: 'center', width: 100 },
   { title: window.$t('lotCard.created_at'), dataIndex: 'created_at', align: 'center', width: 200 },
   { title: window.$t('lotCard.created_at'), dataIndex: 'created_at', align: 'center', width: 200 },
   { title: window.$t('lotCard.deleted_at'), dataIndex: 'deleted_at', align: 'center', width: 200 },
   { title: window.$t('lotCard.deleted_at'), dataIndex: 'deleted_at', align: 'center', width: 200 },
   { title: window.$t('lotCard.updated_at'), dataIndex: 'updated_at', align: 'center', width: 200 },
   { title: window.$t('lotCard.updated_at'), dataIndex: 'updated_at', align: 'center', width: 200 },
-  { title: window.$t('lotCard.msisdn'), dataIndex: 'msisdn', align: 'center', width: 200 },
+  // { title: window.$t('lotCard.msisdn'), dataIndex: 'msisdn', align: 'center', width: 200 },
   { title: window.$t('lotCard.source'), dataIndex: 'source', align: 'center', width: 200 },
   { title: window.$t('lotCard.source'), dataIndex: 'source', align: 'center', width: 200 },
   { title: window.$t('lotCard.ExpireTime'), dataIndex: 'expire_time', align: 'center', width: 200 },
   { title: window.$t('lotCard.ExpireTime'), dataIndex: 'expire_time', align: 'center', width: 200 },
   { title: window.$t('lotCard.UserId'), dataIndex: 'user_id', align: 'center', width: 200 },
   { title: window.$t('lotCard.UserId'), dataIndex: 'user_id', align: 'center', width: 200 },

+ 1 - 6
src/views/lotCard/cardList/index.vue

@@ -14,13 +14,9 @@
     <!-- 搜索条件区 -->
     <!-- 搜索条件区 -->
     <div class="search-section">
     <div class="search-section">
       <a-form :model="searchForm" ref="formRef" layout="inline">
       <a-form :model="searchForm" ref="formRef" layout="inline">
-        <a-form-item field="iccid" :label="$t('lotCard.iccid')" :validate-trigger="['change', 'input', 'blur']"
-          :rules="[{ required: true, message: $t('lotCard.please') + $t('lotCard.iccid') }]">
+        <a-form-item field="iccid" :label="$t('lotCard.iccid')">
           <a-input v-model="searchForm.iccid" :placeholder="$t('lotCard.please') + $t('lotCard.iccid')" allow-clear />
           <a-input v-model="searchForm.iccid" :placeholder="$t('lotCard.please') + $t('lotCard.iccid')" allow-clear />
         </a-form-item>
         </a-form-item>
-        <a-form-item field="hImsi" :label="$t('lotCard.himsi')">
-          <a-input v-model="searchForm.hImsi" :placeholder="$t('lotCard.please') + $t('lotCard.himsi')" allow-clear />
-        </a-form-item>
         <a-form-item>
         <a-form-item>
           <a-space>
           <a-space>
             <a-button type="primary" @click="handleSearch">{{ $t('form.Search') }}</a-button>
             <a-button type="primary" @click="handleSearch">{{ $t('form.Search') }}</a-button>
@@ -56,7 +52,6 @@ const { proxy } = getCurrentInstance()
 const formRef = ref()
 const formRef = ref()
 const searchForm = ref({
 const searchForm = ref({
   "iccid": "",
   "iccid": "",
-  "himsi": "",
 });
 });
 
 
 const dataSource = ref([]);
 const dataSource = ref([]);

+ 1 - 0
src/views/lotCard/orderMange/config.js

@@ -9,6 +9,7 @@ export const columns = [
   { title: window.$t('lotCard.orderID'), dataIndex: 'orderId', align: 'center', width: 200 },
   { title: window.$t('lotCard.orderID'), dataIndex: 'orderId', align: 'center', width: 200 },
   { title: window.$t('lotCard.price'), dataIndex: 'price', align: 'center', width: 200 },
   { title: window.$t('lotCard.price'), dataIndex: 'price', align: 'center', width: 200 },
   { title: window.$t('lotCard.quantity'), dataIndex: 'quantity', align: 'center', width: 200 },
   { title: window.$t('lotCard.quantity'), dataIndex: 'quantity', align: 'center', width: 200 },
+  { title: window.$t('lotCard.packageStatus'), dataIndex: 'status', align: 'center', width: 200 },
   { title: window.$t('lotCard.source'), dataIndex: 'source', align: 'center', width: 200 },
   { title: window.$t('lotCard.source'), dataIndex: 'source', align: 'center', width: 200 },
   { title: window.$t('lotCard.UserId'), dataIndex: 'user_id', align: 'center', width: 200 },
   { title: window.$t('lotCard.UserId'), dataIndex: 'user_id', align: 'center', width: 200 },
   {
   {

+ 12 - 0
src/views/lotCard/orderMange/index.vue

@@ -62,6 +62,10 @@ import { useRoute } from "vue-router";
 import { columns } from "./config";
 import { columns } from "./config";
 import { Message, Notification } from '@arco-design/web-vue'
 import { Message, Notification } from '@arco-design/web-vue'
 import { orderList, setOrderDataPlan, orderCancel } from "@/api/path/lotCard.api"
 import { orderList, setOrderDataPlan, orderCancel } from "@/api/path/lotCard.api"
+import { enum_dict } from "@/hooks/enum";
+import { useSystemStore } from '@/store/modules/systemStore'
+
+const useSystem = useSystemStore()
 
 
 const { proxy } = getCurrentInstance()
 const { proxy } = getCurrentInstance()
 const formRef = ref()
 const formRef = ref()
@@ -110,6 +114,12 @@ const intData = async () => {
     pagination.value.total = data.total
     pagination.value.total = data.total
 }
 }
 
 
+// 获取字典值
+const getDictValue = async () => {
+    const dictList = JSON.parse(window.localStorage.getItem('dictList'))
+    const mainList = dictList.filter((item) => item.type_key == enum_dict.MAIN_CARD_STATUS)
+}
+
 
 
 
 
 // 订购生成订单
 // 订购生成订单
@@ -198,6 +208,7 @@ const handleUnsubscribeDialog = async (record) => {
     }
     }
 };
 };
 
 
+//
 
 
 const handleSearch = () => {
 const handleSearch = () => {
     formRef.value.validate((errors) => {
     formRef.value.validate((errors) => {
@@ -216,6 +227,7 @@ const resetSearch = () => {
 
 
 onMounted(() => {
 onMounted(() => {
     intData()
     intData()
+    getDictValue()
 })
 })
 </script>
 </script>
 
 

+ 428 - 0
src/views/order/BuyCard/index.vue

@@ -0,0 +1,428 @@
+<!-- 购卡订单 -->
+<template>
+  <div class="silent-expire-alarm">
+    <!-- 搜索条件区 -->
+    <div class="search-section">
+      <a-form :model="searchForm" layout="inline">
+        <a-form-item field="cardNumber" label="订单编号">
+          <a-input v-model="searchForm.orderNumber" placeholder="请输入订单编号" allow-clear />
+        </a-form-item>
+        <a-form-item field="customerName" label="客户">
+          <a-input v-model="searchForm.customerName" placeholder="请输入客户名称" allow-clear />
+        </a-form-item>
+        <a-form-item>
+          <a-space>
+            <a-button type="primary" @click="handleSearch">搜索</a-button>
+            <a-button @click="resetSearch">重置</a-button>
+          </a-space>
+        </a-form-item>
+      </a-form>
+    </div>
+    <div class="audit-btn">
+      <a-button @click="openAudit" type="text">
+        <template #icon>
+          <icon-plus-circle />
+        </template>
+        <template #default>购卡</template>
+      </a-button>
+    </div>
+    <!-- 数据表格 -->
+    <a-table row-key="customerName" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection" :columns="columns"
+      :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '400px' }">
+      <template #operate="{ record }">
+        <a-button @click="openContract(record)" type="text">上传合同</a-button>
+      </template>
+      <template #detail="{ record }">
+        <a-button @click="openDetail(record)" type="text">订单详情</a-button>
+      </template>
+    </a-table>
+    <a-modal v-model:visible="uploadContract" title="上传合同" @cancel="handleCancel" @before-ok="handleBeforeOk"
+      okText="保存" cancelText="关闭">
+      <a-form :model="formContract" auto-label-width>
+        <a-form-item field="orderNumber" label="单号">
+          <!-- <a-input v-model="formContract.orderNumber" disabled placeholder="请输入单号" /> -->
+          <div class="audit-txt">{{ formContract.orderNumber }}</div>
+        </a-form-item>
+        <a-form-item field="customerName" label="客户">
+          <!-- <a-input v-model="formContract.customerName" disabled placeholder="请输入客户" /> -->
+          <div class="audit-txt" style="color:#418035;">{{ formContract.customerName }}</div>
+        </a-form-item>
+        <a-form-item field="fileList" label="销售合同">
+          <a-upload action="/" :default-file-list="formContract.fileList" />
+        </a-form-item>
+      </a-form>
+    </a-modal>
+    <a-modal v-model:visible="showAudit" title="购卡" @cancel="showAudit = false" @before-ok="submitAudit" okText="确定审核"
+      cancelText="关闭">
+      <a-form :model="formAudit" auto-label-width>
+        <a-form-item field="customerName" label="客户">
+          <!-- <a-input v-model="formAudit.customerName" placeholder="请输入客户" /> -->
+          <div class="audit-txt" style="color:#418035;">演示账号02</div>
+        </a-form-item>
+        <a-form-item field="cardType" label="卡类型">
+          <!-- <a-input v-model="formAudit.cardType" placeholder="请输入单号" /> -->
+          <div class="audit-txt">普通卡切卡普通卡MP1,1元/涨<div class="audit-tag">共1张卡</div>
+          </div>
+        </a-form-item>
+        <a-form-item field="money" label="资费">
+          <!-- <a-input v-model="formAudit.money" placeholder="请输入单号" /> -->
+          <div class="audit-txt">“移动100M月包” <div class="audit-tag">订购12个月</div>
+          </div>
+        </a-form-item>
+        <a-form-item field="orderStatus" label="订单状态">
+          <!-- <a-input v-model="formAudit.orderStatus" placeholder="请输入单号" /> -->
+          <a-radio-group v-model="formAudit.orderStatus" :options="options" />
+        </a-form-item>
+        <a-form-item field="auditOpinion" label="审核意见">
+          <!-- <a-input v-model="formAudit.auditOpinion" placeholder="请输入单号" /> -->
+          <a-textarea placeholder="您填写的审核意见会直接投送给用户,请认真填写!" v-model="formAudit.auditOpinion" allow-clear />
+        </a-form-item>
+        <a-form-item field="fileList" label="销售合同">
+          <a-upload action="/" :default-file-list="formAudit.fileList" />
+        </a-form-item>
+      </a-form>
+    </a-modal>
+    <a-modal v-model:visible="showDetail" width="800px" title="订单详情" :hide-cancel="true" @cancel="detailCancel">
+      <div class="detail-box">
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">订单编号</div>
+            <div class="item-content">53357981207</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">订单状态</div>
+            <div class="item-content">已发货</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">发货日期</div>
+            <div class="item-content">2024-10-24 17:46:33</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">运营商</div>
+            <div class="item-content">泰国AIS</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">资费信息</div>
+            <div class="item-content">1.0G/月</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">最短订阅周期</div>
+            <div class="item-content">3个月</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">最长订阅周期</div>
+            <div class="item-content">--</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">计费方式</div>
+            <div class="item-content">按单流量消耗计费</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">结算周期</div>
+            <div class="item-content">月</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">流量资费计费</div>
+            <div class="item-content">0.8美金/G;MRC:0元;网络接入0元</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">卡类型</div>
+            <div class="item-content">工业级PlugIn</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">卡板费</div>
+            <div class="item-content">1美金</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">流量池</div>
+            <div class="item-content">组池</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">沉默期</div>
+            <div class="item-content">6个月</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">卡数量</div>
+            <div class="item-content">10000;已分配0,已退回0,已转移0
+              <a-button type="primary" @click="showCard = true" style="margin-left:10px;">分配卡号</a-button>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="detail-table">
+        <a-table :columns="columnsDetail" :data="dataDetail" />
+      </div>
+    </a-modal>
+    <a-modal v-model:visible="showCard" width="800px" title="分配卡号" @cancel="showCard = false" @before-ok="submitCard"
+      okText="确认" cancelText="取消">
+      <a-textarea :auto-size="{
+        minRows: 15,
+        maxRows: 15
+      }" v-model="cardNumber" max-length="1000" :show-word-limit="true" placeholder="请输入iccid,一行一个或者逗号分隔;不支持两种混合号码。"
+        allow-clear />
+    </a-modal>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { Message } from '@arco-design/web-vue';
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+  type: 'checkbox',
+  showCheckedAll: true,
+  onlyCurrent: false,
+});
+const searchForm = reactive({
+  cardNumber: '',
+  customerName: '',
+});
+
+const columns = [
+  { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+  { title: '订单编号', dataIndex: 'cardNumber' },
+  { title: '客户名称', dataIndex: 'customerName' },
+  { title: '审核状态', dataIndex: 'auditStatus' },
+  { title: '订单状态', dataIndex: 'orderStatus' },
+  { title: '开卡张数', dataIndex: 'cardQuantity' },
+  { title: '通道', dataIndex: 'source' },
+  { title: '资费', dataIndex: 'money' },
+  { title: '结算价/原价(元)', dataIndex: 'outMoney' },
+  { title: '下单时间', dataIndex: 'orderTime' },
+  { title: '操作', slotName: 'operate', align: 'center' },
+  { title: '详情', slotName: 'detail', align: 'center' },
+];
+const columnsDetail = [{ title: 'ICCID', dataIndex: 'iccid' },
+{ title: '池名称及编号', dataIndex: 'nameAndId' },
+{ title: '卡状态', dataIndex: 'status' },
+]
+const dataDetail = ref([{
+  iccid: '8986061800002054589N',
+  nameAndId: '泰国监控40G共享/53357981207',
+  status: '沉默期'
+},
+{
+  iccid: '8986061800002054588N',
+  nameAndId: '泰国监控40G共享/53357981207',
+  status: '沉默期'
+}, {
+  iccid: '8986061800002054587N',
+  nameAndId: '泰国监控40G共享/53357981207',
+  status: '沉默期'
+}, {
+  iccid: '8986061800002054586N',
+  nameAndId: '泰国监控40G共享/53357981207',
+  status: '沉默期'
+},])
+const tableData = ref([
+  {
+    cardNumber: '13800138000',
+    customerName: '张三',
+    auditStatus: '1',
+    orderStatus: '1',
+    cardQuantity: 24,
+    source: '联通',
+    money: '100',
+    outMoney: '10',
+    orderTime: '2024-10-11'
+    // operate:'上传合同'
+  },
+  {
+    cardNumber: '13800138000',
+    customerName: '李四',
+    auditStatus: '1',
+    orderStatus: '1',
+    cardQuantity: 24,
+    source: '联通',
+    money: '100',
+    outMoney: '10',
+    orderTime: '2024-10-11'
+    // operate:'上传合同'
+  }, {
+    cardNumber: '13800138000',
+    customerName: '王五',
+    auditStatus: '1',
+    orderStatus: '1',
+    cardQuantity: 24,
+    source: '联通',
+    money: '100',
+    outMoney: '10',
+    orderTime: '2024-10-11'
+    // operate:'上传合同'
+  },
+  // 可以添加更多模拟数据...
+]);
+// 上传合同的弹框
+const uploadContract = ref(false);
+const pagination = reactive({
+  total: tableData.value.length,
+  current: 1,
+  pageSize: 10,
+});
+const openContract = (item) => {
+  console.log(item, '???')
+  uploadContract.value = true;
+  formContract.customerName = item.customerName;
+  formContract.orderNumber = item.cardNumber;
+};
+//订单详情的弹框
+const showDetail = ref(false);
+// 查看订单详情
+const openDetail = (item) => {
+  showDetail.value = true;
+}
+const handleBeforeOk = (done) => {
+  console.log(formContract)
+  window.setTimeout(() => {
+    done()
+    // prevent close
+    // done(false)
+  }, 3000)
+};
+const handleCancel = () => {
+  uploadContract.value = false;
+}
+const handleSearch = () => {
+  console.log('Search form data:', searchForm);
+  Message.success('执行搜索操作');
+};
+
+const resetSearch = () => {
+  Object.keys(searchForm).forEach(key => {
+    if (Array.isArray(searchForm[key])) {
+      searchForm[key] = [];
+    } else {
+      searchForm[key] = null;
+    }
+  });
+  Message.success('搜索条件已重置');
+};
+// 文件上传的列表
+const formContract = reactive({
+  orderNumber: '',
+  customerName: '',
+  fileList: []
+})
+// 订单状态
+const options = [
+  { label: '发货', value: '1' },
+  { label: '退回', value: '2' },
+];
+// 审核
+const showAudit = ref(false);
+const formAudit = reactive({
+  customerName: '',
+  cardType: '',
+  money: '',
+  orderStatus: '',
+  auditOpinion: '',
+  fileList: []
+})
+// 触发审核的弹框
+const openAudit = () => {
+  showAudit.value = true;
+}
+// 确认审核
+const submitAudit = () => {
+  console.log(formAudit, 'lll')
+  window.setTimeout(() => {
+    showAudit.value = false;
+  }, 1000)
+}
+// 分配卡号的值
+const cardNumber = ref('');
+const showCard = ref(false);
+
+const submitCard = () => {
+}
+</script>
+
+<style scoped lang="less">
+.silent-expire-alarm {
+  padding: 20px !important;
+  // background: #fcf;
+}
+
+.search-section {
+  margin-bottom: 20px;
+}
+
+.arco-table-th {
+  white-space: nowrap;
+}
+
+.audit-txt {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  .audit-tag {
+    margin-left: 20px;
+    background: #63c2c6;
+    color: #fff;
+    font-size: 12px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    padding: 0 10px;
+    box-sizing: border-box;
+    border-radius: 50px;
+  }
+}
+
+.audit-btn {
+  margin-bottom: 10px;
+}
+
+.detail-box {
+  .detail-item-box {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 10px;
+
+    .detail-item {
+      //styleName: Body/Medium;
+      font-family: PingFang SC;
+      font-size: 14px;
+      font-weight: 400;
+      line-height: 22px;
+      text-align: left;
+      display: flex;
+      align-items: center;
+      min-width: 350px;
+
+      .item-label {
+        color: rgba(0, 0, 0, 0.4);
+        width: 120px;
+        text-align: right;
+        margin-right: 10px;
+      }
+
+      .item-content {
+        color: rgba(51, 51, 51, 1);
+      }
+    }
+  }
+}
+
+.detail-table {
+  margin-top: 20px;
+}
+</style>

+ 384 - 0
src/views/order/CancelOrder/index.vue

@@ -0,0 +1,384 @@
+<!-- 注销订单 -->
+<template>
+    <div class="silent-expire-alarm">
+        <!-- 搜索条件区 -->
+        <div class="search-section">
+            <a-form :model="searchForm" layout="inline">
+                <a-form-item field="orderNumber" label="订单编号">
+                    <a-input v-model="searchForm.orderNumber" placeholder="请输入订单编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="customerName" label="客户">
+                    <a-input v-model="searchForm.customerName" placeholder="请输入客户名称" allow-clear />
+                </a-form-item>
+                <a-form-item field="customerName" label="卡号">
+                    <a-input v-model="searchForm.cardNumber" placeholder="请输入卡号" allow-clear />
+                </a-form-item>
+                <a-form-item>
+                    <a-space>
+                        <a-button type="primary" @click="handleSearch">搜索</a-button>
+                        <a-button @click="resetSearch">重置</a-button>
+                    </a-space>
+                </a-form-item>
+            </a-form>
+        </div>
+        <div class="audit-btn">
+            <a-button @click="openAudit" type="text">
+                <template #icon>
+                    <icon-plus-circle />
+                </template>
+                <template #default>注销</template>
+            </a-button>
+        </div>
+        <!-- 数据表格 -->
+        <a-table row-key="customerName" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection"
+            :columns="columns" :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '400px' }">
+            <template #detail="{ record }">
+                <a-button @click="openDetail(record)" type="text">订单详情</a-button>
+            </template>
+        </a-table>
+        <a-modal v-model:visible="showAudit" title="卡注销" @cancel="showAudit = false" @before-ok="submitAudit"
+            okText="确定审核" cancelText="关闭">
+            <a-form :model="formAudit" auto-label-width>
+                <a-form-item field="customerName" label="客户">
+                    <!-- <a-input v-model="formAudit.customerName" placeholder="请输入客户" /> -->
+                    <div class="audit-txt" style="color:#418035;">演示账号02</div>
+                </a-form-item>
+                <a-form-item field="cardType" label="卡类型">
+                    <!-- <a-input v-model="formAudit.cardType" placeholder="请输入单号" /> -->
+                    <div class="audit-txt">普通卡切卡普通卡MP1,1元/涨<div class="audit-tag">共1张卡</div>
+                    </div>
+                </a-form-item>
+                <a-form-item field="money" label="资费">
+                    <!-- <a-input v-model="formAudit.money" placeholder="请输入单号" /> -->
+                    <div class="audit-txt">“移动100M月包” <div class="audit-tag">订购12个月</div>
+                    </div>
+                </a-form-item>
+                <a-form-item field="orderStatus" label="订单状态">
+                    <!-- <a-input v-model="formAudit.orderStatus" placeholder="请输入单号" /> -->
+                    <a-radio-group v-model="formAudit.orderStatus" :options="options" />
+                </a-form-item>
+                <a-form-item field="auditOpinion" label="审核意见">
+                    <!-- <a-input v-model="formAudit.auditOpinion" placeholder="请输入单号" /> -->
+                    <a-textarea placeholder="您填写的审核意见会直接投送给用户,请认真填写!" v-model="formAudit.auditOpinion" allow-clear />
+                </a-form-item>
+                <a-form-item field="fileList" label="销售合同">
+                    <a-upload action="/" :default-file-list="formAudit.fileList" />
+                </a-form-item>
+            </a-form>
+        </a-modal>
+        <a-modal v-model:visible="showDetail" width="800px" title="卡注销" :hide-cancel="true" @cancel="detailCancel">
+            <div class="detail-box">
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">订单编号</div>
+                        <div class="item-content">53357981207</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">订单状态</div>
+                        <div class="item-content">已审核</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">运营商</div>
+                        <div class="item-content">泰国AIS</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">下单时间</div>
+                        <div class="item-content">2024-10-24 10:00:23</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">原资费信息</div>
+                        <div class="item-content">1.0G/月</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">原资费编码</div>
+                        <div class="item-content">MR206</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">新资费信息</div>
+                        <div class="item-content">5.0G/月</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">新资费编码</div>
+                        <div class="item-content">MR207</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">计费方式</div>
+                        <div class="item-content">按单流量消耗计费</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">结算周期</div>
+                        <div class="item-content">月</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">流量资费计费</div>
+                        <div class="item-content">0.8美金/G;MRC:0元;网络接入0元</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">变更数量</div>
+                        <div class="item-content">50
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="detail-table">
+                <a-table :columns="columnsDetail" :data="dataDetail" />
+            </div>
+        </a-modal>
+    </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { Message } from '@arco-design/web-vue';
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const searchForm = reactive({
+    cardNumber: '',
+    customerName: '',
+    orderNumber: ''
+});
+
+const columns = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+    {
+        title: '订单编号', dataIndex: 'orderNumber', ellipsis: true,
+        tooltip: true,
+        width: 100
+    },
+    { title: '客户名称', dataIndex: 'customerName' },
+    { title: '订单状态', dataIndex: 'auditStatus' },
+    { title: '注销张数', dataIndex: 'moneyNew' },
+    { title: '资费', dataIndex: 'moneyOld' },
+    { title: '卡号', dataIndex: 'cardNumber' },
+    { title: '下单时间', dataIndex: 'orderTime' },
+];
+const columnsDetail = [{ title: 'ICCID', dataIndex: 'iccid' },
+{ title: '池名称及编号', dataIndex: 'nameAndId' },
+{ title: '卡状态', dataIndex: 'status' },
+]
+const dataDetail = ref([{
+    iccid: '8986061800002054589N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+},
+{
+    iccid: '8986061800002054588N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+}, {
+    iccid: '8986061800002054587N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+}, {
+    iccid: '8986061800002054586N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+},])
+const tableData = ref([
+    {
+        orderNumber: '13800138000',
+        customerName: '张三',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        moneyNew: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '李四',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        moneyNew: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '王五',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        moneyNew: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '赵六',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        moneyNew: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+
+]);
+const pagination = reactive({
+    total: tableData.value.length,
+    current: 1,
+    pageSize: 10,
+});
+//订单详情的弹框
+const showDetail = ref(false);
+// 查看订单详情
+const openDetail = (item) => {
+    showDetail.value = true;
+}
+const handleSearch = () => {
+    console.log('Search form data:', searchForm);
+    Message.success('执行搜索操作');
+};
+
+const resetSearch = () => {
+    Object.keys(searchForm).forEach(key => {
+        if (Array.isArray(searchForm[key])) {
+            searchForm[key] = [];
+        } else {
+            searchForm[key] = null;
+        }
+    });
+    Message.success('搜索条件已重置');
+};
+// 订单状态
+const options = [
+    { label: '发货', value: '1' },
+    { label: '退回', value: '2' },
+];
+// 审核
+const showAudit = ref(false);
+const formAudit = reactive({
+    customerName: '',
+    cardType: '',
+    money: '',
+    orderStatus: '',
+    auditOpinion: '',
+    fileList: []
+})
+// 触发审核的弹框
+const openAudit = () => {
+    showAudit.value = true;
+}
+// 确认审核
+const submitAudit = () => {
+    console.log(formAudit, 'lll')
+    window.setTimeout(() => {
+        showAudit.value = false;
+    }, 1000)
+}
+const detailCancel = () => {
+}
+</script>
+
+<style scoped lang="less">
+.silent-expire-alarm {
+    padding: 20px !important;
+    // background: #fcf;
+}
+
+.search-section {
+    margin-bottom: 20px;
+}
+
+.arco-table-th {
+    white-space: nowrap;
+}
+
+.audit-txt {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .audit-tag {
+        margin-left: 20px;
+        background: #63c2c6;
+        color: #fff;
+        font-size: 12px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 0 10px;
+        box-sizing: border-box;
+        border-radius: 50px;
+    }
+}
+
+.audit-btn {
+    margin-bottom: 10px;
+}
+
+.detail-box {
+    .detail-item-box {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+
+        .detail-item {
+            //styleName: Body/Medium;
+            font-family: PingFang SC;
+            font-size: 14px;
+            font-weight: 400;
+            line-height: 22px;
+            text-align: left;
+            display: flex;
+            align-items: center;
+            min-width: 350px;
+
+            .item-label {
+                color: rgba(0, 0, 0, 0.4);
+                width: 120px;
+                text-align: right;
+                margin-right: 10px;
+            }
+
+            .item-content {
+                color: rgba(51, 51, 51, 1);
+            }
+        }
+    }
+}
+
+.detail-table {
+    margin-top: 20px;
+}
+</style>

+ 393 - 0
src/views/order/ChangeOrder/index.vue

@@ -0,0 +1,393 @@
+<!-- 变更订单 -->
+<template>
+    <div class="silent-expire-alarm">
+        <!-- 搜索条件区 -->
+        <div class="search-section">
+            <a-form :model="searchForm" layout="inline">
+                <a-form-item field="orderNumber" label="订单编号">
+                    <a-input v-model="searchForm.orderNumber" placeholder="请输入订单编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="customerName" label="客户">
+                    <a-input v-model="searchForm.customerName" placeholder="请输入客户名称" allow-clear />
+                </a-form-item>
+                <a-form-item field="customerName" label="卡号">
+                    <a-input v-model="searchForm.cardNumber" placeholder="请输入卡号" allow-clear />
+                </a-form-item>
+                <a-form-item>
+                    <a-space>
+                        <a-button type="primary" @click="handleSearch">搜索</a-button>
+                        <a-button @click="resetSearch">重置</a-button>
+                    </a-space>
+                </a-form-item>
+            </a-form>
+        </div>
+        <div class="audit-btn">
+            <a-button @click="openAudit" type="text">
+                <template #icon>
+                    <icon-plus-circle />
+                </template>
+                <template #default>变更</template>
+            </a-button>
+        </div>
+        <!-- 数据表格 -->
+        <a-table row-key="customerName" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection"
+            :columns="columns" :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '400px' }">
+            <template #detail="{ record }">
+                <a-button @click="openDetail(record)" type="text">订单详情</a-button>
+            </template>
+        </a-table>
+        <a-modal v-model:visible="showAudit" title="卡变更" @cancel="showAudit = false" @before-ok="submitAudit"
+            okText="确定审核" cancelText="关闭">
+            <a-form :model="formAudit" auto-label-width>
+                <a-form-item field="customerName" label="客户">
+                    <!-- <a-input v-model="formAudit.customerName" placeholder="请输入客户" /> -->
+                    <div class="audit-txt" style="color:#418035;">演示账号02</div>
+                </a-form-item>
+                <a-form-item field="cardType" label="卡类型">
+                    <!-- <a-input v-model="formAudit.cardType" placeholder="请输入单号" /> -->
+                    <div class="audit-txt">普通卡切卡普通卡MP1,1元/涨<div class="audit-tag">共1张卡</div>
+                    </div>
+                </a-form-item>
+                <a-form-item field="money" label="资费">
+                    <!-- <a-input v-model="formAudit.money" placeholder="请输入单号" /> -->
+                    <div class="audit-txt">“移动100M月包” <div class="audit-tag">订购12个月</div>
+                    </div>
+                </a-form-item>
+                <a-form-item field="orderStatus" label="订单状态">
+                    <!-- <a-input v-model="formAudit.orderStatus" placeholder="请输入单号" /> -->
+                    <a-radio-group v-model="formAudit.orderStatus" :options="options" />
+                </a-form-item>
+                <a-form-item field="auditOpinion" label="审核意见">
+                    <!-- <a-input v-model="formAudit.auditOpinion" placeholder="请输入单号" /> -->
+                    <a-textarea placeholder="您填写的审核意见会直接投送给用户,请认真填写!" v-model="formAudit.auditOpinion" allow-clear />
+                </a-form-item>
+                <a-form-item field="fileList" label="销售合同">
+                    <a-upload action="/" :default-file-list="formAudit.fileList" />
+                </a-form-item>
+            </a-form>
+        </a-modal>
+        <a-modal v-model:visible="showDetail" width="800px" title="变更资费" :hide-cancel="true" @cancel="detailCancel">
+            <div class="detail-box">
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">订单编号</div>
+                        <div class="item-content">53357981207</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">订单状态</div>
+                        <div class="item-content">已审核</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">运营商</div>
+                        <div class="item-content">泰国AIS</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">下单时间</div>
+                        <div class="item-content">2024-10-24 10:00:23</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">原资费信息</div>
+                        <div class="item-content">1.0G/月</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">原资费编码</div>
+                        <div class="item-content">MR206</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">新资费信息</div>
+                        <div class="item-content">5.0G/月</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">新资费编码</div>
+                        <div class="item-content">MR207</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">计费方式</div>
+                        <div class="item-content">按单流量消耗计费</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">结算周期</div>
+                        <div class="item-content">月</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">流量资费计费</div>
+                        <div class="item-content">0.8美金/G;MRC:0元;网络接入0元</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">变更数量</div>
+                        <div class="item-content">50
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="detail-table">
+                <a-table :columns="columnsDetail" :data="dataDetail" />
+            </div>
+        </a-modal>
+    </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { Message } from '@arco-design/web-vue';
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const searchForm = reactive({
+    cardNumber: '',
+    customerName: '',
+    orderNumber: ''
+});
+
+const columns = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+    {
+        title: '订单编号', dataIndex: 'orderNumber', ellipsis: true,
+        tooltip: true,
+        width: 100
+    },
+    { title: '客户名称', dataIndex: 'customerName' },
+    { title: '审核状态', dataIndex: 'auditStatus' },
+    {
+        title: '供应商名称', dataIndex: 'originName', ellipsis: true,
+        tooltip: true,
+        width: 150
+    },
+    { title: '新资费', dataIndex: 'moneyNew' },
+    { title: '原资费', dataIndex: 'moneyOld' },
+    { title: '卡号', dataIndex: 'cardNumber' },
+    { title: '订单金额(元)', dataIndex: 'orderMoney' },
+    { title: '结算金额(元)', dataIndex: 'finallyMoney' },
+    { title: '退回金额(元)', dataIndex: 'returnMoney' },
+    { title: '下单时间', dataIndex: 'orderTime' },
+    { title: '详情', slotName: 'detail', align: 'center' },
+];
+const columnsDetail = [{ title: 'ICCID', dataIndex: 'iccid' },
+{ title: '池名称及编号', dataIndex: 'nameAndId' },
+{ title: '卡状态', dataIndex: 'status' },
+]
+const dataDetail = ref([{
+    iccid: '8986061800002054589N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+},
+{
+    iccid: '8986061800002054588N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+}, {
+    iccid: '8986061800002054587N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+}, {
+    iccid: '8986061800002054586N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+},])
+const tableData = ref([
+    {
+        orderNumber: '13800138000',
+        customerName: '张三',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        moneyNew: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '李四',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        moneyNew: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '王五',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        moneyNew: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '赵六',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        moneyNew: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+
+]);
+const pagination = reactive({
+    total: tableData.value.length,
+    current: 1,
+    pageSize: 10,
+});
+//订单详情的弹框
+const showDetail = ref(false);
+// 查看订单详情
+const openDetail = (item) => {
+    showDetail.value = true;
+}
+const handleSearch = () => {
+    console.log('Search form data:', searchForm);
+    Message.success('执行搜索操作');
+};
+
+const resetSearch = () => {
+    Object.keys(searchForm).forEach(key => {
+        if (Array.isArray(searchForm[key])) {
+            searchForm[key] = [];
+        } else {
+            searchForm[key] = null;
+        }
+    });
+    Message.success('搜索条件已重置');
+};
+// 订单状态
+const options = [
+    { label: '发货', value: '1' },
+    { label: '退回', value: '2' },
+];
+// 审核
+const showAudit = ref(false);
+const formAudit = reactive({
+    customerName: '',
+    cardType: '',
+    money: '',
+    orderStatus: '',
+    auditOpinion: '',
+    fileList: []
+})
+// 触发审核的弹框
+const openAudit = () => {
+    showAudit.value = true;
+}
+// 确认审核
+const submitAudit = () => {
+    console.log(formAudit, 'lll')
+    window.setTimeout(() => {
+        showAudit.value = false;
+    }, 1000)
+}
+const detailCancel = () => {
+}
+</script>
+
+<style scoped lang="less">
+.silent-expire-alarm {
+    padding: 20px !important;
+    // background: #fcf;
+}
+
+.search-section {
+    margin-bottom: 20px;
+}
+
+.arco-table-th {
+    white-space: nowrap;
+}
+
+.audit-txt {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .audit-tag {
+        margin-left: 20px;
+        background: #63c2c6;
+        color: #fff;
+        font-size: 12px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 0 10px;
+        box-sizing: border-box;
+        border-radius: 50px;
+    }
+}
+
+.audit-btn {
+    margin-bottom: 10px;
+}
+
+.detail-box {
+    .detail-item-box {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+
+        .detail-item {
+            //styleName: Body/Medium;
+            font-family: PingFang SC;
+            font-size: 14px;
+            font-weight: 400;
+            line-height: 22px;
+            text-align: left;
+            display: flex;
+            align-items: center;
+            min-width: 350px;
+
+            .item-label {
+                color: rgba(0, 0, 0, 0.4);
+                width: 120px;
+                text-align: right;
+                margin-right: 10px;
+            }
+
+            .item-content {
+                color: rgba(51, 51, 51, 1);
+            }
+        }
+    }
+}
+
+.detail-table {
+    margin-top: 20px;
+}
+</style>

+ 432 - 0
src/views/order/PackageRecharge/index.vue

@@ -0,0 +1,432 @@
+<!-- 套餐充值订单 -->
+<template>
+    <div class="silent-expire-alarm">
+        <!-- 搜索条件区 -->
+        <div class="search-section">
+            <a-form :model="searchForm" layout="inline">
+                <a-form-item field="cardNumber" label="订单编号">
+                    <a-input v-model="searchForm.orderNumber" placeholder="请输入订单编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="customerName" label="ICCID">
+                    <a-input v-model="searchForm.customerName" placeholder="请输入ICCID" allow-clear />
+                </a-form-item>
+                <a-form-item>
+                    <a-space>
+                        <a-button type="primary" @click="handleSearch">搜索</a-button>
+                        <a-button @click="resetSearch">重置</a-button>
+                    </a-space>
+                </a-form-item>
+            </a-form>
+        </div>
+        <div class="audit-btn">
+            <a-button @click="openAudit" type="text">
+                <template #icon>
+                    <icon-plus-circle />
+                </template>
+                <template #default>购卡</template>
+            </a-button>
+        </div>
+        <!-- 数据表格 -->
+        <a-table row-key="customerName" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection"
+            :columns="columns" :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '400px' }">
+            <template #operate="{ record }">
+                <a-button @click="openContract(record)" type="text">上传合同</a-button>
+            </template>
+            <template #detail="{ record }">
+                <a-button @click="openDetail(record)" type="text">订单详情</a-button>
+            </template>
+        </a-table>
+        <a-modal v-model:visible="uploadContract" title="上传合同" @cancel="handleCancel" @before-ok="handleBeforeOk"
+            okText="保存" cancelText="关闭">
+            <a-form :model="formContract" auto-label-width>
+                <a-form-item field="orderNumber" label="单号">
+                    <!-- <a-input v-model="formContract.orderNumber" disabled placeholder="请输入单号" /> -->
+                    <div class="audit-txt">{{ formContract.orderNumber }}</div>
+                </a-form-item>
+                <a-form-item field="customerName" label="客户">
+                    <!-- <a-input v-model="formContract.customerName" disabled placeholder="请输入客户" /> -->
+                    <div class="audit-txt" style="color:#418035;">{{ formContract.customerName }}</div>
+                </a-form-item>
+                <a-form-item field="fileList" label="销售合同">
+                    <a-upload action="/" :default-file-list="formContract.fileList" />
+                </a-form-item>
+            </a-form>
+        </a-modal>
+        <a-modal v-model:visible="showAudit" title="购卡" @cancel="showAudit = false" @before-ok="submitAudit"
+            okText="确定审核" cancelText="关闭">
+            <a-form :model="formAudit" auto-label-width>
+                <a-form-item field="customerName" label="客户">
+                    <!-- <a-input v-model="formAudit.customerName" placeholder="请输入客户" /> -->
+                    <div class="audit-txt" style="color:#418035;">演示账号02</div>
+                </a-form-item>
+                <a-form-item field="cardType" label="卡类型">
+                    <!-- <a-input v-model="formAudit.cardType" placeholder="请输入单号" /> -->
+                    <div class="audit-txt">普通卡切卡普通卡MP1,1元/涨<div class="audit-tag">共1张卡</div>
+                    </div>
+                </a-form-item>
+                <a-form-item field="money" label="资费">
+                    <!-- <a-input v-model="formAudit.money" placeholder="请输入单号" /> -->
+                    <div class="audit-txt">“移动100M月包” <div class="audit-tag">订购12个月</div>
+                    </div>
+                </a-form-item>
+                <a-form-item field="orderStatus" label="订单状态">
+                    <!-- <a-input v-model="formAudit.orderStatus" placeholder="请输入单号" /> -->
+                    <a-radio-group v-model="formAudit.orderStatus" :options="options" />
+                </a-form-item>
+                <a-form-item field="auditOpinion" label="审核意见">
+                    <!-- <a-input v-model="formAudit.auditOpinion" placeholder="请输入单号" /> -->
+                    <a-textarea placeholder="您填写的审核意见会直接投送给用户,请认真填写!" v-model="formAudit.auditOpinion" allow-clear />
+                </a-form-item>
+                <a-form-item field="fileList" label="销售合同">
+                    <a-upload action="/" :default-file-list="formAudit.fileList" />
+                </a-form-item>
+            </a-form>
+        </a-modal>
+        <a-modal v-model:visible="showDetail" width="800px" title="订单详情" :hide-cancel="true" @cancel="detailCancel">
+            <div class="detail-box">
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">订单编号</div>
+                        <div class="item-content">53357981207</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">订单状态</div>
+                        <div class="item-content">已发货</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">发货日期</div>
+                        <div class="item-content">2024-10-24 17:46:33</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">运营商</div>
+                        <div class="item-content">泰国AIS</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">资费信息</div>
+                        <div class="item-content">1.0G/月</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">最短订阅周期</div>
+                        <div class="item-content">3个月</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">最长订阅周期</div>
+                        <div class="item-content">--</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">计费方式</div>
+                        <div class="item-content">按单流量消耗计费</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">结算周期</div>
+                        <div class="item-content">月</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">流量资费计费</div>
+                        <div class="item-content">0.8美金/G;MRC:0元;网络接入0元</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">卡类型</div>
+                        <div class="item-content">工业级PlugIn</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">卡板费</div>
+                        <div class="item-content">1美金</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">流量池</div>
+                        <div class="item-content">组池</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">沉默期</div>
+                        <div class="item-content">6个月</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">卡数量</div>
+                        <div class="item-content">10000;已分配0,已退回0,已转移0
+                            <a-button type="primary" @click="showCard = true" style="margin-left:10px;">分配卡号</a-button>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="detail-table">
+                <a-table :columns="columnsDetail" :data="dataDetail" />
+            </div>
+        </a-modal>
+        <a-modal v-model:visible="showCard" width="800px" title="分配卡号" @cancel="showCard = false"
+            @before-ok="submitCard" okText="确认" cancelText="取消">
+            <a-textarea :auto-size="{
+                minRows: 15,
+                maxRows: 15
+            }" v-model="cardNumber" max-length="1000" :show-word-limit="true"
+                placeholder="请输入iccid,一行一个或者逗号分隔;不支持两种混合号码。" allow-clear />
+        </a-modal>
+    </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { Message } from '@arco-design/web-vue';
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const searchForm = reactive({
+    cardNumber: '',
+    customerName: '',
+});
+
+const columns = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+    { title: '订单编号', dataIndex: 'cardNumber' },
+    { title: 'ICCID', dataIndex: 'customerName' },
+    { title: 'MSISDN', dataIndex: 'msisdn' },
+    { title: '订单类型', dataIndex: 'orderStatus' },
+    { title: '运营商名称', dataIndex: 'cardQuantity' },
+    { title: '购买套餐', dataIndex: 'source' },
+    { title: '套餐类型', dataIndex: 'packageStatus' },
+    { title: '订购时长', dataIndex: 'money' },
+    { title: '套餐价格', dataIndex: 'outMoney' },
+    { title: '支付状态', dataIndex: 'payStatus' },
+    { title: '支付价格', dataIndex: 'payMoney' },
+    { title: '支付时间', dataIndex: 'orderTime' },
+    // { title: '操作', slotName: 'operate', align: 'center' },
+    { title: '详情', slotName: 'detail', align: 'center' },
+];
+const columnsDetail = [{ title: 'ICCID', dataIndex: 'iccid' },
+{ title: '池名称及编号', dataIndex: 'nameAndId' },
+{ title: '卡状态', dataIndex: 'status' },
+]
+const dataDetail = ref([{
+    iccid: '8986061800002054589N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+},
+{
+    iccid: '8986061800002054588N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+}, {
+    iccid: '8986061800002054587N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+}, {
+    iccid: '8986061800002054586N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+},])
+const tableData = ref([
+    {
+        cardNumber: '13800138000',
+        customerName: '张三',
+        auditStatus: '1',
+        orderStatus: '1',
+        cardQuantity: 24,
+        source: '联通',
+        money: '100',
+        outMoney: '10',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        cardNumber: '13800138000',
+        customerName: '李四',
+        auditStatus: '1',
+        orderStatus: '1',
+        cardQuantity: 24,
+        source: '联通',
+        money: '100',
+        outMoney: '10',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    }, {
+        cardNumber: '13800138000',
+        customerName: '王五',
+        auditStatus: '1',
+        orderStatus: '1',
+        cardQuantity: 24,
+        source: '联通',
+        money: '100',
+        outMoney: '10',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    // 可以添加更多模拟数据...
+]);
+// 上传合同的弹框
+const uploadContract = ref(false);
+const pagination = reactive({
+    total: tableData.value.length,
+    current: 1,
+    pageSize: 10,
+});
+const openContract = (item) => {
+    console.log(item, '???')
+    uploadContract.value = true;
+    formContract.customerName = item.customerName;
+    formContract.orderNumber = item.cardNumber;
+};
+//订单详情的弹框
+const showDetail = ref(false);
+// 查看订单详情
+const openDetail = (item) => {
+    showDetail.value = true;
+}
+const handleBeforeOk = (done) => {
+    console.log(formContract)
+    window.setTimeout(() => {
+        done()
+        // prevent close
+        // done(false)
+    }, 3000)
+};
+const handleCancel = () => {
+    uploadContract.value = false;
+}
+const handleSearch = () => {
+    console.log('Search form data:', searchForm);
+    Message.success('执行搜索操作');
+};
+
+const resetSearch = () => {
+    Object.keys(searchForm).forEach(key => {
+        if (Array.isArray(searchForm[key])) {
+            searchForm[key] = [];
+        } else {
+            searchForm[key] = null;
+        }
+    });
+    Message.success('搜索条件已重置');
+};
+// 文件上传的列表
+const formContract = reactive({
+    orderNumber: '',
+    customerName: '',
+    fileList: []
+})
+// 订单状态
+const options = [
+    { label: '发货', value: '1' },
+    { label: '退回', value: '2' },
+];
+// 审核
+const showAudit = ref(false);
+const formAudit = reactive({
+    customerName: '',
+    cardType: '',
+    money: '',
+    orderStatus: '',
+    auditOpinion: '',
+    fileList: []
+})
+// 触发审核的弹框
+const openAudit = () => {
+    showAudit.value = true;
+}
+// 确认审核
+const submitAudit = () => {
+    console.log(formAudit, 'lll')
+    window.setTimeout(() => {
+        showAudit.value = false;
+    }, 1000)
+}
+// 分配卡号的值
+const cardNumber = ref('');
+const showCard = ref(false);
+const detailCancel = () => {
+}
+const submitCard = () => {
+}
+</script>
+
+<style scoped lang="less">
+.silent-expire-alarm {
+    padding: 20px !important;
+    // background: #fcf;
+}
+
+.search-section {
+    margin-bottom: 20px;
+}
+
+.arco-table-th {
+    white-space: nowrap;
+}
+
+.audit-txt {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .audit-tag {
+        margin-left: 20px;
+        background: #63c2c6;
+        color: #fff;
+        font-size: 12px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 0 10px;
+        box-sizing: border-box;
+        border-radius: 50px;
+    }
+}
+
+.audit-btn {
+    margin-bottom: 10px;
+}
+
+.detail-box {
+    .detail-item-box {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+
+        .detail-item {
+            //styleName: Body/Medium;
+            font-family: PingFang SC;
+            font-size: 14px;
+            font-weight: 400;
+            line-height: 22px;
+            text-align: left;
+            display: flex;
+            align-items: center;
+            min-width: 350px;
+
+            .item-label {
+                color: rgba(0, 0, 0, 0.4);
+                width: 120px;
+                text-align: right;
+                margin-right: 10px;
+            }
+
+            .item-content {
+                color: rgba(51, 51, 51, 1);
+            }
+        }
+    }
+}
+
+.detail-table {
+    margin-top: 20px;
+}
+</style>

+ 379 - 0
src/views/order/RenewalOrder/index.vue

@@ -0,0 +1,379 @@
+<!-- 续费订单 -->
+<template>
+    <div class="silent-expire-alarm">
+        <!-- 搜索条件区 -->
+        <div class="search-section">
+            <a-form :model="searchForm" layout="inline">
+                <a-form-item field="orderNumber" label="订单编号">
+                    <a-input v-model="searchForm.orderNumber" placeholder="请输入订单编号" allow-clear />
+                </a-form-item>
+                <a-form-item field="customerName" label="客户">
+                    <a-input v-model="searchForm.customerName" placeholder="请输入客户名称" allow-clear />
+                </a-form-item>
+                <a-form-item field="customerName" label="卡号">
+                    <a-input v-model="searchForm.cardNumber" placeholder="请输入卡号" allow-clear />
+                </a-form-item>
+                <a-form-item>
+                    <a-space>
+                        <a-button type="primary" @click="handleSearch">搜索</a-button>
+                        <a-button @click="resetSearch">重置</a-button>
+                    </a-space>
+                </a-form-item>
+            </a-form>
+        </div>
+        <div class="audit-btn">
+            <a-button @click="openAudit" type="text">
+                <template #icon>
+                    <icon-plus-circle />
+                </template>
+                <template #default>续费</template>
+            </a-button>
+        </div>
+        <!-- 数据表格 -->
+        <a-table row-key="customerName" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection"
+            :columns="columns" :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '400px' }">
+            <template #detail="{ record }">
+                <a-button @click="openDetail(record)" type="text">订单详情</a-button>
+            </template>
+        </a-table>
+        <a-modal v-model:visible="showAudit" title="卡续期" @cancel="showAudit = false" @before-ok="submitAudit"
+            okText="确定审核" cancelText="关闭">
+            <a-form :model="formAudit" auto-label-width>
+                <a-form-item field="customerName" label="客户">
+                    <!-- <a-input v-model="formAudit.customerName" placeholder="请输入客户" /> -->
+                    <div class="audit-txt" style="color:#418035;">演示账号02</div>
+                </a-form-item>
+                <a-form-item field="cardType" label="卡类型">
+                    <!-- <a-input v-model="formAudit.cardType" placeholder="请输入单号" /> -->
+                    <div class="audit-txt">普通卡切卡普通卡MP1,1元/涨<div class="audit-tag">共1张卡</div>
+                    </div>
+                </a-form-item>
+                <a-form-item field="money" label="资费">
+                    <!-- <a-input v-model="formAudit.money" placeholder="请输入单号" /> -->
+                    <div class="audit-txt">“移动100M月包” <div class="audit-tag">订购12个月</div>
+                    </div>
+                </a-form-item>
+                <a-form-item field="orderStatus" label="订单状态">
+                    <!-- <a-input v-model="formAudit.orderStatus" placeholder="请输入单号" /> -->
+                    <a-radio-group v-model="formAudit.orderStatus" :options="options" />
+                </a-form-item>
+                <a-form-item field="auditOpinion" label="审核意见">
+                    <!-- <a-input v-model="formAudit.auditOpinion" placeholder="请输入单号" /> -->
+                    <a-textarea placeholder="您填写的审核意见会直接投送给用户,请认真填写!" v-model="formAudit.auditOpinion" allow-clear />
+                </a-form-item>
+                <a-form-item field="fileList" label="销售合同">
+                    <a-upload action="/" :default-file-list="formAudit.fileList" />
+                </a-form-item>
+            </a-form>
+        </a-modal>
+        <a-modal v-model:visible="showDetail" width="800px" title="续费订单" :hide-cancel="true" @cancel="detailCancel">
+            <div class="detail-box">
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">订单编号</div>
+                        <div class="item-content">53357981207</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">订单状态</div>
+                        <div class="item-content">已审核</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">运营商</div>
+                        <div class="item-content">泰国AIS</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">下单时间</div>
+                        <div class="item-content">2024-10-24 10:00:23</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">资费信息</div>
+                        <div class="item-content">1.0G/月</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">资费编码</div>
+                        <div class="item-content">MR206</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">计费方式</div>
+                        <div class="item-content">按单流量消耗计费</div>
+                    </div>
+                    <div class="detail-item">
+                        <div class="item-label">结算周期</div>
+                        <div class="item-content">月</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">流量资费计费</div>
+                        <div class="item-content">0.8美金/G;MRC:0元;网络接入0元</div>
+                    </div>
+                </div>
+                <div class="detail-item-box">
+                    <div class="detail-item">
+                        <div class="item-label">续期数量</div>
+                        <div class="item-content">50
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="detail-table">
+                <a-table :columns="columnsDetail" :data="dataDetail" />
+            </div>
+        </a-modal>
+    </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { Message } from '@arco-design/web-vue';
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const searchForm = reactive({
+    cardNumber: '',
+    customerName: '',
+    orderNumber: ''
+});
+
+const columns = [
+    { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+    {
+        title: '订单编号', dataIndex: 'orderNumber', ellipsis: true,
+        tooltip: true,
+        width: 100
+    },
+    { title: '客户名称', dataIndex: 'customerName' },
+    { title: '审核状态', dataIndex: 'auditStatus' },
+    {
+        title: '供应商名称', dataIndex: 'originName', ellipsis: true,
+        tooltip: true,
+        width: 150
+    },
+    { title: '资费', dataIndex: 'money' },
+    { title: '卡号', dataIndex: 'cardNumber' },
+    { title: '订单金额(元)', dataIndex: 'orderMoney' },
+    { title: '下单时间', dataIndex: 'orderTime' },
+    { title: '详情', slotName: 'detail', align: 'center' },
+];
+const columnsDetail = [{ title: 'ICCID', dataIndex: 'iccid' },
+{ title: '池名称及编号', dataIndex: 'nameAndId' },
+{ title: '卡状态', dataIndex: 'status' },
+]
+const dataDetail = ref([{
+    iccid: '8986061800002054589N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+},
+{
+    iccid: '8986061800002054588N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+}, {
+    iccid: '8986061800002054587N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+}, {
+    iccid: '8986061800002054586N',
+    nameAndId: '泰国监控40G共享/53357981207',
+    status: '沉默期'
+},])
+const tableData = ref([
+    {
+        orderNumber: '13800138000',
+        customerName: '张三',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        money: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '李四',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        money: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '王五',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        money: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+    {
+        orderNumber: '13800138000',
+        customerName: '赵六',
+        orderStatus: '1',
+        auditStatus: '待审核',
+        originName: '移动-广州分公司',
+        money: '100',
+        moneyOld: '100',
+        cardNumber: '1124224q',
+        orderMoney: '11美元',
+        finallyMoney: '1美元',
+        returnMoney: '10美元',
+        orderTime: '2024-10-11'
+        // operate:'上传合同'
+    },
+
+]);
+const pagination = reactive({
+    total: tableData.value.length,
+    current: 1,
+    pageSize: 10,
+});
+//订单详情的弹框
+const showDetail = ref(false);
+// 查看订单详情
+const openDetail = (item) => {
+    showDetail.value = true;
+}
+const handleSearch = () => {
+    console.log('Search form data:', searchForm);
+    Message.success('执行搜索操作');
+};
+
+const resetSearch = () => {
+    Object.keys(searchForm).forEach(key => {
+        if (Array.isArray(searchForm[key])) {
+            searchForm[key] = [];
+        } else {
+            searchForm[key] = null;
+        }
+    });
+    Message.success('搜索条件已重置');
+};
+// 订单状态
+const options = [
+    { label: '发货', value: '1' },
+    { label: '退回', value: '2' },
+];
+// 审核
+const showAudit = ref(false);
+const formAudit = reactive({
+    customerName: '',
+    cardType: '',
+    money: '',
+    orderStatus: '',
+    auditOpinion: '',
+    fileList: []
+})
+// 触发审核的弹框
+const openAudit = () => {
+    showAudit.value = true;
+}
+// 确认审核
+const submitAudit = () => {
+    console.log(formAudit, 'lll')
+    window.setTimeout(() => {
+        showAudit.value = false;
+    }, 1000)
+}
+const detailCancel = () => {
+}
+</script>
+
+<style scoped lang="less">
+.silent-expire-alarm {
+    padding: 20px !important;
+    // background: #fcf;
+}
+
+.search-section {
+    margin-bottom: 20px;
+}
+
+.arco-table-th {
+    white-space: nowrap;
+}
+
+.audit-txt {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .audit-tag {
+        margin-left: 20px;
+        background: #63c2c6;
+        color: #fff;
+        font-size: 12px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 0 10px;
+        box-sizing: border-box;
+        border-radius: 50px;
+    }
+}
+
+.audit-btn {
+    margin-bottom: 10px;
+}
+
+.detail-box {
+    .detail-item-box {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+
+        .detail-item {
+            //styleName: Body/Medium;
+            font-family: PingFang SC;
+            font-size: 14px;
+            font-weight: 400;
+            line-height: 22px;
+            text-align: left;
+            display: flex;
+            align-items: center;
+            min-width: 350px;
+
+            .item-label {
+                color: rgba(0, 0, 0, 0.4);
+                width: 120px;
+                text-align: right;
+                margin-right: 10px;
+            }
+
+            .item-content {
+                color: rgba(51, 51, 51, 1);
+            }
+        }
+    }
+}
+
+.detail-table {
+    margin-top: 20px;
+}
+</style>

+ 380 - 0
src/views/order/ReturnCard/index.vue

@@ -0,0 +1,380 @@
+<!-- 退卡订单 -->
+<template>
+  <div class="silent-expire-alarm">
+    <!-- 搜索条件区 -->
+    <div class="search-section">
+      <a-form :model="searchForm" layout="inline">
+        <a-form-item field="cardNumber" label="订单编号">
+          <a-input v-model="searchForm.orderNumber" placeholder="请输入订单编号" allow-clear />
+        </a-form-item>
+        <a-form-item field="customerName" label="客户">
+          <a-input v-model="searchForm.customerName" placeholder="请输入客户名称" allow-clear />
+        </a-form-item>
+        <a-form-item>
+          <a-space>
+            <a-button type="primary" @click="handleSearch">搜索</a-button>
+            <a-button @click="resetSearch">重置</a-button>
+          </a-space>
+        </a-form-item>
+      </a-form>
+    </div>
+    <div class="audit-btn">
+      <a-button @click="openAudit" type="text">
+        <template #icon>
+          <icon-plus-circle />
+        </template>
+        <template #default>退卡</template>
+      </a-button>
+    </div>
+    <!-- 数据表格 -->
+    <a-table row-key="customerName" v-model:selectedKeys="selectedKeys" :row-selection="rowSelection" :columns="columns"
+      :data="tableData" :pagination="pagination" :scroll="{ x: '100%', y: '400px' }">
+      <template #detail="{ record }">
+        <a-button @click="openDetail(record)" type="text">订单详情</a-button>
+      </template>
+    </a-table>
+    <a-modal v-model:visible="showAudit" title="退卡" @cancel="showAudit = false" @before-ok="submitAudit" okText="确定审核"
+      cancelText="关闭">
+      <a-form :model="formAudit" auto-label-width>
+        <a-form-item field="customerName" label="客户">
+          <!-- <a-input v-model="formAudit.customerName" placeholder="请输入客户" /> -->
+          <div class="audit-txt" style="color:#418035;">演示账号02</div>
+        </a-form-item>
+        <a-form-item field="cardType" label="卡类型">
+          <!-- <a-input v-model="formAudit.cardType" placeholder="请输入单号" /> -->
+          <div class="audit-txt">普通卡切卡普通卡MP1,1元/涨<div class="audit-tag">共1张卡</div>
+          </div>
+        </a-form-item>
+        <a-form-item field="money" label="资费">
+          <!-- <a-input v-model="formAudit.money" placeholder="请输入单号" /> -->
+          <div class="audit-txt">“移动100M月包” <div class="audit-tag">订购12个月</div>
+          </div>
+        </a-form-item>
+        <a-form-item field="orderStatus" label="订单状态">
+          <!-- <a-input v-model="formAudit.orderStatus" placeholder="请输入单号" /> -->
+          <a-radio-group v-model="formAudit.orderStatus" :options="options" />
+        </a-form-item>
+        <a-form-item field="auditOpinion" label="审核意见">
+          <!-- <a-input v-model="formAudit.auditOpinion" placeholder="请输入单号" /> -->
+          <a-textarea placeholder="您填写的审核意见会直接投送给用户,请认真填写!" v-model="formAudit.auditOpinion" allow-clear />
+        </a-form-item>
+        <a-form-item field="fileList" label="销售合同">
+          <a-upload action="/" :default-file-list="formAudit.fileList" />
+        </a-form-item>
+      </a-form>
+    </a-modal>
+    <a-modal v-model:visible="showDetail" width="800px" title="退卡详情" :hide-cancel="true" @cancel="detailCancel">
+      <div class="detail-box">
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">订单编号</div>
+            <div class="item-content">53357981207</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">订单状态</div>
+            <div class="item-content">已审核</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">运营商</div>
+            <div class="item-content">泰国AIS</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">资费信息</div>
+            <div class="item-content">1.0G/月</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">最短订阅周期</div>
+            <div class="item-content">3个月</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">剩余时长</div>
+            <div class="item-content">2个月</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">计费方式</div>
+            <div class="item-content">按单流量消耗计费</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">结算周期</div>
+            <div class="item-content">月</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">流量资费计费</div>
+            <div class="item-content">0.8美金/G;MRC:0元;网络接入0元</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">卡类型</div>
+            <div class="item-content">工业级PlugIn</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">卡板费</div>
+            <div class="item-content">1美金</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">流量池</div>
+            <div class="item-content">组池</div>
+          </div>
+          <div class="detail-item">
+            <div class="item-label">沉默期</div>
+            <div class="item-content">6个月</div>
+          </div>
+        </div>
+        <div class="detail-item-box">
+          <div class="detail-item">
+            <div class="item-label">退卡数量</div>
+            <div class="item-content">50
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="detail-table">
+        <a-table :columns="columnsDetail" :data="dataDetail" />
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { Message } from '@arco-design/web-vue';
+const selectedKeys = ref([]);
+const rowSelection = reactive({
+  type: 'checkbox',
+  showCheckedAll: true,
+  onlyCurrent: false,
+});
+const searchForm = reactive({
+  cardNumber: '',
+  customerName: '',
+});
+
+const columns = [
+  { title: '序号', dataIndex: 'index', align: 'center', render: ({ rowIndex }) => rowIndex + 1 },
+  { title: '订单编号', dataIndex: 'cardNumber' },
+  { title: '客户名称', dataIndex: 'customerName' },
+  { title: '订单状态', dataIndex: 'orderStatus' },
+  { title: '退卡张数', dataIndex: 'cardQuantity' },
+  { title: '资费', dataIndex: 'money' },
+  { title: '剩余时长(月)', dataIndex: 'outTime' },
+  { title: '退回金额', dataIndex: 'returnMoney' },
+  { title: '下单时间', dataIndex: 'orderTime' },
+  { title: '详情', slotName: 'detail', align: 'center' },
+];
+const columnsDetail = [{ title: 'ICCID', dataIndex: 'iccid' },
+{ title: '池名称及编号', dataIndex: 'nameAndId' },
+{ title: '卡状态', dataIndex: 'status' },
+]
+const dataDetail = ref([{
+  iccid: '8986061800002054589N',
+  nameAndId: '泰国监控40G共享/53357981207',
+  status: '沉默期'
+},
+{
+  iccid: '8986061800002054588N',
+  nameAndId: '泰国监控40G共享/53357981207',
+  status: '沉默期'
+}, {
+  iccid: '8986061800002054587N',
+  nameAndId: '泰国监控40G共享/53357981207',
+  status: '沉默期'
+}, {
+  iccid: '8986061800002054586N',
+  nameAndId: '泰国监控40G共享/53357981207',
+  status: '沉默期'
+},])
+const tableData = ref([
+  {
+    cardNumber: '13800138000',
+    customerName: '张三',
+    orderStatus: '1',
+    cardQuantity: 24,
+    money: '100',
+    outTime: '11',
+    returnMoney: '11美元',
+    orderTime: '2024-10-11'
+    // operate:'上传合同'
+  },
+  {
+    cardNumber: '13800138000',
+    customerName: '李四',
+    orderStatus: '1',
+    cardQuantity: 24,
+    money: '100',
+    outTime: '11',
+    returnMoney: '11美元',
+    orderTime: '2024-10-11'
+    // operate:'上传合同'
+  }, {
+    cardNumber: '13800138000',
+    customerName: '王五',
+    orderStatus: '1',
+    cardQuantity: 24,
+    money: '100',
+    outTime: '11',
+    returnMoney: '11美元',
+    orderTime: '2024-10-11'
+    // operate:'上传合同'
+  }, {
+    cardNumber: '13800138000',
+    customerName: '赵六',
+    orderStatus: '1',
+    cardQuantity: 24,
+    money: '100',
+    outTime: '11',
+    returnMoney: '11美元',
+    orderTime: '2024-10-11'
+    // operate:'上传合同'
+  }, {
+    cardNumber: '13800138000',
+    customerName: '田七',
+    orderStatus: '1',
+    cardQuantity: 24,
+    money: '100',
+    outTime: '11',
+    returnMoney: '11美元',
+    orderTime: '2024-10-11'
+    // operate:'上传合同'
+  },
+
+]);
+const pagination = reactive({
+  total: tableData.value.length,
+  current: 1,
+  pageSize: 10,
+});
+//订单详情的弹框
+const showDetail = ref(false);
+// 查看订单详情
+const openDetail = (item) => {
+  showDetail.value = true;
+}
+const handleSearch = () => {
+  console.log('Search form data:', searchForm);
+  Message.success('执行搜索操作');
+};
+
+const resetSearch = () => {
+  Object.keys(searchForm).forEach(key => {
+    if (Array.isArray(searchForm[key])) {
+      searchForm[key] = [];
+    } else {
+      searchForm[key] = null;
+    }
+  });
+  Message.success('搜索条件已重置');
+};
+// 订单状态
+const options = [
+  { label: '发货', value: '1' },
+  { label: '退回', value: '2' },
+];
+// 审核
+const showAudit = ref(false);
+const formAudit = reactive({
+  customerName: '',
+  cardType: '',
+  money: '',
+  orderStatus: '',
+  auditOpinion: '',
+  fileList: []
+})
+// 触发审核的弹框
+const openAudit = () => {
+  showAudit.value = true;
+}
+// 确认审核
+const submitAudit = () => {
+  console.log(formAudit, 'lll')
+  window.setTimeout(() => {
+    showAudit.value = false;
+  }, 1000)
+}
+const detailCancel = () => {
+}
+</script>
+
+<style scoped lang="less">
+.silent-expire-alarm {
+  padding: 20px !important;
+  // background: #fcf;
+}
+
+.search-section {
+  margin-bottom: 20px;
+}
+
+.arco-table-th {
+  white-space: nowrap;
+}
+
+.audit-txt {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  .audit-tag {
+    margin-left: 20px;
+    background: #63c2c6;
+    color: #fff;
+    font-size: 12px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    padding: 0 10px;
+    box-sizing: border-box;
+    border-radius: 50px;
+  }
+}
+
+.audit-btn {
+  margin-bottom: 10px;
+}
+
+.detail-box {
+  .detail-item-box {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 10px;
+
+    .detail-item {
+      //styleName: Body/Medium;
+      font-family: PingFang SC;
+      font-size: 14px;
+      font-weight: 400;
+      line-height: 22px;
+      text-align: left;
+      display: flex;
+      align-items: center;
+      min-width: 350px;
+
+      .item-label {
+        color: rgba(0, 0, 0, 0.4);
+        width: 120px;
+        text-align: right;
+        margin-right: 10px;
+      }
+
+      .item-content {
+        color: rgba(51, 51, 51, 1);
+      }
+    }
+  }
+}
+
+.detail-table {
+  margin-top: 20px;
+}
+</style>

+ 28 - 0
src/views/tariffManagement/config.js

@@ -0,0 +1,28 @@
+export const columns = [
+    { title: window.$t('tariffManagement.simDataPlanId'), dataIndex: 'sim_data_plan_id', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.userId'), dataIndex: 'user_id', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.label'), dataIndex: 'label', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.source'), dataIndex: 'source', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.trafficType'), dataIndex: 'traffic_type', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.billingType'), dataIndex: 'billing_type', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.bagSize'), dataIndex: 'bag_size', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.billingCycle'), dataIndex: 'billing_cycle', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.billingMethod'), dataIndex: 'billing_method', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.settlementCycle'), dataIndex: 'settlement_cycle', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.sourcePrice'), dataIndex: 'source_price', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.pricing'), dataIndex: 'pricing', align: 'center', width: 200 },
+    { title: window.$t('tariffManagement.currency'), dataIndex: 'currency', align: 'center', width: 200 },
+    {
+        title: window.$t('global.common.operations'),
+        dataIndex: 'id',
+        slotName: 'id',
+        align: 'center',
+        width: 180,
+        fixed: "right",
+    }
+]
+
+
+
+
+

+ 344 - 0
src/views/tariffManagement/index.vue

@@ -0,0 +1,344 @@
+<!-- 资费管理 -->
+<template>
+    <div class="container">
+        <div class="head-title">
+            <span>{{ route.meta.title }} </span>
+            <span class="head-title-right">
+                <a-button class="m-r-10" type="primary" @click="dictShowModel(1, null)">{{ $t('form.Add') }}</a-button>
+            </span>
+        </div>
+        <!-- 搜索条件区 -->
+        <div class="search-section">
+            <a-form :model="searchForm" layout="inline">
+                <a-form-item field="simDataPlanId" :label="$t('tariffManagement.simDataPlanId')">
+                    <a-input v-model="searchForm.ICCID"
+                        :placeholder="$t('lotCard.please') + $t('tariffManagement.simDataPlanId')" allow-clear />
+                </a-form-item>
+                <a-form-item>
+                    <a-space>
+                        <a-button type="primary" @click="handleSearch">{{ $t('form.Search') }}</a-button>
+                        <a-button @click="resetSearch">{{ $t('form.Reset') }}</a-button>
+                    </a-space>
+                </a-form-item>
+            </a-form>
+        </div>
+
+        <a-table row-key="id" :data="dataSource" :columns="columns" :pagination="pagination"
+            :row-selection="rowSelection" v-model:selectedKeys="selectedKeys" :scroll="{ x: 'auto' }">
+            <template #id="{ record }">
+                <!-- 设置价格 -->
+                <a-popconfirm :content="$t('lotCard.confirmTitleOrder')" :ok-text="$t('form.Confirm')"
+                    :cancel-text="$t('form.Cancel')" @ok="handleprice(record)">
+                    <a class="a-link" href="javascript:;" style="margin-right: 1rem">{{
+                        $t('lotCard.titleOrder') }}</a>
+                </a-popconfirm>
+                <!-- 删除 -->
+                <a-popconfirm :content="$t('lotCard.confirmTitleCancelOrder')" :ok-text="$t('form.Confirm')"
+                    :cancel-text="$t('form.Cancel')" @ok="handleDel(record)">
+                    <a class="a-link" href="javascript:;" style="margin-right: 1rem">{{ $t('lotCard.titleCancelOrder')
+                        }}</a>
+                </a-popconfirm>
+            </template>
+
+        </a-table>
+
+
+        <!-- 弹框 -->
+        <a-modal :title="typeCurrent == 1 ? '添加' : '修改'" v-model:visible="visible" @onCancel="resetForm" centered
+            :maskClosable="false" :footer="null">
+            <a-form ref="formRef" :rules="rules" :model="formState" @submit="handleSubmit">
+                <a-form-item :label="$t('tariffManagement.simDataPlanId')" field="sim_data_plan_id">
+                    <a-input v-model="formState.sim_data_plan_id" />
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.label')" field="label">
+                    <a-input v-model="formState.label" />
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.userId')" field="user_id">
+                    <a-input v-model="formState.user_id" />
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.source')" field="source">
+                    <a-select v-model="formState.source">
+                        <a-option v-for=" item in sourceList" :key="item.id" :value="item.value">{{ item.label
+                            }}</a-option>
+                    </a-select>
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.trafficType')" field="traffic_type">
+                    <a-select v-model="formState.traffic_type">
+                        <a-option v-for=" item in trafficList" :key="item.id" :value="item.value">{{ item.label
+                            }}</a-option>
+                    </a-select>
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.billingType')" field="billing_type">
+                    <a-select v-model="formState.billing_type">
+                        <a-option v-for=" item in typeList" :key="item.id" :value="item.value">{{ item.label
+                            }}</a-option>
+                    </a-select>
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.bagSize')" field="bag_size">
+                    <a-input v-model="formState.bag_size" />
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.billingCycle')" field="billing_cycle">
+                    <a-select v-model="formState.billing_cycle">
+                        <a-option v-for=" item in cycleist" :key="item.id" :value="item.value">{{ item.label
+                            }}</a-option>
+                    </a-select>
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.billingMethod')" field="billing_method">
+                    <a-input v-model="formState.billing_method" />
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.settlementCycle')" field="settlement_cycle">
+                    <a-input v-model="formState.settlement_cycle" />
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.pricing')" field="pricing">
+                    <a-input v-model="formState.pricing" />
+                </a-form-item>
+                <a-form-item :label="$t('tariffManagement.currency')" field="currency">
+                    <a-input v-model="formState.currency" />
+                </a-form-item>
+                <a-form-item>
+                    <a-button type="primary" html-type="submit" style="margin-right: 10px;">确定</a-button>
+                    <a-button @click="resetForm">取消</a-button>
+                </a-form-item>
+            </a-form>
+        </a-modal>
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive, getCurrentInstance, nextTick } from "vue";
+import { useRoute } from "vue-router";
+import { columns } from "./config";
+import { Message, Notification } from '@arco-design/web-vue'
+import { deleteTariff, updateTariff, addTariff, tariffList } from "@/api/path/tariffManagement.api"
+import { enum_dict } from "@/hooks/enum";
+import { useSystemStore } from '@/store/modules/systemStore'
+
+const useSystem = useSystemStore()
+
+const { proxy } = getCurrentInstance()
+const formRef = ref()
+const searchForm = ref({
+    "simDataPlanId": "",
+    "is_Refuel": "",
+    "refuelingId": "",
+    "dataBundleId": "",
+    "quantity": 0,
+    "ICCID": "",
+    "sendLang": "",
+    "price": "",
+    "totalAmount": "",
+    "currency": "",
+    "userId": 0,
+    "current": 1,
+    "size": 10
+});
+
+
+
+const dicId = ref('');
+const dataSource = ref([]);
+const route = useRoute();
+const pagination = ref({
+    total: 0,
+    pageSize: 10,
+    current: 1,
+})
+
+
+
+
+const rowSelection = reactive({
+    type: 'checkbox',
+    showCheckedAll: true,
+    onlyCurrent: false,
+});
+const selectedKeys = ref([])
+
+const dialogRef = ref()
+
+
+const intData = async () => {
+    const param = {
+        current: pagination.value.current,
+        size: pagination.value.pageSize,
+        ...searchForm.value,
+    }
+    const { data } = await tariffList(param)
+    dataSource.value = data.records || []
+    pagination.value.total = data.total
+}
+
+
+
+
+// 设置价格
+const handleprice = async (info) => {
+}
+
+// 删除
+const handleDel = async (record) => {
+
+};
+
+//
+
+const handleSearch = () => {
+    formRef.value.validate((errors) => {
+        if (!errors) {
+            intData()
+        }
+    });
+}
+const resetSearch = () => {
+    proxy.$refs.formRef.resetFields()
+    intData()
+}
+
+
+
+
+// 弹窗数据-----------------------------------------------------------------
+const visible = ref(false);
+const typeCurrent = ref(null);
+const sourceList = ref([])
+const trafficList = ref([])
+const cycleist = ref([])
+const typeList = ref([])
+const formState = reactive({
+
+    // 资费名称(必填)
+    "label": "",
+    // 流量包ID(必填)
+    "sim_data_plan_id": "",
+    // 用户ID(必填)
+    "user_id": 0,
+    // 来源(必填)
+    "source": "",
+    // 流量类型(必填)
+    "traffic_type": "",
+    // 计费类型(必填)
+    "billing_type": "",
+    // 流量包Size(必填)
+    "bag_size": "",
+    // 计费周期(必填)
+    "billing_cycle": "",
+    // 计费方式(必填)
+    "billing_method": "",
+    // 结算周期(必填)
+    "settlement_cycle": "",
+    // 价格(必填)
+    "pricing": "",
+    // 币种(必填)
+    "currency": ""
+
+});
+
+const rules = {
+    label: [{ required: true, trigger: 'change', }],
+    sim_data_plan_id: [{ required: true, trigger: 'change', }],
+    user_id: [{ required: true, trigger: 'change', }],
+    source: [{ required: true, trigger: 'change', }],
+    traffic_type: [{ required: true, trigger: 'change', }],
+    billing_type: [{ required: true, trigger: 'change', }],
+    bag_size: [{ required: true, trigger: 'change', }],
+    billing_cycle: [{ required: true, trigger: 'change', }],
+    billing_method: [{ required: true, trigger: 'change', }],
+    settlement_cycle: [{ required: true, trigger: 'change', }],
+    pricing: [{ required: true, trigger: 'change', }],
+    currency: [{ required: true, trigger: 'change', }],
+};
+
+
+// 提交
+const handleSubmit = ({ values, errors }) => {
+
+
+}
+// 删除
+const deleteChange = (e) => {
+    dictionaryDelete({ id: e }).then(res => {
+        intData();
+    })
+}
+// 弹框
+const dictShowModel = (type, data) => {
+    typeCurrent.value = type;
+    visible.value = true;
+    if (type == 2) {
+        dicId.value = data.id;
+        formState.label = data.label;
+        formState.value = data.value;
+        formState.typeKey = data.type_key;
+        formState.typeLabel = data.type_label;
+        formState.remark = data.remark;
+    }
+}
+// 取消
+const resetForm = () => {
+    visible.value = false;
+    dicId.value = null;
+    formRef.value.resetFields();
+    Object.assign(formState, {
+        label: '',
+        value: '',
+        typeKey: '',
+        typeLabel: '',
+        remark: '',
+    });
+}
+
+// --------------------------------------------------------
+
+const handleDictValue = () => {
+    const dictList = JSON.parse(window.localStorage.getItem('dictList')) ?? []
+    sourceList.value = dictList.filter((item) => item.type_key == enum_dict.SOURCE)
+    trafficList.value = dictList.filter((item) => item.type_key == enum_dict.TRAFFICTYPE)
+    cycleist.value = dictList.filter((item) => item.type_key == enum_dict.BILLINGCYCLE)
+    typeList.value = dictList.filter((item) => item.type_key == enum_dict.BILLINGTYPE)
+}
+
+
+onMounted(() => {
+    handleDictValue()
+    // intData()
+})
+
+
+
+</script>
+
+<style scoped lang="less">
+.head-title-right {
+    .m-r-10 {
+        margin-right: 10px;
+    }
+
+}
+
+.search-section {
+    margin-top: 20px;
+    margin-bottom: 20px;
+}
+
+.container {
+    .head-title {
+        display: flex;
+        justify-content: space-between;
+    }
+
+    .form-row {
+        display: flex;
+
+        .form-row-col {
+            width: 25%;
+            display: flex;
+            align-items: center;
+
+            .form-row-label {
+                width: 120px;
+                text-align: right;
+            }
+        }
+    }
+}
+</style>