zhb 3 месяцев назад
Родитель
Сommit
5bcdfa381d
100 измененных файлов с 3232 добавлено и 14718 удалено
  1. 1 1
      components/cwg-header.vue
  2. 0 21
      pages.json
  3. 3 12
      pages/activities/components/ActivityCard.vue
  4. 632 0
      pages/activities/components/ActivityDialogs.vue
  5. 151 0
      pages/activities/components/DrawLotteryRaffle.vue
  6. 711 0
      pages/activities/composables/useActivityActions.ts
  7. 771 0
      pages/activities/composables/useActivityData.ts
  8. 550 0
      pages/activities/config/activityConfigs.ts
  9. 325 809
      pages/activities/index.vue
  10. 88 0
      pages/activities/types/activity.ts
  11. 0 1067
      pages/apply-record/components/ApplyRecord.vue
  12. 0 17
      pages/apply-record/detail.vue
  13. 0 274
      pages/apply-record/list.vue
  14. 0 474
      pages/card/apply.vue
  15. 0 304
      pages/card/components/CardHandle.vue
  16. 0 352
      pages/card/components/FirstApply.vue
  17. 0 1180
      pages/card/components/VirtualCard.vue
  18. 0 177
      pages/card/index.vue
  19. 0 527
      pages/card/operations.vue
  20. 0 328
      pages/card/select.vue
  21. 0 2
      pages/create-account/index.vue
  22. 0 2
      pages/customer/create-account.vue
  23. 0 18
      pages/mine/about.vue
  24. 0 282
      pages/mine/cog.vue
  25. 0 30
      pages/mine/help-detail.vue
  26. 0 155
      pages/mine/help.vue
  27. 0 434
      pages/recharge-record/components/DeductionList.vue
  28. 0 488
      pages/recharge-record/components/RechargeList.vue
  29. 0 507
      pages/recharge-record/components/TransactionList.vue
  30. 0 750
      pages/recharge-record/detail.vue
  31. 0 313
      pages/recharge-record/list.vue
  32. 0 226
      pages/wallet/balance.vue
  33. 0 387
      pages/wallet/components/DynamicForm.vue
  34. 0 499
      pages/wallet/components/GlobalList.vue
  35. 0 482
      pages/wallet/components/VaultodyList.vue
  36. 0 472
      pages/wallet/components/WithdrawList.vue
  37. 0 126
      pages/wallet/composable/useOrderFields.ts
  38. 0 765
      pages/wallet/global-detail.vue
  39. 0 268
      pages/wallet/global-list.vue
  40. 0 823
      pages/wallet/global-order.vue
  41. 0 489
      pages/wallet/index.vue
  42. 0 258
      pages/wallet/vaultody-list.vue
  43. 0 185
      pages/wallet/vaultody.vue
  44. 0 633
      pages/wallet/withdraw-detail.vue
  45. 0 258
      pages/wallet/withdraw-list.vue
  46. 0 323
      pages/wallet/withdraw.vue
  47. BIN
      static/images/1-1.png
  48. BIN
      static/images/1-2.png
  49. BIN
      static/images/1-3.png
  50. BIN
      static/images/1-4.png
  51. BIN
      static/images/1-5.png
  52. BIN
      static/images/1.png
  53. BIN
      static/images/10-bonus.webp
  54. BIN
      static/images/100-bonus.webp
  55. BIN
      static/images/2.png
  56. BIN
      static/images/2024-Paris-Olympics-3.jpg
  57. BIN
      static/images/23ActiveCn.jpg
  58. BIN
      static/images/23ActiveCn1.jpg
  59. BIN
      static/images/23ActiveEn.jpg
  60. BIN
      static/images/3.png
  61. BIN
      static/images/4.png
  62. BIN
      static/images/5-1.png
  63. BIN
      static/images/5-2.png
  64. BIN
      static/images/5-3.png
  65. BIN
      static/images/5-4.png
  66. BIN
      static/images/5.png
  67. BIN
      static/images/6-01.png
  68. BIN
      static/images/6-02.png
  69. BIN
      static/images/6-03.png
  70. BIN
      static/images/6-04.png
  71. BIN
      static/images/AR.jpg
  72. BIN
      static/images/Android-mt5.png
  73. BIN
      static/images/CN.jpg
  74. BIN
      static/images/CWG_02.png
  75. BIN
      static/images/DE.jpg
  76. BIN
      static/images/EN.jpg
  77. BIN
      static/images/ES.jpg
  78. BIN
      static/images/FA.png
  79. BIN
      static/images/Indonesian.jpg
  80. BIN
      static/images/MS.jpg
  81. BIN
      static/images/MT4_android.png
  82. BIN
      static/images/MT4_ios.png
  83. BIN
      static/images/MT5_android.png
  84. BIN
      static/images/MT5_ios.png
  85. BIN
      static/images/MTBG.jpg
  86. BIN
      static/images/PT.png
  87. BIN
      static/images/Secure_01.png
  88. BIN
      static/images/Secure_02.png
  89. BIN
      static/images/Secure_03.png
  90. BIN
      static/images/TH.jpg
  91. BIN
      static/images/TR.png
  92. BIN
      static/images/Trading-Reward-2.jpg
  93. BIN
      static/images/UB.jpg
  94. BIN
      static/images/VN.jpg
  95. BIN
      static/images/acc_logo.png
  96. BIN
      static/images/android-MT4.png
  97. BIN
      static/images/android-os-3-72.png
  98. BIN
      static/images/apple-os-1-48.png
  99. BIN
      static/images/apple-os-3-72.png
  100. BIN
      static/images/apply-record-1.png

+ 1 - 1
components/cwg-header.vue

@@ -27,7 +27,7 @@ const showBack = computed(() => {
   // 不显示返回按钮的页面
   const noBackPages = [
     '/',
-    '/pages/card/index',
+    '/pages/customer/index',
     '/pages/wallet/index',
     '/pages/mine/index',
     '/pages/login/index'

+ 0 - 21
pages.json

@@ -59,27 +59,6 @@
         "navigationStyle": "custom"
       }
     },
-    {
-      "path": "pages/mine/help",
-      "style": {
-        "navigationBarTitleText": "",
-        "navigationStyle": "custom"
-      }
-    },
-    {
-      "path": "pages/mine/help-detail",
-      "style": {
-        "navigationBarTitleText": "",
-        "navigationStyle": "custom"
-      }
-    },
-    {
-      "path": "pages/mine/cog",
-      "style": {
-        "navigationBarTitleText": "",
-        "navigationStyle": "custom"
-      }
-    },
     {
       "path": "pages/mine/pay-password",
       "style": {

+ 3 - 12
pages/activities/components/ActivityCard.vue

@@ -27,18 +27,15 @@
             <!-- 按钮区域 -->
             <view class="bottom">
                 <template v-for="(btn, index) in config.buttons" :key="index">
-                    <!-- 动态条件按钮 -->
                     <span v-if="shouldShowButton(btn)" :class="['btn', getButtonType(btn)]" @click="handleButtonClick(btn)">
                         {{ t(btn.text) }}
-                        <template v-if="btn.suffix && state && state[btn.suffix]">
+                        <template v-if="btn.suffix && state[btn.suffix]">
                             {{ state[btn.suffix] }}
                         </template>
                         <template v-if="btn.suffixText">
                             {{ t(btn.suffixText) }}
                         </template>
                     </span>
-
-                    <!-- else 情况 -->
                     <span v-else-if="btn.elseType && btn.condition" :class="['btn', btn.elseType]">
                         {{ t(btn.text) }}
                     </span>
@@ -50,9 +47,9 @@
 
 <script setup lang="ts">
 import { computed } from 'vue'
-import { useI18n } from "vue-i18n"
+import { useI18n } from 'vue-i18n'
 
-const { t, locale } = useI18n()
+const { t, locale} = useI18n()
 
 const props = defineProps<{
     config: any
@@ -73,14 +70,10 @@ const imageSrc = computed(() => {
 // 判断按钮是否显示
 const shouldShowButton = (btn: any): boolean => {
     if (!btn.condition) return true
-    
-    // 从 state 中获取值
     if (!props.state) return false
     
     try {
-        // 解析条件表达式
         const conditionStr = btn.condition
-        // 替换变量为实际值
         const evalStr = conditionStr.replace(/([a-zA-Z_][a-zA-Z0-9_.]*)/g, (match) => {
             if (match.includes('.')) {
                 const parts = match.split('.')
@@ -92,8 +85,6 @@ const shouldShowButton = (btn: any): boolean => {
             }
             return JSON.stringify(props.state[match])
         })
-        
-        // 使用 Function 构造函数安全评估
         const fn = new Function(`return ${evalStr}`)
         return fn()
     } catch (error) {

+ 632 - 0
pages/activities/components/ActivityDialogs.vue

@@ -0,0 +1,632 @@
+<template>
+    <view>
+        <!-- 盈利转换弹窗 -->
+        <uni-popup ref="dialogChinaUnionPayPopup" type="center" :mask-click="false">
+            <view class="popup-content">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('common.tip') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogChinaUnionPay')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <text class="message-text">{{ t('news_add_field1.activities.item11') }}</text>
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogChinaUnionPay')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('toTransformActive')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 盈利变现弹窗 -->
+        <uni-popup ref="dialogChinaUnionPay1Popup" type="center" :mask-click="false">
+            <view class="popup-content">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('common.tip') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogChinaUnionPay1')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <text class="message-text">{{ t('news_add_field1.activities.item12') }}</text>
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogChinaUnionPay1')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('toRealizationActive')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 活动过期弹窗 -->
+        <uni-popup ref="dialogChinaUnionPayJXPopup" type="center" :mask-click="false">
+            <view class="popup-content">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('common.tip') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogChinaUnionPayJX')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <text class="message-text">{{ t('news_add_field1.activitiesJX.item24') }}</text>
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogChinaUnionPayJX')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="closeDialog('dialogChinaUnionPayJX')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 23迎新活动申请弹窗 -->
+        <uni-popup ref="dialogDealResultPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('Custom.Activity.Apply') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogDealResult')"></uni-icons>
+                </view>
+                <scroll-view class="popup-body" scroll-y style="max-height: 600rpx;">
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Label.TradingAccount') }}</text>
+                        <picker mode="selector" :range="loginOptions" range-key="login" @change="onLoginChange('dialogDealResult', $event)">
+                            <view class="picker-value">{{ selectedLogin?.login || t('placeholder.choose') }}</view>
+                        </picker>
+                    </view>
+                </scroll-view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogDealResult')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('toApply23')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 23匠鑫活动申请弹窗 -->
+        <uni-popup ref="dialogDealResultJxPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('Custom.Activity.Apply') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogDealResultJx')"></uni-icons>
+                </view>
+                <scroll-view class="popup-body" scroll-y style="max-height: 600rpx;">
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Label.TradingAccount') }}</text>
+                        <picker mode="selector" :range="loginOptions" range-key="login" @change="onLoginChange('dialogDealResultJx', $event)">
+                            <view class="picker-value">{{ selectedJxLogin?.login || t('placeholder.choose') }}</view>
+                        </picker>
+                    </view>
+                </scroll-view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogDealResultJx')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('toApply23Jx')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 23匠鑫VIP活动申请弹窗 -->
+        <uni-popup ref="dialogDealResultJxVipPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('Custom.Activity.Apply') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogDealResultJxVip')"></uni-icons>
+                </view>
+                <scroll-view class="popup-body" scroll-y style="max-height: 600rpx;">
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Label.TradingAccount') }}</text>
+                        <picker mode="selector" :range="loginOptions" range-key="login" @change="onLoginChange('dialogDealResultJxVip', $event)">
+                            <view class="picker-value">{{ selectedJxVipLogin?.login || t('placeholder.choose') }}</view>
+                        </picker>
+                    </view>
+                </scroll-view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogDealResultJxVip')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('toApply23JxVip')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 交易大赛申请弹窗 -->
+        <uni-popup ref="dialogDealResultCptPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('Custom.Activity.Apply') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogDealResultCpt')"></uni-icons>
+                </view>
+                <scroll-view class="popup-body" scroll-y style="max-height: 800rpx;">
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Label.TradingAccount') }}</text>
+                        <picker mode="selector" :range="loginOptions" range-key="login" @change="onLoginChange('dialogDealResultCpt', $event)">
+                            <view class="picker-value">{{ selectedCptLogin?.login || t('placeholder.choose') }}</view>
+                        </picker>
+                    </view>
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Documentary.console.item20') }}</text>
+                        <input class="form-input" v-model="formData.dialogDealResultCpt_form.nickname" :placeholder="t('placeholder.input')" />
+                    </view>
+                    <view class="form-item">
+                        <text class="form-label">{{ t('news_add_field1.activitiesJYDS.item4_3') }}</text>
+                        <input class="form-input" v-model="formData.dialogDealResultCpt_form.recipient" :placeholder="t('placeholder.input')" />
+                    </view>
+                    <view class="form-item">
+                        <text class="form-label">{{ t('news_add_field1.activitiesJYDS.item4_2') }}</text>
+                        <input class="form-input" v-model="formData.dialogDealResultCpt_form.mobile" :placeholder="t('placeholder.input')" />
+                    </view>
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Shop.Address.DetailedAddress') }}</text>
+                        <input class="form-input" v-model="formData.dialogDealResultCpt_form.address" :placeholder="t('placeholder.input')" />
+                    </view>
+                    <view class="form-tip">{{ t('news_add_field1.activitiesJYDS.item4_4') }}</view>
+                </scroll-view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogDealResultCpt')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('toApplyCpt')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 24精英杯申请弹窗 -->
+        <uni-popup ref="dialogDealResultJxJYBPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('Custom.Activity.Apply') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogDealResultJxJYB')"></uni-icons>
+                </view>
+                <scroll-view class="popup-body" scroll-y style="max-height: 600rpx;">
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Label.TradingAccount') }}</text>
+                        <picker mode="selector" :range="loginOptions" range-key="login" @change="onLoginChange('dialogDealResultJxJYB', $event)">
+                            <view class="picker-value">{{ selectedJYBLogin?.login || t('placeholder.choose') }}</view>
+                        </picker>
+                    </view>
+                </scroll-view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogDealResultJxJYB')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('toApply24JYBVip')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 无忧交易申请弹窗 -->
+        <uni-popup ref="dialogDealResultNoWorriesPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('Custom.Activity.Apply') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogDealResultNoWorries')"></uni-icons>
+                </view>
+                <scroll-view class="popup-body" scroll-y style="max-height: 600rpx;">
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Label.TradingAccount') }}</text>
+                        <picker mode="selector" :range="loginOptions" range-key="login" @change="onLoginChange('dialogDealResultNoWorries', $event)">
+                            <view class="picker-value">{{ selectedNoWorriesLogin?.login || t('placeholder.choose') }}</view>
+                        </picker>
+                    </view>
+                </scroll-view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogDealResultNoWorries')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('toApplyNoWorries')">{{ t('news_add_field1.activitiesNoWorries.item6_1') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 无忧交易变现弹窗 -->
+        <uni-popup ref="dialogNoWorriesPopup" type="center" :mask-click="false">
+            <view class="popup-content">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('common.tip') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogNoWorries')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <text class="message-text">{{ t('news_add_field1.activitiesNoWorries.item7') }}</text>
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogNoWorries')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('realizationNoWorries')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 无忧交易申请成功弹窗 -->
+        <uni-popup ref="dialogNoWorriesApplyPopup" type="center" :mask-click="false">
+            <view class="popup-content">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('common.success') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogNoWorriesApply')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <text class="message-text">{{ t('news_add_field1.activitiesNoWorries.item6') }}</text>
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-confirm" type="primary" @click="closeDialog('dialogNoWorriesApply')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 新任务提示弹窗 -->
+        <uni-popup ref="dialogNewTaskPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('wallet.item16') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogNewTask')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <view class="task-info">
+                        <text>{{ t('wallet.item17') }}{{ newTaskList?.endTime }}</text>
+                        <text>{{ t('wallet.item18') }}{{ newTaskList?.tradeVolume }}</text>
+                        <text>{{ t('wallet.item19') }}{{ newTaskList?.raffleNumber }}</text>
+                        <text>{{ t('wallet.item20') }}</text>
+                    </view>
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogNewTask')">{{ t('Home.msg.item3') }}</button>
+                    <button class="btn-confirm" type="primary" @click="closeDialog('dialogNewTask')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 抽奖弹窗 -->
+        <uni-popup ref="dialogNewTaskDrawPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 700rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('wallet.item65') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogNewTaskDraw')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <DrawLotteryRaffle :curLuckyDrawTimesF="luckyDrawsNumber" @draw-complete="handleDrawComplete" />
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogNewTaskDraw')">{{ t('Home.msg.item3') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- Surplus活动弹窗 -->
+        <uni-popup ref="dialogSurplusActivityPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('surplusList.item1') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogSurplusActivity')"></uni-icons>
+                </view>
+                <scroll-view class="popup-body" scroll-y style="max-height: 800rpx;">
+                    <view class="form-item">
+                        <text class="form-label">{{ t('Custom.Deposit.Title1') }}:</text>
+                        <picker mode="selector" :range="loginOptions1" range-key="login" @change="onAccountChange">
+                            <view class="picker-value">{{ selectedAccount?.login || t('placeholder.choose') }}</view>
+                        </picker>
+                    </view>
+                    <view v-if="selectedAccount" class="form-item">
+                        <text class="form-label">{{ t('surplusList.item3') }}:</text>
+                        <picker mode="selector" :range="surplusOptions.options" range-key="label" @change="onSurplusChange">
+                            <view class="picker-value">{{ selectedSurplusLabel || t('placeholder.choose') }}</view>
+                        </picker>
+                    </view>
+                </scroll-view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogSurplusActivity')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('confirmSurplusActivity')" 
+                        :disabled="!selectedAccount || !selectedSurplusValue">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 月赏礼遇弹窗 -->
+        <uni-popup ref="dialogSurplusActivity1Popup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('MonthlyActivities.item1') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('dialogSurplusActivity1')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <text class="message-text" style="font-size: 32rpx; font-weight: bold;">{{ t('MonthlyActivities.item8') }}</text>
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('dialogSurplusActivity1')">{{ t('Btn.Cancel') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('confirmSurplusActivity1')">{{ t('Btn.Confirm') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+
+        <!-- 收益模拟器弹窗 -->
+        <uni-popup ref="openCalculatorFlagPopup" type="center" :mask-click="false">
+            <view class="popup-content" style="width: 650rpx;">
+                <view class="popup-header">
+                    <text class="popup-title">{{ t('news_add_field1.NewYear24.item4') }}</text>
+                    <uni-icons type="closeempty" size="20" color="#999" @click="closeDialog('openCalculatorFlag')"></uni-icons>
+                </view>
+                <view class="popup-body">
+                    <view class="calculator-item">
+                        <text class="calculator-label">{{ t('news_add_field1.NewYear24.item5') }}</text>
+                        <input class="calculator-input" type="digit" v-model="balanceInput" :placeholder="t('placeholder.input')" />
+                    </view>
+                    <view class="calculator-result">
+                        <text>{{ t('news_add_field1.NewYear24.item6') }}</text>
+                        <text class="red">${{ balanceResult }}</text>
+                        <text>{{ t('news_add_field1.NewYear24.item7') }}</text>
+                        <text class="red">${{ incomeResult }}</text>
+                        <text>{{ t('news_add_field1.NewYear24.item8') }}</text>
+                    </view>
+                </view>
+                <view class="popup-footer">
+                    <button class="btn-cancel" @click="closeDialog('openCalculatorFlag')">{{ t('news_add_field1.NewYear24.item8_2') }}</button>
+                    <button class="btn-confirm" type="primary" @click="handleConfirm('calculateIncome')">{{ t('news_add_field1.NewYear24.item8_1') }}</button>
+                </view>
+            </view>
+        </uni-popup>
+    </view>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, watch } from 'vue'
+import { useI18n } from 'vue-i18n'
+import DrawLotteryRaffle from './DrawLotteryRaffle.vue'
+
+const { t } = useI18n()
+
+const props = defineProps<{
+    visible: Record<string, any>
+    formData: any
+    loginOptions: any[]
+    loginOptions1?: any[]
+    surplusOptions: {
+        options: any[]
+        loading: boolean
+    }
+    newTaskList?: any
+    luckyDrawsNumber?: string
+}>()
+
+const emit = defineEmits(['update:visible', 'action'])
+
+// 弹窗引用
+const popupRefs: Record<string, any> = {}
+
+// 选中的登录账号
+const selectedLogin = computed(() => {
+    const login = props.formData.dialogDealResult_form?.login
+    return props.loginOptions.find(item => item.login === login)
+})
+
+const selectedJxLogin = computed(() => {
+    const login = props.formData.dialogDealResultJx_form?.login
+    return props.loginOptions.find(item => item.login === login)
+})
+
+const selectedJxVipLogin = computed(() => {
+    const login = props.formData.dialogDealResultJx_formVip?.login
+    return props.loginOptions.find(item => item.login === login)
+})
+
+const selectedCptLogin = computed(() => {
+    const login = props.formData.dialogDealResultCpt_form?.login
+    return props.loginOptions.find(item => item.login === login)
+})
+
+const selectedJYBLogin = computed(() => {
+    const login = props.formData.dialogDealResultJx_formJYB?.login
+    return props.loginOptions.find(item => item.login === login)
+})
+
+const selectedNoWorriesLogin = computed(() => {
+    const login = props.formData.dialogDeal_formNoWorries?.login
+    return props.loginOptions.find(item => item.login === login)
+})
+
+// 选中的账户
+const selectedAccount = computed(() => props.formData.selectedAccount)
+const selectedSurplusValue = computed(() => props.formData.selectedSurplusActivity)
+const selectedSurplusLabel = computed(() => {
+    const option = props.surplusOptions.options.find(item => item.value === selectedSurplusValue.value)
+    return option?.label || ''
+})
+
+// 收益模拟器
+const balanceInput = ref('')
+const balanceResult = ref(0)
+const incomeResult = ref(0)
+
+// 监听弹窗可见性
+watch(() => props.visible, (newVal) => {
+    Object.entries(newVal).forEach(([key, value]) => {
+        const popup = popupRefs[key + 'Popup']
+        if (popup) {
+            if (value) {
+                popup.open()
+            } else {
+                popup.close()
+            }
+        }
+    })
+}, { deep: true })
+
+// 关闭弹窗
+const closeDialog = (key: string) => {
+    emit('update:visible', key, false)
+}
+
+// 登录账号选择
+const onLoginChange = (type: string, e: any) => {
+    const index = e.detail.value
+    const login = props.loginOptions[index]?.login
+    
+    switch (type) {
+        case 'dialogDealResult':
+            props.formData.dialogDealResult_form.login = login
+            break
+        case 'dialogDealResultJx':
+            props.formData.dialogDealResultJx_form.login = login
+            break
+        case 'dialogDealResultJxVip':
+            props.formData.dialogDealResultJx_formVip.login = login
+            break
+        case 'dialogDealResultCpt':
+            props.formData.dialogDealResultCpt_form.login = login
+            break
+        case 'dialogDealResultJxJYB':
+            props.formData.dialogDealResultJx_formJYB.login = login
+            break
+        case 'dialogDealResultNoWorries':
+            props.formData.dialogDeal_formNoWorries.login = login
+            break
+    }
+}
+
+// 账户选择
+const onAccountChange = (e: any) => {
+    const index = e.detail.value
+    const account = props.loginOptions1?.[index]
+    emit('action', 'accountChange', account)
+}
+
+// Surplus选项选择
+const onSurplusChange = (e: any) => {
+    const index = e.detail.value
+    const option = props.surplusOptions.options[index]
+    emit('action', 'surplusChange', option)
+}
+
+// 确认操作
+const handleConfirm = (action: string) => {
+    emit('action', action)
+}
+
+// 抽奖完成
+const handleDrawComplete = (result: any) => {
+    emit('action', 'drawComplete', result)
+}
+
+// 设置弹窗引用
+const setPopupRef = (el: any, key: string) => {
+    if (el) {
+        popupRefs[key] = el
+    }
+}
+</script>
+
+<style scoped lang="scss">
+.popup-content {
+    width: 580rpx;
+    background-color: #fff;
+    border-radius: 16rpx;
+    overflow: hidden;
+
+    .popup-header {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        padding: 30rpx;
+        border-bottom: 1rpx solid #e5e5e5;
+
+        .popup-title {
+            font-size: 32rpx;
+            font-weight: bold;
+            color: #333;
+        }
+    }
+
+    .popup-body {
+        padding: 30rpx;
+
+        .message-text {
+            display: block;
+            font-size: 28rpx;
+            line-height: 1.6;
+            color: #666;
+            text-align: center;
+        }
+
+        .form-item {
+            margin-bottom: 30rpx;
+
+            .form-label {
+                display: block;
+                margin-bottom: 16rpx;
+                font-size: 28rpx;
+                color: #666;
+            }
+
+            .form-input {
+                padding: 20rpx;
+                border: 1rpx solid #e5e5e5;
+                border-radius: 8rpx;
+                font-size: 28rpx;
+                width: 100%;
+                box-sizing: border-box;
+            }
+
+            .picker-value {
+                padding: 20rpx;
+                border: 1rpx solid #e5e5e5;
+                border-radius: 8rpx;
+                font-size: 28rpx;
+                color: #333;
+            }
+        }
+
+        .form-tip {
+            font-size: 24rpx;
+            color: #999;
+            margin-top: 10rpx;
+        }
+
+        .task-info {
+            display: flex;
+            flex-direction: column;
+            gap: 20rpx;
+            font-size: 28rpx;
+            line-height: 1.6;
+            color: #666;
+        }
+
+        .calculator-item {
+            margin-bottom: 30rpx;
+
+            .calculator-label {
+                display: block;
+                margin-bottom: 16rpx;
+                font-size: 28rpx;
+                color: #666;
+            }
+
+            .calculator-input {
+                padding: 20rpx;
+                border: 1rpx solid #e5e5e5;
+                border-radius: 8rpx;
+                font-size: 28rpx;
+                width: 100%;
+                box-sizing: border-box;
+            }
+        }
+
+        .calculator-result {
+            font-size: 28rpx;
+            line-height: 1.8;
+            color: #666;
+
+            .red {
+                color: #ff4d4f;
+                font-weight: bold;
+            }
+        }
+    }
+
+    .popup-footer {
+        display: flex;
+        padding: 30rpx;
+        border-top: 1rpx solid #e5e5e5;
+
+        button {
+            flex: 1;
+            margin: 0 10rpx;
+            height: 80rpx;
+            line-height: 80rpx;
+            font-size: 28rpx;
+            border-radius: 8rpx;
+
+            &.btn-cancel {
+                background-color: #f5f5f5;
+                color: #666;
+            }
+
+            &.btn-confirm {
+                background-color: #007aff;
+                color: #fff;
+
+                &:disabled {
+                    opacity: 0.5;
+                }
+            }
+        }
+    }
+}
+</style>

+ 151 - 0
pages/activities/components/DrawLotteryRaffle.vue

@@ -0,0 +1,151 @@
+<template>
+    <view class="draw-lottery">
+        <view class="title">{{ t('wallet.item65') }}</view>
+        <view class="times">{{ t('wallet.item10') }}{{ curLuckyDrawTimesF }}{{ t('wallet.item11') }}</view>
+
+        <view class="lottery-grid">
+            <view v-for="(item, index) in lotteryList" :key="index" class="lottery-item" :class="{ active: drawIndex === index }">
+                <image :src="item.icon" mode="aspectFill" />
+                <text>{{ item.name }}</text>
+            </view>
+        </view>
+
+        <button class="draw-btn" type="primary" :disabled="curLuckyDrawTimesF <= 0 || drawing" @click="startDraw">
+            {{ drawing ? t('common.drawing') : t('wallet.item66') }}
+        </button>
+
+        <view v-if="drawResult" class="draw-result">
+            <text>{{ t('wallet.item67') }}: {{ drawResult.name }}</text>
+        </view>
+    </view>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()
+
+const props = defineProps<{
+    curLuckyDrawTimesF: string | number
+}>()
+
+const emit = defineEmits(['draw-complete'])
+
+const lotteryList = ref([
+    { name: '$10', icon: '/static/images/lottery/10.png' },
+    { name: '$20', icon: '/static/images/lottery/20.png' },
+    { name: '$50', icon: '/static/images/lottery/50.png' },
+    { name: '$100', icon: '/static/images/lottery/100.png' },
+    { name: '$200', icon: '/static/images/lottery/200.png' },
+    { name: '$500', icon: '/static/images/lottery/500.png' },
+    { name: '$1000', icon: '/static/images/lottery/1000.png' },
+    { name: t('wallet.item68'), icon: '/static/images/lottery/thanks.png' }
+])
+
+const drawIndex = ref(-1)
+const drawing = ref(false)
+const drawResult = ref<any>(null)
+
+const startDraw = () => {
+    if (drawing.value) return
+
+    drawing.value = true
+    drawResult.value = null
+    let count = 0
+    const maxCount = 20
+
+    const interval = setInterval(() => {
+        drawIndex.value = Math.floor(Math.random() * lotteryList.value.length)
+        count++
+
+        if (count >= maxCount) {
+            clearInterval(interval)
+            drawing.value = false
+            const result = lotteryList.value[drawIndex.value]
+            drawResult.value = result
+            emit('draw-complete', result)
+        }
+    }, 100)
+}
+</script>
+
+<style scoped lang="scss">
+.draw-lottery {
+    padding: 20rpx;
+
+    .title {
+        font-size: 32rpx;
+        font-weight: bold;
+        color: #333;
+        text-align: center;
+        margin-bottom: 20rpx;
+    }
+
+    .times {
+        font-size: 28rpx;
+        color: #666;
+        text-align: center;
+        margin-bottom: 40rpx;
+    }
+
+    .lottery-grid {
+        display: grid;
+        grid-template-columns: repeat(4, 1fr);
+        gap: 20rpx;
+        margin-bottom: 40rpx;
+
+        .lottery-item {
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            padding: 20rpx;
+            background-color: #f5f5f5;
+            border-radius: 16rpx;
+            transition: all 0.3s;
+
+            image {
+                width: 80rpx;
+                height: 80rpx;
+                margin-bottom: 10rpx;
+            }
+
+            text {
+                font-size: 24rpx;
+                color: #666;
+            }
+
+            &.active {
+                transform: scale(1.1);
+                background-color: #ffd700;
+                box-shadow: 0 0 20rpx rgba(255, 215, 0, 0.5);
+
+                text {
+                    color: #333;
+                    font-weight: bold;
+                }
+            }
+        }
+    }
+
+    .draw-btn {
+        width: 100%;
+        height: 80rpx;
+        line-height: 80rpx;
+        font-size: 28rpx;
+        border-radius: 40rpx;
+        margin-bottom: 30rpx;
+
+        &[disabled] {
+            opacity: 0.5;
+        }
+    }
+
+    .draw-result {
+        text-align: center;
+        font-size: 28rpx;
+        color: #ff4d4f;
+        font-weight: bold;
+    }
+}
+</style>

+ 711 - 0
pages/activities/composables/useActivityActions.ts

@@ -0,0 +1,711 @@
+import { ref } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { activityApi } from '@/service/activity'
+import Config from '@/config/index'
+import type { AccountInfo } from '../types/activity'
+
+const { Code, Host80 } = Config
+
+export function useActivityActions(
+    activityState: any,
+    loginOptions: any,
+    tableDataCptFlagCode: any,
+    refreshCallback?: () => void
+) {
+    const { t, locale} = useI18n()
+
+    // ==================== 弹窗状态 ====================
+    const dialogChinaUnionPay = ref(false)
+    const dialogChinaUnionPay1 = ref(false)
+    const dialogChinaUnionPayJX = ref(false)
+    const dialogDealResult = ref(false)
+    const dialogDealResultJx = ref(false)
+    const dialogDealResultJxVip = ref(false)
+    const dialogDealResultCpt = ref(false)
+    const dialogDealResultJxJYB = ref(false)
+    const dialogDealResultNoWorries = ref(false)
+    const dialogNoWorries = ref(false)
+    const dialogNoWorriesApply = ref(false)
+    const dialogNewTask = ref(false)
+    const dialogNewTaskDraw = ref(false)
+    const dialogSurplusActivity = ref(false)
+    const dialogSurplusActivity1 = ref(false)
+    const dialogInfoTradingAdd = ref(false)
+    const openCalculatorFlag = ref(false)
+
+    // ==================== 表单数据 ====================
+    const dialogDealResult_form = ref({ login: '' })
+    const dialogDealResultJx_form = ref({ login: '' })
+    const dialogDealResultJx_formVip = ref({ login: '' })
+    const dialogDealResultJx_formJYB = ref({ login: '' })
+    const dialogDealResultCpt_form = ref({
+        login: '',
+        address: '',
+        cptId: '',
+        mobile: '',
+        nickname: '',
+        recipient: ''
+    })
+    const dialogDeal_formNoWorries = ref({ login: '' })
+
+    // Surplus活动相关
+    const selectedAccount = ref<AccountInfo | null>(null)
+    const valueInfo = ref('')
+    const surplusActivityOptions = ref<any[]>([])
+    const surplusActivityLoading = ref(false)
+    const selectedSurplusActivity = ref('')
+
+    // ==================== 页面跳转 ====================
+    const toSingle = (id: string, listID?: string) => {
+        const specialIds = [
+            '20zj', '23yx', '23jx', '23nz', '23nzTwo', '23jxVip',
+            '23xinjia', '23jnhcj', '23nz_zx', '24JYB', 'NoWorries', 'NewYear24'
+        ]
+
+        if (specialIds.includes(id)) {
+            let query: any = { id: '', type: 1, active: id }
+
+            if (id === '23jx' && activityState.tableData3) {
+                query = {
+                    ...query,
+                    data1: activityState.tableData3.show ? activityState.tableData3.activityStartTime : activityState.tableData3.showActivityStartTime,
+                    data2: activityState.tableData3.show ? activityState.tableData3.activityEndTime : activityState.tableData3.showActivityEndTime,
+                    data3: activityState.tableData3.show ? activityState.tableData3.applicationStartTime : activityState.tableData3.showApplicationStartTime,
+                    data4: activityState.tableData3.show ? activityState.tableData3.applicationEndTime : activityState.tableData3.showApplicationEndTime
+                }
+            } else if (id === '23jxVip' && activityState.tableData3Vip) {
+                query = {
+                    ...query,
+                    data1: activityState.tableData3Vip.show ? activityState.tableData3Vip.activityStartTime : activityState.tableData3Vip.showActivityStartTime,
+                    data2: activityState.tableData3Vip.show ? activityState.tableData3Vip.activityEndTime : activityState.tableData3Vip.showActivityEndTime,
+                    data3: activityState.tableData3Vip.show ? activityState.tableData3Vip.applicationStartTime : activityState.tableData3Vip.showApplicationStartTime,
+                    data4: activityState.tableData3Vip.show ? activityState.tableData3Vip.applicationEndTime : activityState.tableData3Vip.showApplicationEndTime
+                }
+            } else if (id === '24JYB' && activityState.tableData3JYB) {
+                query = {
+                    ...query,
+                    data1: activityState.tableData3JYB.show ? activityState.tableData3JYB.activityStartTime : activityState.tableData3JYB.showActivityStartTime,
+                    data2: activityState.tableData3JYB.show ? activityState.tableData3JYB.activityEndTime : activityState.tableData3JYB.showActivityEndTime,
+                    data3: activityState.tableData3JYB.show ? activityState.tableData3JYB.applicationStartTime : activityState.tableData3JYB.showApplicationStartTime,
+                    data4: activityState.tableData3JYB.show ? activityState.tableData3JYB.applicationEndTime : activityState.tableData3JYB.showApplicationEndTime
+                }
+            } else if (id === '23nz' && activityState.tableData4) {
+                query = {
+                    ...query,
+                    data3: activityState.tableData4.show ? activityState.tableData4.applicationStartTime : activityState.tableData4.showApplicationStartTime,
+                    data4: activityState.tableData4.show ? activityState.tableData4.applicationEndTime : activityState.tableData4.showApplicationEndTime
+                }
+            } else if (id === '23nzTwo' && activityState.tableData4Two) {
+                query = {
+                    ...query,
+                    data3: activityState.tableData4Two.show ? activityState.tableData4Two.applicationStartTime : activityState.tableData4Two.showApplicationStartTime,
+                    data4: activityState.tableData4Two.show ? activityState.tableData4Two.applicationEndTime : activityState.tableData4Two.showApplicationEndTime
+                }
+            }
+
+            uni.navigateTo({
+                url: `/pages/activities/content?${new URLSearchParams(query).toString()}`
+            })
+        } else if (id === 'newList') {
+            uni.navigateTo({
+                url: `/pages/activities/content?id=${listID}&type=1&active=newList`
+            })
+        } else {
+            uni.navigateTo({
+                url: `/pages/activities/content?id=${id}&type=1`
+            })
+        }
+    }
+
+    const toDeposit = () => {
+        uni.navigateTo({ url: '/pages/customer/deposit' })
+    }
+
+    const toActivity24nianzhong = () => {
+        uni.navigateTo({ url: '/pages/customer/deposit' })
+    }
+
+    const toActivity24Trading = () => {
+        uni.navigateTo({ url: '/pages/customer/new' })
+    }
+
+    const toHistoryLuckyDraw = () => {
+        uni.navigateTo({ url: '/pages/customer/history/lucky/draw' })
+    }
+
+    const toTaskList = () => {
+        uni.navigateTo({ url: '/pages/customer/task/list' })
+    }
+
+    const goSurplusTaskList = () => {
+        uni.navigateTo({ url: '/pages/customer/surplus/list' })
+    }
+
+    const goMonthlyTaskList = () => {
+        uni.navigateTo({ url: '/pages/customer/monthly/list' })
+    }
+
+    const toDocumentary = () => {
+        uni.navigateTo({ url: '/pages/documentary/trading/center' })
+    }
+
+    const backActivity = () => {
+        uni.navigateBack()
+    }
+
+    // ==================== PDF打开 ====================
+    const openPdf = (pdfConfig: any) => {
+        let url = ''
+
+        if (typeof pdfConfig === 'string') {
+            url = pdfConfig
+        } else if (pdfConfig.dynamic) {
+            if (pdfConfig.langMap) {
+                url = pdfConfig.langMap[activityState.lang] || pdfConfig.langMap.default
+            } else if (pdfConfig.path) {
+                url = pdfConfig.path.replace('{lang}', activityState.lang)
+                if (pdfConfig.supportedLangs && !pdfConfig.supportedLangs.includes(activityState.lang)) {
+                    url = pdfConfig.fallback || url
+                }
+            }
+        } else if (pdfConfig.cn) {
+            url = pdfConfig[activityState.lang] || pdfConfig.default
+        }
+
+        if (url) {
+            // #ifdef H5
+            window.open(url, '_blank')
+            // #endif
+            // #ifdef APP-PLUS
+            plus.runtime.openURL(url)
+            // #endif
+            // #ifdef MP-WEIXIN
+            uni.downloadFile({
+                url: url,
+                success: (res) => {
+                    if (res.statusCode === 200) {
+                        uni.openDocument({
+                            filePath: res.tempFilePath,
+                            success: () => {
+                                uni.showToast({ title: t('common.success'), icon: 'success' })
+                            }
+                        })
+                    }
+                }
+            })
+            // #endif
+        }
+    }
+
+    // ==================== 活动操作 ====================
+    const toApply23Open = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity23Login({})
+            if (res.code === Code.StatusOK) {
+                loginOptions.value = res.data
+                dialogDealResult.value = true
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取账户列表失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    const toApply23 = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity23HundredApply({
+                login: dialogDealResult_form.value.login
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogDealResult.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('申请失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    const toApply23Cancel = () => {
+        dialogDealResult_form.value = { login: '' }
+        dialogDealResult.value = false
+    }
+
+    const toTransform = () => {
+        dialogChinaUnionPay.value = true
+    }
+
+    const toTransformActive = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity23HundredTransform({})
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogChinaUnionPay.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('转换失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    const toRealization = () => {
+        dialogChinaUnionPay1.value = true
+    }
+
+    const toRealizationActive = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity23HundredRealization({})
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogChinaUnionPay1.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('变现失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+    // 23匠鑫活动申请
+    const toApply23Jx = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity23JiangxinApply({
+                login: dialogDealResultJx_form.value.login
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogDealResultJx.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('申请失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    const toApply23JxCancel = () => {
+        dialogDealResultJx_form.value = { login: '' }
+        dialogDealResultJx.value = false
+    }
+
+    // 23匠鑫VIP活动申请
+    const toApply23JxVip = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity23JiangxinApplyVip({
+                login: dialogDealResultJx_formVip.value.login
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogDealResultJxVip.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('申请失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    const toApply23JxCancelVip = () => {
+        dialogDealResultJx_formVip.value = { login: '' }
+        dialogDealResultJxVip.value = false
+    }
+
+    // 匠鑫活动变现
+    const toRealizationJx = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity23JiangxinRealization({
+                id: activityState.tableData3?.id
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('变现失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    // 匠鑫VIP活动变现
+    const toRealizationJxVip = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity23JiangxinRealizationVip({
+                id: activityState.tableData3Vip?.id
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('变现失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    // 交易大赛申请
+    const toApplyCpt = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.ActivityCptInfoAdd({
+                cptId: activityState.tableDataCpt?.id,
+                login: dialogDealResultCpt_form.value.login,
+                nickname: dialogDealResultCpt_form.value.nickname,
+                mobile: dialogDealResultCpt_form.value.mobile,
+                address: dialogDealResultCpt_form.value.address,
+                recipient: dialogDealResultCpt_form.value.recipient
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogDealResultCpt.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('申请失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    const toApplyCptCancel = () => {
+        dialogDealResultCpt_form.value = {
+            login: '',
+            address: '',
+            cptId: '',
+            mobile: '',
+            nickname: '',
+            recipient: ''
+        }
+        dialogDealResultCpt.value = false
+    }
+
+    // 24精英杯申请
+    const toApply24JYBVip = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity24JYBApplyVip({
+                login: dialogDealResultJx_formJYB.value.login
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogDealResultJxJYB.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('申请失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    const toApply24JYBCancelVip = () => {
+        dialogDealResultJx_formJYB.value = { login: '' }
+        dialogDealResultJxJYB.value = false
+    }
+
+    // 24精英杯变现
+    const toRealization24JYBVip = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.Activity24JYBRealizationVip({
+                id: activityState.tableData3JYB?.id
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('变现失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    // 无忧交易申请
+    const toApplyNoWorries = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.ActivityNoWorriesApply({
+                login: dialogDeal_formNoWorries.value.login
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogDealResultNoWorries.value = false
+                dialogNoWorriesApply.value = true
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('申请失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    const toApplyNoWorriesCancel = () => {
+        dialogDeal_formNoWorries.value = { login: '' }
+        dialogDealResultNoWorries.value = false
+    }
+
+    // 无忧交易变现
+    const realizationNoWorries = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.ActivityNoWorriesRealization({
+                id: activityState.tableDataNoWorries?.id
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogNoWorries.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('变现失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    // Surplus活动相关
+    const getSurplusActivityOptions = async (account: any) => {
+        if (!account) return
+
+        surplusActivityLoading.value = true
+        try {
+            const res = await activityApi.ActivitySurplusDepositAmount({
+                login: account.login,
+                platform: account.platform
+            })
+            if (res.code === Code.StatusOK) {
+                surplusActivityOptions.value = res.data.map((item: any, index: number) => ({
+                    id: index,
+                    value: item.level,
+                    label: `${t('AmountLabel.item1')}: ${item.amount} | ${t('AmountLabel.item2')}: ${item.needVolume}`,
+                    giveFlag: item.giveFlag
+                }))
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取Surplus活动选项失败', error)
+        } finally {
+            surplusActivityLoading.value = false
+        }
+    }
+
+    const confirmSurplusActivity = async () => {
+        if (!selectedAccount.value || !selectedSurplusActivity.value) return
+
+        surplusActivityLoading.value = true
+        try {
+            const res = await activityApi.ActivitySurplusAdd({
+                login: selectedAccount.value.login,
+                platform: selectedAccount.value.platform,
+                level: selectedSurplusActivity.value
+            })
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogSurplusActivity.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('参加Surplus活动失败', error)
+        } finally {
+            surplusActivityLoading.value = false
+        }
+    }
+
+    const confirmSurplusActivity1 = async () => {
+        try {
+            const res = await activityApi.ActivityMonthlyAdd({})
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: res.msg, icon: 'success' })
+                dialogSurplusActivity1.value = false
+                if (refreshCallback) refreshCallback()
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('参加月赏礼遇活动失败', error)
+        }
+    }
+
+    // 现金嘉年华相关
+    const closedialogNewTaskDraw = () => {
+        dialogNewTaskDraw.value = false
+        if (refreshCallback) refreshCallback()
+    }
+
+    // 打开外部链接
+    const toOpenSingle = (pageAddress: string) => {
+        let link = pageAddress
+        if (tableDataCptFlagCode.value) {
+            if (pageAddress.indexOf('html?') === -1) {
+                link = pageAddress + '?code=' + tableDataCptFlagCode.value
+            } else if (pageAddress.indexOf('code') === -1) {
+                link = pageAddress + '&code=' + tableDataCptFlagCode.value
+            }
+        }
+
+        // #ifdef H5
+        window.open(Host80 + link, '_blank')
+        // #endif
+        // #ifndef H5
+        plus.runtime.openURL(Host80 + link)
+        // #endif
+    }
+
+    // 返现
+    const cashBack = async () => {
+        uni.showLoading({ title: t('common.loading') })
+        try {
+            const res = await activityApi.ActivityPercentageGiveApply({})
+            if (res.code === Code.StatusOK) {
+                uni.showToast({ title: t('Msg.Application'), icon: 'success' })
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('返现失败', error)
+        } finally {
+            uni.hideLoading()
+        }
+    }
+
+    // 收益计算
+    const calculateIncome = (balance: number, details: any[]) => {
+        let rate = 0
+        details.forEach((item) => {
+            if (balance > item.min && balance <= item.max) {
+                rate = item.rate
+            } else if (balance > item.min && balance >= item.max && item.max === 0) {
+                rate = item.rate
+            }
+        })
+        return ((balance * rate) / 100 / 365 * 30).toFixed(2)
+    }
+
+
+    return {
+        // 弹窗状态
+        dialogChinaUnionPay,
+        dialogChinaUnionPay1,
+        dialogChinaUnionPayJX,
+        dialogDealResult,
+        dialogDealResultJx,
+        dialogDealResultJxVip,
+        dialogDealResultCpt,
+        dialogDealResultJxJYB,
+        dialogDealResultNoWorries,
+        dialogNoWorries,
+        dialogNoWorriesApply,
+        dialogNewTask,
+        dialogNewTaskDraw,
+        dialogSurplusActivity,
+        dialogSurplusActivity1,
+        dialogInfoTradingAdd,
+        openCalculatorFlag,
+
+        // 表单数据
+        dialogDealResult_form,
+        dialogDealResultJx_form,
+        dialogDealResultJx_formVip,
+        dialogDealResultJx_formJYB,
+        dialogDealResultCpt_form,
+        dialogDeal_formNoWorries,
+        selectedAccount,
+        valueInfo,
+        surplusActivityOptions,
+        surplusActivityLoading,
+        selectedSurplusActivity,
+
+        // 页面跳转
+        toSingle,
+        toDeposit,
+        toActivity24nianzhong,
+        toActivity24Trading,
+        toHistoryLuckyDraw,
+        toTaskList,
+        goSurplusTaskList,
+        goMonthlyTaskList,
+        toDocumentary,
+        backActivity,
+
+        // PDF打开
+        openPdf,
+
+        // 活动操作
+        toApply23Open,
+        toApply23,
+        toApply23Cancel,
+        toTransform,
+        toTransformActive,
+        toRealization,
+        toRealizationActive,
+
+        toApply23Jx,
+        toApply23JxCancel,
+        toApply23JxVip,
+        toApply23JxCancelVip,
+        toRealizationJx,
+        toRealizationJxVip,
+        toApplyCpt,
+        toApplyCptCancel,
+        toApply24JYBVip,
+        toApply24JYBCancelVip,
+        toRealization24JYBVip,
+        toApplyNoWorries,
+        toApplyNoWorriesCancel,
+        realizationNoWorries,
+        getSurplusActivityOptions,
+        confirmSurplusActivity,
+        confirmSurplusActivity1,
+        closedialogNewTaskDraw,
+        toOpenSingle,
+        cashBack,
+        calculateIncome
+    }
+}

+ 771 - 0
pages/activities/composables/useActivityData.ts

@@ -0,0 +1,771 @@
+import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
+import { useI18n } from 'vue-i18n'
+import {activityApi} from '@/service/activity'
+import {customApi} from '@/service/custom'
+import Config from '@/config/index'
+import type { ActivityState, PagerInfo, AccountInfo } from '../types/activity'
+
+const { Code, Host80 } = Config
+
+// 国家列表
+const countries = [
+    "DZ", "AO", "BJ", "BW", "BF", "CM", "CG", "CD", "CI", "DJ", "EG", "ET", "GA", "GM", "GH", "GN", "KE",
+    "MG", "MW", "ML", "MR", "MA", "MZ", "NA", "NE", "NG", "RW", "SN", "SL", "SO", "ZA", "SS", "SD", "TZ",
+    "TG", "TN", "UG", "ZM", "ZW", "LS", "BH", "IR", "IQ", "IL", "JO", "KW", "LB", "OM", "PS", "QA", "SA",
+    "SY", "TR", "AE", "YE", "AR", "BO", "BR", "CL", "CO", "EC", "GY", "PY", "PE", "SR", "UY", "VE", "BZ",
+    "CR", "SV", "GT", "HN", "NI", "PA", "AU", "CA", "AL", "AD", "AM", "AT", "AZ", "BY", "BE", "BA", "BG",
+    "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "GE", "DE", "GR", "HU", "IS", "IE", "IT", "XK", "LV", "LI",
+    "LT", "LU", "MT", "MD", "MC", "ME", "NL", "MK", "NO", "PL", "PT", "RO", "RU", "SM", "RS", "SK", "SI",
+    "ES", "SE", "CH", "UA", "VA"
+]
+
+export function useActivityData() {
+    const { t, locale } = useI18n()
+    
+    // ==================== 用户信息 ====================
+    const userInfo = computed(() => {
+        try {
+            return JSON.parse(uni.getStorageSync('user') || '{}')
+        } catch {
+            return { customInfo: {} }
+        }
+    })
+    
+    const country = computed(() => userInfo.value.customInfo?.country || '')
+    const myCid = computed(() => userInfo.value.customInfo?.cId || '')
+    
+    // ==================== 加载状态 ====================
+    const pictLoading = ref(false)
+    const flag = ref(false)
+    
+    // ==================== 活动数据 ====================
+    const tableData = ref<any[]>([])
+    const tableDataGive = ref<any[]>([])
+    const singleData = ref<any>({})
+    
+    // 分页
+    const pagerInfo = ref<PagerInfo>({
+        row: 10,
+        current: 1,
+        pageTotal: 0,
+        rowTotal: 0
+    })
+    
+    // 账户列表
+    const loginOptions = ref<AccountInfo[]>([])
+    const loginOptions1 = ref<AccountInfo[]>([])
+    
+    // ==================== 活动特定状态 ====================
+    const activityState = reactive<ActivityState>({
+        tableDataNewYear24Flag: false,
+        tableDataNewYear24: {},
+        choujiaClose: false,
+        tableDataNoWorriesFlag: false,
+        tableDataNoWorries: false,
+        isRealizationNoWorries: 0,
+        standard: true,
+        tableData2Flag: false,
+        tableData2: false,
+        isTransform: 0,
+        isRealization: 0,
+        tableDataCptFlag: false,
+        tableDataCpt: {},
+        tableData3FlagJYB: false,
+        tableData3JYB: {},
+        isRealizationJxJYB: 0,
+        tableData3Flag: false,
+        tableData3: {},
+        isRealizationJx: 0,
+        tableData3FlagVip: false,
+        tableData3Vip: {},
+        isRealizationJxVip: 0,
+        tableData4Flag: false,
+        tableData4: {},
+        tableData4TwoFlag: false,
+        tableData4Two: {},
+        monthlyGive: false,
+        surplusGive: false,
+        newTask: false,
+        newTaskList: { endTime: '', tradeVolume: '', raffleNumber: '' },
+        LuckyDrawsNumber: '0',
+        isCountDown: '',
+        isCashBack: false,
+        anshiClose: true,
+        limitedStatus: null,
+        activityShowsInfo: null,
+        country: country.value,
+        lang: locale.value,
+        isGuoQin: false,
+        isSupportedCountry: false
+    })
+    
+    // 交易大赛参数
+    const tableDataCptFlagCode = ref('')
+    
+    // 新年庆典数据
+    const NewYear24DataBalance = ref('')
+    const NewYear24Data = ref({ balance: 0, income: 0 })
+    
+    // 定时器
+    const interval = ref<any>(null)
+    
+    // ==================== 计算属性 ====================
+    // 是否支持的国家
+    const isSupportedCountry = computed(() => {
+        return countries.includes(country.value)
+    })
+    
+    // 国庆节判断
+    const isGuoQin = computed(() => {
+        const startTime1 = '2024/10/01 00:00:00'
+        const endTime1 = '2024/10/07 23:59:59'
+        const timezone = 8
+        const offset_GMT = new Date().getTimezoneOffset()
+        const nowDate = new Date().getTime()
+        const now = new Date(nowDate + offset_GMT * 60 * 1000 + timezone * 60 * 60 * 1000).getTime()
+        const end = new Date(endTime1).getTime()
+        const start = new Date(startTime1).getTime()
+        return now > start && now < end
+    })
+    
+    // ==================== 工具函数 ====================
+    // 获取当前时间(带时区)
+    const getCurrentTime = (timezone: number = 2) => {
+        const offset_GMT = new Date().getTimezoneOffset()
+        const nowDate = new Date().getTime()
+        return new Date(nowDate + offset_GMT * 60 * 1000 + timezone * 60 * 60 * 1000)
+    }
+    
+    // 时间补0
+    const getzero = (time: number) => {
+        return time > 9 ? time : '0' + time
+    }
+    
+    // 时间格式转换
+    const timeConvert = (val: string) => {
+        if (!val) return ''
+        const datetime = new Date(val.replace(/-/g, '/'))
+        const year = datetime.getFullYear()
+        let month: any = datetime.getMonth() + 1
+        let date: any = datetime.getDate()
+        if (month < 10) month = '0' + month
+        if (date < 10) date = '0' + date
+        return year + '年' + month + '月' + date + '日'
+    }
+    
+    // 货币符号
+    const groupCurrency = (type: string) => {
+        const map: Record<string, string> = {
+            'GBP': ': £',
+            'USD': ': $',
+            'EUR': ': €',
+            'USC': ': ¢'
+        }
+        return map[type] || ': $'
+    }
+    
+    // 账户类型名称
+    const groupTypeName = (type: string) => {
+        const map: Record<string, string> = {
+            '1': 'AccountType.ClassicAccount',
+            '2': 'AccountType.SeniorAccount',
+            '3': 'AccountType.AgencyAccount',
+            '5': 'AccountType.SpeedAccount',
+            '6': 'AccountType.SpeedAccount',
+            '7': 'AccountType.StandardAccount',
+            '8': 'AccountType.CentAccount'
+        }
+        return map[type] ? t(map[type]) : ''
+    }
+    
+    // 判断活动是否在有效期内
+    const overdue = (startTime: string, endTime: string) => {
+        if (!startTime || !endTime) return false
+        const startTime1 = startTime.replace(/-/g, '/').split(' ')[0]
+        const endTime1 = endTime.replace(/-/g, '/').split(' ')[0]
+        const now = getCurrentTime(2).getTime()
+        const start = new Date(startTime1).getTime()
+        const end = new Date(endTime1).getTime()
+        return start < now && now < end
+    }
+    
+    // 判断匠鑫活动是否报名结束
+    const timeExpireJx = (endTime: string) => {
+        if (!endTime) return false
+        const endTime1 = endTime.replace(/-/g, '/').split(' ')[0]
+        const now = getCurrentTime(2).getTime()
+        const end = new Date(endTime1).getTime()
+        return now < end
+    }
+    
+    // 判断是否在9月30日之后
+    const isAfterSeptember30 = () => {
+        return true // 根据实际需求修改
+    }
+    
+    // ==================== API 请求函数 ====================
+    // 获取账户信息
+    const getDateList = async () => {
+        try {
+            const res = await customApi.DropdownlusActivityOptions({ platform: '' })
+            if (res.code == Code.StatusOK) {
+                loginOptions1.value = res.data
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取账户信息失败', error)
+        }
+    }
+    
+    // 获取活动列表
+    const searchFunc = async (page: number = 1) => {
+        if (flag.value) return
+        flag.value = true
+        pictLoading.value = true
+        
+        try {
+            const res = await activityApi.ActivityExtensionIist({
+                hot: '',
+                tag: 1,
+                lang: ['cn', 'zhHant'].includes(locale.value) ? 'cn' : 'en',
+                page: {
+                    current: page,
+                    row: pagerInfo.value.row
+                }
+            })
+            
+            if (res.code == Code.StatusOK) {
+                tableData.value = res.data
+                pagerInfo.value.rowTotal = res.page.rowTotal
+                pagerInfo.value.pageTotal = res.page.pageTotal
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取活动列表失败', error)
+        } finally {
+            pictLoading.value = false
+            flag.value = false
+        }
+    }
+    
+    // 获取赠送活动列表
+    const searchFunc1 = async () => {
+        pictLoading.value = true
+        try {
+            const res = await activityApi.ActivityExtensionGiveList({
+                page: {
+                    current: pagerInfo.value.current,
+                    row: pagerInfo.value.row
+                }
+            })
+            if (res.code == Code.StatusOK) {
+                tableDataGive.value = res.data
+                pagerInfo.value.rowTotal = res.page.rowTotal
+                pagerInfo.value.pageTotal = res.page.pageTotal
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取赠送活动列表失败', error)
+        } finally {
+            pictLoading.value = false
+        }
+    }
+    
+    // 获取单个活动详情
+    const getSingle = async (id: string) => {
+        try {
+            const res = await activityApi.ActivitySingle({ id })
+            if (res.code == Code.StatusOK) {
+                singleData.value = res.data
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取活动详情失败', error)
+        }
+    }
+    
+    // 获取赠送活动详情
+    const getSingle1 = async (id: string) => {
+        try {
+            const res = await activityApi.ActivityExtensionGiveSingle({ id })
+            if (res.code == Code.StatusOK) {
+                singleData.value = res.data
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取赠送活动详情失败', error)
+        }
+    }
+    
+    // 2023迎新活动数据
+    const Activity23HundredInfo = async () => {
+        try {
+            const res = await activityApi.Activity23HundredInfo({})
+            if (res.code == Code.StatusOK) {
+                activityState.tableData2 = res.data
+                if (typeof activityState.tableData2 == 'object') {
+                    activityState.tableData2Flag = true
+                    const nowTime = getCurrentTime(2).getTime()
+                    const startTime = new Date(activityState.tableData2.activityStartTime.replace(/-/g, '/')).getTime()
+                    const endTime = new Date(activityState.tableData2.activityEndTime.replace(/-/g, '/')).getTime()
+                    
+                    if (nowTime < endTime && nowTime > startTime) {
+                        if (activityState.tableData2.status == 2 && activityState.tableData2.activityStatus == 0) {
+                            activityState.isTransform = 1
+                        } else if (activityState.tableData2.status == 2 &&
+                            (activityState.tableData2.activityStatus == 1 ||
+                                (activityState.tableData2.balanceStatus != 2 && activityState.tableData2.creditStatus != 2))) {
+                            activityState.isTransform = 2
+                        } else if (activityState.tableData2.status == 2 && activityState.tableData2.activityStatus == 3) {
+                            activityState.isTransform = 2
+                        }
+                    } else {
+                        activityState.isTransform = 2
+                    }
+                    
+                    if (activityState.tableData2.status == 2 && activityState.tableData2.activityStatus == 2) {
+                        activityState.isTransform = null
+                        if (activityState.tableData2.realizationStatus == 0) {
+                            activityState.isRealization = 1
+                        } else if (activityState.tableData2.realizationStatus == 1 ||
+                            (activityState.tableData2.realizationCreditStatus != 2 && activityState.tableData2.realizationBalanceStatus != 2)) {
+                            activityState.isRealization = 2
+                        } else if (activityState.tableData2.realizationStatus == 3) {
+                            activityState.isRealization = 2
+                        }
+                    } else {
+                        activityState.isRealization = null
+                    }
+                } else {
+                    if (activityState.tableData2) {
+                        activityState.tableData2Flag = true
+                    }
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+                activityState.tableData2 = true
+            }
+        } catch (error) {
+            console.error('获取2023迎新活动数据失败', error)
+        }
+    }
+    
+    // 2023匠鑫活动数据
+    const Activity23JiangxinInfo = async () => {
+        try {
+            const res = await activityApi.Activity23JiangxinInfo({})
+            if (res.code == Code.StatusOK) {
+                activityState.tableData3 = res.data
+                if (activityState.tableData3.show == 1) {
+                    activityState.tableData3Flag = true
+                } else if (activityState.tableData3.show == 0) {
+                    activityState.tableData3Flag = false
+                } else if (!activityState.tableData3.show) {
+                    activityState.tableData3Flag = true
+                    const nowTime = getCurrentTime(2).getTime()
+                    const endTime = activityState.tableData3.activityEndTime
+                        ? new Date(activityState.tableData3.activityEndTime.replace(/-/g, '/')).getTime()
+                        : null
+                    if (activityState.tableData3.status == 2 && activityState.tableData3.realizationStatus == 0 && endTime && nowTime > endTime) {
+                        activityState.isRealizationJx = 1
+                    } else {
+                        activityState.isRealizationJx = 2
+                    }
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取2023匠鑫活动数据失败', error)
+        }
+    }
+    
+    // 2023匠鑫活动数据Vip
+    const Activity23JiangxinInfoVip = async () => {
+        try {
+            const res = await activityApi.Activity23JiangxinInfoVip({})
+            if (res.code == Code.StatusOK) {
+                activityState.tableData3Vip = res.data
+                if (activityState.tableData3Vip.show == 1) {
+                    activityState.tableData3FlagVip = true
+                } else if (activityState.tableData3Vip.show == 0) {
+                    activityState.tableData3FlagVip = false
+                } else if (!activityState.tableData3Vip.show) {
+                    activityState.tableData3FlagVip = true
+                    const nowTime = getCurrentTime(2).getTime()
+                    const endTime = activityState.tableData3Vip.activityEndTime
+                        ? new Date(activityState.tableData3Vip.activityEndTime.replace(/-/g, '/')).getTime()
+                        : null
+                    if (activityState.tableData3Vip.status == 2 && activityState.tableData3Vip.realizationStatus == 0 && endTime && nowTime > endTime) {
+                        activityState.isRealizationJxVip = 1
+                    } else {
+                        activityState.isRealizationJxVip = 2
+                    }
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取2023匠鑫活动数据Vip失败', error)
+        }
+    }
+    
+    // 2023年中赠金活动数据-10
+    const Activity24nianzhongInfo = async () => {
+        try {
+            const res = await activityApi.Activity23nianzhongInfo({})
+            if (res.code == Code.StatusOK) {
+                activityState.tableData4 = res.data
+                if (activityState.tableData4.show == 1) {
+                    activityState.tableData4Flag = true
+                } else if (activityState.tableData4.show == 0) {
+                    activityState.tableData4Flag = false
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取年中赠金活动数据失败', error)
+        }
+    }
+    
+    // 2023年中赠金活动数据-20
+    const Activity24nianzhongTwoInfo = async () => {
+        try {
+            const res = await activityApi.Activity23nianzhongTwoInfo({})
+            if (res.code == Code.StatusOK) {
+                activityState.tableData4Two = res.data
+                if (activityState.tableData4Two.show == 1) {
+                    activityState.tableData4TwoFlag = true
+                } else if (activityState.tableData4Two.show == 0) {
+                    activityState.tableData4TwoFlag = false
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取年中赠金活动数据-20失败', error)
+        }
+    }
+    
+    // 交易大赛数据-参数
+    const GetActivityCptCode = async () => {
+        try {
+            const res = await activityApi.ActivityCptinfoGetCode({})
+            if (res.code == Code.StatusOK) {
+                tableDataCptFlagCode.value = res.data.code
+                if (tableDataCptFlagCode.value) {
+                    await ActivityCptInfo(tableDataCptFlagCode.value)
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取交易大赛参数失败', error)
+        }
+    }
+    
+    // 交易大赛数据
+    const ActivityCptInfo = async (code: string) => {
+        try {
+            const res = await activityApi.ActivityCptinfoCode({ infoCode: code })
+            if (res.code == Code.StatusOK) {
+                activityState.tableDataCpt = res.data
+                activityState.tableDataCptFlag = !!activityState.tableDataCpt
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取交易大赛数据失败', error)
+        }
+    }
+    
+    // 24精英杯活动
+    const Activity24JYBInfoVip = async () => {
+        try {
+            const res = await activityApi.Activity24JYBInfoVip({})
+            if (res.code == Code.StatusOK) {
+                activityState.tableData3JYB = res.data
+                if (activityState.tableData3JYB.show == 1) {
+                    activityState.tableData3FlagJYB = true
+                } else if (activityState.tableData3JYB.show == 0) {
+                    activityState.tableData3FlagJYB = false
+                } else if (!activityState.tableData3JYB.show) {
+                    activityState.tableData3FlagJYB = true
+                    const nowTime = getCurrentTime(2).getTime()
+                    const endTime = activityState.tableData3JYB.activityEndTime
+                        ? new Date(activityState.tableData3JYB.activityEndTime.replace(/-/g, '/')).getTime()
+                        : null
+                    if (activityState.tableData3JYB.status == 2 && activityState.tableData3JYB.realizationStatus == 0 && endTime && nowTime > endTime) {
+                        activityState.isRealizationJxJYB = 1
+                    } else {
+                        activityState.isRealizationJxJYB = 2
+                    }
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取24精英杯活动数据失败', error)
+        }
+    }
+    
+    // 24无忧交易
+    const ActivityNoWorriesInfo = async () => {
+        try {
+            const res = await activityApi.ActivityNoWorriesInfo({})
+            if (res.code == Code.StatusOK) {
+                activityState.tableDataNoWorries = res.data
+                if (typeof activityState.tableDataNoWorries == 'object') {
+                    activityState.tableDataNoWorriesFlag = true
+                    const nowTime = getCurrentTime(2).getTime()
+                    const startTime = new Date(activityState.tableDataNoWorries.compensateTime.replace(/-/g, '/')).getTime()
+                    const endTime = new Date(activityState.tableDataNoWorries.revokeTime.replace(/-/g, '/')).getTime()
+                    
+                    if (nowTime < endTime && nowTime > startTime &&
+                        (activityState.tableDataNoWorries.status == 0 || activityState.tableDataNoWorries.status == 3) &&
+                        activityState.tableDataNoWorries.compensateStatus == 2 &&
+                        activityState.tableDataNoWorries.activityStatus == 1) {
+                        activityState.isRealizationNoWorries = 1
+                    } else {
+                        activityState.isRealizationNoWorries = null
+                    }
+                } else {
+                    if (activityState.tableDataNoWorries) {
+                        activityState.tableDataNoWorriesFlag = true
+                    }
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取无忧交易数据失败', error)
+        }
+    }
+    
+    // CWG 现金嘉年华-新任务
+    const ActivitYdepositRaffleAim = async () => {
+        try {
+            const res = await activityApi.ActivitYdepositRaffleAim({})
+            if (res.code == Code.StatusOK) {
+                activityState.newTask = !!res.data
+                if (res.data) {
+                    activityState.newTaskList = res.data
+                }
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取新任务数据失败', error)
+        }
+    }
+    
+    // CWG 现金嘉年华-抽奖次数
+    const ActivitYdepositRaffleinfo = async () => {
+        try {
+            const res = await activityApi.ActivitYdepositRaffleinfo({})
+            if (res.code == Code.StatusOK) {
+                activityState.LuckyDrawsNumber = res.data?.raffleResidueNumber || '0'
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取抽奖次数失败', error)
+        }
+    }
+    
+    // 抽奖活动是否到期
+    const isRaffleOpen = () => {
+        const endTime1 = '2025/9/30 23:59:59'
+        const startTime1 = '2025/7/1 00:00:00'
+        const now = getCurrentTime(2).getTime()
+        const end = new Date(endTime1).getTime()
+        const start = new Date(startTime1).getTime()
+        
+        if (now < end && start < now) {
+            activityState.choujiaClose = true
+            ActivitYdepositRaffleAim()
+            ActivitYdepositRaffleinfo()
+        }
+    }
+    
+    // 新年庆典是否到期
+    const isNewYear24Open = () => {
+        const endTime1 = '2025/3/31 23:59:59'
+        const startTime1 = '2025/1/1 00:00:00'
+        const now = getCurrentTime(2).getTime()
+        const end = new Date(endTime1).getTime()
+        const start = new Date(startTime1).getTime()
+        
+        if (now < end && start < now) {
+            ActivityNewYear24()
+        }
+    }
+    
+    // 新年庆典数据
+    const ActivityNewYear24 = async () => {
+        try {
+            const res = await activityApi.ActivityNewYear24({})
+            if (res.code == Code.StatusOK) {
+                activityState.tableDataNewYear24 = res.data
+                activityState.tableDataNewYear24Flag = !!activityState.tableDataNewYear24
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取新年庆典数据失败', error)
+        }
+    }
+    
+    // 限时活动
+    const ActivityRequiteInfo = async () => {
+        try {
+            const res = await activityApi.ActivityRequiteInfo({})
+            if (res.code == Code.StatusOK) {
+                activityState.limitedStatus = res.data
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+            }
+        } catch (error) {
+            console.error('获取限时活动数据失败', error)
+        }
+    }
+    
+    // 获取活动显示信息
+    const getActivityShowsInfo = async () => {
+        try {
+            const res = await activityApi.ActivityShowsInfo()
+            if (res.code == Code.StatusOK) {
+                activityState.activityShowsInfo = res.data
+                activityState.surplusGive = res.data.surplusGive || false
+                activityState.monthlyGive = res.data.monthlyGive || false
+            } else {
+                uni.showToast({ title: res.msg, icon: 'none' })
+                activityState.surplusGive = false
+                activityState.monthlyGive = false
+            }
+        } catch (error) {
+            console.error('获取活动显示信息失败', error)
+            activityState.surplusGive = false
+            activityState.monthlyGive = false
+        }
+    }
+    
+    // 20赠金是否到期
+    const is20Open = () => {
+        const endTime1 = '2023/04/30 23:59:59'
+        const now = getCurrentTime(2).getTime()
+        const end = new Date(endTime1).getTime()
+        if (now > end) {
+            activityState.anshiClose = false
+        }
+    }
+    
+    // 20赠金活动数据
+    const getActivityPercentageGiveInfo = async () => {
+        try {
+            const res = await activityApi.ActivityPercentageGiveInfo({})
+            if (res.code == Code.StatusOK) {
+                // 处理20赠金活动数据
+                console.log('20赠金活动数据', res.data)
+            }
+        } catch (error) {
+            console.error('获取20赠金活动数据失败', error)
+        }
+    }
+    
+    // 刷新所有活动数据
+    const refreshAllActivities = () => {
+        is20Open()
+        searchFunc()
+        searchFunc1()
+        Activity23HundredInfo()
+        Activity23JiangxinInfoVip()
+        Activity24nianzhongInfo()
+        Activity24nianzhongTwoInfo()
+        GetActivityCptCode()
+        Activity24JYBInfoVip()
+        ActivityNoWorriesInfo()
+        isRaffleOpen()
+        isNewYear24Open()
+        ActivityRequiteInfo()
+        getActivityShowsInfo()
+    }
+    
+    // 分页处理
+    const handlePageChange = (page: number) => {
+        pagerInfo.value.current = page
+        searchFunc(page)
+        searchFunc1()
+    }
+    
+    // 清理定时器
+    onUnmounted(() => {
+        if (interval.value) {
+            clearInterval(interval.value)
+        }
+    })
+    
+    return {
+        // 状态
+        pictLoading,
+        flag,
+        tableData,
+        tableDataGive,
+        singleData,
+        pagerInfo,
+        loginOptions,
+        loginOptions1,
+        activityState,
+        tableDataCptFlagCode,
+        NewYear24DataBalance,
+        NewYear24Data,
+        
+        // 计算属性
+        country,
+        myCid,
+        isSupportedCountry,
+        isGuoQin,
+        
+        // 工具函数
+        getCurrentTime,
+        getzero,
+        timeConvert,
+        groupCurrency,
+        groupTypeName,
+        overdue,
+        timeExpireJx,
+        isAfterSeptember30,
+        
+        // API函数
+        getDateList,
+        searchFunc,
+        searchFunc1,
+        getSingle,
+        getSingle1,
+        Activity23HundredInfo,
+        Activity23JiangxinInfo,
+        Activity23JiangxinInfoVip,
+        Activity24nianzhongInfo,
+        Activity24nianzhongTwoInfo,
+        GetActivityCptCode,
+        ActivityCptInfo,
+        Activity24JYBInfoVip,
+        ActivityNoWorriesInfo,
+        ActivitYdepositRaffleAim,
+        ActivitYdepositRaffleinfo,
+        isRaffleOpen,
+        isNewYear24Open,
+        ActivityNewYear24,
+        ActivityRequiteInfo,
+        getActivityShowsInfo,
+        getActivityPercentageGiveInfo,
+        refreshAllActivities,
+        handlePageChange
+    }
+}

+ 550 - 0
pages/activities/config/activityConfigs.ts

@@ -0,0 +1,550 @@
+// 静态活动配置
+export const staticActivityConfigs = [
+    {
+        id: 'NewYear24',
+        title: 'news_add_field1.NewYear24.item1',
+        description: 'news_add_field1.NewYear24.item2',
+        image: '/static/images/cwg-menu-icons-13.jpg',
+        showCondition: 'tableDataNewYear24Flag',
+        hot: true,
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.NewYear24.item4',
+                action: 'openCalculator'
+            },
+            {
+                type: 'red',
+                text: 'news_add_field1.NewYear24.item9',
+                action: 'toSingle',
+                params: ['NewYear24']
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.NewYear24.item3',
+                action: 'openPdf',
+                pdf: {
+                    cn: '/pdf/pdf3/pdf-cn.pdf',
+                    zhHant: '/pdf/pdf3/pdf-zhHant.pdf',
+                    default: '/pdf/pdf3/pdf-en.pdf'
+                }
+            }
+        ]
+    },
+    {
+        id: 'monthlyGift',
+        title: 'MonthlyActivities.item1',
+        description: 'MonthlyActivities.item1_1',
+        image: '/static/images/yue.jpg',
+        showCondition: "country === 'CN'",
+        hot: true,
+        buttons: [
+            {
+                type: 'dynamic',
+                text: 'news_add_field1.activities10_trading_aoyun.item3',
+                action: 'openSurplusActivityDialog1',
+                condition: 'monthlyGive'
+            },
+            {
+                type: 'check',
+                text: 'wallet.item15',
+                action: 'openPdf',
+                pdf: '/pdf/pdf13/CWG Prime Bonus-cn.pdf'
+            },
+            {
+                type: 'check',
+                text: 'Transfer.item7',
+                action: 'openPdf',
+                pdf: '/pdf/pdf13/CWG Markets Prime Bonus Application Process-cn.pdf'
+            },
+            {
+                type: 'check',
+                text: 'wallet.item14',
+                action: 'goMonthlyTaskList'
+            }
+        ]
+    },
+    {
+        id: 'bonusGift',
+        title: 'surplusList.item1',
+        description: 'surplusList.item2',
+        image: '/static/images/su.png',
+        hot: true,
+        buttons: [
+            {
+                type: 'dynamic',
+                text: 'news_add_field1.activities10_trading_aoyun.item3',
+                action: 'openSurplusActivityDialog',
+                condition: 'surplusGive'
+            },
+            {
+                type: 'check',
+                text: 'wallet.item15',
+                action: 'openPdf',
+                pdf: {
+                    dynamic: true,
+                    path: '/pdf/pdf12/CWG Prime Bonus-{lang}.pdf'
+                }
+            },
+            {
+                type: 'check',
+                text: 'Transfer.item7',
+                action: 'openPdf',
+                pdf: {
+                    dynamic: true,
+                    path: '/pdf/pdf12/CWG Markets Prime Bonus Application Process-{lang}.pdf',
+                    fallback: '/pdf/pdf12/CWG Markets Prime Bonus Application Process-en.pdf',
+                    supportedLangs: ['cn', 'zhHant', 'en']
+                }
+            },
+            {
+                type: 'check',
+                text: 'wallet.item14',
+                action: 'goSurplusTaskList'
+            }
+        ]
+    },
+    {
+        id: 'cashCarnival',
+        title: 'wallet.item8',
+        description: 'wallet.item9',
+        image: '/static/images/cash-carnival.webp',
+        imageTitle: 'wallet.item8',
+        showCondition: 'choujiaClose',
+        hot: true,
+        onClick: 'toSingle',
+        onClickParams: ['23jnhcj'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'wallet.item10',
+                action: 'toHistoryLuckyDraw',
+                suffix: 'LuckyDrawsNumber',
+                suffixText: 'wallet.item11'
+            },
+            {
+                type: 'check',
+                text: 'wallet.item12',
+                action: 'toOpenTask'
+            },
+            {
+                type: 'dynamic',
+                text: 'wallet.item13',
+                action: 'toNewTask',
+                condition: 'newTask',
+                elseType: 'gray'
+            },
+            {
+                type: 'check',
+                text: 'wallet.item14',
+                action: 'toTaskList'
+            },
+            {
+                type: 'check',
+                text: 'wallet.item15',
+                action: 'openPdf',
+                pdf: {
+                    dynamic: true,
+                    langMap: {
+                        ar: '/pdf/pdf5/ar.pdf',
+                        cn: '/pdf/pdf5/cn.pdf',
+                        de: '/pdf/pdf5/en.pdf',
+                        en: '/pdf/pdf5/en.pdf',
+                        es: '/pdf/pdf5/es.pdf',
+                        fa: '/pdf/pdf5/en.pdf',
+                        id: '/pdf/pdf5/en.pdf',
+                        ko: '/pdf/pdf5/ko.pdf',
+                        ms: '/pdf/pdf5/en.pdf',
+                        pt: '/pdf/pdf5/pt.pdf',
+                        th: '/pdf/pdf5/th.pdf',
+                        tr: '/pdf/pdf5/en.pdf',
+                        vn: '/pdf/pdf5/vn.pdf',
+                        zhHant: '/pdf/pdf5/zhHant.pdf'
+                    }
+                }
+            }
+        ]
+    },
+    {
+        id: 'noWorries',
+        title: 'news_add_field1.activitiesNoWorries.item1',
+        description: 'news_add_field1.activitiesNoWorries.item2',
+        image: '/static/images/jihua.png',
+        showCondition: 'tableDataNoWorriesFlag',
+        hot: true,
+        onClick: 'toSingle',
+        onClickParams: ['NoWorries'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesNoWorries.item3',
+                action: 'toApplyNoWorriesOpen',
+                condition: 'tableDataNoWorries === true'
+            },
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesNoWorries.item4',
+                action: 'toRealizationNoWorries',
+                condition: 'isRealizationNoWorries === 1',
+                elseType: 'gray'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activitiesNoWorries.item5',
+                action: 'toSingle',
+                params: ['NoWorries']
+            }
+        ]
+    },
+    {
+        id: 'standardRewards',
+        title: 'news_add_field1.activities10_trading_aoyun.item5',
+        description: 'news_add_field1.activities10_trading_aoyun.item6',
+        image: '/static/images/trading-rewards.webp',
+        showCondition: 'standard',
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activities10_trading_aoyun.item3',
+                action: 'toActivity24Trading'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activities10_trading_aoyun.item4',
+                action: 'openPdf',
+                pdf: {
+                    dynamic: true,
+                    langMap: {
+                        ar: '/pdf/pdf1/ar.pdf',
+                        cn: '/pdf/pdf1/cn.pdf',
+                        de: '/pdf/pdf1/en.pdf',
+                        en: '/pdf/pdf1/en.pdf',
+                        es: '/pdf/pdf1/es.pdf',
+                        fa: '/pdf/pdf1/en.pdf',
+                        id: '/pdf/pdf1/en.pdf',
+                        ko: '/pdf/pdf1/ko.pdf',
+                        ms: '/pdf/pdf1/en.pdf',
+                        pt: '/pdf/pdf1/pt.pdf',
+                        th: '/pdf/pdf1/th.pdf',
+                        tr: '/pdf/pdf1/en.pdf',
+                        vn: '/pdf/pdf1/vn.pdf',
+                        zhHant: '/pdf/pdf1/zhHant.pdf'
+                    }
+                }
+            }
+        ]
+    },
+    {
+        id: 'bonus10',
+        title: 'news_add_field1.activities10_trading_aoyun.item1',
+        description: 'news_add_field1.activities10_trading_aoyun.item2_1',
+        image: '/static/images/10-bonus.webp',
+        showCondition: '!isAfterSeptember30() && !isSupportedCountry',
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activities10_trading_aoyun.item3',
+                action: 'toActivity24nianzhong'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activities10_trading_aoyun.item4',
+                action: 'openPdf',
+                pdf: {
+                    dynamic: true,
+                    path: '/pdf/pdf4/{lang}.pdf'
+                }
+            }
+        ]
+    },
+    {
+        id: 'bonus100',
+        title: 'news_add_field1.activities10_trading_aoyun.item1_2',
+        description: 'news_add_field1.activities10_trading_aoyun.item2_12',
+        image: '/static/images/100-bonus.webp',
+        showCondition: '!isAfterSeptember30() && isSupportedCountry',
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activities10_trading_aoyun.item3',
+                action: 'toActivity24nianzhong'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activities10_trading_aoyun.item4',
+                action: 'openPdf',
+                pdf: {
+                    dynamic: true,
+                    path: '/pdf/pdf4/100Bonus-{lang}.pdf'
+                }
+            }
+        ]
+    },
+    {
+        id: 'welcome2023',
+        title: 'news_add_field1.activities.item8',
+        description: '',
+        image: {
+            cn: '/static/images/23ActiveCn.jpg',
+            zhHant: '/static/images/23ActiveCn1.jpg',
+            default: '/static/images/23ActiveEn.jpg'
+        },
+        showCondition: 'tableData2Flag',
+        hot: true,
+        onClick: 'toSingle',
+        onClickParams: ['23yx'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activities.item4',
+                action: 'toApply23Open',
+                condition: 'tableData2 === true'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activities.item4',
+                condition: 'tableData2 === false'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activities.item5',
+                condition: 'typeof tableData2 === "object"'
+            },
+            {
+                type: 'red',
+                text: 'news_add_field1.activities.item9',
+                action: 'toTransform',
+                condition: 'isTransform === 1'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activities.item9',
+                condition: 'isTransform === 2'
+            },
+            {
+                type: 'red',
+                text: 'news_add_field1.activities.item0',
+                action: 'toRealization',
+                condition: 'isRealization === 1'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activities.item0',
+                condition: 'isRealization === 2'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activities.item7',
+                action: 'toSingle',
+                params: ['23yx']
+            }
+        ]
+    },
+    {
+        id: 'tradingCompetition',
+        title: 'news_add_field1.activitiesJYDS2025.item1',
+        description: 'news_add_field1.activitiesJYDS2025.item2',
+        image: '/static/images/banner.jpg',
+        showCondition: 'tableDataCptFlag',
+        hot: true,
+        onClick: 'toSingle',
+        onClickParams: ['23xinjia'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesJYDS.item3',
+                action: 'toApplyCptOpen',
+                condition: 'tableDataCpt.signStatus === 0'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activitiesJYDS.item3_1',
+                condition: 'tableDataCpt.signStatus === 1'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activitiesJYDS.item4',
+                action: 'toSingle',
+                params: ['23xinjia']
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activitiesJYDS.item4_1',
+                action: 'toOpenSingle',
+                params: ['tableDataCpt.pageAddress']
+            }
+        ]
+    },
+    {
+        id: 'eliteCup24',
+        title: 'news_add_field1.activitiesJYB.item1',
+        description: 'news_add_field1.activitiesJYB.item2',
+        image: '/static/images/jyb.jpg',
+        showCondition: 'tableData3FlagJYB',
+        onClick: 'toSingle',
+        onClickParams: ['24JYB'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesJYB.item3',
+                action: 'toApply24JYBOpenVip',
+                condition: 'tableData3JYB.show === 1 && timeExpireJx(tableData3JYB.applicationEndTime)'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activitiesJYB.item3',
+                action: 'openDialog',
+                params: ['dialogChinaUnionPayJX'],
+                condition: 'tableData3JYB.show === 1 && !timeExpireJx(tableData3JYB.applicationEndTime)'
+            },
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesJYB.item4',
+                action: 'toRealization24JYBVip',
+                condition: 'isRealizationJxJYB === 1'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activitiesJYB.item4',
+                condition: 'isRealizationJxJYB === 2'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activitiesJYB.item5',
+                action: 'toSingle',
+                params: ['24JYB']
+            }
+        ]
+    },
+    {
+        id: 'jiangxinCollege',
+        title: 'news_add_field1.activitiesJX.item1',
+        description: 'news_add_field1.activitiesJX.item2',
+        image: '/static/images/hd_img_100.png',
+        showCondition: 'tableData3Flag',
+        hot: true,
+        onClick: 'toSingle',
+        onClickParams: ['23jx'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesJX.item3',
+                action: 'toApply23JxOpen',
+                condition: 'tableData3.show === 1 && timeExpireJx(tableData3.applicationEndTime)'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activitiesJX.item3',
+                action: 'openDialog',
+                params: ['dialogChinaUnionPayJX'],
+                condition: 'tableData3.show === 1 && !timeExpireJx(tableData3.applicationEndTime)'
+            },
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesJX.item4',
+                action: 'toRealizationJx',
+                condition: 'isRealizationJx === 1'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activitiesJX.item4',
+                condition: 'isRealizationJx === 2'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activitiesJX.item5',
+                action: 'toSingle',
+                params: ['23jx']
+            }
+        ]
+    },
+    {
+        id: 'jiangxinCollegeVip',
+        title: 'news_add_field1.activitiesJX.item1',
+        description: 'news_add_field1.activitiesJX.item2',
+        image: '/static/images/hd_img_100_1.png',
+        showCondition: 'tableData3FlagVip',
+        onClick: 'toSingle',
+        onClickParams: ['23jxVip'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesJX.item3',
+                action: 'toApply23JxOpenVip',
+                condition: 'tableData3Vip.show === 1 && timeExpireJx(tableData3Vip.applicationEndTime)'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activitiesJX.item3',
+                action: 'openDialog',
+                params: ['dialogChinaUnionPayJX'],
+                condition: 'tableData3Vip.show === 1 && !timeExpireJx(tableData3Vip.applicationEndTime)'
+            },
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesJX.item4',
+                action: 'toRealizationJxVip',
+                condition: 'isRealizationJxVip === 1'
+            },
+            {
+                type: 'gray',
+                text: 'news_add_field1.activitiesJX.item4',
+                condition: 'isRealizationJxVip === 2'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activitiesJX.item5',
+                action: 'toSingle',
+                params: ['23jxVip']
+            }
+        ]
+    },
+    {
+        id: 'midYearBonus10',
+        title: 'news_add_field1.activitiesNZ.item1',
+        description: 'news_add_field1.activitiesNZ.item2',
+        image: '/static/images/hd_10_500.jpg',
+        showCondition: 'tableData4Flag',
+        hot: true,
+        onClick: 'toSingle',
+        onClickParams: ['23nz'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesNZ.item3',
+                action: 'toActivity24nianzhong',
+                condition: 'tableData4.show === 1'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activitiesNZ.item5',
+                action: 'toSingle',
+                params: ['23nz']
+            }
+        ]
+    },
+    {
+        id: 'midYearBonus20',
+        title: 'news_add_field1.activitiesNZTwo.item1',
+        description: 'news_add_field1.activitiesNZTwo.item2',
+        image: '/static/images/hd_10_500_20.png',
+        showCondition: 'tableData4TwoFlag',
+        hot: true,
+        onClick: 'toSingle',
+        onClickParams: ['23nzTwo'],
+        buttons: [
+            {
+                type: 'red',
+                text: 'news_add_field1.activitiesNZTwo.item3',
+                action: 'toActivity24nianzhong',
+                condition: 'tableData4Two.show === 1'
+            },
+            {
+                type: 'check',
+                text: 'news_add_field1.activitiesNZTwo.item5',
+                action: 'toSingle',
+                params: ['23nzTwo']
+            }
+        ]
+    }
+]

Разница между файлами не показана из-за своего большого размера
+ 325 - 809
pages/activities/index.vue


+ 88 - 0
pages/activities/types/activity.ts

@@ -0,0 +1,88 @@
+// 活动状态类型
+export interface ActivityState {
+    tableDataNewYear24Flag: boolean
+    tableDataNewYear24: any
+    choujiaClose: boolean
+    tableDataNoWorriesFlag: boolean
+    tableDataNoWorries: any
+    isRealizationNoWorries: number
+    standard: boolean
+    tableData2Flag: boolean
+    tableData2: any
+    isTransform: number
+    isRealization: number
+    tableDataCptFlag: boolean
+    tableDataCpt: any
+    tableData3FlagJYB: boolean
+    tableData3JYB: any
+    isRealizationJxJYB: number
+    tableData3Flag: boolean
+    tableData3: any
+    isRealizationJx: number
+    tableData3FlagVip: boolean
+    tableData3Vip: any
+    isRealizationJxVip: number
+    tableData4Flag: boolean
+    tableData4: any
+    tableData4TwoFlag: boolean
+    tableData4Two: any
+    monthlyGive: boolean
+    surplusGive: boolean
+    newTask: boolean
+    newTaskList: any
+    LuckyDrawsNumber: string
+    isCountDown: string
+    isCashBack: boolean
+    anshiClose: boolean
+    limitedStatus: any
+    activityShowsInfo: any
+    country: string
+    lang: string
+    isGuoQin: boolean
+    isSupportedCountry: boolean
+}
+
+// 分页信息
+export interface PagerInfo {
+    row: number
+    current: number
+    pageTotal: number
+    rowTotal: number
+}
+
+// 账户信息
+export interface AccountInfo {
+    login: string
+    platform?: string
+    currency?: string
+    balance?: number
+    type?: string
+    closeFunctions?: string
+}
+
+// 活动配置
+export interface ActivityConfig {
+    id: string
+    title?: string
+    description?: string
+    image?: string | Record<string, string>
+    imageTitle?: string
+    showCondition?: string
+    hot?: boolean
+    onClick?: string
+    onClickParams?: any[]
+    buttons?: ActivityButton[]
+}
+
+// 活动按钮
+export interface ActivityButton {
+    type: string
+    text: string
+    action?: string
+    params?: any[]
+    condition?: string
+    elseType?: string
+    suffix?: string
+    suffixText?: string
+    pdf?: any
+}

+ 0 - 1067
pages/apply-record/components/ApplyRecord.vue

@@ -1,1067 +0,0 @@
-<template>
-  <view class="page">
-    <view class="step">
-      <view v-for="item in stepList" :key="item.id" :class="step >= item.id ? 'step-item step-active' : 'step-item'">
-        <view v-t="t(item.name)" class="step-item-content"></view>
-      </view>
-    </view>
-
-    <view class="form-box">
-      <view v-if="step == 1" class="status-box">
-        <view class="status">
-          <template v-if="cardInfo.tradeType == '1'">
-            <text v-if="cardInfo.tradeStatus == '2'" v-t="'card.Info.t8'"></text>
-            <text v-else-if="cardInfo.tradeStatus == '3'" v-t="'card.Info.t9'"></text>
-            <text v-else v-t="'card.Info.t5'"></text>
-          </template>
-
-          <template v-if="cardInfo.tradeType == '2'">
-            <text v-if="cardInfo.tradeStatus == '2'" v-t="'card.Info.t12'"></text>
-            <text v-else-if="cardInfo.tradeStatus == '3'" v-t="'card.Info.t13'"></text>
-            <text v-else v-t="'card.Info.t11'"></text>
-          </template>
-        </view>
-        <template v-if="cardInfo.tradeType == '1'">
-          <template v-if="cardInfo.tradeStatus == '1'">
-            <view v-t="'card.Info.s31'"></view>
-            <image class="imgs" mode="widthFix" src="/static/images/card/img1.png" alt="" srcset="" />
-          </template>
-          <template v-if="cardInfo.tradeStatus == '3'">
-            <view v-t="'card.Info.s32'"></view>
-            <image class="imgs" mode="widthFix" src="/static/images/card/img4.png" alt="" srcset="" />
-          </template>
-        </template>
-        <template v-if="cardInfo.tradeType == '2'">
-          <template v-if="cardInfo.tradeStatus == '1'">
-            <view v-t="'card.Info.s32'"></view>
-            <image class="imgs" mode="widthFix" src="/static/images/card/img1.png" alt="" srcset="" />
-          </template>
-          <template v-if="cardInfo.tradeStatus == '2'">
-            <view v-t="'card.Info.s33'"></view>
-            <image class="imgs" mode="widthFix" src="/static/images/card/img3.png" alt="" srcset="" />
-          </template>
-        </template>
-      </view>
-      <view v-if="step == 2" class="status-box">
-        <view class="status">
-          <text v-if="cardInfo.approveStatus == '2'" v-t="'card.Info.t2'"></text>
-          <text v-else-if="cardInfo.approveStatus == '3'" v-t="'card.Info.t3'"></text>
-          <text v-else v-t="'card.Info.t1'"></text>
-        </view>
-        <template v-if="cardInfo.approveStatus == '1'">
-          <view v-t="'card.Info.s34'"></view>
-          <image class="imgs" mode="widthFix" src="/static/images/card/img1.png" alt="" srcset="" />
-        </template>
-        <template v-if="cardInfo.approveStatus == '3'">
-          <view v-t="'card.Info.s35'"></view>
-          <image class="imgs" mode="widthFix" src="/static/images/card/img4.png" alt="" srcset="" />
-        </template>
-      </view>
-      <view v-if="step == 3" class="status-box">
-
-
-        <template v-if="cardInfo.status == 'success'">
-          <template v-if="cardInfo.logisticsStatus">
-            <view class="success-step"
-              v-for="key in Object.keys(logisticsStatusMap).filter(k => Number(k) <= cardInfo.logisticsStatus)"
-              :key="key">
-              <view class="status">
-                <image class="status-img" src="/static/images/card/step-icon.png" alt="" />
-                <text>{{ t(logisticsStatusMap[key]) }}</text>
-              </view>
-              <view class="title">
-                <text>{{ t(logisticsTitleMap[key]) }} </text>
-              </view>
-            </view>
-            <view>
-              <view class="qr-container" @click="handleQrClick(cardGuide)">
-                <QrCode width="200" height="200" :text="cardGuide"></QrCode>
-              </view>
-              <br />
-              <text v-t="'card.New3.p10'"></text>
-            </view>
-          </template>
-          <image class="imgs" mode="widthFix" src="/static/images/card/img5.png" alt="" srcset="" />
-          <view class="step-box">
-            <view class="step-item">
-              <view class="ids">1</view>
-              <view v-t="'card.Info.s22'" class="k"></view>
-              <view v-t="'card.Info.s23'" class="v"></view>
-            </view>
-            <view class="step-item">
-              <view class="ids">2</view>
-              <view v-t="'card.Info.s24'" class="k"></view>
-              <view v-t="'card.Info.s25'" class="v"></view>
-            </view>
-            <view class="step-item">
-              <view class="ids">3</view>
-              <view v-t="'card.Info.s26'" class="k"></view>
-              <view v-t="'card.Info.s27'" class="v"></view>
-            </view>
-            <view class="step-item">
-              <view class="ids">4</view>
-              <view v-t="'card.Info.s28'" class="k"></view>
-              <view v-t="'card.Info.s29'" class="v"></view>
-              <view v-t="'card.Info.s30'" class="v"></view>
-            </view>
-          </view>
-          <view v-t="'card.Info.s21'" class="f"></view>
-
-        </template>
-        <template v-else-if="cardInfo.status == 'fail'">
-          <view class="status">
-            <text v-t="'card.Info.t7'"></text>
-          </view>
-          <view v-t="'card.Info.s37'"></view>
-          <image class="imgs" mode="widthFix" src="/static/images/card/img4.png" alt="" srcset="" />
-        </template>
-        <template v-else>
-          <view class="status">
-            <text v-if="cardInfo.status === 'processing'" v-t="'card.Info.t5'"></text>
-            <text v-else v-t="'card.Info.t10'"></text>
-          </view>
-          <view v-t="'card.Info.s38'"></view>
-          <image class="imgs" mode="widthFix" src="/static/images/card/img1.png" alt="" srcset="" />
-        </template>
-      </view>
-    </view>
-    <view v-if="cardInfo.cardName && !props.type" class="card-info1">
-      <view class="card-title">{{ cardInfo.cardName }}</view>
-      <view class="card-content">{{ cardInfo.cardDesc }}</view>
-      <ul class="card-list">
-        <li>
-          <text class="label">{{ t(`card.New1.d13`) }}</text>
-          <text>{{ cardInfo.mailingAreaCode }} {{ cardInfo.mailingMobile }}</text>
-        </li>
-        <li>
-          <text class="label">{{ t("card.New1.d8") }}</text>
-          <text>{{ cardInfo.mailingCountry || "--" }}</text>
-        </li>
-        <li>
-          <text class="label">{{ t("card.New1.d9") }}</text>
-          <text>{{ cardInfo.mailingTown }}</text>
-        </li>
-        <li>
-          <text class="label">{{ t("card.New1.d10") }}</text>
-          <text>{{ cardInfo.mailingAddressCn }}</text>
-        </li>
-        <li>
-          <text class="label">{{ t("card.New1.d11") }}</text>
-          <text>{{ cardInfo.mailingAddress }}</text>
-        </li>
-        <li>
-          <text class="label">{{ t("card.New1.d12") }}</text>
-          <text>{{ cardInfo.mailingPostCode }}</text>
-        </li>
-        <li class="one" :class="statusClass(cardInfo.status)">
-          <text class="label">{{ t("card.Status.v5") }}</text>
-          <text>{{
-            statusMap[cardInfo.status] || t("card.Status.t3")
-          }}</text>
-        </li>
-      </ul>
-    </view>
-  </view>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, computed } from "vue";
-import { useI18n } from "vue-i18n";
-import useCardStore from "@/stores/use-card-store";
-import QrCode from "@/components/QrCode.vue";
-import { ucardApi } from "@/api/ucard";
-
-const props = defineProps({
-  id: String,
-  type: String,
-});
-const cardStore = useCardStore();
-const applyList = computed(() => cardStore.applyCard);
-const { t } = useI18n();
-const cardInfo = ref({
-  status: "success",
-  tradeStatus: 2,
-  approveStatus: 2,
-  tradeType: 1,
-});
-const isShowBtn = ref(false);
-const dateRange = ref<[string, string] | undefined>(undefined);
-dateRange.value = ["", ""];
-const stepList = [
-  { id: 1, name: "card.Info.s39", status: "finish" },
-  { id: 2, name: "card.Info.s40", status: "process" },
-  { id: 3, name: "card.Info.s41", status: "wait" },
-];
-const logisticsStatusMap = ref({
-  1: 'card.New3.p1',
-  2: 'card.New3.p3',
-  3: 'card.New3.p5',
-  4: 'card.New3.p7'
-})
-const logisticsTitleMap = ref({
-  1: 'card.New3.p2',
-  2: 'card.New3.p4',
-  3: 'card.New3.p6',
-  4: 'card.New3.p8'
-})
-const step = ref(1);
-async function getKycList() {
-  const b = applyList.value.filter((i) => {
-    return i.kycStatus == null;
-  });
-
-  if (props.id) {
-    let a = {
-      status: "success",
-      tradeStatus: 2,
-      approveStatus: 2,
-      tradeType: 1,
-    };
-    a = applyList.value.filter((item) => item.id == props.id)[0];
-    if (a?.tradeStatus == 1) step.value = 1;
-    if (a?.tradeStatus == 2 && a.tradeType == 1) step.value = 2;
-    if (a?.approveStatus == 2) step.value = 3;
-    cardInfo.value = a;
-    if (a.status == 'success') getCardInfo(a.cardNumber);
-  }
-}
-const statusMap: Record<string, string> = {
-  success: t("card.Status.t6"),
-  fail: t("card.Status.t7"),
-  processing: t("card.Status.t3"),
-  wait_process: t("card.Status.t3"),
-  cancel: t("card.Status.t3"),
-};
-function statusClass(status: string) {
-  switch (status) {
-    case "success":
-      return "one";
-    case "fail":
-      return "error";
-    case "cancel":
-      return "error";
-    default:
-      return "default";
-  }
-}
-
-async function getCardInfo(cardNumber?: string) {
-  try {
-    if (props.type == "card") {
-      isShowBtn.value = false;
-      const res = await ucardApi.getCardInfo({ id: props.id || "" });
-      if (res.code == 200) {
-        cardInfo.value = { ...cardInfo.value, ...res.data };
-        isShowBtn.value = true;
-      }
-    } else {
-      if (!cardNumber) return;
-      const res = await ucardApi.cardList({ page: { current: 1, row: 10 }, cardNumber })
-      if (res.code == 200) {
-        cardInfo.value = { ...cardInfo.value, ...res.data[0] };
-      }
-    }
-
-  } catch (error) {
-    console.log(error);
-  }
-}
-
-onMounted(async () => {
-  if (props.type == "card") {
-    step.value = 3
-    await getCardInfo();
-  } else {
-    getKycList();
-  }
-});
-
-// 二维码目标链接
-const cardGuide = "https://secure.ucardwallet.com/card-guide";
-
-function handleQrClick(url) {
-  if (!url) return;
-  uni.showModal({
-    title: t('pages.apply-record.index'),
-    content: t('pages.apply-record.confirmOpen'),
-    confirmText: t('pages.apply-record.open'),
-    cancelText: t('common.cancel'),
-    success: (res) => {
-      if (!res.confirm) return;
-      try {
-        // #ifdef APP-PLUS
-        plus.runtime.openURL(url);
-        return;
-        // #endif
-        // #ifdef H5
-        window.open(url, "_blank");
-        return;
-        // #endif
-      } catch (e) {
-      }
-      uni.setClipboardData({
-        data: url,
-        success() {
-          uni.showToast({ title: t("pages.apply-record.copyPrompt"), icon: "none" });
-        },
-        fail() {
-          uni.showToast({ title: t("pages.apply-record.openFailed"), icon: "none" });
-        },
-      });
-    },
-  });
-}
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page {
-  padding-bottom: px2rpx(20);
-  box-sizing: border-box;
-  min-height: 100vh;
-  background: var(--main-bg);
-}
-
-.page1 {
-  padding: px2rpx(16);
-}
-
-.card-wrapper {
-  position: absolute;
-  width: 100%;
-  height: 100%;
-  transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
-  will-change: transform;
-}
-
-.card-info {
-  background: url("/static/images/visa.png") no-repeat center center;
-  background-size: cover;
-  border-radius: 0.426667rem;
-  padding: 0.64rem 0.533333rem 0 0.533333rem;
-  color: var(--main-yellow);
-  box-shadow: 0 0.106667rem 0.533333rem rgba(214, 255, 0, 0.1);
-  border: 1px solid rgba(214, 255, 0, 0.2);
-  width: 100%;
-  height: 100%;
-  display: flex;
-  justify-content: flex-start;
-  align-items: baseline;
-  flex-wrap: wrap;
-  transform-style: preserve-3d;
-  transition: transform 0.6s ease;
-  flex-direction: column;
-
-  &.flipping {
-    transform: rotateY(180deg);
-  }
-
-  .card-b {
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: center;
-    align-items: center;
-
-    text {
-      display: block;
-    }
-
-    .valid {
-      font-size: var(--font-size-14);
-      font-weight: 500;
-      color: var(--black);
-      text-shadow: 0 0 px2rpx(8) rgba(214, 255, 0, 0.2);
-      gap: px2rpx(8);
-      padding-right: px2rpx(30);
-      line-height: px2rpx(20);
-    }
-
-    .lable {
-      font-size: var(--font-size-10);
-      font-weight: 400;
-    }
-  }
-}
-
-.card-front,
-.card-back {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  padding: px2rpx(24) px2rpx(20) px2rpx(16) px2rpx(20);
-  backface-visibility: hidden;
-  -webkit-backface-visibility: hidden;
-}
-
-.card-back {
-  transform: rotateY(180deg);
-}
-
-.owner {
-  font-size: var(--font-size-14);
-  line-height: 2;
-  margin-bottom: px2rpx(8);
-  text-shadow: 0 0 px2rpx(10) rgba(214, 255, 0, 0.3);
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-
-  i {
-    font-size: var(--font-size-18);
-    color: var(--main-yellow);
-  }
-}
-
-.number {
-  color: var(--black);
-  font-size: var(--font-size-18);
-  font-weight: 500;
-  line-height: 3;
-  letter-spacing: px2rpx(2);
-  margin: px2rpx(24) 0;
-  text-shadow: 0 0 px2rpx(15) rgba(214, 255, 0, 0.4);
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-}
-
-.actions {
-  display: flex;
-  justify-content: space-between;
-  margin: px2rpx(20) 0 px2rpx(16) 0;
-}
-
-.action-btn {
-  color: var(--white);
-  border: none;
-  border-radius: px2rpx(12);
-  padding: px2rpx(10) px2rpx(2);
-  font-size: var(--font-size-14);
-  cursor: pointer;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  gap: px2rpx(4);
-  transition: all 0.3s ease;
-  text-align: center;
-  color: #1a1a1a;
-
-  .btn-icon {
-    width: px2rpx(46);
-    height: px2rpx(46);
-    border-radius: 50%;
-    background: #ff4766;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-  }
-
-  i {
-    display: inline-block;
-    line-height: px2rpx(46);
-    width: px2rpx(22);
-    height: px2rpx(22);
-    color: var(--black);
-    margin-bottom: px2rpx(4);
-  }
-}
-
-.balance-wrap {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin: px2rpx(30) 0;
-  font-size: var(--font-size-14);
-}
-
-.balance-content {
-  font-size: var(--font-size-20);
-  color: var(--white);
-  font-weight: bold;
-  margin-bottom: px2rpx(24);
-}
-
-.balance-title {
-  font-size: var(--font-size-12);
-  color: var(--white);
-}
-
-.currency {
-  display: flex;
-  align-items: center;
-  font-size: var(--font-size-14);
-  margin-right: px2rpx(12);
-  color: var(--white);
-}
-
-.flag {
-  width: px2rpx(24);
-  height: px2rpx(24);
-  border-radius: 50%;
-  margin-right: px2rpx(6);
-}
-
-.balance {
-  font-size: var(--font-size-14);
-  font-weight: bold;
-  color: var(--white);
-}
-
-.transactions {
-  border-radius: px2rpx(16);
-  margin-bottom: px2rpx(16);
-  padding: px2rpx(16) 0;
-}
-
-.trans-icon {
-  width: px2rpx(40);
-  height: px2rpx(40);
-  display: flex;
-  background: var(--main-bg);
-  box-shadow: 0 px2rpx(4) px2rpx(12) rgba(214, 255, 0, 0.1);
-  border-radius: px2rpx(8);
-  margin-right: px2rpx(12);
-  align-items: center;
-  justify-content: center;
-
-  .trans-icon-inner {
-    width: px2rpx(36);
-    height: px2rpx(36);
-    background: rgba(212, 206, 206, 0.24);
-    border-radius: 50%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-
-  i {
-    color: #000;
-    width: px2rpx(18);
-    height: px2rpx(18);
-    font-size: var(--font-size-16);
-    border-radius: 50%;
-  }
-}
-
-.trans-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: px2rpx(10);
-  color: var(--white);
-
-  i {
-    font-size: var(--font-size-20);
-    cursor: pointer;
-  }
-}
-
-::v-deep .van-calendar {
-  background: var(--action-bg);
-}
-
-::v-deep .van-calendar__month-mark {
-  display: none;
-}
-
-::v-deep .van-calendar__header-subtitle {
-  color: var(--white);
-}
-
-::v-deep .van-calendar__header-title {
-  color: var(--white);
-}
-
-::v-deep .van-calendar__month-title {
-  color: var(--main-yellow);
-}
-
-.trans-title {
-  font-size: var(--font-size-20);
-  color: var(--white);
-  font-weight: bold;
-}
-
-.date-field {
-  width: px2rpx(200);
-
-  :deep(.van-field__control) {
-    color: var(--white);
-  }
-
-  :deep(.van-field__placeholder) {
-    color: var(--gray);
-  }
-}
-
-:deep(.van-popup) {
-  background: var(--action-bg);
-}
-
-:deep(.van-picker__toolbar) {
-  background: var(--action-bg);
-  border-bottom: 1px solid var(--border);
-}
-
-:deep(.van-picker__title) {
-  color: var(--white);
-}
-
-:deep(.van-picker__confirm) {
-  color: var(--main-yellow);
-}
-
-:deep(.van-picker__cancel) {
-  color: var(--gray);
-}
-
-:deep(.van-picker-column) {
-  color: var(--white);
-}
-
-:deep(.van-picker-column__item) {
-  color: var(--white);
-}
-
-:deep(.van-picker-column__item--selected) {
-  color: var(--main-yellow);
-}
-
-.transaction {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding: px2rpx(10) 0;
-  /* border-bottom: 1px solid var(--border); */
-  font-size: var(--font-size-16);
-}
-
-.transaction:last-child {
-  border-bottom: none;
-}
-
-.trans-left {
-  width: px2rpx(200);
-}
-
-.trans-right {
-  width: px2rpx(100);
-
-  view {
-    text-align: right;
-  }
-}
-
-.trans-type {
-  color: var(--white);
-  font-size: var(--font-size-14);
-  line-height: 2;
-}
-
-.trans-desc {
-  font-size: var(--font-size-12);
-  color: var(--gray);
-}
-
-.trans-amount {
-  font-size: var(--font-size-14);
-  color: var(--white);
-  line-height: 2;
-}
-
-.trans-date {
-  color: var(--gray);
-  font-size: var(--font-size-12);
-}
-
-.card-swiper {
-  position: relative;
-  overflow: hidden;
-  margin-bottom: px2rpx(20);
-  padding-bottom: px2rpx(5);
-}
-
-.swiper-container {
-  position: relative;
-  width: 100%;
-  height: px2rpx(209);
-  touch-action: pan-y pinch-zoom;
-  user-select: none;
-}
-
-.card-info {
-  position: absolute;
-  width: 100%;
-  height: 100%;
-  transition: transform 0.3s ease;
-  will-change: transform;
-}
-
-.swiper-controls {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  margin-top: px2rpx(16);
-  gap: px2rpx(16);
-}
-
-.swiper-btn {
-  background: var(--action-bg);
-  border: none;
-  border-radius: 50%;
-  width: px2rpx(32);
-  height: px2rpx(32);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  cursor: pointer;
-  color: var(--main-yellow);
-
-  &:disabled {
-    opacity: 0.5;
-    cursor: not-allowed;
-  }
-
-  i {
-    font-size: var(--font-size-20);
-  }
-}
-
-.swiper-dots {
-  display: flex;
-  gap: px2rpx(8);
-}
-
-.dot {
-  width: px2rpx(8);
-  height: px2rpx(8);
-  border-radius: 50%;
-  background: var(--action-bg);
-  cursor: pointer;
-  transition: all 0.3s ease;
-
-  &.active {
-    background: var(--main-yellow);
-    transform: scale(1.2);
-  }
-}
-
-.swiper-indicators {
-  display: flex;
-  justify-content: center;
-  margin-top: px2rpx(16);
-  gap: px2rpx(8);
-}
-
-.indicator-dot {
-  width: px2rpx(8);
-  height: px2rpx(8);
-  border-radius: 50%;
-  background: var(--gray);
-  cursor: pointer;
-  transition: all 0.3s ease;
-
-  &.active {
-    background: var(--main-yellow);
-    transform: scale(1.2);
-  }
-}
-
-.flags {
-  width: px2rpx(20);
-  height: px2rpx(20);
-  cursor: pointer;
-  position: absolute;
-  top: px2rpx(10);
-  right: px2rpx(10);
-}
-
-.cwg-btn {
-  margin: px2rpx(36) 0 px2rpx(80) 0;
-}
-
-.card-info1 {
-  width: 100%;
-}
-
-.card-chip {
-  position: absolute;
-  right: px2rpx(12);
-  top: px2rpx(16);
-  width: px2rpx(18);
-  height: px2rpx(12);
-  background: linear-gradient(145deg, #f5f5f5, #eaeaea);
-  border-radius: px2rpx(3);
-  border: 1px solid #bbb;
-  box-shadow: 0 px2rpx(1) px2rpx(3) rgba(0, 0, 0, 0.1);
-}
-
-.card-title {
-  margin: px2rpx(24) 0 px2rpx(12) 0;
-  font-weight: 600;
-  font-size: px2rpx(22);
-  line-height: px2rpx(28);
-  text-align: left;
-  color: #1a1a1a;
-}
-
-.card-list {
-  list-style: none;
-  padding: px2rpx(12) 0;
-  margin: 0;
-  width: 100%;
-  flex: 1;
-  overflow-y: auto;
-  box-shadow: 0 px2rpx(4) px2rpx(20) rgba(140, 145, 143, 0.194);
-  border-radius: px2rpx(10);
-}
-
-.card-list li {
-  display: flex;
-  justify-content: space-between;
-  font-size: var(--font-size-12);
-  color: #1a1a1a;
-  padding: px2rpx(12) px2rpx(24);
-  transition: all 0.3s ease;
-  position: relative;
-  font-family: "Roboto";
-  font-style: normal;
-  font-weight: 600;
-  font-size: px2rpx(14);
-  line-height: px2rpx(20);
-}
-
-.label {
-  display: inline-block;
-  font-weight: 600;
-  font-size: px2rpx(14);
-  line-height: px2rpx(20);
-  color: #8e8a8a;
-  width: px2rpx(100);
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  padding-right: px2rpx(10);
-}
-
-.card-list li:hover {
-  background: rgba(73, 247, 166, 0.1);
-  border-radius: px2rpx(6);
-}
-
-.card-list li:last-child {
-  margin-bottom: 0;
-}
-
-.card-list li text:first-child {
-  color: #bbb;
-}
-
-.card-content {
-  font-size: var(--font-size-16);
-  color: #474747;
-  margin: 0 0 px2rpx(26) 0;
-  text-align: left;
-  line-height: px2rpx(24);
-}
-
-.a1 {
-  flex: 1;
-}
-
-.card-list {
-  .one {
-    margin: px2rpx(12) px2rpx(24);
-    padding: px2rpx(12) 0;
-    border-top: 1px dashed #beb6b6;
-    color: #329644;
-    font-family: Roboto;
-    font-size: px2rpx(28);
-    font-style: normal;
-    font-weight: 700;
-    line-height: px2rpx(36);
-    align-items: flex-end;
-
-    .label {
-      color: #343434;
-      font-family: Roboto;
-      font-size: px2rpx(16);
-      font-style: normal;
-      font-weight: 600;
-      line-height: px2rpx(24);
-    }
-  }
-
-  .error {
-    color: #d32f2f;
-  }
-
-  .default {
-    color: #009deb;
-  }
-}
-
-.step {
-  display: flex;
-  align-items: flex-start;
-  padding: px2rpx(20) 0;
-  color: #000;
-
-  .step-item {
-    width: px2rpx(315);
-    position: relative;
-    text-align: center;
-    margin-right: px2rpx(20);
-    text-align: left;
-    font-size: px2rpx(16);
-    padding-top: px2rpx(20);
-
-    &::after {
-      content: "";
-      position: absolute;
-      top: 0;
-      right: 0;
-      width: 100%;
-      z-index: 1;
-      height: px2rpx(5);
-      position: absolute;
-      background: #f1f1f1;
-    }
-  }
-
-  .step-active {
-    font-weight: bold;
-
-    &::after {
-      background: #eb3f57;
-    }
-  }
-}
-
-.status-box {
-  width: 100%;
-  display: flex;
-  align-items: flex-start;
-  justify-content: flex-start;
-  flex-wrap: wrap;
-  padding: px2rpx(20) 0;
-
-  .status {
-    font-weight: 600;
-    font-size: px2rpx(22);
-    line-height: px2rpx(28);
-    text-align: left;
-    color: #1a1a1a;
-    display: flex;
-    align-items: center;
-  }
-
-  .status-img {
-    width: px2rpx(20);
-    height: px2rpx(20);
-    padding-right: px2rpx(10);
-    flex-shrink: 0;
-  }
-
-  .qr-container {
-    justify-content: flex-start;
-  }
-
-  view {
-    width: 100%;
-    text-align: start;
-    color: #6f6f6f;
-    font-size: px2rpx(16);
-    font-weight: 400;
-    word-wrap: break-word;
-    line-height: px2rpx(32);
-
-    text {
-      display: block;
-      padding: px2rpx(8) 0;
-    }
-  }
-
-  .a-title {
-    color: #333333;
-    font-size: px2rpx(18);
-    font-weight: 500;
-    word-wrap: break-word;
-    margin-top: px2rpx(44);
-  }
-
-  .step-box {
-    width: 100%;
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: space-between;
-    margin-top: px2rpx(20);
-
-    .step-item {
-      width: 100%;
-      padding: 0 0 px2rpx(20) px2rpx(40);
-      text-align: center;
-      position: relative;
-
-      &::after {
-        content: "";
-        position: absolute;
-        top: 0;
-        left: px2rpx(15);
-        width: 0;
-        height: 100%;
-        border-left: 1px dashed #ccc;
-        z-index: 1;
-      }
-
-      &:last-child {
-        &::after {
-          display: none;
-        }
-      }
-
-      .ids {
-        position: absolute;
-        left: 0;
-        top: 0;
-        width: px2rpx(30);
-        height: px2rpx(30);
-        position: absolute;
-        color: #000;
-        line-height: px2rpx(30);
-        background-color: #fff;
-        text-align: center;
-        border-radius: px2rpx(9999);
-        border: 1px #ccc dashed;
-        z-index: 12;
-        padding: 0;
-      }
-
-      .k {
-        font-size: px2rpx(14);
-        color: #333333;
-        font-weight: bold;
-        padding: 0;
-      }
-
-      .v {
-        font-size: px2rpx(14);
-        color: #6f6f6f;
-        padding: 0;
-      }
-    }
-  }
-
-  .f {
-    margin: px2rpx(20) 0 0 0;
-    color: #333333;
-    font-size: px2rpx(15);
-    font-family: PingFang SC;
-    font-weight: 500;
-    word-wrap: break-word;
-  }
-}
-</style>

+ 0 - 17
pages/apply-record/detail.vue

@@ -1,17 +0,0 @@
-<template>
-  <cwg-page-wrapper>
-    <ApplyRecord :id="id" :type="type" />
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, computed } from "vue";
-import ApplyRecord from "./components/ApplyRecord.vue";
-import { onLoad } from '@dcloudio/uni-app'
-const id = ref("");
-const type = ref("");
-onLoad((options) => {
-  id.value = options.id
-  type.value = options.type
-})
-</script>

+ 0 - 274
pages/apply-record/list.vue

@@ -1,274 +0,0 @@
-<template>
-  <cwg-page-wrapper>
-    <view class="page page-shadow">
-      <view class="apply-card-footer">
-        <view v-if="cardList.length > 0">
-          <view class="kyc-list">
-            <view v-for="item in cardList" :key="item.id" class="kyc-item">
-              <view class="g">
-                <view class="g-l">
-                  <view class="g-item">
-                    <view class="label a1 ellipsis">{{ item.cardName }}</view>
-                    <view class="status" :class="statusClass1(item.status)">{{
-                      status[item.status]
-                      }}</view>
-                  </view>
-                  <view class="g-item">
-                    <view class="label a2">{{
-                      item?.cardNumber?.replace(
-                        /(\d{4})\d+(\d{4})/,
-                        "$1 **** **** $2"
-                      )
-                    }}</view>
-                  </view>
-                </view>
-              </view>
-              <view class="g">
-                <view class="g-l g-l1">
-                  <view class="g-item">
-                    <view class="label a3">{{ t("cards.p12") }}</view>
-                    <view class="status-views" @click="handleApply(item)">{{
-                      t("cards.p11")
-                      }}</view>
-                  </view>
-                </view>
-              </view>
-            </view>
-          </view>
-        </view>
-        <cwg-empty-state v-if="cardList.length === 0" :title="t('empty-state.t3')" :text="t('empty-state.c3')" />
-      </view>
-    </view>
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, computed } from "vue";
-import type { CardInfo } from "@/api/ucard";
-import { useI18n } from "vue-i18n";
-import useRouter from "@/hooks/useRouter";
-import { ucardApi } from "@/api/ucard";
-import useCardStore from "@/stores/use-card-store";
-const cardStore = useCardStore();
-const router = useRouter();
-const { t } = useI18n();
-const status: Record<string, string> = {
-  success: t("card.Status.t6"),
-  fail: t("card.Status.t7"),
-  processing: t("card.Status.t3"),
-  wait_process: t("card.Status.t3"),
-  cancel: t("card.New2.p3"),
-  null: t("card.Status.t3"),
-};
-function statusClass1(status: string) {
-  switch (status) {
-    case "success":
-      return "status-default status-success";
-    case "fail":
-      return "status-default status-error";
-    case "cancel":
-      return "status-default status-error";
-    default:
-      return "status-default";
-  }
-}
-
-const cardList = ref<CardInfo[]>([]);
-const search = ref({});
-async function getCardList() {
-  try {
-    const res = await ucardApi.applyList({
-      ...search.value,
-      page: { current: 1, row: 10 },
-    });
-    if (res.code == 200) {
-      const a = res.data.map((i) => {
-        if (i.cardNumber) {
-          i.isOk = true;
-        } else {
-          i.isOk = false;
-          i.cardNumber = "**** **** **** ****";
-        }
-        return i;
-      });
-      cardList.value = a;
-    } else {
-      cardList.value = [];
-    }
-    cardStore.saveApplyCard(cardList.value);
-  } catch (error) {
-    cardList.value = [];
-  }
-}
-function handleApply(item: any) {
-  router.push({
-    path: "/pages/apply-record/detail",
-    query: {
-      id: item.id,
-    },
-  });
-}
-
-onMounted(async () => {
-  getCardList();
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.apply-card-footer {
-  width: 100%;
-}
-
-.kyc-item {
-  display: flex;
-  align-items: center;
-  flex-direction: column;
-  padding: px2rpx(12);
-  border-bottom: 1px solid var(--border, #333);
-  font-size: px2rpx(16);
-  background: var(--action-bg);
-  border-radius: px2rpx(16);
-  margin-bottom: px2rpx(16);
-  border: 1px solid rgba(214, 255, 0, 0.2);
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
-  gap: px2rpx(16);
-}
-
-.kyc-item:last-child {
-  border-bottom: none;
-}
-
-.g {
-  width: 100%;
-
-  img {
-    width: px2rpx(56);
-    height: px2rpx(35);
-  }
-
-  .g-l {
-    margin-left: 0;
-
-    .g-item {
-      margin-bottom: 0;
-    }
-
-    .label {
-      font-family: 'Roboto';
-      font-style: normal;
-      font-weight: 600;
-      font-size: px2rpx(14);
-      line-height: px2rpx(16);
-      text-align: left;
-      color: #1a1a1a;
-      width: px2rpx(180);
-    }
-
-    .a2 {
-      color: #6b7280;
-      font-size: px2rpx(12);
-      line-height: px2rpx(16);
-    }
-
-    .a1 {
-      line-height: px2rpx(16);
-    }
-
-    .a3 {
-      color: #8e8a8a;
-      font-family: Roboto;
-      font-size: px2rpx(14);
-      font-style: normal;
-      font-weight: 400;
-      line-height: px2rpx(16);
-      letter-spacing: px2rpx(0.07);
-    }
-  }
-
-  .g-l1 {
-    margin-left: 0;
-  }
-}
-</style>
-
-//
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-// .apply-card-footer {
-//   width: 100%;
-// }
-
-// .kyc-item {
-//   display: flex;
-//   align-items: center;
-//   flex-direction: column;
-//   padding: px2rpx(12);
-//   border-bottom: 1px solid var(--border, #333);
-//   font-size: px2rpx(31);
-//   background: var(--action-bg);
-//   border-radius: px2rpx(31);
-//   margin-bottom: px2rpx(31);
-//   border: 1px solid rgba(214, 255, 0, 0.2);
-//   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
-//   gap: px2rpx(31);
-// }
-
-// .kyc-item:last-child {
-//   border-bottom: none;
-// }
-
-// .g {
-//   width: 100%;
-
-//   img {
-//     width: px2rpx(111);
-//     height: px2rpx(35);
-//   }
-
-//   .g-l {
-//     margin-left: 0;
-
-//     .g-item {
-//       margin-bottom: 0;
-//     }
-
-//     .label {
-//       font-family: "Roboto";
-//       font-style: normal;
-//       font-weight: 600;
-//       font-size: px2rpx(14);
-//       line-height: px2rpx(31);
-//       text-align: left;
-//       color: #1a1a1a;
-//       width: px2rpx(330);
-//     }
-
-//     .a2 {
-//       color: #6b7280;
-//       font-size: px2rpx(12);
-//       line-height: px2rpx(31);
-//     }
-
-//     .a1 {
-//       line-height: px2rpx(31);
-//     }
-
-//     .a3 {
-//       color: #8e8a8a;
-//       font-family: Roboto;
-//       font-size: px2rpx(14);
-//       font-style: normal;
-//       font-weight: 400;
-//       line-height: px2rpx(31);
-//       letter-spacing: px2rpx(0.07);
-//     }
-//   }
-
-//   .g-l1 {
-//     margin-left: 0;
-//   }
-// }
-// </style>

+ 0 - 474
pages/card/apply.vue

@@ -1,474 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="page page-shadow">
-            <u-form ref="formRef" :rules="rules" :model="formData" class="kyc-form">
-                <cwg-input v-model:value="infoForm.lastName" fkey="lastName" :required="true" :label="t('card.Form.f4')"
-                    rulesKey="lastName" :readonly="true" :disabled="true" @change="handleChange" />
-                <cwg-input v-model:value="infoForm.firstName" fkey="firstName" :required="true"
-                    :label="t('card.Form.f5')" rulesKey="firstName" :readonly="true" :disabled="true"
-                    @change="handleChange" />
-                <cwg-input v-model:value="infoForm.email" fkey="email" :label="t('card.Form.f3')" :required="true"
-                    rulesKey="email" :readonly="true" :disabled="true" @change="handleChange" />
-                <cwg-input v-model:value="infoForm.birthday" :required="true" type="date" fkey="birthday"
-                    :label="t('card.Form.f6')" rulesKey="birthday" :readonly="true" :disabled="true"
-                    @change="handleChange" />
-                <cwg-input v-model:value="infoForm.gender" fkey="gender" type="select" :required="true"
-                    :columns="sexOptions" :label="t('card.Form.f8')" rulesKey="gender" :readonly="true" :disabled="true"
-                    @change="handleChange" />
-                <cwg-input v-model:value="infoForm.mailingAreaCode" fkey="mailingAreaCode" type="select"
-                    :required="true" :columns="phoneCodes" :label="t('card.Form.f1')" rulesKey="mailingAreaCode"
-                    @change="handleChange" />
-                <cwg-input v-model:value="infoForm.mailingMobile" fkey="mailingMobile" :required="true"
-                    :label="t('card.Form.f2')" rulesKey="mailingMobile" :readonly="isReadonly" :disabled="isReadonly"
-                    @change="handleChange" />
-                <cwg-input v-model:value="infoForm.mailingCountry" fkey="mailingCountry" type="select" :required="true"
-                    :columns="countryOptions" :label="t('card.New1.d8')" rulesKey="mailingCountry"
-                    @change="handleChange" />
-                <cwg-input v-model:value="infoForm.mailingTown" fkey="mailingTown" type="select" :required="true"
-                    :columns="cityOptions" :label="t('card.New1.d9')" rulesKey="mailingTown" @change="handleChange" />
-                <cwg-input v-model:value="infoForm.addressCn" fkey="addressCn" :required="true"
-                    :label="t('card.New1.d10')" rulesKey="addressCn" :readonly="isReadonly" :disabled="isReadonly"
-                    @change="handleChange" />
-                <cwg-input v-model:value="infoForm.address" fkey="address" :required="true" :label="t('card.New1.d11')"
-                    rulesKey="address" :readonly="isReadonly" :disabled="isReadonly" @change="handleChange" />
-                <cwg-input v-model:value="infoForm.mailingPostCode" fkey="mailingPostCode" :required="true"
-                    :label="t('card.New1.d12')" rulesKey="mailingPostCode" :readonly="isReadonly" :disabled="isReadonly"
-                    @change="handleChange" />
-                <cwg-input v-model:value="infoForm.login" fkey="login" type="select" :required="true"
-                    :columns="typesOptions" :label="t('card.New.n10')" rulesKey="login" @change="handleChange" />
-                <view class="fixed-btn">
-                    <view class="cwg-button">
-                        <u-button type="primary" block @click="infoSubmit">{{ t('card.Btn.Submit') }}</u-button>
-                    </view>
-                </view>
-            </u-form>
-            <card-websdk-link ref="cardWebsdkLinkRef" />
-        </view>
-    </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, computed, onMounted } from 'vue'
-import { pinyin } from 'pinyin-pro'
-import { useI18n } from 'vue-i18n'
-import { onLoad } from '@dcloudio/uni-app'
-import useRouter from '@/hooks/useRouter'
-import useRoute from '@/hooks/useRoute'
-import { ucardApi } from '@/api/ucard'
-import { userApi } from '@/api/user'
-import useUserStore from '@/stores/use-user-store'
-import { Patterns, Validators } from '@/utils/validators'
-import CardWebsdkLink from '@/components/card-websdkLink.vue'
-
-const cardWebsdkLinkRef = ref<InstanceType<typeof CardWebsdkLink> | null>(null)
-const userStore = useUserStore()
-const userInfo = computed(() => userStore.userInfo)
-const { t } = useI18n()
-const router = useRouter()
-const route = useRoute()
-const formRef = ref()
-const reductionData = ref(0)
-const isViews = ref(false)
-
-// 路由参数
-const type = ref<string>('')
-const cardTypeId = ref<string>('')
-
-onLoad((options) => {
-    type.value = options?.type || ''
-    cardTypeId.value = options?.cardTypeId || ''
-})
-
-// 国家选项
-const countryOptions = ref<Array<{ text: string, value: string }>>([])
-const cityOptions = ref<Array<{ text: string, value: string }>>([])
-const phoneCodes = ref<Array<{ text: string, value: string }>>([])
-const isReadonly = computed(() => infoForm.value?.authStatus == 1)
-
-const sexOptions = ref([
-    { text: t('card.Form.v1'), value: 'M' },
-    { text: t('card.Form.v2'), value: 'F' },
-])
-const typesOptions = ref<Array<any>>([])
-const idTypeOptions = ref([
-    { text: t('card.Form.v3'), value: 'EUROPEAN_ID' },
-    { text: t('card.Form.v4'), value: 'PASSPORT' },
-])
-
-// 表单验证规则
-const rules = {
-    mailingAreaCode: [Validators.required(t('card.vaildate.v1'))],
-    mailingMobile: [Validators.required(t('card.vaildate.v2')), Validators.pattern(Patterns.mobile, t('card.vaildate.v44'))],
-    mailingCountry: [Validators.required(t('card.vaildate.v6'), 'change')],
-    mailingTown: [Validators.required(t('card.vaildate.v7'), 'change')],
-    login: [Validators.required(t('vaildate.select.empty') + t('card.New.n10'), 'change')],
-    address: [
-        Validators.required(t('card.vaildate.v27')),
-        Validators.custom((val: any) => {
-            const v = String(val ?? '').trim()
-            if (v.length < 2 || v.length > 40)
-                return t('card.New.n1')
-            return Patterns.address.test(v) ? true : t('card.New.n1')
-        }),
-    ],
-    addressCn: [Validators.required(t('card.vaildate.v27')), Validators.pattern(Patterns.addressCn, t('card.vaildate.v27'))],
-    mailingPostCode: [Validators.required(t('card.vaildate.v8')), Validators.pattern(Patterns.postcode, t('card.New.n2'))],
-}
-
-const infoForm = ref({
-    gender: undefined,
-    mailingMobile: undefined,
-    mailingAreaCode: undefined,
-    mailingCountry: undefined,
-    mailingTown: undefined,
-    addressCn: undefined,
-    address: undefined,
-    mailingPostCode: undefined,
-    login: undefined,
-    email: undefined,
-    lastName: undefined,
-    firstName: undefined,
-    birthday: undefined,
-})
-
-const formData = ref<typeof infoForm.value>({} as any)
-const formDatas = ref<typeof infoForm.value>({} as any)
-const isShow = ref(false)
-
-async function infoSubmit() {
-    try {
-        const requiredFields = [
-            'mailingMobile',
-            'mailingAreaCode',
-            'mailingCountry',
-            'mailingTown',
-            'addressCn',
-            'address',
-            'mailingPostCode',
-            'login',
-        ] as const
-        await formRef.value?.validate(requiredFields)
-    }
-    catch (error: any) {
-        if (Array.isArray(error) && error.length > 0) {
-            uni.showToast({
-                title: error[0].message,
-                icon: 'none'
-            })
-        }
-        else {
-            uni.showToast({
-                title: t('card.New.errer'),
-                icon: 'none'
-            })
-        }
-        return
-    }
-
-    const res = await ucardApi.ucardApply({ ...formData.value, cardTypeId: cardTypeId.value })
-    if (res.code === 200) {
-        uni.showToast({
-            title: t('card.Msg.m1'),
-            icon: 'success'
-        })
-        // 成功后打开 WebSDK 弹窗
-        if (cardWebsdkLinkRef.value) {
-            cardWebsdkLinkRef.value.getWebsdkLink(
-                (res.data as any)?.cardId ||
-                (formData.value as any)?.cId ||
-                cardTypeId.value
-            )
-        }
-        goCardPage()
-    }
-    else {
-        uni.showToast({
-            title: res.msg || t('common.error'),
-            icon: 'none'
-        })
-    }
-}
-
-async function handleChange(value: any) {
-    formData.value = { ...formData.value, [value.key]: value.value }
-
-    if (value.key === 'login') {
-        if (value.value == -1) {
-            formData.value.discountType = 2
-        }
-        else {
-            const res = typesOptions.value.find((item: any) => item.login == value.value)
-            formData.value.discountType = 1
-            formData.value.platform = res?.platform
-        }
-    }
-    if (value.key === 'addressCn') {
-        const containsChinese = (str: string) => /[\u4E00-\u9FA5]/.test(str)
-        if (containsChinese(value.value)) {
-            formData.value.address = await formatText(value.value)
-            infoForm.value.address = await formatText(value.value)
-        }
-        else {
-            formData.value.address = value.value
-            infoForm.value.address = value.value
-        }
-    }
-    if (value.key === 'mailingCountry') {
-        formData.value.mailingCountry = value.value
-        await getCityListForSelect(value.value)
-        formData.value.mailingTown = ''
-        infoForm.value.mailingTown = ''
-    }
-}
-
-function formatText(input: string) {
-    const chinesePattern = /[\u4E00-\u9FA5]+/g
-    const formattedText = input.replace(chinesePattern, (match) => {
-        return ` ${pinyin(match, { toneType: 'none', type: 'capitalize' })} `
-    })
-    return formattedText
-}
-
-async function reductionNum() {
-    const { cId } = formData.value
-    if (!cId) return
-    const res = await ucardApi.reductionNum({ cId })
-    if (res.code === 200) {
-        reductionData.value = res.data
-    }
-}
-
-async function accountDropdown() {
-    const res = await userApi.accountDropdown()
-
-    if (res.code === 200) {
-        const data = flatData(res.data)
-        const loginOptions = data.map((item: any) => {
-            item.discountType = 1
-            item.text
-                = `${item.login} - ${groupTypeName(item.type)} - ${t('kyc.AvailableBalance')}${groupCurrency(item.currency)}${item.balance}`
-            item.value = item.login
-            item.disabled = item.closeFunctions?.includes('1')
-            if (item.balance == 0) {
-                item.disabled = true
-            }
-            return item
-        })
-        loginOptions.push({
-            discountType: 2,
-            text: t('kyc.AvailableBalance1') + reductionData.value,
-            login: -1,
-            value: -1,
-            disabled: reductionData.value == 0,
-        })
-
-        typesOptions.value = loginOptions
-    }
-}
-
-function groupTypeName(type: string) {
-    if (type == '1') {
-        return t('AccountType.ClassicAccount')
-    }
-    else if (type == '2') {
-        return t('AccountType.SeniorAccount')
-    }
-    else if (type == '5') {
-        return t('AccountType.SpeedAccount')
-    }
-    else if (type == '6') {
-        return t('AccountType.SpeedAccount')
-    }
-    else if (type == '7') {
-        return t('AccountType.StandardAccount')
-    }
-    else if (type == '8') {
-        return t('AccountType.CentAccount')
-    }
-    else if (type == '3') {
-        return t('AccountType.AgencyAccount')
-    }
-    return ''
-}
-
-function groupCurrency(type: string) {
-    if (type == 'GBP') {
-        return ': £'
-    }
-    else if (type == 'USD') {
-        return ': $'
-    }
-    else if (type == 'EUR') {
-        return ': €'
-    }
-    else if (type == 'USC') {
-        return ': ¢'
-    }
-    else {
-        return ': $'
-    }
-}
-
-function flatData(data: any[]) {
-    return data.flatMap((card) => {
-        if (!card.rechargeCurrencyInfoList || card.rechargeCurrencyInfoList.length === 0) {
-            return [
-                {
-                    ...card,
-                    currency: null,
-                    rechargeFeeRate: null,
-                    rechargeFixedFee: null,
-                    rechargeMaxQuota: null,
-                    rechargeMinQuota: null,
-                },
-            ]
-        }
-        return card.rechargeCurrencyInfoList.map((recharge: any) => ({
-            ...card,
-            ...recharge,
-        }))
-    })
-}
-
-// 获取国家列表
-async function getCountryListForSelect() {
-    try {
-        const res = await ucardApi.ucardCountryCity({})
-        if (res.code === 200 || res.code === 0) {
-            countryOptions.value = res.data.map((item: any) => ({
-                text: item.enName,
-                value: item.code,
-            }))
-            phoneCodes.value = res.data
-                .map((item: any) => ({
-                    text: `${item.enName} ${item.areaCode}`,
-                    value: item.areaCode,
-                }))
-                .filter((item: any) => item.value !== null && item.value !== '-')
-        }
-    }
-    catch (error) {
-        //  console.error('获取国家列表失败:', error)
-        countryOptions.value = []
-    }
-}
-
-// 获取城市列表
-async function getCityListForSelect(countryCode: string) {
-    try {
-        const res = await ucardApi.ucardCountryCity({ code: countryCode })
-        if (res.code === 200 || res.code === 0) {
-            const cityList = res.data.map((item: any) => ({
-                text: item.enName,
-                value: item.code,
-            }))
-            cityOptions.value = cityList
-        }
-    }
-    catch (error) {
-        //  console.error('获取城市列表失败:', error)
-        cityOptions.value = []
-    }
-}
-
-function goCardPage() {
-    router.push({
-        path: '/pages/card/index',
-    })
-}
-
-onMounted(async () => {
-    //  console.log(userInfo.value, 1988)
-
-    // 第一步:先回显基本信息(不依赖下拉数据的字段)
-    const userData = userInfo.value as any
-    infoForm.value = {
-        lastName: userData.lastName,
-        firstName: userData.firstName,
-        email: userData.email,
-        birthday: userData.birthday,
-        gender: userData.gender,
-    }
-    formData.value = {
-        lastName: userData.lastName,
-        firstName: userData.firstName,
-        email: userData.email,
-        birthday: userData.birthday,
-        gender: userData.gender,
-    }
-
-    // 第二步:加载下拉数据
-    await getCountryListForSelect()
-
-    // 第三步:等待下拉数据加载完成后,再回显国家和城市等字段
-    if (userData.mailingCountry) {
-        await getCityListForSelect(userData.mailingCountry)
-        // 城市列表加载完成后再回显
-        infoForm.value.mailingCountry = userData.mailingCountry
-        infoForm.value.mailingTown = userData.mailingTown
-        formData.value.mailingCountry = userData.mailingCountry
-        formData.value.mailingTown = userData.mailingTown
-    }
-
-    // 回显其他地址相关字段
-    infoForm.value.mailingAreaCode = userData.mailingAreaCode
-    infoForm.value.mailingMobile = userData.mailingMobile
-    infoForm.value.addressCn = userData.addressCn
-    infoForm.value.address = userData.address
-    infoForm.value.mailingPostCode = userData.mailingPostCode
-
-    formData.value.mailingAreaCode = userData.mailingAreaCode
-    formData.value.mailingMobile = userData.mailingMobile
-    formData.value.addressCn = userData.addressCn
-    formData.value.address = userData.address
-    formData.value.mailingPostCode = userData.mailingPostCode
-
-    // 加载其他数据
-    await reductionNum()
-    await accountDropdown()
-
-    // 最后回显登录账户字段(需要等待 accountDropdown 完成)
-    if (userData.login) {
-        infoForm.value.login = userData.login
-        formData.value.login = userData.login
-    }
-})
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page {
-    // padding: px2rpx(12) px2rpx(16);
-    padding-bottom: px2rpx(100);
-}
-
-.pointer-none {
-    pointer-events: none;
-}
-
-.f {
-    display: flex;
-    align-items: flex-end;
-    gap: px2rpx(12);
-
-    .l {
-        flex: 1;
-    }
-
-    .r {
-        width: px2rpx(273);
-    }
-}
-
-.fixed-btn {
-    position: fixed;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    padding: px2rpx(16);
-    background: #fff;
-    box-shadow: 0 px2rpx(-2) px2rpx(10) rgba(0, 0, 0, 0.1);
-    z-index: 100;
-}
-</style>

+ 0 - 304
pages/card/components/CardHandle.vue

@@ -1,304 +0,0 @@
-<template>
-  <u-modal v-model:show="showDialog" class="card-handle-dialog" :title="t('card.vaildate.v42')"
-    :show-confirm-button="false" :show-cancel-button="false" :close-on-click-overlay="false" @closed="handleClose">
-    <view class="card-handle-dialog-content">
-      <u-form ref="formRef" :model="form" class="payment-form">
-        <view class="code-input-label">{{ t("newSignup.item9") }}</view>
-        <view class="code-input-wrapper">
-          <view class="code-input">
-            <cwg-input v-model:value="form.emailCode" fkey="emailCode" type="text" :required="true"
-              :placeholder="t('newSignup.item10')" @change="handleChange" />
-          </view>
-          <view class="get-code-btn">
-            <view class="cwg-button ok-button">
-              <u-button type="primary" block @click="handleGetCode">{{
-                getCodeString
-                }}</u-button>
-            </view>
-          </view>
-        </view>
-        <cwg-input v-if="cvv" v-model:value="cvv" fkey="cvv" type="text" label="CVV" :readonly="true"
-          :disabled="true" />
-      </u-form>
-
-      <view class="dialog-footer">
-        <view v-if="!cvv" class="cwg-button ok-button">
-          <u-button type="primary" block @click="handleConfirm">{{
-            t("card.vaildate.v42")
-            }}</u-button>
-        </view>
-        <view v-else class="cwg-button ok-button">
-          <u-button type="primary" block @click="cardCopy">{{
-            t("card.vaildate.v43")
-            }}</u-button>
-        </view>
-        <view class="cwg-button no-button">
-          <u-button type="default" block @click="handleClose">{{
-            t("card.Btn.Cancel")
-            }}</u-button>
-        </view>
-      </view>
-    </view>
-  </u-modal>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, onBeforeUnmount } from "vue";
-import { showToast } from "@/utils/toast";
-import { useI18n } from "vue-i18n";
-import { ucardApi } from "@/api/ucard";
-import errorIcon from "/static/images/error.png";
-import copyIcon from "/static/images/success.png";
-import { useEmailCountdown } from '@/hooks/useEmailCountdown';
-const {
-  time,
-  text: getCodeString,
-  canSend,
-  start,
-  restore
-} = useEmailCountdown({ storageKey: 'cvvTimer' })
-const { t } = useI18n();
-const props = defineProps<{
-  dialogInfoTradingAdd: boolean;
-  formList: Record<string, any>;
-}>();
-
-const emit = defineEmits(["closeAdd"]);
-
-const showDialog = ref(false);
-const formRef = ref();
-const form = ref<{
-  emailCode: string;
-  password?: string;
-  country?: string;
-  email?: string;
-}>({
-  emailCode: "",
-});
-const cvv = ref("");
-const rules = {
-  emailCode: [
-    {
-      required: true,
-      message: t("vaildate.code.empty"),
-    },
-  ],
-};
-
-// 监听 props 变化
-watch(
-  () => props.dialogInfoTradingAdd,
-  (newVal) => {
-    showDialog.value = newVal;
-    if (newVal) {
-      initForm();
-      restore()
-    } else {
-      handleClose();
-    }
-  },
-  { immediate: true }
-);
-
-// 初始化表单
-function initForm() {
-  if (props.formList) {
-    form.value = {
-      ...JSON.parse(JSON.stringify(props.formList)),
-      emailCode: "",
-    };
-  }
-  cvv.value = "";
-}
-
-// 发送邮箱验证码
-async function sendEmailCode() {
-  try {
-    if (!form.value.country) {
-      showToast(t("vaildate.country.empty"));
-      return false;
-    }
-    if (!form.value.email) {
-      showToast(t("vaildate.email.empty"));
-      return false;
-    }
-
-    const res = await ucardApi.sendEmailCode({
-      ...form.value,
-    });
-
-    if (res.code === 200) {
-      showToast(t("Msg.CodeSuccess"));
-      start();
-      return true;
-    } else {
-      showToast(t("Msg.CodeFail"));
-      return false;
-    }
-  } catch (error: any) {
-    console.log(error, 12);
-
-    showToast(t("Msg.CodeFail"));
-    return false;
-  }
-}
-
-// 获取验证码按钮点击
-async function handleGetCode() {
-  if (!canSend.value) {
-    return;
-  }
-  cvv.value = "";
-  await sendEmailCode();
-}
-
-// 表单字段变化
-function handleChange(value: any) {
-  if (value.key === "emailCode") {
-    form.value.emailCode = value.value;
-  }
-}
-
-// 确认获取 CVV
-async function handleConfirm() {
-  try {
-    await formRef.value?.validate();
-    if (!form.value.emailCode) {
-      // showToast(t('vaildate.code.empty'))
-      return;
-    }
-
-    const res = await ucardApi.getCvvCode({
-      ...form.value,
-    } as any);
-
-    if (res.code === 200) {
-      cvv.value = res.data;
-    } else {
-      showToast(res.msg);
-      cvv.value = "";
-    }
-  } catch (error: any) {
-    if (Array.isArray(error) && error.length > 0) {
-      showToast({
-        message: error[0].message,
-        icon: errorIcon,
-        className: "custom-toast",
-      });
-    } else {
-      showToast({
-        message: error?.message,
-        icon: errorIcon,
-        className: "custom-toast",
-      });
-    }
-  }
-}
-
-// 复制 CVV
-function cardCopy() {
-  let title = t("common.copy2");
-  uni.setClipboardData({
-    data: cvv.value,
-    success: () => {
-      uni.showToast({
-        title,
-      });
-    },
-  });
-}
-
-// 降级复制方案
-function fallbackCopy() {
-  const textarea = document.createElement("textarea");
-  textarea.value = cvv.value;
-  textarea.setAttribute("readonly", "");
-  textarea.style.position = "absolute";
-  textarea.style.left = "-9999px";
-  document.body.appendChild(textarea);
-  textarea.select();
-  try {
-    document.execCommand("copy");
-    showToast({
-      message: t("card.Msg.m8"),
-      icon: copyIcon,
-      className: "custom-toast",
-    });
-  } catch (_err) {
-    showToast({
-      message: t("card.Msg.m9"),
-      icon: errorIcon,
-      className: "custom-toast",
-    });
-  }
-  document.body.removeChild(textarea);
-}
-
-// 关闭对话框
-function handleClose() {
-  showDialog.value = false;
-  emit("closeAdd", false);
-  restore()
-}
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.card-handle-dialog {
-  width: 100%;
-
-  :deep(.u-popup__content) {
-    width: 90% !important;
-  }
-
-  :deep(.u-modal) {
-    width: 100% !important;
-  }
-
-  .card-handle-dialog-content {
-    padding: px2rpx(44) px2rpx(2);
-
-    .no-button {
-      width: 100%;
-      margin: px2rpx(12) 0;
-
-      .u-button {
-        background-color: #ffbdc8 !important;
-      }
-    }
-
-    .ok-button {
-      margin: px2rpx(4) 0;
-      /* background-color: #EA002A; */
-    }
-  }
-
-  .code-input-label {
-    font-size: var(--font-size-16);
-    line-height: px2rpx(44);
-    letter-spacing: px2rpx(1);
-    color: #474747;
-  }
-
-  .code-input-wrapper {
-    position: relative;
-    display: flex;
-    align-items: center;
-  }
-
-  .code-input {
-    flex: 1;
-  }
-
-  .get-code-btn {
-    min-width: px2rpx(100);
-    margin-bottom: px2rpx(12);
-    margin-left: px2rpx(10);
-
-    .cwg-button .u-button {
-      border-radius: px2rpx(8);
-    }
-  }
-}
-</style>

+ 0 - 352
pages/card/components/FirstApply.vue

@@ -1,352 +0,0 @@
-<template>
-  <view class="page">
-    <view class="status-box">
-      <view v-t="'card.Info.s11'"></view>
-      <image src="/static/images/card/img2.png" mode="aspectFit" />
-      <view class="status-box-btn">
-        <view v-t="'card.Btn.b7'" class="btn-apply" :class="{ disabled: !isAuthVerified || isLoading }"
-          @click="handleApply"></view>
-      </view>
-      <view v-if="!isAuthVerified && !isLoading" class="auth-tip">
-        {{ t('pages.card.authTip') || '请先完成身份认证' }}
-      </view>
-      <view v-t="'card.Info.s12'" class="a-title"></view>
-      <view class="step-box">
-        <view class="step-item">
-          <view class="ids">1</view>
-          <view v-t="'card.Info.s13'" class="k"></view>
-          <view v-t="'card.Info.s14'" class="v"></view>
-        </view>
-        <view class="step-item">
-          <view class="ids">2</view>
-          <view v-t="'card.Info.s15'" class="k"></view>
-          <view v-t="'card.Info.s16'" class="v"></view>
-        </view>
-        <view class="step-item">
-          <view class="ids">3</view>
-          <view v-t="'card.Info.s17'" class="k"></view>
-          <view v-t="'card.Info.s18'" class="v"></view>
-        </view>
-        <view class="step-item">
-          <view class="ids">4</view>
-          <view v-t="'card.Info.s19'" class="k"></view>
-          <view v-t="'card.Info.s20'" class="v"></view>
-        </view>
-      </view>
-      <view v-t="'card.Info.s21'" class="f"></view>
-    </view>
-  </view>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, computed } from "vue";
-import { useI18n } from "vue-i18n";
-import useRouter from "@/hooks/useRouter";
-import { userApi } from "@/api/user";
-import useUserStore from "@/stores/use-user-store";
-import { userToken } from "@/composables/config";
-
-const router = useRouter();
-const { t } = useI18n();
-const userStore = useUserStore();
-const userInfo = computed(() => userStore.userInfo);
-
-// 认证状态
-const isAuthVerified = ref(false);
-const isLoading = ref(true);
-
-// 检查认证状态
-function checkAuthStatus(userData: any) {
-  // approveStatus == 2 或 kycStatus == 2 表示认证通过
-  if (userData?.approveStatus == 2) {
-    isAuthVerified.value = true;
-  } else {
-    isAuthVerified.value = false;
-  }
-}
-
-// 获取用户详情
-async function getUserSingle() {
-  if (!userToken.value) {
-    isLoading.value = false;
-    isAuthVerified.value = false;
-    return;
-  }
-
-  try {
-    isLoading.value = true;
-    const res = await userApi.getUserSingle();
-    if (res.code === 200 && res.data) {
-      // 更新用户信息到 store
-      userStore.saveUserInfo(res.data);
-      // 检查认证状态
-      checkAuthStatus(res.data);
-    } else {
-      isAuthVerified.value = false;
-    }
-  } catch (error: any) {
-    console.error('获取用户详情失败:', error);
-    isAuthVerified.value = false;
-  } finally {
-    isLoading.value = false;
-  }
-}
-
-function handleApply() {
-  if (!isAuthVerified.value || isLoading.value) {
-    uni.showToast({
-      title: t('pages.card.authTip') || '请先完成身份认证',
-      icon: 'none'
-    });
-    return;
-  }
-  router.push("/pages/card/select");
-}
-
-onMounted(async () => {
-  // 如果 store 中已有用户信息,先检查认证状态
-  if (userInfo.value) {
-    checkAuthStatus(userInfo.value);
-    isLoading.value = false;
-  }
-  // 调用接口获取最新用户信息
-  await getUserSingle();
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page {
-  // margin: 0 px2rpx(24) px2rpx(100) px2rpx(24);
-}
-
-.imgs {
-  margin-left: px2rpx(74);
-  margin-bottom: px2rpx(40);
-}
-
-.apply-card-steps {
-  width: 100%;
-  margin-bottom: px2rpx(52);
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-}
-
-.steps-top {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 100%;
-  position: relative;
-  max-width: px2rpx(600);
-  margin: 0 auto;
-}
-
-.step {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  position: relative;
-  z-index: 2;
-  flex: 0 0 auto;
-}
-
-.step-circle {
-  width: px2rpx(28);
-  height: px2rpx(28);
-  color: var(--main-yellow);
-  border-radius: 50%;
-  font-size: px2rpx(14);
-  font-weight: bold;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  border: 2px solid var(--main-yellow);
-  margin-bottom: px2rpx(8);
-  transition: all 0.3s ease;
-}
-
-.step-circle:hover {
-  transform: scale(1.1);
-  box-shadow: 0 0 10px rgba(73, 247, 166, 0.3);
-}
-
-.step-dash {
-  flex: 1;
-  height: px2rpx(2);
-  background: repeating-linear-gradient(to right,
-      var(--main-yellow),
-      var(--main-yellow) px2rpx(6),
-      transparent px2rpx(6),
-      transparent px2rpx(12));
-  min-width: px2rpx(18);
-  position: relative;
-  top: -px2rpx(16);
-}
-
-.step-label {
-  color: var(--white);
-  font-size: px2rpx(14);
-  font-weight: 500;
-  text-align: center;
-  line-height: 2;
-}
-
-.status-box {
-  width: 100%;
-  display: flex;
-  justify-content: flex-start;
-  flex-wrap: wrap;
-  margin-bottom: px2rpx(20);
-  gap: px2rpx(16);
-
-  .status {
-    width: 100%;
-    color: #333333;
-    font-size: px2rpx(26);
-    font-family: PingFang SC;
-    font-weight: 500;
-    word-wrap: break-word;
-    text-align: start;
-  }
-
-  view {
-    width: 100%;
-    text-align: start;
-    color: #6f6f6f;
-    font-size: px2rpx(18);
-    font-family: PingFang SC;
-    font-weight: 400;
-    word-wrap: break-word;
-    line-height: px2rpx(32);
-    padding: px2rpx(20) px2rpx(30) px2rpx(20) 0;
-    margin: 0;
-  }
-
-  .a-title {
-    color: #333333;
-    font-size: px2rpx(18);
-    font-family: PingFang SC;
-    font-weight: 500;
-    word-wrap: break-word;
-    margin-top: px2rpx(44);
-  }
-
-  .step-box {
-    width: 100%;
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: space-between;
-    margin-top: px2rpx(20);
-    padding: 0 0;
-
-    .step-item {
-      width: 100%;
-      padding: 0 0 px2rpx(10) px2rpx(60);
-      text-align: center;
-      position: relative;
-
-      &::after {
-        content: "";
-        position: absolute;
-        top: 0;
-        left: px2rpx(15);
-        width: 0;
-        height: 100%;
-        border-left: 1px dashed #ccc;
-        z-index: 1;
-      }
-
-      &:last-child {
-        &::after {
-          display: none;
-        }
-      }
-
-      .ids {
-        position: absolute;
-        left: 0;
-        top: 0;
-        width: px2rpx(30);
-        height: px2rpx(30);
-        padding: 0;
-        position: absolute;
-        color: #000;
-        line-height: px2rpx(30);
-        background-color: #fff;
-        text-align: center;
-        border-radius: px2rpx(9999);
-        border: 1px #ccc dashed;
-        z-index: 12;
-      }
-
-      .k {
-        font-size: px2rpx(14);
-        color: #333333;
-        font-weight: bold;
-        padding: 0;
-      }
-
-      .v {
-        font-size: px2rpx(14);
-        color: #6f6f6f;
-        padding: 0;
-      }
-    }
-  }
-
-  .f {
-    margin: px2rpx(20) 0 0 px2rpx(60);
-    color: #333333;
-    font-size: px2rpx(14);
-    font-family: PingFang SC;
-    font-weight: 500;
-    word-wrap: break-word;
-  }
-}
-
-.status-box-btn {
-  margin-top: px2rpx(20);
-  width: 100%;
-  display: flex;
-  justify-content: flex-start;
-
-  .btn-apply {
-    width: px2rpx(193);
-    height: px2rpx(40);
-    background: #eb3f57;
-    border-radius: px2rpx(4);
-    text-align: center;
-    color: white;
-    font-size: px2rpx(16);
-    font-family: Roboto;
-    font-weight: 600;
-    line-height: px2rpx(40);
-    cursor: pointer;
-    user-select: none;
-    padding: 0;
-    transition: all 0.3s ease;
-
-    &.disabled {
-      background: #ccc;
-      cursor: not-allowed;
-      opacity: 0.6;
-    }
-  }
-}
-
-.status-box-btn1 {
-  justify-content: center;
-}
-
-.auth-tip {
-  margin-top: px2rpx(12);
-  width: 100%;
-  color: #ff6b6b;
-  font-size: px2rpx(14);
-  text-align: left;
-  padding: 0 px2rpx(30) 0 0;
-}
-</style>

+ 0 - 1180
pages/card/components/VirtualCard.vue

@@ -1,1180 +0,0 @@
-<template>
-  <view v-if="cardList.length" class="page">
-    <view class="card-swiper">
-      <swiper class="swiper-container" :current="currentIndex" @change="handleSwiperChange">
-        <swiper-item v-for="(card, index) in cardList" :key="card.id">
-          <view class="card-wrapper">
-            <view class="card-info" :class="{ flipping: isFlipping[card.id] }"
-              @click.stop="(e: MouseEvent) => toggleCardNo(card, e)">
-              <view v-if="card.type == 'Virtual'" class="card-name">
-                {{ card.type || "Virtual" }}
-              </view>
-              <view v-if="card.type == 'Physical'" class="card-name">
-                {{ card.type || "Physical" }}
-              </view>
-              <image class="card-type" src="/static/images/c-type.png" alt="" srcset="" />
-              <image class="logo" src="/static/images/logo1.png" alt="" srcset="" />
-              <template v-if="showCardNo[card.id]">
-                <view class="number">
-                  {{ card?.cardNumber }}
-                  <view class="copy" @click.stop="cardCopy(card.cardNumber, 'cardNumber')"><cwg-icon name="copy"
-                      :size="13" color="" /></view>
-                </view>
-                <view class="card-b">
-                  <view class="valid">
-                    <view class="lable">{{ t("cards.p13") }}</view>
-                    <view>{{ card.firstName }} {{ card.lastName }}</view>
-                  </view>
-                  <view class="valid">
-                    <view class="lable">{{ t("cards.p14") }}</view>
-                    <view>{{ card.expireDate || "--" }}</view>
-                  </view>
-                  <view class="valid" @click.stop="setCvv">
-                    <view class="lable" v-if="!card.expireDate">CVV</view>
-                    <view v-if="!card.expireDate" class="cvv">
-                      ***
-                      <view class="copy"><cwg-icon name="icon_visiable" :size="13" color="" /></view>
-                    </view>
-                  </view>
-                </view>
-              </template>
-              <template v-else>
-                <view v-if="currentCard.status == 'success' && currentCard?.activateStatus" class="zw">{{
-                  card.cardNumber }}</view>
-                <view v-else class="zw">{{ "**** **** **** ****" }}</view>
-              </template>
-            </view>
-          </view>
-        </swiper-item>
-      </swiper>
-      <view v-if="cardList.length > 1" class="swiper-indicators">
-        <view v-for="(card, index) in cardList" :key="card.id" class="indicator-dot"
-          :class="{ active: index === currentIndex }" @click="currentIndex = index"></view>
-      </view>
-    </view>
-    <template v-if="currentCard.status == 'success' && currentCard?.activateStatus">
-      <view class="actions">
-        <template v-if="
-          currentCard.freezeType == 1 && currentCard.freezeStatus == 'success'
-        ">
-          <view class="action-btn" @click="ucardOperation(currentCard, 2)">
-            <cwg-icon name="icon_recharge" :size="28" color="#EA002A" />
-            <view>{{ t("card.Btn.b3") }}</view>
-          </view>
-          <view class="action-btn" @click="ucardOperation(currentCard, 3)">
-            <cwg-icon name="icon_card password reset" :size="28" color="#EA002A" />
-            <view>{{ t("card.Btn.b4") }}</view>
-          </view>
-        </template>
-        <template v-else>
-          <view class="action-btn action-btn1">
-            <cwg-icon name="icon_recharge" :size="28" color="#999" />
-            <view>{{ t("card.Btn.b3") }}</view>
-          </view>
-          <view class="action-btn action-btn1">
-            <cwg-icon name="icon_card password reset" :size="28" color="#999" />
-            <view>{{ t("card.Btn.b4") }}</view>
-          </view>
-        </template>
-        <view v-if="currentCard.freezeType == '1'" class="action-btn" @click="ucardOperation(currentCard, 4)">
-          <cwg-icon name="icon_unfreeze" :size="28" color="#EA002A" />
-          <view v-if="currentCard.freezeStatus == 'success'">{{
-            t("card.Btn.b5")
-            }}</view>
-          <view v-else>{{ t("card.Btn.b14") }}</view>
-        </view>
-        <view v-if="currentCard.freezeType == '2'" class="action-btn" @click="ucardOperation(currentCard, 5)">
-          <cwg-icon name="icon_freeze" :size="28" color="#EA002A" />
-          <view v-if="currentCard.freezeStatus == 'success'">{{
-            t("card.Btn.b6")
-            }}</view>
-          <view v-else>{{ t("card.Btn.b15") }}</view>
-        </view>
-      </view>
-      <view class="balance-wrap">
-        <!-- <view class="balance-content">{{ t('cards.currency') }}</view> -->
-        <view class="balance-content">{{ t("card.Btn.b10") }}</view>
-      </view>
-      <view class="balance-wrap balance-wrap1">
-        <view class="global-con-l">
-          <!-- <view class="global-con-l" @click="setModelValue"> -->
-          <image class="l-img" :src="imageSrc(currency)" alt="" srcset="" />
-          <view class="r">
-            <view>{{ currency }}</view>
-          </view>
-          <!-- <cwg-icon name="icon_dropdown" :size="24" /> -->
-        </view>
-        <view class="balance">
-          <view class="balance-amount">{{
-            isOpen ? amount + " " + "USD" : "*****"
-            }}</view>
-          <cwg-icon :name="isOpen ? 'icon_visiable' : 'icon_unvisiable'" :size="24" @click.stop="debouncedGetBalance" />
-        </view>
-      </view>
-      <view class="trans-header">
-        <view class="trans-title">{{ t("cards.transactions") }}</view>
-        <view class="all" @click="goRechargeRecord">{{
-          t("card.Status.t22")
-          }}</view>
-        <!-- <i class="i-mdi-calendar-month-outline" @click="showDatePicker = true" /> -->
-      </view>
-      <cwg-tabs :list="tabList" @click="handleTabClick" />
-      <view class="transaction-list">
-        <!-- Recharge Records -->
-        <view v-if="jiluIndex === 0" :a="currentCard.cardNumber">
-          <RechargeList :pageSize="4" ref="rechargeListRef" :cardNumber="currentCard.cardNumber" />
-        </view>
-        <!-- Transfer Records -->
-        <view v-if="jiluIndex === 1" :a="currentCard.cardNumber">
-          <TransactionList :pageSize="4" ref="rechargeListRef" :cardNumber="currentCard.cardNumber" />
-        </view>
-      </view>
-    </template>
-    <template v-else>
-      <view class="actions1">
-        <view class="card-btn">
-          <view class="yue st">
-            <view class="a">{{ t("card.Info.t15") }}</view>
-            <view v-if="
-              !currentCard.activateStatus &&
-              (currentCard.applyStatus == null ||
-                currentCard.applyStatus == 'wait_process' ||
-                currentCard.applyStatus == 'processing')
-            " v-t="'card.Info.t16'" class="v"></view>
-            <view v-if="currentCard.applyStatus == 'fail'" v-t="'card.Info.t17'" class="v"></view>
-            <view v-if="currentCard.activateStatus == 'unactivate'" v-t="'card.Info.t18'" class="v"></view>
-            <view v-if="
-              currentCard.activateStatus &&
-              (currentCard.status == 'processing' ||
-                currentCard.status == 'wait_process')
-            " v-t="'card.Info.t19'" class="v"></view>
-            <view v-if="currentCard.activateStatus == 'fail'" v-t="'card.Info.t20'" class="v"></view>
-          </view>
-          <!-- 查询进度 -->
-          <view v-if="!currentCard.activateStatus" class="btn1 btn2" @click="viewApply(currentCard)">
-            <view v-t="'card.Btn.b11'"></view>
-          </view>
-          <!-- 激活 -->
-          <view v-if="currentCard.activateStatus" class="btn1 btn2" :class="currentCard.activateStatus == 'unactivate' ||
-            currentCard.activateStatus == 'fail'
-            ? ''
-            : 'btn3'
-            " @click="ucardOperation(currentCard, 1)">
-            <view v-t="'card.Btn.b1'"></view>
-          </view>
-          <!-- 重新开卡 -->
-          <view v-if="
-            (currentCard.tradeStatus == '3' ||
-              (currentCard.tradeStatus == '2' &&
-                currentCard.tradeType == '2')) &&
-            currentCard.applyStatus == 'fail'
-          " class="btn1 btn2" @click="updateCardTypes(card, 1)">
-            <view v-t="'card.Btn.b12'"></view>
-          </view>
-        </view>
-      </view>
-    </template>
-    <CardHandle v-if="dialogInfoTradingAdd" :dialog-info-trading-add="dialogInfoTradingAdd" :form-list="formList"
-      @close-add="dialogInfoTradingAdd = false" />
-  </view>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, computed, onUnmounted } from "vue";
-import type { CardInfo } from "@/api/ucard";
-import { showToast } from "@/utils/toast";
-import { useI18n } from "vue-i18n";
-import useRouter from "@/hooks/useRouter";
-import { ucardApi } from "@/api/ucard";
-import _ from 'lodash';
-import useCardStore from "@/stores/use-card-store";
-import CardHandle from "./CardHandle.vue";
-import RechargeList from "@/pages/recharge-record/components/RechargeList.vue";
-import TransactionList from "@/pages/recharge-record/components/TransactionList.vue";
-const debouncedGetBalance = _.debounce(getBalance, 300, { leading: true, trailing: false });
-const router = useRouter();
-const cardStore = useCardStore();
-const cardList = computed(() => {
-  return cardStore.userCard;
-});
-const { t } = useI18n();
-const currentCard = computed<CardInfo | null>(() => {
-  if (!cardList.value.length) return null;
-  return cardList.value[currentIndex.value] || null;
-});
-const formList = ref({});
-const balance = ref<{ amount: number; currency: string; value: string }[]>([
-  {
-    amount: 0,
-    currency: "USD",
-    value: "USD",
-  },
-]);
-const showCardNo = ref<{ [key: string]: boolean }>({});
-const isFlipping = ref<{ [key: string]: boolean }>({});
-const isOpen = ref(false);
-const currentIndex = ref(0);
-const dialogInfoTradingAdd = ref(false);
-const images = import.meta.glob("/static/images/currency/*.png", {
-  eager: true,
-});
-const tabList = ref([
-  { name: t("cards.rechargeB1") },
-  { name: t("Shop.Index.Transaction") }
-]);
-
-const handleTabClick = (item, index) => {
-  jiluIndex.value = index;
-};
-
-function imageSrc(currency: string) {
-  return images[`/static/images/currency/${currency}.png`]?.default;
-}
-function setCvv() {
-  dialogInfoTradingAdd.value = true;
-  formList.value = currentCard.value;
-}
-const jiluIndex = ref(0);
-function cardCopy(data) {
-  let title = t("common.copy1");
-  console.log(title);
-  uni.setClipboardData({
-    data,
-    success: () => {
-      uni.showToast({ title });
-    },
-  });
-}
-const currency = ref("USD");
-const amount = ref(0);
-const dateRange = ref<[string, string] | undefined>(undefined);
-dateRange.value = ["", ""];
-
-function goRechargeRecord() {
-  router.push(`/pages/recharge-record/list?cardNumber=${currentCard.value?.cardNumber}`);
-}
-
-
-async function getBalance() {
-  if (isOpen.value) {
-    isOpen.value = false;
-    return;
-  }
-  try {
-    balance.value = [
-      {
-        amount: 0,
-        currency: "USD",
-        value: "USD",
-      },
-    ];
-    if (!currentCard.value?.cardNo) return;
-    const res = await ucardApi.ucardBalance({
-      cardNo: currentCard.value?.cardNo,
-      uniqueId: currentCard.value?.uniqueId,
-    });
-
-    if (res.code == 200) {
-      currency.value = "USD";
-      amount.value = res.data.amount;
-      isOpen.value = true;
-    } else {
-      balance.value = [
-        {
-          amount: 0,
-          currency: "USD",
-          value: "USD",
-        },
-      ];
-      currency.value = "USD";
-      amount.value = 0;
-      isOpen.value = false;
-    }
-  } catch (error: any) {
-    showToast(error?.message || String(error));
-    balance.value = [
-      {
-        amount: 0,
-        currency: "USD",
-        value: "USD",
-      },
-    ];
-    isOpen.value = false;
-  }
-}
-
-
-function toggleCardNo(card: any, event: MouseEvent) {
-  if (!card.id) return;
-  if (!(card.status == "success" && card?.activateStatus)) return;
-  event.stopPropagation();
-  isFlipping.value[card.id] = !isFlipping.value[card.id];
-  showCardNo.value[card.id] = !showCardNo.value[card.id];
-}
-
-function handleSwiperChange(e: any) {
-  const newIndex = e?.detail?.current ?? 0;
-  currentIndex.value = newIndex;
-  // 切换卡片时重置卡号显示状态
-  cardList.value.forEach((card) => {
-    if (!card.id) return;
-    showCardNo.value[card.id] = false;
-    isFlipping.value[card.id] = false;
-  });
-}
-
-async function ucardOperation(card, type) {
-  if (card.freezeType == "2" && type != "5") {
-    showToast(t("card.Msg.m10"));
-    return;
-  }
-  if (card.blocked) {
-    showToast(t("card.New2.p6"));
-    return;
-  }
-  if (card.freezeStatus != "success") {
-    if (card.freezeType == "1") {
-      showToast(t("card.Btn.b14"));
-    } else {
-      showToast(t("card.Btn.b15"));
-    }
-    return;
-  }
-  router.push({
-    path: "/pages/card/operations",
-    query: { id: card.id, type },
-  });
-}
-function viewApply(item: any) {
-  router.push({
-    path: "/pages/apply-record/detail",
-    query: {
-      id: item.id,
-      type: "card",
-    },
-  });
-}
-
-watch(
-  currentIndex,
-  (newIndex) => {
-    if (cardList.value[newIndex]) {
-      if (
-        cardList.value[newIndex].cardNo &&
-        cardList.value[newIndex].activateStatus == "success"
-      ) {
-        isOpen.value = false;
-      }
-    }
-  },
-  { immediate: true }
-);
-
-onMounted(async () => {
-  cardList.value.forEach((card) => {
-    showCardNo.value[card.id] = false;
-    isFlipping.value[card.id] = false;
-  });
-});
-onUnmounted(() => {
-  debouncedGetBalance.cancel();
-});
-</script>
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page {
-  padding: 0 px2rpx(24) px2rpx(130) px2rpx(24);
-}
-
-.card-wrapper {
-  position: absolute;
-  width: 100%;
-  height: 100%;
-  transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
-  will-change: transform;
-}
-
-.card-info {
-  background: url(/static/images/card/physical.png) no-repeat center center;
-  background-size: cover;
-  border-radius: px2rpx(16);
-  padding: px2rpx(16);
-  color: var(--main-yellow);
-  width: 100%;
-  height: 100%;
-  display: flex;
-  justify-content: flex-start;
-  align-items: baseline;
-  flex-wrap: wrap;
-  /* transform-style: preserve-3d;
-    transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1); */
-  /* flex-direction: column; */
-
-  .logo {
-    width: px2rpx(120);
-    height: auto;
-    margin-bottom: px2rpx(16);
-  }
-
-  .card-type {
-    width: px2rpx(74);
-    height: px2rpx(39);
-    position: absolute;
-    bottom: px2rpx(16);
-    right: px2rpx(16);
-    z-index: 1;
-  }
-
-  .card-name {
-    position: absolute;
-    top: px2rpx(16);
-    right: px2rpx(16);
-    font-size: var(--font-size-14);
-    font-weight: 500;
-    color: #fff;
-    font-family: Rubik;
-  }
-
-  &.flipping {
-    transform: rotateX(360deg);
-  }
-
-  .zw {
-    position: absolute;
-    left: px2rpx(16);
-    bottom: px2rpx(16);
-    color: #fff;
-    font-family: Rubik;
-    font-size: px2rpx(12);
-    font-style: normal;
-    font-weight: 700;
-    display: flex;
-    align-items: center;
-  }
-
-  .card-b {
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: center;
-    align-items: center;
-    gap: px2rpx(16);
-
-    span {
-      display: block;
-    }
-
-    .valid {
-      font-size: var(--font-size-14);
-      font-weight: 500;
-      color: var(--black);
-      gap: px2rpx(8);
-      line-height: px2rpx(20);
-    }
-
-    .lable {
-      font-size: var(--font-size-10);
-      font-weight: 400;
-    }
-
-    .cvv {
-      display: flex;
-      align-items: center;
-      gap: px2rpx(8);
-      font-size: var(--font-size-14);
-      font-weight: 500;
-      color: var(--black);
-
-      .copy,
-      .icon {
-        display: flex;
-      }
-    }
-  }
-
-  .copy {
-    width: px2rpx(18);
-    height: px2rpx(18);
-    border-radius: 50%;
-    background: rgba(255, 255, 255, 0.6);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-    color: #000;
-  }
-}
-
-.card-front,
-.card-back {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  padding: px2rpx(24) px2rpx(20) px2rpx(16) px2rpx(20);
-  backface-visibility: hidden;
-  -webkit-backface-visibility: hidden;
-}
-
-.card-back {
-  transform: rotateY(180deg);
-}
-
-.owner {
-  font-size: var(--font-size-14);
-  line-height: 2;
-  margin-bottom: px2rpx(8);
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-
-  i {
-    font-size: var(--font-size-18);
-    color: var(--main-yellow);
-  }
-}
-
-.number {
-  color: var(--black);
-  font-size: var(--font-size-18);
-  font-weight: 500;
-  line-height: 3;
-  margin: px2rpx(20) 0;
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-}
-
-.actions {
-  display: flex;
-  justify-content: space-between;
-  margin: px2rpx(20) 0 px2rpx(16) 0;
-  gap: px2rpx(8);
-  background-color: #fff;
-  width: 100%;
-}
-
-.action-btn {
-  color: var(--white);
-  border: none;
-  border-radius: px2rpx(12);
-  padding: 0 px2rpx(12);
-  font-size: var(--font-size-14);
-  cursor: pointer;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  gap: px2rpx(8);
-  transition: all 0.3s ease;
-  text-align: center;
-  color: #1a1a1a;
-  flex: 1;
-  height: px2rpx(100);
-  flex-shrink: 0;
-  border-radius: px2rpx(15);
-  box-shadow: 0px 5px 30px 0px rgba(5, 0, 1, 0.05);
-
-  .icon {
-    margin: px2rpx(16) 0 px2rpx(4) 0;
-  }
-
-  span {
-    line-height: px2rpx(20);
-  }
-}
-
-.action-btn1 {
-  background: rgba(153, 153, 153, 0.03) !important;
-  color: #999 !important;
-  pointer-events: none !important;
-}
-
-.balance-wrap {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin: px2rpx(24) 0;
-  font-size: var(--font-size-14);
-}
-
-.balance-wrap1 {
-  background-color: #f9fafb;
-  border-radius: px2rpx(12);
-  padding: px2rpx(16) px2rpx(12);
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: px2rpx(12);
-
-  .global-con-l {
-    display: flex;
-    width: px2rpx(164);
-    align-items: center;
-    gap: px2rpx(12);
-    border-radius: px2rpx(12);
-    // box-shadow: 0px 5px 30px 0px rgba(5, 0, 1, 0.05);
-    color: var(--white);
-
-    p {
-      color: #000;
-      font-family: Roboto;
-      font-size: px2rpx(16);
-      font-style: normal;
-      font-weight: 600;
-      line-height: px2rpx(24);
-    }
-
-    .l-img {
-      width: px2rpx(36);
-      height: px2rpx(36);
-      border: 1px solid #f4f4f4;
-      border-radius: 50%;
-    }
-  }
-}
-
-.balance-content {
-  font-size: var(--font-size-20);
-  color: var(--white);
-  font-weight: bold;
-}
-
-.balance-title {
-  font-size: var(--font-size-12);
-  color: var(--white);
-}
-
-.currency {
-  display: flex;
-  align-items: center;
-  font-size: var(--font-size-14);
-  margin-right: px2rpx(12);
-  color: var(--white);
-}
-
-.flag {
-  width: px2rpx(24);
-  height: px2rpx(24);
-  border-radius: 50%;
-  margin-right: px2rpx(6);
-}
-
-.balance {
-  display: flex;
-  align-items: center;
-  font-size: var(--font-size-14);
-  font-weight: bold;
-  color: var(--white);
-
-  .balance-amount {
-    display: inline-flex;
-    padding-right: px2rpx(8);
-  }
-}
-
-.transactions {
-  border-radius: px2rpx(16);
-  margin-bottom: px2rpx(16);
-  padding-bottom: px2rpx(16);
-}
-
-.trans-icon {
-  width: px2rpx(48);
-  height: px2rpx(48);
-  display: flex;
-  background: var(--main-bg);
-  box-shadow: 0 4px 12px rgba(214, 255, 0, 0.1);
-  border-radius: px2rpx(8);
-  margin-right: px2rpx(12);
-  align-items: center;
-  justify-content: center;
-
-  .trans-icon-inner {
-    width: px2rpx(48);
-    height: px2rpx(48);
-    background: rgba(212, 206, 206, 0.24);
-    border-radius: 50%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-
-  i {
-    color: #000;
-    width: px2rpx(24);
-    height: px2rpx(24);
-    border-radius: 50%;
-  }
-}
-
-.trans-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin: px2rpx(32) 0;
-  color: var(--white);
-
-  i {
-    font-size: var(--font-size-20);
-    cursor: pointer;
-  }
-}
-
-::v-deep .van-calendar {
-  background: var(--action-bg);
-}
-
-::v-deep .van-calendar__month-mark {
-  display: none;
-}
-
-::v-deep .van-calendar__header-subtitle {
-  color: var(--white);
-}
-
-::v-deep .van-calendar__header-title {
-  color: var(--white);
-}
-
-::v-deep .van-calendar__month-title {
-  color: var(--main-yellow);
-}
-
-.trans-title {
-  font-size: var(--font-size-20);
-  color: var(--white);
-  font-weight: bold;
-}
-
-.date-field {
-  width: px2rpx(200);
-
-  :deep(.van-field__control) {
-    color: var(--white);
-  }
-
-  :deep(.van-field__placeholder) {
-    color: var(--gray);
-  }
-}
-
-:deep(.van-popup) {
-  background: var(--action-bg);
-}
-
-:deep(.van-picker__toolbar) {
-  background: var(--action-bg);
-  border-bottom: 1px solid var(--border);
-}
-
-:deep(.van-picker__title) {
-  color: var(--white);
-}
-
-:deep(.van-picker__confirm) {
-  color: var(--main-yellow);
-}
-
-:deep(.van-picker__cancel) {
-  color: var(--gray);
-}
-
-:deep(.van-picker-column) {
-  color: var(--white);
-}
-
-:deep(.van-picker-column__item) {
-  color: var(--white);
-}
-
-:deep(.van-picker-column__item--selected) {
-  color: var(--main-yellow);
-}
-
-.transaction {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding: px2rpx(10) 0;
-  /* border-bottom: 1px solid var(--border); */
-  font-size: var(--font-size-16);
-}
-
-.transaction:last-child {
-  border-bottom: none;
-}
-
-.trans-left {
-  width: px2rpx(200);
-}
-
-.trans-right {
-  width: px2rpx(100);
-
-  div {
-    text-align: right;
-  }
-}
-
-.trans-type {
-  color: var(--white);
-  font-size: var(--font-size-16);
-  font-weight: 600;
-  line-height: 2;
-}
-
-.trans-desc {
-  font-size: var(--font-size-12);
-  color: var(--gray);
-}
-
-.trans-amount {
-  font-size: var(--font-size-16);
-  font-weight: 600;
-  color: var(--white);
-  line-height: 2;
-}
-
-.trans-date {
-  color: var(--gray);
-  font-size: var(--font-size-12);
-}
-
-.card-swiper {
-  width: 100%;
-  margin: px2rpx(20) 0 0 0;
-  position: relative;
-  overflow: hidden;
-  display: flex;
-  justify-content: center;
-  flex-direction: column;
-  align-items: center;
-  padding-bottom: px2rpx(5);
-}
-
-.swiper-container {
-  position: relative;
-  width: 100%;
-  height: px2rpx(219);
-  touch-action: pan-y pinch-zoom;
-  user-select: none;
-}
-
-.card-info {
-  position: absolute;
-  width: 100%;
-  height: 100%;
-  transition: transform 0.3s ease;
-  will-change: transform;
-  box-sizing: border-box;
-}
-
-.swiper-controls {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  margin-top: px2rpx(12);
-  gap: px2rpx(16);
-}
-
-.swiper-btn {
-  background: var(--action-bg);
-  border: none;
-  border-radius: 50%;
-  width: px2rpx(32);
-  height: px2rpx(32);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  cursor: pointer;
-  color: var(--main-yellow);
-
-  &:disabled {
-    opacity: 0.5;
-    cursor: not-allowed;
-  }
-
-  i {
-    font-size: var(--font-size-20);
-  }
-}
-
-.swiper-dots {
-  display: flex;
-  gap: px2rpx(8);
-}
-
-.dot {
-  width: px2rpx(8);
-  height: px2rpx(8);
-  border-radius: 50%;
-  background: var(--action-bg);
-  cursor: pointer;
-  transition: all 0.3s ease;
-
-  &.active {
-    background: var(--main-yellow);
-    transform: scale(1.2);
-  }
-}
-
-.swiper-indicators {
-  display: flex;
-  justify-content: center;
-  margin-top: px2rpx(16);
-  gap: px2rpx(8);
-}
-
-.indicator-dot {
-  width: px2rpx(8);
-  height: px2rpx(8);
-  border-radius: 50%;
-  background: var(--gray);
-  cursor: pointer;
-  transition: all 0.3s ease;
-
-  &.active {
-    background: var(--main-yellow);
-    transform: scale(1.2);
-  }
-}
-
-.flags {
-  width: px2rpx(20);
-  height: px2rpx(20);
-  cursor: pointer;
-  position: absolute;
-  top: px2rpx(10);
-  right: px2rpx(10);
-}
-
-.balance-content1 {
-  margin-bottom: px2rpx(20);
-  font-size: var(--font-size-20);
-  color: var(--white);
-  font-weight: bold;
-}
-
-.cwg-btn {
-  margin-top: px2rpx(36);
-}
-
-
-
-.custom-toast {
-  background: rgba(0, 0, 0, 0) !important;
-  color: #fff;
-  font-size: px2rpx(14);
-  padding: px2rpx(10);
-  border-radius: px2rpx(8);
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-
-  .van-icon {
-    width: px2rpx(24);
-    height: px2rpx(24);
-  }
-
-  .van-icon--copy {
-    color: #fff;
-  }
-}
-
-.actions1 {
-  width: 100%;
-  padding: px2rpx(20);
-
-  margin-top: px2rpx(20);
-  border: 1px solid rgba(214, 255, 0, 0.2);
-  box-shadow: 0 0.053333rem 0.213333rem rgba(0, 0, 0, 0.08);
-}
-
-.card-btn {
-  width: 100%;
-
-  .yue {
-    display: flex;
-    align-items: center;
-    box-sizing: border-box;
-    line-height: px2rpx(50);
-    width: 100%;
-    height: px2rpx(50);
-    background: rgba(208, 37, 55, 0.03);
-    border-radius: px2rpx(8);
-    text-align: left;
-    padding-left: px2rpx(20);
-    margin-bottom: px2rpx(20);
-  }
-
-  .a {
-    font-size: px2rpx(14);
-    color: #333333;
-    font-weight: bold;
-    padding: 0;
-  }
-
-  .v {
-    font-size: px2rpx(14);
-    color: #eb3f57;
-    padding: 0;
-  }
-
-  .btn {
-    width: px2rpx(193);
-    height: px2rpx(40);
-    border: 1px solid #eb3f57;
-    border-radius: px2rpx(4);
-    text-align: center;
-    color: #eb3f57;
-    font-size: px2rpx(16);
-    font-family: Roboto;
-    font-weight: 600;
-    line-height: px2rpx(40);
-    cursor: pointer;
-    user-select: none;
-  }
-
-  .btn1 {
-    width: px2rpx(100);
-    height: px2rpx(94);
-    background: rgba(208, 37, 55, 0.03);
-    border: 1px solid rgba(208, 37, 55, 0.03);
-    border-radius: px2rpx(15);
-    text-align: center;
-    color: #eb3f57;
-    font-size: px2rpx(16);
-    font-family: Roboto;
-    font-weight: 600;
-    line-height: px2rpx(20);
-    padding: 0 px2rpx(8);
-    cursor: pointer;
-    user-select: none;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-direction: column;
-    gap: px2rpx(8);
-
-    &:hover {
-      border: 1px solid #eb3f57;
-    }
-
-    img {
-      width: px2rpx(28);
-      height: px2rpx(28);
-      vertical-align: middle;
-      margin-right: px2rpx(5);
-    }
-  }
-
-  .btn2 {
-    width: px2rpx(162);
-  }
-
-  .btn3 {
-    background: rgba(153, 153, 153, 0.03) !important;
-    color: #999 !important;
-    pointer-events: none !important;
-  }
-}
-
-.status {
-  position: absolute;
-  top: px2rpx(15);
-  right: -px2rpx(30);
-  padding: px2rpx(4) px2rpx(40);
-  background: rgba(235, 63, 87, 0.1);
-  color: #eb3f57;
-  font-size: px2rpx(14);
-  font-weight: 500;
-  text-align: center;
-  transform: rotate(45deg);
-  transform-origin: center center;
-}
-
-.status1 {
-  position: absolute;
-  top: px2rpx(15);
-  right: -px2rpx(30);
-  padding: px2rpx(4) px2rpx(40);
-  background: rgba(67, 68, 68, 0.1);
-  color: #434444;
-  font-size: px2rpx(14);
-  font-weight: 500;
-  text-align: center;
-  transform: rotate(45deg);
-  transform-origin: center center;
-}
-
-.transaction-list {
-  display: flex;
-  flex-direction: column;
-
-  .transaction-item {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: px2rpx(16) 0;
-    border-bottom: 1px solid #f3f4f6;
-  }
-
-  .transaction-item:last-child {
-    border-bottom: none;
-  }
-
-  .transaction-left {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(12);
-  }
-
-  .transaction-icon {
-    width: px2rpx(40);
-    height: px2rpx(40);
-    background-color: #f9fafb;
-    border-radius: 50%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-
-  .icon-text {
-    font-size: px2rpx(20);
-    color: #6b7280;
-  }
-
-  .transaction-info {
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(4);
-  }
-
-  .transaction-status {
-    font-size: px2rpx(14);
-    color: #111827;
-  }
-
-  .transaction-time {
-    font-size: px2rpx(12);
-    color: #9ca3af;
-  }
-
-  .transaction-right {
-    display: flex;
-    flex-direction: column;
-    align-items: flex-end;
-  }
-
-  .transaction-amount {
-    font-size: px2rpx(16);
-    font-weight: 600;
-    color: #111827;
-  }
-
-  .transaction-amount.negative {
-    color: #ef4444;
-  }
-}
-</style>

+ 0 - 177
pages/card/index.vue

@@ -1,177 +0,0 @@
-<template>
-  <cwg-page-wrapper>
-    <view v-if="isShow">
-      <view v-if="typesList.length > 0 && cardList.length > 0" class="add-apply" @click="addApply">{{ t("cards.p10") }}
-      </view>
-      <FirstApply v-if="cardList.length == 0" />
-      <cwg-page-more-wrapper ref="loadMoreWrapperRef" v-else :loading="loading" :refresher-enabled="true"
-        @refresh="handleRefresh">
-        <VirtualCard />
-      </cwg-page-more-wrapper>
-
-    </view>
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, computed } from "vue";
-import type { CardInfo } from "@/api/ucard";
-import { useI18n } from "vue-i18n";
-import useRouter from "@/hooks/useRouter";
-import { ucardApi } from "@/api/ucard";
-import FirstApply from "./components/FirstApply.vue";
-import VirtualCard from "./components/VirtualCard.vue";
-import useUserStore from "@/stores/use-user-store";
-import useCardStore from "@/stores/use-card-store";
-import useGlobalStore from "@/stores/use-global-store";
-
-const userStore = useUserStore();
-const cardStore = useCardStore();
-const router = useRouter();
-const { t } = useI18n();
-const globalStore = useGlobalStore();
-const cardList = ref<CardInfo[]>([]);
-const typesList = ref<CardInfo[]>([]);
-
-const isShow = ref(false);
-
-async function applyList() {
-  // 后台刷新最新卡列表,不阻塞已有缓存渲染
-  globalStore.setFullScreenLoading(true);
-  try {
-    const [response1, response2, response3] = await Promise.all([
-      ucardApi.cardList({ page: { current: 1, row: 10 }, a: 1 }),
-      ucardApi.applyList({
-        page: { current: 1, row: 100 },
-      }),
-      ucardApi.cardTypesList(),
-    ]);
-    const [data1, data2, data3] = await Promise.all([
-      response1.data,
-      response2.data,
-      response3.data,
-    ]);
-    const merged = await mergeLists(data1, data2);
-    cardList.value = merged;
-    cardStore.saveUserCard(merged);
-    cardTypesList(data3, data2);
-    cardStore.saveApplyCard(data2);
-    isShow.value = true;
-  } catch (error) {
-    // 请求失败时保留本地缓存的 cardList,避免页面空白
-    console.error('加载卡片列表失败', error);
-  } finally {
-    globalStore.setFullScreenLoading(false);
-    isShow.value = true;
-  }
-}
-async function cardTypesList(data1, data2) {
-  try {
-    const recordTypeIds = new Set(
-      data2.map((item) => {
-        if (item.status != "fail" && item.status != "cancel") {
-          return item.cardTypeId;
-        }
-      })
-    );
-    const result1 = data1;
-    const result2 = result1.filter(
-      (item) => !recordTypeIds.has(item.cardTypeId)
-    );
-    const result3 = result2.filter((item) =>
-      item.supportHolderRegin.includes(this.businessForm.country)
-    );
-    typesList.value = result3;
-  } catch (error) {
-    typesList.value = [];
-  }
-}
-async function mergeLists(list1, list2) {
-  const mainList = list1.map((item) => {
-    const { status, ...rest } = item;
-    return {
-      ...rest,
-      activateStatus: status || null,
-      status,
-    };
-  });
-  const list3 = list2.filter((i) => i.status != "fail");
-  const mainList2 = list3.map((item) => {
-    const { status, ...rest } = item;
-    return {
-      ...rest,
-      applyStatus: status || null,
-      status,
-    };
-  });
-
-  const mainCardTypeIds = new Set(mainList.map((i) => i.cardTypeId));
-  const filteredList2 = mainList2.filter(
-    (i) => !mainCardTypeIds.has(i.cardTypeId)
-  );
-
-  const latestMap = {};
-  for (const item of filteredList2) {
-    const cur = latestMap[item.cardTypeId];
-    if (
-      !cur ||
-      new Date(item.addTime).getTime() > new Date(cur.addTime).getTime()
-    ) {
-      latestMap[item.cardTypeId] = { ...item, aId: item.id };
-    }
-  }
-  const latestList2 = Object.values(latestMap);
-  const latestList3 = latestList2.filter((i) => i.status != "cancel");
-  return [...latestList3, ...mainList];
-}
-
-function addApply() {
-  router.push("/select/card");
-}
-const loadMoreWrapperRef = ref<any>(null);
-const loading = ref(false);
-const finished = ref(false);
-
-const handleRefresh = async () => {
-  await applyList();
-  // 停止下拉刷新动画
-  if (loadMoreWrapperRef.value) {
-    loadMoreWrapperRef.value.stopRefresh();
-  }
-};
-onMounted(() => {
-  // 1. 先用本地缓存的卡列表快速渲染,提升首屏速度
-  const cachedCards = (cardStore.userCard as any) || [];
-  if (Array.isArray(cachedCards) && cachedCards.length > 0) {
-    cardList.value = cachedCards as CardInfo[];
-    isShow.value = true;
-  }
-
-  // 2. 异步拉取最新数据并更新缓存
-  applyList();
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.add-apply {
-  position: fixed;
-  top: px2rpx(14);
-  right: px2rpx(10);
-  cursor: pointer;
-  z-index: 100;
-  display: flex;
-  flex-direction: row;
-  justify-content: center;
-  align-items: center;
-  gap: px2rpx(4);
-  min-width: px2rpx(100);
-  padding: 0 px2rpx(10);
-  height: px2rpx(30);
-  background: #ea002a;
-  border-radius: px2rpx(100);
-  font-size: px2rpx(14);
-  color: #ffffff;
-}
-</style>

+ 0 - 527
pages/card/operations.vue

@@ -1,527 +0,0 @@
-<template>
-  <cwg-page-wrapper :isHeaderFixed="true">
-    <cwg-header :showBack="true" :title="title[type]">
-      <view v-if="type == 2" @click="goRechargeRecord">
-        <cwg-icon name="icon_history" :size="24" color="#000" />
-      </view>
-    </cwg-header>
-
-    <view class="page page-shadow">
-      <u-form ref="formRef" :rules="rules" :model="infoForm" class="kyc-form">
-        <template v-if="type == '1'">
-          <cwg-input v-model:value="infoForm.cardNumber1" fkey="cardNumber1" :required="true"
-            :label="`${t('card.Form.f24')}:`" rulesKey="cardNumber1" @change="handleChange" />
-          <cwg-input v-model:value="infoForm.activeCode" fkey="activeCode" :required="true"
-            :label="`${t('card.Form.f26')}:`" rulesKey="activeCode" @change="handleChange" />
-          <cwg-input v-model:value="infoForm.pin" fkey="pin" :required="true" :maxlength="6" :label="t('card.Info.s26')"
-            rulesKey="pin" @change="handleChange" />
-          <cwg-input v-model:value="infoForm.password" fkey="password" :required="true" :maxlength="6"
-            :label="`${t('card.Info.s26_1')}`" rulesKey="password" @change="handleChange" />
-          <view class="pwd">
-            <view class="lis" v-t="'card.vaildate.v32'" :class="{ fit: rule1 }"></view>
-            <view class="lis" v-t="'card.vaildate.v33'" :class="{ fit: rule2 }"></view>
-          </view>
-        </template>
-        <template v-if="type == '2'">
-          <cwg-input v-model:value="infoForm.cardNumber1" fkey="cardNumber1" :required="true"
-            :label="`${t('card.Form.f24')}:`" rulesKey="cardNumber1" @change="handleChange" />
-          <cwg-input v-model:value="infoForm.amount" fkey="amount" type="number" :label="`${t('card.Form.f28')}:`"
-            :required="true" :min="rechargeMinQuota" :max="rechargeMaxQuota" :placeholder="t('card.vaildate.v26')"
-            @change="handleChange">
-          </cwg-input>
-          <view class="balance-info">
-            <text class="balance-key">{{ t("card.Form.f56") }}</text>
-            <text class="balance-value">{{ userBalance }} USD</text>
-            <view class="all-btn" @click="allBalance">{{
-              t("card.Form.f57")
-            }}</view>
-          </view>
-          <view class="balance-info">
-            <text class="balance-key">{{ t("card.Form.f58") }}</text>
-            <text class="balance-value">{{ exchangeRate }}%</text>
-            <text></text>
-          </view>
-          <view class="balance-info">
-            <text class="balance-key">{{ t("card.Form.f59") }}</text>
-            <text class="balance-value">{{ fee }}</text>
-            <text></text>
-          </view>
-        </template>
-        <template v-if="type == '3'">
-          <cwg-input v-model:value="infoForm.cardNumber1" fkey="cardNumber1" :required="true"
-            :label="`${t('card.Form.f24')}:`" rulesKey="cardNumber1" @change="handleChange" />
-          <cwg-input v-model:value="infoForm.pin" fkey="pin" :required="true" :label="t('card.Info.s26')" :maxlength="6"
-            rulesKey="pin" @change="handleChange" />
-          <cwg-input v-model:value="infoForm.password" fkey="password" :required="true" :maxlength="6"
-            :label="`${t('card.Info.s26_1')}`" rulesKey="password" @change="handleChange" />
-
-          <view class="pwd">
-            <view class="lis" v-t="'card.vaildate.v32'" :class="{ fit: rule1 }"></view>
-            <view class="lis" v-t="'card.vaildate.v33'" :class="{ fit: rule2 }"></view>
-          </view>
-        </template>
-        <template v-if="type == '4' || type == '5'">
-          <cwg-input v-model:value="infoForm.cardNumber1" fkey="cardNumber1" :required="true"
-            :label="`${t('card.Form.f24')}:`" rulesKey="cardNumber1" @change="handleChange" />
-          <cwg-input v-model:value="infoForm.clientRemark" fkey="clientRemark" :label="`${t('card.Form.f27')}:`"
-            @change="handleChange" />
-        </template>
-
-        <view v-if="infoForm.authStatus != 1" class="fixed-btn">
-          <view class="cwg-button">
-            <u-button type="primary" block @click="infoSubmit">{{
-              t(btn[type])
-            }}</u-button>
-          </view>
-        </view>
-      </u-form>
-    </view>
-    <cwg-SuccessPrompt v-model:show="showSuccessPrompt" :title="t(title[type])" :desc="t('card.Msg.m2')"
-      :btn-click="btnClick" />
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-
-
-import { ref, onMounted, watch, computed } from "vue";
-import { showToast } from "@/utils/toast";
-import { useI18n } from "vue-i18n";
-import useRouter from "@/hooks/useRouter";
-import { onLoad } from '@dcloudio/uni-app'
-import { ucardApi } from "@/api/ucard";
-import config from "@/config";
-import { Validators } from "@/utils/validators";
-const { t } = useI18n();
-const router = useRouter();
-const form = ref({});
-const formRef = ref(null);
-const infoForm = ref({
-  password: undefined,
-  cardNumber1: undefined,
-  cardNo: undefined,
-  activeCode: undefined,
-  pin: undefined,
-  amount: undefined,
-  clientRemark: undefined,
-});
-const title = ref({
-  1: t('card.Btn.b1'),
-  2: t('card.Btn.b3'),
-  3: t('card.Btn.b4'),
-  4: t('card.Btn.b5'),
-  5: t('card.Btn.b6')
-})
-const btn = ref({
-  1: t('card.Btn.Activate'),
-  2: t('card.Btn.Recharge'),
-  3: t('card.Btn.Submit'),
-  4: t('card.Btn.Freeze'),
-  5: t('card.Btn.Unfreeze')
-})
-const type = ref()
-const id = ref()
-onLoad((options) => {
-  id.value = options.id
-  type.value = options.type
-})
-const showSuccessPrompt = ref(false);
-const btnClick = () => {
-  router.push('/pages/card/index');
-};
-// 动态限制
-const exchangeRate = ref(0);
-const rechargeMinQuota = ref(0);
-const rechargeMaxQuota = ref(0);
-const rechargeFixedFee = ref(0);
-const userBalance = ref(0);
-const pictLoading = ref(false);
-function validatePin(s) {
-  if (!/^\d{6}$/.test(s)) return false;
-  if (/(.)\1\1/.test(s)) return false;
-  const isSequential = (str) => {
-    let inc = true;
-    let dec = true;
-    for (let i = 1; i < str.length; i++) {
-      if (str[i] - str[i - 1] !== 1) inc = false;
-      if (str[i - 1] - str[i] !== 1) dec = false;
-    }
-    return inc || dec;
-  };
-  if (isSequential(s)) return false;
-  if (/^(\d{2})\1\1$/.test(s)) return false;
-  if (/^(\d{3})\1$/.test(s)) return false;
-  return true;
-}
-
-function validatePina(a: any, b?: any, c?: any) {
-  if (typeof c === "function") {
-    const value = b;
-    const callback = c;
-    const val = String(value ?? "").trim();
-    if (validatePin(val)) {
-      return callback();
-    } else {
-      return callback(new Error(t("card.vaildate.v23")));
-    }
-  }
-
-}
-function validatePassword(a: any, b?: any, c?: any) {
-  if (typeof c === "function") {
-    const value = b;
-    const callback = c;
-    const val = String(value ?? "").trim();
-    if (validatePin(val)) {
-      if (formData.value.pin != formData.value.password) {
-        callback(new Error(t("vaildate.password.same")));
-        return;
-      } else {
-        return callback();
-      }
-    } else {
-      callback(new Error(t("vaildate.password.same")));
-    }
-  }
-}
-const rules = {
-  pin: [
-    Validators.required(t("card.vaildate.v23")),
-    Validators.custom(validatePina),
-  ],
-  password: [
-    Validators.required(t("card.vaildate.v31")),
-    Validators.custom(validatePassword)
-  ],
-  cardNumber1: [
-    {
-      required: true,
-      message: t("card.vaildate.v41"),
-      trigger: "blur",
-    },
-  ],
-  amount: [
-    {
-      required: true,
-      message: t("card.vaildate.v26"),
-      trigger: "blur",
-    },
-    {
-      validator: (rule, value, callback) => validateAmount(value, callback),
-      trigger: "blur",
-    },
-  ],
-  activeCode: [
-    {
-      required: true,
-      message: t("card.vaildate.v24"),
-      trigger: "blur",
-    },
-  ],
-};
-
-const formData = ref<typeof infoForm.value>({ id } as any);
-const headerTitleMap: Record<number, string> = {
-  1: "card.tab10",
-  2: "card.tab11",
-  3: "card.tab12",
-  4: "card.tab13",
-  5: "card.tab14",
-};
-
-// 根据 type 自动取标题
-const maxRecharge = computed(() => {
-  const balance = Number(userBalance.value) || 0;
-  const rate = Number(exchangeRate.value) / 100;
-  if (balance <= 0) return 0;
-  return Math.floor((balance / (1 + rate)) * 100) / 100;
-});
-const fee = computed(() => {
-  if (!formData.value.amount) {
-    return 0;
-  }
-  if (rechargeFixedFee.value) {
-    return rechargeFixedFee.value;
-  }
-  const amount = Math.ceil(formData.value.amount);
-  return ((amount * exchangeRate.value) / 100).toFixed(2);
-});
-function goRechargeRecord() {
-  router.push(`/pages/recharge-record/list?cardNo=${formData.value?.cardNo}`);
-}
-// 计算属性 rule1
-const rule1 = computed(() => {
-  if (!formData.value.pin) return false;
-  return /^(\d)\d{5}$/.test(formData.value.pin);
-});
-
-// 计算属性 rule2
-const rule2 = computed(() => {
-  if (!formData.value.pin) return false;
-  return config.Pattern.Pin.test(formData.value.pin);
-});
-async function infoSubmit() {
-  if (formData.value.cardNumber1 != infoForm.value.cardNumber) {
-    showToast(t("card.vaildate.v41"));
-    return;
-  }
-  if (pictLoading.value) {
-    return
-  }
-  pictLoading.value = true;
-  try {
-    switch (type.value) {
-      case "1":
-        await formRef.value?.validate();
-        ucardActivate();
-        break;
-      case "2":
-        await formRef.value?.validate();
-        ucardRecharge();
-        break;
-      case "3":
-        await formRef.value?.validate();
-        ucardResetPassword();
-        break;
-      case "4":
-        await formRef.value?.validate();
-        ucardFreeze();
-        break;
-      case "5":
-        await formRef.value?.validate();
-        ucardUnfreeze();
-        break;
-    }
-  } catch (error) {
-    pictLoading.value = false;
-  }
-}
-function backActivity() {
-  setTimeout(() => {
-    router.back();
-  }, 3000);
-}
-async function ucardActivate() {
-  if (formData.value.pin != formData.value.password) {
-    showToast(t("card.Msg.m11"));
-    return;
-  }
-  const res = await ucardApi.ucardActivate(formData.value);
-  if (res.code == 200) {
-    showToast(t("card.Msg.m3"));
-    backActivity();
-  } else {
-    showToast(res.msg);
-  }
-  pictLoading.value = false;
-}
-async function ucardResetPassword() {
-  const res = await ucardApi.ucardResetPassword(formData.value);
-  if (res.code == 200) {
-    showToast(t("card.Msg.m6"));
-    backActivity();
-  } else {
-    showToast(res.msg);
-  }
-  pictLoading.value = false;
-}
-async function ucardFreeze() {
-  const res = await ucardApi.ucardFreeze(formData.value);
-  if (res.code == 200) {
-    showToast(t("card.Msg.m4"));
-    backActivity();
-  } else {
-    showToast(res.msg);
-  }
-  pictLoading.value = false;
-}
-async function ucardUnfreeze() {
-  const res = await ucardApi.ucardUnfreeze(formData.value);
-  if (res.code == 200) {
-    showToast(t("card.Msg.m5"));
-    backActivity();
-  } else {
-    showToast(res.msg);
-  }
-  pictLoading.value = false;
-}
-async function getCardInfo() {
-  try {
-    if (!id) return;
-    const res = await ucardApi.getCardInfo({ id: id.value });
-    // 只更新后端返回的字段,避免整体替换导致输入被清空
-    Object.assign(infoForm.value, res.data);
-    Object.assign(formData.value, res.data);
-    exchangeRate.value = res.data.rechargeFeeRate;
-    rechargeMaxQuota.value = res.data.rechargeMaxQuota;
-    rechargeMinQuota.value = res.data.rechargeMinQuota;
-    rechargeFixedFee.value = res.data.rechargeFixedFee;
-  } catch (error) {
-    console.log(error);
-  }
-}
-
-// 一键填充最大金额
-function allBalance() {
-  infoForm.value.amount = maxRecharge.value;
-}
-
-// 金额验证函数(配合 Vant <Field /> 的 rules)
-function validateAmount(value: string | number) {
-  const num = Number(value);
-  if (!num || num <= 0) {
-    return t("card.vaildate.v34"); // 请输入有效金额
-  } else if (maxRecharge.value === 0) {
-    return `${t("card.Form.f56")} 0 USD`;
-  } else if (num > maxRecharge.value) {
-    return `${t("card.vaildate.v35")} ${maxRecharge.value} USD`;
-  } else if (num < rechargeMinQuota.value) {
-    return `${t("card.vaildate.v36")} ${rechargeMinQuota.value} USD`;
-  } else if (num >= rechargeMaxQuota.value) {
-    return `${t("card.vaildate.v37")} ${rechargeMaxQuota.value} USD`;
-  }
-  return true;
-}
-
-// 获取钱包余额
-async function walletBalance() {
-  try {
-    const res = await ucardApi.walletBalance();
-    if (res.code === 200) {
-      userBalance.value = res.data.balance || 0;
-    } else {
-      showToast(res.msg);
-      userBalance.value = 0;
-    }
-  } catch (err) {
-    userBalance.value = 0;
-  }
-}
-
-// 银行卡充值
-async function ucardRecharge() {
-  const amount = Number(formData.value.amount);
-  const cardNo = formData.value.cardNo;
-  if (validateAmount(amount) !== true) {
-    showToast(validateAmount(amount));
-    return;
-  }
-  try {
-    const res = await ucardApi.ucardRecharge({ amount, cardNo });
-    if (res.code === 200) {
-      // showToast(t("card.Msg.m2"));
-      showSuccessPrompt.value = true;
-    } else {
-      showToast(res.msg);
-    }
-  } catch (err) {
-    console.log(err);
-  } finally {
-    pictLoading.value = false;
-  }
-}
-onMounted(() => {
-  getCardInfo();
-
-  if (type.value == "2") {
-    walletBalance();
-  }
-});
-
-function handleChange(value: any) {
-  formData.value = { ...formData.value, [value.key]: value.value };
-}
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.pointer-none {
-  pointer-events: none;
-}
-
-.f {
-  display: flex;
-  align-items: flex-end;
-  gap: px2rpx(12);
-
-  .l {
-    flex: 1;
-  }
-
-  .r {
-    width: px2rpx(273);
-  }
-}
-
-.pwd {
-  line-height: px2rpx(20);
-
-  .lis {
-    list-style-type: disc;
-    line-height: 1.2;
-    margin: px2rpx(4) 0 px2rpx(4) px2rpx(10);
-    color: #c0c4cc;
-    position: relative;
-
-    &::after {
-      content: '';
-      position: absolute;
-      left: px2rpx(-6);
-      top: px2rpx(6);
-      width: px2rpx(4);
-      height: px2rpx(4);
-      border-radius: 50%;
-      background: #c0c4cc;
-    }
-  }
-
-  .fit {
-    color: var(--main-yellow);
-
-    &::after {
-      background: var(--main-yellow);
-    }
-  }
-}
-
-.balance-info {
-  width: 100%;
-  color: #bdbdbd;
-  font-size: px2rpx(14);
-  margin-bottom: px2rpx(44);
-  display: flex;
-  align-items: center;
-  /* justify-content: space-between; */
-}
-
-.balance-value {
-  width: px2rpx(140);
-  color: var(--white);
-  font-weight: bold;
-  margin: 0 px2rpx(8);
-}
-
-.balance-key {
-  color: #8e8a8a;
-  width: px2rpx(130);
-}
-
-.all-btn {
-  min-width: px2rpx(30);
-  display: flex;
-  padding: px2rpx(4) px2rpx(12);
-  justify-content: center;
-  align-items: center;
-  gap: px2rpx(10);
-  border-radius: px2rpx(35);
-  border: 1px solid #ea002a;
-  color: var(--Brand-color, #ea002a);
-  font-family: Roboto;
-  font-size: px2rpx(14);
-  font-style: normal;
-  font-weight: 600;
-  line-height: px2rpx(20);
-  letter-spacing: px2rpx(0.07);
-}
-</style>

+ 0 - 328
pages/card/select.vue

@@ -1,328 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="page">
-            <view class="select-card-desc">{{ t('pages.card.select') }}</view>
-            <view class="card-types-container">
-                <swiper class="card-types-wrapper" :circular="false" :duration="300" :current="currentCardIndex"
-                    @change="handleSwiperChange">
-                    <swiper-item v-for="(type, index) in cardTypes" :key="index" class="card-box">
-                        <image src="/static/images/select-card-1.png" mode="aspectFit" />
-                        <view class="card-info">
-                            <view class="card-title">{{ type.cardName }}</view>
-                            <view class="card-content">{{ type.cardDesc }}</view>
-                            <view class="card-list">
-                                <view class="card-item">
-                                    <text class="label">{{ t('card.New.n6') }}</text>
-                                    <text>{{ type.currency || 'USD' }}</text>
-                                </view>
-                                <view class="card-item">
-                                    <text class="label">{{ t('card.New.n7') }}</text>
-                                    <text>{{ type.rechargeMinQuota }} USD</text>
-                                </view>
-                                <view class="card-item">
-                                    <text class="label">{{ t('card.New2.n8') }}</text>
-                                    <text>{{ type.rechargeMaxQuota }} USD</text>
-                                </view>
-                                <view class="card-item">
-                                    <text class="label">{{ t('card.New.n9') }}</text>
-                                    <text>{{ type.rechargeFeeRate }} %</text>
-                                </view>
-                                <view class="card-item one">
-                                    <text class="label">{{ t('card.New.n4') }}</text>
-                                    <text>
-                                        <text v-if="type.originalCardFee > type.cardFee" class="strike strike1">{{
-                                            type.originalCardFee }}</text>
-                                        <text class="strike1">{{ type.cardFee }} USD</text>
-                                    </text>
-                                </view>
-                                <view class="card-item" v-if="isPromotionActive">
-                                    <text class="k"></text>
-                                    <text class="v strike1" v-t="'card.New3.p13'"></text>
-                                </view>
-                            </view>
-                        </view>
-                    </swiper-item>
-                </swiper>
-                <view class="swiper-indicators" v-if="cardTypes.length > 1">
-                    <view v-for="(card, index) in cardTypes" :key="card.id || index" class="indicator-dot"
-                        :class="{ active: index === currentCardIndex }" @click="currentCardIndex = index"></view>
-                </view>
-            </view>
-            <view class="fixed-btn">
-                <view class="cwg-button">
-                    <u-button type="primary" block @click="handleSubmit">{{ t('card.Btn.Next') }}</u-button>
-                </view>
-            </view>
-        </view>
-    </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, computed } from 'vue'
-import type { CardType } from '@/api/ucard'
-import { useI18n } from 'vue-i18n'
-import useRouter from '@/hooks/useRouter'
-import useGlobalStore from '@/stores/use-global-store'
-import { ucardApi } from '@/api/ucard'
-const isPromotionActive = computed(() => {
-    const now = new Date();
-    return now <= new Date('2026-01-31T23:59:59');
-})
-const globalStore = useGlobalStore()
-const router = useRouter()
-const { t } = useI18n()
-const cardTypes = ref<CardType[]>([])
-const currentCardIndex = ref(0)
-
-function handleSwiperChange(e: any) {
-    const current = e.detail?.current ?? 0
-    currentCardIndex.value = current
-}
-
-async function getCardTypes() {
-    globalStore.setFullScreenLoading(true)
-    try {
-        const [response1, response2] = await Promise.all([
-            ucardApi.cardTypesList(),
-            ucardApi.applyList({
-                page: { current: 1, row: 100 },
-            }),
-        ])
-        const [data1, data2] = await Promise.all([response1.data, response2.data])
-
-        const recordTypeIds = new Set(
-            data2.map((item) => {
-                if (item.status != 'fail' && item.status != 'cancel') {
-                    return item.cardTypeId
-                }
-            }),
-        )
-        const result1 = data1
-        const result2 = result1.filter((item) => !recordTypeIds.has(item.cardTypeId))
-        // const result3 = result2.filter((item) => item.supportHolderRegin.includes(this.businessForm.country))
-        cardTypes.value = [...result2]
-        console.log(cardTypes.value, 1212);
-
-        globalStore.setFullScreenLoading(false)
-    } catch (error) {
-        console.log(error)
-        globalStore.setFullScreenLoading(false)
-        cardTypes.value = []
-    }
-}
-
-function handleSubmit() {
-    const selectedCard = cardTypes.value[currentCardIndex.value]
-    if (!selectedCard) {
-        uni.showToast({
-            title: t('cards.selectCard') || '请先选择卡片',
-            icon: 'none'
-        })
-        return
-    }
-    router.push({
-        path: '/pages/card/apply',
-        query: {
-            cardTypeId: selectedCard.cardTypeId,
-            type: selectedCard.type,
-        },
-    })
-}
-
-onMounted(() => {
-    getCardTypes()
-})
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page {
-    padding-bottom: px2rpx(100);
-}
-
-.select-card-desc {
-    color: #474747;
-    width: 100%;
-    text-align: left;
-    font-size: var(--font-size-16);
-    line-height: px2rpx(24);
-    margin-bottom: px2rpx(20);
-}
-
-.card-types-container {
-    width: 100%;
-    position: relative;
-    overflow: hidden;
-    margin-bottom: px2rpx(40);
-}
-
-.card-types-wrapper {
-    width: 100%;
-    height: px2rpx(600);
-}
-
-:deep(.swiper-item) {
-    height: 100%;
-    display: flex;
-    align-items: flex-start;
-    justify-content: center;
-}
-
-.card-box {
-    width: 100%;
-    height: 100%;
-    border-radius: px2rpx(20);
-    // padding: px2rpx(16);
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    box-sizing: border-box;
-    overflow-y: auto;
-
-    image {
-        width: 100%;
-        height: auto;
-        max-height: px2rpx(200);
-        flex-shrink: 0;
-    }
-}
-
-.card-info {
-    width: 100%;
-    margin-top: px2rpx(16);
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-}
-
-.card-title {
-    margin: px2rpx(24) 0 px2rpx(12) 0;
-    font-weight: 600;
-    font-size: px2rpx(22);
-    line-height: px2rpx(28);
-    text-align: left;
-    color: #1a1a1a;
-}
-
-.card-content {
-    font-size: var(--font-size-16);
-    color: #474747;
-    margin: 0 0 px2rpx(26) 0;
-    text-align: left;
-    line-height: px2rpx(24);
-}
-
-.card-list {
-    width: 100%;
-    padding: px2rpx(12) 0;
-    margin: 0;
-    box-shadow: 0 4px 20px rgba(140, 145, 143, 0.194);
-    border-radius: px2rpx(10);
-    background: #fff;
-}
-
-.card-item {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    font-size: px2rpx(14);
-    color: #1a1a1a;
-    padding: px2rpx(12) px2rpx(24);
-    transition: all 0.3s ease;
-    position: relative;
-    font-family: 'Roboto';
-    font-style: normal;
-    font-weight: 600;
-    line-height: px2rpx(20);
-
-    text {
-        display: inline-block;
-    }
-}
-
-.label {
-    width: px2rpx(200);
-    font-weight: 600;
-    font-size: px2rpx(14);
-    line-height: px2rpx(20);
-    color: #8e8a8a;
-}
-
-.card-item:last-child {
-    margin-bottom: 0;
-}
-
-.swiper-indicators {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    margin-top: px2rpx(16);
-    gap: px2rpx(8);
-}
-
-.indicator-dot {
-    width: px2rpx(9);
-    height: px2rpx(9);
-    border-radius: 50%;
-    background: var(--gray);
-    transition: all 0.3s ease;
-
-    &.active {
-        background-color: var(--main-yellow);
-        transform: scale(1.2);
-    }
-}
-
-.card-list {
-    .one {
-        margin: px2rpx(12) px2rpx(24);
-        padding: px2rpx(12) 0;
-        border-top: 1px dashed #beb6b6;
-        color: #329644;
-        font-family: Roboto;
-        font-size: px2rpx(28);
-        font-style: normal;
-        font-weight: 700;
-        line-height: px2rpx(36);
-        align-items: flex-end;
-
-        .label {
-            color: #343434;
-            font-family: Roboto;
-            font-size: px2rpx(16);
-            font-style: normal;
-            font-weight: 600;
-            line-height: px2rpx(24);
-            width: px2rpx(100);
-        }
-
-        .strike {
-            display: inline-block;
-            padding-right: px2rpx(12);
-            text-decoration-line: line-through;
-            text-decoration-color: #333;
-            text-decoration-thickness: px2rpx(1);
-            text-decoration-skip-ink: none;
-            font-size: px2rpx(20);
-        }
-
-
-    }
-}
-
-.fixed-btn {
-    position: fixed;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    padding: px2rpx(16);
-    background: #fff;
-    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
-    z-index: 100;
-}
-
-.strike1 {
-    color: var(--main-yellow);
-}
-</style>

+ 0 - 2
pages/create-account/index.vue

@@ -94,8 +94,6 @@ async function getUserInfo() {
     if (res.code === 200) {
       if (!res.data || res.data.approveStatus != 2) {
         router.push("/pages/mine/improve");
-      } else {
-        router.push("/pages/card/index");
       }
     } else {
       uni.$u.toast(res.msg || t("login.msg0"));

+ 0 - 2
pages/customer/create-account.vue

@@ -94,8 +94,6 @@ async function getUserInfo() {
         if (res.code === 200) {
             if (!res.data || res.data.approveStatus != 2) {
                 router.push("/pages/mine/improve");
-            } else {
-                router.push("/pages/card/index");
             }
         } else {
             uni.$u.toast(res.msg || t("login.msg0"));

Разница между файлами не показана из-за своего большого размера
+ 0 - 18
pages/mine/about.vue


+ 0 - 282
pages/mine/cog.vue

@@ -1,282 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="page">
-            <view class="group">
-                <view class="group-item" @click="router.push('/pages/mine/pay-password')">
-                    <cwg-icon color="#000" icon="xgmm" />
-                    <text class="item-text">{{ t("language.i2") }}</text>
-                    <text class="version item-text"></text>
-                    <cwg-icon color="#817f7f" icon="chevron-right" />
-                </view>
-                <view class="group-item" @click="router.push('/pages/mine/language')">
-                    <cwg-icon color="#000" icon="web" />
-                    <text class="item-text">{{ t("language.i1") }}</text>
-                    <text class="version item-text">{{ t(`language.${lang}`) }}</text>
-                    <cwg-icon color="#817f7f" icon="chevron-right" />
-                </view>
-            </view>
-
-            <!-- <view class="group">
-                <view class="group-item" @click="router.push('/pages/mine/pay-password')">
-                    <cwg-icon color="#000" icon="xxtz" />
-                    <text class="item-text">消息通知设置</text>
-                    <text class="version item-text"></text>
-                    <cwg-icon color="#817f7f" icon="chevron-right" />
-                </view>
-            </view> -->
-            <view class="group">
-                <view class="group-item" @click="router.push('/pages/mine/permission')">
-                    <cwg-icon color="#000" icon="yszc" />
-                    <text class="item-text">{{ t('pages.mine.permission') }}</text>
-                    <text class="version item-text"></text>
-                    <cwg-icon color="#817f7f" icon="chevron-right" />
-                </view>
-            </view>
-            <view class="group">
-                <view class="group-item" @click="router.push('/pages/mine/privacy')">
-                    <cwg-icon color="#000" icon="ys" />
-                    <text class="item-text">{{ t('pages.mine.privacy') }}</text>
-                    <text class="version item-text"></text>
-                    <cwg-icon color="#817f7f" icon="chevron-right" />
-                </view>
-            </view>
-            <view class="group">
-                <view class="group-item">
-                    <cwg-icon color="#000" icon="qchc" />
-                    <text class="item-text">{{ t('pages.mine.clearCache') }}</text>
-                    <text class="version item-text" @click="clearCache">{{ b || a }}</text>
-                    <cwg-icon color="#817f7f" icon="chevron-right" />
-                </view>
-            </view>
-
-            <view class="group" v-if="appVersion?.currentVersion">
-                <view class="group-item">
-                    <cwg-icon color="#000" icon="dqbb" />
-                    <text class="item-text">{{ t('pages.mine.currentVersion') }} v{{ appVersion.currentVersion }}</text>
-                    <text class="version item-text" @click="checkUpdate">{{ isUploadD }}</text>
-                    <cwg-icon color="#817f7f" icon="chevron-right" />
-                </view>
-            </view>
-
-            <view class="group">
-                <view class="group-item">
-                    <cwg-icon color="#000" icon="gy" />
-                    <text class="item-text">{{ t('pages.mine.about') }}</text>
-                    <text class="version item-text"></text>
-                    <cwg-icon color="#817f7f" icon="chevron-right" />
-                </view>
-            </view>
-
-            <view class="fixed-btn">
-                <view class="cwg-button">
-                    <u-button type="primary" block :loading="loading" @click="showLogoutPopup = true">{{
-                        t("language.i6") }}</u-button>
-                </view>
-            </view>
-            <u-modal class="code-dialog" :show="showLogoutPopup" title="" :show-confirm-button="false"
-                :show-cancel-button="false" :close-on-click-overlay="false">
-                <view class="modal-class">
-                    <view class="p1 title">{{ t('mine.logout') }}</view>
-                    <view class="p1">{{ t('mine.p') }}</view>
-                    <view class="cwg-button ok-button">
-                        <u-button type="primary" block @click="handleLogout('confirm')">{{
-                            t("mine.b1")
-                        }}</u-button>
-                    </view>
-                    <view class="cwg-button no-button">
-                        <u-button type="primary" block @click="handleLogout">{{
-                            t("mine.b2")
-                        }}</u-button>
-                    </view>
-                </view>
-            </u-modal>
-        </view>
-    </cwg-page-wrapper>
-
-</template>
-
-<script setup lang="ts">
-import { onLoad } from '@dcloudio/uni-app'
-import { ref, computed } from "vue";
-import { useI18n } from "vue-i18n";
-import useRouter from "@/hooks/useRouter";
-import { userApi } from "@/api/user";
-import { lang } from "@/composables/config";
-import useUserStore from "@/stores/use-user-store";
-import { showToast } from "@/utils/toast";
-import { useAppUpdate } from '@/hooks/useAppUpdate'
-const { checkUpdate } = useAppUpdate()
-const { t } = useI18n();
-const userStore = useUserStore();
-const router = useRouter();
-const b = ref('')
-const a = computed(() => {
-    try {
-        const res = uni.getStorageInfoSync();
-        const currentSizeMB = (res.currentSize / 1024).toFixed(2);
-        return `${currentSizeMB} MB`;
-    } catch (e) {
-        return 0
-    }
-});
-const appVersion = computed(() => userStore.appVersion);
-const isUploadD = computed(() => appVersion.value?.isUpdate ? t('pages.mine.newVersion') : t('pages.mine.hasNewVersion'));
-const showLogoutPopup = ref(false);
-async function handleLogout(action: string) {
-    if (action === "confirm") {
-        try {
-            const res = await userApi.logout();
-            if (res.code === 200) {
-                userStore.clearUserInfo();
-                router.push("/pages/login/index");
-            }
-        } catch (error) {
-            showToast(error.message || "退出登录失败");
-        }
-    }
-    showLogoutPopup.value = false;
-}
-
-const clearCache = () => {
-    uni.showModal({
-        title: t('pages.mine.clearCache'),
-        cancelText: t('common.cancel'),
-        confirmText: t('common.confirm'),
-        content: t('mine.p19') + a.value,
-        success: async (e) => {
-            if (e.confirm) {
-                b.value = '0 MB';
-            } else {
-                b.value = '';
-            }
-        }
-    });
-};
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-:deep(.u-modal__content) {
-    padding: px2rpx(24) px2rpx(40);
-
-    .p1 {
-        color: #363130;
-        font-family: "League Spartan";
-        font-size: px2rpx(17);
-        font-style: normal;
-        font-weight: 400;
-        line-height: normal;
-        margin-bottom: px2rpx(32);
-    }
-
-    .modal-class {
-        width: px2rpx(300);
-
-    }
-
-    .title {
-        color: #1a1a1a;
-        text-align: center;
-        font-family: Roboto;
-        font-size: px2rpx(22);
-        font-style: normal;
-        font-weight: 600;
-        line-height: px2rpx(22);
-    }
-
-    .no-button {
-        width: 100%;
-        margin: px2rpx(12) 0;
-
-        .u-button {
-            background-color: #ffbdc8 !important;
-        }
-    }
-
-    .ok-button {
-        margin: px2rpx(4) 0;
-        /* background-color: #EA002A; */
-    }
-}
-
-.user-card {
-    width: 100%;
-    display: inline-flex;
-    flex-direction: column;
-    justify-content: center;
-    align-items: center;
-    gap: px2rpx(24);
-    padding-bottom: px2rpx(48);
-
-    .avatar {
-        width: px2rpx(64);
-        height: px2rpx(64);
-        border-radius: 50%;
-        background: #d8d8d8 url("/static/images/avatars.png") center/cover no-repeat;
-        border: 4rpx solid #fff;
-    }
-
-    .phone {
-        color: #1a1a1a;
-        font-family: Roboto;
-        font-size: px2rpx(22);
-        font-style: normal;
-        font-weight: 600;
-        line-height: px2rpx(4);
-    }
-}
-
-.user-info .group {
-    background: var(--action-bg);
-    border-radius: px2rpx(16);
-    margin-top: px2rpx(24);
-    overflow: hidden;
-}
-
-.group-item {
-    display: flex;
-    align-items: center;
-    padding: px2rpx(16) 0;
-    color: #000;
-    font-size: px2rpx(16);
-    /* border-bottom: 2rpx solid var(--action-bg); */
-    position: relative;
-}
-
-.group-item:last-child {
-    border-bottom: none;
-}
-
-svg {
-    width: px2rpx(24);
-    height: px2rpx(24);
-    color: #000;
-    font-size: px2rpx(24);
-}
-
-.group-item .version {
-    margin-left: auto;
-    color: #817f7f;
-    font-size: px2rpx(16);
-}
-
-.item-text {
-    margin-left: px2rpx(12);
-}
-
-.code-dialog {
-    display: flex;
-    justify-content: center;
-    gap: px2rpx(12);
-    padding: px2rpx(16);
-
-    :deep(.u-popup__content) {
-        width: 90% !important;
-    }
-
-    :deep(.u-modal) {
-        width: 100% !important;
-    }
-}
-</style>

+ 0 - 30
pages/mine/help-detail.vue

@@ -1,30 +0,0 @@
-<template>
-    <cwg-page-wrapper class="permission-page">
-
-        <view class="content">
-            <view class="privacy" v-html="problemDetails.answer"></view>
-        </view>
-    </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { onLoad } from '@dcloudio/uni-app'
-import { computed } from 'vue'
-import useUserStore from "@/stores/use-user-store";
-const userStore = useUserStore();
-const problemDetails = computed(() => {
-    return userStore.problemDetails;
-});
-</script>
-
-<style lang="scss" scoped>
-@import "@/uni.scss";
-
-.permission-page {
-    min-height: 100vh;
-    background-color: #f5f5f5;
-    padding: px2rpx(12) !important;
-
-    .content {}
-}
-</style>

+ 0 - 155
pages/mine/help.vue

@@ -1,155 +0,0 @@
-<template>
-    <cwg-page-wrapper class="permission-page">
-        <view class="content">
-            <u-collapse :border="false" @close="close" @open="open" class="u-collapses" v-if="treeData.length > 0">
-                <u-collapse-item :border="false" v-for="value in treeData" :title="value.type" :name="value.id"
-                    :key="value.id" :class="value.id !== typeId ? 'u-collapse-items' : 'u-collapse-item'">
-                    <view class="u-collapse-content" v-for="(item, index) in value.children" :key="item.id"
-                        @click="openProblem(item)">
-                        <view class="answer">{{ Number(index) + 1 }}</view>
-                        <view class="question">{{ item.problem }}</view>
-                    </view>
-                </u-collapse-item>
-            </u-collapse>
-            <cwg-empty-state v-if="treeData.length === 0" />
-        </view>
-    </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { onLoad } from '@dcloudio/uni-app'
-import { ref, onMounted } from 'vue'
-import { ucardApi } from '@/api/ucard'
-import { useI18n } from "vue-i18n";
-import useUserStore from "@/stores/use-user-store";
-const userStore = useUserStore();
-const { t, locale } = useI18n();
-const list = ref([]);
-const dropdownList = ref([]);
-const treeData = ref([]);
-const typeId = ref(null);
-
-const open = (name) => {
-    typeId.value = name;
-};
-const close = (name) => {
-    typeId.value = null;
-};
-const openProblem = (item) => {
-    userStore.saveProblemDetails(item);
-    uni.navigateTo({
-        url: `/pages/mine/help-detail`
-    });
-};
-const getAppCommonProblemPage = async () => {
-    const res = await ucardApi.getAppCommonProblemPage({ page: { current: 1, row: 100 }, language: locale.value });
-    if (res.code === 200) {
-        list.value = res.data
-    }
-};
-const getAppCommonProblemDropdown = async () => {
-    const res = await ucardApi.getAppCommonProblemDropdown({ language: locale.value });
-    if (res.code === 200) {
-        dropdownList.value = res.data
-    }
-};
-
-// 将数据处理成树形结构
-const buildTreeData = () => {
-    treeData.value = dropdownList.value.map(dropdown => {
-        const children = list.value.filter(item => item.typeId === dropdown.id);
-        if (children.length === 0) return null;
-        return { ...dropdown, children }
-    }).filter(item => item !== null);
-};
-
-const loadData = async () => {
-    await getAppCommonProblemDropdown();
-    await getAppCommonProblemPage();
-    buildTreeData();
-};
-
-onMounted(() => {
-    loadData();
-})
-</script>
-
-<style lang="scss" scoped>
-@import "@/uni.scss";
-
-.permission-page {
-    min-height: 100vh;
-    background: #f5f5f5;
-    padding: px2rpx(12) !important;
-
-    .u-collapses {
-        border-radius: px2rpx(8);
-        overflow: hidden;
-    }
-
-    .u-collapse-item {
-        background: #fff;
-        transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-
-        :deep(.u-cell__body) {
-            // background: linear-gradient(90deg, #eb4e6b 0%, #e7afba 100%);
-            background: rgba(208, 37, 55, 0.03);
-            border-radius: px2rpx(8);
-            // color: #fff;
-            transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
-        }
-
-        :deep(.u-collapse-item__content) {
-            border-radius: px2rpx(8);
-            z-index: 3;
-            background: #fff;
-            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-            overflow: hidden;
-        }
-
-        :deep(.u-collapse-item__content__text) {
-            transition: opacity 0.25s ease-in-out;
-        }
-    }
-
-    .u-collapse-items {
-        border-radius: px2rpx(8);
-        transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-
-        :deep(.u-cell__body) {
-            background: #fff;
-            border-radius: px2rpx(8);
-            color: #333;
-            transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
-        }
-
-        :deep(.u-collapse-item__content) {
-            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-            overflow: hidden;
-        }
-
-        :deep(.u-collapse-item__content__text) {
-            transition: opacity 0.25s ease-in-out;
-        }
-    }
-
-    .u-collapse-content {
-        display: flex;
-        align-items: center;
-        transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.25s ease-in-out;
-
-        &:active {
-            transform: scale(0.98);
-            opacity: 0.8;
-        }
-
-        .question {
-            flex: 1;
-            padding: px2rpx(16);
-            font-size: px2rpx(16);
-            color: #333;
-        }
-    }
-
-}
-</style>

+ 0 - 434
pages/recharge-record/components/DeductionList.vue

@@ -1,434 +0,0 @@
-<template>
-  <cwg-load-more-wrapper ref="loadMoreWrapperRef" :loading="loading" :finished="finished" :height='108'
-    :refresher-enabled="true" @reach-bottom="loadMore" @refresh="handleRefresh">
-    <view v-if="records.length > 0" class="records-list">
-      <view v-for="record in records" :key="record.id" class="record-card" @click="goToDeductionDetail(record)">
-        <view class="record-main">
-          <view class="record-left">
-            <view class="type-icon deduction-icon">
-              <cwg-icon class="icons" :name="getDeductionIcon(record.type || record.typeStr)" :size="20"
-                color="#ef4444" />
-            </view>
-
-            <view class="record-info">
-              <view class="info-header">
-                <text class="record-type">{{ getDeductionTypeText(record.type || record.typeStr) }}</text>
-                <view :class="['status-badge', getStatusBadgeClass(record.status)]">
-                  <cwg-icon class="icons" :name="getStatusIcon(record.status)" :size="12"
-                    :color="getStatusColor(record.status)" />
-                  <text :class="['status-text', getStatusTextClass(record.status)]">
-                    {{ getStatusText(record.status) }}
-                  </text>
-                </view>
-              </view>
-              <text class="record-detail">{{ record.remark || record.cardNumber || '--' }}</text>
-            </view>
-          </view>
-
-          <view class="record-right">
-            <text class="amount-deduction">-{{ Math.abs(Number(record.amount || 0)).toFixed(2) }} {{ record.currency
-              || 'USD' }}</text>
-            <text class="fee-text">{{ t('global.p17') }} {{ Number(record.fee || 0).toFixed(2) }}</text>
-          </view>
-        </view>
-
-        <view class="record-footer">
-          <text class="footer-time">{{ formatDateTime(record.addTime || record.time) }}</text>
-        </view>
-      </view>
-    </view>
-    <cwg-empty-state v-else />
-  </cwg-load-more-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch, onMounted } from 'vue';
-import dayjs from 'dayjs';
-import { useI18n } from 'vue-i18n';
-import { showToast } from '@/utils/toast';
-import { ucardApi, TransactionInfo } from '@/api/ucard';
-import { transactionStatusMap, WITHDRAW_TYPE_MAP } from '@/utils/dataMap';
-import useCardStore from '@/stores/use-card-store';
-
-interface RecordItem extends TransactionInfo {
-  type?: string | number;
-  typeStr?: string;
-  remark?: string;
-  status?: string | number;
-  addTime?: string | number;
-  fee?: number;
-  currency?: string;
-  merchantOrderNo?: string;
-  reason?: string;
-  time?: string | number;
-}
-
-type NormalizedStatus = 'success' | 'processing' | 'failed';
-
-const props = defineProps<{
-  cardNumber: string;
-  typeIndex: number;
-  statusIndex: number;
-  dateFilter: string;
-  typeOptions: string[];
-}>();
-
-const { t } = useI18n();
-
-const records = ref<RecordItem[]>([]);
-const page = ref(1);
-const pageSize = 10;
-const loading = ref(false);
-const finished = ref(false);
-
-const cardStore = useCardStore();
-
-const normalizeStatus = (status?: string | number): NormalizedStatus => {
-  if (!status) return 'success';
-  const statusStr = String(status).toLowerCase();
-  if (statusStr === 'processing' || statusStr === 'wait_process') return 'processing';
-  if (statusStr === 'fail' || statusStr === 'failed') return 'failed';
-  if (statusStr === 'succeed' || statusStr === 'success') return 'success';
-  return 'success';
-};
-
-const getStatusText = (status?: string | number): string => {
-  if (!status) return '';
-  const statusKey = String(status).toLowerCase();
-  if (transactionStatusMap[statusKey as keyof typeof transactionStatusMap]) {
-    return t(transactionStatusMap[statusKey as keyof typeof transactionStatusMap]);
-  }
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return t('card.Status.t1');
-  if (normalized === 'processing') return t('card.Status.t3');
-  return t('card.Status.t2');
-};
-
-const getStatusIcon = (status?: string | number): string => {
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return 'checkmarkempty1';
-  if (normalized === 'processing') return 'info1';
-  return 'closeempty1';
-};
-
-const getStatusColor = (status?: string | number): string => {
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return '#22c55e';
-  if (normalized === 'processing') return '#eab308';
-  return '#ef4444';
-};
-
-const getStatusBadgeClass = (status?: string | number) => `status-${normalizeStatus(status)}`;
-const getStatusTextClass = (status?: string | number) => `status-text-${normalizeStatus(status)}`;
-
-const getDeductionTypeText = (type?: string | number): string => {
-  if (!type) return '--';
-  const typeNum = typeof type === 'string' ? parseInt(type) : type;
-  if (WITHDRAW_TYPE_MAP[typeNum as keyof typeof WITHDRAW_TYPE_MAP]) {
-    return t(WITHDRAW_TYPE_MAP[typeNum as keyof typeof WITHDRAW_TYPE_MAP]);
-  }
-  return String(type);
-};
-
-const getDeductionIcon = (type?: string | number): string => {
-  const typeStr = String(type || '');
-  if (typeStr.includes('服务费') || typeStr === '1') return 'servicefee';
-  if (typeStr.includes('手续费') || typeStr === '2') return 'handlingfee';
-  return 'servicefee';
-};
-
-const formatDateTime = (time?: string | number): string => {
-  if (!time) return '--';
-  try {
-    let date: dayjs.Dayjs;
-    if (typeof time === 'number') {
-      if (time.toString().length === 10) {
-        date = dayjs.unix(time);
-      } else {
-        date = dayjs(time);
-      }
-    } else {
-      date = dayjs(time);
-    }
-    if (!date.isValid()) return '--';
-    return date.format('YYYY-MM-DD HH:mm:ss');
-  } catch (error) {
-    return '--';
-  }
-};
-
-const fetchRecords = async (isLoadMore = false) => {
-  if (!props.cardNumber || loading.value) return;
-  if (isLoadMore && finished.value) return;
-
-  loading.value = true;
-  try {
-    const res = await ucardApi.getCardWithdrawPage({
-      cardNumber: props.cardNumber,
-      type: props.typeIndex == -1 ? undefined : props.typeIndex,
-      status: props.statusIndex == -1 ? undefined : props.statusIndex,
-      beginDate: props.dateFilter[0] || undefined,
-      endDate: (() => {
-        let date = props.dateFilter?.[1];
-        if (!date) return undefined;
-        return Number(date) + 24 * 60 * 60 * 1000 - 1
-      })(),
-      page: { current: page.value, row: pageSize },
-    });
-    const data = res.code === 200 && Array.isArray(res.data) ? res.data : [];
-
-    if (isLoadMore) {
-      records.value.push(...data);
-    } else {
-      records.value = data;
-    }
-
-    if (data.length < pageSize) {
-      finished.value = true;
-    } else {
-      finished.value = false;
-    }
-  } catch (error: any) {
-    if (!isLoadMore) {
-      records.value = [];
-    }
-    showToast(error?.message || String(error));
-  } finally {
-    loading.value = false;
-  }
-};
-
-const goToDeductionDetail = (record: RecordItem) => {
-  const amount = Number(record.amount || 0);
-  const fee = Number(record.fee || 0);
-  const normalizedStatus = normalizeStatus(record.status);
-
-  const detailPayload = {
-    category: 'deduction' as const,
-    type: getDeductionTypeText(record.type || record.typeStr),
-    amount,
-    fee,
-    actualAmount: amount - fee,
-    currency: record.currency || 'USD',
-    orderStatus: normalizedStatus,
-    statusMessage: getStatusText(record.status),
-    createTime: formatDateTime(record.transactionTime),
-    completeTime: '',
-    merchant: '',
-    bankCard: '',
-    bankCard: record.cardNumber,
-    remark: record.remark || record.reason || '',
-    approvalSteps: [] as any[]
-  };
-
-
-  cardStore.saveOrderDetail(detailPayload);
-  uni.navigateTo({
-    url: '/pages/recharge-record/detail'
-  });
-};
-
-const loadMore = () => {
-  if (finished.value || loading.value) return;
-  page.value++;
-  fetchRecords(true);
-};
-
-watch([() => props.dateFilter], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-watch([() => props.typeIndex], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-watch([() => props.statusIndex], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-
-const loadMoreWrapperRef = ref<any>(null);
-
-const refresh = async () => {
-  page.value = 1;
-  finished.value = false;
-  await fetchRecords();
-};
-
-const handleRefresh = async () => {
-  await refresh();
-  // 停止下拉刷新动画
-  if (loadMoreWrapperRef.value) {
-    loadMoreWrapperRef.value.stopRefresh();
-  }
-};
-
-onMounted(() => {
-  fetchRecords();
-});
-
-defineExpose({
-  refresh
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.records-list {
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(12);
-  padding: px2rpx(16);
-}
-
-.record-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  border: 1px solid #e5e7eb;
-  overflow: hidden;
-  transition: box-shadow 0.3s;
-  padding: px2rpx(16);
-}
-
-.record-card:active {
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-}
-
-.record-main {
-  display: flex;
-  align-items: flex-start;
-  justify-content: space-between;
-  padding-bottom: px2rpx(16);
-}
-
-.record-left {
-  display: flex;
-  align-items: flex-start;
-  gap: px2rpx(12);
-  flex: 1;
-  min-width: 0;
-}
-
-.type-icon {
-  width: px2rpx(40);
-  height: px2rpx(40);
-  border-radius: px2rpx(10);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.deduction-icon {
-  background-color: #fef2f2;
-}
-
-.icons {
-  width: px2rpx(20);
-  height: px2rpx(20);
-}
-
-.record-info {
-  flex: 1;
-  min-width: 0;
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(6);
-}
-
-.info-header {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  flex-wrap: wrap;
-}
-
-.record-type {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-
-.status-success {
-  background-color: #f0fdf4;
-}
-
-.status-processing {
-  background-color: #fefce8;
-}
-
-.status-failed {
-  background-color: #fef2f2;
-}
-
-.status-text {
-  font-size: px2rpx(11);
-}
-
-.status-text-success {
-  color: #22c55e;
-}
-
-.status-text-processing {
-  color: #eab308;
-}
-
-.status-text-failed {
-  color: #ef4444;
-}
-
-.record-detail {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.record-right {
-  display: flex;
-  flex-direction: column;
-  align-items: flex-end;
-  gap: px2rpx(4);
-  margin-left: px2rpx(12);
-  flex-shrink: 0;
-}
-
-.amount-deduction {
-  font-size: px2rpx(18);
-  color: #ef4444;
-}
-
-.fee-text {
-  font-size: px2rpx(11);
-  color: #9ca3af;
-}
-
-.record-footer {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding-top: px2rpx(16);
-  border-top: 1px solid #f3f4f6;
-}
-
-.footer-time {
-  font-size: px2rpx(11);
-  color: #9ca3af;
-}
-
-.footer-actions {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(2);
-}
-
-.footer-detail {
-  font-size: px2rpx(11);
-  color: #2563eb;
-}
-</style>

+ 0 - 488
pages/recharge-record/components/RechargeList.vue

@@ -1,488 +0,0 @@
-<template>
-  <cwg-load-more-wrapper ref="loadMoreWrapperRef" :loading="loading" :finished="finished" :height='108'
-    :refresher-enabled="pageSize != 4" @reach-bottom="loadMore" @refresh="handleRefresh">
-    <view v-if="records.length > 0" :class="{
-      'records-list': true,
-      'records-list1': pageSize === 4
-    }">
-      <view v-for="record in records" :key="record.id" class="record-card" @click="goToRechargeDetail(record)">
-        <view class="record-main">
-          <view class="record-left">
-            <view class="type-icon recharge-icon">
-              <cwg-icon class="icons" name="download-filled" :size="20" color="#22c55e" />
-            </view>
-            <view class="record-info">
-              <view class="info-header">
-                <text class="record-type">{{ t(rechargeTypes[record.rechargeType]) }}</text>
-                <view :class="['status-badge', getStatusBadgeClass(record.status)]">
-                  <cwg-icon class="icons" :name="getStatusIcon(record.status)" :size="12"
-                    :color="getStatusColor(record.status)" />
-                  <text :class="['status-text', getStatusTextClass(record.status)]">
-                    {{ getStatusText(record.status) }}
-                  </text>
-                </view>
-              </view>
-              <text class="record-detail">{{ record.cardNumber || record.remark ||
-                '--' }}</text>
-            </view>
-          </view>
-
-          <view class="record-right">
-            <text class="amount-recharge">+{{ Number(record.amount || 0).toFixed(2) }} {{ record.currency || 'USD'
-              }}</text>
-            <text class="fee-text">{{ t('global.p17') }} {{ Number(record.rechargeFee || 0).toFixed(2) }}</text>
-          </view>
-        </view>
-        <view class="record-footer">
-          <text class="footer-time">{{ formatDateTime(record.addTime || record.time) }}</text>
-          <view class="footer-actions">
-            <text class="footer-order">
-              {{ t('global.p15') }}: {{ formatOrderNo(record.merchantOrderNo || record.orderNo) }}
-            </text>
-            <cwg-icon class="footer-order-icon" name="copy" :size="14" color="#9ca3af"
-              @click.stop="copyOrderNo(record.merchantOrderNo || record.orderNo)" />
-          </view>
-        </view>
-      </view>
-    </view>
-    <cwg-empty-state v-else />
-  </cwg-load-more-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch, onMounted } from 'vue';
-import dayjs from 'dayjs';
-import { useI18n } from 'vue-i18n';
-import { showToast } from '@/utils/toast';
-import { ucardApi, TransactionInfo } from '@/api/ucard';
-import { rechargeStatusMap } from '@/utils/dataMap';
-import useCardStore from '@/stores/use-card-store';
-import { rechargeType } from '@/utils/dataMap';
-const rechargeTypes = computed(() => rechargeType);
-interface RecordItem extends TransactionInfo {
-  type?: string;
-  typeStr?: string;
-  remark?: string;
-  status?: string | number;
-  addTime?: string;
-  fee?: number;
-  currency?: string;
-  merchantOrderNo?: string;
-  cardNumber?: string;
-  time?: string;
-  rechargeType?: string;
-  rechargeFee?: number;
-  amount?: number;
-}
-
-
-type NormalizedStatus = 'success' | 'processing' | 'failed';
-
-const props = defineProps<{
-  cardNumber: string;
-  pageSize: number;
-  typeIndex: number;
-  statusIndex: number;
-  dateFilter: string;
-  typeOptions: string[];
-}>();
-
-const { t } = useI18n();
-
-const records = ref<RecordItem[]>([]);
-const page = ref(1);
-const pageSize = computed(() => props.pageSize || 10);
-const loading = ref(false);
-const finished = ref(false);
-
-const cardStore = useCardStore();
-
-const normalizeStatus = (status?: string | number): NormalizedStatus => {
-  if (!status) return 'success';
-  const statusStr = String(status).toLowerCase();
-  if (statusStr === 'processing' || statusStr === 'wait_process') return 'processing';
-  if (statusStr === 'fail' || statusStr === 'failed') return 'failed';
-  if (statusStr === 'succeed' || statusStr === 'success') return 'success';
-  return 'success';
-};
-
-const getStatusText = (status?: string | number): string => {
-  if (!status) return '';
-  const statusKey = String(status).toLowerCase();
-  if (rechargeStatusMap[statusKey as keyof typeof rechargeStatusMap]) {
-    return t(rechargeStatusMap[statusKey as keyof typeof rechargeStatusMap]);
-  }
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return t('card.Status.t1');
-  if (normalized === 'processing') return t('card.Status.t3');
-  return t('card.Status.t2');
-};
-
-const getStatusIcon = (status?: string | number): string => {
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return 'checkmarkempty1';
-  if (normalized === 'processing') return 'info1';
-  return 'closeempty1';
-};
-
-const getStatusColor = (status?: string | number): string => {
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return '#22c55e';
-  if (normalized === 'processing') return '#eab308';
-  return '#ef4444';
-};
-
-const getStatusBadgeClass = (status?: string | number) => `status-${normalizeStatus(status)}`;
-const getStatusTextClass = (status?: string | number) => `status-text-${normalizeStatus(status)}`;
-
-
-const formatDateTime = (time?: string | number): string => {
-  if (!time) return '--';
-  try {
-    let date: dayjs.Dayjs;
-    if (typeof time === 'number') {
-      if (time.toString().length === 10) {
-        date = dayjs.unix(time);
-      } else {
-        date = dayjs(time);
-      }
-    } else {
-      date = dayjs(time);
-    }
-    if (!date.isValid()) return '--';
-    return date.format('YYYY-MM-DD HH:mm:ss');
-  } catch (error) {
-    return '--';
-  }
-};
-
-const getDatePart = (time?: string | number): string => {
-  if (!time) return '';
-  try {
-    let date: dayjs.Dayjs;
-    if (typeof time === 'number') {
-      if (time.toString().length === 10) {
-        date = dayjs.unix(time);
-      } else {
-        date = dayjs(time);
-      }
-    } else {
-      date = dayjs(time);
-    }
-    if (!date.isValid()) return '';
-    return date.format('YYYY-MM-DD');
-  } catch (error) {
-    return '';
-  }
-};
-
-const formatOrderNo = (orderNo?: string) => {
-  if (!orderNo) return '--';
-  if (orderNo.length <= 20) return orderNo;
-  return orderNo.slice(0, 6) + '...' + orderNo.slice(-4);
-};
-
-const copyOrderNo = (orderNo?: string) => {
-  if (!orderNo) return;
-  uni.setClipboardData({
-    data: orderNo,
-    success: () => {
-      uni.showToast({
-        title: t('card.Msg.m8') || '复制成功',
-        icon: 'success'
-      });
-    }
-  });
-};
-
-const fetchRecords = async (isLoadMore = false) => {
-  if (!props.cardNumber || loading.value) return;
-  if (isLoadMore && finished.value) return;
-
-  loading.value = true;
-  try {
-    const res = await ucardApi.rechargeList({
-      cardNumber: props.cardNumber,
-      rechargeType: props.typeIndex == -1 ? undefined : props.typeIndex,
-      status: props.statusIndex == -1 ? undefined : props.statusIndex,
-      startDate: props.dateFilter?.[0] ? dayjs(props.dateFilter[0]).format('YYYY-MM-DD') : undefined,
-      endDate: props.dateFilter?.[1] ? dayjs(props.dateFilter[1]).format('YYYY-MM-DD') : undefined,
-      page: { current: page.value, row: pageSize.value },
-    });
-    const data = res.code === 200 && Array.isArray(res.data) ? res.data : [];
-
-    if (isLoadMore) {
-      records.value.push(...data);
-    } else {
-      records.value = data;
-    }
-    if (data.length < pageSize.value) {
-      finished.value = true;
-    } else {
-      finished.value = false;
-    }
-  } catch (error: any) {
-    if (!isLoadMore) {
-      records.value = [];
-    }
-    showToast(error?.message || String(error));
-  } finally {
-    loading.value = false;
-  }
-};
-
-const goToRechargeDetail = (record: RecordItem) => {
-  const amount = Number(record.amount || 0);
-  const fee = Number(record.rechargeFee || 0);
-  const normalizedStatus = normalizeStatus(record.status);
-
-  const detailPayload = {
-    category: 'recharge' as const,
-    orderNo: record.merchantOrderNo || record.orderNo || '',
-    type: t(rechargeTypes.value[record.rechargeType]),
-    amount,
-    fee,
-    actualAmount: amount - fee,
-    currency: record.currency || 'USD',
-    orderStatus: normalizedStatus,
-    statusMessage: getStatusText(record.status),
-    createTime: formatDateTime(record.addTime || record.time),
-    completeTime: '',
-    merchant: '',
-    bankCard: record.cardNumber || '',
-    remark: record.remark || '',
-    approvalSteps: [] as any[]
-  };
-
-  cardStore.saveOrderDetail(detailPayload);
-  uni.navigateTo({
-    url: '/pages/recharge-record/detail'
-  });
-};
-
-const loadMore = () => {
-  if (finished.value || loading.value || props.pageSize == 4) return;
-  page.value++;
-  fetchRecords(true);
-};
-
-
-// 监听筛选条件变化,重新加载数据
-watch([() => props.dateFilter], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-watch([() => props.typeIndex], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-watch([() => props.statusIndex], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-watch([() => props.cardNumber], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-
-const loadMoreWrapperRef = ref<any>(null);
-
-const refresh = async () => {
-  page.value = 1;
-  finished.value = false;
-  await fetchRecords();
-};
-
-const handleRefresh = async () => {
-  await refresh();
-  // 停止下拉刷新动画
-  if (loadMoreWrapperRef.value) {
-    loadMoreWrapperRef.value.stopRefresh();
-  }
-};
-
-onMounted(() => {
-  fetchRecords();
-});
-
-defineExpose({
-  refresh
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.records-list {
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(12);
-  padding: px2rpx(16);
-}
-
-.records-list1 {
-  gap: px2rpx(12);
-  padding: px2rpx(16) 0;
-}
-
-.record-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  border: 1px solid #e5e7eb;
-  overflow: hidden;
-  transition: box-shadow 0.3s;
-  padding: px2rpx(16);
-}
-
-.record-card:active {
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-}
-
-.record-main {
-  display: flex;
-  align-items: flex-start;
-  justify-content: space-between;
-  padding-bottom: px2rpx(16);
-}
-
-.record-left {
-  display: flex;
-  align-items: flex-start;
-  gap: px2rpx(12);
-  flex: 1;
-  min-width: 0;
-}
-
-.type-icon {
-  width: px2rpx(40);
-  height: px2rpx(40);
-  border-radius: px2rpx(10);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.recharge-icon {
-  background-color: #f0fdf4;
-}
-
-.icons {
-  width: px2rpx(20);
-  height: px2rpx(20);
-}
-
-.record-info {
-  flex: 1;
-  min-width: 0;
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(6);
-}
-
-.info-header {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  flex-wrap: wrap;
-}
-
-.record-type {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-.status-success {
-  background-color: #f0fdf4;
-}
-
-.status-processing {
-  background-color: #fefce8;
-}
-
-.status-failed {
-  background-color: #fef2f2;
-}
-
-.status-text {
-  font-size: px2rpx(11);
-}
-
-.status-text-success {
-  color: #22c55e;
-}
-
-.status-text-processing {
-  color: #eab308;
-}
-
-.status-text-failed {
-  color: #ef4444;
-}
-
-.record-detail {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.record-right {
-  display: flex;
-  flex-direction: column;
-  align-items: flex-end;
-  gap: px2rpx(4);
-  margin-left: px2rpx(12);
-  flex-shrink: 0;
-}
-
-.amount-recharge {
-  font-size: px2rpx(18);
-  color: #22c55e;
-}
-
-.fee-text {
-  font-size: px2rpx(11);
-  color: #9ca3af;
-}
-
-.record-footer {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding-top: px2rpx(16);
-  border-top: 1px solid #f3f4f6;
-}
-
-.footer-actions {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-}
-
-.footer-time {
-  font-size: px2rpx(11);
-  color: #9ca3af;
-}
-
-.footer-actions {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(2);
-}
-
-.footer-order {
-  font-size: px2rpx(11);
-  color: #9ca3af;
-}
-
-.footer-detail {
-  font-size: px2rpx(11);
-  color: #2563eb;
-}
-</style>

+ 0 - 507
pages/recharge-record/components/TransactionList.vue

@@ -1,507 +0,0 @@
-<template>
-  <cwg-load-more-wrapper ref="loadMoreWrapperRef" :loading="loading" :finished="finished" :height='108'
-    :refresher-enabled="pageSize != 4" @reach-bottom="loadMore" @refresh="handleRefresh">
-    <view v-if="records.length > 0" :class="{
-      'records-list': true,
-      'records-list1': pageSize === 4
-    }">
-      <view v-for="record in records" :key="record.id" class="record-card" @click="goToTransactionDetail(record)">
-        <view class="record-main">
-          <view class="record-left">
-            <view class="type-icon transaction-icon">
-              <cwg-icon class="icons" :name="getTransactionIcon(record.type)" :size="20" color="#2563eb" />
-            </view>
-            <view class="record-info">
-              <view class="info-header">
-                <text class="record-type">{{ getTransactionTypeText(record.type) }}</text>
-                <view :class="['status-badge', getStatusBadgeClass(record.status)]">
-                  <cwg-icon class="icons" :name="getStatusIcon(record.status)" :size="12"
-                    :color="getStatusColor(record.status)" />
-                  <text :class="['status-text', getStatusTextClass(record.status)]">
-                    {{ getStatusText(record.status) }}
-                  </text>
-                </view>
-              </view>
-              <text class="record-detail">{{ record.remark || record.merchant || '--' }}</text>
-            </view>
-          </view>
-
-          <view class="record-right">
-            <text class="amount-transaction">{{ Number(record.amount || 0) >= 0 ? '+' : '-' }}{{
-              Math.abs(Number(record.amount || 0)).toFixed(2) }} {{ record.currency || 'USD' }}</text>
-            <text class="fee-text">{{ t('global.p17') }} {{ Number(record.fee || 0).toFixed(2) }}</text>
-          </view>
-        </view>
-
-        <view class="record-footer">
-          <text class="footer-time">{{ formatDateTime(record.transactionTime) }}</text>
-          <view class="footer-actions">
-            <text class="footer-order">
-              {{ t('global.p15') }}: {{ formatOrderNo(record.tradeNo) }}
-            </text>
-            <cwg-icon class="footer-order-icon" name="copy" :size="14" color="#9ca3af"
-              @click.stop="copyOrderNo(record.tradeNo)" />
-          </view>
-        </view>
-      </view>
-    </view>
-    <cwg-empty-state v-else />
-  </cwg-load-more-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch, onMounted } from 'vue';
-import dayjs from 'dayjs';
-import { useI18n } from 'vue-i18n';
-import { showToast } from '@/utils/toast';
-import { ucardApi, TransactionInfo } from '@/api/ucard';
-import { transactionTypeMap, transactionStatusMap } from '@/utils/dataMap';
-import useCardStore from '@/stores/use-card-store';
-
-interface RecordItem extends TransactionInfo {
-  type?: string;
-  typeStr?: string;
-  remark?: string;
-  status?: string | number;
-  transactionTime?: string | number;
-  fee?: number;
-  currency?: string;
-  tradeNo?: string;
-  merchant?: string;
-}
-
-type NormalizedStatus = 'success' | 'processing' | 'failed';
-
-const props = defineProps<{
-  cardNumber: string;
-  pageSize: number;
-  typeIndex: number;
-  statusIndex: number;
-  dateFilter: string;
-  typeOptions: string[];
-}>();
-
-const { t } = useI18n();
-
-const records = ref<RecordItem[]>([]);
-const page = ref(1);
-const pageSize = computed(() => props.pageSize || 10);
-const loading = ref(false);
-const finished = ref(false);
-
-const cardStore = useCardStore();
-
-const normalizeStatus = (status?: string | number): NormalizedStatus => {
-  if (!status) return 'success';
-  const statusStr = String(status).toLowerCase();
-  if (statusStr === 'processing' || statusStr === 'wait_process') return 'processing';
-  if (statusStr === 'fail' || statusStr === 'failed') return 'failed';
-  if (statusStr === 'succeed' || statusStr === 'success') return 'success';
-  return 'success';
-};
-
-const getStatusText = (status?: string | number): string => {
-  if (!status) return '';
-  const statusKey = String(status).toLowerCase();
-  if (transactionStatusMap[statusKey as keyof typeof transactionStatusMap]) {
-    return t(transactionStatusMap[statusKey as keyof typeof transactionStatusMap]);
-  }
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return t('card.Status.t1');
-  if (normalized === 'processing') return t('card.Status.t3');
-  return t('card.Status.t2');
-};
-
-const getStatusIcon = (status?: string | number): string => {
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return 'checkmarkempty1';
-  if (normalized === 'processing') return 'info1';
-  return 'closeempty1';
-};
-
-const getStatusColor = (status?: string | number): string => {
-  const normalized = normalizeStatus(status);
-  if (normalized === 'success') return '#22c55e';
-  if (normalized === 'processing') return '#eab308';
-  return '#ef4444';
-};
-
-const getStatusBadgeClass = (status?: string | number) => `status-${normalizeStatus(status)}`;
-const getStatusTextClass = (status?: string | number) => `status-text-${normalizeStatus(status)}`;
-
-const getStatusValue = (index: number): NormalizedStatus | null => {
-  if (index === 0) return null;
-  const statusMap: NormalizedStatus[] = ['success', 'processing', 'failed'];
-  return statusMap[index - 1];
-};
-
-const getTransactionTypeText = (type?: string): string => {
-  if (!type) return '--';
-  const key = type.toLowerCase();
-  if (transactionTypeMap[key as keyof typeof transactionTypeMap]) {
-    return t(transactionTypeMap[key as keyof typeof transactionTypeMap]);
-  }
-  return type;
-};
-
-const getTransactionIcon = (type = ''): string => {
-  if (type.includes('购买') || type === 'refund') return 'cart';
-  if (type.includes('提现') || type === 'auth') return 'minus-filled';
-  if (type.includes('转账')) return 'redo';
-  if (type.includes('话费')) return 'phone';
-  if (type.includes('缴费')) return 'flame';
-  if (type === 'maintain_fee') return 'servicefee';
-  return 'servicefee';
-};
-
-const formatDateTime = (time?: string | number): string => {
-  if (!time) return '--';
-  try {
-    let date: dayjs.Dayjs;
-    if (typeof time === 'number') {
-      if (time.toString().length === 10) {
-        date = dayjs.unix(time);
-      } else {
-        date = dayjs(time);
-      }
-    } else {
-      date = dayjs(time);
-    }
-    if (!date.isValid()) return '--';
-    return date.format('YYYY-MM-DD HH:mm:ss');
-  } catch (error) {
-    return '--';
-  }
-};
-
-const getDatePart = (time?: string | number): string => {
-  if (!time) return '';
-  try {
-    let date: dayjs.Dayjs;
-    if (typeof time === 'number') {
-      if (time.toString().length === 10) {
-        date = dayjs.unix(time);
-      } else {
-        date = dayjs(time);
-      }
-    } else {
-      date = dayjs(time);
-    }
-    if (!date.isValid()) return '';
-    return date.format('YYYY-MM-DD');
-  } catch (error) {
-    return '';
-  }
-};
-
-const formatOrderNo = (orderNo?: string) => {
-  if (!orderNo) return '--';
-  if (orderNo.length <= 20) return orderNo;
-  return orderNo.slice(0, 6) + '...' + orderNo.slice(-4);
-};
-
-const copyOrderNo = (orderNo?: string) => {
-  if (!orderNo) return;
-  uni.setClipboardData({
-    data: orderNo,
-    success: () => {
-      uni.showToast({
-        title: t('card.Msg.m8') || '复制成功',
-        icon: 'success'
-      });
-    }
-  });
-};
-
-const fetchRecords = async (isLoadMore = false) => {
-  if (!props.cardNumber || loading.value) return;
-  if (isLoadMore && finished.value) return;
-
-  loading.value = true;
-  try {
-    const res = await ucardApi.transactionsList({
-      cardNumber: props.cardNumber,
-      type: props.typeIndex == -1 ? undefined : props.typeIndex,
-      status: props.statusIndex == -1 ? undefined : props.statusIndex,
-        beginDate: props.dateFilter?.[0] ? dayjs(props.dateFilter[0]).format('YYYY-MM-DD') : undefined,
-        endDate: props.dateFilter?.[1] ? dayjs(props.dateFilter[1]).format('YYYY-MM-DD') : undefined,
-      page: { current: page.value, row: pageSize.value },
-    });
-    const data = res.code === 200 && Array.isArray(res.data) ? res.data : [];
-
-    if (isLoadMore) {
-      records.value.push(...data);
-    } else {
-      records.value = data;
-    }
-
-    if (data.length < pageSize.value) {
-      finished.value = true;
-    } else {
-      finished.value = false;
-    }
-  } catch (error: any) {
-    if (!isLoadMore) {
-      records.value = [];
-    }
-    showToast(error?.message || String(error));
-  } finally {
-    loading.value = false;
-  }
-};
-
-const goToTransactionDetail = (record: RecordItem) => {
-  const amount = Number(record.amount || 0);
-  const fee = Number(record.fee || 0);
-  const normalizedStatus = normalizeStatus(record.status);
-
-  const detailPayload = {
-    category: 'transaction' as const,
-    orderNo: record.tradeNo || '',
-    type: getTransactionTypeText(record.type),
-    amount,
-    fee,
-    actualAmount: amount - fee,
-    currency: record.currency || 'USD',
-    orderStatus: normalizedStatus,
-    statusMessage: getStatusText(record.status),
-    createTime: formatDateTime(record.transactionTime),
-    completeTime: '',
-    merchant: record.merchant || '',
-    bankCard: '',
-    remark: record.remark || '',
-    approvalSteps: [] as any[]
-  };
-
-  cardStore.saveOrderDetail(detailPayload);
-  uni.navigateTo({
-    url: '/pages/recharge-record/detail'
-  });
-};
-
-const loadMore = () => {
-  if (finished.value || loading.value || props.pageSize == 4) return;
-  page.value++;
-  fetchRecords(true);
-};
-
-
-watch([() => props.dateFilter], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-watch([() => props.typeIndex], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-watch([() => props.statusIndex], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-watch([() => props.cardNumber], () => {
-  page.value = 1;
-  finished.value = false;
-  fetchRecords();
-}, { immediate: false });
-const loadMoreWrapperRef = ref<any>(null);
-
-const refresh = async () => {
-  page.value = 1;
-  finished.value = false;
-  await fetchRecords();
-};
-
-const handleRefresh = async () => {
-  await refresh();
-  // 停止下拉刷新动画
-  if (loadMoreWrapperRef.value) {
-    loadMoreWrapperRef.value.stopRefresh();
-  }
-};
-
-onMounted(() => {
-  fetchRecords();
-});
-
-defineExpose({
-  refresh
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.records-list {
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(12);
-  padding: px2rpx(16);
-}
-
-.records-list1 {
-  flex-direction: row;
-  flex-wrap: wrap;
-  gap: px2rpx(12);
-  padding: px2rpx(16) 0;
-}
-
-.record-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  border: 1px solid #e5e7eb;
-  overflow: hidden;
-  transition: box-shadow 0.3s;
-  padding: px2rpx(16);
-}
-
-.record-card:active {
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-}
-
-.record-main {
-  display: flex;
-  align-items: flex-start;
-  justify-content: space-between;
-  padding-bottom: px2rpx(16);
-}
-
-.record-left {
-  display: flex;
-  align-items: flex-start;
-  gap: px2rpx(12);
-  flex: 1;
-  min-width: 0;
-}
-
-.type-icon {
-  width: px2rpx(40);
-  height: px2rpx(40);
-  border-radius: px2rpx(10);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.transaction-icon {
-  background-color: #eff6ff;
-}
-
-.icons {
-  width: px2rpx(20);
-  height: px2rpx(20);
-}
-
-.record-info {
-  flex: 1;
-  min-width: 0;
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(6);
-}
-
-.info-header {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  flex-wrap: wrap;
-}
-
-.record-type {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-.status-success {
-  background-color: #f0fdf4;
-}
-
-.status-processing {
-  background-color: #fefce8;
-}
-
-.status-failed {
-  background-color: #fef2f2;
-}
-
-.status-text {
-  font-size: px2rpx(11);
-}
-
-.status-text-success {
-  color: #22c55e;
-}
-
-.status-text-processing {
-  color: #eab308;
-}
-
-.status-text-failed {
-  color: #ef4444;
-}
-
-.record-detail {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.record-right {
-  display: flex;
-  flex-direction: column;
-  align-items: flex-end;
-  gap: px2rpx(4);
-  margin-left: px2rpx(12);
-  flex-shrink: 0;
-}
-
-.amount-transaction {
-  font-size: px2rpx(18);
-  color: #111827;
-}
-
-.fee-text {
-  font-size: px2rpx(11);
-  color: #9ca3af;
-}
-
-.record-footer {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding-top: px2rpx(16);
-  border-top: 1px solid #f3f4f6;
-}
-
-.footer-actions {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-}
-
-.footer-time {
-  font-size: px2rpx(11);
-  color: #9ca3af;
-}
-
-.footer-actions {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(2);
-}
-
-.footer-order {
-  font-size: px2rpx(11);
-  color: #9ca3af;
-}
-
-.footer-detail {
-  font-size: px2rpx(11);
-  color: #2563eb;
-}
-</style>

+ 0 - 750
pages/recharge-record/detail.vue

@@ -1,750 +0,0 @@
-<template>
-  <cwg-page-wrapper>
-    <view class="order-detail-page">
-      <view class="content">
-        <view class="status-card section-card">
-          <view class="success-icon-wrapper">
-            <image v-if="orderDetail.orderStatus === 'success'" src="/static/images/vector.png" alt=""
-              mode="widthFix" />
-            <image v-else-if="orderDetail.orderStatus === 'failed'" src="/static/images/vector2.png" alt=""
-              mode="widthFix" />
-            <image v-else src="/static/images/vector3.png" alt="" mode="widthFix" />
-          </view>
-          <text class="status-title">{{ getOrderStatusText(orderDetail.orderStatus) }}</text>
-          <text v-if="approveDesc" class="success-text">{{ approveDesc }}</text>
-        </view>
-
-        <!-- Approval Progress -->
-        <!-- <view class="section-card">
-          <view class="section-header">
-            <uni-icons type="bars" size="18" color="#2563eb" />
-            <text class="section-title">{{ t('card.Status.t15') }}</text>
-          </view>
-
-          <view class="approval-timeline">
-            <view v-for="(step, index) in orderDetail.approvalSteps" :key="index" class="timeline-item">
-              <view class="timeline-left">
-                <view
-                  :class="['timeline-dot', step.status === 'completed' ? 'timeline-dot-active' : step.status === 'current' ? 'timeline-dot-current' : '']">
-                  <uni-icons v-if="step.status === 'completed'" type="checkmarkempty" size="14" color="#ffffff" />
-                </view>
-                <view v-if="index < orderDetail.approvalSteps.length - 1" class="timeline-line"></view>
-              </view>
-
-              <view class="timeline-right">
-                <view class="timeline-header">
-                  <text class="timeline-title">{{ step.title }}</text>
-                  <view v-if="step.status === 'completed'" class="timeline-status completed">
-                    <uni-icons type="checkmarkempty" size="12" color="#22c55e" />
-                    <text class="timeline-status-text">{{ t('State.Completed') }}</text>
-                  </view>
-                  <view v-else-if="step.status === 'current'" class="timeline-status current">
-                    <uni-icons type="info" size="12" color="#eab308" />
-                    <text class="timeline-status-text">{{ t('State.Ongoing') }}</text>
-                  </view>
-                  <view v-else class="timeline-status pending">
-                    <text class="timeline-status-text">{{ t('State.ToBeProcessed') }}</text>
-                  </view>
-                </view>
-                <text v-if="step.operator" class="timeline-operator">操作人: {{ step.operator }}</text>
-                <text v-if="step.time" class="timeline-time">{{ step.time }}</text>
-                <text v-if="step.remark" class="timeline-remark">{{ step.remark }}</text>
-              </view>
-            </view>
-          </view>
-        </view> -->
-
-        <!-- Amount Info -->
-        <view class="section-card">
-          <view class="section-header">
-            <uni-icons type="wallet" size="18" color="#2563eb" />
-            <text class="section-title">{{ t('card.Form.f55') }}</text>
-          </view>
-
-          <view class="info-list">
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f37') }}</text>
-              <text class="info-value amount-highlight">
-                {{ orderDetail.amount.toFixed(2) }} <text class="currency">{{ orderDetail.currency || 'USD' }}</text>
-              </text>
-            </view>
-
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f30') }}</text>
-              <text class="info-value">
-                {{ orderDetail.fee.toFixed(2) }} <text class="currency">{{ orderDetail.currency || 'USD' }}</text>
-              </text>
-            </view>
-
-            <!-- <view class="divider"></view>
-
-            <view class="info-row">
-              <text class="info-label total-label">{{ t('card.Form.f55') }}</text>
-              <text class="info-value total-value">
-                {{ orderDetail.actualAmount.toFixed(2) }} <text class="currency">{{ orderDetail.currency || 'USD'
-                  }}</text>
-              </text>
-            </view> -->
-          </view>
-        </view>
-
-        <!-- Order Info -->
-        <view class="section-card">
-          <view class="section-header">
-            <uni-icons type="list" size="18" color="#2563eb" />
-            <text class="section-title">{{ t('global.title3') }}</text>
-          </view>
-
-          <view class="info-list">
-            <view class="info-row" v-if="orderDetail.orderNo">
-              <text class="info-label">{{ t('card.Form.f35') }}</text>
-              <view class="info-value-wrapper">
-                <text class="info-value">{{ formatOrderNo(orderDetail.orderNo) }}</text>
-                <cwg-icon name="copy" :size="14" color="#9ca3af" @click.stop="copyOrderNo" />
-              </view>
-            </view>
-
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f42') }}</text>
-              <text class="info-value">{{ orderDetail.type || '-' }}</text>
-            </view>
-
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f33') }}</text>
-              <text class="info-value">{{ orderDetail.createTime }}</text>
-            </view>
-
-            <view class="info-row" v-if="orderDetail.completeTime">
-              <text class="info-label">{{ t('State.Complete') }}</text>
-              <text class="info-value">{{ orderDetail.completeTime || '-' }}</text>
-            </view>
-
-            <view v-if="orderDetail.merchant" class="info-row">
-              <text class="info-label">{{ t('card.Form.f41') }}</text>
-              <text class="info-value">{{ orderDetail.merchant }}</text>
-            </view>
-
-            <view v-if="orderDetail.bankCard" class="info-row">
-              <text class="info-label">{{ t('card.Form.f24') }}</text>
-              <text class="info-value">{{ orderDetail.bankCard }}</text>
-            </view>
-
-            <view v-if="orderDetail.remark" class="info-row vertical">
-              <text class="info-label">{{ t('card.Form.f27') }}</text>
-              <text class="info-value remark-text">{{ orderDetail.remark }}</text>
-            </view>
-          </view>
-        </view>
-      </view>
-    </view>
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { reactive, computed, ref } from 'vue';
-import { onLoad, onUnload } from '@dcloudio/uni-app';
-import { useI18n } from 'vue-i18n';
-import useCardStore from '@/stores/use-card-store';
-import useUserStore from '@/stores/use-user-store';
-import { ucardApi } from '@/api/ucard';
-type OrderStatus = 'success' | 'processing' | 'failed' | 'cancelled';
-type ApprovalStatus = 'completed' | 'current' | 'pending';
-
-interface ApprovalStep {
-  title: string;
-  status: ApprovalStatus;
-  operator?: string;
-  time?: string;
-  remark?: string;
-}
-
-interface OrderDetail {
-  category?: 'recharge' | 'transaction' | 'deduction';
-  orderNo: string;
-  type: string;
-  amount: number;
-  fee: number;
-  actualAmount: number;
-  currency?: string;
-  orderStatus: OrderStatus;
-  statusMessage: string;
-  createTime: string;
-  completeTime?: string;
-  merchant?: string;
-  bankCard?: string;
-  remark?: string;
-  approvalSteps: ApprovalStep[];
-}
-
-// 订单详情数据(默认占位,进入页面后会用缓存覆盖)
-const orderDetail = reactive<OrderDetail>({
-  category: 'recharge',
-  orderNo: '',
-  type: '',
-  amount: 0,
-  fee: 0,
-  actualAmount: 0,
-  currency: 'USD',
-  orderStatus: 'processing',
-  statusMessage: '',
-  createTime: '',
-  completeTime: '',
-  merchant: '',
-  bankCard: '',
-  remark: '',
-  approvalSteps: []
-});
-
-const { t, locale } = useI18n();
-const cardStore = useCardStore();
-const userStore = useUserStore();
-const approveDesc = ref('');
-const getApproveDesc = () => {
-  const d = orderDetail.approveDesc
-  if (!d) return
-  const c = userStore.reasonsOptions
-  const a = c[d || '']
-  const b = locale.value == 'cn' || locale.value == 'zhHant' ? a.content : a.enContent
-  if (!b) {
-    reasonsRefusalList()
-  }
-  approveDesc.value = b;
-}
-async function reasonsRefusalList() {
-  try {
-    const res = await ucardApi.reasonsRefusalList();
-    if (res.code === 200) {
-      pickFields(res.data);
-      getApproveDesc()
-    } else {
-      uni.$u.toast(res.msg || t("login.msg0"));
-    }
-  } catch (error) {
-    console.log(error, 111);
-  }
-}
-function pickFields(source, fields = ['content', 'enContent']) {
-  const result = {}
-  Object.entries(source).forEach(([key, value]) => {
-    result[key] = fields.reduce((acc, f) => {
-      acc[f] = value[f] ?? null
-      return acc
-    }, {})
-  })
-  userStore.saveReasonsOptions(result);
-}
-const formatOrderNo = (orderNo?: string) => {
-  if (!orderNo) return '--';
-  if (orderNo.length <= 20) return orderNo;
-  return orderNo.slice(0, 6) + '...' + orderNo.slice(-4);
-}
-// 获取订单状态颜色
-const getOrderStatusColor = (status: OrderStatus): string => {
-  switch (status) {
-    case 'success':
-      return '#22c55e';
-    case 'processing':
-      return '#eab308';
-    case 'failed':
-      return '#ef4444';
-    case 'cancelled':
-      return '#9ca3af';
-    default:
-      return '#9ca3af';
-  }
-};
-
-// 获取订单状态文本
-const getOrderStatusText = (status: OrderStatus): string => {
-  switch (status) {
-    case 'success':
-      return t('card.Status.t1'); // 成功
-    case 'processing':
-      return t('card.Status.t3'); // 处理中
-    case 'failed':
-      return t('card.Status.t2'); // 失败
-    case 'cancelled':
-      return t('card.Status.t5'); // 待处理 / 已取消,复用状态文案
-    default:
-      return t('card.Status.t5');
-  }
-};
-
-// 复制订单号
-const copyOrderNo = () => {
-  uni.setClipboardData({
-    data: orderDetail.orderNo,
-    success: () => {
-      uni.showToast({
-        title: t('card.Msg.m8') || '复制成功',
-        icon: 'success'
-      });
-    }
-  });
-};
-
-// 联系客服
-const contactService = () => {
-  uni.showToast({
-    title: '联系客服',
-    icon: 'none'
-  });
-};
-
-// 取消订单
-const cancelOrder = () => {
-  uni.showModal({
-    title: '确认取消',
-    content: '确定要取消此订单吗?',
-    success: (res) => {
-      if (res.confirm) {
-        uni.showToast({
-          title: '订单已取消',
-          icon: 'success'
-        });
-      }
-    }
-  });
-};
-
-// 申诉订单
-const appealOrder = () => {
-  uni.showToast({
-    title: '提交申诉',
-    icon: 'none'
-  });
-};
-
-// 删除订单
-const deleteOrder = () => {
-  uni.showModal({
-    title: '确认删除',
-    content: '确定要删除此订单吗?删除后无法恢复',
-    success: (res) => {
-      if (res.confirm) {
-        uni.showToast({
-          title: '订单已删除',
-          icon: 'success'
-        });
-      }
-    }
-  });
-};
-
-// 页面加载时,从 store 中读取订单详情
-onLoad(() => {
-  const cache = cardStore.orderDetail;
-  if (cache && typeof cache === 'object') {
-    Object.assign(orderDetail, cache);
-  } else {
-    uni.showToast({
-      title: '暂无订单数据',
-      icon: 'none'
-    });
-    setTimeout(() => {
-      uni.navigateBack();
-    }, 800);
-  }
-});
-
-// 离开页面时清空订单详情
-onUnload(() => {
-  cardStore.clearOrderDetail();
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page-wrapper {
-  padding: 0;
-}
-
-.order-detail-page {
-  background-color: #f9fafb;
-  padding-bottom: px2rpx(80);
-}
-
-/* Header */
-.header {
-  background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-  padding: px2rpx(12) px2rpx(16);
-  padding-top: calc(px2rpx(12) + env(safe-area-inset-top));
-}
-
-.header-nav {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-}
-
-.back-btn {
-  width: px2rpx(40);
-  height: px2rpx(40);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.header-title {
-  color: #ffffff;
-  font-size: px2rpx(18);
-}
-
-.header-action {
-  width: px2rpx(40);
-}
-
-/* Content */
-.content {
-  padding: px2rpx(16);
-}
-
-/* Status Card */
-.status-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(16);
-  padding: px2rpx(32) px2rpx(24);
-  margin-bottom: px2rpx(16);
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-}
-
-.status-icon-wrapper {
-  margin-bottom: px2rpx(16);
-}
-
-.status-icon {
-  width: px2rpx(80);
-  height: px2rpx(80);
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.status-icon-success {
-  background-color: #f0fdf4;
-}
-
-.status-icon-processing {
-  background-color: #fefce8;
-}
-
-.status-icon-failed {
-  background-color: #fef2f2;
-}
-
-.status-icon-cancelled {
-  background-color: #f9fafb;
-}
-
-.status-title {
-  font-size: px2rpx(22);
-  color: #111827;
-  margin-bottom: px2rpx(8);
-}
-
-.status-subtitle {
-  font-size: px2rpx(14);
-  color: #6b7280;
-  text-align: center;
-}
-
-/* Section Card */
-.section-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  padding: px2rpx(16);
-  margin-bottom: px2rpx(16);
-}
-
-.section-header {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  margin-bottom: px2rpx(16);
-}
-
-.section-title {
-  font-size: px2rpx(16);
-  color: #111827;
-}
-
-/* Approval Timeline */
-.approval-timeline {
-  display: flex;
-  flex-direction: column;
-}
-
-.timeline-item {
-  display: flex;
-  gap: px2rpx(12);
-}
-
-.timeline-left {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  flex-shrink: 0;
-}
-
-.timeline-dot {
-  width: px2rpx(24);
-  height: px2rpx(24);
-  border-radius: 50%;
-  background-color: #f3f4f6;
-  border: 2px solid #e5e7eb;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.timeline-dot-active {
-  background-color: #22c55e;
-  border-color: #22c55e;
-}
-
-.timeline-dot-current {
-  background-color: #eab308;
-  border-color: #eab308;
-  animation: pulse 2s infinite;
-}
-
-@keyframes pulse {
-
-  0%,
-  100% {
-    opacity: 1;
-  }
-
-  50% {
-    opacity: 0.7;
-  }
-}
-
-.timeline-line {
-  width: px2rpx(2);
-  flex: 1;
-  background-color: #e5e7eb;
-  margin: px2rpx(4) 0;
-}
-
-.timeline-right {
-  flex: 1;
-  padding-bottom: px2rpx(24);
-}
-
-.timeline-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: px2rpx(6);
-}
-
-.timeline-title {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-.timeline-status {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(4);
-  padding: px2rpx(2) px2rpx(8);
-  border-radius: px2rpx(12);
-}
-
-.timeline-status.completed {
-  background-color: #f0fdf4;
-}
-
-.timeline-status.current {
-  background-color: #fefce8;
-}
-
-.timeline-status.pending {
-  background-color: #f9fafb;
-}
-
-.timeline-status-text {
-  font-size: px2rpx(12);
-}
-
-.timeline-status.completed .timeline-status-text {
-  color: #22c55e;
-}
-
-.timeline-status.current .timeline-status-text {
-  color: #eab308;
-}
-
-.timeline-status.pending .timeline-status-text {
-  color: #9ca3af;
-}
-
-.timeline-operator {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  display: block;
-  margin-bottom: px2rpx(4);
-}
-
-.timeline-time {
-  font-size: px2rpx(12);
-  color: #9ca3af;
-  display: block;
-  margin-bottom: px2rpx(4);
-}
-
-.timeline-remark {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  display: block;
-  margin-top: px2rpx(6);
-  padding: px2rpx(8);
-  background-color: #f9fafb;
-  border-radius: px2rpx(6);
-}
-
-/* Info List */
-.info-list {
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(12);
-}
-
-.info-row {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  gap: px2rpx(12);
-}
-
-.info-row.vertical {
-  flex-direction: column;
-  align-items: flex-start;
-}
-
-.info-label {
-  font-size: px2rpx(14);
-  color: #6b7280;
-  flex-shrink: 0;
-}
-
-.info-value {
-  font-size: px2rpx(14);
-  color: #111827;
-  text-align: right;
-  word-break: break-all;
-}
-
-.info-value-wrapper {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  flex: 1;
-  justify-content: flex-end;
-}
-
-.amount-highlight {
-  font-size: px2rpx(20);
-  color: #2563eb;
-}
-
-.total-label {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-.total-value {
-  font-size: px2rpx(18);
-  color: #ef4444;
-}
-
-.remark-text {
-  text-align: left;
-  color: #6b7280;
-  line-height: 1.6;
-}
-
-.divider {
-  height: px2rpx(1);
-  background-color: #f3f4f6;
-  margin: px2rpx(4) 0;
-}
-
-/* Service Card */
-.service-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  padding: px2rpx(16);
-  display: flex;
-  align-items: center;
-  gap: px2rpx(12);
-  margin-bottom: px2rpx(16);
-}
-
-.service-text {
-  flex: 1;
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-/* Bottom Actions */
-.bottom-actions {
-  position: fixed;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  background-color: #ffffff;
-  border-top: 1px solid #e5e7eb;
-  padding: px2rpx(12) px2rpx(16);
-  padding-bottom: calc(px2rpx(12) + env(safe-area-inset-bottom));
-  display: flex;
-  gap: px2rpx(12);
-}
-
-.action-btn {
-  flex: 1;
-  height: px2rpx(44);
-  border-radius: px2rpx(8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.cancel-btn {
-  background-color: #f3f4f6;
-}
-
-.cancel-btn .btn-text {
-  color: #6b7280;
-}
-
-.appeal-btn {
-  background-color: #2563eb;
-}
-
-.appeal-btn .btn-text {
-  color: #ffffff;
-}
-
-.delete-btn {
-  background-color: #f3f4f6;
-}
-
-.delete-btn .btn-text {
-  color: #ef4444;
-}
-
-.btn-text {
-  font-size: px2rpx(15);
-}
-
-.currency {
-  font-size: px2rpx(12);
-}
-</style>

+ 0 - 313
pages/recharge-record/list.vue

@@ -1,313 +0,0 @@
-<template>
-  <cwg-page-wrapper :isHeaderFixed="true">
-    <view class="bank-transaction-page">
-      <cwg-header color="#000" :title="pageTitle" />
-      <!-- Tabs -->
-      <view class="tabs-container" :style="{ top: statusBarHeight + 60 + 'px' }">
-        <view :class="['tab-item', { 'tab-active': activeTab === 'recharge' }]" @click="activeTab = 'recharge'">
-          <cwg-icon class="icons" name="plus-filled" :size="18"
-            :color="activeTab === 'recharge' ? '#ea002a' : '#9ca3af'" />
-          <view :class="['tab-text', { 'tab-text-active': activeTab === 'recharge' }]">{{ t('card.Status.t18') }}</view>
-          <view v-if="activeTab === 'recharge'" class="tab-indicator" />
-        </view>
-
-        <view :class="['tab-item', { 'tab-active': activeTab === 'transaction' }]" @click="activeTab = 'transaction'">
-          <cwg-icon class="icons" name="list" :size="18" :color="activeTab === 'transaction' ? '#ea002a' : '#9ca3af'" />
-          <view :class="['tab-text', { 'tab-text-active': activeTab === 'transaction' }]">{{ t('Shop.Index.Transaction')
-            }}</view>
-          <view v-if="activeTab === 'transaction'" class="tab-indicator" />
-        </view>
-
-        <view :class="['tab-item', { 'tab-active': activeTab === 'deduction' }]" @click="activeTab = 'deduction'">
-          <cwg-icon class="icons" name="trending-down" :size="18"
-            :color="activeTab === 'deduction' ? '#ea002a' : '#9ca3af'" />
-          <view :class="['tab-text', { 'tab-text-active': activeTab === 'deduction' }]">{{ t('card.tab20') }}
-          </view>
-          <view v-if="activeTab === 'deduction'" class="tab-indicator" />
-        </view>
-      </view>
-      <view class="filters-scroll">
-        <view class="filters-container" :style="{ top: statusBarHeight + 113 + 'px' }">
-          <view class="filter-item">
-            <text class="filter-label">{{ t('card.Form.f52') }}</text>
-            <cwg-filter-select v-model="currentTypeIndex" :options="currentTypeOptions" />
-          </view>
-
-          <view class="filter-item" v-if="activeTab !== 'deduction'">
-            <text class="filter-label">{{ t('card.Form.f45') }}</text>
-            <cwg-filter-select v-model="statusFilterIndex" :options="statusOptions" />
-          </view>
-
-          <view class="filter-item">
-            <text class="filter-label">{{ t('card.Form.f51') }}</text>
-            <cwg-filter-picker v-model="dateFilter"
-              :returnType="activeTab == 'deduction' ? 'timestamp' : 'string'"></cwg-filter-picker>
-          </view>
-
-          <view class="reset-btn" @click="resetFilters">
-            <uni-icons type="loop" size="16" color="#ea002a" />
-          </view>
-        </view>
-      </view>
-
-      <!-- Content -->
-      <view class="content">
-        <!-- Recharge Records -->
-        <RechargeList v-if="activeTab === 'recharge'" ref="rechargeListRef" :cardNumber="cardNumber"
-          :typeIndex="currentTypeIndex" :statusIndex="statusFilterIndex" :dateFilter="dateFilter"
-          :typeOptions="currentTypeOptions" />
-
-        <!-- Transaction Records -->
-        <TransactionList v-if="activeTab === 'transaction'" ref="transactionListRef" :cardNumber="cardNumber"
-          :typeIndex="currentTypeIndex" :statusIndex="statusFilterIndex" :dateFilter="dateFilter"
-          :typeOptions="currentTypeOptions" />
-
-        <!-- Deduction Records -->
-        <DeductionList v-if="activeTab === 'deduction'" ref="deductionListRef" :cardNumber="cardNumber"
-          :typeIndex="currentTypeIndex" :statusIndex="statusFilterIndex" :dateFilter="dateFilter"
-          :typeOptions="currentTypeOptions" />
-      </view>
-    </view>
-  </cwg-page-wrapper>
-
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch } from 'vue';
-import { onLoad } from '@dcloudio/uni-app';
-import { useI18n } from 'vue-i18n';
-import useGlobalStore from '@/stores/use-global-store';
-import RechargeList from './components/RechargeList.vue';
-import TransactionList from './components/TransactionList.vue';
-import DeductionList from './components/DeductionList.vue';
-import { rechargeType, transactionTypeMap, WITHDRAW_TYPE_MAP, transactionStatusMap, rechargeStatusMap } from '@/utils/dataMap';
-const globalStore = useGlobalStore()
-const statusBarHeight = computed(() => globalStore.statusBarHeight);
-const { t } = useI18n();
-const activeTab = ref<'recharge' | 'transaction' | 'deduction'>('recharge');
-const cardNumber = ref('');
-onLoad((options) => {
-  cardNumber.value = options.cardNumber || '';
-});
-const currentTypeOptions = computed(() => {
-  if (activeTab.value === 'recharge') {
-    return rechargeType;
-  } else if (activeTab.value === 'transaction') {
-    return transactionTypeMap;
-  } else {
-    return WITHDRAW_TYPE_MAP;
-  }
-});
-const statusOptions = computed(() => {
-  if (activeTab.value === 'recharge') {
-    return rechargeStatusMap;
-  } else if (activeTab.value === 'transaction') {
-    return transactionStatusMap;
-  } else {
-    return [];
-  }
-});
-console.log(statusOptions, 1212);
-
-// const statusOptions = ['全部', '成功', '处理中', '失败'];
-const currentTypeIndex = ref(-1);
-const statusFilterIndex = ref(-1);
-const dateFilter = ref([]);
-const pageTitle = computed(() => {
-  if (activeTab.value === 'recharge') {
-    return t('card.tab7'); // 充值记录
-  } else if (activeTab.value === 'transaction') {
-    return t('card.tab2'); // 交易记录
-  } else {
-    return t('card.tab20'); // 扣款记录
-  }
-});
-
-const resetFilters = () => {
-  currentTypeIndex.value = -1;
-  statusFilterIndex.value = -1;
-  dateFilter.value = [];
-};
-
-
-
-// 监听 tab 切换,重置查询条件
-watch(activeTab, () => {
-  resetFilters();
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page-wrapper {
-  padding: 0;
-  border: 0;
-}
-
-.bank-transaction-page {
-  // background-color: #f9fafb;
-}
-
-.wallet-header {
-  background: #fff;
-  color: #000 !important;
-
-  .header {
-    color: #000 !important;
-  }
-}
-
-/* Header */
-.header {
-  background: linear-gradient(90deg, #ea002a 0%, #eb4e6b 100%);
-  padding: px2rpx(16);
-  padding-bottom: px2rpx(20);
-}
-
-.header-content {
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(16);
-}
-
-.header-title {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-}
-
-.title-text {
-  color: #ffffff;
-  font-size: px2rpx(20);
-}
-
-.stats-container {
-  display: flex;
-  gap: px2rpx(12);
-}
-
-.stat-card {
-  flex: 1;
-  background-color: rgba(255, 255, 255, 0.15);
-  backdrop-filter: blur(px2rpx(10));
-  border-radius: px2rpx(12);
-  padding: px2rpx(12);
-}
-
-.stat-header {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(6);
-  margin-bottom: px2rpx(8);
-}
-
-.icons {
-  width: px2rpx(20);
-  height: px2rpx(20);
-}
-
-.stat-label {
-  font-size: px2rpx(12);
-  color: rgba(255, 255, 255, 0.9);
-}
-
-.stat-value {
-  font-size: px2rpx(20);
-  color: #ffffff;
-  display: block;
-  margin-bottom: px2rpx(4);
-}
-
-.stat-count {
-  font-size: px2rpx(11);
-  color: rgba(255, 255, 255, 0.8);
-}
-
-/* Tabs */
-.tabs-container {
-  background-color: #ffffff;
-  display: flex;
-  border-bottom: 1px solid #e5e7eb;
-  position: sticky;
-  top: 0;
-  z-index: 10;
-}
-
-.tab-item {
-  flex: 1;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  gap: px2rpx(6);
-  padding: px2rpx(16);
-  position: relative;
-  transition: all 0.3s;
-}
-
-.tab-text {
-  font-size: px2rpx(15);
-  color: #9ca3af;
-  transition: color 0.3s;
-}
-
-.tab-text-active {
-  color: #ea002a;
-}
-
-.tab-indicator {
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  height: px2rpx(3);
-  background-color: #ea002a;
-  border-radius: px2rpx(3);
-}
-
-/* Content */
-.content {
-  padding: 0;
-}
-
-.filters-container {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  padding: px2rpx(12) px2rpx(6);
-  background-color: #ffffff;
-  position: sticky;
-  top: 0;
-  z-index: 10;
-  // overflow-x: auto;
-  // overflow-y: visible;
-  -webkit-overflow-scrolling: touch;
-}
-
-.filter-item {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(4);
-  flex-shrink: 0;
-  min-width: 0;
-}
-
-.filter-label {
-  font-size: px2rpx(12);
-  color: #6b7280;
-  white-space: nowrap;
-  flex-shrink: 0;
-}
-
-.reset-btn {
-  background-color: #ffffff;
-  border: 1px solid #e5e7eb;
-  border-radius: px2rpx(8);
-  padding: px2rpx(6) 0;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-  min-width: px2rpx(36);
-}
-</style>

+ 0 - 226
pages/wallet/balance.vue

@@ -1,226 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="page">
-            <view class="apply-card-footer">
-                <cwg-load-more-wrapper :loading="loading" :finished="finished" @reach-bottom="loadMore">
-                    <view v-if="cardList.length > 0">
-                        <view class="kyc-list">
-                            <view v-for="item in cardList" :key="item.id" class="kyc-item">
-                                <view class="g">
-                                    <view class="g-l">
-                                        <view class="g-item">
-                                            <view class="label a1 ellipsis">
-                                                <text> {{ t(walletBalanceTypeMap[item.type]) }}</text>
-                                            </view>
-                                            <view class="status" :class="statusClass1(item.status)">
-                                                <text v-if="item.status == '2'" v-t="'card.Status.t1'"></text>
-                                                <text v-else-if="item.status == '3'" v-t="'card.Status.t2'"></text>
-                                                <text v-else v-t="'card.Status.t3'"></text>
-                                            </view>
-                                        </view>
-                                        <view class="g-item g-item1">
-                                            <view v-t="'card.Form.f55'" class="label1 a2"></view>
-                                            <view class="label a1">{{ item.amount }} USD</view>
-                                        </view>
-                                        <view class="g-item g-item1">
-                                            <view v-t="'card.Form.f30'" class="label1 a2"></view>
-                                            <view class="label a1">{{ item.fee }} USD</view>
-                                        </view>
-                                        <view class="g-item">
-                                            <view class="label a3"></view>
-                                            <view class="label a3">{{ item.addTime }}</view>
-                                        </view>
-                                    </view>
-                                </view>
-                            </view>
-                        </view>
-                    </view>
-                    <cwg-empty-state v-if="cardList.length == 0" :title="t('empty-state.t1')"
-                        :text="t('empty-state.c1')" />
-                </cwg-load-more-wrapper>
-            </view>
-        </view>
-    </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, computed } from "vue";
-import { showToast } from "@/utils/toast";
-import { onLoad } from '@dcloudio/uni-app'
-import useRouter from "@/hooks/useRouter";
-import { useI18n } from "vue-i18n";
-import { ucardApi } from "@/api/ucard";
-import { walletBalanceTypeMap } from '@/utils/dataMap';
-const { t } = useI18n();
-const router = useRouter();
-onLoad((options) => {
-    // id.value = options.id
-    // type.value = options.type
-})
-const status: Record<string, string> = {
-    success: t('card.Status.t6'),
-    fail: t('card.Status.t7'),
-    processing: t('card.Status.t3'),
-    wait_process: t('card.Status.t3'),
-    cancel: t('card.New2.p3'),
-}
-function statusClass1(status: string) {
-    switch (status) {
-        case 2:
-            return 'status-default status-success'
-        case 3:
-            return 'status-default status-error'
-        default:
-            return 'status-default'
-    }
-}
-
-
-// 分页字段
-const page = ref(1)
-const pageSize = 10
-
-// 状态
-const loading = ref(false)
-const finished = ref(false)
-const loadingInit = ref(true) // 控制首次加载避免闪 empty
-
-const cardList = ref<CardInfo[]>([])
-const search = ref({})
-// 加载列表
-async function getCardList(isLoadMore = false) {
-    if (loading.value || finished.value) return
-    loading.value = true
-
-    try {
-        const res = await ucardApi.getRecordPage({
-            page: { current: page.value, row: pageSize }
-        })
-
-        const data = res.code === 200 ? res.data || [] : []
-
-        if (isLoadMore) {
-            cardList.value.push(...data)
-        } else {
-            cardList.value = data
-        }
-
-        // 判断是否还有更多
-        if (data.length < pageSize) {
-            finished.value = true
-        }
-    } catch (e) {
-        console.error(e)
-    } finally {
-        loading.value = false
-        loadingInit.value = false
-    }
-}
-
-// 父组件触底触发
-function loadMore() {
-    console.log(234234);
-
-    if (finished.value || loading.value) return
-    page.value++
-    getCardList(true)
-}
-
-onMounted(async () => {
-    getCardList()
-})
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.apply-card-footer {
-    width: 100%;
-}
-
-.kyc-item {
-    display: flex;
-    align-items: center;
-    flex-direction: column;
-    padding: px2rpx(12);
-    border-bottom: 1px solid var(--border, #333);
-    font-size: px2rpx(16);
-    background: var(--action-bg);
-    border-radius: px2rpx(16);
-    margin-bottom: px2rpx(16);
-    border: 1px solid rgba(214, 255, 0, 0.2);
-    box-shadow: 0 px2rpx(2) px2rpx(8) rgba(0, 0, 0, 0.08);
-    gap: px2rpx(16);
-}
-
-.kyc-item:last-child {
-    border-bottom: none;
-}
-
-.g {
-    width: 100%;
-
-    img {
-        width: px2rpx(56);
-        height: px2rpx(35);
-    }
-
-    .g-l {
-        width: 100%;
-        margin: 0;
-
-        .g-item {
-            margin-bottom: 0;
-        }
-
-        .g-item1 {
-            justify-content: start;
-            align-items: center;
-        }
-
-        .label {
-            font-family: 'Roboto';
-            font-style: normal;
-            font-weight: 600;
-            font-size: px2rpx(14);
-            line-height: px2rpx(20);
-            text-align: left;
-            color: #1a1a1a;
-            width: px2rpx(180);
-        }
-
-        .label1 {
-            font-family: 'Roboto';
-            font-style: normal;
-            font-weight: 600;
-            font-size: px2rpx(14);
-            line-height: px2rpx(20);
-            text-align: left;
-            color: #1a1a1a;
-            max-width: px2rpx(180);
-            padding-right: px2rpx(10);
-        }
-
-        .a2 {
-            color: #6b7280;
-            font-size: px2rpx(12);
-            line-height: px2rpx(16);
-        }
-
-        .a3 {
-            color: #8e8a8a;
-            font-family: Roboto;
-            font-size: px2rpx(14);
-            font-style: normal;
-            font-weight: 400;
-            line-height: px2rpx(36);
-            letter-spacing: px2rpx(0.07);
-            text-align: end;
-        }
-    }
-
-    /* .g-l1 {
-        margin-left: 0;
-    } */
-}
-</style>

+ 0 - 387
pages/wallet/components/DynamicForm.vue

@@ -1,387 +0,0 @@
-<template>
-  <view class="dynamic-form">
-    <u-form ref="formRef" :model="form" @submit="submitForm" :rules="rules">
-      <slot name="top"></slot>
-
-      <template v-if="step2">
-        <slot name="bottom"></slot>
-        <slot name="transferAmount"></slot>
-        <view v-for="(group, groupKey) in groupedFields" :key="groupKey">
-          <view class="form-group" v-if="type != 2">
-            <text class="form-label1">{{ getGroupTitle(groupKey) }}</text>
-          </view>
-          <view v-for="field in group" :key="field.fieldName" class="form-group">
-            <template v-if="!isNoList.includes(field.fieldName)">
-              <!-- 输入框 -->
-              <cwg-input :rulesKey="field.fieldName" :label="tFieldTitle(field)" :required="field.required"
-                :disabled="field.disabled || !!field.fixedValue" v-if="field.fieldType === 'input'"
-                v-model:value="form[field.fieldName]" :fkey="field.fieldName" type="text"
-                :placeholder="tDescription(field)" @change="clearFieldValidate(field)" />
-              <!-- 数字 -->
-              <cwg-input :rulesKey="field.fieldName" :label="tFieldTitle(field)" :required="field.required"
-                :disabled="field.disabled || !!field.fixedValue" v-else-if="field.fieldType === 'number'"
-                v-model:value="form[field.fieldName]" :fkey="field.fieldName" type="number"
-                :placeholder="tDescription(field)" />
-
-              <!-- 日期 -->
-              <cwg-input :rulesKey="field.fieldName" :label="tFieldTitle(field)" :required="field.required"
-                :disabled="field.disabled || !!field.fixedValue" v-else-if="field.fieldType === 'date'"
-                v-model:value="form[field.fieldName]" :fkey="field.fieldName" type="date"
-                :placeholder="tDescription(field)" @change="clearFieldValidate(field)" />
-              <!-- 下拉选择 -->
-              <cwg-input :rulesKey="field.fieldName" :label="tFieldTitle(field)" :required="field.required"
-                :disabled="false" v-else-if="field.fieldType === 'select'" v-model:value="form[field.fieldName]"
-                v-model:selectedValueDoc="form[field.fieldName + 'Value']" :fkey="field.fieldName" type="select"
-                :columns="field.availableDtos.map(i => ({ text: i.value, value: i.valueId }))"
-                :placeholder="tDescription(field)" @change="clearFieldValidate(field)" @change1="change11()" />
-              <!-- 文件上传 -->
-              <template v-else-if="field.fieldType === 'file'">
-                <cwg-input :rulesKey="field.fieldName" :label="tFieldTitle(field)" :required="field.required"
-                  :disabled="field.disabled || !!field.fixedValue" v-model:value="form[field.fieldName]"
-                  :fkey="field.fieldName" type="upload" :accept="'.jpg,.jpeg,.png,.pdf'" :is-upload-d="true"
-                  @change="onFileChange(field, $event)">
-                  <view class="cwg-upload">
-                    <u-icon name="folder" />
-                    <text class="name">{{ tFieldDescription(field) }}</text>
-                    <text class="back">{{ t('card.New1.d4') }}</text>
-                  </view>
-                </cwg-input>
-
-                <view>
-                  <text class="pdf-link" v-if="form[field.fieldName] && isPdf(form[field.fieldName])"
-                    @tap="previewFile(form[field.fieldName + 'Value']?.[0]?.url)">
-                    {{ getFileName(form[field.fieldName]) }}
-                  </text>
-                </view>
-              </template>
-
-              <!-- 未支持 -->
-              <view v-else>
-                未支持类型:{{ field.fieldType }}
-              </view>
-
-            </template>
-          </view>
-        </view>
-      </template>
-
-
-      <slot name="tips"></slot>
-      <slot v-if="step2" name="submit"></slot>
-    </u-form>
-  </view>
-</template>
-
-<script setup>
-import { reactive, ref, computed, watch, nextTick, onMounted } from "vue";
-import dayjs from "dayjs";
-import { showToast } from "@/utils/toast";
-import { useI18n } from "vue-i18n";
-import { uploadApi } from "@/api/upload";
-import Config from "@/config";
-const { Host00 } = Config;
-const isNoList = ['payoutMethod', 'transferType', 'payoutCurrency', 'transferAmount', 'senderAddress', 'senderDateOfBirth', 'senderCity', 'senderNationality', 'senderGender']
-
-// props
-const props = defineProps({
-  fields: Array,
-  globalForm: Object,
-  step2: Boolean,
-  type: String
-});
-
-// emit
-const emit = defineEmits(["submit", "validate"]);
-const formRef = ref();
-
-// i18n
-const { t } = useI18n();
-
-const getGroupTitle = (type) => {
-  const map = {
-    common: "global.GlobalOrder.common",
-    receiver: "global.GlobalOrder.receiver",
-    sender: "global.GlobalOrder.sender",
-    other: "global.GlobalOrder.other",
-  };
-  return t(map[type] || type);
-}
-
-// -----------------------------------------------------
-// 1️⃣ form 本地 copy(解决父组件传值无回显)
-// -----------------------------------------------------
-const form = ref({ ...props.globalForm });
-watch(
-  () => props.globalForm,
-  (val) => {
-    Object.keys(val).forEach(key => {
-      form.value[key] = val[key]
-      if (typeof val[key] === 'string' && val[key].startsWith('/wasabi')) {
-        form.value[key + 'Value'] = [{ url: Host00 + val[key] }]
-      }
-    })
-  },
-  { deep: true, immediate: true }
-)
-
-// 子组件更新 → 同步到父组件
-watch(
-  form,
-  (val) => {
-    Object.assign(props.globalForm, val);
-  },
-  { deep: true, immediate: true }
-);
-
-// -----------------------------------------------------
-// 校验规则
-// -----------------------------------------------------
-const rules = ref({});
-// -----------------------------------------------------
-// 多语言
-// -----------------------------------------------------
-const tFieldTitle = (f) =>
-  t(`global.fieldName.${f.fieldName}.fieldTitle`) || f.fieldTitle;
-
-const tFieldDescription = (f) =>
-  t(`global.fieldName.${f.fieldName}.fieldDescription`) || f.fieldDescription;
-
-const tDescription = (f) =>
-  t(`global.fieldName.${f.fieldName}.fieldDescription`) || f.fieldDescription;
-// -----------------------------------------------------
-// 校验
-// -----------------------------------------------------
-const getRules = (field) => {
-  const fieldRules = [];
-
-  if (field.required) {
-    fieldRules.push({
-      required: true,
-      message: tFieldTitle(field) + t("global.GlobalOrder.RulesRequire"),
-      trigger: ['blur', 'change']
-    });
-  }
-
-  if (field.regex) {
-    try {
-      fieldRules.push({
-        pattern: new RegExp(field.regex),
-        message: tFieldTitle(field) + t("global.GlobalOrder.RulesReg"),
-        trigger: ['blur', 'change']
-      });
-    } catch (e) {
-      console.warn('正则表达式解析失败:', field.regex, e);
-    }
-  }
-
-  return fieldRules;
-};
-// -----------------------------------------------------
-// 字段初始化回显 (相当于Vue2中的watch fields)
-// -----------------------------------------------------
-watch(
-  () => props.fields,
-  (newFields) => {
-    if (!newFields || !Array.isArray(newFields)) return;
-    console.log('newFields', newFields);
-
-    const newRules = {};
-    newFields.forEach((field) => {
-      // 有 fixedValue 时回显
-      if (field.fieldType == 'file') {
-        props.globalForm[field.fieldName] = field.rfiValueUrl;
-      } else if (field.fieldType == 'select') {
-        // props.globalForm[field.fieldName] = field.rfiValue;
-      } else if (field.fixedValue !== undefined && field.fixedValue !== null) {
-        props.globalForm[field.fieldName] = field.fixedValue;
-      } else if (field.rfiValue !== undefined && field.rfiValue !== null) {
-        props.globalForm[field.fieldName] = field.rfiValue;
-      } else if (!(field.fieldName in props.globalForm)) {
-        // 没有则初始化为空
-        props.globalForm[field.fieldName] = undefined;
-      }
-
-      // 设置校验规则
-      newRules[field.fieldName] = getRules(field);
-    });
-
-    // 更新规则对象
-    rules.value = newRules;
-
-    nextTick(() => {
-      if (formRef.value && formRef.value.clearValidate) {
-        formRef.value.clearValidate();
-      }
-    });
-  },
-  { immediate: true, deep: true }
-);
-
-
-
-// -----------------------------------------------------
-// 分组排序
-// -----------------------------------------------------
-const order = { common: 1, sender: 2, receiver: 3 };
-const groupedFields = computed(() => {
-  // 先排序
-  const sorted = props.fields
-    .slice()
-    .sort((a, b) => {
-      const o1 = order[a.customerType] || 99;
-      const o2 = order[b.customerType] || 99;
-      if (o1 !== o2) return o1 - o2;
-      return (a.sorting || 0) - (b.sorting || 0);
-    });
-
-  // 分组
-  const groupsMap = {};
-  sorted.forEach((f) => {
-    const key = f.fieldUserType || f.customerType || "other";
-    if (!groupsMap[key]) groupsMap[key] = [];
-    groupsMap[key].push(f);
-  });
-
-  // 按固定顺序生成最终 groups
-  const groupOrder = ['common', "sender", "receiver"];
-  const groups = {};
-  groupOrder.forEach((key) => {
-    if (groupsMap[key]) {
-      groups[key] = groupsMap[key];
-    }
-  });
-  return groups;
-});
-
-
-
-const clearFieldValidate = (field) => {
-  nextTick(() => {
-    if (formRef.value && formRef.value.validateField) {
-      formRef.value.validateField(field.fieldName);
-    }
-  });
-};
-const change11 = (e) => {
-  return
-
-  nextTick(() => {
-    if (formRef.value && formRef.value.validateField) {
-      formRef.value.validateField(field.fieldName);
-    }
-  });
-};
-
-
-// 表单验证方法
-const validateForm = async () => {
-  try {
-    if (formRef.value && formRef.value.validate) {
-      await formRef.value.validate();
-      return true;
-    }
-    return false;
-  } catch (error) {
-    console.error('表单验证失败:', error[0].message);
-    showToast(error[0].message);
-    return false;
-  }
-};
-
-// -----------------------------------------------------
-// 文件上传处理
-// -----------------------------------------------------
-const isPdf = (url) => url?.toLowerCase().endsWith(".pdf");
-const getFileName = (url) => url.split("/").pop();
-
-const previewFile = (url) => {
-  // 在新窗口中打开文件预览
-  window.open(url, '_blank');
-};
-
-const onFileChange = (field, event) => {
-  const fname = field.fieldName;
-  form.value[fname] = event.value;
-
-  // 如果是文件URL,构建预览数据
-  if (event.value && (event.value.includes('.pdf') || event.value.includes('.jpg') ||
-    event.value.includes('.jpeg') || event.value.includes('.png'))) {
-    form.value[fname + 'Value'] = [{ url: Host00 + event.value }];
-  }
-
-  clearFieldValidate(field);
-};
-
-// -----------------------------------------------------
-// 提交
-// -----------------------------------------------------
-const submitForm = () => emit("submit", form);
-
-// 暴露方法给父组件
-defineExpose({
-  formRef,
-  validateForm
-});
-
-// 兼容微信小程序的规则设置
-onMounted(() => {
-  // 如果需要兼容微信小程序,并且校验规则中含有方法等,只能通过setRules方法设置规则。
-  if (formRef.value && typeof formRef.value.setRules === 'function') {
-    nextTick(() => {
-      formRef.value.setRules(rules.value);
-    });
-  }
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.u-form-item__body {
-  padding: 0;
-}
-
-.form-group-title {
-  font-weight: bold;
-  margin: px2rpx(10) 0;
-  display: flex;
-  align-items: center;
-}
-
-.upload-wrapper {
-  margin: px2rpx(10) 0;
-}
-
-.preview-img {
-  width: px2rpx(130);
-  border-radius: px2rpx(6);
-  margin-top: px2rpx(6);
-}
-
-.pdf-link {
-  display: inline-block;
-  margin-top: px2rpx(6);
-  color: #1989fa;
-  text-decoration: underline;
-}
-
-.form-label1 {
-  display: block;
-  font-size: px2rpx(24);
-  font-weight: 500;
-  margin: px2rpx(24) 0;
-  padding-left: px2rpx(12);
-  position: relative;
-
-  &::before {
-    content: '';
-    display: block;
-    width: px2rpx(4);
-    height: px2rpx(24);
-    background-color: #ea002a;
-    position: absolute;
-    top: 0;
-    left: 0;
-  }
-}
-</style>

+ 0 - 499
pages/wallet/components/GlobalList.vue

@@ -1,499 +0,0 @@
-<template>
-    <cwg-load-more-wrapper ref="loadMoreWrapperRef" :loading="loading" :finished="finished" :height='54'
-        :refresher-enabled="true" @reach-bottom="loadMore" @refresh="handleRefresh">
-        <view v-if="records.length > 0" class="records-list">
-            <view v-for="record in records" :key="record.id" class="record-card" @click="goToDeductionDetail(record)">
-                <view class="record-main">
-                    <view class="record-left">
-                        <view class="type-icon deduction-icon">
-                            <cwg-icon class="icons" :name="getDeductionIcon(record.type || record.typeStr)" :size="20"
-                                color="#ef4444" />
-                        </view>
-                    </view>
-
-                    <view class="record-right">
-                        <view class="record-info">
-                            <view class="info-header">
-                                <text class="record-type">{{ Math.abs(Number(record.deductionAmount ||
-                                    0)).toFixed(2) }}
-                                    {{
-                                        record.sendCurrency
-                                        || 'USD' }}</text>
-                                <text class="record-detail"><cwg-icon name="icon_transfer" :size="18"
-                                        color="#000" /></text>
-                                <text class="record-type">{{ Math.abs(Number(record.transferAmount || 0)).toFixed(2) }}
-                                    {{
-                                        record.payoutCurrency
-                                        || 'USD' }}</text>
-
-                                <view :class="['status-badge', getStatusBadgeClass(record.status)]">
-                                    <cwg-icon class="icons" :name="getStatusIcon(record.status)" :size="12"
-                                        :color="getStatusColor(record.status)" />
-                                    <text :class="['status-text', getStatusTextClass(record.status)]">
-                                        {{ getStatusText(record.status) }}
-                                    </text>
-                                </view>
-                            </view>
-                        </view>
-                        <view class="row">
-                            <view class="l"><text class="record-detail" v-if="record.deductionAccountType == 1">{{
-                                record.cardNumber ||
-                                '--' }}</text>
-                                <text class="record-detail" v-if="record.deductionAccountType == 2">{{
-                                    t('global.GlobalOrder.bagBal') }}</text>
-                            </view>
-
-                            <view class="r">
-
-                                <text class="fee-text">{{ t('card.Form.f30') }} {{ Number(record.deductionFee ||
-                                    0).toFixed(2)
-                                }} {{
-                                        record.sendCurrency
-                                        || 'USD' }}</text>
-                            </view>
-                        </view>
-
-                    </view>
-                </view>
-
-                <view class="record-footer">
-                    <text class="footer-time">{{ formatDateTime(record.addTime || record.time) }}</text>
-                    <view class="footer-actions">
-                        <text class="footer-order">
-                            {{ t('card.Form.f35') }}: {{ formatOrderNo(record.merchantOrderNo) }}
-                        </text>
-                        <cwg-icon class="footer-order-icon" name="copy" :size="14" color="#9ca3af"
-                            @click.stop="copyOrderNo(record.merchantOrderNo)" />
-                    </view>
-                </view>
-            </view>
-        </view>
-        <cwg-empty-state v-else />
-    </cwg-load-more-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch, onMounted } from 'vue';
-import dayjs from 'dayjs';
-import { useI18n } from 'vue-i18n';
-import { showToast } from '@/utils/toast';
-import { ucardApi, TransactionInfo } from '@/api/ucard';
-import useRouter from "@/hooks/useRouter";
-const router = useRouter();
-import { globalStatusText } from '@/utils/dataMap';
-import useCardStore from '@/stores/use-card-store';
-
-interface RecordItem extends TransactionInfo {
-    type?: string | number;
-    typeStr?: string;
-    remark?: string;
-    status?: string | number;
-    addTime?: string | number;
-    fee?: number;
-    currency?: string;
-    merchantOrderNo?: string;
-    reason?: string;
-    time?: string | number;
-}
-
-type NormalizedStatus = 'success' | 'wait_process' | 'fail';
-
-const props = defineProps<{
-    cardNumber: string;
-    typeIndex: number;
-    statusIndex: number;
-    dateFilter: string;
-    typeOptions: string[];
-    payoutCurrency: string;
-}>();
-
-const { t } = useI18n();
-
-const records = ref<RecordItem[]>([]);
-const page = ref(1);
-const pageSize = 10;
-const loading = ref(false);
-const finished = ref(false);
-
-const cardStore = useCardStore();
-const normalizeStatus = (status?: string | number): NormalizedStatus => {
-    if (!status) return 'wait_process';
-    if (status === 'processing' || status === 'wait_process' || status === 'partner_processing') return 'wait_process';
-    if (status === 'fail' || status === 'cancel') return 'fail';
-    if (status === 'succeed' || status === 'success') return 'success';
-    return 'success';
-};
-
-const getStatusText = (status?: string | number): string => {
-    return t(globalStatusText[status]);
-};
-
-const getStatusIcon = (status?: string | number): string => {
-    const normalized = normalizeStatus(status);
-    if (normalized === 'success') return 'checkmarkempty1';
-    if (normalized === 'wait_process') return 'info1';
-    return 'closeempty1';
-};
-
-const getStatusColor = (status?: string | number): string => {
-    const normalized = normalizeStatus(status);
-    if (normalized === 'success') return '#22c55e';
-    if (normalized === 'wait_process') return '#eab308';
-    return '#ef4444';
-};
-
-const getStatusBadgeClass = (status?: string | number) => `status-${normalizeStatus(status)}`;
-const getStatusTextClass = (status?: string | number) => `status-text-${normalizeStatus(status)}`;
-
-const getStatusValue = (index: number): NormalizedStatus | null => {
-    if (index === 0) return null;
-    const statusMap: NormalizedStatus[] = ['success', 'wait_process', 'fail'];
-    return statusMap[index - 1];
-};
-
-const getDeductionIcon = (type?: string | number): string => {
-    const typeStr = String(type || '');
-    if (typeStr.includes('服务费') || typeStr === '1') return 'servicefee';
-    if (typeStr.includes('手续费') || typeStr === '2') return 'handlingfee';
-    return 'handlingfee';
-};
-
-const formatDateTime = (time?: string | number): string => {
-    if (!time) return '--';
-    try {
-        let date: dayjs.Dayjs;
-        if (typeof time === 'number') {
-            if (time.toString().length === 10) {
-                date = dayjs.unix(time);
-            } else {
-                date = dayjs(time);
-            }
-        } else {
-            date = dayjs(time);
-        }
-        if (!date.isValid()) return '--';
-        return date.format('YYYY-MM-DD HH:mm:ss');
-    } catch (error) {
-        return '--';
-    }
-};
-
-const getDatePart = (time?: string | number): string => {
-    if (!time) return '';
-    try {
-        let date: dayjs.Dayjs;
-        if (typeof time === 'number') {
-            if (time.toString().length === 10) {
-                date = dayjs.unix(time);
-            } else {
-                date = dayjs(time);
-            }
-        } else {
-            date = dayjs(time);
-        }
-        if (!date.isValid()) return '';
-        return date.format('YYYY-MM-DD');
-    } catch (error) {
-        return '';
-    }
-};
-
-const formatOrderNo = (orderNo?: string) => {
-    if (!orderNo) return '--';
-    if (orderNo.length <= 20) return orderNo;
-    return orderNo.slice(0, 6) + '...' + orderNo.slice(-4);
-};
-
-const copyOrderNo = (orderNo?: string) => {
-    if (!orderNo) return;
-    uni.setClipboardData({
-        data: orderNo,
-        success: () => {
-            uni.showToast({
-                title: t('card.Msg.m8') || '复制成功',
-                icon: 'success'
-            });
-        }
-    });
-};
-
-const fetchRecords = async (isLoadMore = false) => {
-    if (isLoadMore && finished.value) return;
-    loading.value = true;
-    try {
-        const res = await ucardApi.globalOrdersList({
-            cardNumber: props.cardNumber,
-            payoutCurrency: props.payoutCurrency === -1 ? undefined : props.payoutCurrency,
-            status: props.statusIndex === -1 ? undefined : props.statusIndex,
-            startDate: props.dateFilter?.[0] ? dayjs(props.dateFilter[0]).format('YYYY-MM-DD') : undefined,
-            endDate: props.dateFilter?.[1] ? dayjs(props.dateFilter[1]).format('YYYY-MM-DD') : undefined,
-            page: { current: page.value, row: pageSize },
-        });
-        const data = res.code === 200 && Array.isArray(res.data) ? res.data : [];
-
-        if (isLoadMore) {
-            records.value.push(...data);
-        } else {
-            records.value = data;
-        }
-
-        if (data.length < pageSize) {
-            finished.value = true;
-        } else {
-            finished.value = false;
-        }
-    } catch (error: any) {
-        if (!isLoadMore) {
-            records.value = [];
-        }
-        showToast(error?.message || String(error));
-    } finally {
-        loading.value = false;
-    }
-};
-
-const goToDeductionDetail = (record: RecordItem) => {
-    cardStore.saveOrderDetail(record);
-    router.push({
-        path: '/pages/wallet/global-detail',
-        query: { id: record.id }
-    });
-};
-
-const loadMore = () => {
-    if (finished.value || loading.value) return;
-    page.value++;
-    fetchRecords(true);
-};
-
-watch([() => props.dateFilter], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-watch([() => props.payoutCurrency], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-watch([() => props.statusIndex], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-
-const loadMoreWrapperRef = ref<any>(null);
-
-const refresh = async () => {
-    page.value = 1;
-    finished.value = false;
-    await fetchRecords();
-};
-
-const handleRefresh = async () => {
-    await refresh();
-    // 停止下拉刷新动画
-    if (loadMoreWrapperRef.value) {
-        loadMoreWrapperRef.value.stopRefresh();
-    }
-};
-
-onMounted(() => {
-    fetchRecords();
-});
-
-defineExpose({
-    refresh
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.records-list {
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(12);
-    padding: px2rpx(16);
-}
-
-.record-card {
-    background-color: #ffffff;
-    border-radius: px2rpx(12);
-    border: 1px solid #e5e7eb;
-    overflow: hidden;
-    transition: box-shadow 0.3s;
-    padding: px2rpx(16);
-    position: relative;
-}
-
-.record-card:active {
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-}
-
-.record-main {
-    display: flex;
-    align-items: flex-start;
-    justify-content: space-between;
-    padding-bottom: px2rpx(16);
-}
-
-.record-left {
-    display: flex;
-    align-items: flex-start;
-    gap: px2rpx(12);
-    min-width: 0;
-    margin-top: px2rpx(8);
-}
-
-.type-icon {
-    width: px2rpx(40);
-    height: px2rpx(40);
-    border-radius: px2rpx(10);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-shrink: 0;
-}
-
-.deduction-icon {
-    background-color: #fef2f2;
-}
-
-.icons {
-    width: px2rpx(20);
-    height: px2rpx(20);
-}
-
-.record-info {
-    flex: 1;
-    min-width: 0;
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(6);
-}
-
-.info-header {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    flex-wrap: wrap;
-}
-
-.record-type {
-    font-size: px2rpx(15);
-    color: #111827;
-}
-
-.status-badge {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    padding: px2rpx(3) px2rpx(8) px2rpx(3) px2rpx(3);
-    border-radius: px2rpx(12);
-    position: absolute;
-    top: px2rpx(1);
-    right: px2rpx(1);
-}
-
-.status-success {
-    background-color: #f0fdf4;
-}
-
-.status-wait_process {
-    background-color: #fefce8;
-}
-
-.status-fail {
-    background-color: #fef2f2;
-}
-
-.status-text {
-    font-size: px2rpx(11);
-}
-
-.status-text-success {
-    color: #22c55e;
-}
-
-.status-text-wait_process {
-    color: #eab308;
-}
-
-.status-text-fail {
-    color: #ef4444;
-}
-
-.record-detail {
-    font-size: px2rpx(13);
-    color: #6b7280;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.record-right {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    align-items: flex-start;
-    gap: px2rpx(4);
-    margin: px2rpx(8) 0 0 px2rpx(12);
-    flex-shrink: 0;
-
-    .row {
-        width: 100%;
-        display: flex;
-        align-items: center;
-        justify-content: space-around;
-
-    }
-
-    .l {
-        flex: 1;
-    }
-
-    .r {
-        display: flex;
-        flex-direction: column;
-        align-items: flex-start;
-        gap: px2rpx(4);
-        margin-left: px2rpx(12);
-        flex-shrink: 0;
-    }
-}
-
-.amount-deduction {
-    font-size: px2rpx(18);
-    color: #ef4444;
-}
-
-.fee-text {
-    font-size: px2rpx(11);
-    color: #9ca3af;
-}
-
-.record-footer {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    padding-top: px2rpx(16);
-    border-top: 1px solid #f3f4f6;
-}
-
-.footer-time {
-    font-size: px2rpx(11);
-    color: #9ca3af;
-}
-
-.footer-actions {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(2);
-}
-
-.footer-detail {
-    font-size: px2rpx(11);
-    color: #2563eb;
-}
-</style>

+ 0 - 482
pages/wallet/components/VaultodyList.vue

@@ -1,482 +0,0 @@
-<template>
-    <cwg-load-more-wrapper ref="loadMoreWrapperRef" :loading="loading" :finished="finished" :height='54'
-        :refresher-enabled="true" @reach-bottom="loadMore" @refresh="handleRefresh">
-        <view v-if="records.length > 0" class="records-list">
-            <view v-for="record in records" :key="record.id" class="record-card">
-                <view class="record-main">
-                    <view class="record-left">
-                        <view class="type-icon deduction-icon">
-                            <cwg-icon class="icons" :name="getDeductionIcon(record.type || record.typeStr)" :size="20"
-                                color="#ef4444" />
-                        </view>
-                    </view>
-
-                    <view class="record-right">
-                        <view class="record-info">
-                            <view class="info-header">
-                                <text class="record-type">{{ Math.abs(Number(record.receivedAmount ||
-                                    0)) }}
-                                    {{
-                                        record.receivedCurrency
-                                        || 'USD' }}</text>
-                                <text class="record-detail"><cwg-icon name="icon_transfer" :size="18"
-                                        color="#000" /></text>
-                                <text class="record-type">{{ Math.abs(Number(record.amount || 0)).toFixed(2) }}
-                                    {{
-                                        record.currency
-                                        || 'USDT' }}</text>
-
-                                <view :class="['status-badge', getStatusBadgeClass(record.status)]">
-                                    <cwg-icon class="icons" :name="getStatusIcon(record.status)" :size="12"
-                                        :color="getStatusColor(record.status)" />
-                                    <text :class="['status-text', getStatusTextClass(record.status)]">
-                                        {{ getStatusText(record.status) }}
-                                    </text>
-                                </view>
-                            </view>
-                        </view>
-                    </view>
-                </view>
-
-                <view class="record-footer">
-                    <text class="footer-time">{{ formatDateTime(record.addTime || record.time) }}</text>
-                    <view class="footer-actions">
-                        <text class="footer-order">
-                            {{ t('DepositAddress.p2') }}: {{ formatOrderNo(record.address) }}
-                        </text>
-                        <cwg-icon class="footer-order-icon" name="copy" :size="14" color="#9ca3af"
-                            @click.stop="copyOrderNo(record.address)" />
-                    </view>
-                </view>
-            </view>
-        </view>
-        <cwg-empty-state v-else />
-    </cwg-load-more-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch, onMounted } from 'vue';
-import dayjs from 'dayjs';
-import { useI18n } from 'vue-i18n';
-import { showToast } from '@/utils/toast';
-import { ucardApi, TransactionInfo } from '@/api/ucard';
-import useRouter from "@/hooks/useRouter";
-const router = useRouter();
-import { vaultodyStatusText } from '@/utils/dataMap';
-import useCardStore from '@/stores/use-card-store';
-
-interface RecordItem extends TransactionInfo {
-    type?: string | number;
-    typeStr?: string;
-    remark?: string;
-    status?: string | number;
-    addTime?: string | number;
-    fee?: number;
-    currency?: string;
-    merchantOrderNo?: string;
-    reason?: string;
-    time?: string | number;
-}
-
-type NormalizedStatus = 'success' | 'wait_process' | 'fail';
-
-const props = defineProps<{
-    cardNumber: string;
-    typeIndex: number;
-    statusIndex: number;
-    dateFilter: string;
-    typeOptions: string[];
-    payoutCurrency: string;
-}>();
-
-const { t } = useI18n();
-
-const records = ref<RecordItem[]>([]);
-const page = ref(1);
-const pageSize = 10;
-const loading = ref(false);
-const finished = ref(false);
-
-const cardStore = useCardStore();
-const normalizeStatus = (status?: string | number): NormalizedStatus => {
-    if (status == 2) return 'fail';
-    if (status == '1') return 'success';
-    return 'success';
-};
-
-const getStatusText = (status?: string | number): string => {
-    return t(vaultodyStatusText[status]);
-};
-
-const getStatusIcon = (status?: string | number): string => {
-    const normalized = normalizeStatus(status);
-    if (normalized === 'success') return 'checkmarkempty1';
-    if (normalized === 'wait_process') return 'info1';
-    return 'closeempty1';
-};
-
-const getStatusColor = (status?: string | number): string => {
-    const normalized = normalizeStatus(status);
-    if (normalized === 'success') return '#22c55e';
-    if (normalized === 'wait_process') return '#eab308';
-    return '#ef4444';
-};
-
-const getStatusBadgeClass = (status?: string | number) => `status-${normalizeStatus(status)}`;
-const getStatusTextClass = (status?: string | number) => `status-text-${normalizeStatus(status)}`;
-
-const getStatusValue = (index: number): NormalizedStatus | null => {
-    if (index === 0) return null;
-    const statusMap: NormalizedStatus[] = ['success', 'wait_process', 'fail'];
-    return statusMap[index - 1];
-};
-
-const getDeductionIcon = (type?: string | number): string => {
-    const typeStr = String(type || '');
-    if (typeStr.includes('服务费') || typeStr === '1') return 'servicefee';
-    if (typeStr.includes('手续费') || typeStr === '2') return 'handlingfee';
-    return 'handlingfee';
-};
-
-const formatDateTime = (time?: string | number): string => {
-    if (!time) return '--';
-    try {
-        let date: dayjs.Dayjs;
-        if (typeof time === 'number') {
-            if (time.toString().length === 10) {
-                date = dayjs.unix(time);
-            } else {
-                date = dayjs(time);
-            }
-        } else {
-            date = dayjs(time);
-        }
-        if (!date.isValid()) return '--';
-        return date.format('YYYY-MM-DD HH:mm:ss');
-    } catch (error) {
-        return '--';
-    }
-};
-
-const getDatePart = (time?: string | number): string => {
-    if (!time) return '';
-    try {
-        let date: dayjs.Dayjs;
-        if (typeof time === 'number') {
-            if (time.toString().length === 10) {
-                date = dayjs.unix(time);
-            } else {
-                date = dayjs(time);
-            }
-        } else {
-            date = dayjs(time);
-        }
-        if (!date.isValid()) return '';
-        return date.format('YYYY-MM-DD');
-    } catch (error) {
-        return '';
-    }
-};
-
-const formatOrderNo = (orderNo?: string) => {
-    if (!orderNo) return '--';
-    if (orderNo.length <= 20) return orderNo;
-    return orderNo.slice(0, 6) + '...' + orderNo.slice(-4);
-};
-
-const copyOrderNo = (orderNo?: string) => {
-    if (!orderNo) return;
-    uni.setClipboardData({
-        data: orderNo,
-        success: () => {
-            uni.showToast({
-                title: t('card.Msg.m8') || '复制成功',
-                icon: 'success'
-            });
-        }
-    });
-};
-
-const fetchRecords = async (isLoadMore = false) => {
-    if (isLoadMore && finished.value) return;
-    loading.value = true;
-    try {
-        const res = await ucardApi.getBlockchainTransactionPage({
-            cardNumber: props.cardNumber,
-            payoutCurrency: props.payoutCurrency,
-            status: props.statusIndex == -1 ? undefined : props.statusIndex,
-            startDate: props.dateFilter?.[0] ? dayjs(props.dateFilter[0]).format('YYYY-MM-DD') : undefined,
-            endDate: props.dateFilter?.[1] ? dayjs(props.dateFilter[1]).format('YYYY-MM-DD') : undefined,
-            page: { current: page.value, row: pageSize },
-        });
-        const data = res.code === 200 && Array.isArray(res.data) ? res.data : [];
-
-        if (isLoadMore) {
-            records.value.push(...data);
-        } else {
-            records.value = data;
-        }
-        console.log(records.value, 1112212);
-
-
-        if (data.length < pageSize) {
-            finished.value = true;
-        } else {
-            finished.value = false;
-        }
-    } catch (error: any) {
-        console.log(error, 11111);
-
-        if (!isLoadMore) {
-            records.value = [];
-        }
-        showToast(error?.message || String(error));
-    } finally {
-        loading.value = false;
-    }
-};
-
-const goToDeductionDetail = (record: RecordItem) => {
-    cardStore.saveOrderDetail(record);
-    router.push({
-        path: '/pages/wallet/global-detail',
-        query: { id: record.id }
-    });
-};
-
-const loadMore = () => {
-    if (finished.value || loading.value) return;
-    page.value++;
-    fetchRecords(true);
-};
-
-watch([() => props.dateFilter], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-watch([() => props.payoutCurrency], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-watch([() => props.statusIndex], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-
-const loadMoreWrapperRef = ref<any>(null);
-
-const refresh = async () => {
-    page.value = 1;
-    finished.value = false;
-    await fetchRecords();
-};
-
-const handleRefresh = async () => {
-    await refresh();
-    // 停止下拉刷新动画
-    if (loadMoreWrapperRef.value) {
-        loadMoreWrapperRef.value.stopRefresh();
-    }
-};
-
-onMounted(() => {
-    fetchRecords();
-});
-
-defineExpose({
-    refresh
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.records-list {
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(12);
-    padding: px2rpx(16);
-}
-
-.record-card {
-    background-color: #ffffff;
-    border-radius: px2rpx(12);
-    border: 1px solid #e5e7eb;
-    overflow: hidden;
-    transition: box-shadow 0.3s;
-    padding: px2rpx(16);
-    position: relative;
-}
-
-.record-card:active {
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-}
-
-.record-main {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    padding-bottom: px2rpx(16);
-}
-
-.record-left {
-    display: flex;
-    align-items: flex-start;
-    gap: px2rpx(12);
-    min-width: 0;
-}
-
-.type-icon {
-    width: px2rpx(40);
-    height: px2rpx(40);
-    border-radius: px2rpx(10);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-shrink: 0;
-}
-
-.deduction-icon {
-    background-color: #fef2f2;
-}
-
-.icons {
-    width: px2rpx(20);
-    height: px2rpx(20);
-}
-
-.record-info {
-    flex: 1;
-    min-width: 0;
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(6);
-}
-
-.info-header {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    flex-wrap: wrap;
-}
-
-.record-type {
-    font-size: px2rpx(15);
-    color: #111827;
-}
-
-.status-badge {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    padding: px2rpx(3) px2rpx(8) px2rpx(3) px2rpx(3);
-    border-radius: px2rpx(12);
-    position: absolute;
-    top: px2rpx(1);
-    right: px2rpx(1);
-}
-
-.status-success {
-    background-color: #f0fdf4;
-}
-
-.status-wait_process {
-    background-color: #fefce8;
-}
-
-.status-fail {
-    background-color: #fef2f2;
-}
-
-.status-text {
-    font-size: px2rpx(11);
-}
-
-.status-text-success {
-    color: #22c55e;
-}
-
-.status-text-wait_process {
-    color: #eab308;
-}
-
-.status-text-fail {
-    color: #ef4444;
-}
-
-.record-detail {
-    font-size: px2rpx(13);
-    color: #6b7280;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.record-right {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    align-items: flex-start;
-    gap: px2rpx(4);
-    margin-left: px2rpx(12);
-    flex-shrink: 0;
-
-    .row {
-        width: 100%;
-        display: flex;
-        align-items: center;
-        justify-content: space-around;
-
-    }
-
-    .l {
-        flex: 1;
-    }
-
-    .r {
-        display: flex;
-        flex-direction: column;
-        align-items: flex-start;
-        gap: px2rpx(4);
-        margin-left: px2rpx(12);
-        flex-shrink: 0;
-    }
-}
-
-.amount-deduction {
-    font-size: px2rpx(18);
-    color: #ef4444;
-}
-
-.fee-text {
-    font-size: px2rpx(11);
-    color: #9ca3af;
-}
-
-.record-footer {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    padding-top: px2rpx(16);
-    border-top: 1px solid #f3f4f6;
-}
-
-.footer-time {
-    font-size: px2rpx(11);
-    color: #9ca3af;
-}
-
-.footer-actions {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(2);
-}
-
-.footer-detail {
-    font-size: px2rpx(11);
-    color: #2563eb;
-}
-</style>

+ 0 - 472
pages/wallet/components/WithdrawList.vue

@@ -1,472 +0,0 @@
-<template>
-    <cwg-load-more-wrapper ref="loadMoreWrapperRef" :loading="loading" :finished="finished" :height='54'
-        :refresher-enabled="true" @reach-bottom="loadMore" @refresh="handleRefresh">
-        <view v-if="records.length > 0" class="records-list">
-            <view v-for="record in records" :key="record.id" class="record-card" @click="goToDeductionDetail(record)">
-                <view class="record-main">
-                    <view class="record-left">
-                        <view class="type-icon deduction-icon">
-                            <cwg-icon class="icons" :name="getDeductionIcon(record.type || record.typeStr)" :size="20"
-                                color="#ef4444" />
-                        </view>
-                    </view>
-
-                    <view class="record-right">
-                        <view class="record-info">
-                            <view class="info-header">
-                                <text class="record-type">{{ Math.abs(Number(record.amount || 0)) }}
-                                    {{ record.currency || 'USD' }}</text>
-                                <text class="record-detail"><cwg-icon name="icon_transfer" :size="18"
-                                        color="#000" /></text>
-                                <text class="record-type">{{ Math.abs(Number(record.receivedAmount || 0)) }}
-                                    {{ record.receivedCurrency }}</text>
-                                <view :class="['status-badge', getStatusBadgeClass(record.transactionStatus)]">
-                                    <cwg-icon class="icons" :name="getStatusIcon(record.transactionStatus)" :size="12"
-                                        :color="getStatusColor(record.transactionStatus)" />
-                                    <text :class="['status-text', getStatusTextClass(record.transactionStatus)]">
-                                        {{ getStatusText(record.transactionStatus) }}
-                                    </text>
-                                </view>
-                            </view>
-                        </view>
-                    </view>
-                </view>
-
-                <view class="record-footer">
-                    <text class="footer-time">{{ formatDateTime(record.addTime || record.time) }}</text>
-                    <view class="footer-actions">
-                        <text class="footer-order">
-                            {{ t('DepositAddress.p2') }}: {{ formatOrderNo(record.address) }}
-                        </text>
-                        <cwg-icon class="footer-order-icon" name="copy" :size="14" color="#9ca3af"
-                            @click.stop="copyOrderNo(record.address)" />
-                    </view>
-                </view>
-            </view>
-        </view>
-        <cwg-empty-state v-else />
-    </cwg-load-more-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch, onMounted } from 'vue';
-import dayjs from 'dayjs';
-import { useI18n } from 'vue-i18n';
-import { showToast } from '@/utils/toast';
-import { ucardApi, TransactionInfo } from '@/api/ucard';
-import useRouter from "@/hooks/useRouter";
-const router = useRouter();
-import { withdrawStatus } from '@/utils/dataMap';
-import useCardStore from '@/stores/use-card-store';
-
-interface RecordItem extends TransactionInfo {
-    type?: string | number;
-    typeStr?: string;
-    remark?: string;
-    status?: string | number;
-    addTime?: string | number;
-    fee?: number;
-    currency?: string;
-    merchantOrderNo?: string;
-    reason?: string;
-    time?: string | number;
-}
-
-type NormalizedStatus = 'success' | 'wait_process' | 'fail';
-
-const props = defineProps<{
-    cardNumber: string;
-    typeIndex: number;
-    statusIndex: number;
-    dateFilter: string;
-    typeOptions: string[];
-    payoutCurrency: string;
-}>();
-
-const { t } = useI18n();
-
-const records = ref<RecordItem[]>([]);
-const page = ref(1);
-const pageSize = 10;
-const loading = ref(false);
-const finished = ref(false);
-
-const cardStore = useCardStore();
-const normalizeStatus = (status?: string | number): NormalizedStatus => {
-    if (!status) return 'wait_process';
-    if (status == 4 || status == 5) return 'fail';
-    if (status == 3) return 'success';
-    return 'wait_process';
-};
-
-const getStatusText = (status?: string | number): string => {
-    return t(withdrawStatus[status]);
-};
-
-const getStatusIcon = (status?: string | number): string => {
-    const normalized = normalizeStatus(status);
-    if (normalized === 'success') return 'checkmarkempty1';
-    if (normalized === 'wait_process') return 'info1';
-    return 'closeempty1';
-};
-
-const getStatusColor = (status?: string | number): string => {
-    const normalized = normalizeStatus(status);
-    if (normalized === 'success') return '#22c55e';
-    if (normalized === 'wait_process') return '#eab308';
-    return '#ef4444';
-};
-
-const getStatusBadgeClass = (status?: string | number) => `status-${normalizeStatus(status)}`;
-const getStatusTextClass = (status?: string | number) => `status-text-${normalizeStatus(status)}`;
-
-const getStatusValue = (index: number): NormalizedStatus | null => {
-    if (index === 0) return null;
-    const statusMap: NormalizedStatus[] = ['success', 'wait_process', 'fail'];
-    return statusMap[index - 1];
-};
-
-const getDeductionIcon = (type?: string | number): string => {
-    const typeStr = String(type || '');
-    if (typeStr.includes('服务费') || typeStr === '1') return 'servicefee';
-    if (typeStr.includes('手续费') || typeStr === '2') return 'handlingfee';
-    return 'handlingfee';
-};
-
-const formatDateTime = (time?: string | number): string => {
-    if (!time) return '--';
-    try {
-        let date: dayjs.Dayjs;
-        if (typeof time === 'number') {
-            if (time.toString().length === 10) {
-                date = dayjs.unix(time);
-            } else {
-                date = dayjs(time);
-            }
-        } else {
-            date = dayjs(time);
-        }
-        if (!date.isValid()) return '--';
-        return date.format('YYYY-MM-DD HH:mm:ss');
-    } catch (error) {
-        return '--';
-    }
-};
-
-const getDatePart = (time?: string | number): string => {
-    if (!time) return '';
-    try {
-        let date: dayjs.Dayjs;
-        if (typeof time === 'number') {
-            if (time.toString().length === 10) {
-                date = dayjs.unix(time);
-            } else {
-                date = dayjs(time);
-            }
-        } else {
-            date = dayjs(time);
-        }
-        if (!date.isValid()) return '';
-        return date.format('YYYY-MM-DD');
-    } catch (error) {
-        return '';
-    }
-};
-
-const formatOrderNo = (orderNo?: string) => {
-    if (!orderNo) return '--';
-    if (orderNo.length <= 16) return orderNo;
-    return orderNo.slice(0, 6) + '...' + orderNo.slice(-4);
-};
-
-const copyOrderNo = (orderNo?: string) => {
-    if (!orderNo) return;
-    uni.setClipboardData({
-        data: orderNo,
-        success: () => {
-            uni.showToast({
-                title: t('card.Msg.m8') || '复制成功',
-                icon: 'success'
-            });
-        }
-    });
-};
-
-const fetchRecords = async (isLoadMore = false) => {
-    if (isLoadMore && finished.value) return;
-    loading.value = true;
-    try {
-        const res = await ucardApi.getBlockchainWithdrawPage({
-            cardNumber: props.cardNumber,
-            payoutCurrency: props.payoutCurrency,
-            transactionStatus: props.statusIndex == -1 ? undefined : props.statusIndex,
-            startDate: props.dateFilter?.[0] ? dayjs(props.dateFilter[0]).format('YYYY-MM-DD') : undefined,
-            endDate: props.dateFilter?.[1] ? dayjs(props.dateFilter[1]).format('YYYY-MM-DD') : undefined,
-            page: { current: page.value, row: pageSize },
-        });
-        const data = res.code === 200 && Array.isArray(res.data) ? res.data : [];
-
-        if (isLoadMore) {
-            records.value.push(...data);
-        } else {
-            records.value = data;
-        }
-        if (data.length < pageSize) {
-            finished.value = true;
-        } else {
-            finished.value = false;
-        }
-    } catch (error: any) {
-        if (!isLoadMore) {
-            records.value = [];
-        }
-        showToast(error?.message || String(error));
-    } finally {
-        loading.value = false;
-    }
-};
-
-const goToDeductionDetail = (record: RecordItem) => {
-    cardStore.saveOrderDetail(record);
-    router.push({
-        path: '/pages/wallet/withdraw-detail',
-        query: { id: record.id }
-    });
-};
-
-const loadMore = () => {
-    if (finished.value || loading.value) return;
-    page.value++;
-    fetchRecords(true);
-};
-
-watch([() => props.dateFilter], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-watch([() => props.payoutCurrency], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-watch([() => props.statusIndex], () => {
-    page.value = 1;
-    finished.value = false;
-    fetchRecords();
-}, { immediate: false });
-
-const loadMoreWrapperRef = ref<any>(null);
-
-const refresh = async () => {
-    page.value = 1;
-    finished.value = false;
-    await fetchRecords();
-};
-
-const handleRefresh = async () => {
-    await refresh();
-    // 停止下拉刷新动画
-    if (loadMoreWrapperRef.value) {
-        loadMoreWrapperRef.value.stopRefresh();
-    }
-};
-
-onMounted(() => {
-    fetchRecords();
-});
-
-defineExpose({
-    refresh
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.records-list {
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(12);
-    padding: px2rpx(16);
-}
-
-.record-card {
-    background-color: #ffffff;
-    border-radius: px2rpx(12);
-    border: 1px solid #e5e7eb;
-    overflow: hidden;
-    transition: box-shadow 0.3s;
-    padding: px2rpx(16);
-    position: relative;
-}
-
-.record-card:active {
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
-}
-
-.record-main {
-    display: flex;
-    align-items: flex-start;
-    justify-content: space-between;
-    padding-bottom: px2rpx(16);
-}
-
-.record-left {
-    display: flex;
-    align-items: flex-start;
-    gap: px2rpx(12);
-    min-width: 0;
-}
-
-.type-icon {
-    width: px2rpx(40);
-    height: px2rpx(40);
-    border-radius: px2rpx(10);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-shrink: 0;
-}
-
-.deduction-icon {
-    background-color: #fef2f2;
-}
-
-.icons {
-    width: px2rpx(20);
-    height: px2rpx(20);
-}
-
-.record-info {
-    flex: 1;
-    min-width: 0;
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(6);
-}
-
-.info-header {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    flex-wrap: wrap;
-}
-
-.record-type {
-    font-size: px2rpx(15);
-    color: #111827;
-}
-
-.status-badge {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    padding: px2rpx(3) px2rpx(8) px2rpx(3) px2rpx(3);
-    border-radius: px2rpx(12);
-    position: absolute;
-    top: px2rpx(1);
-    right: px2rpx(1);
-}
-
-.status-success {
-    background-color: #f0fdf4;
-}
-
-.status-wait_process {
-    background-color: #fefce8;
-}
-
-.status-fail {
-    background-color: #fef2f2;
-}
-
-.status-text {
-    font-size: px2rpx(11);
-}
-
-.status-text-success {
-    color: #22c55e;
-}
-
-.status-text-wait_process {
-    color: #eab308;
-}
-
-.status-text-fail {
-    color: #ef4444;
-}
-
-.record-detail {
-    font-size: px2rpx(13);
-    color: #6b7280;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.record-right {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    align-items: flex-start;
-    gap: px2rpx(4);
-    margin-left: px2rpx(12);
-    flex-shrink: 0;
-
-    .row {
-        width: 100%;
-        display: flex;
-        align-items: center;
-        justify-content: space-around;
-
-    }
-
-    .l {
-        flex: 1;
-    }
-
-    .r {
-        display: flex;
-        flex-direction: column;
-        align-items: flex-start;
-        gap: px2rpx(4);
-        margin-left: px2rpx(12);
-        flex-shrink: 0;
-    }
-}
-
-.amount-deduction {
-    font-size: px2rpx(18);
-    color: #ef4444;
-}
-
-.fee-text {
-    font-size: px2rpx(11);
-    color: #9ca3af;
-}
-
-.record-footer {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    padding-top: px2rpx(16);
-    border-top: 1px solid #f3f4f6;
-}
-
-.footer-time {
-    font-size: px2rpx(11);
-    color: #9ca3af;
-}
-
-.footer-actions {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(2);
-}
-
-.footer-detail {
-    font-size: px2rpx(11);
-    color: #2563eb;
-}
-</style>

+ 0 - 126
pages/wallet/composable/useOrderFields.ts

@@ -1,126 +0,0 @@
-import { computed, } from 'vue'
-import { useI18n } from 'vue-i18n'
-import useCardStore from '@/stores/use-card-store';
-/**
- * 订单字段处理 Composable
- * 将 detailData 中的字段数据转换为分组列表,支持缓存数据立即渲染
- */
-export function useOrderFields(detailData: any) {
-    const { t } = useI18n()
-    const cardStore = useCardStore()
-
-    /** 1️⃣ 字段解析(一维数组) */
-    const fieldList = computed(() => {
-        const dt = detailData.value
-
-        if (!dt) {
-            return []
-        }
-
-        // 检查 dt 是否已经加载了数据(通过检查是否有属性)
-        const hasData = Object.keys(dt).length > 0
-
-        if (!hasData) {
-            //  console.log('数据尚未加载,返回空数组');
-            return []
-        }
-
-        // fieldDtos 存在且不为空数组时使用 fieldDtos
-        if (dt.fieldDtos && Array.isArray(dt.fieldDtos) && dt.fieldDtos.length > 0) {
-            //  console.log('使用 fieldDtos 分支,数量:', dt.fieldDtos.length);
-            return [...dt.fieldDtos]
-                .sort((a, b) => (a.sorting || 0) - (b.sorting || 0))
-                .map(item => {
-                    const key = Object.keys(dt).find(
-                        k => k.toLowerCase() === item.fieldName.toLowerCase()
-                    )
-                    const i18nKey = `global.fieldName.${item.fieldName}.fieldTitle`
-                    let name = t(i18nKey)
-                    if (name === i18nKey) {
-                        name = item.fieldName
-                    }
-                    let value = key ? dt[key] : item.fixedValue
-                    if (
-                        item.fieldType === 'select' &&
-                        key &&
-                        !['transferType', 'payoutMethod'].includes(key)
-                    ) {
-                        value = dt[key + 'Value'] || value
-                    }
-                    if (item.fieldName === 'transferAmount' && dt.payoutCurrency) {
-                        value = `${value} ${dt.payoutCurrency}`
-                    }
-
-                    return {
-                        name,
-                        value: value ?? '',
-                        type: item.fieldUserType || 'other',
-                        fieldName: item.fieldName,
-                        fieldType: item.fieldType,
-                        options: item.options || null
-                    }
-                })
-        }
-
-        // 使用 globalFieldParams
-        //  console.log('使用 globalFieldParams 分支');
-        //  console.log('globalFieldParams:', cardStore.globalFieldParams);
-
-        return cardStore.globalFieldParams
-            .map((item: any) => {
-                const key = Object.keys(dt).find(
-                    k => k === item.fieldName
-                )
-
-                const i18nKey = `global.fieldName.${item.fieldName}.fieldTitle`
-                let name = t(i18nKey)
-                if (name === i18nKey) {
-                    name = item.fieldName
-                }
-                let value = key ? dt[key] : ''
-
-                if (
-                    item.fieldType === 'select' &&
-                    key &&
-                    !['transferType', 'payoutMethod'].includes(key)
-                ) {
-                    value = dt[key + 'Value'] || value
-                }
-                if (item.fieldName === 'transferAmount' && dt.payoutCurrency) {
-                    value = `${value} ${dt.payoutCurrency}`
-                }
-
-                return {
-                    name,
-                    value: value ?? '',
-                    type: item.fieldUserType || 'other',
-                    fieldName: item.fieldName,
-                    fieldType: item.fieldType,
-                    options: item.options || null
-                }
-            })
-            .filter(field => {
-                // 过滤掉 value 为空的字段
-                const val = field.value
-                return val !== '' && val !== null && val !== undefined
-            })
-    })
-
-    /** 2️⃣ 分组字段(按类型分组) */
-    const fieldGroups = computed(() => {
-        const groups: Record<string, any[]> = {}
-
-        fieldList.value.forEach(field => {
-            const type = field.type || 'other'
-            if (!groups[type]) {
-                groups[type] = []
-            }
-            groups[type].push(field)
-        })
-        return groups
-    })
-    return {
-        fieldList,
-        fieldGroups
-    }
-}

+ 0 - 765
pages/wallet/global-detail.vue

@@ -1,765 +0,0 @@
-<template>
-  <cwg-page-wrapper>
-    <view class="order-detail-page">
-
-
-      <!-- Content -->
-      <view class="content">
-        <view class="section-card">
-          <view class="success-icon-wrap">
-            <image v-if="detailData.status === 'success'" src="/static/images/vector.png" alt="" mode="widthFix" />
-            <image v-else-if="detailData.status === 'fail' || detailData.status === 'cancel'" src="/static/images/vector2.png" alt="" mode="widthFix" />
-            <image v-else src="/static/images/vector3.png" alt="" mode="widthFix" />
-            <text class="success-text">{{ t(globalStatusText[detailData.status]) }}</text>
-            <text v-if="approveDesc" class="success-text">{{ approveDesc }}</text>
-          </view>
-        </view>
-
-        <view class="section-card">
-          <view class="section-header">
-            <uni-icons type="wallet" size="18" color="#2563eb" />
-            <text class="section-title">{{ t('Ib.Report.Title3') }}</text>
-          </view>
-          <view class="info-list">
-            <view class="info-row" v-if="detailData.merchantOrderNo">
-              <text class="info-label">{{ t('card.Form.f35') }}</text>
-              <view class="info-value-wrapper">
-                <text class="info-value">{{ detailData.merchantOrderNo }}</text>
-                <cwg-icon name="copy" :size="14" color="#9ca3af" @click.stop="copyOrderNo" />
-              </view>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f37') }}</text>
-              <text class="info-value amount-highlight">
-                {{ detailData.deductionAmount || '0' }}
-                <text class="info-valuecurrency">USD</text>
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f30') }}</text>
-              <text class="info-value">
-                {{ detailData.deductionFee || '0' }}
-                <text class="currency">USD</text>
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('global.p12') }}</text>
-              <text class="info-value">
-                {{ detailData.exchangeRate ? `1 : ${detailData.exchangeRate}` : '-- ' }}
-              </text>
-            </view>
-            <view class="divider"></view>
-            <view class="info-row" v-for="(item, index) in list.common" :key="index">
-              <text class="info-label">{{ item.name }}</text>
-              <text class="info-value">{{ item.value }}</text>
-            </view>
-          </view>
-        </view>
-        <view class="section-card">
-          <view class="section-header">
-            <uni-icons type="list" size="18" color="#2563eb" />
-            <text class="section-title">{{ getGroupTitle('sender') }}</text>
-          </view>
-          <view class="info-list">
-            <view class="info-row" v-for="(item, index) in list.sender" :key="index">
-              <text class="info-label">{{ item.name }}</text>
-              <text class="info-value">{{ item.value }}</text>
-            </view>
-          </view>
-        </view>
-        <view class="section-card">
-          <view class="section-header">
-            <uni-icons type="list" size="18" color="#2563eb" />
-            <text class="section-title">{{ getGroupTitle('receiver') }}</text>
-          </view>
-          <view class="info-list">
-            <view class="info-row" v-for="(item, index) in list.receiver" :key="index">
-              <text class="info-label">{{ item.name }}</text>
-              <text class="info-value">{{ item.value }}</text>
-            </view>
-          </view>
-        </view>
-      </view>
-      <view class="content" v-if="complianceStatus">
-        <view>
-          <view class="section-header">
-            <uni-icons type="list" size="18" color="#2563eb" />
-            <text class="section-title">{{ getGroupTitle('submitRfi') }}</text>
-          </view>
-        </view>
-        <DynamicForm ref="globalFormRef" :fields="complianceItems" :globalForm="globalForm" :step2="true" type="2">
-        </DynamicForm>
-      </view>
-      <!-- Bottom Actions -->
-      <view class="bottom-actions"
-        v-if="(detailData.approveStatus == 1 && detailData.status != 'cancel') || detailData.needSupplement">
-        <view v-if="detailData.approveStatus == 1 && detailData.status != 'cancel'" class="action-btn cancel-btn"
-          @click="cancelOrder">
-          <text class="btn-text">{{ t('global.GlobalOrder.CancelOrder') }}</text>
-        </view>
-        <view v-if="detailData.needSupplement" class="action-btn appeal-btn" @click="appealOrder">
-          <text class="btn-text">{{ t('global.GlobalOrder.submitRfi') }}</text>
-        </view>
-      </view>
-    </view>
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, watch, nextTick, computed } from 'vue'
-import { onLoad, onUnload } from '@dcloudio/uni-app';
-import { useI18n } from 'vue-i18n';
-import useCardStore from '@/stores/use-card-store';
-import { ucardApi } from "@/api/ucard";
-import DynamicForm from "./components/DynamicForm.vue";
-import { useOrderFields } from './composable/useOrderFields';
-import { globalApprovalText, globalComplianceText, globalStatusText } from '@/utils/dataMap';
-import useUserStore from "@/stores/use-user-store";
-const { t, locale } = useI18n();
-
-const userStore = useUserStore();
-const approveDesc = ref('');
-const getApproveDesc = () => {
-  const d = detailData.value.approveDesc
-  if (!d) return
-  const c = userStore.reasonsOptions
-  const a = c[d || '']
-  const b = locale.value == 'cn' || locale.value == 'zhHant' ? a.content : a.enContent
-  if (!b) {
-    reasonsRefusalList()
-  }
-  approveDesc.value = b;
-}
-async function reasonsRefusalList() {
-  try {
-    const res = await ucardApi.reasonsRefusalList();
-    if (res.code === 200) {
-      pickFields(res.data);
-      getApproveDesc()
-    } else {
-      uni.$u.toast(res.msg || t("login.msg0"));
-    }
-  } catch (error) {
-    console.log(error, 111);
-  }
-}
-function pickFields(source, fields = ['content', 'enContent']) {
-  const result = {}
-  Object.entries(source).forEach(([key, value]) => {
-    result[key] = fields.reduce((acc, f) => {
-      acc[f] = value[f] ?? null
-      return acc
-    }, {})
-  })
-  userStore.saveReasonsOptions(result);
-}
-
-const cardStore = useCardStore();
-const getGroupTitle = (type) => {
-  const map = {
-    common: "global.GlobalOrder.common",
-    receiver: "global.GlobalOrder.receiver",
-    sender: "global.GlobalOrder.sender",
-    other: "global.GlobalOrder.other",
-    submitRfi: "global.GlobalOrder.submitRfi",
-  };
-  return t(map[type] || type);
-}
-// 复制订单号
-const copyOrderNo = () => {
-  uni.setClipboardData({
-    data: detailData.value.merchantOrderNo,
-    success: () => {
-      uni.showToast({
-        title: t('card.Msg.m8') || '复制成功',
-        icon: 'success'
-      });
-    }
-  });
-};
-
-// 取消订单
-const cancelOrder = () => {
-  uni.showModal({
-    title: t('Msg.SystemPrompt'),
-    cancelText: t('common.cancel'),
-    confirmText: t('common.confirm'),
-    content: t('global.GlobalOrder.ConfirmCancelOrder'),
-    success: async (e) => {
-      if (e.confirm) {
-        const res = await ucardApi.globalCancelOrder({ id: detailData.value.id })
-        if (res.code == 200) {
-          // 刷新订单详情
-          uni.showToast({
-            title: t('global.GlobalOrder.CancelOrderSuccess'),
-            icon: 'success'
-          });
-          await getOrderDetail(detailData.value.id);
-        }
-      }
-    }
-  });
-};
-const globalFormRef = ref(null)
-const setRfiInfos = () => {
-  let list = []
-  list = complianceItems.value.filter(item => globalForm.value[item.fieldName])
-  const rfiInfos = list.map((item) => {
-    const { fieldType, rfiId } = item;
-    let rfiValue = undefined;
-    let rfiValueUrl = undefined;
-    if (fieldType === "file") {
-      rfiValueUrl = globalForm.value[item.fieldName]
-    } else {
-      rfiValue = globalForm.value[item.fieldName];
-    }
-    return {
-      rfiId,
-      fieldType,
-      rfiValueUrl,
-      rfiValue,
-    };
-  });
-  return {
-    orderNo: detailData.value.orderNo,
-    rfiInfos,
-  };
-}
-// 申诉订单
-const appealOrder = async () => {
-  try {
-    const isValid = await globalFormRef.value.validateForm();
-    if (!isValid) {
-      return;
-    }
-    const params = setRfiInfos();
-    const res = await ucardApi.globalSupplementary(params);
-    if (res.code == 200) {
-      await getOrderDetail(detailData.value.id);
-    }
-  } catch (error) {
-    console.log(error);
-  }
-};
-
-const isLoading = ref(false) // 接口加载状态
-
-const detailData = ref<any>({})
-const list = ref<Record<string, any[]>>({})
-
-const complianceItems = ref<any[]>([])
-const globalForm = ref<any>({})
-
-const complianceStatus = ref(false)
-
-const type = ref<'1' | '2'>('1')
-
-const { fieldGroups } = useOrderFields(detailData)
-
-/** 自动同步字段分组到列表 */
-watch(
-  fieldGroups,
-  (val) => {
-    list.value = { ...val }
-  },
-  { immediate: true, deep: true }
-)
-
-/**
- * 处理合规字段和状态
- * 从 detailData 中提取并处理合规相关数据
- */
-function processComplianceData() {
-  // 处理合规字段
-  complianceItems.value = (detailData.value.dataDtos || []).map(item => {
-    const fieldName = `${item.customerType}_${item.fieldName}`
-
-    if (item.status !== "pending_check" && item.status !== "approved") {
-      globalForm.value[fieldName] =
-        item.fieldType === 'file'
-          ? item.rfiValueUrl
-          : item.rfiValue
-
-      return { ...item, fieldName, disabled: true }
-    } else {
-      if (item.status == "pending" || item.status == "approved") {
-        return {
-          ...item, fieldName,
-          disabled: true,
-        };
-      } else {
-        return { ...item };
-      }
-    }
-  })
-  // 更新合规状态
-  complianceStatus.value = complianceItems.value.length > 0
-}
-
-/**
- * 获取订单详情
- * 接口返回后会更新 detailData,通过 watch 自动同步到 list
- */
-async function getOrderDetail(id: string | number) {
-  try {
-    isLoading.value = true
-    const res = await ucardApi.globalOrdersDetail({ id })
-    if (res.code !== 200) {
-      console.warn('获取订单详情失败:', res.msg)
-      return
-    }
-    Object.assign(detailData.value, res.data)
-    await nextTick()
-    processComplianceData()
-    getApproveDesc()
-  } catch (e) {
-    console.error('获取订单详情异常:', e)
-  } finally {
-    isLoading.value = false
-  }
-}
-
-// 页面加载时,先使用缓存数据渲染,然后获取最新数据
-onLoad((e) => {
-  const cachedData = cardStore.orderDetail
-  if (cachedData) {
-    try {
-      const clonedData = JSON.parse(JSON.stringify(cachedData))
-      Object.assign(detailData.value, clonedData)
-      nextTick()
-      console.log(clonedData, detailData.value, 'clonedDataclonedDataclonedDataclonedData');
-
-      processComplianceData()
-    } catch (error) {
-      console.error('加载缓存数据失败:', error)
-    }
-  }
-  if (e.id) {
-    nextTick(() => {
-      getOrderDetail(e.id)
-    })
-  }
-});
-
-// 离开页面时清空订单详情
-onUnload(() => {
-  cardStore.clearOrderDetail();
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page-wrapper {
-  padding: 0;
-}
-
-.success-icon-wrap {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  flex-wrap: wrap;
-  background-color: #ffffff;
-
-  image {
-    width: 100%;
-  }
-
-  .success-text {
-    width: 100%;
-    text-align: center;
-    font-size: px2rpx(18);
-    color: #111827;
-    margin-bottom: px2rpx(24);
-  }
-}
-
-.order-detail-page {
-  background-color: #f9fafb;
-  padding-bottom: px2rpx(80);
-}
-
-/* Header */
-.header {
-  background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-  padding: px2rpx(12) px2rpx(16);
-  padding-top: calc(px2rpx(12) + env(safe-area-inset-top));
-}
-
-.header-nav {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-}
-
-.back-btn {
-  width: px2rpx(40);
-  height: px2rpx(40);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.header-title {
-  color: #ffffff;
-  font-size: px2rpx(18);
-}
-
-.header-action {
-  width: px2rpx(40);
-}
-
-/* Content */
-.content {
-  padding: px2rpx(16);
-}
-
-/* Status Card */
-.status-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(16);
-  padding: px2rpx(32) px2rpx(24);
-  margin-bottom: px2rpx(16);
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-}
-
-.status-icon-wrapper {
-  margin-bottom: px2rpx(16);
-}
-
-.status-icon {
-  width: px2rpx(80);
-  height: px2rpx(80);
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.status-icon-success {
-  background-color: #f0fdf4;
-}
-
-.status-icon-processing {
-  background-color: #fefce8;
-}
-
-.status-icon-failed {
-  background-color: #fef2f2;
-}
-
-.status-icon-cancelled {
-  background-color: #f9fafb;
-}
-
-.status-title {
-  font-size: px2rpx(22);
-  color: #111827;
-  margin-bottom: px2rpx(8);
-}
-
-.status-subtitle {
-  font-size: px2rpx(14);
-  color: #6b7280;
-  text-align: center;
-}
-
-/* Section Card */
-.section-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  padding: px2rpx(16);
-  margin-bottom: px2rpx(16);
-}
-
-.section-header {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  margin-bottom: px2rpx(16);
-}
-
-.section-title {
-  font-size: px2rpx(16);
-  color: #111827;
-}
-
-/* Approval Timeline */
-.approval-timeline {
-  display: flex;
-  flex-direction: column;
-}
-
-.timeline-item {
-  display: flex;
-  gap: px2rpx(12);
-}
-
-.timeline-left {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  flex-shrink: 0;
-}
-
-.timeline-dot {
-  width: px2rpx(24);
-  height: px2rpx(24);
-  border-radius: 50%;
-  background-color: #f3f4f6;
-  border: 2px solid #e5e7eb;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.timeline-dot-active {
-  background-color: #22c55e;
-  border-color: #22c55e;
-}
-
-.timeline-dot-current {
-  background-color: #eab308;
-  border-color: #eab308;
-  animation: pulse 2s infinite;
-}
-
-@keyframes pulse {
-
-  0%,
-  100% {
-    opacity: 1;
-  }
-
-  50% {
-    opacity: 0.7;
-  }
-}
-
-.timeline-line {
-  width: px2rpx(2);
-  flex: 1;
-  background-color: #e5e7eb;
-  margin: px2rpx(4) 0;
-}
-
-.timeline-right {
-  flex: 1;
-  padding-bottom: px2rpx(24);
-}
-
-.timeline-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: px2rpx(6);
-}
-
-.timeline-title {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-.timeline-status {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(4);
-  padding: px2rpx(2) px2rpx(8);
-  border-radius: px2rpx(12);
-}
-
-.timeline-status.completed {
-  background-color: #f0fdf4;
-}
-
-.timeline-status.current {
-  background-color: #fefce8;
-}
-
-.timeline-status.pending {
-  background-color: #f9fafb;
-}
-
-.timeline-status-text {
-  font-size: px2rpx(12);
-}
-
-.timeline-status.completed .timeline-status-text {
-  color: #22c55e;
-}
-
-.timeline-status.current .timeline-status-text {
-  color: #eab308;
-}
-
-.timeline-status.pending .timeline-status-text {
-  color: #9ca3af;
-}
-
-.timeline-operator {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  display: block;
-  margin-bottom: px2rpx(4);
-}
-
-.timeline-time {
-  font-size: px2rpx(12);
-  color: #9ca3af;
-  display: block;
-  margin-bottom: px2rpx(4);
-}
-
-.timeline-remark {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  display: block;
-  margin-top: px2rpx(6);
-  padding: px2rpx(8);
-  background-color: #f9fafb;
-  border-radius: px2rpx(6);
-}
-
-/* Info List */
-.info-list {
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(12);
-}
-
-.info-row {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  gap: px2rpx(12);
-  padding: px2rpx(4) 0;
-}
-
-.info-row.vertical {
-  flex-direction: column;
-  align-items: flex-start;
-}
-
-.info-label {
-  font-size: px2rpx(14);
-  color: #6b7280;
-  flex-shrink: 0;
-}
-
-.info-value {
-  font-size: px2rpx(14);
-  color: #111827;
-  text-align: right;
-  word-break: break-all;
-}
-
-.info-value-wrapper {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  flex: 1;
-  justify-content: flex-end;
-}
-
-.amount-highlight {
-  font-size: px2rpx(20);
-  color: #2563eb;
-}
-
-.total-label {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-.total-value {
-  font-size: px2rpx(18);
-  color: #ef4444;
-}
-
-.remark-text {
-  text-align: left;
-  color: #6b7280;
-  line-height: 1.6;
-}
-
-.divider {
-  height: px2rpx(1);
-  background-color: #f3f4f6;
-  margin: px2rpx(4) 0;
-}
-
-/* Service Card */
-.service-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  padding: px2rpx(16);
-  display: flex;
-  align-items: center;
-  gap: px2rpx(12);
-  margin-bottom: px2rpx(16);
-}
-
-.service-text {
-  flex: 1;
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-/* Bottom Actions */
-.bottom-actions {
-  position: fixed;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  background-color: #ffffff;
-  border-top: 1px solid #e5e7eb;
-  padding: px2rpx(12) px2rpx(16);
-  padding-bottom: calc(px2rpx(12) + env(safe-area-inset-bottom));
-  display: flex;
-  gap: px2rpx(12);
-}
-
-.action-btn {
-  flex: 1;
-  height: px2rpx(44);
-  border-radius: px2rpx(8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.cancel-btn {
-  background-color: #f3f4f6;
-}
-
-.cancel-btn .btn-text {
-  color: #6b7280;
-}
-
-.appeal-btn {
-  background-color: #2563eb;
-}
-
-.appeal-btn .btn-text {
-  color: #ffffff;
-}
-
-.delete-btn {
-  background-color: #f3f4f6;
-}
-
-.delete-btn .btn-text {
-  color: #ef4444;
-}
-
-.btn-text {
-  font-size: px2rpx(15);
-}
-
-.currency {
-  font-size: px2rpx(12);
-}
-</style>

+ 0 - 268
pages/wallet/global-list.vue

@@ -1,268 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="bank-transaction-page">
-            <view class="filters-container" :style="{ top: statusBarHeight + 53 + 'px' }">
-                <view class="filter-item">
-                    <text class="filter-label">{{ t('global.p25') }}</text>
-                    <cwg-filter-select v-model="payoutCurrency" :options="currencyList" />
-                </view>
-                <view class="filter-item">
-                    <text class="filter-label">{{ t('card.Form.f45') }}</text>
-                    <cwg-filter-select v-model="statusFilterIndex" :options="statusOptions" />
-                </view>
-                <view class="filter-item">
-                    <text class="filter-label">{{ t('card.Form.f43') }}</text>
-                    <cwg-filter-picker v-model="dateFilter"></cwg-filter-picker>
-                </view>
-                <view class="reset-btn" @click="resetFilters">
-                    <uni-icons type="loop" size="16" color="#2563eb" />
-                </view>
-            </view>
-            <view class="content">
-                <GlobalList ref="globalListRef" :cardNumber="cardNumber" :payoutCurrency="payoutCurrency"
-                    :statusIndex="statusFilterIndex" :dateFilter="dateFilter" />
-            </view>
-        </view>
-    </cwg-page-wrapper>
-
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch } from 'vue';
-import { onLoad } from '@dcloudio/uni-app';
-import { useI18n } from 'vue-i18n';
-import useGlobalStore from '@/stores/use-global-store';
-import GlobalList from './components/GlobalList.vue';
-import { globalStatusText1 } from '@/utils/dataMap';
-import useCardStore from "@/stores/use-card-store";
-const cardStore = useCardStore();
-const globalStore = useGlobalStore()
-const statusBarHeight = computed(() => globalStore.statusBarHeight);
-const { t } = useI18n();
-const cardNumber = ref('');
-onLoad((options) => {
-    cardNumber.value = options.cardNumber || '';
-});
-
-const statusOptions = computed(() => {
-    return globalStatusText1
-});
-const currencyList = computed(() => {
-    const res = cardStore.currencyList.map(item => { return { label: item.payoutCurrency, value: item.payoutCurrency } });
-    return res;
-});
-const payoutCurrency = ref(-1);
-const statusFilterIndex = ref(-1);
-const dateFilter = ref([]);
-
-const resetFilters = () => {
-    payoutCurrency.value = -1;
-    statusFilterIndex.value = -1;
-    dateFilter.value = [];
-};
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page-wrapper {
-    padding: 0;
-    border: 0;
-}
-
-.bank-transaction-page {
-    // background-color: #f9fafb;
-}
-
-.wallet-header {
-    background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-}
-
-/* Header */
-.header {
-    background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-    padding: px2rpx(16);
-    padding-bottom: px2rpx(20);
-}
-
-.header-content {
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(16);
-}
-
-.header-title {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(8);
-}
-
-.title-text {
-    color: #ffffff;
-    font-size: px2rpx(20);
-}
-
-.stats-container {
-    display: flex;
-    gap: px2rpx(12);
-}
-
-.stat-card {
-    flex: 1;
-    background-color: rgba(255, 255, 255, 0.15);
-    backdrop-filter: blur(px2rpx(10));
-    border-radius: px2rpx(12);
-    padding: px2rpx(12);
-}
-
-.stat-header {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(6);
-    margin-bottom: px2rpx(8);
-}
-
-.icons {
-    width: px2rpx(20);
-    height: px2rpx(20);
-}
-
-.stat-label {
-    font-size: px2rpx(12);
-    color: rgba(255, 255, 255, 0.9);
-}
-
-.stat-value {
-    font-size: px2rpx(20);
-    color: #ffffff;
-    display: block;
-    margin-bottom: px2rpx(4);
-}
-
-.stat-count {
-    font-size: px2rpx(11);
-    color: rgba(255, 255, 255, 0.8);
-}
-
-/* Tabs */
-.tabs-container {
-    background-color: #ffffff;
-    display: flex;
-    border-bottom: 1px solid #e5e7eb;
-    position: sticky;
-    top: 0;
-    z-index: 10;
-}
-
-.tab-item {
-    flex: 1;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: px2rpx(6);
-    padding: px2rpx(16);
-    position: relative;
-    transition: all 0.3s;
-}
-
-.tab-text {
-    font-size: px2rpx(15);
-    color: #9ca3af;
-    transition: color 0.3s;
-}
-
-.tab-text-active {
-    color: #2563eb;
-}
-
-.tab-indicator {
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    height: px2rpx(3);
-    background-color: #2563eb;
-    border-radius: px2rpx(3) px2rpx(3) 0 0;
-}
-
-/* Content */
-.content {
-    padding: 0;
-}
-
-.filters-container {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(8);
-    padding: px2rpx(12) px2rpx(16);
-    background-color: #ffffff;
-    position: sticky;
-    top: 0;
-    z-index: 10;
-    // overflow-x: auto;
-    -webkit-overflow-scrolling: touch;
-}
-
-.filter-item {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    flex-shrink: 0;
-    min-width: 0;
-}
-
-.filter-label {
-    font-size: px2rpx(12);
-    color: #6b7280;
-    white-space: nowrap;
-    flex-shrink: 0;
-}
-
-.filter-picker {
-    background-color: #ffffff;
-    border: 1px solid #e5e7eb;
-    border-radius: px2rpx(8);
-    padding: px2rpx(6) px2rpx(8);
-    display: flex;
-    align-items: center;
-    min-width: px2rpx(60);
-    max-width: px2rpx(120);
-    flex-shrink: 1;
-}
-
-.picker-value {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    width: 100%;
-    min-width: 0;
-}
-
-.picker-text {
-    flex: 1;
-    min-width: 0;
-    font-size: px2rpx(12);
-    color: #111827;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.picker-icon {
-    flex-shrink: 0;
-    width: px2rpx(14);
-    height: px2rpx(14);
-}
-
-.reset-btn {
-    background-color: #ffffff;
-    border: 1px solid #e5e7eb;
-    border-radius: px2rpx(8);
-    padding: px2rpx(6) px2rpx(10);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-shrink: 0;
-    min-width: px2rpx(36);
-}
-</style>

+ 0 - 823
pages/wallet/global-order.vue

@@ -1,823 +0,0 @@
-<template>
-  <cwg-page-wrapper>
-    <view class="page">
-      <DynamicForm ref="globalFormRef" :global-form="globalForm" :fields="globalCurrenciesField" :step2="step2"
-        type="1">
-        <template #top>
-          <cwg-input :label="t('global.t2')" v-model:value="globalForm.deductionAccount" fkey="deductionAccount"
-            type="select" :columns="loginOptionsSelect" @change="changeLogin" :placeholder="t('placeholder.choose')" />
-        </template>
-        <template #bottom>
-          <view class="form-section">
-            <view class="form-item">
-              <cwg-input :label="t('global.t6')" v-model:value="globalForm.receiver" fkey="receiver" type="select"
-                :columns="receiverUserListSelect" @change="selectReceiver" :placeholder="t('global.t7')" />
-            </view>
-            <view class="form-item">
-              <cwg-input :label="t('global.p1')" v-model:value="globalForm.payoutCurrency" fkey="payoutCurrency"
-                v-model:selectedValueDoc="globalForm['payoutCurrencyValue']" type="select" :columns="currencyListSelect"
-                @change="handlePayoutCurrencyChange" :disabled="!currencyList.length" :placeholder="t('global.p1')" />
-            </view>
-            <view class="form-item">
-              <cwg-input :label="t('global.p2')" v-model:value="globalForm.payType" fkey="payType" type="select"
-                v-model:selectedValueDoc="globalForm['transferTypeValue']" :columns="transferTypeListSelect"
-                @change="handlePayTypeChange" :disabled="!globalForm.payoutCurrency || !transferTypeList.length"
-                :placeholder="t('global.p2')" />
-            </view>
-
-            <view class="form-item" v-if="payoutMethodListSelect.length">
-              <cwg-input :label="t('global.p3')" v-model:value="globalForm.payMethod" fkey="payMethod" type="select"
-                v-model:selectedValueDoc="globalForm['payoutMethodValue']" :columns="payoutMethodListSelect"
-                @change="handlePayMethodChange" :disabled="!globalForm.payType || !payoutMethodList.length"
-                :placeholder="t('global.p3')" />
-            </view>
-          </view>
-        </template>
-        <template #transferAmount v-if="globalCurrenciesField.length">
-          <view class="form-section">
-            <view class="form-item">
-              <text class="form-label">
-                {{ t("card.Form.f55") }}
-                <text class="quota-tip" v-if="exchangeRateData && exchangeRateData.maxQuota">
-                  ({{ t("global.GlobalOrder.quoteTip") }} {{ exchangeRateData.minQuota }} - {{ exchangeRateData.maxQuota
-                  }} USD)
-                </text>
-              </text>
-
-              <cwg-input v-model:value="globalForm.amount" :required="true" fkey="amount" type="number"
-                :placeholder="t('global.placeholder.p4')" @change="handleAmountChange" />
-
-              <text class="form-error" v-if="form__error">{{ form__error }}</text>
-
-              <text class="fee-text" v-if="feeNum">
-                {{ `${t("global.GlobalOrder.fee")}:${feeNum}` }} USD
-              </text>
-            </view>
-
-            <view class="form-item">
-              <cwg-input
-                :label="t('global.fieldName.' + 'transferAmount' + '.fieldTitle') + ' (' + globalForm.payoutCurrency + ')'"
-                :required="true" v-model:value="globalForm.transferAmount" fkey="transferAmount" :disabled="true"
-                :placeholder="t('global.fieldName.' + 'transferAmount' + '.fieldDescription')" />
-            </view>
-          </view>
-        </template>
-        <template #tips>
-          <view class="tips-section">
-            <view class="tips">
-              <text class="title">{{ t('global.Tips') }}</text>
-              <text>{{ t('global.Tips1') }}</text>
-              <text>{{ t('global.Tips2') }}</text>
-              <text>{{ t('global.Tips3') }}</text>
-              <text>{{ t('global.Tips4') }}</text>
-            </view>
-          </view>
-        </template>
-
-        <template #submit>
-          <view class="submit-section cwg-button">
-            <u-button type="primary" @click="saveDlobal" class="submit-btn  prev-btn">
-              <text>{{ t('Btn.Submit') }}</text>
-            </u-button>
-          </view>
-        </template>
-      </DynamicForm>
-    </view>
-
-    <cwg-SuccessPrompt v-model:show="showSuccessPrompt" :title="t('global.title1')" :desc="t('Custom.Withdraw.Des1')"
-      :btn-click="btnClick" />
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, computed, nextTick } from "vue";
-import _ from "lodash";
-import DynamicForm from "./components/DynamicForm.vue";
-import { showToast } from "@/utils/toast";
-import { onLoad, onUnload } from '@dcloudio/uni-app'
-import useRouter from "@/hooks/useRouter";
-import { useI18n } from "vue-i18n";
-import { ucardApi } from "@/api/ucard";
-import useCardStore from "@/stores/use-card-store";
-import { useKeyboardScroll } from '@/hooks/useKeyboardScroll'
-
-const cardStore = useCardStore();
-import useUserStore from "@/stores/use-user-store";
-const userStore = useUserStore();
-const showSuccessPrompt = ref(false);
-const { t } = useI18n();
-const router = useRouter();
-const currency = ref()
-useKeyboardScroll()
-onLoad((options) => {
-  currency.value = options.currency
-})
-// Reactive variables
-const globalForm = ref({
-  transferAmount: null,
-  payoutCurrency: undefined,
-  payType: undefined,
-  payMethod: undefined,
-  deductionAccount: '',
-  amount: undefined,
-  receiver: undefined,
-  // Other fields go here
-});
-
-const businessForm = ref({});
-const feeNum = ref(0);
-const exchangeRateData = ref({});
-const form__error = ref('');
-const loginOptions = ref([]);
-const globalCurrenciesDropdown = ref([]);
-const receiverUserList = ref([]);
-const step2 = ref(false);
-const currencyList = ref([]);
-const globalCurrenciesField = ref([]);
-const globalFormRef = ref();
-
-// Computed properties for select lists
-const loginOptionsSelect = computed(() => {
-  return loginOptions.value
-});
-
-
-
-const currencyListSelect = computed(() => {
-  return currencyList.value.map((item: any) => ({
-    text: item.payoutCurrency,
-    value: item.payoutCurrency
-  }));
-});
-
-const transferTypeListSelect = computed(() => {
-  return transferTypeList.value.map((item: any) => ({
-    text: item.transferType,
-    value: item.transferTypeId
-  }));
-});
-
-const payoutMethodListSelect = computed(() => {
-  return payoutMethodList.value.map((item: any) => ({
-    text: item.payoutMethodValue,
-    value: item.payoutMethodId
-  }));
-});
-
-const transferTypeList = computed(() => {
-  return currencyList.value.find((item) => item.payoutCurrency === globalForm.value.payoutCurrency)?.types || [];
-});
-
-const payoutMethodList = computed(() => {
-  return transferTypeList.value.find((item) => item.transferTypeId === globalForm.value.payType)?.methods || [];
-});
-
-const currentBalance = computed(() => {
-  if (!globalForm.value.deductionAccount || !loginOptions.value.length) return 0;
-  const target = loginOptions.value.find((item) => item.value === globalForm.value.deductionAccount);
-  return target ? Number(target.balance) || 0 : 0;
-});
-
-const amountDisabled = computed(() => {
-  const { payoutCurrency, payType, payMethod } = globalForm.value;
-  return !payoutCurrency || !payType || !payMethod;
-});
-
-const receiverUserListSelect = computed(() => {
-  const map = new Map();
-  receiverUserList.value.forEach(item => {
-    const cardNumber = item.receiverBankAccountNumber;
-    if (!cardNumber) return;
-    if (!map.has(cardNumber)) {
-      map.set(cardNumber, {
-        cardNumber,
-        firstName: '',
-        lastName: '',
-        nativeFirstName: '',
-        nativeLastName: ''
-      });
-    }
-    const target = map.get(cardNumber);
-    if (!target.firstName && (item.receiverFirstName || item.receiverLastName)) {
-      target.firstName = item.receiverFirstName || '';
-      target.lastName = item.receiverLastName || '';
-    }
-    if (
-      !target.nativeFirstName &&
-      (item.receiverNativeFirstName || item.receiverNativeLastName)
-    ) {
-      target.nativeFirstName = item.receiverNativeFirstName || '';
-      target.nativeLastName = item.receiverNativeLastName || '';
-    }
-  });
-  const result = Array.from(map.values()).map(item => {
-    const enName = `${item.firstName} ${item.lastName}`.trim();
-    const nativeName = `${item.nativeFirstName} ${item.nativeLastName}`.trim();
-    let label = '';
-    if (enName && nativeName) {
-      label = `${enName}(${nativeName}) / ${item.cardNumber}`;
-    } else if (enName) {
-      label = `${enName} / ${item.cardNumber}`;
-    } else if (nativeName) {
-      label = `${nativeName} / ${item.cardNumber}`;
-    } else {
-      label = item.cardNumber;
-    }
-    return {
-      value: item.cardNumber,
-      text: label
-    };
-  });
-  return result
-});
-
-// Methods
-const changeLogin = (value: any) => {
-  if (globalForm.value.amount) {
-    globalExchangeRate()
-  }
-  globalForm.value.deductionAccount = value.value;
-  if (value.value) {
-    step2.value = true;
-  }
-};
-
-const handlePayoutCurrencyChange = (value: any) => {
-  globalForm.value.payoutCurrency = value.value;
-  selectOption1(1);
-};
-
-const handlePayTypeChange = (value: any) => {
-  globalForm.value.payType = value.value;
-  selectOption1(2);
-};
-
-const handlePayMethodChange = (value: any) => {
-  globalForm.value.payMethod = value.value;
-  selectOption1(3);
-};
-
-const handleAmountChange = (value: any) => {
-  globalForm.value.amount = value.value;
-  if (!value.value) return globalForm.value.transferAmount = 0
-  globalExchangeRate();
-};
-async function globalExchangeRate() {
-  feeNum.value = 0
-  const amount = Number(globalForm.value.amount)
-  // 校验金额是否填写
-  if (!amount) {
-    const msg = t("global.validator.v15")
-    // pigeon.MessageError(msg)
-    form__error.value = msg
-    return
-  }
-
-  const { usedQuota, yearTransferAmountQuota, maxQuota, minQuota } = exchangeRateData.value
-
-  // 金额格式校验
-  if (!/^(0|([1-9][0-9]*))(\.[\d]{1,2})?$/.test(amount)) {
-    const msg = t("global.validator.v15")
-    // pigeon.MessageError(msg)
-    form__error.value = msg
-    return
-  }
-
-  // 最小 / 最大额度校验
-  if (amount < minQuota || amount > maxQuota) {
-    const msg = t("global.validator.v14", { minQuota, maxQuota })
-    // pigeon.MessageError(msg)
-    form__error.value = msg
-    return
-  }
-
-  // 余额校验
-  if (currentBalance.value && amount > currentBalance.value) {
-    const msg = t("global.validator.balanceTip", {
-      balance: currentBalance.value,
-    })
-    // pigeon.MessageError(msg)
-    form__error.value = msg
-    return
-  }
-
-  // 年度额度校验
-  if (yearTransferAmountQuota) {
-    const add = _.add(usedQuota, amount)
-    if (add > yearTransferAmountQuota) {
-      const msg = t("global.GlobalOrder.rateTip")
-      // pigeon.MessageError(msg)
-      form__error.value = msg
-      return
-    }
-  }
-
-  form__error.value = ''
-
-  // 调接口
-  const res = await ucardApi.globalExchangeRate({
-    amount,
-    uniqueId: businessForm.value.uniqueId,
-    country: businessForm.value.fieldData.country,
-    payoutCurrency: businessForm.value.fieldData.payoutCurrency,
-    transferTypeId: businessForm.value.fieldData.transferTypeId,
-    payoutMethodId: businessForm.value.fieldData.payoutMethodId,
-  })
-  if (res.code === 200) {
-    businessForm.value.exchangeRate = res.data
-    form__error.value = ''
-
-    // 手续费 (deductionFee ÷ exchangeRate)
-    feeNum.value = divideNum(
-      res.data.deductionFee,
-      businessForm.value.fieldData.exchangeRate
-    )
-    // 回显转账金额
-    globalForm.value.transferAmount = res.data.transferAmount
-
-  } else {
-    // pigeon.MessageError(res.msg)
-  }
-}
-const divideNum = (quote, fee) => {
-  return _.floor(_.divide(quote, fee), 2);
-};
-
-
-const backActivity = () => {
-  // router.push({ path: "/card/index" });
-};
-
-const selectOption1 = async (type: number, e?: boolean) => {
-  if (type === 1 || type === 2) {
-    const list1 = transferTypeList.value;
-    if (list1.length === 1) {
-      globalForm.value.payType = list1[0].transferTypeId;
-    } else {
-      globalForm.value.payType = undefined;
-    }
-    const list2 = list1[0]?.methods || [];
-    if (list2.length === 1) {
-      globalForm.value.payMethod = list2[0].payoutMethodId;
-    } else {
-      globalForm.value.payMethod = undefined;
-    }
-  }
-
-  globalForm.value.amount = undefined;
-  feeNum.value = undefined;
-
-  fetchExchangeRateDebounced(type, e);
-};
-
-// 防抖函数,300ms 内多次触发只执行最后一次
-const fetchExchangeRateDebounced = _.debounce(async (type, e) => {
-  const { payoutCurrency, payType, payMethod } = globalForm.value;
-  if (globalForm.value.receiver && !e && type === 1) {
-    selectReceiver({ value: globalForm.value.receiver }, true)
-  }
-  if (!payoutCurrency || !payType || !payMethod) return;
-
-  const row = globalCurrenciesDropdown.value.filter(
-    (currency: any) =>
-      currency.payoutCurrency === payoutCurrency &&
-      currency.transferTypeId === payType &&
-      currency.payoutMethodId === payMethod
-  );
-
-  if (!row[0]) return;
-
-  businessForm.value = { ...businessForm.value, fieldData: row[0] };
-  getGlobalCurrenciesField(row[0]);
-
-  try {
-    const res = await ucardApi.globalExchangeRate({
-      uniqueId: businessForm.value.uniqueId,
-      country: row[0].country,
-      payoutCurrency: row[0].payoutCurrency,
-      transferTypeId: row[0].transferTypeId,
-      payoutMethodId: row[0].payoutMethodId,
-    });
-
-    if (res.code === 200) {
-      exchangeRateData.value = res.data;
-    }
-  } catch (error) {
-    console.error("Error fetching exchange rate:", error);
-  }
-}, 500); // 300ms 可根据需要调整
-
-const getGlobalCurrenciesField = async (row: any) => {
-  try {
-    const res = await ucardApi.globalCurrenciesField(row);
-    if (res.code === 200) {
-      setData(res.data || []);
-    }
-  } catch (error) {
-    console.error("Error fetching currencies field:", error);
-  }
-};
-
-const getSenderData = () => {
-  const { idType, idNumber } = businessForm.value;
-  const senderIdType =
-    idType === "PASSPORT"
-      ? "1"
-      : idType === "GOVERNMENT_ISSUED_ID_CARD"
-        ? "2"
-        : "";
-  const senderIdNumber =
-    idType === "PASSPORT"
-      ? idNumber
-      : idType === "GOVERNMENT_ISSUED_ID_CARD"
-        ? idNumber
-        : "";
-
-  return {
-    senderFirstName: businessForm.value.firstName,
-    senderLastName: businessForm.value.lastName,
-    senderGender: businessForm.value.gender,
-    senderIdType,
-    senderIdNumber,
-    senderNationality: businessForm.value.nationality,
-    senderIdIssueCountry: businessForm.value.senderIdIssueCountry,
-    senderDateOfBirth: businessForm.value.birthday,
-    senderCountry: businessForm.value.country == "CHN" || businessForm.value.country == "CN" ? '' : businessForm.value.country,
-    senderState: businessForm.value.senderState,
-    senderRegion: businessForm.value.senderRegion,
-    senderCity: businessForm.value.townEnName,
-    senderAddress: businessForm.value.address,
-    senderZipCode: businessForm.value.postCode,
-    senderMobileAreaCode: businessForm.value.areaCode,
-    senderMobileNumber: businessForm.value.mobile,
-    senderEmail: businessForm.value.email,
-    senderBeneficiaryRelationship: '3', // 付款人关系
-    senderOccupation: businessForm.value.occupation,
-    transferType: businessForm.value.fieldData.transferTypeId,
-    PayoutMethod: businessForm.value.fieldData.payoutMethodId,
-  };
-};
-function btnClick() {
-  showSuccessPrompt.value = false;
-  router.push({ path: "/pages/wallet/index" })
-}
-// Function to merge dynamic fields and sender data
-const setData = async (data: any) => {
-  const senderData = getSenderData();
-  //  console.log(senderData, 'senderData');
-
-  const mergedFields = await Promise.all(
-    data.map(async (field: any) => {
-      const { fieldName } = field;
-      const key = Object.keys(senderData).find(
-        (k) => k.toLowerCase() === fieldName.toLowerCase()
-      );
-      let fixedValue = key ? senderData[key] : field.fixedValue;
-      //  console.log(key, fixedValue, 1222222);
-
-      if (fieldName === "receiverBankCity") {
-        try {
-          const res = await ucardApi.globalQueryBankCities({
-            payoutCurrency: businessForm.value.fieldData.payoutCurrency,
-            country: businessForm.value.fieldData.country,
-          });
-
-          if (res.code === 200 && Array.isArray(res.data)) {
-            field.availableDtos = res.data.map((item: any) => ({
-              value: item.bankCitiesValue,
-              valueId: item.bankCitiesKey,
-            }));
-          }
-        } catch (e) {
-          console.error("Error loading receiverBankCity data:", e);
-        }
-      }
-      // 如果币种为 CNY,且字段是 senderIdType,则从下拉数据中移除 valueId 为 "2" 的选项
-      if (
-        fieldName === "senderIdType" &&
-        businessForm.value.fieldData &&
-        businessForm.value.fieldData.payoutCurrency === "CNY" &&
-        Array.isArray(field.availableDtos)
-      ) {
-        field.availableDtos = field.availableDtos.filter(
-          (item) => String(item.valueId) !== "2"
-        );
-        // 如果当前固定值是被移除的 valueId,则清空以避免不可用的默认选中
-        if (String(fixedValue) === "2") {
-          fixedValue = null;
-        }
-        if (String(field.fixedValue) === "2") {
-          field.fixedValue = null;
-        }
-      }
-      if (
-        fieldName === "senderIdNumber" &&
-        businessForm.value.fieldData &&
-        businessForm.value.fieldData.payoutCurrency === "CNY"
-      ) {
-        // 如果当前固定值是被移除的 valueId,则清空以避免不可用的默认选中
-        fixedValue = ''
-      }
-      // Handle select fields
-      if (field.fieldType === "select") {
-        let rValue = globalForm.value[fieldName] || fixedValue;
-        const label = field.availableDtos?.find(
-          (item: any) => item.valueId === rValue
-        ) ?? null;
-        fixedValue = label?.valueId || fixedValue;
-        globalForm.value[fieldName + "Value"] = label?.value ?? null;
-        globalForm.value[fieldName] = fixedValue;
-        //  console.log(field, fixedValue, 'select field');
-
-      }
-      return { ...field, fixedValue };
-    })
-  );
-  globalCurrenciesField.value = mergedFields;
-};
-// 选择的收款人
-const selectReceiver = (a, isCurrencyChange = false) => {
-  const cardNumber = a.value;
-  if (!cardNumber) return;
-  const sameCardList = receiverUserList.value.filter(
-    (item) => item.receiverBankAccountNumber === cardNumber
-  );
-  const receiverFields = cardStore.globalFieldParams.filter(item => item.fieldUserType === 'receiver' && !['transferType', 'payoutMethod', 'payoutCurrency'].includes(item.fieldName)).map(item => item.fieldName)
-  if (!sameCardList.length) {
-    receiverFields.forEach(field => {
-      globalForm.value[field] = undefined;
-      const valueKey = field + 'Value';
-      globalForm.value[valueKey] = undefined;
-    });
-    return;
-  }
-
-  const { payoutCurrency, payType, payMethod } = globalForm.value;
-  let matchingData = null;
-  if (payoutCurrency && payType && payMethod) {
-    matchingData = sameCardList.find(
-      (item) =>
-        item.payoutCurrency === payoutCurrency &&
-        String(item.payoutMethod) === String(payMethod) &&
-        String(item.transferType) === String(payType)
-    );
-  }
-  if (!matchingData) {
-    if (isCurrencyChange) {
-      receiverFields.forEach(field => {
-        globalForm.value[field] = undefined;
-        const valueKey = field + 'Value';
-        globalForm.value[valueKey] = undefined;
-      });
-      return;
-    }
-    matchingData = sameCardList[0];
-    if (matchingData) {
-      if (!isCurrencyChange) {
-        globalForm.value.payoutCurrency = matchingData.payoutCurrency;
-        globalForm.value.payType = String(matchingData.transferType);
-        globalForm.value.payMethod = String(matchingData.payoutMethod);
-        selectOption1(3, true);
-      }
-    }
-  } else {
-    if (!isCurrencyChange) {
-      selectOption1(3, true);
-    }
-  }
-
-  if (!matchingData) return;
-  receiverFields.forEach(field => {
-    globalForm.value[field] = matchingData[field];
-  });
-};
-const getGlobalCurrenciesDropdown = () => {
-  const res = cardStore.currencyList;
-  globalCurrenciesDropdown.value = res || [];
-  const data = _.cloneDeep(res);
-  const payoutCurrencies = [...new Set(data.map((item: any) => item.payoutCurrency))];
-  const array = payoutCurrencies.map((item) => {
-    let list = data.filter((item2: any) => item === item2.payoutCurrency);
-    let transferTypes = [...new Set(list.map((item: any) => item.transferTypeValue))];
-    const types = transferTypes.map((type) => {
-      const cur = list.find((item2: any) => item2.transferTypeValue === type);
-      let list2 = list
-        .filter((item2: any) => item2.transferTypeValue === type)
-        .map((item2: any) => ({
-          payoutMethodId: item2.payoutMethodId,
-          payoutMethodValue: item2.payoutMethodValue,
-        }));
-      return { transferType: type, transferTypeId: cur.transferTypeId, methods: list2 };
-    });
-    return { payoutCurrency: item, types };
-  });
-  currencyList.value = array;
-  globalForm.value.payoutCurrency = currency.value
-};
-
-// 提交订单
-const saveDlobal = async () => {
-  const isValid = await globalFormRef.value.validateForm();
-  if (!isValid) {
-    return;
-  }
-  try {
-    if (!globalForm.value.amount) {
-      showToast(t("global.validator.v15"));
-      return;
-    }
-    if (form__error.value) {
-      showToast(form__error.value);
-      return
-    }
-    if (!globalForm.value.deductionAccount) {
-      showToast(t('placeholder.choose'));
-      return;
-    }
-    const [cardNumber, deductionAccountType] = globalForm.value.deductionAccount.split(",");
-    const otherData = {};
-    globalCurrenciesField.value
-      .map((item) => ({
-        fieldName: item.fieldName,
-        fieldType: item.fieldType,
-      }))
-      .forEach((item) => {
-        otherData[item.fieldName] = globalForm.value[item.fieldName];
-        if (item.fieldType === "select") {
-          const key = item.fieldName + 'Value';
-          otherData[key] = globalForm.value[key];
-        }
-      });
-
-    const params = {
-      ...otherData,
-      cardNumber,
-      amount: globalForm.value.amount,
-      deductionAccountType,
-      uniqueId: businessForm.value.uniqueId,
-      ...businessForm.value.exchangeRate,
-    };
-    const res = await ucardApi.globalOrdersCreate({ ...params });
-    if (res.code === 200) {
-      showSuccessPrompt.value = true;
-    } else {
-      showToast(res.msg);
-    }
-  } catch (error: any) {
-    console.error("Error submitting order:", error);
-    showToast(error.message || t('common.error'));
-  }
-};
-
-// 收款人list
-const globalReceiverUserList = async ({ uniqueId }: any) => {
-  try {
-    const res = await ucardApi.globalReceiverUserList({ uniqueId });
-    if (res.code === 200) {
-      receiverUserList.value = res.data;
-    } else {
-      showToast(res.msg);
-    }
-  } catch (error) {
-    console.error("Error fetching receiver list:", error);
-    showToast(t('common.error'));
-  }
-};
-
-// 付款账户下拉
-const getAccountDropdown = async () => {
-  try {
-    const res = await ucardApi.cardAccountDropdown();
-    if (res.code === 200) {
-      loginOptions.value = res.data.map((item: any) => {
-
-        if (item.type === "1") {
-          item.text = `${t("global.GlobalOrder.cardNumber")} - ${item.cardNumber} ${t("global.GlobalOrder.bal")}: ${item.balance}`;
-        } else {
-          item.text = `${t("global.GlobalOrder.bagBal")}: ${item.balance}`;
-        }
-        item.value = `${item.cardNumber},${item.type}`;
-        item.disabled = item.balance === 0;
-        return item;
-      });
-    } else {
-      showToast(res.msg);
-    }
-  } catch (error) {
-    console.error("Error fetching account dropdown:", error);
-    showToast(t('common.error'));
-  }
-};
-// 付款账户下拉
-const globalUserDetails = async () => {
-  try {
-    const res = await ucardApi.globalUserDetails();
-    if (res.code === 200) {
-      businessForm.value = res.data;
-    }
-    //  console.log(res.data);
-
-  } catch (error) {
-    console.error("Error fetching account dropdown:", error);
-    showToast(t('common.error'));
-  }
-};
-
-
-onMounted(async () => {
-  await globalUserDetails();
-  await getAccountDropdown();
-  getGlobalCurrenciesDropdown();
-  globalReceiverUserList(businessForm.value);
-});
-</script>
-
-<style lang="scss" scoped>
-@import "@/uni.scss";
-
-.form-section {
-  margin-bottom: px2rpx(20);
-}
-
-.section-title {
-  font-size: px2rpx(16);
-  font-weight: bold;
-  margin-bottom: px2rpx(15);
-  display: block;
-}
-
-.form-item {
-  margin-bottom: px2rpx(15);
-}
-
-.form-label {
-  font-size: var(--font-size-16);
-  line-height: px2rpx(24);
-  letter-spacing: px2rpx(1);
-  color: #474747;
-  margin-bottom: px2rpx(4);
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-  display: flex;
-  align-items: center;
-
-  .required-mark {
-    color: red;
-  }
-}
-
-.quota-tip {
-  font-size: px2rpx(12);
-  color: #999;
-  margin-left: px2rpx(5);
-
-}
-
-.form-error {
-  color: #ff0000;
-  font-size: px2rpx(12);
-  margin-top: px2rpx(5);
-  display: block;
-}
-
-.fee-text {
-  font-size: px2rpx(12);
-  color: #666;
-  margin-top: px2rpx(5);
-  display: block;
-}
-
-.tips-section {
-  margin: px2rpx(20) 0;
-}
-
-.tips {
-  background-color: #f5f5f5;
-  padding: px2rpx(15);
-  border-radius: px2rpx(8);
-}
-
-.tips .title {
-  font-weight: bold;
-  margin-bottom: px2rpx(16);
-  display: block;
-
-}
-
-.tips text {
-  display: block;
-  margin-bottom: px2rpx(10);
-  font-size: px2rpx(13);
-  color: #666;
-  line-height: px2rpx(20);
-}
-
-.submit-section {
-  margin: px2rpx(20) 0;
-}
-
-.submit-btn {
-  width: 100%;
-}
-</style>

+ 0 - 489
pages/wallet/index.vue

@@ -1,489 +0,0 @@
-<template>
-  <cwg-page-wrapper :isHeaderFixed="true">
-    <cwg-header class="wallet-header" :title="t('wallet1.title')"
-      backgrounds="hhh" />
-    <view class="page">
-
-      <view class="wallet-banner">
-        <view class="balance">
-          <view class="balance-item">
-            <view class="r l" @click="setModelValue1">
-              <image :src="imageSrc(balance)" alt="" srcset="" />
-              <text>{{ balance }}</text>
-              <cwg-icon name="icon_dropdown" :size="24" />
-            </view>
-            <view class="r">
-              <text>$ {{ currencyList[0]?.amount }}</text>
-              <text class="decimal">{{ currencyList[0]?.decimal }}</text>
-            </view>
-          </view>
-        </view>
-      </view>
-
-      <view class="wallet-actions">
-        <view class="cwg-button two-btn">
-          <u-button type="primary" block @click="goToVaultody">{{ t('pages.wallet.vaultody') }}</u-button>
-          <u-button plain block class="prev-btn" @click="goToWithdraw">{{ t('pages.wallet.withdraw') }}</u-button>
-        </view>
-      </view>
-      <view class="wallet-page">
-        <view class="global-title">{{ t("global.title1") }}</view>
-        <view class="global-con">
-          <view class="global-con-l">
-            <image src="/static/images/currency/USD.png" alt="" srcset="" />
-            <view class="r">
-              <view>USD</view>
-            </view>
-          </view>
-          <cwg-icon name="icon_transfer" :size="23" color="#1a1a1a" />
-          <view class="global-con-r" @click="setModelValue">
-            <image :src="imageSrc(currency)" alt="" srcset="" />
-            <view class="r">
-              <view>{{ currency }}</view>
-            </view>
-            <cwg-icon name="icon_dropdown" :size="24" />
-          </view>
-        </view>
-        <view class="cwg-button">
-          <u-button type="primary" block @click="goToGlobalRemit">{{
-            t("global.title1")
-          }}</u-button>
-        </view>
-        <view class="trans-header">
-          <view class="record-title">{{ t("global.title") }} </view>
-
-          <view class="all" @click="goRechargeRecord">{{
-            t("card.Status.t22")
-          }}</view>
-
-        </view>
-
-
-        <view class="transaction-list">
-          <template v-if="globalOrdersList.length > 0">
-            <view v-for="item in globalOrdersList" :key="item.id" class="transaction-item"
-              @click="goToDeductionDetail(item)">
-              <view class="transaction-left">
-                <view class="transaction-icon">
-                  <text class="icon-text"><cwg-icon name="icon_transfer" :size="23" color="#1a1a1a" /></text>
-                </view>
-                <view class="transaction-info">
-                  <text class="transaction-status">{{ item.merchantOrderNo }}</text>
-                  <text class="transaction-time">{{ item.addTime }}</text>
-                </view>
-              </view>
-
-              <view class="transaction-right">
-                <text class="transaction-amount">{{ item.deductionAmount }} {{ item.sendCurrency }}</text>
-              </view>
-            </view>
-          </template>
-          <cwg-empty-state v-if="globalOrdersList.length == 0" />
-        </view>
-      </view>
-      <cwg-currency-select v-model="modelValue" :show-search="true" :options="globalCurrenciesDropdown"
-        @select="changeSelect" :placeholder="t('common.country')" />
-      <cwg-currency-select v-model="modelValue1" :show-search="true" :options="globalCurrenciesDropdown"
-        @select="changeSelect1" />
-    </view>
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, onMounted, watch, computed } from "vue";
-import { showToast } from "@/utils/toast";
-import { onLoad } from '@dcloudio/uni-app'
-import useRouter from "@/hooks/useRouter";
-import { useI18n } from "vue-i18n";
-import { ucardApi } from "@/api/ucard";
-import _ from "lodash";
-import useCardStore from "@/stores/use-card-store";
-const cardStore = useCardStore();
-const { t } = useI18n();
-const router = useRouter();
-onLoad((options) => {
-  // id.value = options.id
-  // type.value = options.type
-})
-const currency = ref("EUR");
-const balance = ref("USD");
-const modelValue = ref(false);
-const modelValue1 = ref(false);
-const currencyList = ref([]);
-const allAmount = ref(0);
-async function getBalance() {
-  try {
-    const res = await ucardApi.walletBalance();
-    const n = Number.parseFloat(res.data.balance).toFixed(2);
-    const { amount, decimal } = splitNumber(n);
-
-    allAmount.value = n;
-    currencyList.value.push({
-      name: "USD",
-      amount,
-      decimal,
-    });
-  } catch (error) { }
-}
-async function getGlobalFieldParams() {
-  try {
-    const res = await ucardApi.getGlobalFieldParams();
-    const sorted = res.data
-      .sort((a, b) => {
-        return (a.sorting || 0) - (b.sorting || 0);
-      }).map((item) => {
-        return { fieldUserType: item.fieldUserType, fieldName: item.fieldName, fieldType: item.fieldType }
-      });
-    cardStore.saveGlobalFieldParams(sorted);
-  } catch (error) { }
-}
-function imageSrc(currency: string) {
-  return `/static/images/currency/${currency}.png`;
-}
-const goToDeductionDetail = (record: RecordItem) => {
-  console.log(record, 1212);
-  cardStore.saveOrderDetail(record);
-  router.push({
-    path: '/pages/wallet/global-detail',
-    query: { id: record.id }
-  });
-};
-
-function splitNumber(n) {
-  if (
-    n === undefined ||
-    n === null ||
-    n === 0 ||
-    (typeof n !== "number" && typeof n !== "string") ||
-    (typeof n === "string" && !/^\d+(\.\d+)?$/.test(n))
-  ) {
-    return { amount: 0, decimal: "" };
-  }
-  const str = n.toString();
-  if (!str.includes(".")) {
-    return { amount: str, decimal: "" };
-  }
-  const [int, dec] = str.split(".");
-  return {
-    amount: `${int}.`,
-    decimal: dec || "",
-  };
-}
-
-function setModelValue() {
-  modelValue.value = true;
-}
-function setModelValue1() {
-  return;
-  //   modelValue1.value = true
-
-}
-function goRechargeRecord() {
-  router.push(`/pages/wallet/global-list`);
-}
-function goToGlobalRemit() {
-  router.push(
-    `/pages/wallet/global-order?currency=${currency.value}`
-  );
-}
-function goToVaultody() {
-  router.push(`/pages/wallet/vaultody`);
-}
-function goToWithdraw() {
-  router.push(`/pages/wallet/withdraw?allAmount=${allAmount.value}`);
-}
-function changeSelect(e) {
-  currency.value = e.value;
-}
-function changeSelect1(e) {
-  balance.value = e.value;
-}
-const globalCurrenciesDropdown = ref([]);
-const getGlobalCurrenciesDropdown = async () => {
-  const res = await ucardApi.globalCurrenciesDropdown({ code: "", status: 'online' });
-  if (res.code === 200 || res.code === 0) {
-    globalCurrenciesDropdown.value = res.data.map((i) => {
-      return { currency: i.payoutCurrency, text: i.country, value: i.payoutCurrency };
-    }) || [];
-    const data = _.cloneDeep(res.data);
-    cardStore.saveCurrencyList(data)
-  }
-};
-const globalOrdersList = ref<TransferInfo[]>([]);
-async function getGlobalOrdersList() {
-  try {
-    const res = await ucardApi.globalOrdersList({ page: { current: 1, row: 5 } });
-    if (res.code === 200) {
-      globalOrdersList.value = res.data;
-    } else {
-      globalOrdersList.value = [];
-    }
-  } catch (error) {
-    showToast(t("common.error"));
-  }
-}
-function goToTransferDetail(id: string) {
-  router.push(`/transfer/detail?id=${id}`);
-}
-onMounted(() => {
-  getGlobalCurrenciesDropdown()
-  getGlobalOrdersList()
-  getBalance();
-  getGlobalFieldParams()
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page-wrapper {
-  padding-left: 0 !important;
-  padding-right: 0 !important;
-  border: 0 !important;
-}
-
-.page {
-  box-sizing: border-box;
-  background: var(--main-bg);
-}
-
-.wallet-page {
-  padding: 0 px2rpx(24);
-  box-sizing: border-box;
-}
-
-.wallet-header {
-  // position: relative;
-  // background: linear-gradient(90deg, #ea002a 0%, #eb4e6b 100%);
-  // z-index: 1113;
-}
-
-.banner-title {
-  color: #fff;
-  font-family: Roboto;
-  font-size: px2rpx(22);
-  font-style: normal;
-  font-weight: 600;
-  line-height: px2rpx(28);
-  padding: px2rpx(12) 0 px2rpx(31) 0;
-}
-
-.wallet-banner {
-  background: linear-gradient(90deg, #ea002a 0%, #eb4e6b 100%);
-  margin-bottom: px2rpx(20);
-  padding: 0 px2rpx(31) px2rpx(62) px2rpx(31);
-  color: #fff;
-
-  .balance {
-    display: flex;
-    width: 100%;
-    justify-content: space-between;
-    align-items: center;
-  }
-
-  .balance-item {
-    width: 100%;
-    display: flex;
-    padding: px2rpx(16) px2rpx(24);
-    justify-content: center;
-    align-items: center;
-    gap: px2rpx(31);
-    border-radius: px2rpx(8);
-    border: 1px solid var(--Netural-color-content-color-stoke, #f4f4f4);
-    background: #fff;
-    color: var(--white);
-    flex-direction: column;
-
-    .r {
-      display: flex;
-      justify-content: center;
-      align-items: flex-end;
-    }
-
-    .l {
-      align-items: center;
-    }
-
-    text {
-      color: #000;
-      font-family: Roboto;
-      font-size: px2rpx(44);
-      font-style: normal;
-      font-weight: 600;
-      text-align: left;
-    }
-
-    .decimal {
-      color: #1a1a1a;
-      font-family: Roboto;
-      font-size: px2rpx(14);
-      font-style: normal;
-      font-weight: 600;
-      letter-spacing: px2rpx(0.07);
-    }
-
-    .l {
-      text {
-        color: #474747;
-        font-size: px2rpx(31);
-        line-height: px2rpx(44);
-      }
-    }
-
-    image {
-      width: px2rpx(28);
-      height: px2rpx(28);
-      margin-right: px2rpx(12);
-      display: inline-block;
-    }
-  }
-}
-
-.global-title {
-  margin: px2rpx(44) 0 px2rpx(36) 0;
-  color: #000;
-  font-family: Roboto;
-  font-size: px2rpx(22);
-  font-style: normal;
-  font-weight: 600;
-  line-height: px2rpx(28);
-}
-
-.global-con {
-  display: flex;
-  width: 100%;
-  margin: px2rpx(44) 0;
-  align-items: center;
-  gap: px2rpx(12);
-  color: #1a1a1a;
-
-  .global-con-l,
-  .global-con-r {
-    display: flex;
-    flex: 1;
-    padding: px2rpx(12) px2rpx(8);
-    align-items: center;
-    gap: px2rpx(6);
-    border-radius: px2rpx(12);
-    box-shadow: 0px px2rpx(10) px2rpx(30) 0px rgba(5, 0, 1, 0.1);
-    color: var(--white);
-
-    view {
-      color: #000;
-      font-family: Roboto;
-      font-size: px2rpx(24);
-      font-style: normal;
-      font-weight: 600;
-      line-height: px2rpx(44);
-    }
-
-    image {
-      width: px2rpx(36);
-      height: px2rpx(36);
-      border: 1px solid #f4f4f4;
-      border-radius: 50%;
-    }
-  }
-}
-
-.trans-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-}
-
-.record-title {
-  margin: px2rpx(44) 0 px2rpx(44) 0;
-  color: #000;
-  font-family: Roboto;
-  font-size: px2rpx(22);
-  font-style: normal;
-  font-weight: 600;
-  line-height: px2rpx(28);
-}
-
-.transaction-list {
-  display: flex;
-  flex-direction: column;
-
-  .transaction-item {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: px2rpx(16) 0;
-    border-bottom: 1px solid #f3f4f6;
-  }
-
-  .transaction-item:last-child {
-    border-bottom: none;
-  }
-
-  .transaction-left {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(12);
-  }
-
-  .transaction-icon {
-    width: px2rpx(40);
-    height: px2rpx(40);
-    background-color: #f9fafb;
-    border-radius: 50%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-
-  .icon-text {
-    font-size: px2rpx(20);
-    color: #6b7280;
-  }
-
-  .transaction-info {
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(4);
-  }
-
-  .transaction-status {
-    font-size: px2rpx(14);
-    color: #111827;
-  }
-
-  .transaction-time {
-    font-size: px2rpx(12);
-    color: #9ca3af;
-  }
-
-  .transaction-right {
-    display: flex;
-    flex-direction: column;
-    align-items: flex-end;
-  }
-
-  .transaction-amount {
-    font-size: px2rpx(16);
-    font-weight: 600;
-    color: #111827;
-  }
-
-  .transaction-amount.negative {
-    color: #ef4444;
-  }
-}
-
-.wallet-actions {
-  padding: px2rpx(16) px2rpx(24);
-}
-
-.wallet-actions .two-btn {
-  display: flex;
-  gap: px2rpx(16);
-}
-
-.wallet-actions .prev-btn {
-  border: 1px solid var(--main-yellow) !important;
-  color: #fff !important;
-  background: transparent;
-}
-</style>

+ 0 - 258
pages/wallet/vaultody-list.vue

@@ -1,258 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="bank-transaction-page">
-            <view class="filters-container" :style="{ top: statusBarHeight + 53 + 'px' }">
-                <view class="filter-item">
-                    <text class="filter-label">{{ t('card.Form.f45') }}</text>
-                    <cwg-filter-select v-model="statusFilterIndex" :options="statusOptions" />
-                </view>
-                <view class="filter-item">
-                    <text class="filter-label">{{ t('card.Form.f43') }}</text>
-                    <cwg-filter-picker v-model="dateFilter"></cwg-filter-picker>
-                </view>
-                <view class="reset-btn" @click="resetFilters">
-                    <uni-icons type="loop" size="16" color="#2563eb" />
-                </view>
-            </view>
-            <view class="content">
-                <VaultodyList ref="globalListRef" :cardNumber="cardNumber" :payoutCurrency="payoutCurrency"
-                    :statusIndex="statusFilterIndex" :dateFilter="dateFilter" />
-            </view>
-        </view>
-    </cwg-page-wrapper>
-
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch } from 'vue';
-import { onLoad } from '@dcloudio/uni-app';
-import { useI18n } from 'vue-i18n';
-import useGlobalStore from '@/stores/use-global-store';
-import VaultodyList from './components/VaultodyList.vue';
-import { vaultodyStatusText } from '@/utils/dataMap';
-const globalStore = useGlobalStore()
-const statusBarHeight = computed(() => globalStore.statusBarHeight);
-const { t } = useI18n();
-const cardNumber = ref('');
-onLoad((options) => {
-    cardNumber.value = options.cardNumber || '';
-});
-
-const statusOptions = computed(() => {
-    return vaultodyStatusText
-});
-const payoutCurrency = ref();
-const statusFilterIndex = ref(-1);
-const dateFilter = ref([]);
-
-const resetFilters = () => {
-    payoutCurrency.value = '';
-    statusFilterIndex.value = -1;
-    dateFilter.value = [];
-};
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page-wrapper {
-    padding: 0;
-    border: 0;
-}
-
-.bank-transaction-page {
-    // background-color: #f9fafb;
-}
-
-.wallet-header {
-    background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-}
-
-/* Header */
-.header {
-    background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-    padding: px2rpx(16);
-    padding-bottom: px2rpx(20);
-}
-
-.header-content {
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(16);
-}
-
-.header-title {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(8);
-}
-
-.title-text {
-    color: #ffffff;
-    font-size: px2rpx(20);
-}
-
-.stats-container {
-    display: flex;
-    gap: px2rpx(12);
-}
-
-.stat-card {
-    flex: 1;
-    background-color: rgba(255, 255, 255, 0.15);
-    backdrop-filter: blur(px2rpx(10));
-    border-radius: px2rpx(12);
-    padding: px2rpx(12);
-}
-
-.stat-header {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(6);
-    margin-bottom: px2rpx(8);
-}
-
-.icons {
-    width: px2rpx(20);
-    height: px2rpx(20);
-}
-
-.stat-label {
-    font-size: px2rpx(12);
-    color: rgba(255, 255, 255, 0.9);
-}
-
-.stat-value {
-    font-size: px2rpx(20);
-    color: #ffffff;
-    display: block;
-    margin-bottom: px2rpx(4);
-}
-
-.stat-count {
-    font-size: px2rpx(11);
-    color: rgba(255, 255, 255, 0.8);
-}
-
-/* Tabs */
-.tabs-container {
-    background-color: #ffffff;
-    display: flex;
-    border-bottom: 1px solid #e5e7eb;
-    position: sticky;
-    top: 0;
-    z-index: 10;
-}
-
-.tab-item {
-    flex: 1;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: px2rpx(6);
-    padding: px2rpx(16);
-    position: relative;
-    transition: all 0.3s;
-}
-
-.tab-text {
-    font-size: px2rpx(15);
-    color: #9ca3af;
-    transition: color 0.3s;
-}
-
-.tab-text-active {
-    color: #2563eb;
-}
-
-.tab-indicator {
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    height: px2rpx(3);
-    background-color: #2563eb;
-    border-radius: px2rpx(3) px2rpx(3) 0 0;
-}
-
-/* Content */
-.content {
-    padding: 0;
-}
-
-.filters-container {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(8);
-    padding: px2rpx(12) px2rpx(16);
-    background-color: #ffffff;
-    position: sticky;
-    top: 0;
-    z-index: 10;
-    // overflow-x: auto;
-    -webkit-overflow-scrolling: touch;
-}
-
-.filter-item {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    flex-shrink: 0;
-    min-width: 0;
-}
-
-.filter-label {
-    font-size: px2rpx(12);
-    color: #6b7280;
-    white-space: nowrap;
-    flex-shrink: 0;
-}
-
-.filter-picker {
-    background-color: #ffffff;
-    border: 1px solid #e5e7eb;
-    border-radius: px2rpx(8);
-    padding: px2rpx(6) px2rpx(8);
-    display: flex;
-    align-items: center;
-    min-width: px2rpx(60);
-    max-width: px2rpx(120);
-    flex-shrink: 1;
-}
-
-.picker-value {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    width: 100%;
-    min-width: 0;
-}
-
-.picker-text {
-    flex: 1;
-    min-width: 0;
-    font-size: px2rpx(12);
-    color: #111827;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.picker-icon {
-    flex-shrink: 0;
-    width: px2rpx(14);
-    height: px2rpx(14);
-}
-
-.reset-btn {
-    background-color: #ffffff;
-    border: 1px solid #e5e7eb;
-    border-radius: px2rpx(8);
-    padding: px2rpx(6) px2rpx(10);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-shrink: 0;
-    min-width: px2rpx(36);
-}
-</style>

+ 0 - 185
pages/wallet/vaultody.vue

@@ -1,185 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="page">
-            <u-form ref="formRef" :rules="rules" :model="form" class="payment-form">
-                <cwg-input v-model:value="form.blockchain" fkey="blockchain" type="select" :required="true"
-                    :columns="blockchainList" :label="t('Blockchain.addP2')" rulesKey="blockchain"
-                    @change="handleChange" />
-                <cwg-input v-if="text1" v-model:value="text1" fkey="text1" type="text" :label="t('Blockchain1.p2')"
-                    :readonly="true" :disabled="true" />
-            </u-form>
-
-            <QrCode v-if="text1" :text="text1"></QrCode>
-
-            <view class="fixed-btn">
-                <view v-if="!text1" class="cwg-button ok-button">
-                    <u-button type="primary" block @click="getVaultodyAddress">{{
-                        t("Blockchain1.p3")
-                        }}</u-button>
-                </view>
-                <view v-else class="cwg-button ok-button">
-                    <u-button type="primary" block @click="cardCopy">{{
-                        t("Blockchain1.p4")
-                        }}</u-button>
-                </view>
-            </view>
-        </view>
-    </cwg-page-wrapper>
-</template>
-<script setup lang="ts">
-import { ref, onMounted, computed } from "vue";
-import { showToast } from "@/utils/toast";
-import { useI18n } from "vue-i18n";
-import { ucardApi } from "@/api/ucard";
-import useUserStore from "@/stores/use-user-store";
-import QrCode from "@/components/QrCode.vue";
-import { Validators } from "@/utils/validators";
-const { t } = useI18n();
-const userStore = useUserStore();
-const userInfo = computed(() => userStore.userInfo);
-const formRef = ref();
-const form = ref<{
-    emailCode: string;
-    cardNumber?: string;
-    password?: string;
-    country?: string;
-    email?: string;
-}>({
-    blockchain: "",
-});
-const text1 = ref("");
-const blockchainList = ref([]);
-// 表单验证规则
-const rules = {
-    blockchain: [Validators.required(t("Blockchain.addP2"))],
-    address: [Validators.required(t("WalletApply.p2"))],
-    amount: [
-        Validators.required(t("global.validator.v15"))
-    ],
-};
-// 初始化表单
-function initForm() {
-    if (userInfo.value) {
-        const a = { uniqueId: userInfo.value.uniqueId, country: userInfo.value.country, email: userInfo.value.email }
-        if (userInfo.value) {
-            form.value = {
-                ...a,
-            };
-        }
-    }
-}
-
-//生成支付地址
-async function getVaultodyAddress() {
-    try {
-        await formRef.value?.validate();
-        let res = await ucardApi.getVaultodyAddress({
-            ...form.value,
-        });
-        if (res.code == 200) {
-            text1.value = res.data;
-        } else {
-            text1.value = "";
-            showToast(res.msg);
-        }
-    } catch (error) {
-        console.log(error, 1111);
-
-    }
-}
-//获取区块链
-async function getBlockchainDropdown() {
-    let res = await ucardApi.getBlockchainDropdown({
-        ...form.value,
-    });
-    if (res.code == 200) {
-        res.data.map((item: any) => {
-            item.text = item.alias;
-            item.value = item.blockchain;
-        });
-        blockchainList.value = res.data;
-    } else {
-        blockchainList.value = []
-        showToast(res.msg);
-    }
-}
-
-// 表单字段变化
-function handleChange(value: any) {
-    if (value.key === "emailCode") {
-        form.value.emailCode = value.value;
-    }
-}
-
-
-// 复制 CVV
-function cardCopy() {
-    let title = t("card.Msg.m8");
-    uni.setClipboardData({
-        data: text1.value,
-        success: () => {
-            uni.showToast({
-                title,
-            });
-        },
-    });
-}
-onMounted(() => {
-    initForm();
-    getBlockchainDropdown();
-});
-</script>
-
-<style lang="scss" scoped>
-@import "@/uni.scss";
-
-.no-button {
-    width: 100%;
-    margin: px2rpx(12) 0;
-
-    .u-button {
-        background-color: #ffbdc8 !important;
-    }
-}
-
-.ok-button {
-    margin: px2rpx(4) 0;
-    /* background-color: #EA002A; */
-}
-
-
-.code-input-label {
-    font-size: var(--font-size-16);
-    line-height: px2rpx(44);
-    letter-spacing: px2rpx(1);
-    color: #474747;
-}
-
-.code-input-wrapper {
-    position: relative;
-    display: flex;
-    align-items: center;
-}
-
-.code-input {
-    flex: 1;
-}
-
-.get-code-btn {
-    min-width: px2rpx(100);
-    margin-bottom: px2rpx(12);
-    margin-left: px2rpx(10);
-
-    .cwg-button .u-button {
-        border-radius: px2rpx(8);
-    }
-}
-
-.submit-section {
-    margin: px2rpx(20) 0;
-}
-
-.submit-btn {
-    width: 100%;
-}
-</style>

+ 0 - 633
pages/wallet/withdraw-detail.vue

@@ -1,633 +0,0 @@
-<template>
-  <cwg-page-wrapper>
-    <view class="order-detail-page">
-      <view class="content">
-        <view class="section-card">
-          <view class="success-icon-wrap">
-            <image v-if="detailData.transactionStatus == 3" src="/static/images/vector.png" alt="" mode="widthFix" />
-            <image v-else-if="detailData.transactionStatus == 4 || detailData.transactionStatus == 5"
-              src="/static/images/vector2.png" alt="" mode="widthFix" />
-            <image v-else src="/static/images/vector3.png" alt="" mode="widthFix" />
-            <text class="success-text">{{ t(withdrawStatus[detailData.transactionStatus]) }}</text>
-            <text v-if="approveDesc" class="success-text">{{ approveDesc }}</text>
-          </view>
-        </view>
-
-        <view class="section-card">
-          <view class="section-header">
-            <uni-icons type="wallet" size="18" color="#2563eb" />
-            <text class="section-title">{{ t('Ib.Report.Title3') }}</text>
-          </view>
-          <view class="info-list">
-            <view class="info-row" v-if="detailData.merchantOrderNo">
-              <text class="info-label">{{ t('card.Form.f35') }}</text>
-              <view class="info-value-wrapper">
-                <text class="info-value">{{ detailData.merchantOrderNo }}</text>
-                <cwg-icon name="copy" :size="14" color="#9ca3af" @click.stop="copyOrderNo" />
-              </view>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('WalletApply.p3') }}</text>
-              <text class="info-value amount-highlight">
-                {{ detailData.amount }} USDT
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f31') }}</text>
-              <text class="info-value">
-                {{ detailData.receivedAmount || '0' }}
-                <text class="currency">{{ detailData.receivedCurrency }}</text>
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('WalletApply.p8') }}</text>
-              <text class="info-value">
-                {{ detailData.contractAddress }}
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('WalletApply.p9') }}</text>
-              <text class="info-value">
-                {{ detailData.fromAddress }}
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('WalletApply.p1') }}</text>
-              <text class="info-value">
-                {{ formatOrderNo(detailData.address) }}
-                <cwg-icon class="footer-order-icon" name="copy" :size="14" color="#9ca3af"
-                  @click.stop="copyOrderNo(detailData.address)" />
-              </text>
-            </view>
-            <view class="divider"></view>
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f27') }}</text>
-              <text class="info-value">
-                <text v-if="detailData.remark">{{ detailData.remark }}</text>
-                <text v-else-if="detailData.note">{{ detailData.note }}</text>
-                <text v-else-if="approveDesc">{{ approveDesc }}</text>
-                <text v-else>--</text>
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('Label.ApplyTime') }}</text>
-              <text class="info-value">
-                <text>{{ detailData.addTime }}</text>
-              </text>
-            </view>
-            <view class="info-row" v-if="detailData.approveTime">
-              <text class="info-label">{{ t('WalletApply.p10') }}</text>
-              <text class="info-value">
-                <text>{{ detailData.approveTime }}</text>
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('global.p22') }}</text>
-              <text class="info-value">
-                <text>{{ t(withdrawApprovalText[detailData.status]) }}</text>
-              </text>
-            </view>
-            <view class="info-row">
-              <text class="info-label">{{ t('card.Form.f45') }}</text>
-              <text class="info-value">
-                <text>{{ t(withdrawStatus[detailData.transactionStatus]) }}</text>
-              </text>
-            </view>
-          </view>
-        </view>
-      </view>
-      <view class="bottom-actions" v-if="(detailData.transactionStatus == 1 && detailData.transactionStatus != 5)">
-        <view class="action-btn cancel-btn" @click="cancelOrder">
-          <text class="btn-text">{{ t('global.GlobalOrder.CancelOrder') }}</text>
-        </view>
-      </view>
-    </view>
-  </cwg-page-wrapper>
-</template>
-
-<script setup lang="ts">
-import { ref, watch, nextTick, computed } from 'vue'
-import { onLoad, onUnload } from '@dcloudio/uni-app';
-import { useI18n } from 'vue-i18n';
-import useCardStore from '@/stores/use-card-store';
-import { ucardApi } from "@/api/ucard";
-import { withdrawApprovalText, withdrawStatus } from '@/utils/dataMap';
-import useUserStore from "@/stores/use-user-store";
-const { t, locale } = useI18n();
-
-const userStore = useUserStore();
-const approveDesc = ref('');
-const getApproveDesc = () => {
-  const d = detailData.value.approveDesc
-  if (!d) return
-  const c = userStore.reasonsOptions
-  const a = c[d || '']
-  const b = locale.value == 'cn' || locale.value == 'zhHant' ? a.content : a.enContent
-  if (!b) {
-    reasonsRefusalList()
-  }
-  approveDesc.value = b;
-}
-const formatOrderNo = (orderNo?: string) => {
-  if (!orderNo) return '--';
-  if (orderNo.length <= 16) return orderNo;
-  return orderNo.slice(0, 6) + '...' + orderNo.slice(-4);
-};
-
-const copyOrderNo = (orderNo?: string) => {
-  if (!orderNo) return;
-  uni.setClipboardData({
-    data: orderNo,
-    success: () => {
-      uni.showToast({
-        title: t('card.Msg.m8') || '复制成功',
-        icon: 'success'
-      });
-    }
-  });
-};
-async function reasonsRefusalList() {
-  try {
-    const res = await ucardApi.reasonsRefusalList();
-    if (res.code === 200) {
-      pickFields(res.data);
-      getApproveDesc()
-    } else {
-      uni.$u.toast(res.msg || t("login.msg0"));
-    }
-  } catch (error) {
-    console.log(error, 111);
-  }
-}
-function pickFields(source, fields = ['content', 'enContent']) {
-  const result = {}
-  Object.entries(source).forEach(([key, value]) => {
-    result[key] = fields.reduce((acc, f) => {
-      acc[f] = value[f] ?? null
-      return acc
-    }, {})
-  })
-  userStore.saveReasonsOptions(result);
-}
-
-const cardStore = useCardStore();
-
-// 取消订单
-const cancelOrder = () => {
-  uni.showModal({
-    title: t('Msg.SystemPrompt'),
-    cancelText: t('common.cancel'),
-    confirmText: t('common.confirm'),
-    content: t('global.GlobalOrder.ConfirmCancelOrder'),
-    success: async (e) => {
-      if (e.confirm) {
-        const res = await ucardApi.getBlockchainWithdrawCancel({ id: detailData.value.id })
-        if (res.code == 200) {
-          // 刷新订单详情
-          uni.showToast({
-            title: t('global.GlobalOrder.CancelOrderSuccess'),
-            icon: 'success'
-          });
-          detailData.value.transactionStatus = 5;
-        }
-      }
-    }
-  });
-};
-
-const detailData = ref<any>({})
-// 页面加载时,先使用缓存数据渲染,然后获取最新数据
-onLoad((e) => {
-  const cachedData = cardStore.orderDetail
-  if (cachedData) {
-    try {
-      const clonedData = JSON.parse(JSON.stringify(cachedData))
-      Object.assign(detailData.value, clonedData)
-    } catch (error) {
-      console.error('加载缓存数据失败:', error)
-    }
-  }
-});
-
-// 离开页面时清空订单详情
-onUnload(() => {
-  cardStore.clearOrderDetail();
-});
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page-wrapper {
-  padding: 0;
-}
-
-.success-icon-wrap {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  flex-wrap: wrap;
-  background-color: #ffffff;
-
-  image {
-    width: 100%;
-  }
-
-  .success-text {
-    width: 100%;
-    text-align: center;
-    font-size: px2rpx(18);
-    color: #111827;
-    margin-bottom: px2rpx(24);
-  }
-}
-
-.order-detail-page {
-  background-color: #f9fafb;
-  padding-bottom: px2rpx(80);
-}
-
-/* Header */
-.header {
-  background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-  padding: px2rpx(12) px2rpx(16);
-  padding-top: calc(px2rpx(12) + env(safe-area-inset-top));
-}
-
-.header-nav {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-}
-
-.back-btn {
-  width: px2rpx(40);
-  height: px2rpx(40);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.header-title {
-  color: #ffffff;
-  font-size: px2rpx(18);
-}
-
-.header-action {
-  width: px2rpx(40);
-}
-
-/* Content */
-.content {
-  padding: px2rpx(16);
-}
-
-/* Status Card */
-.status-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(16);
-  padding: px2rpx(32) px2rpx(24);
-  margin-bottom: px2rpx(16);
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-}
-
-.status-icon-wrapper {
-  margin-bottom: px2rpx(16);
-}
-
-.status-icon {
-  width: px2rpx(80);
-  height: px2rpx(80);
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.status-icon-success {
-  background-color: #f0fdf4;
-}
-
-.status-icon-processing {
-  background-color: #fefce8;
-}
-
-.status-icon-failed {
-  background-color: #fef2f2;
-}
-
-.status-icon-cancelled {
-  background-color: #f9fafb;
-}
-
-.status-title {
-  font-size: px2rpx(22);
-  color: #111827;
-  margin-bottom: px2rpx(8);
-}
-
-.status-subtitle {
-  font-size: px2rpx(14);
-  color: #6b7280;
-  text-align: center;
-}
-
-/* Section Card */
-.section-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  padding: px2rpx(16);
-  margin-bottom: px2rpx(16);
-}
-
-.section-header {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  margin-bottom: px2rpx(16);
-}
-
-.section-title {
-  font-size: px2rpx(16);
-  color: #111827;
-}
-
-/* Approval Timeline */
-.approval-timeline {
-  display: flex;
-  flex-direction: column;
-}
-
-.timeline-item {
-  display: flex;
-  gap: px2rpx(12);
-}
-
-.timeline-left {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  flex-shrink: 0;
-}
-
-.timeline-dot {
-  width: px2rpx(24);
-  height: px2rpx(24);
-  border-radius: 50%;
-  background-color: #f3f4f6;
-  border: 2px solid #e5e7eb;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.timeline-dot-active {
-  background-color: #22c55e;
-  border-color: #22c55e;
-}
-
-.timeline-dot-current {
-  background-color: #eab308;
-  border-color: #eab308;
-  animation: pulse 2s infinite;
-}
-
-@keyframes pulse {
-
-  0%,
-  100% {
-    opacity: 1;
-  }
-
-  50% {
-    opacity: 0.7;
-  }
-}
-
-.timeline-line {
-  width: px2rpx(2);
-  flex: 1;
-  background-color: #e5e7eb;
-  margin: px2rpx(4) 0;
-}
-
-.timeline-right {
-  flex: 1;
-  padding-bottom: px2rpx(24);
-}
-
-.timeline-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: px2rpx(6);
-}
-
-.timeline-title {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-.timeline-status {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(4);
-  padding: px2rpx(2) px2rpx(8);
-  border-radius: px2rpx(12);
-}
-
-.timeline-status.completed {
-  background-color: #f0fdf4;
-}
-
-.timeline-status.current {
-  background-color: #fefce8;
-}
-
-.timeline-status.pending {
-  background-color: #f9fafb;
-}
-
-.timeline-status-text {
-  font-size: px2rpx(12);
-}
-
-.timeline-status.completed .timeline-status-text {
-  color: #22c55e;
-}
-
-.timeline-status.current .timeline-status-text {
-  color: #eab308;
-}
-
-.timeline-status.pending .timeline-status-text {
-  color: #9ca3af;
-}
-
-.timeline-operator {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  display: block;
-  margin-bottom: px2rpx(4);
-}
-
-.timeline-time {
-  font-size: px2rpx(12);
-  color: #9ca3af;
-  display: block;
-  margin-bottom: px2rpx(4);
-}
-
-.timeline-remark {
-  font-size: px2rpx(13);
-  color: #6b7280;
-  display: block;
-  margin-top: px2rpx(6);
-  padding: px2rpx(8);
-  background-color: #f9fafb;
-  border-radius: px2rpx(6);
-}
-
-/* Info List */
-.info-list {
-  display: flex;
-  flex-direction: column;
-  gap: px2rpx(12);
-}
-
-.info-row {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  gap: px2rpx(12);
-  padding: px2rpx(4) 0;
-}
-
-.info-row.vertical {
-  flex-direction: column;
-  align-items: flex-start;
-}
-
-.info-label {
-  font-size: px2rpx(14);
-  color: #6b7280;
-  flex-shrink: 0;
-}
-
-.info-value {
-  font-size: px2rpx(14);
-  color: #111827;
-  text-align: right;
-  word-break: break-all;
-}
-
-.info-value-wrapper {
-  display: flex;
-  align-items: center;
-  gap: px2rpx(8);
-  flex: 1;
-  justify-content: flex-end;
-}
-
-.amount-highlight {
-  font-size: px2rpx(20);
-  color: #2563eb;
-}
-
-.total-label {
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-.total-value {
-  font-size: px2rpx(18);
-  color: #ef4444;
-}
-
-.remark-text {
-  text-align: left;
-  color: #6b7280;
-  line-height: 1.6;
-}
-
-.divider {
-  height: px2rpx(1);
-  background-color: #f3f4f6;
-  margin: px2rpx(4) 0;
-}
-
-/* Service Card */
-.service-card {
-  background-color: #ffffff;
-  border-radius: px2rpx(12);
-  padding: px2rpx(16);
-  display: flex;
-  align-items: center;
-  gap: px2rpx(12);
-  margin-bottom: px2rpx(16);
-}
-
-.service-text {
-  flex: 1;
-  font-size: px2rpx(15);
-  color: #111827;
-}
-
-/* Bottom Actions */
-.bottom-actions {
-  position: fixed;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  background-color: #ffffff;
-  border-top: 1px solid #e5e7eb;
-  padding: px2rpx(12) px2rpx(16);
-  padding-bottom: calc(px2rpx(12) + env(safe-area-inset-bottom));
-  display: flex;
-  gap: px2rpx(12);
-}
-
-.action-btn {
-  flex: 1;
-  height: px2rpx(44);
-  border-radius: px2rpx(8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.cancel-btn {
-  background-color: #f3f4f6;
-}
-
-.cancel-btn .btn-text {
-  color: #6b7280;
-}
-
-.appeal-btn {
-  background-color: #2563eb;
-}
-
-.appeal-btn .btn-text {
-  color: #ffffff;
-}
-
-.delete-btn {
-  background-color: #f3f4f6;
-}
-
-.delete-btn .btn-text {
-  color: #ef4444;
-}
-
-.btn-text {
-  font-size: px2rpx(15);
-}
-
-.currency {
-  font-size: px2rpx(12);
-}
-</style>

+ 0 - 258
pages/wallet/withdraw-list.vue

@@ -1,258 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="bank-transaction-page">
-            <view class="filters-container" :style="{ top: statusBarHeight + 53 + 'px' }">
-                <view class="filter-item">
-                    <text class="filter-label">{{ t('card.Form.f45') }}</text>
-                    <cwg-filter-select v-model="statusFilterIndex" :options="statusOptions" />
-                </view>
-                <view class="filter-item">
-                    <text class="filter-label">{{ t('card.Form.f43') }}</text>
-                    <cwg-filter-picker v-model="dateFilter"></cwg-filter-picker>
-                </view>
-                <view class="reset-btn" @click="resetFilters">
-                    <uni-icons type="loop" size="16" color="#2563eb" />
-                </view>
-            </view>
-            <view class="content">
-                <WithdrawList ref="globalListRef" :cardNumber="cardNumber" :payoutCurrency="payoutCurrency"
-                    :statusIndex="statusFilterIndex" :dateFilter="dateFilter" />
-            </view>
-        </view>
-    </cwg-page-wrapper>
-
-</template>
-
-<script setup lang="ts">
-import { ref, computed, watch } from 'vue';
-import { onLoad } from '@dcloudio/uni-app';
-import { useI18n } from 'vue-i18n';
-import useGlobalStore from '@/stores/use-global-store';
-import WithdrawList from './components/WithdrawList.vue';
-import { withdrawStatus } from '@/utils/dataMap';
-const globalStore = useGlobalStore()
-const statusBarHeight = computed(() => globalStore.statusBarHeight);
-const { t } = useI18n();
-const cardNumber = ref('');
-onLoad((options) => {
-    cardNumber.value = options.cardNumber || '';
-});
-
-const statusOptions = computed(() => {
-    return withdrawStatus
-});
-const payoutCurrency = ref();
-const statusFilterIndex = ref(-1);
-const dateFilter = ref([]);
-
-const resetFilters = () => {
-    payoutCurrency.value = '';
-    statusFilterIndex.value = -1;
-    dateFilter.value = [];
-};
-</script>
-
-<style scoped lang="scss">
-@import "@/uni.scss";
-
-.page-wrapper {
-    padding: 0;
-    border: 0;
-}
-
-.bank-transaction-page {
-    // background-color: #f9fafb;
-}
-
-.wallet-header {
-    background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-}
-
-/* Header */
-.header {
-    background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
-    padding: px2rpx(16);
-    padding-bottom: px2rpx(20);
-}
-
-.header-content {
-    display: flex;
-    flex-direction: column;
-    gap: px2rpx(16);
-}
-
-.header-title {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(8);
-}
-
-.title-text {
-    color: #ffffff;
-    font-size: px2rpx(20);
-}
-
-.stats-container {
-    display: flex;
-    gap: px2rpx(12);
-}
-
-.stat-card {
-    flex: 1;
-    background-color: rgba(255, 255, 255, 0.15);
-    backdrop-filter: blur(px2rpx(10));
-    border-radius: px2rpx(12);
-    padding: px2rpx(12);
-}
-
-.stat-header {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(6);
-    margin-bottom: px2rpx(8);
-}
-
-.icons {
-    width: px2rpx(20);
-    height: px2rpx(20);
-}
-
-.stat-label {
-    font-size: px2rpx(12);
-    color: rgba(255, 255, 255, 0.9);
-}
-
-.stat-value {
-    font-size: px2rpx(20);
-    color: #ffffff;
-    display: block;
-    margin-bottom: px2rpx(4);
-}
-
-.stat-count {
-    font-size: px2rpx(11);
-    color: rgba(255, 255, 255, 0.8);
-}
-
-/* Tabs */
-.tabs-container {
-    background-color: #ffffff;
-    display: flex;
-    border-bottom: 1px solid #e5e7eb;
-    position: sticky;
-    top: 0;
-    z-index: 10;
-}
-
-.tab-item {
-    flex: 1;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: px2rpx(6);
-    padding: px2rpx(16);
-    position: relative;
-    transition: all 0.3s;
-}
-
-.tab-text {
-    font-size: px2rpx(15);
-    color: #9ca3af;
-    transition: color 0.3s;
-}
-
-.tab-text-active {
-    color: #2563eb;
-}
-
-.tab-indicator {
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    height: px2rpx(3);
-    background-color: #2563eb;
-    border-radius: px2rpx(3) px2rpx(3) 0 0;
-}
-
-/* Content */
-.content {
-    padding: 0;
-}
-
-.filters-container {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(8);
-    padding: px2rpx(12) px2rpx(16);
-    background-color: #ffffff;
-    position: sticky;
-    top: 0;
-    z-index: 10;
-    // overflow-x: auto;
-    -webkit-overflow-scrolling: touch;
-}
-
-.filter-item {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    flex-shrink: 0;
-    min-width: 0;
-}
-
-.filter-label {
-    font-size: px2rpx(12);
-    color: #6b7280;
-    white-space: nowrap;
-    flex-shrink: 0;
-}
-
-.filter-picker {
-    background-color: #ffffff;
-    border: 1px solid #e5e7eb;
-    border-radius: px2rpx(8);
-    padding: px2rpx(6) px2rpx(8);
-    display: flex;
-    align-items: center;
-    min-width: px2rpx(60);
-    max-width: px2rpx(120);
-    flex-shrink: 1;
-}
-
-.picker-value {
-    display: flex;
-    align-items: center;
-    gap: px2rpx(4);
-    width: 100%;
-    min-width: 0;
-}
-
-.picker-text {
-    flex: 1;
-    min-width: 0;
-    font-size: px2rpx(12);
-    color: #111827;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.picker-icon {
-    flex-shrink: 0;
-    width: px2rpx(14);
-    height: px2rpx(14);
-}
-
-.reset-btn {
-    background-color: #ffffff;
-    border: 1px solid #e5e7eb;
-    border-radius: px2rpx(8);
-    padding: px2rpx(6) px2rpx(10);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-shrink: 0;
-    min-width: px2rpx(36);
-}
-</style>

+ 0 - 323
pages/wallet/withdraw.vue

@@ -1,323 +0,0 @@
-<template>
-    <cwg-page-wrapper>
-        <view class="page">
-            <u-form ref="formRef" :rules="rules" :model="form" class="payment-form">
-                <cwg-input v-model:value="form.blockchain" fkey="blockchain" type="select" :required="true"
-                    :columns="blockchainList" :label="t('Blockchain.addP2')" rulesKey="blockchain"
-                    @change="handleChange" />
-                <cwg-input :label="t('WalletApply.p1')" v-model:value="form.address" fkey="address" type="text"
-                    rulesKey="address" :placeholder="t('WalletApply.p2')" :required="true" clearable />
-                <cwg-input :label="`${t('WalletApply.p3')} ${t('WalletApply.p5', { userBalance: form.userBalance })}`"
-                    rulesKey="amount" v-model:value="form.amount" fkey="amount" type="number"
-                    :placeholder="t('WalletApply.p4')" :required="true" @change="globalExchangeRate" clearable />
-
-                <view>
-                    <view class="code-input-wrapper">
-                        <view class="code-input">
-                            <cwg-input v-model:value="form.emailCode" :label="t('newSignup.item9')" fkey="emailCode"
-                                type="text" :required="true" rulesKey="emailCode" :placeholder="t('newSignup.item10')"
-                                @change="handleChange" />
-                        </view>
-                        <view class="get-code-btn1">
-                            <view class="ok-button">
-                                <u-button type="primary" block>{{ getCodeString }}</u-button>
-                            </view>
-                        </view>
-                        <view class="get-code-btn">
-                            <view class="cwg-button">
-                                <u-button type="primary" block @click="handleGetCode">{{ getCodeString }}</u-button>
-                            </view>
-                        </view>
-                    </view>
-                </view>
-            </u-form>
-
-            <view class="fixed-btn">
-                <view class="cwg-button">
-                    <u-button type="primary" block @click="infoSubmit">{{ t("card.Btn.Submit") }}</u-button>
-                </view>
-            </view>
-        </view>
-        <cwg-SuccessPrompt v-model:show="showSuccessPrompt" :title="t('pages.wallet.withdraw')"
-            :desc="t('Custom.Withdraw.Des1')" :btn-click="btnClick" />
-    </cwg-page-wrapper>
-</template>
-<script setup lang="ts">
-import { ref, onMounted, watch, computed, onBeforeUnmount } from "vue";
-import { showToast } from "@/utils/toast";
-import { useI18n } from "vue-i18n";
-import { ucardApi } from "@/api/ucard";
-import useUserStore from "@/stores/use-user-store";
-import useRouter from "@/hooks/useRouter";
-import { Validators } from "@/utils/validators";
-import { onLoad } from '@dcloudio/uni-app'
-import { useEmailCountdown } from '@/hooks/useEmailCountdown';
-const {
-    time,
-    text: getCodeString,
-    canSend,
-    start,
-    restore
-} = useEmailCountdown()
-onLoad((options) => {
-    userBalance.value = options.allAmount
-})
-const userBalance = ref(0);
-const router = useRouter();
-const { t } = useI18n();
-const userStore = useUserStore();
-const userInfo = computed(() => userStore.userInfo);
-const formRef = ref();
-const form = ref<{
-    emailCode: string;
-    cardNumber?: string;
-    password?: string;
-    country?: string;
-    email?: string;
-}>({
-    emailCode: "",
-});
-const text1 = ref("");
-const blockchainList = ref([]);
-// 表单验证规则
-const rules = {
-    blockchain: [Validators.required(t("Blockchain.addP2"))],
-    address: [Validators.required(t("WalletApply.p2"))],
-    amount: [
-        Validators.required(t("global.validator.v15")),
-        Validators.custom(validateAmount),
-    ],
-};
-function validateAmount(a: any, b?: any, c?: any) {
-    if (typeof c === "function") {
-        const value = b;
-        const callback = c;
-        const val = String(value ?? "").trim();
-        const num = Number(val);
-        const pattern = /^(?:[1-9]\d*(?:\.\d{1,2})?|0\.(?!0+$)\d{1,2})$/;
-        if (!pattern.test(val)) {
-            callback(new Error(t("global.validator.v15")));
-            return;
-        }
-        if (isNaN(num) || num <= 0) {
-            callback(new Error(t("global.validator.v15")));
-            return;
-        }
-        const balance = Number(form.value.userBalance);
-        if (!isNaN(balance) && num > balance) {
-            const msg = t("WalletApply.p6", { userBalance: form.value.userBalance });
-            callback(new Error(msg));
-            return;
-        }
-        return callback();
-    }
-}
-function btnClick() {
-    showSuccessPrompt.value = false;
-    router.push({ path: "/pages/wallet/index" })
-}
-// 初始化表单
-function initForm() {
-    const a = { uniqueId: userInfo.value.uniqueId, country: userInfo.value.country, email: userInfo.value.email }
-    if (userInfo.value) {
-        form.value = {
-            ...a,
-            userBalance: userBalance.value,
-            emailCode: "",
-        };
-    }
-    text1.value = "";
-}
-const showSuccessPrompt = ref(false);
-// 提交表单
-async function infoSubmit() {
-    try {
-        await formRef.value?.validate();
-        let res = await ucardApi.getBlockchainWithdrawApply({
-            ...form.value,
-        });
-        if (res.code == 200) {
-            showSuccessPrompt.value = true;
-        } else {
-            showToast(res.msg);
-        }
-    } catch (error) {
-        console.log(error, 1111);
-
-    }
-}
-//获取区块链
-async function getBlockchainDropdown() {
-    let res = await ucardApi.getBlockchainDropdown({
-        ...form.value,
-        type: '2'
-    });
-    if (res.code == 200) {
-        res.data.map((item: any) => {
-            item.text = item.alias;
-            item.value = item.blockchain;
-        });
-        blockchainList.value = res.data;
-    } else {
-        blockchainList.value = []
-        showToast(res.msg);
-    }
-}
-
-// 发送邮箱验证码
-async function sendEmailCode() {
-    try {
-        if (!form.value.country) {
-            showToast(t("vaildate.country.empty"));
-            return false;
-        }
-        if (!form.value.email) {
-            showToast(t("vaildate.email.empty"));
-            return false;
-        }
-
-        const res = await ucardApi.getBlockchainWithdrawSendEmailCode({
-            ...form.value,
-        });
-
-        if (res.code === 200) {
-            showToast(t("Msg.CodeSuccess"));
-            start()
-            return true;
-        } else {
-            showToast(t("Msg.CodeFail"));
-            return false;
-        }
-    } catch (error: any) {
-        console.log(error, 12);
-
-        showToast(t("Msg.CodeFail"));
-        return false;
-    }
-}
-
-// 获取验证码按钮点击
-async function handleGetCode() {
-    if (!canSend.value) return
-    text1.value = "";
-    await sendEmailCode();
-}
-
-// 表单字段变化
-function handleChange(value: any) {
-    if (value.key === "emailCode") {
-        form.value.emailCode = value.value;
-    }
-    if (value.key === "blockchain") {
-        changeBlockchain(value.value);
-    }
-}
-
-function changeBlockchain(e) {
-    blockchainList.value.forEach(item => {
-        if (item.blockchain === e) {
-            form.value.receivedCurrency = item.alias;
-            form.value.exchangeRate = item.exchangeRate;
-        }
-    });
-    if (form.value.amount) {
-        globalExchangeRate();
-    }
-}
-function globalExchangeRate() {
-    const amount = Number(form.value.amount);
-    formRef.value.validateField(['amount'], (valid) => {
-        if (valid.length > 0) {
-            form.value.receivedAmount = '';
-            return
-        }
-        if (amount && form.value.exchangeRate) {
-            const receivedAmount = parseFloat((amount * form.value.exchangeRate).toFixed(4));
-            form.value.receivedAmount = receivedAmount;
-        } else {
-            form.value.receivedAmount = '';
-        }
-    });
-}
-
-onMounted(() => {
-    console.log(3333);
-
-    initForm();
-    restore()
-    getBlockchainDropdown();
-});
-
-</script>
-
-<style lang="scss" scoped>
-@import "@/uni.scss";
-
-.no-button {
-    width: 100%;
-    margin: px2rpx(12) 0;
-
-    .u-button {
-        background-color: #ffbdc8 !important;
-    }
-}
-
-
-.code-input-label {
-    font-size: var(--font-size-16);
-    line-height: px2rpx(44);
-    letter-spacing: px2rpx(1);
-    color: #474747;
-}
-
-.code-input-wrapper {
-    position: relative;
-    display: flex;
-    align-items: center;
-}
-
-.code-input {
-    flex: 1;
-}
-
-.get-code-btn1 {
-    min-width: px2rpx(100);
-    margin-left: px2rpx(8);
-
-    .ok-button {
-
-        .u-button {
-            background-color: #fff;
-            opacity: 0;
-        }
-    }
-
-}
-
-.get-code-btn {
-    position: absolute;
-    right: 0;
-    bottom: px2rpx(12);
-    min-width: px2rpx(100);
-    background-color: #fff;
-    z-index: 1;
-    margin-left: px2rpx(8);
-
-    .cwg-button {
-        margin: 0;
-    }
-
-    .cwg-button .u-button {
-        border-radius: px2rpx(8);
-        height: px2rpx(46) !important;
-    }
-}
-
-.submit-section {
-    margin: px2rpx(20) 0;
-}
-
-.submit-btn {
-    width: 100%;
-}
-</style>

BIN
static/images/1-1.png


BIN
static/images/1-2.png


BIN
static/images/1-3.png


BIN
static/images/1-4.png


BIN
static/images/1-5.png


BIN
static/images/1.png


BIN
static/images/10-bonus.webp


BIN
static/images/100-bonus.webp


BIN
static/images/2.png


BIN
static/images/2024-Paris-Olympics-3.jpg


BIN
static/images/23ActiveCn.jpg


BIN
static/images/23ActiveCn1.jpg


BIN
static/images/23ActiveEn.jpg


BIN
static/images/3.png


BIN
static/images/4.png


BIN
static/images/5-1.png


BIN
static/images/5-2.png


BIN
static/images/5-3.png


BIN
static/images/5-4.png


BIN
static/images/5.png


BIN
static/images/6-01.png


BIN
static/images/6-02.png


BIN
static/images/6-03.png


BIN
static/images/6-04.png


BIN
static/images/AR.jpg


BIN
static/images/Android-mt5.png


BIN
static/images/CN.jpg


BIN
static/images/CWG_02.png


BIN
static/images/DE.jpg


BIN
static/images/EN.jpg


BIN
static/images/ES.jpg


BIN
static/images/FA.png


BIN
static/images/Indonesian.jpg


BIN
static/images/MS.jpg


BIN
static/images/MT4_android.png


BIN
static/images/MT4_ios.png


BIN
static/images/MT5_android.png


BIN
static/images/MT5_ios.png


BIN
static/images/MTBG.jpg


BIN
static/images/PT.png


BIN
static/images/Secure_01.png


BIN
static/images/Secure_02.png


BIN
static/images/Secure_03.png


BIN
static/images/TH.jpg


BIN
static/images/TR.png


BIN
static/images/Trading-Reward-2.jpg


BIN
static/images/UB.jpg


BIN
static/images/VN.jpg


BIN
static/images/acc_logo.png


BIN
static/images/android-MT4.png


BIN
static/images/android-os-3-72.png


BIN
static/images/apple-os-1-48.png


BIN
static/images/apple-os-3-72.png


BIN
static/images/apply-record-1.png


Некоторые файлы не были показаны из-за большого количества измененных файлов