zhb 2 bulan lalu
induk
melakukan
4d4f98e405
100 mengubah file dengan 5853 tambahan dan 2677 penghapusan
  1. 209 0
      components/cwg-dropdown.vue
  2. 12 14
      components/cwg-header.vue
  3. 11 6
      components/cwg-label-line-value.vue
  4. 1 1
      components/cwg-page-wrapper.vue
  5. 9 6
      components/cwg-popup.vue
  6. 9 4
      config/index.ts
  7. 403 0
      global/constPY.js
  8. 128 0
      global/index.js
  9. 12 0
      global/isImageType.js
  10. 40 0
      global/py.js
  11. 11 0
      global/tool.js
  12. 28 0
      lib/crypt.js
  13. 159 0
      lib/service.js
  14. 56 0
      lib/session.js
  15. 138 0
      lib/upload.js
  16. 1 0
      package.json
  17. 33 10
      pages.json
  18. 480 0
      pages/customer/account-select.vue
  19. 119 45
      pages/customer/components/AccountCard.vue
  20. 21 17
      pages/customer/components/AccountList.vue
  21. 1 1
      pages/customer/components/DeleteAccountDialogs.vue
  22. 184 0
      pages/customer/components/PaymentMethodsList.vue
  23. 210 0
      pages/customer/components/TerminalChangePasswordDialog.vue
  24. 332 0
      pages/customer/components/TerminalDialog.vue
  25. 182 0
      pages/customer/components/TerminalInfoDialog.vue
  26. 184 0
      pages/customer/components/TerminalNickNameDialog.vue
  27. 1 1
      pages/customer/components/TransactionDialogs.vue
  28. 116 0
      pages/customer/composables/TerminalMap.ts
  29. 0 1379
      pages/customer/create-account copy.vue
  30. 169 181
      pages/customer/create-account.vue
  31. 824 577
      pages/customer/deposit.vue
  32. 350 0
      pages/customer/style.scss
  33. 1347 0
      pages/customer/withdrawal.vue
  34. 0 257
      pages/login/forget.vue
  35. 6 2
      pages/login/index.vue
  36. 60 174
      pages/login/regist.vue
  37. 1 2
      pages/mine/improve.vue
  38. 5 0
      service/custom.ts
  39. 1 0
      static/icons/crm-caret-right.svg
  40. TEMPAT SAMPAH
      static/pdf/Client_Agreement.pdf
  41. TEMPAT SAMPAH
      static/pdf/CopyTradeUserAgreement.pdf
  42. TEMPAT SAMPAH
      static/pdf/CopyTradeUserAgreementcn.pdf
  43. TEMPAT SAMPAH
      static/pdf/DigitalCurrency_Withdrawal_Cn.pdf
  44. TEMPAT SAMPAH
      static/pdf/DigitalCurrency_Withdrawal_En.pdf
  45. TEMPAT SAMPAH
      static/pdf/PrivacyPolicy2019_01.pdf
  46. TEMPAT SAMPAH
      static/pdf/Privacy_Policy.pdf
  47. TEMPAT SAMPAH
      static/pdf/Terms&Conditions.pdf
  48. TEMPAT SAMPAH
      static/pdf/pdf1/ar.pdf
  49. TEMPAT SAMPAH
      static/pdf/pdf1/cn.pdf
  50. TEMPAT SAMPAH
      static/pdf/pdf1/en.pdf
  51. TEMPAT SAMPAH
      static/pdf/pdf1/es.pdf
  52. TEMPAT SAMPAH
      static/pdf/pdf1/ko.pdf
  53. TEMPAT SAMPAH
      static/pdf/pdf1/pt.pdf
  54. TEMPAT SAMPAH
      static/pdf/pdf1/th.pdf
  55. TEMPAT SAMPAH
      static/pdf/pdf1/vn.pdf
  56. TEMPAT SAMPAH
      static/pdf/pdf1/zhHant.pdf
  57. TEMPAT SAMPAH
      static/pdf/pdf10/Account Type Allocation Table-cn.pdf
  58. TEMPAT SAMPAH
      static/pdf/pdf10/Account Type Allocation Table-en.pdf
  59. TEMPAT SAMPAH
      static/pdf/pdf10/Account Type Allocation Table-zhHant.pdf
  60. TEMPAT SAMPAH
      static/pdf/pdf11/Account Type Allocation Table-cn.pdf
  61. TEMPAT SAMPAH
      static/pdf/pdf11/Account Type Allocation Table-en.pdf
  62. TEMPAT SAMPAH
      static/pdf/pdf11/Account Type Allocation Table-zhHant.pdf
  63. TEMPAT SAMPAH
      static/pdf/pdf12/Account Type Allocation Table-cn.pdf
  64. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Markets Prime Bonus Application Process-cn.pdf
  65. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Markets Prime Bonus Application Process-en.pdf
  66. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Markets Prime Bonus Application Process-zhHant.pdf
  67. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-ar.pdf
  68. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-cn.pdf
  69. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-de.pdf
  70. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-en.pdf
  71. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-es.pdf
  72. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-fa.pdf
  73. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-id.pdf
  74. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-ko.pdf
  75. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-ms.pdf
  76. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-pt.pdf
  77. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-th.pdf
  78. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-tr.pdf
  79. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-vn.pdf
  80. TEMPAT SAMPAH
      static/pdf/pdf12/CWG Prime Bonus-zhHant.pdf
  81. TEMPAT SAMPAH
      static/pdf/pdf13/CWG Markets Prime Bonus Application Process-cn.pdf
  82. TEMPAT SAMPAH
      static/pdf/pdf13/CWG Prime Bonus-cn.pdf
  83. TEMPAT SAMPAH
      static/pdf/pdf2/pdf-cn.pdf
  84. TEMPAT SAMPAH
      static/pdf/pdf2/pdf-en.pdf
  85. TEMPAT SAMPAH
      static/pdf/pdf2/pdf-es.pdf
  86. TEMPAT SAMPAH
      static/pdf/pdf2/pdf-pt.pdf
  87. TEMPAT SAMPAH
      static/pdf/pdf2/pdf-th.pdf
  88. TEMPAT SAMPAH
      static/pdf/pdf2/pdf-vn.pdf
  89. TEMPAT SAMPAH
      static/pdf/pdf2/pdf-zhHant.pdf
  90. TEMPAT SAMPAH
      static/pdf/pdf3/pdf-cn.pdf
  91. TEMPAT SAMPAH
      static/pdf/pdf3/pdf-en.pdf
  92. TEMPAT SAMPAH
      static/pdf/pdf3/pdf-zhHant.pdf
  93. TEMPAT SAMPAH
      static/pdf/pdf4/100Bonus-ar.pdf
  94. TEMPAT SAMPAH
      static/pdf/pdf4/100Bonus-en.pdf
  95. TEMPAT SAMPAH
      static/pdf/pdf4/100Bonus-es.pdf
  96. TEMPAT SAMPAH
      static/pdf/pdf4/ar.pdf
  97. TEMPAT SAMPAH
      static/pdf/pdf4/cn.pdf
  98. TEMPAT SAMPAH
      static/pdf/pdf4/de.pdf
  99. TEMPAT SAMPAH
      static/pdf/pdf4/en.pdf
  100. TEMPAT SAMPAH
      static/pdf/pdf4/es.pdf

+ 209 - 0
components/cwg-dropdown.vue

@@ -0,0 +1,209 @@
+<template>
+    <view>
+        <view class="cwg-dropdown" :style="customStyle" @click="click">
+            <slot></slot>
+        </view>
+        <view class="cwg-dropdown-menu">
+            <view class="cwg-dropdown-menu-container" :style="[layout]" @click.stop>
+                <slot name="menu">
+                    <view class="menu">
+                        <view class="menu-item" v-for="(item, idx) in menuList" :key="idx"
+                            @click="menuClick(item, idx)">
+                            <view>{{ item.label || item }}</view>
+                        </view>
+                    </view>
+                </slot>
+            </view>
+        </view>
+        <view class="cwg-dropdown-mask" :class="{ 'cwg-dropdown-mask-show': maskShow }" @touchmove.prevent="() => { }"
+            @click="close" />
+    </view>
+</template>
+
+<script setup>
+import { ref, reactive, nextTick, onMounted } from 'vue'
+import { queryElementRect } from '@/uni_modules/x-tools/tools/sugar.js'
+import { str2px, commonProps } from '@/uni_modules/x-tools/tools/com.js'
+
+// 合并 props
+const props = defineProps({
+    ...commonProps,
+    menuList: {
+        type: Object,
+        default: () => ['菜单1', '菜单2', '菜单3']
+    },
+    menuStyle: {
+        type: Object,
+        default: () => ({})
+    },
+    interspace: {
+        type: [String, Number],
+        default: '10rpx'
+    }
+})
+
+const emit = defineEmits(['open', 'close', 'change', 'menuClick'])
+
+// 响应式数据
+const maskShow = ref(false)
+const windowInfo = reactive({
+    width: 0,
+    height: 0
+})
+const layout = reactive({})
+const innerInterspace = ref(0)
+
+// 获取系统信息
+const getSystemInfo = () => {
+    return new Promise((resolve) => {
+        if (windowInfo.width > 0) {
+            resolve(windowInfo)
+        } else {
+            uni.getSystemInfo({
+                success: (res) => {
+                    windowInfo.width = res.windowWidth
+                    windowInfo.height = res.windowHeight
+                    resolve(windowInfo)
+                },
+                fail: () => {
+                    setTimeout(() => getSystemInfo().then(resolve), 100)
+                }
+            })
+        }
+    })
+}
+
+// 点击触发器
+const click = async (e) => {
+    e.stopPropagation()
+    await getSystemInfo()
+    const triggerRect = await queryElementRect('.cwg-dropdown')
+    if (!triggerRect) return
+    const tempStyle = {
+        transform: 'scaleY(1)',
+        visibility: 'hidden',
+        top: '-9999px',
+        left: '-9999px',
+        transition: 'none'
+    }
+    Object.assign(layout, tempStyle)
+    await nextTick()
+    const menuRect = await queryElementRect('.cwg-dropdown-menu-container')
+    if (!menuRect) {
+        Object.keys(layout).forEach(key => delete layout[key])
+        layout.transform = 'scaleY(0)'
+        return
+    }
+    const { width: winWidth } = windowInfo
+    const { left, right, bottom } = triggerRect
+    const interspaceVal = innerInterspace.value
+    const finalLayout = {
+        transition: 'transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)',
+        transform: 'scaleY(1)',
+        top: `10px`
+    }
+    if (left + menuRect.width < winWidth) {
+        finalLayout.left = `-110px`
+    } else {
+        const val = winWidth - right
+        finalLayout.right = `${val > 0 ? val : 0}px`
+    }
+    Object.keys(layout).forEach(key => delete layout[key])
+    Object.assign(layout, finalLayout)
+    maskShow.value = true
+    emit('open')
+    emit('change', true)
+}
+const menuClick = (value, index) => {
+    emit('menuClick', { value, index })
+    close()
+}
+const close = () => {
+    maskShow.value = false
+    Object.keys(layout).forEach(key => delete layout[key])
+    layout.transform = 'scaleY(0)'
+    emit('close')
+    emit('change', false)
+}
+onMounted(() => {
+    getSystemInfo()
+    innerInterspace.value = str2px(props.interspace)
+})
+</script>
+
+<style lang="scss" scoped>
+@import '@/uni.scss';
+
+.cwg-dropdown {
+    width: fit-content;
+    position: relative;
+    overflow: hidden;
+}
+
+.cwg-dropdown-menu {
+    position: relative;
+    z-index: 1000;
+}
+
+.cwg-dropdown-mask {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100vw;
+    height: 100vh;
+    z-index: 999;
+    transition: all 0.3s;
+    opacity: 0;
+    pointer-events: none;
+    background-color: rgba(0, 0, 0, 0);
+}
+
+.cwg-dropdown-mask-show {
+    opacity: 1;
+    pointer-events: auto;
+}
+
+.cwg-dropdown-menu-container {
+    position: absolute;
+    transform-origin: top;
+    transform: scaleY(0);
+
+    .menu {
+        position: relative;
+        background: #FFFFFF;
+        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+        border-radius: px2rpx(4);
+        overflow: hidden;
+
+        .menu-item {
+            width: px2rpx(150);
+            display: flex;
+            align-items: center;
+            padding: px2rpx(10) px2rpx(16);
+            font-size: px2rpx(14);
+            line-height: px2rpx(30);
+            color: #333;
+            transition: background 0.2s;
+            border-bottom: 1px solid #f0f0f0;
+            box-sizing: border-box;
+
+            &:last-child {
+                border-bottom: none;
+            }
+
+            text {
+                flex: 1;
+                line-height: 1.4;
+            }
+
+            &:hover {
+                background-color: rgba(0, 0, 0, 0.05);
+            }
+
+            &:active {
+                background-color: rgba(0, 0, 0, 0.05);
+            }
+        }
+    }
+}
+</style>

+ 12 - 14
components/cwg-header.vue

@@ -1,18 +1,15 @@
 <template>
-  <uni-nav-bar :leftWidth="0" :rightWidth="0" :statusBar="true" :fixed="true" :height="60"
-    :backgroundColor="props.backgrounds || '#fff'" :border="false" :a="props.backgrounds">
-    <view class="pages-header">
-      <view class="header">
-        <view v-if="showBack" class="back">
-          <cwg-icon name="dropdown" class="back-icon" color="#000" @click="handleBack" />
-        </view>
-        <view>{{ headerTitleReady ? headerTitle : '' }}</view>
-      </view>
-      <view class="header-r">
-        <slot></slot>
+  <view class="pages-header" v-if="showBack">
+    <view class="header">
+      <view v-if="showBack" class="back">
+        <cwg-icon name="dropdown" class="back-icon" color="#000" @click="handleBack" />
       </view>
+      <view>{{ headerTitleReady ? headerTitle : '' }}</view>
+    </view>
+    <view class="header-r">
+      <slot></slot>
     </view>
-  </uni-nav-bar>
+  </view>
 </template>
 
 <script setup lang="ts">
@@ -83,13 +80,14 @@ function handleBack() {
   align-items: center;
   justify-content: space-between;
   box-sizing: border-box;
+  margin-bottom: px2rpx(24);
 }
 
 .header {
   position: relative;
   text-align: left;
-  font-size: var(--font-size-22);
-  color: var(--white);
+  font-size: px2rpx(32);
+  color: #141d22;
   font-weight: 700;
   margin: px2rpx(10) 0;
   height: px2rpx(40);

+ 11 - 6
components/cwg-label-line-value.vue

@@ -1,8 +1,11 @@
 <template>
     <view class="info-item">
-        <span class="label">{{ label }}</span>
-        <span class="line"></span>
-        <span class="value">{{ value }}</span>
+        <view class="label">{{ label }}</view>
+        <view class="line"></view>
+        <view class="value">
+            <view>{{ value }}</view>
+            <slot name="operation" />
+        </view>
     </view>
 </template>
 
@@ -24,24 +27,26 @@ const props = defineProps({
 @import "@/uni.scss";
 
 .info-item {
+    width: 100%;
     display: flex;
     justify-content: space-between;
     align-items: flex-end;
     font-size: px2rpx(14);
+    line-height: px2rpx(24);
 
     .label {
         color: #6c8595;
     }
-
     .line {
         flex: 1;
         height: 1px;
-        border-top: 1px dashed rgba(108, 133, 149, 0.5);
+        border-top: 1px dashed rgba(20, 29, 34, .122);
         margin-bottom: px2rpx(1);
 
     }
-
     .value {
+        display: flex;
+        align-items: flex-end;
         font-weight: 500;
         color: #2e3a47;
     }

+ 1 - 1
components/cwg-page-wrapper.vue

@@ -9,7 +9,6 @@
       <cwg-match-media :max-width="991" v-if="!isLoginPage">
         <view class="left-sidebar" :class="{ 'sidebar-visible': sidebarVisible }">
           <cwg-sidebar />
-
         </view>
         <view class="sidebar-mask" v-if="sidebarVisible" @click="openLeftDrawer" :style="{
           opacity: sidebarVisible ? 1 : 0,
@@ -17,6 +16,7 @@
         }"></view>
       </cwg-match-media>
       <view class="content-wrapper" :class="{ 'content-wrapper-padding': isContentPadding }">
+        <cwg-header />
         <slot />
       </view>
       <view :style="{ height: isTabBarPage ? '60px' : '0px' }" />

+ 9 - 6
components/cwg-popup.vue

@@ -1,6 +1,6 @@
 <template>
-    <uni-popup ref="popupRef" type="center" :mask-click="false" @change="handlePopupChange">
-        <view class="delete-account-dialog">
+    <uni-popup ref="popupRef" type="center" @change="handlePopupChange">
+        <view class="cwg-dialog">
             <!-- 弹窗头部 -->
             <view class="dialog-header">
                 <text class="dialog-title">{{ title || t('Tips.DeleteAccount') }}</text>
@@ -168,18 +168,21 @@ defineExpose({
 <style scoped lang="scss">
 @import "@/uni.scss";
 
-.delete-account-dialog {
+.cwg-dialog {
     background-color: var(--color-white);
     border-radius: px2rpx(8);
     overflow: hidden;
     width: px2rpx(600);
     max-width: 90vw;
+}
 
-    @media (min-width: 768px) {
-        width: px2rpx(800);
+@media (min-width: 768px) {
+    :deep(.cwg-dialog) {
+        width: px2rpx(600) !important;
     }
 }
 
+
 .dialog-header {
     display: flex;
     align-items: center;
@@ -195,7 +198,7 @@ defineExpose({
 }
 
 .dialog-content {
-    padding: px2rpx(20);
+    padding: px2rpx(20) px2rpx(30);
     max-height: 60vh;
     overflow-y: auto;
 

+ 9 - 4
config/index.ts

@@ -11,16 +11,21 @@ let ho = '44a5c8109e4'; // 默认主域名或可根据实际APP环境配置
 const config = {
 
   HostWs: "wss://ws." + ho + ".com",
-  Host80: ht + "//secure." + ho + ".com",
-  Host00: ht + "//ucard." + ho + ".com",
-  Host85: ht + "//ucard." + ho + ".com",
-  Host04: ht + "//pay." + ho + ".com",
+  // Host80: ht + "//secure." + ho + ".com",
+  // Host00: ht + "//ucard." + ho + ".com",
+  // Host85: ht + "//ucard." + ho + ".com",
+  // Host04: ht + "//pay." + ho + ".com",
+  Host80: 'http://192.168.0.21:8000',
+  Host00: 'http://192.168.0.21:8000',
+  Host85: 'http://192.168.0.21:8000',
+  Host04: 'http://192.168.0.21:8004',
   Host90: ht + "//data." + ho + ".com",
   HostShop: ht + "//shopcustom." + ho + ".com",
   HostShopImg: ht + "//shopmanager." + ho + ".com",
   Host87: ht + "//followup." + ho + ".com",
   Host05: ht + "//file." + ho + ".com",
   HostEnter: ht + "//ad." + ho + ".com",
+  ho,
   Code: {
     StatusOK: 200,
     StatusFail: 400,

+ 403 - 0
global/constPY.js

@@ -0,0 +1,403 @@
+export const pinyin = {
+  'a': '\u554a\u963f\u9515',
+  'ai': '\u57c3\u6328\u54ce\u5509\u54c0\u7691\u764c\u853c\u77ee\u827e\u788d\u7231\u9698\u8bf6\u6371\u55f3\u55cc\u5ad2\u7477\u66a7\u7839\u953f\u972d',
+  'an': '\u978d\u6c28\u5b89\u4ffa\u6309\u6697\u5cb8\u80fa\u6848\u8c19\u57ef\u63de\u72b4\u5eb5\u6849\u94f5\u9e4c\u9878\u9eef',
+  'ang': '\u80ae\u6602\u76ce',
+  'ao': '\u51f9\u6556\u71ac\u7ff1\u8884\u50b2\u5965\u61ca\u6fb3\u5773\u62d7\u55f7\u5662\u5c99\u5ed2\u9068\u5aaa\u9a9c\u8071\u87af\u93ca\u9ccc\u93d6',
+  'ba': '\u82ad\u634c\u6252\u53ed\u5427\u7b06\u516b\u75a4\u5df4\u62d4\u8dcb\u9776\u628a\u8019\u575d\u9738\u7f62\u7238\u8307\u83dd\u8406\u636d\u5c9c\u705e\u6777\u94af\u7c91\u9c85\u9b43',
+  'bai': '\u767d\u67cf\u767e\u6446\u4f70\u8d25\u62dc\u7a17\u859c\u63b0\u97b4',
+  'ban': '\u6591\u73ed\u642c\u6273\u822c\u9881\u677f\u7248\u626e\u62cc\u4f34\u74e3\u534a\u529e\u7eca\u962a\u5742\u8c73\u94a3\u7622\u764d\u8228',
+  'bang': '\u90a6\u5e2e\u6886\u699c\u8180\u7ed1\u68d2\u78c5\u868c\u9551\u508d\u8c24\u84a1\u8783',
+  'bao': '\u82de\u80de\u5305\u8912\u96f9\u4fdd\u5821\u9971\u5b9d\u62b1\u62a5\u66b4\u8c79\u9c8d\u7206\u52f9\u8446\u5b80\u5b62\u7172\u9e28\u8913\u8db5\u9f85',
+  'bo': '\u5265\u8584\u73bb\u83e0\u64ad\u62e8\u94b5\u6ce2\u535a\u52c3\u640f\u94c2\u7b94\u4f2f\u5e1b\u8236\u8116\u818a\u6e24\u6cca\u9a73\u4eb3\u8543\u5575\u997d\u6a97\u64d8\u7934\u94b9\u9e41\u7c38\u8ddb',
+  'bei': '\u676f\u7891\u60b2\u5351\u5317\u8f88\u80cc\u8d1d\u94a1\u500d\u72c8\u5907\u60eb\u7119\u88ab\u5b5b\u9642\u90b6\u57e4\u84d3\u5457\u602b\u6096\u789a\u9e4e\u8919\u943e',
+  'ben': '\u5954\u82ef\u672c\u7b28\u755a\u574c\u951b',
+  'beng': '\u5d29\u7ef7\u752d\u6cf5\u8e66\u8ff8\u552a\u5623\u750f',
+  'bi': '\u903c\u9f3b\u6bd4\u9119\u7b14\u5f7c\u78a7\u84d6\u853d\u6bd5\u6bd9\u6bd6\u5e01\u5e87\u75f9\u95ed\u655d\u5f0a\u5fc5\u8f9f\u58c1\u81c2\u907f\u965b\u5315\u4ef3\u4ffe\u8298\u835c\u8378\u5421\u54d4\u72f4\u5eb3\u610e\u6ed7\u6fde\u5f3c\u59a3\u5a62\u5b16\u74a7\u8d32\u7540\u94cb\u79d5\u88e8\u7b5a\u7b85\u7be6\u822d\u895e\u8df8\u9ac0',
+  'bian': '\u97ad\u8fb9\u7f16\u8d2c\u6241\u4fbf\u53d8\u535e\u8fa8\u8fa9\u8fab\u904d\u533e\u5f01\u82c4\u5fed\u6c74\u7f0f\u7178\u782d\u78a5\u7a39\u7a86\u8759\u7b3e\u9cca',
+  'biao': '\u6807\u5f6a\u8198\u8868\u5a4a\u9aa0\u98d1\u98d9\u98da\u706c\u9556\u9573\u762d\u88f1\u9cd4',
+  'bie': '\u9cd6\u618b\u522b\u762a\u8e69\u9cd8',
+  'bin': '\u5f6c\u658c\u6fd2\u6ee8\u5bbe\u6448\u50a7\u6d5c\u7f24\u73a2\u6ba1\u8191\u9554\u9acc\u9b13',
+  'bing': '\u5175\u51b0\u67c4\u4e19\u79c9\u997c\u70b3\u75c5\u5e76\u7980\u90b4\u6452\u7ee0\u678b\u69df\u71f9',
+  'bu': '\u6355\u535c\u54fa\u8865\u57e0\u4e0d\u5e03\u6b65\u7c3f\u90e8\u6016\u62ca\u535f\u900b\u74ff\u6661\u949a\u91ad',
+  'ca': '\u64e6\u5693\u7924',
+  'cai': '\u731c\u88c1\u6750\u624d\u8d22\u776c\u8e29\u91c7\u5f69\u83dc\u8521',
+  'can': '\u9910\u53c2\u8695\u6b8b\u60ed\u60e8\u707f\u9a96\u74a8\u7cb2\u9eea',
+  'cang': '\u82cd\u8231\u4ed3\u6ca7\u85cf\u4f27',
+  'cao': '\u64cd\u7cd9\u69fd\u66f9\u8349\u8279\u5608\u6f15\u87ac\u825a',
+  'ce': '\u5395\u7b56\u4fa7\u518c\u6d4b\u5202\u5e3b\u607b',
+  'ceng': '\u5c42\u8e6d\u564c',
+  'cha': '\u63d2\u53c9\u832c\u8336\u67e5\u78b4\u643d\u5bdf\u5c94\u5dee\u8be7\u7339\u9987\u6c4a\u59f9\u6748\u6942\u69ce\u6aab\u9497\u9538\u9572\u8869',
+  'chai': '\u62c6\u67f4\u8c7a\u4faa\u8308\u7625\u867f\u9f87',
+  'chan': '\u6400\u63ba\u8749\u998b\u8c17\u7f20\u94f2\u4ea7\u9610\u98a4\u5181\u8c04\u8c36\u8487\u5edb\u5fcf\u6f7a\u6fb6\u5b71\u7fbc\u5a75\u5b17\u9aa3\u89c7\u7985\u9561\u88e3\u87fe\u8e94',
+  'chang': '\u660c\u7316\u573a\u5c1d\u5e38\u957f\u507f\u80a0\u5382\u655e\u7545\u5531\u5021\u4f25\u9b2f\u82cc\u83d6\u5f9c\u6005\u60dd\u960a\u5a3c\u5ae6\u6636\u6c05\u9cb3',
+  'chao': '\u8d85\u6284\u949e\u671d\u5632\u6f6e\u5de2\u5435\u7092\u600a\u7ec9\u6641\u8016',
+  'che': '\u8f66\u626f\u64a4\u63a3\u5f7b\u6f88\u577c\u5c6e\u7817',
+  'chen': '\u90f4\u81e3\u8fb0\u5c18\u6668\u5ff1\u6c89\u9648\u8d81\u886c\u79f0\u8c0c\u62bb\u55d4\u5bb8\u741b\u6987\u809c\u80c2\u789c\u9f80',
+  'cheng': '\u6491\u57ce\u6a59\u6210\u5448\u4e58\u7a0b\u60e9\u6f84\u8bda\u627f\u901e\u9a8b\u79e4\u57d5\u5d4a\u5fb5\u6d48\u67a8\u67fd\u6a18\u665f\u584d\u77a0\u94d6\u88ce\u86cf\u9172',
+  'chi': '\u5403\u75f4\u6301\u5319\u6c60\u8fdf\u5f1b\u9a70\u803b\u9f7f\u4f88\u5c3a\u8d64\u7fc5\u65a5\u70bd\u50ba\u5880\u82aa\u830c\u640b\u53f1\u54e7\u557b\u55e4\u5f73\u996c\u6cb2\u5ab8\u6555\u80dd\u7719\u7735\u9e31\u761b\u892b\u86a9\u87ad\u7b1e\u7bea\u8c49\u8e05\u8e1f\u9b51',
+  'chong': '\u5145\u51b2\u866b\u5d07\u5ba0\u833a\u5fe1\u61a7\u94f3\u825f',
+  'chou': '\u62bd\u916c\u7574\u8e0c\u7a20\u6101\u7b79\u4ec7\u7ef8\u7785\u4e11\u4fe6\u5733\u5e31\u60c6\u6eb4\u59af\u7633\u96e0\u9c8b',
+  'chu': '\u81ed\u521d\u51fa\u6a71\u53a8\u8e87\u9504\u96cf\u6ec1\u9664\u695a\u7840\u50a8\u77d7\u6410\u89e6\u5904\u4e8d\u520d\u61b7\u7ecc\u6775\u696e\u6a17\u870d\u8e70\u9edc',
+  'chuan': '\u63e3\u5ddd\u7a7f\u693d\u4f20\u8239\u5598\u4e32\u63be\u821b\u60f4\u9044\u5ddb\u6c1a\u948f\u9569\u8221',
+  'chuang': '\u75ae\u7a97\u5e62\u5e8a\u95ef\u521b\u6006',
+  'chui': '\u5439\u708a\u6376\u9524\u5782\u9672\u68f0\u69cc',
+  'chun': '\u6625\u693f\u9187\u5507\u6df3\u7eaf\u8822\u4fc3\u83bc\u6c8c\u80ab\u6710\u9e51\u877d',
+  'chuo': '\u6233\u7ef0\u851f\u8fb6\u8f8d\u955e\u8e14\u9f8a',
+  'ci': '\u75b5\u8328\u78c1\u96cc\u8f9e\u6148\u74f7\u8bcd\u6b64\u523a\u8d50\u6b21\u8360\u5472\u5d6f\u9e5a\u8785\u7ccd\u8d91',
+  'cong': '\u806a\u8471\u56f1\u5306\u4ece\u4e1b\u506c\u82c1\u6dd9\u9aa2\u742e\u7481\u679e',
+  'cu': '\u51d1\u7c97\u918b\u7c07\u731d\u6b82\u8e59',
+  'cuan': '\u8e7f\u7be1\u7a9c\u6c46\u64ba\u6615\u7228',
+  'cui': '\u6467\u5d14\u50ac\u8106\u7601\u7cb9\u6dec\u7fe0\u8403\u60b4\u7480\u69b1\u96b9',
+  'cun': '\u6751\u5b58\u5bf8\u78cb\u5fd6\u76b4',
+  'cuo': '\u64ae\u6413\u63aa\u632b\u9519\u539d\u811e\u9509\u77ec\u75e4\u9e7e\u8e49\u8e9c',
+  'da': '\u642d\u8fbe\u7b54\u7629\u6253\u5927\u8037\u54d2\u55d2\u601b\u59b2\u75b8\u8921\u7b2a\u977c\u9791',
+  'dai': '\u5446\u6b79\u50a3\u6234\u5e26\u6b86\u4ee3\u8d37\u888b\u5f85\u902e\u6020\u57ed\u7519\u5454\u5cb1\u8fe8\u902f\u9a80\u7ed0\u73b3\u9edb',
+  'dan': '\u803d\u62c5\u4e39\u5355\u90f8\u63b8\u80c6\u65e6\u6c2e\u4f46\u60ee\u6de1\u8bde\u5f39\u86cb\u4ebb\u510b\u5369\u840f\u5556\u6fb9\u6a90\u6b9a\u8d55\u7708\u7605\u8043\u7baa',
+  'dang': '\u5f53\u6321\u515a\u8361\u6863\u8c20\u51fc\u83ea\u5b95\u7800\u94db\u88c6',
+  'dao': '\u5200\u6363\u8e48\u5012\u5c9b\u7977\u5bfc\u5230\u7a3b\u60bc\u9053\u76d7\u53e8\u5541\u5fc9\u6d2e\u6c18\u7118\u5fd1\u7e9b',
+  'de': '\u5fb7\u5f97\u7684\u951d',
+  'deng': '\u8e6c\u706f\u767b\u7b49\u77aa\u51f3\u9093\u5654\u5d9d\u6225\u78f4\u956b\u7c26',
+  'di': '\u5824\u4f4e\u6ef4\u8fea\u654c\u7b1b\u72c4\u6da4\u7fdf\u5ae1\u62b5\u5e95\u5730\u8482\u7b2c\u5e1d\u5f1f\u9012\u7f14\u6c10\u7c74\u8bcb\u8c1b\u90b8\u577b\u839c\u837b\u5600\u5a23\u67e2\u68e3\u89cc\u7825\u78b2\u7747\u955d\u7f9d\u9ab6',
+  'dian': '\u98a0\u6382\u6ec7\u7898\u70b9\u5178\u975b\u57ab\u7535\u4f43\u7538\u5e97\u60e6\u5960\u6dc0\u6bbf\u4e36\u963d\u576b\u57dd\u5dc5\u73b7\u765c\u766b\u7c1f\u8e2e',
+  'diao': '\u7889\u53fc\u96d5\u51cb\u5201\u6389\u540a\u9493\u8c03\u8f7a\u94de\u8729\u7c9c\u8c82',
+  'die': '\u8dcc\u7239\u789f\u8776\u8fed\u8c0d\u53e0\u4f5a\u57a4\u581e\u63f2\u558b\u6e2b\u8f76\u7252\u74de\u8936\u800b\u8e40\u9cbd\u9cce',
+  'ding': '\u4e01\u76ef\u53ee\u9489\u9876\u9f0e\u952d\u5b9a\u8ba2\u4e22\u4ec3\u5576\u738e\u815a\u7887\u753a\u94e4\u7594\u8035\u914a',
+  'dong': '\u4e1c\u51ac\u8463\u61c2\u52a8\u680b\u4f97\u606b\u51bb\u6d1e\u578c\u549a\u5cbd\u5cd2\u5902\u6c21\u80e8\u80f4\u7850\u9e2b',
+  'dou': '\u515c\u6296\u6597\u9661\u8c46\u9017\u75d8\u8538\u94ad\u7aa6\u7aac\u86aa\u7bfc\u9161',
+  'du': '\u90fd\u7763\u6bd2\u728a\u72ec\u8bfb\u5835\u7779\u8d4c\u675c\u9540\u809a\u5ea6\u6e21\u5992\u828f\u561f\u6e0e\u691f\u6a50\u724d\u8839\u7b03\u9ad1\u9ee9',
+  'duan': '\u7aef\u77ed\u953b\u6bb5\u65ad\u7f0e\u5f56\u6934\u7145\u7c16',
+  'dui': '\u5806\u5151\u961f\u5bf9\u603c\u619d\u7893',
+  'dun': '\u58a9\u5428\u8e72\u6566\u987f\u56e4\u949d\u76fe\u9041\u7096\u7818\u7905\u76f9\u9566\u8db8',
+  'duo': '\u6387\u54c6\u591a\u593a\u579b\u8eb2\u6735\u8dfa\u8235\u5241\u60f0\u5815\u5484\u54da\u7f0d\u67c1\u94ce\u88f0\u8e31',
+  'e': '\u86fe\u5ce8\u9e45\u4fc4\u989d\u8bb9\u5a25\u6076\u5384\u627c\u904f\u9102\u997f\u5669\u8c14\u57a9\u57ad\u82ca\u83aa\u843c\u5443\u6115\u5c59\u5a40\u8f6d\u66f7\u816d\u786a\u9507\u9537\u9e57\u989a\u9cc4',
+  'en': '\u6069\u84bd\u6441\u5514\u55ef',
+  'er': '\u800c\u513f\u8033\u5c14\u9975\u6d31\u4e8c\u8d30\u8fe9\u73e5\u94d2\u9e38\u9c95',
+  'fa': '\u53d1\u7f5a\u7b4f\u4f10\u4e4f\u9600\u6cd5\u73d0\u57a1\u781d',
+  'fan': '\u85e9\u5e06\u756a\u7ffb\u6a0a\u77fe\u9492\u7e41\u51e1\u70e6\u53cd\u8fd4\u8303\u8d29\u72af\u996d\u6cdb\u8629\u5e61\u72ad\u68b5\u6535\u71d4\u7548\u8e6f',
+  'fang': '\u574a\u82b3\u65b9\u80aa\u623f\u9632\u59a8\u4eff\u8bbf\u7eba\u653e\u531a\u90a1\u5f77\u94ab\u822b\u9c82',
+  'fei': '\u83f2\u975e\u5561\u98de\u80a5\u532a\u8bfd\u5420\u80ba\u5e9f\u6cb8\u8d39\u82be\u72d2\u60b1\u6ddd\u5983\u7ecb\u7eef\u69a7\u8153\u6590\u6249\u7953\u7829\u9544\u75f1\u871a\u7bda\u7fe1\u970f\u9cb1',
+  'fen': '\u82ac\u915a\u5429\u6c1b\u5206\u7eb7\u575f\u711a\u6c7e\u7c89\u594b\u4efd\u5fff\u6124\u7caa\u507e\u7035\u68fc\u610d\u9cbc\u9f22',
+  'feng': '\u4e30\u5c01\u67ab\u8702\u5cf0\u950b\u98ce\u75af\u70fd\u9022\u51af\u7f1d\u8bbd\u5949\u51e4\u4ff8\u9146\u8451\u6ca3\u781c',
+  'fu': '\u4f5b\u5426\u592b\u6577\u80a4\u5b75\u6276\u62c2\u8f90\u5e45\u6c1f\u7b26\u4f0f\u4fd8\u670d\u6d6e\u6daa\u798f\u88b1\u5f17\u752b\u629a\u8f85\u4fef\u91dc\u65a7\u812f\u8151\u5e9c\u8150\u8d74\u526f\u8986\u8d4b\u590d\u5085\u4ed8\u961c\u7236\u8179\u8d1f\u5bcc\u8ba3\u9644\u5987\u7f1a\u5490\u5310\u51eb\u90db\u8299\u82fb\u832f\u83a9\u83d4\u544b\u5e5e\u6ecf\u8274\u5b5a\u9a78\u7ec2\u6874\u8d59\u9efb\u9efc\u7f58\u7a03\u99a5\u864d\u86a8\u8709\u8760\u876e\u9eb8\u8dba\u8dd7\u9cc6',
+  'ga': '\u5676\u560e\u86e4\u5c2c\u5477\u5c15\u5c1c\u65ee\u9486',
+  'gai': '\u8be5\u6539\u6982\u9499\u76d6\u6e89\u4e10\u9654\u5793\u6224\u8d45\u80f2',
+  'gan': '\u5e72\u7518\u6746\u67d1\u7aff\u809d\u8d76\u611f\u79c6\u6562\u8d63\u5769\u82f7\u5c34\u64c0\u6cd4\u6de6\u6f89\u7ec0\u6a44\u65f0\u77f8\u75b3\u9150',
+  'gang': '\u5188\u521a\u94a2\u7f38\u809b\u7eb2\u5c97\u6e2f\u6206\u7f61\u9883\u7b7b',
+  'gong': '\u6760\u5de5\u653b\u529f\u606d\u9f9a\u4f9b\u8eac\u516c\u5bab\u5f13\u5de9\u6c5e\u62f1\u8d21\u5171\u857b\u5efe\u54a3\u73d9\u80b1\u86a3\u86e9\u89e5',
+  'gao': '\u7bd9\u768b\u9ad8\u818f\u7f94\u7cd5\u641e\u9550\u7a3f\u544a\u777e\u8bf0\u90dc\u84bf\u85c1\u7f1f\u69d4\u69c1\u6772\u9506',
+  'ge': '\u54e5\u6b4c\u6401\u6208\u9e3d\u80f3\u7599\u5272\u9769\u845b\u683c\u9601\u9694\u94ec\u4e2a\u5404\u9b32\u4ee1\u54ff\u5865\u55dd\u7ea5\u643f\u8188\u784c\u94ea\u9549\u88bc\u988c\u867c\u8238\u9abc\u9ac2',
+  'gei': '\u7ed9',
+  'gen': '\u6839\u8ddf\u4e98\u831b\u54cf\u826e',
+  'geng': '\u8015\u66f4\u5e9a\u7fb9\u57c2\u803f\u6897\u54fd\u8d53\u9ca0',
+  'gou': '\u94a9\u52fe\u6c9f\u82df\u72d7\u57a2\u6784\u8d2d\u591f\u4f5d\u8bdf\u5ca3\u9058\u5abe\u7f11\u89cf\u5f40\u9e32\u7b31\u7bdd\u97b2',
+  'gu': '\u8f9c\u83c7\u5495\u7b8d\u4f30\u6cbd\u5b64\u59d1\u9f13\u53e4\u86ca\u9aa8\u8c37\u80a1\u6545\u987e\u56fa\u96c7\u560f\u8bc2\u83f0\u54cc\u5d2e\u6c69\u688f\u8f71\u726f\u727f\u80cd\u81cc\u6bc2\u77bd\u7f5f\u94b4\u9522\u74e0\u9e2a\u9e44\u75fc\u86c4\u9164\u89da\u9cb4\u9ab0\u9e58',
+  'gua': '\u522e\u74dc\u5250\u5be1\u6302\u8902\u5366\u8bd6\u5471\u681d\u9e39',
+  'guai': '\u4e56\u62d0\u602a\u54d9',
+  'guan': '\u68fa\u5173\u5b98\u51a0\u89c2\u7ba1\u9986\u7f50\u60ef\u704c\u8d2f\u500c\u839e\u63bc\u6dab\u76e5\u9e73\u9ccf',
+  'guang': '\u5149\u5e7f\u901b\u72b7\u6844\u80f1\u7592',
+  'gui': '\u7470\u89c4\u572d\u7845\u5f52\u9f9f\u95fa\u8f68\u9b3c\u8be1\u7678\u6842\u67dc\u8dea\u8d35\u523d\u5326\u523f\u5e8b\u5b84\u59ab\u6867\u7085\u6677\u7688\u7c0b\u9c91\u9cdc',
+  'gun': '\u8f8a\u6eda\u68cd\u4e28\u886e\u7ef2\u78d9\u9ca7',
+  'guo': '\u9505\u90ed\u56fd\u679c\u88f9\u8fc7\u9998\u8803\u57da\u63b4\u5459\u56d7\u5e3c\u5d1e\u7313\u6901\u8662\u951e\u8052\u872e\u873e\u8748',
+  'ha': '\u54c8',
+  'hai': '\u9ab8\u5b69\u6d77\u6c26\u4ea5\u5bb3\u9a87\u54b4\u55e8\u988f\u91a2',
+  'han': '\u9163\u61a8\u90af\u97e9\u542b\u6db5\u5bd2\u51fd\u558a\u7f55\u7ff0\u64bc\u634d\u65f1\u61be\u608d\u710a\u6c57\u6c49\u9097\u83e1\u6496\u961a\u701a\u6657\u7113\u9894\u86b6\u9f3e',
+  'hen': '\u592f\u75d5\u5f88\u72e0\u6068',
+  'hang': '\u676d\u822a\u6c86\u7ed7\u73e9\u6841',
+  'hao': '\u58d5\u568e\u8c6a\u6beb\u90dd\u597d\u8017\u53f7\u6d69\u8585\u55e5\u5686\u6fe0\u704f\u660a\u7693\u98a2\u869d',
+  'he': '\u5475\u559d\u8377\u83cf\u6838\u79be\u548c\u4f55\u5408\u76d2\u8c89\u9602\u6cb3\u6db8\u8d6b\u8910\u9e64\u8d3a\u8bc3\u52be\u58d1\u85ff\u55d1\u55ec\u9616\u76cd\u86b5\u7fee',
+  'hei': '\u563f\u9ed1',
+  'heng': '\u54fc\u4ea8\u6a2a\u8861\u6052\u8a07\u8605',
+  'hong': '\u8f70\u54c4\u70d8\u8679\u9e3f\u6d2a\u5b8f\u5f18\u7ea2\u9ec9\u8ba7\u836d\u85a8\u95f3\u6cd3',
+  'hou': '\u5589\u4faf\u7334\u543c\u539a\u5019\u540e\u5820\u5f8c\u9005\u760a\u7bcc\u7cc7\u9c8e\u9aba',
+  'hu': '\u547c\u4e4e\u5ffd\u745a\u58f6\u846b\u80e1\u8774\u72d0\u7cca\u6e56\u5f27\u864e\u552c\u62a4\u4e92\u6caa\u6237\u51b1\u553f\u56eb\u5cb5\u7322\u6019\u60da\u6d52\u6ef9\u7425\u69f2\u8f77\u89f3\u70c0\u7173\u623d\u6248\u795c\u9e55\u9e71\u7b0f\u9190\u659b',
+  'hua': '\u82b1\u54d7\u534e\u733e\u6ed1\u753b\u5212\u5316\u8bdd\u5290\u6d4d\u9a85\u6866\u94e7\u7a1e',
+  'huai': '\u69d0\u5f8a\u6000\u6dee\u574f\u8fd8\u8e1d',
+  'huan': '\u6b22\u73af\u6853\u7f13\u6362\u60a3\u5524\u75ea\u8c62\u7115\u6da3\u5ba6\u5e7b\u90c7\u5942\u57b8\u64d0\u571c\u6d39\u6d63\u6f36\u5bf0\u902d\u7f33\u953e\u9ca9\u9b1f',
+  'huang': '\u8352\u614c\u9ec4\u78fa\u8757\u7c27\u7687\u51f0\u60f6\u714c\u6643\u5e4c\u604d\u8c0e\u968d\u5fa8\u6e5f\u6f62\u9051\u749c\u8093\u7640\u87e5\u7bc1\u9cc7',
+  'hui': '\u7070\u6325\u8f89\u5fbd\u6062\u86d4\u56de\u6bc1\u6094\u6167\u5349\u60e0\u6666\u8d3f\u79fd\u4f1a\u70e9\u6c47\u8bb3\u8bf2\u7ed8\u8bd9\u8334\u835f\u8559\u54d5\u5599\u96b3\u6d04\u5f57\u7f0b\u73f2\u6656\u605a\u867a\u87ea\u9ebe\u8886',
+  'hun': '\u8364\u660f\u5a5a\u9b42\u6d51\u6df7\u8be8\u9984\u960d\u6eb7\u7f17',
+  'huo': '\u8c41\u6d3b\u4f19\u706b\u83b7\u6216\u60d1\u970d\u8d27\u7978\u6509\u56af\u5925\u94ac\u952a\u956c\u8020\u8816',
+  'ji': '\u51fb\u573e\u57fa\u673a\u7578\u7a3d\u79ef\u7b95\u808c\u9965\u8ff9\u6fc0\u8ba5\u9e21\u59ec\u7ee9\u7f09\u5409\u6781\u68d8\u8f91\u7c4d\u96c6\u53ca\u6025\u75be\u6c72\u5373\u5ac9\u7ea7\u6324\u51e0\u810a\u5df1\u84df\u6280\u5180\u5b63\u4f0e\u796d\u5242\u60b8\u6d4e\u5bc4\u5bc2\u8ba1\u8bb0\u65e2\u5fcc\u9645\u5993\u7ee7\u7eaa\u5c45\u4e0c\u4e69\u525e\u4f76\u4f74\u8114\u58bc\u82a8\u82b0\u8401\u84ba\u857a\u638e\u53fd\u54ad\u54dc\u5527\u5c8c\u5d74\u6d0e\u5f50\u5c50\u9aa5\u757f\u7391\u696b\u6b9b\u621f\u6222\u8d4d\u89ca\u7284\u9f51\u77f6\u7f81\u5d47\u7a37\u7620\u7635\u866e\u7b08\u7b04\u66a8\u8dfb\u8dfd\u9701\u9c9a\u9cab\u9afb\u9e82',
+  'jia': '\u5609\u67b7\u5939\u4f73\u5bb6\u52a0\u835a\u988a\u8d3e\u7532\u94be\u5047\u7a3c\u4ef7\u67b6\u9a7e\u5ac1\u4f3d\u90cf\u62ee\u5cac\u6d43\u8fe6\u73c8\u621b\u80db\u605d\u94d7\u9553\u75c2\u86f1\u7b33\u8888\u8dcf',
+  'jian': '\u6b7c\u76d1\u575a\u5c16\u7b3a\u95f4\u714e\u517c\u80a9\u8270\u5978\u7f04\u8327\u68c0\u67ec\u78b1\u7877\u62e3\u6361\u7b80\u4fed\u526a\u51cf\u8350\u69db\u9274\u8df5\u8d31\u89c1\u952e\u7bad\u4ef6\u5065\u8230\u5251\u996f\u6e10\u6e85\u6da7\u5efa\u50ed\u8c0f\u8c2b\u83c5\u84b9\u641b\u56dd\u6e54\u8e47\u8b07\u7f23\u67a7\u67d9\u6957\u620b\u622c\u726e\u728d\u6bfd\u8171\u7751\u950f\u9e63\u88e5\u7b15\u7bb4\u7fe6\u8dbc\u8e3a\u9ca3\u97af',
+  'jiang': '\u50f5\u59dc\u5c06\u6d46\u6c5f\u7586\u848b\u6868\u5956\u8bb2\u5320\u9171\u964d\u8333\u6d1a\u7edb\u7f30\u729f\u7913\u8029\u7ce8\u8c47',
+  'jiao': '\u8549\u6912\u7901\u7126\u80f6\u4ea4\u90ca\u6d47\u9a84\u5a07\u56bc\u6405\u94f0\u77eb\u4fa5\u811a\u72e1\u89d2\u997a\u7f34\u7ede\u527f\u6559\u9175\u8f7f\u8f83\u53eb\u4f7c\u50ec\u832d\u6322\u564d\u5ce4\u5fbc\u59e3\u7e9f\u656b\u768e\u9e6a\u86df\u91ae\u8de4\u9c9b',
+  'jie': '\u7a96\u63ed\u63a5\u7686\u79f8\u8857\u9636\u622a\u52ab\u8282\u6854\u6770\u6377\u776b\u7aed\u6d01\u7ed3\u89e3\u59d0\u6212\u85c9\u82a5\u754c\u501f\u4ecb\u75a5\u8beb\u5c4a\u5048\u8ba6\u8bd8\u5588\u55df\u736c\u5a55\u5b51\u6840\u7352\u78a3\u9534\u7596\u88b7\u9889\u86a7\u7faf\u9c92\u9ab1\u9aeb',
+  'jin': '\u5dfe\u7b4b\u65a4\u91d1\u4eca\u6d25\u895f\u7d27\u9526\u4ec5\u8c28\u8fdb\u9773\u664b\u7981\u8fd1\u70ec\u6d78\u5c3d\u537a\u8369\u5807\u5664\u9991\u5ed1\u5997\u7f19\u747e\u69ff\u8d46\u89d0\u9485\u9513\u887f\u77dc',
+  'jing': '\u52b2\u8346\u5162\u830e\u775b\u6676\u9cb8\u4eac\u60ca\u7cbe\u7cb3\u7ecf\u4e95\u8b66\u666f\u9888\u9759\u5883\u656c\u955c\u5f84\u75c9\u9756\u7adf\u7ade\u51c0\u522d\u5106\u9631\u83c1\u734d\u61ac\u6cfe\u8ff3\u5f2a\u5a67\u80bc\u80eb\u8148\u65cc',
+  'jiong': '\u70af\u7a98\u5182\u8fe5\u6243',
+  'jiu': '\u63ea\u7a76\u7ea0\u7396\u97ed\u4e45\u7078\u4e5d\u9152\u53a9\u6551\u65e7\u81fc\u8205\u548e\u5c31\u759a\u50e6\u557e\u9604\u67e9\u6855\u9e6b\u8d73\u9b0f',
+  'ju': '\u97a0\u62d8\u72d9\u75bd\u9a79\u83ca\u5c40\u5480\u77e9\u4e3e\u6cae\u805a\u62d2\u636e\u5de8\u5177\u8ddd\u8e1e\u952f\u4ff1\u53e5\u60e7\u70ac\u5267\u5028\u8bb5\u82e3\u82f4\u8392\u63ac\u907d\u5c66\u741a\u67b8\u6910\u6998\u6989\u6a58\u728b\u98d3\u949c\u9514\u7aad\u88fe\u8d84\u91b5\u8e3d\u9f83\u96ce\u97ab',
+  'juan': '\u6350\u9e43\u5a1f\u5026\u7737\u5377\u7ee2\u9104\u72f7\u6d93\u684a\u8832\u9529\u954c\u96bd',
+  'jue': '\u6485\u652b\u6289\u6398\u5014\u7235\u89c9\u51b3\u8bc0\u7edd\u53a5\u5282\u8c32\u77cd\u8568\u5658\u5d1b\u7357\u5b53\u73cf\u6877\u6a5b\u721d\u9562\u8e76\u89d6',
+  'jun': '\u5747\u83cc\u94a7\u519b\u541b\u5cfb\u4fca\u7ae3\u6d5a\u90e1\u9a8f\u6343\u72fb\u76b2\u7b60\u9e87',
+  'ka': '\u5580\u5496\u5361\u4f67\u5494\u80e9',
+  'ke': '\u54af\u5777\u82db\u67ef\u68f5\u78d5\u9897\u79d1\u58f3\u54b3\u53ef\u6e34\u514b\u523b\u5ba2\u8bfe\u5ca2\u606a\u6e98\u9a92\u7f02\u73c2\u8f72\u6c2a\u778c\u94b6\u75b4\u7aa0\u874c\u9ac1',
+  'kai': '\u5f00\u63e9\u6977\u51ef\u6168\u5240\u57b2\u8488\u5ffe\u607a\u94e0\u950e',
+  'kan': '\u520a\u582a\u52d8\u574e\u780d\u770b\u4f83\u51f5\u83b0\u83b6\u6221\u9f9b\u77b0',
+  'kang': '\u5eb7\u6177\u7ce0\u625b\u6297\u4ea2\u7095\u5751\u4f09\u95f6\u94aa',
+  'kao': '\u8003\u62f7\u70e4\u9760\u5c3b\u6832\u7292\u94d0',
+  'ken': '\u80af\u5543\u57a6\u6073\u57a0\u88c9\u9880',
+  'keng': '\u542d\u5fd0\u94ff',
+  'kong': '\u7a7a\u6050\u5b54\u63a7\u5025\u5d06\u7b9c',
+  'kou': '\u62a0\u53e3\u6263\u5bc7\u82a4\u853b\u53e9\u770d\u7b58',
+  'ku': '\u67af\u54ed\u7a9f\u82e6\u9177\u5e93\u88e4\u5233\u5800\u55be\u7ed4\u9ab7',
+  'kua': '\u5938\u57ae\u630e\u8de8\u80ef\u4f89',
+  'kuai': '\u5757\u7b77\u4fa9\u5feb\u84af\u90d0\u8489\u72ef\u810d',
+  'kuan': '\u5bbd\u6b3e\u9acb',
+  'kuang': '\u5321\u7b50\u72c2\u6846\u77ff\u7736\u65f7\u51b5\u8bd3\u8bf3\u909d\u5739\u593c\u54d0\u7ea9\u8d36',
+  'kui': '\u4e8f\u76d4\u5cbf\u7aa5\u8475\u594e\u9b41\u5080\u9988\u6127\u6e83\u9997\u532e\u5914\u9697\u63c6\u55b9\u559f\u609d\u6126\u9615\u9035\u668c\u777d\u8069\u8770\u7bd1\u81fe\u8dec',
+  'kun': '\u5764\u6606\u6346\u56f0\u6083\u9603\u7428\u951f\u918c\u9cb2\u9ae1',
+  'kuo': '\u62ec\u6269\u5ed3\u9614\u86de',
+  'la': '\u5783\u62c9\u5587\u8721\u814a\u8fa3\u5566\u524c\u647a\u908b\u65ef\u782c\u760c',
+  'lai': '\u83b1\u6765\u8d56\u5d03\u5f95\u6d9e\u6fd1\u8d49\u7750\u94fc\u765e\u7c41',
+  'lan': '\u84dd\u5a6a\u680f\u62e6\u7bee\u9611\u5170\u6f9c\u8c30\u63fd\u89c8\u61d2\u7f06\u70c2\u6ee5\u5549\u5c9a\u61d4\u6f24\u6984\u6593\u7f71\u9567\u8934',
+  'lang': '\u7405\u6994\u72fc\u5eca\u90ce\u6717\u6d6a\u83a8\u8497\u5577\u9606\u9512\u7a02\u8782',
+  'lao': '\u635e\u52b3\u7262\u8001\u4f6c\u59e5\u916a\u70d9\u6d9d\u5520\u5d02\u6833\u94d1\u94f9\u75e8\u91aa',
+  'le': '\u52d2\u4e50\u808b\u4ec2\u53fb\u561e\u6cd0\u9cd3',
+  'lei': '\u96f7\u956d\u857e\u78ca\u7d2f\u5121\u5792\u64c2\u7c7b\u6cea\u7fb8\u8bd4\u837d\u54a7\u6f2f\u5ad8\u7f27\u6a91\u8012\u9179',
+  'ling': '\u68f1\u51b7\u62ce\u73b2\u83f1\u96f6\u9f84\u94c3\u4f36\u7f9a\u51cc\u7075\u9675\u5cad\u9886\u53e6\u4ee4\u9143\u5844\u82d3\u5464\u56f9\u6ce0\u7eeb\u67c3\u68c2\u74f4\u8046\u86c9\u7fce\u9cae',
+  'leng': '\u695e\u6123',
+  'li': '\u5398\u68a8\u7281\u9ece\u7bf1\u72f8\u79bb\u6f13\u7406\u674e\u91cc\u9ca4\u793c\u8389\u8354\u540f\u6817\u4e3d\u5389\u52b1\u783e\u5386\u5229\u5088\u4f8b\u4fd0\u75e2\u7acb\u7c92\u6ca5\u96b6\u529b\u7483\u54e9\u4fea\u4fda\u90e6\u575c\u82c8\u8385\u84e0\u85dc\u6369\u5456\u5533\u55b1\u7301\u6ea7\u6fa7\u9026\u5a0c\u5ae0\u9a8a\u7f21\u73de\u67a5\u680e\u8f79\u623e\u783a\u8a48\u7f79\u9502\u9e42\u75a0\u75ac\u86ce\u870a\u8821\u7b20\u7be5\u7c9d\u91b4\u8dde\u96f3\u9ca1\u9ce2\u9ee7',
+  'lian': '\u4fe9\u8054\u83b2\u8fde\u9570\u5ec9\u601c\u6d9f\u5e18\u655b\u8138\u94fe\u604b\u70bc\u7ec3\u631b\u8539\u5941\u6f4b\u6fc2\u5a08\u740f\u695d\u6b93\u81c1\u81a6\u88e2\u880a\u9ca2',
+  'liang': '\u7cae\u51c9\u6881\u7cb1\u826f\u4e24\u8f86\u91cf\u667e\u4eae\u8c05\u589a\u690b\u8e09\u9753\u9b49',
+  'liao': '\u64a9\u804a\u50da\u7597\u71ce\u5be5\u8fbd\u6f66\u4e86\u6482\u9563\u5ed6\u6599\u84fc\u5c25\u5639\u7360\u5bee\u7f2d\u948c\u9e69\u8022',
+  'lie': '\u5217\u88c2\u70c8\u52a3\u730e\u51bd\u57d2\u6d0c\u8d94\u8e90\u9b23',
+  'lin': '\u7433\u6797\u78f7\u9716\u4e34\u90bb\u9cde\u6dcb\u51db\u8d41\u541d\u853a\u5d99\u5eea\u9074\u6aa9\u8f9a\u77b5\u7cbc\u8e8f\u9e9f',
+  'liu': '\u6e9c\u7409\u69b4\u786b\u998f\u7559\u5218\u7624\u6d41\u67f3\u516d\u62a1\u507b\u848c\u6cd6\u6d4f\u905b\u9a9d\u7efa\u65d2\u7198\u950d\u954f\u9e68\u938f',
+  'long': '\u9f99\u804b\u5499\u7b3c\u7abf\u9686\u5784\u62e2\u9647\u5f04\u5785\u830f\u6cf7\u73d1\u680a\u80e7\u783b\u7643',
+  'lou': '\u697c\u5a04\u6402\u7bd3\u6f0f\u964b\u55bd\u5d5d\u9542\u7618\u8027\u877c\u9ac5',
+  'lu': '\u82a6\u5362\u9885\u5e90\u7089\u63b3\u5364\u864f\u9c81\u9e93\u788c\u9732\u8def\u8d42\u9e7f\u6f5e\u7984\u5f55\u9646\u622e\u5786\u6445\u64b8\u565c\u6cf8\u6e0c\u6f09\u7490\u680c\u6a79\u8f73\u8f82\u8f98\u6c07\u80ea\u9565\u9e2c\u9e6d\u7c0f\u823b\u9c88',
+  'lv': '\u9a74\u5415\u94dd\u4fa3\u65c5\u5c65\u5c61\u7f15\u8651\u6c2f\u5f8b\u7387\u6ee4\u7eff\u634b\u95fe\u6988\u8182\u7a06\u891b',
+  'luan': '\u5ce6\u5b6a\u6ee6\u5375\u4e71\u683e\u9e3e\u92ae',
+  'lue': '\u63a0\u7565\u950a',
+  'lun': '\u8f6e\u4f26\u4ed1\u6ca6\u7eb6\u8bba\u56f5',
+  'luo': '\u841d\u87ba\u7f57\u903b\u9523\u7ba9\u9aa1\u88f8\u843d\u6d1b\u9a86\u7edc\u502e\u8366\u645e\u7321\u6cfa\u6924\u8136\u9559\u7630\u96d2',
+  'ma': '\u5988\u9ebb\u739b\u7801\u8682\u9a6c\u9a82\u561b\u5417\u551b\u72b8\u5b37\u6769\u9ebd',
+  'mai': '\u57cb\u4e70\u9ea6\u5356\u8fc8\u8109\u52a2\u836c\u54aa\u973e',
+  'man': '\u7792\u9992\u86ee\u6ee1\u8513\u66fc\u6162\u6f2b\u8c29\u5881\u5e54\u7f26\u71b3\u9558\u989f\u87a8\u9cd7\u9794',
+  'mang': '\u8292\u832b\u76f2\u5fd9\u83bd\u9099\u6f2d\u6726\u786d\u87d2',
+  'meng': '\u6c13\u840c\u8499\u6aac\u76df\u9530\u731b\u68a6\u5b5f\u52d0\u750d\u77a2\u61f5\u791e\u867b\u8722\u8813\u824b\u8268\u9efe',
+  'miao': '\u732b\u82d7\u63cf\u7784\u85d0\u79d2\u6e3a\u5e99\u5999\u55b5\u9088\u7f08\u7f2a\u676a\u6dfc\u7707\u9e4b\u8731',
+  'mao': '\u8305\u951a\u6bdb\u77db\u94c6\u536f\u8302\u5192\u5e3d\u8c8c\u8d38\u4f94\u88a4\u52d6\u8306\u5cc1\u7441\u6634\u7266\u8004\u65c4\u61cb\u7780\u86d1\u8765\u87ca\u9ae6',
+  'me': '\u4e48',
+  'mei': '\u73ab\u679a\u6885\u9176\u9709\u7164\u6ca1\u7709\u5a92\u9541\u6bcf\u7f8e\u6627\u5bd0\u59b9\u5a9a\u5776\u8393\u5d4b\u7338\u6d7c\u6e44\u6963\u9545\u9e5b\u8882\u9b45',
+  'men': '\u95e8\u95f7\u4eec\u626a\u739f\u7116\u61d1\u9494',
+  'mi': '\u772f\u919a\u9761\u7cdc\u8ff7\u8c1c\u5f25\u7c73\u79d8\u89c5\u6ccc\u871c\u5bc6\u5e42\u8288\u5196\u8c27\u863c\u5627\u7315\u736f\u6c68\u5b93\u5f2d\u8112\u6549\u7cf8\u7e3b\u9e8b',
+  'mian': '\u68c9\u7720\u7ef5\u5195\u514d\u52c9\u5a29\u7f05\u9762\u6c94\u6e4e\u817c\u7704',
+  'mie': '\u8511\u706d\u54a9\u881b\u7bfe',
+  'min': '\u6c11\u62bf\u76bf\u654f\u60af\u95fd\u82e0\u5cb7\u95f5\u6cef\u73c9',
+  'ming': '\u660e\u879f\u9e23\u94ed\u540d\u547d\u51a5\u8317\u6e9f\u669d\u7791\u9169',
+  'miu': '\u8c2c',
+  'mo': '\u6478\u6479\u8611\u6a21\u819c\u78e8\u6469\u9b54\u62b9\u672b\u83ab\u58a8\u9ed8\u6cab\u6f20\u5bde\u964c\u8c1f\u8309\u84e6\u998d\u5aeb\u9546\u79e3\u763c\u8031\u87c6\u8c8a\u8c98',
+  'mou': '\u8c0b\u725f\u67d0\u53b6\u54de\u5a7a\u7738\u936a',
+  'mu': '\u62c7\u7261\u4ea9\u59c6\u6bcd\u5893\u66ae\u5e55\u52df\u6155\u6728\u76ee\u7766\u7267\u7a46\u4eeb\u82dc\u5452\u6c90\u6bea\u94bc',
+  'na': '\u62ff\u54ea\u5450\u94a0\u90a3\u5a1c\u7eb3\u5185\u637a\u80ad\u954e\u8872\u7bac',
+  'nai': '\u6c16\u4e43\u5976\u8010\u5948\u9f10\u827f\u8418\u67f0',
+  'nan': '\u5357\u7537\u96be\u56ca\u5583\u56e1\u6960\u8169\u877b\u8d67',
+  'nao': '\u6320\u8111\u607c\u95f9\u5b6c\u57b4\u7331\u7459\u7847\u94d9\u86f2',
+  'ne': '\u6dd6\u5462\u8bb7',
+  'nei': '\u9981',
+  'nen': '\u5ae9\u80fd\u6798\u6041',
+  'ni': '\u59ae\u9713\u502a\u6ce5\u5c3c\u62df\u4f60\u533f\u817b\u9006\u6eba\u4f32\u576d\u730a\u6029\u6ee0\u6635\u65ce\u7962\u615d\u7768\u94cc\u9cb5',
+  'nian': '\u852b\u62c8\u5e74\u78be\u64b5\u637b\u5ff5\u5eff\u8f87\u9ecf\u9c87\u9cb6',
+  'niang': '\u5a18\u917f',
+  'niao': '\u9e1f\u5c3f\u8311\u5b32\u8132\u8885',
+  'nie': '\u634f\u8042\u5b7d\u556e\u954a\u954d\u6d85\u4e5c\u9667\u8616\u55eb\u8080\u989e\u81ec\u8e51',
+  'nin': '\u60a8\u67e0',
+  'ning': '\u72de\u51dd\u5b81\u62e7\u6cde\u4f5e\u84e5\u549b\u752f\u804d',
+  'niu': '\u725b\u626d\u94ae\u7ebd\u72c3\u5ff8\u599e\u86b4',
+  'nong': '\u8113\u6d53\u519c\u4fac',
+  'nu': '\u5974\u52aa\u6012\u5476\u5e11\u5f29\u80ec\u5b65\u9a7d',
+  'nv': '\u5973\u6067\u9495\u8844',
+  'nuan': '\u6696',
+  'nuenue': '\u8650',
+  'nue': '\u759f\u8c11',
+  'nuo': '\u632a\u61e6\u7cef\u8bfa\u50a9\u6426\u558f\u9518',
+  'ou': '\u54e6\u6b27\u9e25\u6bb4\u85d5\u5455\u5076\u6ca4\u6004\u74ef\u8026',
+  'pa': '\u556a\u8db4\u722c\u5e15\u6015\u7436\u8469\u7b62',
+  'pai': '\u62cd\u6392\u724c\u5f98\u6e43\u6d3e\u4ff3\u848e',
+  'pan': '\u6500\u6f58\u76d8\u78d0\u76fc\u7554\u5224\u53db\u723f\u6cee\u88a2\u897b\u87e0\u8e52',
+  'pang': '\u4e53\u5e9e\u65c1\u802a\u80d6\u6ec2\u9004',
+  'pao': '\u629b\u5486\u5228\u70ae\u888d\u8dd1\u6ce1\u530f\u72cd\u5e96\u812c\u75b1',
+  'pei': '\u5478\u80da\u57f9\u88f4\u8d54\u966a\u914d\u4f69\u6c9b\u638a\u8f94\u5e14\u6de0\u65c6\u952b\u9185\u9708',
+  'pen': '\u55b7\u76c6\u6e53',
+  'peng': '\u7830\u62a8\u70f9\u6f8e\u5f6d\u84ec\u68da\u787c\u7bf7\u81a8\u670b\u9e4f\u6367\u78b0\u576f\u580b\u562d\u6026\u87db',
+  'pi': '\u7812\u9739\u6279\u62ab\u5288\u7435\u6bd7\u5564\u813e\u75b2\u76ae\u5339\u75de\u50fb\u5c41\u8b6c\u4e15\u9674\u90b3\u90eb\u572e\u9f19\u64d7\u567c\u5e80\u5ab2\u7eb0\u6787\u7513\u7765\u7f74\u94cd\u75e6\u7656\u758b\u868d\u8c94',
+  'pian': '\u7bc7\u504f\u7247\u9a97\u8c1d\u9a88\u728f\u80fc\u890a\u7fe9\u8e41',
+  'piao': '\u98d8\u6f02\u74e2\u7968\u527d\u560c\u5ad6\u7f25\u6b8d\u779f\u87b5',
+  'pie': '\u6487\u77a5\u4e3f\u82e4\u6c15',
+  'pin': '\u62fc\u9891\u8d2b\u54c1\u8058\u62da\u59d8\u5ad4\u6980\u725d\u98a6',
+  'ping': '\u4e52\u576a\u82f9\u840d\u5e73\u51ed\u74f6\u8bc4\u5c4f\u4fdc\u5a09\u67b0\u9c86',
+  'po': '\u5761\u6cfc\u9887\u5a46\u7834\u9b44\u8feb\u7c95\u53f5\u9131\u6ea5\u73c0\u948b\u94b7\u76a4\u7b38',
+  'pou': '\u5256\u88d2\u8e23',
+  'pu': '\u6251\u94fa\u4ec6\u8386\u8461\u83e9\u84b2\u57d4\u6734\u5703\u666e\u6d66\u8c31\u66dd\u7011\u530d\u5657\u6fee\u749e\u6c06\u9564\u9568\u8e7c',
+  'qi': '\u671f\u6b3a\u6816\u621a\u59bb\u4e03\u51c4\u6f06\u67d2\u6c8f\u5176\u68cb\u5947\u6b67\u7566\u5d0e\u8110\u9f50\u65d7\u7948\u7941\u9a91\u8d77\u5c82\u4e5e\u4f01\u542f\u5951\u780c\u5668\u6c14\u8fc4\u5f03\u6c7d\u6ce3\u8bab\u4e9f\u4e93\u573b\u8291\u840b\u847a\u5601\u5c7a\u5c90\u6c54\u6dc7\u9a90\u7eee\u742a\u7426\u675e\u6864\u69ed\u6b39\u797a\u61a9\u789b\u86f4\u871e\u7da6\u7dae\u8dbf\u8e4a\u9ccd\u9e92',
+  'qia': '\u6390\u6070\u6d3d\u845c',
+  'qian': '\u7275\u6266\u948e\u94c5\u5343\u8fc1\u7b7e\u4edf\u8c26\u4e7e\u9ed4\u94b1\u94b3\u524d\u6f5c\u9063\u6d45\u8c34\u5811\u5d4c\u6b20\u6b49\u4f65\u9621\u828a\u82a1\u8368\u63ae\u5c8d\u60ad\u614a\u9a9e\u6434\u8930\u7f31\u6920\u80b7\u6106\u94a4\u8654\u7b9d',
+  'qiang': '\u67aa\u545b\u8154\u7f8c\u5899\u8537\u5f3a\u62a2\u5af1\u6a2f\u6217\u709d\u9516\u9535\u956a\u8941\u8723\u7f9f\u8deb\u8dc4',
+  'qiao': '\u6a47\u9539\u6572\u6084\u6865\u77a7\u4e54\u4fa8\u5de7\u9798\u64ac\u7fd8\u5ced\u4fcf\u7a8d\u5281\u8bee\u8c2f\u835e\u6100\u6194\u7f32\u6a35\u6bf3\u7857\u8df7\u9792',
+  'qie': '\u5207\u8304\u4e14\u602f\u7a83\u90c4\u553c\u60ec\u59be\u6308\u9532\u7ba7',
+  'qin': '\u94a6\u4fb5\u4eb2\u79e6\u7434\u52e4\u82b9\u64d2\u79bd\u5bdd\u6c81\u82a9\u84c1\u8572\u63ff\u5423\u55ea\u5659\u6eb1\u6a8e\u8793\u887e',
+  'qing': '\u9752\u8f7b\u6c22\u503e\u537f\u6e05\u64ce\u6674\u6c30\u60c5\u9877\u8bf7\u5e86\u5029\u82d8\u570a\u6aa0\u78ec\u873b\u7f44\u7b90\u8b26\u9cad\u9ee5',
+  'qiong': '\u743c\u7a77\u909b\u8315\u7a79\u7b47\u928e',
+  'qiu': '\u79cb\u4e18\u90b1\u7403\u6c42\u56da\u914b\u6cc5\u4fc5\u6c3d\u5def\u827d\u72b0\u6e6b\u9011\u9052\u6978\u8d47\u9e20\u866c\u86af\u8764\u88d8\u7cd7\u9cc5\u9f3d',
+  'qu': '\u8d8b\u533a\u86c6\u66f2\u8eaf\u5c48\u9a71\u6e20\u53d6\u5a36\u9f8b\u8da3\u53bb\u8bce\u52ac\u8556\u8627\u5c96\u8862\u9612\u74a9\u89d1\u6c0d\u795b\u78f2\u766f\u86d0\u883c\u9eb4\u77bf\u9ee2',
+  'quan': '\u5708\u98a7\u6743\u919b\u6cc9\u5168\u75ca\u62f3\u72ac\u5238\u529d\u8be0\u8343\u737e\u609b\u7efb\u8f81\u754e\u94e8\u8737\u7b4c\u9b08',
+  'que': '\u7f3a\u7094\u7638\u5374\u9e4a\u69b7\u786e\u96c0\u9619\u60ab',
+  'qun': '\u88d9\u7fa4\u9021',
+  'ran': '\u7136\u71c3\u5189\u67d3\u82d2\u9aef',
+  'rang': '\u74e4\u58e4\u6518\u56b7\u8ba9\u79b3\u7a70',
+  'rao': '\u9976\u6270\u7ed5\u835b\u5a06\u6861',
+  'ruo': '\u60f9\u82e5\u5f31',
+  're': '\u70ed\u504c',
+  'ren': '\u58ec\u4ec1\u4eba\u5fcd\u97e7\u4efb\u8ba4\u5203\u598a\u7eab\u4ede\u834f\u845a\u996a\u8f6b\u7a14\u887d',
+  'reng': '\u6254\u4ecd',
+  'ri': '\u65e5',
+  'rong': '\u620e\u8338\u84c9\u8363\u878d\u7194\u6eb6\u5bb9\u7ed2\u5197\u5d58\u72e8\u7f1b\u6995\u877e',
+  'rou': '\u63c9\u67d4\u8089\u7cc5\u8e42\u97a3',
+  'ru': '\u8339\u8815\u5112\u5b7a\u5982\u8fb1\u4e73\u6c5d\u5165\u8925\u84d0\u85b7\u5685\u6d33\u6ebd\u6fe1\u94f7\u8966\u98a5',
+  'ruan': '\u8f6f\u962e\u670a',
+  'rui': '\u854a\u745e\u9510\u82ae\u8564\u777f\u868b',
+  'run': '\u95f0\u6da6',
+  'sa': '\u6492\u6d12\u8428\u5345\u4ee8\u6332\u98d2',
+  'sai': '\u816e\u9cc3\u585e\u8d5b\u567b',
+  'san': '\u4e09\u53c1\u4f1e\u6563\u5f61\u9993\u6c35\u6bf5\u7cc1\u9730',
+  'sang': '\u6851\u55d3\u4e27\u6421\u78c9\u98a1',
+  'sao': '\u6414\u9a9a\u626b\u5ac2\u57fd\u81ca\u7619\u9ccb',
+  'se': '\u745f\u8272\u6da9\u556c\u94e9\u94ef\u7a51',
+  'sen': '\u68ee',
+  'seng': '\u50e7',
+  'sha': '\u838e\u7802\u6740\u5239\u6c99\u7eb1\u50bb\u5565\u715e\u810e\u6b43\u75e7\u88df\u970e\u9ca8',
+  'shai': '\u7b5b\u6652\u917e',
+  'shan': '\u73ca\u82eb\u6749\u5c71\u5220\u717d\u886b\u95ea\u9655\u64c5\u8d61\u81b3\u5584\u6c55\u6247\u7f2e\u5261\u8baa\u912f\u57cf\u829f\u6f78\u59d7\u9a9f\u81bb\u9490\u759d\u87ee\u8222\u8dda\u9cdd',
+  'shang': '\u5892\u4f24\u5546\u8d4f\u664c\u4e0a\u5c1a\u88f3\u57a7\u7ef1\u6b87\u71b5\u89de',
+  'shao': '\u68a2\u634e\u7a0d\u70e7\u828d\u52fa\u97f6\u5c11\u54e8\u90b5\u7ecd\u52ad\u82d5\u6f72\u86f8\u7b24\u7b72\u8244',
+  'she': '\u5962\u8d4a\u86c7\u820c\u820d\u8d66\u6444\u5c04\u6151\u6d89\u793e\u8bbe\u538d\u4f58\u731e\u7572\u9e9d',
+  'shen': '\u7837\u7533\u547b\u4f38\u8eab\u6df1\u5a20\u7ec5\u795e\u6c88\u5ba1\u5a76\u751a\u80be\u614e\u6e17\u8bdc\u8c02\u5432\u54c2\u6e16\u6939\u77e7\u8703',
+  'sheng': '\u58f0\u751f\u7525\u7272\u5347\u7ef3\u7701\u76db\u5269\u80dc\u5723\u4e1e\u6e11\u5ab5\u771a\u7b19',
+  'shi': '\u5e08\u5931\u72ee\u65bd\u6e7f\u8bd7\u5c38\u8671\u5341\u77f3\u62fe\u65f6\u4ec0\u98df\u8680\u5b9e\u8bc6\u53f2\u77e2\u4f7f\u5c4e\u9a76\u59cb\u5f0f\u793a\u58eb\u4e16\u67ff\u4e8b\u62ed\u8a93\u901d\u52bf\u662f\u55dc\u566c\u9002\u4ed5\u4f8d\u91ca\u9970\u6c0f\u5e02\u6043\u5ba4\u89c6\u8bd5\u8c25\u57d8\u83b3\u84cd\u5f11\u5511\u9963\u8f7c\u8006\u8d33\u70bb\u793b\u94c8\u94ca\u87ab\u8210\u7b6e\u8c55\u9ca5\u9cba',
+  'shou': '\u6536\u624b\u9996\u5b88\u5bff\u6388\u552e\u53d7\u7626\u517d\u624c\u72e9\u7ef6\u824f',
+  'shu': '\u852c\u67a2\u68b3\u6b8a\u6292\u8f93\u53d4\u8212\u6dd1\u758f\u4e66\u8d4e\u5b70\u719f\u85af\u6691\u66d9\u7f72\u8700\u9ecd\u9f20\u5c5e\u672f\u8ff0\u6811\u675f\u620d\u7ad6\u5885\u5eb6\u6570\u6f31\u6055\u500f\u587e\u83fd\u5fc4\u6cad\u6d91\u6f8d\u59dd\u7ebe\u6bf9\u8167\u6bb3\u956f\u79eb\u9e6c',
+  'shua': '\u5237\u800d\u5530\u6dae',
+  'shuai': '\u6454\u8870\u7529\u5e05\u87c0',
+  'shuan': '\u6813\u62f4\u95e9',
+  'shuang': '\u971c\u53cc\u723d\u5b40',
+  'shui': '\u8c01\u6c34\u7761\u7a0e',
+  'shun': '\u542e\u77ac\u987a\u821c\u6042',
+  'shuo': '\u8bf4\u7855\u6714\u70c1\u84b4\u6420\u55cd\u6fef\u5981\u69ca\u94c4',
+  'si': '\u65af\u6495\u5636\u601d\u79c1\u53f8\u4e1d\u6b7b\u8086\u5bfa\u55e3\u56db\u4f3a\u4f3c\u9972\u5df3\u53ae\u4fdf\u5155\u83e5\u549d\u6c5c\u6cd7\u6f8c\u59d2\u9a77\u7f0c\u7940\u7960\u9536\u9e36\u801c\u86f3\u7b25',
+  'song': '\u677e\u8038\u6002\u9882\u9001\u5b8b\u8bbc\u8bf5\u51c7\u83d8\u5d27\u5d69\u5fea\u609a\u6dde\u7ae6',
+  'sou': '\u641c\u8258\u64de\u55fd\u53df\u55d6\u55fe\u998a\u6eb2\u98d5\u778d\u953c\u878b',
+  'su': '\u82cf\u9165\u4fd7\u7d20\u901f\u7c9f\u50f3\u5851\u6eaf\u5bbf\u8bc9\u8083\u5919\u8c21\u850c\u55c9\u612b\u7c0c\u89eb\u7a23',
+  'suan': '\u9178\u849c\u7b97',
+  'sui': '\u867d\u968b\u968f\u7ee5\u9ad3\u788e\u5c81\u7a57\u9042\u96a7\u795f\u84d1\u51ab\u8c07\u6fc9\u9083\u71e7\u772d\u7762',
+  'sun': '\u5b59\u635f\u7b0b\u836a\u72f2\u98e7\u69ab\u8de3\u96bc',
+  'suo': '\u68ad\u5506\u7f29\u7410\u7d22\u9501\u6240\u5522\u55e6\u5a11\u686b\u7743\u7fa7',
+  'ta': '\u584c\u4ed6\u5b83\u5979\u5854\u736d\u631e\u8e4b\u8e0f\u95fc\u6ebb\u9062\u69bb\u6c93',
+  'tai': '\u80ce\u82d4\u62ac\u53f0\u6cf0\u915e\u592a\u6001\u6c70\u90b0\u85b9\u80bd\u70b1\u949b\u8dc6\u9c90',
+  'tan': '\u574d\u644a\u8d2a\u762b\u6ee9\u575b\u6a80\u75f0\u6f6d\u8c2d\u8c08\u5766\u6bef\u8892\u78b3\u63a2\u53f9\u70ad\u90ef\u8548\u6619\u94bd\u952c\u8983',
+  'tang': '\u6c64\u5858\u642a\u5802\u68e0\u819b\u5510\u7cd6\u50a5\u9967\u6e8f\u746d\u94f4\u9557\u8025\u8797\u87b3\u7fb0\u91a3',
+  'thang': '\u5018\u8eba\u6dcc',
+  'theng': '\u8d9f\u70eb',
+  'tao': '\u638f\u6d9b\u6ed4\u7ee6\u8404\u6843\u9003\u6dd8\u9676\u8ba8\u5957\u6311\u9f17\u5555\u97ec\u9955',
+  'te': '\u7279',
+  'teng': '\u85e4\u817e\u75bc\u8a8a\u6ed5',
+  'ti': '\u68af\u5254\u8e22\u9511\u63d0\u9898\u8e44\u557c\u4f53\u66ff\u568f\u60d5\u6d95\u5243\u5c49\u8351\u608c\u9016\u7ee8\u7f07\u9e48\u88fc\u918d',
+  'tian': '\u5929\u6dfb\u586b\u7530\u751c\u606c\u8214\u8146\u63ad\u5fdd\u9617\u6b84\u754b\u94bf\u86ba',
+  'tiao': '\u6761\u8fe2\u773a\u8df3\u4f7b\u7967\u94eb\u7a95\u9f86\u9ca6',
+  'tie': '\u8d34\u94c1\u5e16\u841c\u992e',
+  'ting': '\u5385\u542c\u70c3\u6c40\u5ef7\u505c\u4ead\u5ead\u633a\u8247\u839b\u8476\u5a77\u6883\u8713\u9706',
+  'tong': '\u901a\u6850\u916e\u77b3\u540c\u94dc\u5f64\u7ae5\u6876\u6345\u7b52\u7edf\u75db\u4f5f\u50ee\u4edd\u833c\u55f5\u6078\u6f7c\u783c',
+  'tou': '\u5077\u6295\u5934\u900f\u4ea0',
+  'tu': '\u51f8\u79c3\u7a81\u56fe\u5f92\u9014\u6d82\u5c60\u571f\u5410\u5154\u580d\u837c\u83df\u948d\u9174',
+  'tuan': '\u6e4d\u56e2\u7583',
+  'tui': '\u63a8\u9893\u817f\u8715\u892a\u9000\u5fd2\u717a',
+  'tun': '\u541e\u5c6f\u81c0\u9968\u66be\u8c5a\u7a80',
+  'tuo': '\u62d6\u6258\u8131\u9e35\u9640\u9a6e\u9a7c\u692d\u59a5\u62d3\u553e\u4e47\u4f57\u5768\u5eb9\u6cb1\u67dd\u7823\u7ba8\u8204\u8dce\u9f0d',
+  'wa': '\u6316\u54c7\u86d9\u6d3c\u5a03\u74e6\u889c\u4f64\u5a32\u817d',
+  'wai': '\u6b6a\u5916',
+  'wan': '\u8c4c\u5f2f\u6e7e\u73a9\u987d\u4e38\u70f7\u5b8c\u7897\u633d\u665a\u7696\u60cb\u5b9b\u5a49\u4e07\u8155\u525c\u8284\u82cb\u83c0\u7ea8\u7efe\u742c\u8118\u7579\u873f\u7ba2',
+  'wang': '\u6c6a\u738b\u4ea1\u6789\u7f51\u5f80\u65fa\u671b\u5fd8\u5984\u7f54\u5c22\u60d8\u8f8b\u9b4d',
+  'wei': '\u5a01\u5dcd\u5fae\u5371\u97e6\u8fdd\u6845\u56f4\u552f\u60df\u4e3a\u6f4d\u7ef4\u82c7\u840e\u59d4\u4f1f\u4f2a\u5c3e\u7eac\u672a\u851a\u5473\u754f\u80c3\u5582\u9b4f\u4f4d\u6e2d\u8c13\u5c09\u6170\u536b\u502d\u504e\u8bff\u9688\u8473\u8587\u5e0f\u5e37\u5d34\u5d6c\u7325\u732c\u95f1\u6ca9\u6d27\u6da0\u9036\u5a13\u73ae\u97ea\u8ece\u709c\u7168\u71a8\u75ff\u8249\u9c94',
+  'wen': '\u761f\u6e29\u868a\u6587\u95fb\u7eb9\u543b\u7a33\u7d0a\u95ee\u520e\u6120\u960c\u6c76\u74ba\u97eb\u6b81\u96ef',
+  'weng': '\u55e1\u7fc1\u74ee\u84ca\u8579',
+  'wo': '\u631d\u8717\u6da1\u7a9d\u6211\u65a1\u5367\u63e1\u6c83\u83b4\u5e44\u6e25\u674c\u809f\u9f8c',
+  'wu': '\u5deb\u545c\u94a8\u4e4c\u6c61\u8bec\u5c4b\u65e0\u829c\u68a7\u543e\u5434\u6bcb\u6b66\u4e94\u6342\u5348\u821e\u4f0d\u4fae\u575e\u620a\u96fe\u6664\u7269\u52ff\u52a1\u609f\u8bef\u5140\u4ef5\u9622\u90ac\u572c\u82b4\u5e91\u6003\u5fe4\u6d6f\u5be4\u8fd5\u59a9\u9a9b\u727e\u7110\u9e49\u9e5c\u8708\u92c8\u9f2f',
+  'xi': '\u6614\u7199\u6790\u897f\u7852\u77fd\u6670\u563b\u5438\u9521\u727a\u7a00\u606f\u5e0c\u6089\u819d\u5915\u60dc\u7184\u70ef\u6eaa\u6c50\u7280\u6a84\u88ad\u5e2d\u4e60\u5ab3\u559c\u94e3\u6d17\u7cfb\u9699\u620f\u7ec6\u50d6\u516e\u96b0\u90d7\u831c\u8478\u84f0\u595a\u550f\u5f99\u9969\u960b\u6d60\u6dc5\u5c63\u5b09\u73ba\u6a28\u66e6\u89cb\u6b37\u71b9\u798a\u79a7\u94b8\u7699\u7a78\u8725\u87cb\u823e\u7fb2\u7c9e\u7fd5\u91af\u9f37',
+  'xia': '\u778e\u867e\u5323\u971e\u8f96\u6687\u5ce1\u4fa0\u72ed\u4e0b\u53a6\u590f\u5413\u6380\u846d\u55c4\u72ce\u9050\u7455\u7856\u7615\u7f45\u9ee0',
+  'xian': '\u9528\u5148\u4ed9\u9c9c\u7ea4\u54b8\u8d24\u8854\u8237\u95f2\u6d8e\u5f26\u5acc\u663e\u9669\u73b0\u732e\u53bf\u817a\u9985\u7fa1\u5baa\u9677\u9650\u7ebf\u51bc\u85d3\u5c98\u7303\u66b9\u5a34\u6c19\u7946\u9e47\u75eb\u86ac\u7b45\u7c7c\u9170\u8df9',
+  'xiang': '\u76f8\u53a2\u9576\u9999\u7bb1\u8944\u6e58\u4e61\u7fd4\u7965\u8be6\u60f3\u54cd\u4eab\u9879\u5df7\u6a61\u50cf\u5411\u8c61\u8297\u8459\u9977\u5ea0\u9aa7\u7f03\u87d3\u9c9e\u98e8',
+  'xiao': '\u8427\u785d\u9704\u524a\u54ee\u56a3\u9500\u6d88\u5bb5\u6dc6\u6653\u5c0f\u5b5d\u6821\u8096\u5578\u7b11\u6548\u54d3\u54bb\u5d24\u6f47\u900d\u9a81\u7ee1\u67ad\u67b5\u7b71\u7bab\u9b48',
+  'xie': '\u6954\u4e9b\u6b47\u874e\u978b\u534f\u631f\u643a\u90aa\u659c\u80c1\u8c10\u5199\u68b0\u5378\u87f9\u61c8\u6cc4\u6cfb\u8c22\u5c51\u5055\u4eb5\u52f0\u71ee\u85a4\u64b7\u5ee8\u7023\u9082\u7ec1\u7f2c\u69ad\u698d\u6b59\u8e9e',
+  'xin': '\u85aa\u82af\u950c\u6b23\u8f9b\u65b0\u5ffb\u5fc3\u4fe1\u8845\u56df\u99a8\u8398\u6b46\u94fd\u946b',
+  'xing': '\u661f\u8165\u7329\u60fa\u5174\u5211\u578b\u5f62\u90a2\u884c\u9192\u5e78\u674f\u6027\u59d3\u9649\u8347\u8365\u64e4\u60bb\u784e',
+  'xiong': '\u5144\u51f6\u80f8\u5308\u6c79\u96c4\u718a\u828e',
+  'xiu': '\u4f11\u4fee\u7f9e\u673d\u55c5\u9508\u79c0\u8896\u7ee3\u83a0\u5cab\u9990\u5ea5\u9e3a\u8c85\u9af9',
+  'xu': '\u589f\u620c\u9700\u865a\u5618\u987b\u5f90\u8bb8\u84c4\u9157\u53d9\u65ed\u5e8f\u755c\u6064\u7d6e\u5a7f\u7eea\u7eed\u8bb4\u8be9\u5729\u84ff\u6035\u6d2b\u6e86\u987c\u6829\u7166\u7809\u76f1\u80e5\u7cc8\u9191',
+  'xuan': '\u8f69\u55a7\u5ba3\u60ac\u65cb\u7384\u9009\u7663\u7729\u7eda\u5107\u8c16\u8431\u63ce\u9994\u6ceb\u6d35\u6e32\u6f29\u7487\u6966\u6684\u70ab\u714a\u78b9\u94c9\u955f\u75c3',
+  'xue': '\u9774\u859b\u5b66\u7a74\u96ea\u8840\u5671\u6cf6\u9cd5',
+  'xun': '\u52cb\u718f\u5faa\u65ec\u8be2\u5bfb\u9a6f\u5de1\u6b89\u6c5b\u8bad\u8baf\u900a\u8fc5\u5dfd\u57d9\u8340\u85b0\u5ccb\u5f87\u6d54\u66db\u7aa8\u91ba\u9c9f',
+  'ya': '\u538b\u62bc\u9e26\u9e2d\u5440\u4e2b\u82bd\u7259\u869c\u5d16\u8859\u6daf\u96c5\u54d1\u4e9a\u8bb6\u4f22\u63e0\u5416\u5c88\u8fd3\u5a05\u740a\u6860\u6c29\u7811\u775a\u75d6',
+  'yan': '\u7109\u54bd\u9609\u70df\u6df9\u76d0\u4e25\u7814\u8712\u5ca9\u5ef6\u8a00\u989c\u960e\u708e\u6cbf\u5944\u63a9\u773c\u884d\u6f14\u8273\u5830\u71d5\u538c\u781a\u96c1\u5501\u5f66\u7130\u5bb4\u8c1a\u9a8c\u53a3\u9765\u8d5d\u4fe8\u5043\u5156\u8ba0\u8c33\u90fe\u9122\u82ab\u83f8\u5d26\u6079\u95eb\u960f\u6d07\u6e6e\u6edf\u598d\u5ae3\u7430\u664f\u80ed\u814c\u7131\u7f68\u7b75\u917d\u9b47\u990d\u9f39',
+  'yang': '\u6b83\u592e\u9e2f\u79e7\u6768\u626c\u4f6f\u75a1\u7f8a\u6d0b\u9633\u6c27\u4ef0\u75d2\u517b\u6837\u6f3e\u5f89\u600f\u6cf1\u7080\u70ca\u6059\u86d8\u9785',
+  'yao': '\u9080\u8170\u5996\u7476\u6447\u5c27\u9065\u7a91\u8c23\u59da\u54ac\u8200\u836f\u8981\u8000\u592d\u723b\u5406\u5d3e\u5fad\u7039\u5e7a\u73e7\u6773\u66dc\u80b4\u9e5e\u7a88\u7e47\u9cd0',
+  'ye': '\u6930\u564e\u8036\u7237\u91ce\u51b6\u4e5f\u9875\u6396\u4e1a\u53f6\u66f3\u814b\u591c\u6db2\u8c12\u90ba\u63f6\u9980\u6654\u70e8\u94d8',
+  'yi': '\u4e00\u58f9\u533b\u63d6\u94f1\u4f9d\u4f0a\u8863\u9890\u5937\u9057\u79fb\u4eea\u80f0\u7591\u6c82\u5b9c\u59e8\u5f5d\u6905\u8681\u501a\u5df2\u4e59\u77e3\u4ee5\u827a\u6291\u6613\u9091\u5c79\u4ebf\u5f79\u81c6\u9038\u8084\u75ab\u4ea6\u88d4\u610f\u6bc5\u5fc6\u4e49\u76ca\u6ea2\u8be3\u8bae\u8c0a\u8bd1\u5f02\u7ffc\u7fcc\u7ece\u5208\u5293\u4f7e\u8bd2\u572a\u572f\u57f8\u61ff\u82e1\u858f\u5f08\u5955\u6339\u5f0b\u5453\u54a6\u54bf\u566b\u5cc4\u5db7\u7317\u9974\u603f\u6021\u6092\u6f2a\u8fe4\u9a7f\u7f22\u6baa\u8d3b\u65d6\u71a0\u9487\u9552\u9571\u75cd\u7617\u7654\u7fca\u8864\u8734\u8223\u7fbf\u7ff3\u914f\u9edf',
+  'yin': '\u8335\u836b\u56e0\u6bb7\u97f3\u9634\u59fb\u541f\u94f6\u6deb\u5bc5\u996e\u5c39\u5f15\u9690\u5370\u80e4\u911e\u5819\u831a\u5591\u72fa\u5924\u6c24\u94df\u763e\u8693\u972a\u9f88',
+  'ying': '\u82f1\u6a31\u5a74\u9e70\u5e94\u7f28\u83b9\u8424\u8425\u8367\u8747\u8fce\u8d62\u76c8\u5f71\u9896\u786c\u6620\u5b34\u90e2\u8314\u83ba\u8426\u6484\u5624\u81ba\u6ee2\u6f46\u701b\u745b\u748e\u6979\u9e66\u763f\u988d\u7f42',
+  'yo': '\u54df\u5537',
+  'yong': '\u62e5\u4f63\u81c3\u75c8\u5eb8\u96cd\u8e0a\u86f9\u548f\u6cf3\u6d8c\u6c38\u607f\u52c7\u7528\u4fd1\u58c5\u5889\u6175\u9095\u955b\u752c\u9cd9\u9954',
+  'you': '\u5e7d\u4f18\u60a0\u5fe7\u5c24\u7531\u90ae\u94c0\u72b9\u6cb9\u6e38\u9149\u6709\u53cb\u53f3\u4f51\u91c9\u8bf1\u53c8\u5e7c\u5363\u6538\u4f91\u83b8\u5466\u56ff\u5ba5\u67da\u7337\u7256\u94d5\u75a3\u8763\u9c7f\u9edd\u9f2c',
+  'yu': '\u8fc2\u6de4\u4e8e\u76c2\u6986\u865e\u611a\u8206\u4f59\u4fde\u903e\u9c7c\u6109\u6e1d\u6e14\u9685\u4e88\u5a31\u96e8\u4e0e\u5c7f\u79b9\u5b87\u8bed\u7fbd\u7389\u57df\u828b\u90c1\u5401\u9047\u55bb\u5cea\u5fa1\u6108\u6b32\u72f1\u80b2\u8a89\u6d74\u5bd3\u88d5\u9884\u8c6b\u9a6d\u79ba\u6bd3\u4f1b\u4fe3\u8c00\u8c15\u8438\u84e3\u63c4\u5581\u5704\u5709\u5d5b\u72f3\u996b\u5ebe\u9608\u59aa\u59a4\u7ea1\u745c\u6631\u89ce\u8174\u6b24\u65bc\u715c\u71e0\u807f\u94b0\u9e46\u7610\u7600\u7ab3\u8753\u7afd\u8201\u96e9\u9f89',
+  'yuan': '\u9e33\u6e0a\u51a4\u5143\u57a3\u8881\u539f\u63f4\u8f95\u56ed\u5458\u5706\u733f\u6e90\u7f18\u8fdc\u82d1\u613f\u6028\u9662\u586c\u6c85\u5a9b\u7457\u6a7c\u7230\u7722\u9e22\u8788\u9f0b',
+  'yue': '\u66f0\u7ea6\u8d8a\u8dc3\u94a5\u5cb3\u7ca4\u6708\u60a6\u9605\u9fa0\u6a3e\u5216\u94ba',
+  'yun': '\u8018\u4e91\u90e7\u5300\u9668\u5141\u8fd0\u8574\u915d\u6655\u97f5\u5b55\u90d3\u82b8\u72c1\u607d\u7ead\u6b92\u6600\u6c32',
+  'za': '\u531d\u7838\u6742\u62f6\u5482',
+  'zai': '\u683d\u54c9\u707e\u5bb0\u8f7d\u518d\u5728\u54b1\u5d3d\u753e',
+  'zan': '\u6512\u6682\u8d5e\u74d2\u661d\u7c2a\u7ccc\u8db1\u933e',
+  'zang': '\u8d43\u810f\u846c\u5958\u6215\u81e7',
+  'zao': '\u906d\u7cdf\u51ff\u85fb\u67a3\u65e9\u6fa1\u86a4\u8e81\u566a\u9020\u7682\u7076\u71e5\u5523\u7f2b',
+  'ze': '\u8d23\u62e9\u5219\u6cfd\u4ec4\u8d5c\u5567\u8fee\u6603\u7b2e\u7ba6\u8234',
+  'zei': '\u8d3c',
+  'zen': '\u600e\u8c2e',
+  'zeng': '\u589e\u618e\u66fe\u8d60\u7f2f\u7511\u7f7e\u9503',
+  'zha': '\u624e\u55b3\u6e23\u672d\u8f67\u94e1\u95f8\u7728\u6805\u69a8\u548b\u4e4d\u70b8\u8bc8\u63f8\u5412\u54a4\u54f3\u600d\u781f\u75c4\u86b1\u9f44',
+  'zhai': '\u6458\u658b\u5b85\u7a84\u503a\u5be8\u7826',
+  'zhan': '\u77bb\u6be1\u8a79\u7c98\u6cbe\u76cf\u65a9\u8f97\u5d2d\u5c55\u8638\u6808\u5360\u6218\u7ad9\u6e5b\u7efd\u8c35\u640c\u65c3',
+  'zhang': '\u6a1f\u7ae0\u5f70\u6f33\u5f20\u638c\u6da8\u6756\u4e08\u5e10\u8d26\u4ed7\u80c0\u7634\u969c\u4ec9\u9123\u5e5b\u5d82\u7350\u5adc\u748b\u87d1',
+  'zhao': '\u62db\u662d\u627e\u6cbc\u8d75\u7167\u7f69\u5146\u8087\u53ec\u722a\u8bcf\u68f9\u948a\u7b0a',
+  'zhe': '\u906e\u6298\u54f2\u86f0\u8f99\u8005\u9517\u8517\u8fd9\u6d59\u8c2a\u966c\u67d8\u8f84\u78d4\u9e67\u891a\u8707\u8d6d',
+  'zhen': '\u73cd\u659f\u771f\u7504\u7827\u81fb\u8d1e\u9488\u4fa6\u6795\u75b9\u8bca\u9707\u632f\u9547\u9635\u7f1c\u6862\u699b\u8f78\u8d48\u80d7\u6715\u796f\u755b\u9e29',
+  'zheng': '\u84b8\u6323\u7741\u5f81\u72f0\u4e89\u6014\u6574\u62ef\u6b63\u653f\u5e27\u75c7\u90d1\u8bc1\u8be4\u5ce5\u94b2\u94ee\u7b5d',
+  'zhi': '\u829d\u679d\u652f\u5431\u8718\u77e5\u80a2\u8102\u6c41\u4e4b\u7ec7\u804c\u76f4\u690d\u6b96\u6267\u503c\u4f84\u5740\u6307\u6b62\u8dbe\u53ea\u65e8\u7eb8\u5fd7\u631a\u63b7\u81f3\u81f4\u7f6e\u5e1c\u5cd9\u5236\u667a\u79e9\u7a1a\u8d28\u7099\u75d4\u6ede\u6cbb\u7a92\u536e\u965f\u90c5\u57f4\u82b7\u646d\u5e19\u5fee\u5f58\u54ab\u9a98\u6809\u67b3\u6800\u684e\u8f75\u8f7e\u6534\u8d3d\u81a3\u7949\u7957\u9ef9\u96c9\u9e37\u75e3\u86ed\u7d77\u916f\u8dd6\u8e2c\u8e2f\u8c78\u89ef',
+  'zhong': '\u4e2d\u76c5\u5fe0\u949f\u8877\u7ec8\u79cd\u80bf\u91cd\u4ef2\u4f17\u51a2\u953a\u87bd\u8202\u822f\u8e35',
+  'zhou': '\u821f\u5468\u5dde\u6d32\u8bcc\u7ca5\u8f74\u8098\u5e1a\u5492\u76b1\u5b99\u663c\u9aa4\u5544\u7740\u501c\u8bf9\u836e\u9b3b\u7ea3\u80c4\u78a1\u7c40\u8233\u914e\u9cb7',
+  'zhu': '\u73e0\u682a\u86db\u6731\u732a\u8bf8\u8bdb\u9010\u7af9\u70db\u716e\u62c4\u77a9\u5631\u4e3b\u8457\u67f1\u52a9\u86c0\u8d2e\u94f8\u7b51\u4f4f\u6ce8\u795d\u9a7b\u4f2b\u4f8f\u90be\u82ce\u8331\u6d19\u6e1a\u6f74\u9a7a\u677c\u69e0\u6a65\u70b7\u94e2\u75b0\u7603\u86b0\u7afa\u7bb8\u7fe5\u8e85\u9e88',
+  'zhua': '\u6293',
+  'zhuai': '\u62fd',
+  'zhuan': '\u4e13\u7816\u8f6c\u64b0\u8d5a\u7bc6\u629f\u556d\u989b',
+  'zhuang': '\u6869\u5e84\u88c5\u5986\u649e\u58ee\u72b6\u4e2c',
+  'zhui': '\u690e\u9525\u8ffd\u8d58\u5760\u7f00\u8411\u9a93\u7f12',
+  'zhun': '\u8c06\u51c6',
+  'zhuo': '\u6349\u62d9\u5353\u684c\u7422\u8301\u914c\u707c\u6d4a\u502c\u8bfc\u5ef4\u855e\u64e2\u555c\u6d5e\u6dbf\u6753\u712f\u799a\u65ab',
+  'zi': '\u5179\u54a8\u8d44\u59ff\u6ecb\u6dc4\u5b5c\u7d2b\u4ed4\u7c7d\u6ed3\u5b50\u81ea\u6e0d\u5b57\u8c18\u5d6b\u59ca\u5b73\u7f01\u6893\u8f8e\u8d40\u6063\u7726\u9531\u79ed\u8014\u7b2b\u7ca2\u89dc\u8a3e\u9cbb\u9aed',
+  'zong': '\u9b03\u68d5\u8e2a\u5b97\u7efc\u603b\u7eb5\u8159\u7cbd',
+  'zou': '\u90b9\u8d70\u594f\u63cd\u9139\u9cb0',
+  'zu': '\u79df\u8db3\u5352\u65cf\u7956\u8bc5\u963b\u7ec4\u4fce\u83f9\u5550\u5f82\u9a75\u8e74',
+  'zuan': '\u94bb\u7e82\u6525\u7f35',
+  'zui': '\u5634\u9189\u6700\u7f6a',
+  'zun': '\u5c0a\u9075\u6499\u6a3d\u9cdf',
+  'zuo': '\u6628\u5de6\u4f50\u67de\u505a\u4f5c\u5750\u5ea7\u961d\u963c\u80d9\u795a\u9162',
+  'cou': '\u85ae\u6971\u8f8f\u8160',
+  'nang': '\u652e\u54dd\u56d4\u9995\u66e9',
+  'o': '\u5594',
+  'dia': '\u55f2',
+  'chuai': '\u562c\u81aa\u8e39',
+  'cen': '\u5c91\u6d94',
+  'diu': '\u94e5',
+  'nou': '\u8028',
+  'fou': '\u7f36',
+  'bia': '\u9adf'
+}

+ 128 - 0
global/index.js

@@ -0,0 +1,128 @@
+import Vue from 'vue'
+
+Vue.filter('PercentFormat',function (value) {
+  if (value == null || value == undefined) {
+    return '+0%';
+  } else if (value < 0) {
+    return value + '%';
+  } else if (value == '+∞') {
+    return value ;
+  } else if (value == '-∞') {
+    return value ;
+  } else {
+    return '+' + value + '%';
+  }
+});
+
+Vue.filter('NumberFormat',function (value) {
+  
+  if (value == '***') {
+    return '***';
+  }
+  if (isNaN(value)) {
+    return 0;
+  }
+  let value1 = value.toString();
+  if (value1.indexOf('-')>-1) {
+    value1 = value1.split('-')[1];
+    let num = value1.split('.');
+    let interCount = num[0].length;
+    if (interCount < 3) {
+      return value;
+    }
+    let index = 0;
+    let inter = '';
+    for (let i = interCount - 3; i >= 0; i -= 3) {
+      inter = num[0].substr(i, 3) + (inter == '' ? '' : ',') + inter;
+      index = i;
+    }
+    if (index > 0) {
+      inter = num[0].substr(0, index) + (inter == '' ? '' : ',') + inter;
+    }
+    return '-' + inter + (num.length == 1 ? '' : '.' + num[1]);
+  } else {
+    let num = value1.split('.');
+    let interCount = num[0].length;
+    if (interCount < 3) {
+      return value;
+    }
+    let index = 0;
+    let inter = '';
+    for (let i = interCount - 3; i >= 0; i -= 3) {
+      inter = num[0].substr(i, 3) + (inter == '' ? '' : ',') + inter;
+      index = i;
+    }
+    if (index > 0) {
+      inter = num[0].substr(0, index) + (inter == '' ? '' : ',') + inter;
+    }
+    return inter + (num.length == 1 ? '' : '.' + num[1]);
+  }
+  
+});
+
+Vue.filter('NumberFormat1',function (value) {
+  if (value == '--') {
+    return '--';
+  }
+  if (isNaN(value)) {
+    return 0;
+  }
+  let num = value.toString().split('.');
+  let interCount = num[0].length;
+  if (interCount < 3) {
+    return value;
+  }
+  let index = 0;
+  let inter = '';
+  for (let i = interCount - 3; i >= 0; i -= 3) {
+    inter = num[0].substr(i, 3) + (inter == '' ? '' : ',') + inter;
+    index = i;
+  }
+  if (index > 0) {
+    inter = num[0].substr(0, index) + (inter == '' ? '' : ',') + inter;
+  }
+  return inter + (num.length == 1 ? '' : '.' + num[1]);
+});
+
+Vue.filter('PwdFormat',function (value) {
+  if (value == null || value == undefined) {
+    return 'Null';
+  } else {
+    let len = value.toString().length;
+    let val = '';
+    for (let i = 0; i < len; i++) {
+      val = val + '*';
+    }
+    return val;
+  }
+});
+
+
+Vue.filter('NumberDecimal',function (value) {
+  let realVal = ''
+  if (!isNaN(value) && value!== '') {
+    // 截取当前数据到小数点后两位
+    realVal = parseFloat(value).toFixed(2)
+  } else {
+    realVal = '0'
+  }
+  return realVal
+});
+
+Vue.filter('NumberDesensitization',function (value) {
+  let realVal = ''
+  if (!isNaN(value) && value!== '') {
+    value = value.toString();
+    realVal = value.substr(0,2) + '****' + value.substr(-2);
+  } else {
+    realVal = '--'
+  }
+  return realVal
+});
+
+Vue.filter('NumberDesensitization1',function (value) {
+  let realVal = ''
+  value = value.toString();
+  realVal = value.substr(0,1) + '***' + value.substr(-2);
+  return realVal
+});

+ 12 - 0
global/isImageType.js

@@ -0,0 +1,12 @@
+
+export default {
+  checkFile: function (val) {
+    const imageType = ['image/jpeg', 'image/png', 'image/jpg', 'application/pdf']
+    const isImage = imageType.indexOf(val.toLocaleLowerCase()) == -1 ? false : true;
+    return isImage
+  },
+  checkSize: function (val) {
+    const isSize = val / 1024 / 1024 < 20;
+    return isSize
+  },
+}

+ 40 - 0
global/py.js

@@ -0,0 +1,40 @@
+import { pinyin } from '../global/constPY'
+export default {
+  chineseToPinYin: function (l1) {
+    if (!l1) {
+      return ''
+    }
+    var l2 = l1.length
+    var I1 = ''
+    var reg = new RegExp('[a-zA-Z0-9]')
+    for (var i = 0; i < l2; i++) {
+      var val = l1.substr(i, 1)
+      var name = this.arraySearch(val, pinyin)
+      if (reg.test(val)) {
+        I1 += val
+      } else if (name !== false) {
+        I1 += name
+      }
+    }
+    I1 = I1.replace(/ /g, '-')
+    while (I1.indexOf('--') > 0) {
+      I1 = I1.replace('--', '-')
+    }
+    return I1
+  },
+  arraySearch: function (l1) {
+    for (var name in pinyin) {
+      if (pinyin[name].indexOf(l1) !== -1) {
+        return this.ucfirst(name)
+      }
+    }
+    return false
+  },
+  ucfirst: function (l1) {
+    if (l1.length > 0) {
+      var first = l1.substr(0, 1).toUpperCase()
+      var spare = l1.substr(1, l1.length)
+      return first + spare
+    }
+  }
+}

+ 11 - 0
global/tool.js

@@ -0,0 +1,11 @@
+
+export default {
+  tokenReplace: function (val) {
+    if (!val) {
+      return val
+    }
+    let token = '';
+    token = val.replace(/%/g,'%25').replace(/\+/g,'%2B').replace(/ /g,'%20').replace(/\//g,'%2F').replace(/\?/g,'%3F');
+    return token
+  },
+}

+ 28 - 0
lib/crypt.js

@@ -0,0 +1,28 @@
+/*
+ * @Description: 本地数据加密解密
+ * @Author: sql
+ * @Date: 2018-11-23 20:38:06
+ * @LastEditTime: 2018-11-29 16:14:16
+ */
+import CryptoJs from 'crypto-js'
+
+class CryptToJS {
+    constructor() {
+        this.crypt = CryptoJs
+        this.secret = 'Believe in yourself.'
+    }
+    // 加密内容, 原文
+    Encrypt(text) {
+        return this.crypt.AES.encrypt(text, this.secret).toString()
+    }
+    // 解密,加密内容
+    Decrypt(text) {
+        if (text == null || text.lenth == 0) {
+            return ""
+        }
+        return this.crypt.AES.decrypt(text, this.secret).toString(CryptoJs.enc.Utf8)
+    }
+
+}
+
+export default new CryptToJS

+ 159 - 0
lib/service.js

@@ -0,0 +1,159 @@
+/*
+ * @Description: service类,其他业务层继承此类
+ * @Author: sql
+ * @Date: 2018-11-22 16:57:16
+ * @LastEditTime: 2018-11-30 10:39:09
+ */
+import Vue from "vue"
+import axios from 'axios'
+import Config from '../config'
+import store from '../store'
+import session from "./session";
+Vue.prototype.$store = store;
+// axios.defaults.baseURL = Config.Host
+
+if (sessionStorage.getItem("access_token")) {
+  axios.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token")
+}
+if (sessionStorage.getItem("lang")) {
+	axios.defaults.headers.common['Language'] = sessionStorage.getItem("lang")
+}
+if (sessionStorage.getItem("CLIENT")) {
+	axios.defaults.headers.common['CLIENT'] = sessionStorage.getItem("CLIENT")
+}
+axios.defaults.headers.common['X-System'] = 'A'
+const SystemError = {
+    "cn":"网络状态不佳,请稍后重试。",
+    "en":"The network is not in good condition. Please try again later.",
+    "vn":"Mạng không được tốt lắm. Vui lòng thử lại sau.",
+}
+
+class Service {
+	constructor() {
+		this.axio = axios;
+		this.vue = new Vue({store})
+	}
+
+	// session过期
+	SessionExpire() {
+		this.vue.$store.commit("InfoExpire", true)
+	}
+
+	// // 统一登陆
+	// Login(params) {
+	// 	//console.log(params)
+	// }
+
+	// 统一登出
+	Logout() {
+		let _vue = new Vue()
+		_vue.$routes.push({
+			name: 'login'
+		})
+		_vue = null
+	}
+
+
+	//多端口-多token
+	getAll(type,url,params){
+		switch (type) {
+			case 'Host80':
+				this.axio.defaults.baseURL = Config.Host80;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token");
+			break;
+			case 'Host04':
+				this.axio.defaults.baseURL = Config.Host04;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token");
+			break;
+			case 'Host90':
+				this.axio.defaults.baseURL = Config.Host90;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token");
+			break;
+			case 'HostShop':
+				this.axio.defaults.baseURL = Config.HostShop;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("shop_token");
+			break;
+			case 'Host87':
+				this.axio.defaults.baseURL = Config.Host87;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token");
+			break;
+		}
+		return this.get(url,params);
+	}
+	postAll(type,url,params,config = {}){
+		switch (type) {
+			case 'Host80':
+				this.axio.defaults.baseURL = Config.Host80;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token");
+				
+			break;
+			case 'Host04':
+				this.axio.defaults.baseURL = Config.Host04;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token");
+			break;
+			case 'Host90':
+				this.axio.defaults.baseURL = Config.Host90;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token");
+			break;
+			case 'HostShop':
+				this.axio.defaults.baseURL = Config.HostShop;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("shop_token");
+			break;
+			case 'Host87':
+				this.axio.defaults.baseURL = Config.Host87;
+				this.axio.defaults.headers.common['Access-Token'] = sessionStorage.getItem("access_token");
+			break;
+		}
+		return this.post(url,params,config);
+	}
+
+	// method GET
+	get(url,params) {
+		return this.axio.get(url,params).then((response) => {
+			if (response.data.code == Config.Code.StatusSessionExpire) {
+				this.SessionExpire()
+			} else if (response.data.code == 500) {
+				return {
+					code: 500,
+					msg: SystemError[session.Get('lang')] || SystemError['en']
+				}
+			} else {
+				return response.data
+			}
+		}).catch(() => {
+			this.SessionExpire()
+			return {
+				code: Config.Code.StatusFail,
+				msg: SystemError[session.Get('lang')] || SystemError['en']
+			}
+		})
+	}
+
+	// method POST
+	post(url, params, config = {}) {
+        return this.axio.post(url, params, config).then((response) => {
+			if (response.data.code == Config.Code.StatusSessionExpire) {
+				this.SessionExpire()
+			} else if (response.data.code == Config.Code.StatusSNotFound) {
+				return {
+					code: Config.Code.StatusFail,
+					msg: SystemError[session.Get('lang')] || SystemError['en']
+				}
+			} else if (response.data.code == 500) {
+				return {
+					code: 500,
+					msg: SystemError[session.Get('lang')] || SystemError['en']
+				}
+			} else {
+				return response.data
+			}
+		}).catch(() => {
+			return {
+				code: Config.Code.StatusFail,
+				msg: SystemError[session.Get('lang')] || SystemError['en']
+			}
+		})
+	}
+}
+
+export default Service

+ 56 - 0
lib/session.js

@@ -0,0 +1,56 @@
+/*
+ * @Description: sessionStorage 封装
+ * @Author: sql
+ * @Date: 2018-11-23 21:02:16
+ * @LastEditTime: 2018-11-27 17:25:50
+ */
+import crypt from "@/lib/crypt"
+
+class SessionStorage {
+
+  constructor() {
+    this.Data = sessionStorage
+  }
+
+  // 获取 key中的数据
+  Get(key, flag = false) {
+    let res = null
+    if (flag) {
+      res = crypt.Decrypt(this.Data[key])
+    } else {
+      res = this.Data[key]
+
+    }
+    return this.IsExist(key) ? res : null
+  }
+
+  // 更新或创建新数据
+  Set(key, val, flag = false) {
+    let res = null
+    if (flag) {
+      res = crypt.Encrypt(String(val))
+    } else {
+      res = String(val)
+    }
+    this.Data[key] = sessionStorage[key] = res
+  }
+
+  // 输出 key 数据
+  Del(key) {
+    this.Data[key] = null
+    sessionStorage.removeItem(key)
+  }
+
+  // key数据是否存在
+  IsExist(key) {
+    return this.Data.getItem(key) ? true : false
+  }
+
+  // 清除所有session
+  Clear() {
+    this.Data = null
+    sessionStorage.clear()
+  }
+}
+
+export default new SessionStorage

+ 138 - 0
lib/upload.js

@@ -0,0 +1,138 @@
+/*
+ * @Description: 统一上传工具,先获取uploadToken,再上传到新接口
+ * @Author: Auto
+ * @Date: 2024-01-01
+ */
+import axios from 'axios'
+import Config from '../config'
+
+
+/**
+ * 统一上传方法
+ * @param {File} file - 要上传的文件
+ * @param {String} originalUrl - 原上传接口URL(用于获取uploadToken)
+ * @param {Object} headers - 请求头
+ * @param {Function} onProgress - 上传进度回调
+ * @returns {Promise} 上传结果
+ */
+export async function unifiedUpload(file, originalUrl, headers = {}, onProgress = null, id = null) {
+  try {
+    // 第一步:调用原接口获取 uploadToken
+    const formData = new FormData()
+    formData.append('file', file)
+    
+    // 设置请求头
+    const requestHeaders = {
+      'Access-Token': sessionStorage.getItem("access_token") || '',
+      'Language': sessionStorage.getItem("lang") || '',
+      'CLIENT': sessionStorage.getItem("CLIENT") || '',
+      ...headers
+    }
+    
+    // 获取基础URL
+    let baseURL = Config.Host80
+    if (originalUrl.includes(Config.Host80)) {
+      baseURL = Config.Host80
+    } else if (originalUrl.includes(Config.Host04)) {
+      baseURL = Config.Host04
+    } else if (originalUrl.includes(Config.Host90)) {
+      baseURL = Config.Host90
+    } else if (originalUrl.includes(Config.HostShop)) {
+      baseURL = Config.HostShop
+    } else if (originalUrl.includes(Config.Host87)) {
+      baseURL = Config.Host87
+    }
+    
+    // 提取原接口路径
+    let originalPath = originalUrl
+    if (originalUrl.startsWith('http://') || originalUrl.startsWith('https://')) {
+      // 完整URL,提取路径部分
+      const urlObj = new URL(originalUrl)
+      originalPath = urlObj.pathname
+    }
+    
+    // 调用原接口获取 uploadToken(先不传文件,只获取token)
+    // 如果原接口需要文件才能返回token,则传文件
+    const tokenFormData = new FormData()
+    tokenFormData.append('file', file)
+    
+    const tokenResponse = await axios.post(originalPath, tokenFormData, {
+      baseURL: baseURL,
+      headers: requestHeaders,
+      timeout: 30000
+    })
+    
+    // 从原接口响应中获取 uploadToken
+    // 假设原接口返回格式为 { code: 200, data: { uploadToken: 'xxx', ... } } 或 { code: 200, uploadToken: 'xxx' }
+    let uploadToken = null  
+    if (tokenResponse.data.code == 200) {
+      if(id === 1){
+        uploadToken = tokenResponse.data.data
+      }else {
+         // 如果直接返回 uploadToken
+         uploadToken = tokenResponse.data.data.path
+      }
+    }
+    
+    if (!uploadToken) {
+      throw new Error('Failed to get uploadToken from original upload interface')
+    }
+    
+    // 第二步:使用新接口上传文件
+    const uploadFormData = new FormData()
+    uploadFormData.append('file', file)
+    uploadFormData.append('uploadToken', uploadToken)
+    
+    const uploadResponse = await axios.post('/common/base/upload', uploadFormData, {
+      baseURL: Config.Host05,
+      headers: requestHeaders,
+      timeout: 60000,
+      onUploadProgress: (progressEvent) => {
+        if (onProgress && progressEvent.total) {
+          const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total)
+          onProgress({ percent })
+        }
+      }
+    })
+    
+    return uploadResponse.data
+    
+  } catch (error) {
+    console.error('Upload error:', error)
+    if (error.response) {
+      return {
+        code: error.response.status || 400,
+        msg: (error.response.data && error.response.data.msg) || error.message || 'Upload failed'
+      }
+    }
+    return {
+      code: 400,
+      msg: error.message || 'Upload failed'
+    }
+  }
+}
+
+/**
+ * 为 Element UI Upload 组件创建自定义上传方法
+ * @param {String} originalUrl - 原上传接口URL
+ * @param {Object} headers - 请求头
+ * @returns {Function} http-request 方法
+ */
+export function createUploadRequest(originalUrl, headers = {}, id = null) {
+  return async (options) => {
+    const { file, onProgress, onSuccess, onError } = options
+    
+    try {
+      const result = await unifiedUpload(file, originalUrl, headers, onProgress, id)
+      
+      if (result.code === 200) {
+        onSuccess(result)
+      } else {
+        onError(new Error(result.msg || 'Upload failed'))
+      }
+    } catch (error) {
+      onError(error)
+    }
+  }
+}
+

+ 1 - 0
package.json

@@ -18,6 +18,7 @@
     "clipboard": "^2.0.11",
     "crypto-js": "^4.2.0",
     "dayjs": "^1.11.13",
+    "decimal.js": "^10.6.0",
     "lodash": "^4.17.21",
     "pdfh5": "^3.0.0",
     "pinyin-pro": "^3.27.0",

+ 33 - 10
pages.json

@@ -95,28 +95,30 @@
       "path": "pages/login/index",
       "style": {
         "navigationBarTitleText": "",
-        "navigationStyle": "custom"
+        "navigationStyle": "custom",
+        "topWindow": false,
+        "leftWindow": false,
+        "rightWindow": false
       }
     },
     {
       "path": "pages/login/regist",
       "style": {
         "navigationBarTitleText": "",
-        "navigationStyle": "custom"
+        "navigationStyle": "custom",
+        "topWindow": false,
+        "leftWindow": false,
+        "rightWindow": false
       }
     },
     {
       "path": "pages/login/reset",
       "style": {
         "navigationBarTitleText": "",
-        "navigationStyle": "custom"
-      }
-    },
-    {
-      "path": "pages/login/forget",
-      "style": {
-        "navigationBarTitleText": "",
-        "navigationStyle": "custom"
+        "navigationStyle": "custom",
+        "topWindow": false,
+        "leftWindow": false,
+        "rightWindow": false
       }
     },
     {
@@ -161,6 +163,13 @@
         "navigationStyle": "custom"
       }
     },
+    {
+      "path": "pages/customer/account-select",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/customer/create-account",
       "style": {
@@ -168,6 +177,20 @@
         "navigationStyle": "custom"
       }
     },
+    {
+      "path": "pages/customer/deposit",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/customer/withdrawal",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/mine/notice",
       "style": {

+ 480 - 0
pages/customer/account-select.vue

@@ -0,0 +1,480 @@
+<template>
+    <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
+        <view class="account-selector">
+            <!-- PC 端表格视图 -->
+            <view class="account-table pc-view">
+                <!-- 表头:账户类型 -->
+                <view class="table-header">
+                    <view class="header-cell type-cell">标准型账户</view>
+                    <view class="header-cell">最低入金</view>
+                    <view class="header-cell">最小手数</view>
+                    <view class="header-cell">最大杠杆</view>
+                </view>
+                <!-- 标准账户行 -->
+                <template v-for="account in standardAccounts" :key="account.id">
+                    <view class="account-row" v-if="account.showCondition()" @click="onAccountSelect(account.id)"
+                        :class="{ 'active': account.id == selectedAccountId }">
+                        <view class="row-cell type-cell">
+                            <radio-group @change="(e) => onAccountSelect(account.id)" class="radio-group">
+                                <label class="radio-label">
+                                    <radio :value="account.id" :checked="selectedAccountId === account.id"
+                                        color="#1e2a3a" />
+                                    <image class="account-icon" :src="account.icon" mode="aspectFit" />
+                                    <view class="account-info">
+                                        <text class="account-name" v-t="account.name" />
+                                        <text class="account-desc" v-t="account.description" />
+                                    </view>
+                                </label>
+                            </radio-group>
+                        </view>
+                        <view class="row-cell">{{ account.minDeposit }}</view>
+                        <view class="row-cell">{{ account.minSpread }}</view>
+                        <view class="row-cell">{{ account.maxLeverage }}</view>
+                    </view>
+                </template>
+            </view>
+
+            <!-- 移动端轮播视图 -->
+            <view class="mobile-view">
+                <swiper class="account-swiper" :current="currentSwiperIndex" circular indicator-dots
+                    indicator-active-color="#1e2a3a" @change="onSwiperChange">
+                    <swiper-item v-for="account in filteredAccounts" :key="account.id">
+                        <view class="account-card" @click="onAccountSelect(account.id)"
+                            :class="{ 'active': account.id == selectedAccountId }">
+                            <image class="card-img" :src="account.icon" mode="aspectFit" />
+                            <view class="card-title" v-t="account.name"></view>
+                            <view class="card-tag">
+                                <text class="tag-label">{{ account.typeLabel }}</text>
+                            </view>
+                            <p class="card-desc" v-t="account.description"></p>
+                            <view class="card-info-stack">
+                                <cwg-label-line-value :label="'最低入金'" :value="account.minDeposit" />
+                                <cwg-label-line-value :label="'最小手数'" :value="account.minSpread" />
+                                <cwg-label-line-value :label="'最大杠杆'" :value="account.maxLeverage" />
+                            </view>
+                        </view>
+                    </swiper-item>
+                </swiper>
+            </view>
+        </view>
+        <!-- 继续按钮 -->
+        <view class="action-button">
+            <view class="btn" @click="handleContinue">
+                <text class="button-text">继续</text>
+            </view>
+        </view>
+        <!-- 条款说明 -->
+        <view class="terms-section">
+            <text v-t="'news_add_field.OpenAccount.Des1'"></text>
+            <text class="pdfLink">
+                <a href="/static/pdf/PrivacyPolicy2019_01.pdf" target="_blank"
+                    v-t="'news_add_field.OpenAccount.Des2'"></a>
+            </text>
+        </view>
+
+    </cwg-page-wrapper>
+</template>
+
+
+<script setup>
+import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue';
+import { onLoad } from '@dcloudio/uni-app';
+import { userToken } from "@/composables/config";
+import { customApi } from "@/service/custom";
+import { ucardApi } from "@/api/ucard";
+import useUserStore from "@/stores/use-user-store";
+import useRouter from "@/hooks/useRouter";
+import { useI18n } from "vue-i18n";
+const router = useRouter();
+const { t, locale } = useI18n();
+const userStore = useUserStore();
+const server = ref('')
+const showLogin = ref([])
+const isTimeShow = ref(true)
+
+onLoad((e) => {
+    server.value = e.server
+})
+
+// 定义账户数据类型
+const standardAccounts = ref([
+    {
+        id: 7,
+        type: 'StandardAccount',
+        name: 'AccountType.StandardAccount',
+        showCondition: () => showLogin.value.indexOf('7') === -1,
+        description: 'Custom.NewAccount.DesLogin5',
+        minDeposit: '50 USD',
+        minSpread: '0.01',
+        maxLeverage: '1:1000',
+        icon: '/static/images/info/bank-information-1.webp',
+    },
+    {
+        id: 2,
+        type: 'SeniorAccount',
+        name: 'AccountType.SeniorAccount',
+        showCondition: () => showLogin.value.indexOf('2') === -1,
+        description: 'Custom.NewAccount.DesLogin3',
+        minDeposit: '200 USD',
+        minSpread: '0.01',
+        maxLeverage: '1:2000',
+        icon: '/static/images/info/bank-information-2.webp',
+    },
+    {
+        id: 8,
+        type: 'CentAccount',
+        name: 'AccountType.CentAccount',
+        showCondition: () => showLogin.value.indexOf('8') === -1 && isTimeShow.value,
+        description: 'Custom.NewAccount.DesLogin8',
+        minDeposit: '10 USD',
+        minSpread: '0.01',
+        maxLeverage: '1:1000',
+        icon: '/static/images/info/bank-information-3.webp',
+    }
+])
+
+// 过滤后的账户列表
+const filteredAccounts = computed(() => {
+    return standardAccounts.value.filter(account => account.showCondition())
+})
+
+// 当前选中的账户 ID
+const selectedAccountId = ref(7)
+
+// 轮播图当前索引
+const currentSwiperIndex = computed(() => {
+    const index = filteredAccounts.value.findIndex(a => a.id === selectedAccountId.value)
+    return index > -1 ? index : 0
+})
+
+// 账户选择事件
+const onAccountSelect = (id) => {
+    selectedAccountId.value = id
+}
+
+// 轮播图切换事件
+const onSwiperChange = (e) => {
+    const index = e.detail.current
+    const account = filteredAccounts.value[index]
+    if (account) {
+        selectedAccountId.value = account.id
+    }
+}
+
+// 继续按钮点击事件,向上传递选中的账户信息
+const handleContinue = () => {
+    router.push({
+        path: "/pages/customer/create-account",
+        query: { id: selectedAccountId.value, server: server.value },
+    });
+}
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+
+.account-selector {
+    background-color: #fff;
+    overflow: hidden;
+}
+
+.table-wrapper {
+    width: 100%;
+    overflow-x: auto;
+
+    white-space: nowrap;
+}
+
+.account-table {
+    min-width: px2rpx(350);
+    margin-bottom: px2rpx(10);
+    /* 保证在小屏上可滚动 */
+    display: flex;
+    flex-direction: column;
+    font-size: px2rpx(14);
+    color: #333;
+}
+
+.table-header {
+    display: flex;
+    padding: px2rpx(10) 0;
+    font-weight: 500;
+    color: #666;
+
+    .header-cell {
+        flex: 1;
+        text-align: center;
+        padding: 0 px2rpx(8);
+        white-space: normal;
+        word-break: break-word;
+    }
+
+    .type-cell {
+        flex: 2;
+        text-align: left;
+        padding-left: px2rpx(12);
+    }
+}
+
+.professional-header {
+    margin-top: px2rpx(8);
+}
+
+.account-row {
+    display: flex;
+    align-items: center;
+    padding: px2rpx(12) 0;
+    margin: px2rpx(12) 0;
+    border: 1px solid rgba(108, 133, 149, 0.2);
+    border-radius: px2rpx(8);
+
+    &:hover {
+        box-shadow: 0 10px 15px -3px rgba(7, 10, 12, 0.08), 0 4px 6px -4px rgba(7, 10, 12, 0.08), 0 0 4px 0 rgba(7, 10, 12, 0.08);
+    }
+
+    &.active {
+        background-color: rgba(108, 133, 149, 0.07843);
+    }
+
+    .row-cell {
+        flex: 1;
+        text-align: center;
+        padding: 0 px2rpx(8);
+        font-size: px2rpx(12);
+        color: #1e2a3a;
+        white-space: normal;
+        word-break: break-word;
+    }
+
+    .type-cell {
+        flex: 2;
+        text-align: left;
+        padding-left: px2rpx(12);
+    }
+}
+
+.radio-group {
+    display: flex;
+    align-items: center;
+    width: 100%;
+}
+
+.radio-label {
+    display: flex;
+    align-items: center;
+    gap: px2rpx(6);
+    width: 100%;
+}
+
+radio {
+    transform: scale(0.8);
+    margin-right: px2rpx(4);
+}
+
+.account-icon {
+    width: px2rpx(48);
+    height: px2rpx(48);
+    margin-right: px2rpx(24);
+    flex-shrink: 0;
+}
+
+.account-info {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    text-align: left;
+
+    .account-name {
+        font-size: px2rpx(14);
+        font-weight: 500;
+        color: #1e2a3a;
+        margin-bottom: px2rpx(4);
+    }
+
+    .account-desc {
+        font-size: px2rpx(12);
+        color: #7f8c8d;
+        line-height: 1.4;
+    }
+}
+
+.mobile-view {
+    display: none;
+}
+
+@media screen and (max-width: 600px) {
+    .pc-view {
+        display: none;
+    }
+
+    .mobile-view {
+        display: block;
+        padding: px2rpx(20) 0;
+    }
+
+    .account-swiper {
+        height: px2rpx(520);
+        width: 100%;
+
+    }
+
+    .account-card {
+        background: #fff;
+        border-radius: px2rpx(8);
+        margin: px2rpx(2) px2rpx(20);
+        padding: px2rpx(30);
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        text-align: center;
+        border: 2px solid transparent;
+        transition: all 0.3s;
+        height: px2rpx(400);
+        color: rgb(20, 29, 34);
+        box-shadow:
+            rgba(54, 61, 66, 0.15) 0px 0px 1px 0px,
+            rgba(54, 61, 66, 0.04) 0px 2px 2px 0px,
+            rgba(54, 61, 66, 0.12) 0px 2px 8px 0px,
+            rgba(54, 61, 66, 0.08) 0px -2px 4px 0px;
+        transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
+        overflow: hidden;
+
+        &.active {
+            transform: translateY(px2rpx(-5));
+        }
+
+        .card-img {
+            width: px2rpx(120);
+            height: px2rpx(120);
+            margin-bottom: px2rpx(20);
+        }
+
+        .card-title {
+            font-size: px2rpx(24);
+            font-weight: 700;
+            color: #1e2a3a;
+            margin-bottom: px2rpx(8);
+        }
+
+        .card-tag {
+            background: #f0f2f5;
+            padding: px2rpx(4) px2rpx(12);
+            border-radius: px2rpx(20);
+            margin-bottom: px2rpx(16);
+
+            .tag-label {
+                font-size: px2rpx(12);
+                color: #666;
+            }
+        }
+
+        .card-desc {
+            font-size: px2rpx(14);
+            color: #7f8c8d;
+            line-height: 1.6;
+            margin-bottom: px2rpx(24);
+            height: px2rpx(44);
+            overflow: hidden;
+        }
+
+        .card-info-stack {
+            width: 100%;
+            display: flex;
+            flex-direction: column;
+            gap: px2rpx(12);
+
+            .info-row {
+                display: flex;
+                justify-content: space-between;
+                align-items: baseline;
+                position: relative;
+                font-size: px2rpx(14);
+
+                &::after {
+                    content: "";
+                    flex: 1;
+                    margin: 0 px2rpx(10);
+                    border-bottom: 1px dotted #ddd;
+                    height: 1px;
+                }
+
+                .label {
+                    color: #666;
+                    order: 1;
+                }
+
+                .value {
+                    color: #1e2a3a;
+                    font-weight: 500;
+                    order: 3;
+                }
+            }
+        }
+    }
+
+    .action-button {
+        justify-content: center !important;
+        // padding: 0 px2rpx(20);
+
+        .btn {
+            width: 100%;
+            min-width: unset !important;
+        }
+    }
+
+    .terms-section {
+        text-align: center;
+        padding: 0 px2rpx(20);
+    }
+}
+
+.action-button {
+    width: 100%;
+    display: flex;
+    justify-content: flex-end;
+    margin-top: px2rpx(40);
+
+    .btn {
+        width: px2rpx(320);
+        background-color: #1e2a3a;
+        padding: px2rpx(12) px2rpx(20);
+        border-radius: px2rpx(8);
+        text-align: center;
+        cursor: pointer;
+        box-sizing: border-box;
+        transition: all 0.2s;
+
+        &:active {
+            opacity: 0.9;
+            transform: scale(0.98);
+        }
+
+        .button-text {
+            color: #fff;
+            font-size: px2rpx(16);
+            font-weight: 600;
+        }
+    }
+}
+
+.terms-section {
+    margin: px2rpx(30) 0;
+    font-size: px2rpx(14);
+    line-height: 1.7;
+    color: #666;
+    text-align: center;
+
+    .pdfLink {
+        margin-left: px2rpx(4);
+
+        a {
+            color: var(--color-primary);
+            text-decoration: none;
+
+            &:hover {
+                text-decoration: underline;
+            }
+        }
+    }
+}
+</style>

+ 119 - 45
pages/customer/components/AccountCard.vue

@@ -12,12 +12,14 @@
         <!-- 标签区域 -->
         <view class="labels-container">
             <view class="labels">
-                <view v-for="(label, index) in account.labels" :key="index" class="label-badge">
-                    {{ label }}
-                </view>
+                <template v-for="(label, index) in account.labels" :key="index">
+                    <view v-if="label" class="label-badge">
+                        {{ label }}
+                    </view>
+                </template>
             </view>
             <view class="account-number"># {{ account.accountNumber }}</view>
-            <view class="account-nickname">{{ account.nickname }}</view>
+            <view class="account-nickname">{{ nickName }}</view>
         </view>
 
         <!-- 主要内容区域(余额和操作按钮) -->
@@ -42,9 +44,8 @@
                     </view>
                     <text class="circle-label">交易</text>
                 </view>
-
                 <!-- 入金(带限制包装,此处简化) -->
-                <view class="circle-btn" @click="toDeposit">
+                <view class="circle-btn" @click="toDeposit" v-if="!isDemo">
                     <view class="circle-icon">
                         <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                             stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -58,7 +59,7 @@
                 </view>
 
                 <!-- 出金 -->
-                <view class="circle-btn" @click="toWithdraw">
+                <view class="circle-btn" @click="toWithdraw" v-if="!isDemo">
                     <view class="circle-icon">
                         <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                             stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -71,7 +72,7 @@
                 </view>
 
                 <!-- 转账 -->
-                <view class="circle-btn" @click="toTransfer">
+                <view class="circle-btn" @click="toTransfer" v-if="!isDemo">
                     <view class="circle-icon">
                         <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
                             <path d="M21 17H3M21 17L17.5 20.5M21 17L17.5 13.5M6.5 10.5L3 7M3 7L6.5 3.5M3 7H21"
@@ -82,17 +83,22 @@
                 </view>
 
                 <!-- 更多(三点) -->
-                <view class="circle-btn" @click="handleAction('more')">
-                    <view class="circle-icon">
-                        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
-                            stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
-                            <path d="M12 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
-                            <path d="M12 19m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
-                            <path d="M12 5m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
-                        </svg>
+                <cwg-dropdown @open="onOpen" @close="onClose" :menu-list="customMenuList"
+                    @menuClick="handleCustomClick">
+                    <view class="circle-btn">
+                        <view class="circle-icon">
+                            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
+                                fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
+                                stroke-linejoin="round">
+                                <path d="M12 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
+                                <path d="M12 19m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
+                                <path d="M12 5m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
+                            </svg>
+                        </view>
+                        <text class="circle-label">更多</text>
                     </view>
-                    <text class="circle-label">更多</text>
-                </view>
+                </cwg-dropdown>
+
             </view>
 
             <!-- 桌面端按钮组(>1100px显示) -->
@@ -108,7 +114,7 @@
                     </span>
                     交易
                 </view>
-                <view class="action-btn" @click="toDeposit">
+                <view class="action-btn" @click="toDeposit" v-if="!isDemo">
                     <span class="btn-icon">
                         <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                             stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -120,7 +126,7 @@
                     </span>
                     入金
                 </view>
-                <view class="action-btn" @click="toWithdraw">
+                <view class="action-btn" @click="toWithdraw" v-if="!isDemo">
                     <span class="btn-icon">
                         <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                             stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -131,7 +137,7 @@
                     </span>
                     出金
                 </view>
-                <view class="action-btn" @click="toTransfer">
+                <view class="action-btn" @click="toTransfer" v-if="!isDemo">
                     <span class="btn-icon">
                         <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
                             <path d="M21 17H3M21 17L17.5 20.5M21 17L17.5 13.5M6.5 10.5L3 7M3 7L6.5 3.5M3 7H21"
@@ -140,14 +146,18 @@
                     </span>
                     转账
                 </view>
-                <view class="action-btn icon-only" @click="handleAction('more')">
-                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
-                        stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
-                        <path d="M12 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
-                        <path d="M12 19m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
-                        <path d="M12 5m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
-                    </svg>
-                </view>
+                <cwg-dropdown @open="onOpen" @close="onClose" :menu-list="customMenuList"
+                    @menuClick="handleCustomClick">
+                    <view class="action-btn icon-only">
+                        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
+                            stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+                            <path d="M12 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
+                            <path d="M12 19m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
+                            <path d="M12 5m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
+                        </svg>
+                    </view>
+                </cwg-dropdown>
+
             </view>
         </view>
         <view ref="infoBottomRef" class="info-bottom" :style="{
@@ -185,7 +195,7 @@
                 </view>
 
                 <!-- 更改交易密码按钮 -->
-                <view class="change-password-btn" @click="handleChangePassword">
+                <view class="change-password-btn" @click="handleAction('changePassword1')" v-if="!isDemo">
                     <span class="btn-icon">
                         <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
                             stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -200,22 +210,36 @@
 
         <!-- 通知区域(预留) -->
         <view class="notificators"></view>
+        <TerminalDialog v-model:visible="terminalDialogVisible" />
+        <!-- <TerminalNickNameDialog v-model:visible="terminalNickNameDialogVisible" :account="account"
+            @save="saveNickName" /> -->
+        <TerminalChangePasswordDialog v-model:visible="terminalChangePasswordDialogVisible" :pwdType="pwdType"
+            :account="account" />
+        <TerminalInfoDialog v-model:visible="terminalInfoDialogVisible" :accountNumber="accountInfo.login"
+            :form="accountInfo" :fieldList="fieldList" />
     </view>
 </template>
 
 <script setup lang="ts">
-import { ref, computed, onMounted, nextTick, onBeforeUnmount } from 'vue';
+import { ref, computed, onMounted, nextTick, onBeforeUnmount, watch } from 'vue';
 import useRouter from "@/hooks/useRouter";
 const router = useRouter();
 import { useI18n } from 'vue-i18n';
 const { t, locale } = useI18n();
+import TerminalDialog from './TerminalDialog.vue'
+import TerminalNickNameDialog from './TerminalNickNameDialog.vue'
+import TerminalChangePasswordDialog from './TerminalChangePasswordDialog.vue'
+import TerminalInfoDialog from './TerminalInfoDialog.vue'
 
-
+const props = defineProps<{
+    account: Account;
+}>();
+const accountInfo = ref(props.account)
 // 定义账户数据类型
 export interface Account {
     labels: string[];          // 标签数组,如 ['真实', 'MT4', 'Standard']
     accountNumber: string;      // 账号,如 '85319215'
-    nickname: string;           // 昵称,如 '标准账户'
+    nickName: string;           // 昵称,如 '标准账户'
     balance: number;            // 余额数字
     currency: string;           // 货币,如 'USD'
     actualLeverage: string;     // 实际杠杆,如 '1:2000'
@@ -228,6 +252,23 @@ export interface Account {
     login: string;              // 登录名,如 '85319215'
     balanceWithSymbol: string;              // 余额,如 '85319215'
 }
+const isDemo = computed(() => accountInfo.value.listType == 'demo')
+
+const fieldList = ref([
+    { label: '账户类型', key: 'nickname', copyable: false },
+    { label: t('Label.Leverage'), key: 'actualLeverage', copyable: false },
+    { label: '浮动盈/亏', key: 'floatingPL', copyable: false },
+    { label: t('Label.Balance'), key: 'balanceWithSymbol', copyable: false },
+    { label: t('Label.Equity'), key: 'equityWithSymbol', copyable: false },
+    { label: t('Label.Credit'), key: 'creditWithSymbol', copyable: false },
+    { label: '平台', key: 'platform', copyable: false },
+    { label: '账号', key: 'login', copyable: true }
+])
+const nickName = ref(accountInfo.value.nickName)
+const saveNickName = (newNickName) => {
+    nickName.value = newNickName
+    accountInfo.value.nickName = newNickName
+}
 
 const infoBottomRef = ref(null);
 const infoBottomHeight = ref(0);
@@ -256,47 +297,80 @@ const toggleExpand = () => {
     }
 };
 
-const props = defineProps<{
-    account: Account;
-}>();
 
+const terminalDialogVisible = ref(false)
+const terminalChangePasswordDialogVisible = ref(false)
+const terminalInfoDialogVisible = ref(false)
+const pwdType = ref(1)
 // 处理按钮操作
 const handleAction = (type: string) => {
+    console.log(type == 'info', type, 'info');
+    switch (type) {
+        case 'trade':
+            terminalDialogVisible.value = true
+            break;
+        case 'changePassword1':
+            pwdType.value = 1
+            terminalChangePasswordDialogVisible.value = true
+            break;
+        case 'changePassword2':
+            pwdType.value = 2
+            terminalChangePasswordDialogVisible.value = true
+            break;
+        case 'info':
+            console.log(type);
+            terminalInfoDialogVisible.value = true
+            break;
+        default:
+            break;
+    }
 };
 
+const customMenuList = computed(() => !isDemo.value ? [{ label: '修改交易密码', type: 'changePassword1' }, { label: '修改投资者密码', type: 'changePassword2' }, { label: '账户信息', type: 'info' }] : [{ label: '账户信息', type: 'info' }])
+
+
+const handleCustomClick = (item, index) => {
+
+
+    handleAction(item.value.type)
+}
+
+
 // 复制文本
 const copy = (text: string) => {
     uni.setClipboardData({ data: text });
 };
 
+
+
 // 按钮对应的操作方法
 const toDeposit = () => {
-    router.push(`/pages/customer/deposit?login=${props.accountlogin}&type=${props.accounttype}&balance=${props.accountbalance}&currency=${props.accountcurrency}`)
+    router.push(`/pages/customer/deposit?login=${accountInfo.value.login}&type=${accountInfo.value.type}&balance=${accountInfo.value.balance}&currency=${accountInfo.value.currency}`)
 }
 
 const toWithdraw = () => {
-    router.push(`/pages/customer/withdraw?login=${props.accountlogin}&type=${props.accounttype}&balance=${props.accountbalance}&currency=${props.accountcurrency}`)
+    router.push(`/pages/customer/withdraw?login=${accountInfo.value.login}&type=${accountInfo.value.type}&balance=${accountInfo.value.balance}&currency=${accountInfo.value.currency}`)
 }
 
 const toTransfer = () => {
-    router.push(`/pages/customer/transfer?login=${props.accountlogin}&type=${props.accounttype}&balance=${props.accountbalance}&currency=${props.accountcurrency}`)
+    router.push(`/pages/customer/transfer?login=${accountInfo.value.login}&type=${accountInfo.value.type}&balance=${accountInfo.value.balance}&currency=${accountInfo.value.currency}`)
 }
 
 // 更改交易密码
 const handleChangePassword = () => {
-    const close = props.accountcloseFunctions?.indexOf('4') !== -1 ? 1 : 0
-    router.push(`/pages/customer/settings?login=${props.accountlogin}&platform=${props.accountplatform}&type=${props.accounttype}&currency=${props.accountcurrency}&leverage=${props.accountleverage}&close=${close}`)
+    const close = accountInfo.value.closeFunctions?.indexOf('4') !== -1 ? 1 : 0
+    router.push(`/pages/customer/settings?login=${accountInfo.value.login}&platform=${accountInfo.value.platform}&type=${accountInfo.value.type}&currency=${accountInfo.value.currency}&leverage=${accountInfo.value.leverage}&close=${close}`)
 }
 
 const toStandardRebate = () => {
-    router.push(`/pages/customer/standard/rebate?login=${props.accountlogin}`)
+    router.push(`/pages/customer/standard/rebate?login=${accountInfo.value.login}`)
 }
 // 格式化余额,拆分为整数和小数部分
 const balanceInteger = computed(() => {
-    return Math.floor(props.account.balance).toString();
+    return Math.floor(accountInfo.value.balance).toString();
 });
 const balanceDecimal = computed(() => {
-    const parts = props.account.balance.toFixed(2).split('.');
+    const parts = accountInfo.value.balance.toFixed(2).split('.');
     return parts[1] ? '.' + parts[1] : '.00';
 });
 // 在组件挂载后初始化高度
@@ -305,7 +379,7 @@ onMounted(() => {
         updateSubmenuHeight();
     });
     window.addEventListener('resize', handleResize);
-    isExpanded.value = props.account.isExpanded;
+    isExpanded.value = accountInfo.value.isExpanded;
 });
 // 监听窗口 resize
 const handleResize = () => {

+ 21 - 17
pages/customer/components/AccountList.vue

@@ -7,16 +7,14 @@
                     <cwg-icon icon="crm-plus" :size="16" color="#fff" />
                     <text v-t="'Custom.Index.AddAccount'" />
                 </view>
-                <view class="btn-primary" @click="openDeleteAccountDialogs()">
-                    <cwg-icon icon="crm-trash-can" :size="16" color="#fff" />
-                    <text v-t="'Tips.DeleteAccount'" />
-                </view>
             </view>
         </view>
-        <cwg-tabs v-model:cativeIndex="cativeIndex" :tabs="tabs" class="tabs-class" />
-        <AccountCard v-for="acc in accounts" :key="acc.accountNumber" :account="acc" @action="handleAction"
-            @copy="handleCopy" @change-password="handleChangePassword" />
-
+        <view class="tabs-class"><cwg-tabs v-model:cativeIndex="cativeIndex" :tabs="tabs" /></view>
+        <view v-if="accounts.length">
+            <AccountCard v-for="acc in accounts" :zhtype="cativeIndex" :key="acc.accountNumber" :account="acc" @action="handleAction"
+                @copy="handleCopy" @change-password="handleChangePassword" />
+        </view>
+        <cwg-empty-state v-else />
         <DeleteAccountDialogs ref="deleteAccountDialogRef" v-model:visible="deleteAccountDialogVisible" />
     </view>
 </template>
@@ -58,8 +56,8 @@ const typeMap = computed(() => ({
 }));
 const cativeIndex = ref(0)
 const tabs = computed(() => ([
-    { id: 'MT4', name: 'MT4' },
-    { id: 'MT5', name: 'MT5' }
+    { id: 'real', name: '真实' },
+    { id: 'demo', name: '模拟' }
 ]))
 
 const tableRef = ref(null)
@@ -152,7 +150,7 @@ const createAccount = () => {
 const isZh = computed(() => ['cn', 'zh', 'zhHant'].includes(locale.value));
 
 watch(cativeIndex, (newVal) => {
-    search.value.platform = tabs.value[newVal].id
+    // search.value.platform = tabs.value[newVal].id
     getAccountList()
 })
 
@@ -166,7 +164,7 @@ async function getCustomLoginInfo() {
                 res.data.customInfo.status == 2 &&
                 res.data.customInfo.applyRealStatus == 2
             ) {
-                router.push('/pages/customer/create-account')
+                router.push(`/pages/customer/account-select?server=${cativeIndex.value == 1 ? 'demo' : 'real'}`)
             } else {
                 // this.dialogCheck = true;
             }
@@ -177,11 +175,14 @@ async function getCustomLoginInfo() {
 }
 const AccountList = ref([])
 const getAccountList = async () => {
-    const res = await customApi.AccountList({
+    AccountList.value = []
+
+    const api = cativeIndex.value == 1 ? customApi.demoList : customApi.AccountAllList
+    const res = await api({
         page: {
             current: 1,
             size: 100
-        }, ...search.value
+        }
     })
     if (res.code === 200) {
         AccountList.value = res.data
@@ -197,10 +198,11 @@ function formatMoney(value) {
 
 // 转换数组
 const accounts = computed(() =>
-    AccountList.value.map((acc, index) => {
+    AccountList.value && AccountList.value.length != 0 ? AccountList.value.map((acc, index) => {
         const currency = acc.currency || 'USD';
         const floating = acc.floating ?? 0;
         let labels = ['真实', 'MT4', 'Standard'];
+        labels[0] = cativeIndex.value == 1 ? '模拟' : '真实';
         labels[1] = acc.platform || 'MT4';
         labels[2] = typeMap.value[acc.type];
         let nickname = typeMap.value[acc.type];
@@ -220,9 +222,10 @@ const accounts = computed(() =>
             floatingPL: formatMoney(floating), // 盈亏
             platform: acc.platform || 'MT4',
             server: acc.groupCode || '',
-            login: acc.login.toString()
+            login: acc.login.toString(),
+            listType: cativeIndex.value == 1 ? 'demo' : 'real'
         };
-    })
+    }) : []
 )
 onMounted(async () => {
     await getAccountList()
@@ -240,6 +243,7 @@ onMounted(async () => {
 }
 
 .tabs-class {
+    width: px2rpx(200);
     margin: px2rpx(20) 0;
 }
 

+ 1 - 1
pages/customer/components/DeleteAccountDialogs.vue

@@ -1,5 +1,5 @@
 <template>
-    <cwg-popup :title="t('Tips.DeleteAccount')" v-model:visible="props.visible" :showFooter="false"
+    <cwg-popup :title="t('Tips.DeleteAccount')" :visible="props.visible" :showFooter="false"
         @update:visible="$emit('update:visible', $event)">
         <scroll-view scroll-y class="account-list" :style="{ maxHeight: '40vh' }">
             <!-- 加载状态 -->

+ 184 - 0
pages/customer/components/PaymentMethodsList.vue

@@ -0,0 +1,184 @@
+<template>
+  <view class="payment-list">
+    <view v-for="item in list" :key="item.id" class="payment-card" :class="{ disabled: item.disabled }"
+      @click="handleClick(item)">
+      <view class="icon-wrapper">
+        <image class="icon" :src="imgUrl + item.icon" mode="widthFix" />
+      </view>
+      <view class="content">
+        <view class="header">
+          <text class="title">{{ item.name }}</text>
+        </view>
+        <view class="info-list">
+          <view class="info-item">
+            <text class="info-label" v-t="'Label.ProcessingTime'" />
+            <text class="info-value">{{ item.fundingTime }}</text>
+          </view>
+          <view class="info-item">
+            <text class="info-label" v-t="'Label.Fee'" />
+            <text class="info-value">{{ item.free != null ? item.free + '%' : '-' }}</text>
+          </view>
+          <view class="info-item">
+            <text class="info-label">限制</text>
+            <text class="info-value">{{ item.minAmount }}-{{ item.maxAmount }} {{ item.currency }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { defineProps, defineEmits } from 'vue'
+import Config from '@/config/index'
+const { Code, Host80 } = Config
+const imgUrl = Host80
+// 定义 props,接收支付方式列表
+const props = defineProps({
+  list: {
+    type: Array,
+    default: () => []
+  }
+})
+
+// 定义事件,点击卡片时触发
+const emit = defineEmits(['select'])
+
+const handleClick = (item) => {
+  if (!item.disabled) {
+    emit('select', item)
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+
+.payment-list {
+  display: grid;
+  grid-row-gap: px2rpx(16);
+  grid-column-gap: px2rpx(24);
+  grid-template-columns: repeat(auto-fill, minmax(px2rpx(320), 1fr));
+}
+
+.payment-card {
+  background-color: #fff;
+  border-radius: px2rpx(12);
+  padding: px2rpx(16);
+  display: flex;
+  align-items: flex-start;
+  border: 1px solid rgba(14, 15, 12, 0.08);
+  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+  cursor: pointer;
+  box-sizing: border-box;
+  gap: px2rpx(16);
+
+  &:hover {
+    transform: translateY(px2rpx(-2));
+    background-color: #fff;
+    box-shadow: 0 px2rpx(8) px2rpx(20) rgba(0, 0, 0, 0.06);
+    border-color: var(--color-primary, #007aff);
+  }
+
+  &.disabled {
+    opacity: 0.5;
+    cursor: not-allowed;
+    filter: grayscale(100%);
+  }
+
+  .icon-wrapper {
+    width: px2rpx(120);
+    height: px2rpx(120);
+    flex-shrink: 0;
+    border-radius: px2rpx(8);
+    background-color: var(--color-zinc-50, #f9f9f9);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    overflow: hidden;
+
+    .icon {
+      width: 80%;
+    }
+  }
+
+  .content {
+    flex: 1;
+    min-width: 0; // 防止文本溢出
+
+    .header {
+      margin-bottom: px2rpx(12);
+
+      .title {
+        font-size: px2rpx(16);
+        font-weight: 700;
+        color: var(--color-navy-900, #1e2a3a);
+        word-break: break-all;
+      }
+    }
+
+    .info-list {
+      .info-item {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: px2rpx(8);
+        font-size: px2rpx(13);
+        line-height: 1.4;
+
+        .info-label {
+          color: var(--color-zinc-500, #7f8c8d);
+          margin-right: px2rpx(8);
+          white-space: nowrap;
+        }
+
+        .info-value {
+          color: var(--color-navy-900, #1e2a3a);
+          font-weight: 600;
+          text-align: right;
+          word-break: break-all;
+        }
+
+        &:last-child {
+          margin-bottom: 0;
+        }
+      }
+    }
+  }
+}
+
+/* 移动端适配 */
+@media screen and (max-width: 768px) {
+  .payment-list {
+    grid-template-columns: 1fr;
+    grid-row-gap: px2rpx(12);
+  }
+
+  .payment-card {
+    padding: px2rpx(12);
+    gap: px2rpx(12);
+
+    .icon-wrapper {
+      width: px2rpx(90);
+      height: px2rpx(90);
+    }
+
+    .content {
+      .header {
+        margin-bottom: px2rpx(8);
+
+        .title {
+          font-size: px2rpx(15);
+        }
+      }
+
+      .info-list {
+        .info-item {
+          margin-bottom: px2rpx(4);
+          font-size: px2rpx(12);
+        }
+      }
+    }
+  }
+}
+</style>

+ 210 - 0
pages/customer/components/TerminalChangePasswordDialog.vue

@@ -0,0 +1,210 @@
+<template>
+    <cwg-popup :title="props.pwdType == 1 ? t('Custom.Settings.LoginPwd') : t('Custom.Settings.InvestorPwd')"
+        :visible="props.visible" :showFooter="false" @update:visible="$emit('update:visible', $event)">
+        <view class="popup-content">
+            <text class="account-number">{{ accountLabel }} {{ account.login }}</text>
+
+            <uni-forms :model="passwordInfo" labelWidth="200" label-position="top" class="crm-form">
+                <uni-forms-item
+                    :label="props.pwdType == 1 ? t('Custom.Settings.LoginPwdOld') : t('Custom.Settings.InvestorPwdOld')">
+                    <uni-easyinput type="password" :clearable="false" v-model="passwordInfo.oldPassword"
+                        :placeholder="props.pwdType == 1 ? t('Custom.Settings.LoginPwdOld') : t('Custom.Settings.InvestorPwdOld')" />
+                </uni-forms-item>
+                <uni-forms-item :label="t('Custom.Settings.NewPwd')">
+                    <uni-easyinput type="password" :clearable="false" v-model="passwordInfo.newPassword"
+                        :placeholder="t('Custom.Settings.NewPwd')" />
+                </uni-forms-item>
+            </uni-forms>
+
+            <view class="notice-list">
+                <view v-for="(item, index) in noticeItems" :key="index"
+                    :class="['notice-item', item.valid ? 'isOK' : '']">
+                    {{ item.label }}
+                </view>
+            </view>
+
+            <view class="save-btn">
+                <view class="btn primary" @click="save" :disabled="!isFormValid" v-t="'Btn.Save'" />
+            </view>
+        </view>
+    </cwg-popup>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue'
+import { customApi } from '@/service/custom';
+import { useI18n } from 'vue-i18n'
+import { showToast } from "@/utils/toast";
+
+const { t } = useI18n()
+
+const props = defineProps({
+    visible: { type: Boolean, default: false },
+    account: { type: Object, default: () => ({}) },
+    accountLabel: { type: String, default: '账户: #' },
+    // 1: 交易密码, 2: 投资者密码
+    pwdType: { type: [Number, String], default: 1 },
+})
+
+const emit = defineEmits(['update:visible', 'save'])
+
+const passwordInfo = ref({
+    oldPassword: '',
+    newPassword: ''
+});
+
+const rule1 = computed(() => {
+    if (!passwordInfo.value.newPassword) return false;
+    return /^.{8,16}$/.test(passwordInfo.value.newPassword);
+});
+
+const rule2 = computed(() => {
+    return /^(?=.*?[a-z])(?=.*?[A-Z]).*$/.test(passwordInfo.value.newPassword);
+});
+
+const rule3 = computed(() => {
+    return /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?!.*([~!@&%$^\\(\\)#_]).*\\1.*\\1)[A-Za-z0-9~!@&%$^\\(\\)#_]{8,16}$/.test(
+        passwordInfo.value.newPassword
+    );
+});
+
+const noticeItems = computed(() => [
+    { label: t('signup.form.rules.1st'), valid: rule1.value },
+    { label: t('signup.form.rules.2nd'), valid: rule2.value },
+    { label: t('signup.form.rules.3rd'), valid: rule3.value }
+]);
+
+const isFormValid = computed(() => {
+    return rule1.value && rule2.value && rule3.value && passwordInfo.value.oldPassword && passwordInfo.value.newPassword;
+});
+
+const flag = ref(false); // 防止重复提交
+
+const save = async () => {
+    if (!isFormValid.value) {
+        return;
+    }
+
+    if (flag.value) return;
+    flag.value = true;
+
+    try {
+        let res;
+        if (props.pwdType == 1) {
+            // 修改交易账户密码
+            res = await customApi.ChangeDealPassword({
+                login: props.account.login,
+                ...passwordInfo.value
+            });
+        } else {
+            // 修改投资者密码
+            res = await customApi.ChangeInvestorOassword({
+                login: props.account.login,
+                ...passwordInfo.value
+            });
+        }
+
+        if (res.code == 200) {
+            showToast(t('Msg.Success'));
+            emit('update:visible', false);
+            passwordInfo.value = {
+                oldPassword: '',
+                newPassword: ''
+            }
+            emit('save');
+
+        } else {
+            showToast(res.msg);
+        }
+    } catch (error) {
+        console.error(error);
+    } finally {
+        flag.value = false;
+    }
+}
+</script>
+
+<style scoped lang="scss">
+@import "@/uni.scss";
+@media (min-width: 768px) {
+    :deep(.cwg-dialog) {
+        background-color: var(--color-white);
+        border-radius: px2rpx(8);
+        width: px2rpx(480) !important;
+    }
+}
+
+.popup-content {
+    padding: px2rpx(16);
+}
+
+.account-number {
+    display: block;
+    font-size: px2rpx(14);
+    color: #141d22;
+    margin-bottom: px2rpx(24);
+}
+
+.crm-form {
+    :deep(.uni-forms-item) {
+        margin-bottom: px2rpx(16);
+    }
+
+    :deep(.uni-easyinput__content) {
+        border: none !important;
+        background-color: var(--color-zinc-100) !important;
+    }
+}
+
+.notice-list {
+    margin: px2rpx(10) 0;
+    padding: 0 px2rpx(12) px2rpx(12) 0;
+
+    .notice-item {
+        font-size: px2rpx(14);
+        color: var(--color-yellow-800);
+        line-height: px2rpx(24);
+    }
+
+    .isOK {
+        color: var(--color-success);
+    }
+}
+
+.save-btn {
+    width: 100%;
+    display: flex;
+    justify-content: flex-end;
+    margin-top: px2rpx(20);
+
+    .btn {
+        border: 1px solid rgba(108, 133, 149, 0);
+        border-radius: px2rpx(8);
+        padding: px2rpx(8) px2rpx(20);
+        font-size: px2rpx(14);
+        color: #2e3a47;
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        gap: px2rpx(8);
+        cursor: pointer;
+        transition: all 0.2s;
+        height: px2rpx(40);
+        box-sizing: border-box;
+        background-color: rgba(108, 133, 149, 0.08);
+
+        &.primary {
+            background-color: var(--color-navy-700);
+            color: #fff;
+
+            &:hover {
+                background-color: var(--color-navy-600);
+            }
+
+            &[disabled] {
+                cursor: not-allowed;
+            }
+        }
+    }
+}
+</style>

+ 332 - 0
pages/customer/components/TerminalDialog.vue

@@ -0,0 +1,332 @@
+<template>
+    <cwg-popup :title="t('Shop.Index.Transaction')" :visible="props.visible" :showFooter="false"
+        @update:visible="$emit('update:visible', $event)">
+        <view class="card-list">
+            <view class="card" @click="handleWebClick">
+                <view class="card-icon">
+                    <svg width="48" height="48" viewBox="0 0 48 48" class="muiltr-l39xog">
+                        <rect width="48" height="48" rx="8" fill="#141D22"></rect>
+                        <path
+                            d="M24.3183 13.6533C26.025 13.6533 27.4116 12.2667 27.4116 10.56C27.4116 8.85334 26.025 7.46667 24.3183 7.46667C22.6116 7.46667 21.225 8.85334 21.225 10.56C21.225 12.2667 22.6116 13.6533 24.3183 13.6533Z"
+                            fill="white"></path>
+                        <path
+                            d="M24.3174 31.5951C27.3254 31.5951 29.768 29.1524 29.768 26.1444C29.768 23.1364 27.3254 20.6937 24.3174 20.6937C21.3094 20.6937 18.8667 23.1364 18.8667 26.1444C18.8667 29.1524 21.3094 31.5951 24.3174 31.5951Z"
+                            fill="white"></path>
+                        <path
+                            d="M28.8627 12.4052C28.8627 12.4052 28.7774 12.3732 28.724 12.3625C28.0094 14.1012 26.3027 15.3279 24.308 15.3279C22.3134 15.3279 20.6067 14.1012 19.892 12.3625C19.8494 12.3732 19.8067 12.3945 19.7534 12.4052C18.26 12.9065 17.3 14.3572 17.3 15.9252V20.3092C17.4494 20.5012 17.588 20.7039 17.7587 20.8745L18.868 21.9839C19.4227 21.2479 20.1267 20.6292 20.9267 20.1705V18.9759C20.9267 18.2825 21.4814 17.7279 22.1747 17.7279H26.4094C27.1027 17.7279 27.6574 18.2825 27.6574 18.9759V20.1065C28.532 20.5865 29.2787 21.2585 29.8654 22.0479L30.8254 21.0879C30.996 20.9172 31.1454 20.7145 31.284 20.5225V15.9145C31.284 14.3465 30.324 12.8959 28.8307 12.3945L28.8627 12.4052Z"
+                            fill="white"></path>
+                        <path
+                            d="M13.245 32.4272C12.3916 30.9445 10.5036 30.4325 9.02095 31.2859C7.53828 32.1392 7.02628 34.0272 7.87962 35.5099C8.73295 36.9925 10.621 37.5045 12.1036 36.6512C13.5863 35.7979 14.0983 33.9099 13.245 32.4272Z"
+                            fill="white"></path>
+                        <path
+                            d="M9.92847 29.2056V29.2376C11.7951 28.9923 13.7151 29.8563 14.7071 31.5843C15.6991 33.3123 15.4858 35.403 14.3338 36.8856C14.3338 36.8856 14.3445 36.8963 14.3551 36.907C15.5605 38.0163 17.3845 38.1123 18.8031 37.3016L22.5151 35.1683C22.6111 34.9443 22.7071 34.7203 22.7711 34.4856L23.1765 32.971C22.2591 32.8536 21.3738 32.555 20.5738 32.0856L19.3258 32.8003C18.8458 33.0776 18.2378 32.907 17.9711 32.4376L15.6138 28.331C15.3365 27.851 15.5071 27.243 15.9765 26.9763L17.1818 26.283C17.1605 25.291 17.3738 24.299 17.7685 23.3923L16.4458 23.0403C16.2111 22.9763 15.9658 22.955 15.7311 22.923L11.8271 25.163C10.4085 25.9736 9.57647 27.6056 9.92847 29.2056Z"
+                            fill="white"></path>
+                        <path
+                            d="M35.3692 32.4272C36.2226 30.9445 38.1106 30.4325 39.5932 31.2859C41.0759 32.1392 41.5879 34.0272 40.7346 35.5099C39.8812 36.9925 37.9932 37.5045 36.5106 36.6512C35.0279 35.7979 34.5159 33.9099 35.3692 32.4272Z"
+                            fill="white"></path>
+                        <path
+                            d="M38.6959 29.2058V29.2378C36.8292 28.9925 34.9092 29.8565 33.9172 31.5845C32.9252 33.3125 33.1385 35.4031 34.2905 36.8858C34.2905 36.8858 34.2799 36.8965 34.2692 36.9071C33.0639 38.0165 31.2399 38.1125 29.8212 37.3018L26.1092 35.1685C26.0132 34.9445 25.9172 34.7205 25.8532 34.4858L25.4479 32.9711C26.3652 32.8538 27.2505 32.5551 28.0505 32.0858L28.9252 32.5871C29.6079 32.9818 30.4825 32.7471 30.8772 32.0645L32.8079 28.7045C33.2025 28.0218 32.9679 27.1471 32.2852 26.7525L31.4532 26.2725C31.4745 25.2805 31.2612 24.2885 30.8665 23.3818L32.1892 23.0298C32.4239 22.9658 32.6692 22.9445 32.9039 22.9125L36.8079 25.1525C38.2265 25.9631 39.0585 27.5951 38.7065 29.1951L38.6959 29.2058Z"
+                            fill="white"></path>
+                    </svg>
+                </view>
+                <view class="card-content">
+                    <text class="card-title">{{ webTitle }}</text>
+                    <text class="card-desc">{{ t('Downloadpage.item40') }}</text>
+                </view>
+                <view class="card-arrow">
+                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
+                        stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
+                        class="muiltr-isq1pf">
+                        <path d="M5 12l14 0"></path>
+                        <path d="M13 18l6 -6"></path>
+                        <path d="M13 6l6 6"></path>
+                    </svg>
+                </view>
+            </view>
+            <view class="card" @click="handleDownloadClick">
+                <view class="card-icon">
+                    <svg width="48" height="48" viewBox="0 0 48 48" class="muiltr-l39xog">
+                        <rect width="48" height="48" rx="8" fill="#141D22"></rect>
+                        <path
+                            d="M24.3183 13.6533C26.025 13.6533 27.4116 12.2667 27.4116 10.56C27.4116 8.85334 26.025 7.46667 24.3183 7.46667C22.6116 7.46667 21.225 8.85334 21.225 10.56C21.225 12.2667 22.6116 13.6533 24.3183 13.6533Z"
+                            fill="white"></path>
+                        <path
+                            d="M24.3174 31.5951C27.3254 31.5951 29.768 29.1524 29.768 26.1444C29.768 23.1364 27.3254 20.6937 24.3174 20.6937C21.3094 20.6937 18.8667 23.1364 18.8667 26.1444C18.8667 29.1524 21.3094 31.5951 24.3174 31.5951Z"
+                            fill="white"></path>
+                        <path
+                            d="M28.8627 12.4052C28.8627 12.4052 28.7774 12.3732 28.724 12.3625C28.0094 14.1012 26.3027 15.3279 24.308 15.3279C22.3134 15.3279 20.6067 14.1012 19.892 12.3625C19.8494 12.3732 19.8067 12.3945 19.7534 12.4052C18.26 12.9065 17.3 14.3572 17.3 15.9252V20.3092C17.4494 20.5012 17.588 20.7039 17.7587 20.8745L18.868 21.9839C19.4227 21.2479 20.1267 20.6292 20.9267 20.1705V18.9759C20.9267 18.2825 21.4814 17.7279 22.1747 17.7279H26.4094C27.1027 17.7279 27.6574 18.2825 27.6574 18.9759V20.1065C28.532 20.5865 29.2787 21.2585 29.8654 22.0479L30.8254 21.0879C30.996 20.9172 31.1454 20.7145 31.284 20.5225V15.9145C31.284 14.3465 30.324 12.8959 28.8307 12.3945L28.8627 12.4052Z"
+                            fill="white"></path>
+                        <path
+                            d="M13.245 32.4272C12.3916 30.9445 10.5036 30.4325 9.02095 31.2859C7.53828 32.1392 7.02628 34.0272 7.87962 35.5099C8.73295 36.9925 10.621 37.5045 12.1036 36.6512C13.5863 35.7979 14.0983 33.9099 13.245 32.4272Z"
+                            fill="white"></path>
+                        <path
+                            d="M9.92847 29.2056V29.2376C11.7951 28.9923 13.7151 29.8563 14.7071 31.5843C15.6991 33.3123 15.4858 35.403 14.3338 36.8856C14.3338 36.8856 14.3445 36.8963 14.3551 36.907C15.5605 38.0163 17.3845 38.1123 18.8031 37.3016L22.5151 35.1683C22.6111 34.9443 22.7071 34.7203 22.7711 34.4856L23.1765 32.971C22.2591 32.8536 21.3738 32.555 20.5738 32.0856L19.3258 32.8003C18.8458 33.0776 18.2378 32.907 17.9711 32.4376L15.6138 28.331C15.3365 27.851 15.5071 27.243 15.9765 26.9763L17.1818 26.283C17.1605 25.291 17.3738 24.299 17.7685 23.3923L16.4458 23.0403C16.2111 22.9763 15.9658 22.955 15.7311 22.923L11.8271 25.163C10.4085 25.9736 9.57647 27.6056 9.92847 29.2056Z"
+                            fill="white"></path>
+                        <path
+                            d="M35.3692 32.4272C36.2226 30.9445 38.1106 30.4325 39.5932 31.2859C41.0759 32.1392 41.5879 34.0272 40.7346 35.5099C39.8812 36.9925 37.9932 37.5045 36.5106 36.6512C35.0279 35.7979 34.5159 33.9099 35.3692 32.4272Z"
+                            fill="white"></path>
+                        <path
+                            d="M38.6959 29.2058V29.2378C36.8292 28.9925 34.9092 29.8565 33.9172 31.5845C32.9252 33.3125 33.1385 35.4031 34.2905 36.8858C34.2905 36.8858 34.2799 36.8965 34.2692 36.9071C33.0639 38.0165 31.2399 38.1125 29.8212 37.3018L26.1092 35.1685C26.0132 34.9445 25.9172 34.7205 25.8532 34.4858L25.4479 32.9711C26.3652 32.8538 27.2505 32.5551 28.0505 32.0858L28.9252 32.5871C29.6079 32.9818 30.4825 32.7471 30.8772 32.0645L32.8079 28.7045C33.2025 28.0218 32.9679 27.1471 32.2852 26.7525L31.4532 26.2725C31.4745 25.2805 31.2612 24.2885 30.8665 23.3818L32.1892 23.0298C32.4239 22.9658 32.6692 22.9445 32.9039 22.9125L36.8079 25.1525C38.2265 25.9631 39.0585 27.5951 38.7065 29.1951L38.6959 29.2058Z"
+                            fill="white"></path>
+                    </svg>
+                </view>
+                <view class="card-content">
+                    <text class="card-title">{{ downloadItem.name }}</text>
+                    <text class="card-desc">{{ downloadItem.description }}</text>
+                </view>
+                <view class="card-arrow">
+                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
+                        stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+                        <path d="M5 12l14 0"></path>
+                        <path d="M13 18l6 -6"></path>
+                        <path d="M13 6l6 6"></path>
+                    </svg>
+                </view>
+            </view>
+        </view>
+    </cwg-popup>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { TerminalMap } from '../composables/TerminalMap'
+import config from '@/config';
+const { t, locale } = useI18n()
+const props = defineProps({
+    visible: { type: Boolean, default: false },
+    mtType: { type: String, default: 'MT4', validator: val => ['MT4', 'MT5'].includes(val) }
+})
+const emit = defineEmits(['update:visible'])
+
+// ---------- 平台相关 ----------
+const platform = ref('')
+const baseUrl = ref('')
+const domain = ref('')
+
+// 获取当前运行平台
+const getPlatform = () => {
+    // #ifdef APP-PLUS
+    const sys = uni.getSystemInfoSync()
+    return sys.platform === 'android' ? 'android' : 'ios'
+    // #endif
+    // #ifdef H5
+    const ua = navigator.userAgent.toLowerCase()
+    if (ua.includes('windows')) return 'windows'
+    if (ua.includes('mac')) return 'mac'
+    if (ua.includes('android')) return 'android'
+    if (ua.includes('iphone') || ua.includes('ipad')) return 'ios'
+    return 'windows'
+    // #endif
+}
+
+// 初始化环境变量(域名、基础URL)
+const initEnv = () => {
+    baseUrl.value = config.Host80
+    domain.value = config.ho
+}
+
+// 替换 URL 中的占位符
+const resolveUrl = (urlTemplate) => {
+    if (!urlTemplate) return ''
+    let url = urlTemplate
+    if (url.includes('{myLink}')) {
+        url = url.replace(/{myLink}/g, baseUrl.value)
+    }
+    if (url.includes('{domain}')) {
+        url = url.replace(/{domain}/g, domain.value)
+    }
+    return url
+}
+
+// 获取当前 MT 版本的数据
+const mtData = computed(() => TerminalMap[props.mtType] || {})
+
+// Web 端标题(根据版本显示不同标题)
+const webTitle = computed(() => {
+    return props.mtType === 'MT4' ? t('Downloadpage.item38') : t('Downloadpage.item39')
+})
+
+// 根据当前 MT 版本和平台,获取对应的下载端信息
+const downloadItem = computed(() => {
+    const data = mtData.value
+    if (!data) return null
+
+    let item = null
+    if (platform.value === 'windows' || platform.value === 'mac') {
+        const list = data.desktop?.[platform.value] || []
+        item = list[0]
+    } else if (platform.value === 'android' || platform.value === 'ios') {
+        const list = data.mobile?.[platform.value] || []
+        item = list[0]
+    }
+
+    if (!item) return null
+
+    // 构造显示名称和描述(国际化)
+    let name = ''
+    let description = ''
+    if (item.name) {
+        name = item.name
+        description = item.descriptionKey ? t(item.descriptionKey) : (item.description || '')
+    } else if (item.nameKey) {
+        name = t(item.nameKey)
+        description = item.descriptionKey ? t(item.descriptionKey) : ''
+    }
+
+    // 图标路径处理
+    let icon = item.icon || ''
+    if (platform.value === 'android' && !icon) icon = 'android-os-3-72.png'
+    if (platform.value === 'ios' && !icon) icon = 'apple-os-3-72.png'
+    if (platform.value === 'windows' && !icon) icon = 'windows-os-1-48.png'
+    if (platform.value === 'mac' && !icon) icon = 'apple-os-1-48.png'
+
+    return {
+        url: resolveUrl(item.url),
+        filename: item.filename,
+        name,
+        description,
+        icon
+    }
+})
+
+// 获取 Web 端链接(根据当前 MT 版本和语言)
+const webUrl = computed(() => {
+    const data = mtData.value
+    if (!data || !data.web) return ''
+    let url = data.web.url
+    // 替换动态变量
+    url = resolveUrl(url)
+    // 替换语言占位符({lang})
+    url = url.replace(/{lang}/g, locale.value)
+    return url
+})
+
+// 处理 Web 端点击
+const handleWebClick = () => {
+    if (!webUrl.value) {
+        uni.showToast({ title: t('Downloadpage.invalidLink') || '链接无效', icon: 'none' })
+        return
+    }
+    // #ifdef APP-PLUS
+    plus.runtime.openURL(webUrl.value, (err) => {
+        uni.showToast({ title: t('Downloadpage.openFailed') || '打开失败,请重试', icon: 'none' })
+    })
+    // #endif
+    // #ifdef H5
+    window.location.href = webUrl.value
+    // #endif
+}
+
+// 处理下载端点击
+const handleDownloadClick = () => {
+    if (!downloadItem.value || !downloadItem.value.url) {
+        uni.showToast({ title: t('Downloadpage.unsupported') || '暂不支持当前平台下载', icon: 'none' })
+        return
+    }
+
+    const url = downloadItem.value.url
+    // #ifdef APP-PLUS
+    plus.runtime.openURL(url, (err) => {
+        uni.showToast({ title: t('Downloadpage.openFailed') || '打开失败,请重试', icon: 'none' })
+    })
+    // #endif
+    // #ifdef H5
+    if (url.match(/\.(exe|dmg|pkg|apk|zip)$/i)) {
+        const a = document.createElement('a')
+        a.href = url
+        a.download = downloadItem.value.filename || ''
+        document.body.appendChild(a)
+        a.click()
+        document.body.removeChild(a)
+    } else {
+        window.open(url, '_blank')
+    }
+    // #endif
+}
+
+// 初始化
+onMounted(() => {
+    platform.value = getPlatform()
+    initEnv()
+})
+</script>
+
+<style scoped lang="scss">
+@import "@/uni.scss";
+
+@media (min-width: 768px) {
+    :deep(.cwg-dialog) {
+        background-color: var(--color-white);
+        border-radius: px2rpx(8);
+        width: px2rpx(600) !important;
+    }
+}
+
+.card-list {
+    display: flex;
+    flex-direction: column;
+    gap: px2rpx(12);
+}
+
+.card {
+    display: flex;
+    align-items: center;
+    background-color: rgba(108, 133, 149, 0.08);
+    border-radius: px2rpx(12);
+    padding: px2rpx(14) px2rpx(12);
+    border: 1px solid rgba(108, 133, 149, 0);
+    transition: background-color 0.2s;
+
+    &:hover {
+        border: 1px solid rgba(108, 133, 149, 0.2);
+    }
+}
+
+.card-icon {
+    width: px2rpx(54);
+    height: px2rpx(54);
+    background-color: #141D22;
+    border-radius: px2rpx(12);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-right: px2rpx(12);
+    flex-shrink: 0;
+
+    .icon-image {
+        width: px2rpx(32);
+        height: px2rpx(32);
+    }
+}
+
+.card-content {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+}
+
+.card-title {
+    font-size: px2rpx(14);
+    font-weight: 600;
+    line-height: 1.4;
+    color: #141d22;
+}
+
+.card-desc {
+    font-size: px2rpx(14);
+    color: #A0B0C0;
+    margin-top: 8rpx;
+}
+
+.card-arrow {
+    width: px2rpx(24);
+    height: px2rpx(24);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-left: 16rpx;
+    flex-shrink: 0;
+    color: #141d22;
+}
+</style>

+ 182 - 0
pages/customer/components/TerminalInfoDialog.vue

@@ -0,0 +1,182 @@
+<template>
+    <cwg-popup :title="title" v-model:visible="props.visible" :showFooter="false"
+        @update:visible="$emit('update:visible', $event)">
+        <view class="account-detail-content">
+            <!-- 账户编号独立显示(如果需要,也可以作为 fieldList 中的一项) -->
+            <view v-if="accountNumber" class="account-number-row">
+                <text class="label">{{ accountLabel }}</text>
+                <text class="value">{{ accountNumber }}</text>
+            </view>
+
+            <!-- 动态字段列表 -->
+            <view v-for="(field, index) in fieldList" :key="index" class="field-row">
+
+                <cwg-label-line-value :label="field.label" :value="getFieldValue(field.key)">
+                    <template #operation v-if="field.copyable">
+                        <view class="copy-btn" @click="copyValue(getFieldValue(field.key))">
+                            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
+                                fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
+                                stroke-linejoin="round">
+                                <path
+                                    d="M7 7m0 2.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667z" />
+                                <path
+                                    d="M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1" />
+                            </svg>
+                        </view>
+                    </template>
+                </cwg-label-line-value>
+                <!-- <text class="label">{{ field.label }}</text>
+                <view class="value-wrapper">
+                    <text class="value">{{ getFieldValue(field.key) || '--' }}</text>
+                    <view v-if="field.copyable" class="copy-btn" @click="copyValue(getFieldValue(field.key))">
+                        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
+                            stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+                            <path
+                                d="M7 7m0 2.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667z" />
+                            <path
+                                d="M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1" />
+                        </svg>
+                    </view>
+                </view> -->
+            </view>
+        </view>
+    </cwg-popup>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+
+const props = defineProps({
+    // 是否显示弹窗
+    visible: {
+        type: Boolean,
+        default: false
+    },
+    // 弹窗标题
+    title: {
+        type: String,
+        default: '账户详情'
+    },
+    // 账户编号(若单独展示)
+    accountNumber: {
+        type: String,
+        default: ''
+    },
+    // 账户编号标签
+    accountLabel: {
+        type: String,
+        default: '账户:'
+    },
+    // 表单数据对象
+    form: {
+        type: Object,
+        default: () => ({})
+    },
+    // 字段配置列表,每项包含:
+    // - label: 字段显示名称
+    // - key: 在 form 中对应的键名
+    // - copyable: 是否显示复制按钮,默认 false
+    fieldList: {
+        type: Array,
+        default: () => []
+    }
+})
+
+const emit = defineEmits(['update:visible'])
+
+// 获取字段值
+const getFieldValue = (key) => {
+    return props.form?.[key] ?? ''
+}
+
+// 复制文本到剪贴板
+const copyValue = (text) => {
+    if (!text) {
+        uni.showToast({ title: '无内容可复制', icon: 'none' })
+        return
+    }
+    uni.setClipboardData({
+        data: String(text),
+        success: () => {
+            uni.showToast({ title: '复制成功', icon: 'success' })
+        },
+        fail: () => {
+            uni.showToast({ title: '复制失败', icon: 'none' })
+        }
+    })
+}
+</script>
+
+<style scoped lang="scss">
+@import "@/uni.scss";
+@media (min-width: 768px) {
+    :deep(.cwg-dialog) {
+        background-color: var(--color-white);
+        border-radius: px2rpx(8);
+        width: px2rpx(500) !important;
+    }
+}
+
+.account-number-row,
+.field-row {
+    display: flex;
+    align-items: center;
+    padding: px2rpx(10) 0;
+    width: 100%;
+    font-size: px2rpx(14);
+
+    &:last-child {
+        border-bottom: none;
+    }
+
+    .label {
+        min-width: px2rpx(30);
+        color: #666;
+        font-weight: normal;
+        flex-shrink: 0;
+    }
+
+    .value-wrapper {
+        flex: 1;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+    }
+
+    .value {
+        color: #333;
+        flex: 1;
+    }
+
+    .copy-btn {
+        width: px2rpx(20);
+        height: px2rpx(20);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin-left: px2rpx(12);
+        cursor: pointer;
+        color: #999;
+        transition: color 0.2s;
+
+        &:active {
+            color: #007aff;
+        }
+
+        svg {
+            width: px2rpx(20);
+            height: px2rpx(20);
+        }
+    }
+}
+
+// 可复制行样式(仅用于视觉区分)
+.copyable-row {
+    .value-wrapper {
+        .value {
+            // 可复制字段的值留出右侧空间
+            margin-right: px2rpx(8);
+        }
+    }
+}
+</style>

+ 184 - 0
pages/customer/components/TerminalNickNameDialog.vue

@@ -0,0 +1,184 @@
+<template>
+    <cwg-popup :title="'账户昵称'" :visible="props.visible" :showFooter="false"
+        @update:visible="$emit('update:visible', $event)">
+        <view class="popup-content">
+            <text class="account-number">{{ accountLabel }} {{ account.login }}</text>
+            <text class="account-hint">{{ hint }}</text>
+
+            <view class="form-item">
+                <view class="input-label">账户昵称</view>
+                <input class="input-field" v-model="nickName" :maxlength="36" :placeholder="placeholder"
+                    @input="onInput" />
+                <text class="input-hint">{{ constraint }}</text>
+            </view>
+            <view class="save-btn">
+                <view class="btn primary" @click="save" :disabled="!isValid || !nickName.trim()" v-t="'Btn.Save'" />
+            </view>
+        </view>
+    </cwg-popup>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue'
+import { customApi } from '@/service/custom';
+import { useI18n } from 'vue-i18n'
+const { t, locale } = useI18n()
+const props = defineProps({
+    visible: { type: Boolean, default: false },
+    // 账户编号
+    account: { type: Object, default: {} },
+    // 标题
+    title: { type: String, default: '账户昵称' },
+    // 账户标签前缀
+    accountLabel: { type: String, default: '账户: #' },
+    // 提示文字
+    hint: { type: String, default: '为账户定制名称,以便快速查找。' },
+    // 输入框占位符
+    placeholder: { type: String, default: '为账户定制名称,以便快速查找。' },
+    // 特殊字符限制说明
+    constraint: { type: String, default: '昵称不可包含特殊字符:< > " \' & ? ^ * # @' }
+})
+const emit = defineEmits(['update:visible', 'save'])
+
+const nickName = ref(props.account.nickName)
+
+// 特殊字符正则
+const specialCharsRegex = /[<>"\'&?^*#@]/
+
+// 校验昵称是否合法
+const isValid = computed(() => {
+    if (!nickName.value) return false
+    return !specialCharsRegex.test(nickName.value)
+})
+
+// 输入时实时校验(可选,可去掉)
+const onInput = (e) => {
+    // 实时过滤非法字符(也可以只是校验)
+}
+// 保存昵称
+const save = async () => {
+    if (!isValid.value) {
+        uni.showToast({
+            title: '昵称包含非法字符,请重新输入',
+            icon: 'none'
+        })
+        return
+    }
+    const nickname = nickName.value.trim()
+    if (!nickname) {
+        uni.showToast({
+            title: '昵称不能为空',
+            icon: 'none'
+        })
+        return
+    }
+    const res = await customApi.updateNick({ nickName: nickname, login: props.account.login })
+    if (res.code == 200) {
+        emit('update:visible', false)
+        emit('save', nickname)
+    }
+}
+</script>
+
+<style scoped lang="scss">
+@import "@/uni.scss";
+
+@media (min-width: 768px) {
+    :deep(.cwg-dialog) {
+        background-color: var(--color-white);
+        border-radius: px2rpx(8);
+        width: px2rpx(480) !important;
+    }
+}
+
+.popup-content {
+    padding: px2rpx(16);
+}
+
+.account-number {
+    display: block;
+    font-size: px2rpx(14);
+    color: #141d22;
+    margin-bottom: px2rpx(40);
+}
+
+.account-hint {
+    display: block;
+    font-size: px2rpx(13);
+    color: #141d22;
+    margin-bottom: px2rpx(40);
+}
+
+.form-item {
+    margin-bottom: px2rpx(20);
+}
+
+.input-label {
+    font-size: px2rpx(12);
+    color: #141d22;
+    margin-bottom: px2rpx(4);
+}
+
+.input-field {
+    width: 100%;
+    height: px2rpx(40);
+    border: 1px solid #ddd;
+    border-radius: px2rpx(6);
+    padding: 0 px2rpx(12);
+    font-size: px2rpx(14);
+    box-sizing: border-box;
+}
+
+.input-hint {
+    display: block;
+    font-size: px2rpx(11);
+    color: #999;
+    margin-top: px2rpx(6);
+    line-height: 1.4;
+}
+
+.save-btn {
+    width: 100%;
+    height: px2rpx(40);
+    color: #fff;
+    border-radius: px2rpx(8);
+    font-size: px2rpx(16);
+    font-weight: 500;
+    display: flex;
+    justify-content: flex-end;
+
+    border: none;
+
+
+    .btn {
+        background: transparent;
+        border: 1px solid rgba(108, 133, 149, 0);
+        border-radius: px2rpx(8);
+        padding: px2rpx(8) px2rpx(20);
+        font-size: px2rpx(14);
+        color: #2e3a47;
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        gap: px2rpx(8);
+        cursor: pointer;
+        transition: all 0.2s;
+        height: px2rpx(40);
+        box-sizing: border-box;
+        background-color: rgba(108, 133, 149, 0.08);
+
+        &.primary {
+            background-color: var(--color-navy-700);
+            color: #fff;
+
+            svg {
+                stroke: #fff;
+            }
+
+            &:hover {
+                background-color: var(--color-navy-600);
+            }
+        }
+    }
+}
+</style>

+ 1 - 1
pages/customer/components/TransactionDialogs.vue

@@ -1,5 +1,5 @@
 <template>
-    <cwg-popup :title="t('Tips.TransactionRecord')" v-model:visible="props.visible" :showFooter="false"
+    <cwg-popup :title="t('Tips.TransactionRecord')" :visible="props.visible" :showFooter="false"
         @update:visible="$emit('update:visible', $event)">
         <scroll-view scroll-y class="account-list" :style="{ maxHeight: '40vh' }">
             <view v-if="loading" class="loading-state">

+ 116 - 0
pages/customer/composables/TerminalMap.ts

@@ -0,0 +1,116 @@
+export const TerminalMap = {
+    "MT4": {
+        "desktop": {
+            "windows": [
+                {
+                    "nameKey": "Downloadpage.item4",
+                    "descriptionKey": "Downloadpage.item5",
+                    "url": "{myLink}/mt/cwgmarketssvgltd4setup.exe",
+                    "filename": "cwgmarketssvgltd4setup.exe",
+                    "icon": "windows-os-1-48.png"
+                },
+                {
+                    "nameKey": "Downloadpage.item4-1",
+                    "descriptionKey": "Downloadpage.item5",
+                    "url": "{myLink}/mt/mt4.zip",
+                    "filename": "mt4.zip",
+                    "icon": "windows-os-1-48.png"
+                }
+            ],
+            "mac": [
+                {
+                    "nameKey": "Downloadpage.item6",
+                    "descriptionKey": "Downloadpage.item5",
+                    "url": "{myLink}/mt/MetaTrader4.pkg",
+                    "filename": "MetaTrader4.pkg",
+                    "icon": "apple-os-1-48.png"
+                }
+            ]
+        },
+        "web": {
+            "url": "https://www.{domain}.com/{lang}/mt4/web",
+            "descriptionKey": "Downloadpage.item40"
+        },
+        "mobile": {
+            "android": [
+                {
+                    "name": "Google Play",
+                    "descriptionKey": "Downloadpage.item9",
+                    "url": "https://www.metatrader4.com/en/download#download-block-android?server=CWGMarketsSVGLtd-Demo,CWGMarketsSVGLtd-Live",
+                    "qrText": "https://www.metatrader4.com/en/download#download-block-android?server=CWGMarketsSVGLtd-Demo,CWGMarketsSVGLtd-Live"
+                },
+                {
+                    "name": "MetaTrader .Apk",
+                    "descriptionKey": "Downloadpage.item9",
+                    "url": "https://secure.{domain}.com/metatrader/metatrader4.apk",
+                    "qrText": "https://secure.{domain}.com/metatrader/metatrader4.apk"
+                }
+            ],
+            "ios": [
+                {
+                    "name": "App Store",
+                    "descriptionKey": "Downloadpage.item10",
+                    "url": "https://apps.apple.com/us/app/metatrader-4/id496212596?server=CWGMarketsSVGLtd-Demo,CWGMarketsSVGLtd-Live",
+                    "qrText": "https://apps.apple.com/us/app/metatrader-4/id496212596?server=CWGMarketsSVGLtd-Demo,CWGMarketsSVGLtd-Live"
+                }
+            ]
+        }
+    },
+    "MT5": {
+        "desktop": {
+            "windows": [
+                {
+                    "nameKey": "Downloadpage.item4",
+                    "descriptionKey": "Downloadpage.item5",
+                    "url": "{myLink}/mt/cwgmarketssvg5setup.exe",
+                    "filename": "cwgmarketssvg5setup.exe",
+                    "icon": "windows-os-1-48.png"
+                },
+                {
+                    "nameKey": "Downloadpage.item4-1",
+                    "descriptionKey": "Downloadpage.item5",
+                    "url": "{myLink}/mt/mt5.zip",
+                    "filename": "mt5.zip",
+                    "icon": "windows-os-1-48.png"
+                }
+            ],
+            "mac": [
+                {
+                    "nameKey": "Downloadpage.item6",
+                    "descriptionKey": "Downloadpage.item5",
+                    "url": "{myLink}/mt/MetaTrader5.pkg",
+                    "filename": "MetaTrader5.dmg",
+                    "icon": "apple-os-1-48.png"
+                }
+            ]
+        },
+        "web": {
+            "url": "https://www.{domain}.com/{lang}/mt5/web",
+            "descriptionKey": "Downloadpage.item40"
+        },
+        "mobile": {
+            "android": [
+                {
+                    "name": "Google Play",
+                    "descriptionKey": "Downloadpage.item14",
+                    "url": "https://download.metatrader.com/cdn/mobile/mt5/android?server=CWGMarketsSVG-Demo,CWGMarketsSVG-Live",
+                    "qrText": "https://download.metatrader.com/cdn/mobile/mt5/android?server=CWGMarketsSVG-Demo,CWGMarketsSVG-Live"
+                },
+                {
+                    "name": "MetaTrader .Apk",
+                    "descriptionKey": "Downloadpage.item14",
+                    "url": "{myLink}/mt/metatrader5.apk",
+                    "qrText": "{myLink}/mt/metatrader5.apk"
+                }
+            ],
+            "ios": [
+                {
+                    "name": "App Store",
+                    "descriptionKey": "Downloadpage.item15",
+                    "url": "https://download.metatrader.com/cdn/mobile/mt5/ios?server=CWGMarketsSVG-Demo,CWGMarketsSVG-Live",
+                    "qrText": "https://download.metatrader.com/cdn/mobile/mt5/ios?server=CWGMarketsSVG-Demo,CWGMarketsSVG-Live"
+                }
+            ]
+        }
+    }
+}

+ 0 - 1379
pages/customer/create-account copy.vue

@@ -1,1379 +0,0 @@
-<template>
-    <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
-        <uni-card class="create-content" :margin="0" :spacing="0">
-            <view class="content-title" v-t="'Custom.NewAccount.Title'"></view>
-            <view class="tit">
-                <text class="iconfont icon-caret-right"></text>
-                <text>{{ t('Custom.NewAccount.Title1') }}</text>
-            </view>
-            <view class="des">
-                <text>{{ t('Custom.NewAccount.Des1') }}</text>
-            </view>
-            <cwg-tabs :cativeIndex="cativeIndex" :tabs="tabs" class="tabs-class" />
-
-        </uni-card>
-        <view id="custom_newAccount" :class="{ 'u-loading': pictLoading }">
-            <view class="main-content" v-if="showPage">
-                <!-- 账户列表 -->
-                <view class="box" v-if="
-                    showLogin.indexOf('6') === -1 ||
-                    showLogin.indexOf('2') === -1 ||
-                    showLogin.indexOf('7') === -1 ||
-                    (showLogin.indexOf('8') === -1 && isTimeShow)
-                ">
-
-
-                    <!-- 极速账户 -->
-                    <!-- <view class="b-card" v-if="showLogin.indexOf('6') === -1">
-                        <view class="btn-tag-star" v-if="false">
-                            <text class="iconfont icon-star-on"></text>
-                        </view>
-                        <view class="card-top">
-                            <view class="header" style="width: 66.66667%;">
-                                <view class="tit">
-                                    <text>{{ t('AccountType.SpeedAccount') }}</text>
-                                </view>
-                                <view class="des">
-                                    <text>{{ t('Custom.NewAccount.DesLogin1') }}</text>
-                                </view>
-                                <view class="btn-bottom">
-                                    <text class="btn-open" @click="isOpenClose(6, null)">
-                                        <text>{{ t('Custom.NewAccount.Btn') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                    <text class="btn-try" @click="isOpenClose(6, 6)">
-                                        <text>{{ t('Custom.NewAccount.BtnDome') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                </view>
-                            </view>
-                            <view class="descending" style="width: 33.33333%;">
-                                <view><text>{{ t('Custom.NewAccount.DesLogin11') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin12') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin13') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin14') }}</text></view>
-                            </view>
-                        </view>
-                        <view class="card-bottom" v-if="isOpenAccount == 6">
-                            <uv-form :model="params" :rules="rules" ref="formRef" label-position="top">
-                                <uv-form-item prop="platform" :label="t('Custom.NewAccount.Platform')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.platform" :columns="platformColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handlePlatformConfirm">
-                                        <view class="picker-value">{{ params.platform || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="currency" :label="t('Custom.NewAccount.Currency')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.currency" :columns="currencyColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handleCurrencyConfirm">
-                                        <view class="picker-value">{{ params.currency || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="password" :label="t('Custom.NewAccount.Password')"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.password" :password="true"
-                                        :placeholder="t('Custom.NewAccount.Password')"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="leverage" :label="t('Custom.NewAccount.Lever')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.leverage" :columns="leverageColumns"
-                                        :placeholder="t('placeholder.choose')" :disabled="hidden"
-                                        @confirm="handleLeverageConfirm">
-                                        <view class="picker-value">{{ params.leverage || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">{{ t('signup.form.rules.1st') }}</view>
-                                        <view :class="{ fit: rule2 }">{{ t('signup.form.rules.2nd') }}</view>
-                                        <view :class="{ fit: rule4 }">{{ t('signup.form.rules.4rd') }}</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item prop="balance" :label="t('Custom.NewAccount.Balance')" v-if="dome"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.balance" type="number"
-                                        :placeholder="t('Custom.NewAccount.BalancePlaceholder')"
-                                        @blur="handleBalanceChange"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" v-if="dome" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">0 - 100000</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item :borderBottom="false">
-                                    <uv-button type="primary" class="s-btn" @click="newAccount(6, dome ? 1 : null)">
-                                        {{ t('Btn.OpenAccount') }}
-                                    </uv-button>
-                                </uv-form-item>
-
-                                <uv-form-item :borderBottom="false" v-if="!dome">
-                                    <view style="margin: 20px 0; font-size: 14px; line-height: 1.7;">
-                                        <text>{{ t('news_add_field.OpenAccount.Des4') }}</text>
-                                        <text class="pdfLink" @click="openLink('leveragemargin')">
-                                            {{ t('news_add_field.OpenAccount.Des5') }}
-                                        </text>
-                                    </view>
-                                </uv-form-item>
-                            </uv-form>
-                        </view>
-                    </view> -->
-
-                    <!-- 经典账户 -->
-                    <!-- <view class="b-card" v-if="showLogin.indexOf('1') === -1">
-                        <view class="btn-tag-star" v-if="false">
-                            <text class="iconfont icon-star-on"></text>
-                        </view>
-                        <view class="card-top">
-                            <view class="header" style="width: 66.66667%;">
-                                <view class="tit">
-                                    <text>{{ t('AccountType.ClassicAccount') }}</text>
-                                </view>
-                                <view class="des">
-                                    <text>{{ t('Custom.NewAccount.DesLogin2') }}</text>
-                                </view>
-                                <view class="btn-bottom">
-                                    <text class="btn-open" @click="isOpenClose(1, null)">
-                                        <text>{{ t('Custom.NewAccount.Btn') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                    <text class="btn-try" @click="isOpenClose(1, 1)">
-                                        <text>{{ t('Custom.NewAccount.BtnDome') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                </view>
-                            </view>
-                            <view class="descending" style="width: 33.33333%;">
-                                <view><text>{{ t('Custom.NewAccount.DesLogin21') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin22') }}</text></view>
-                                <view v-if="['cn', 'zhHant'].indexOf(language) === -1">
-                                    <text>{{ t('Custom.NewAccount.DesLogin23') }}</text>
-                                </view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin24') }}</text></view>
-                            </view>
-                        </view>
-                        <view class="card-bottom" v-if="isOpenAccount == 1">
-                            <uv-form :model="params" :rules="rules" ref="formRef" label-position="top">
-                                <uv-form-item prop="platform" :label="t('Custom.NewAccount.Platform')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.platform" :columns="platformColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handlePlatformConfirm">
-                                        <view class="picker-value">{{ params.platform || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="currency" :label="t('Custom.NewAccount.Currency')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.currency" :columns="currencyColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handleCurrencyConfirm">
-                                        <view class="picker-value">{{ params.currency || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="password" :label="t('Custom.NewAccount.Password')"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.password" :password="true"
-                                        :placeholder="t('Custom.NewAccount.Password')"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="leverage" :label="t('Custom.NewAccount.Lever')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.leverage" :columns="leverageColumns"
-                                        :placeholder="t('placeholder.choose')" :disabled="true"
-                                        @confirm="handleLeverageConfirm">
-                                        <view class="picker-value">{{ params.leverage || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">{{ t('signup.form.rules.1st') }}</view>
-                                        <view :class="{ fit: rule2 }">{{ t('signup.form.rules.2nd') }}</view>
-                                        <view :class="{ fit: rule4 }">{{ t('signup.form.rules.4rd') }}</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item :borderBottom="false">
-                                    <uv-button type="primary" class="s-btn" @click="newAccount(1, dome ? 1 : null)">
-                                        {{ t('Btn.OpenAccount') }}
-                                    </uv-button>
-                                </uv-form-item>
-                            </uv-form>
-                        </view>
-                    </view> -->
-
-                    <!-- 标准账户 -->
-                    <view class="b-card" v-if="showLogin.indexOf('7') === -1">
-                        <view class="btn-tag-star">
-                            <text class="iconfont icon-star-on"></text>
-                        </view>
-                        <view class="card-top">
-                            <view class="header" style="width: 66.66667%;">
-                                <view class="tit">
-                                    <text>{{ t('AccountType.StandardAccount') }}</text>
-                                </view>
-                                <view class="des">
-                                    <text>{{ t('Custom.NewAccount.DesLogin5') }}</text>
-                                </view>
-                                <view class="btn-bottom">
-                                    <text class="btn-open" @click="isOpenClose(7, null)">
-                                        <text>{{ t('Custom.NewAccount.Btn') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                    <text class="btn-try" @click="isOpenClose(7, 7)">
-                                        <text>{{ t('Custom.NewAccount.BtnDome') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                </view>
-                            </view>
-                            <view class="descending" style="width: 33.33333%;">
-                                <view><text>{{ t('Custom.NewAccount.DesLogin51') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin52') }}</text></view>
-                                <view v-if="['cn', 'zhHant'].indexOf(language) === -1">
-                                    <text>{{ t('Custom.NewAccount.DesLogin53') }}</text>
-                                </view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin54') }}</text></view>
-                            </view>
-                        </view>
-
-                        <!-- 标准账户表单 -->
-                        <view class="card-bottom" v-if="isOpenAccount == 7">
-                            <uv-form :model="params" :rules="rules" ref="formRef" label-position="top">
-                                <uv-form-item prop="platform" :label="t('Custom.NewAccount.Platform')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.platform" :columns="platformColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handlePlatformConfirm">
-                                        <view class="picker-value">{{ params.platform || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="currency" :label="t('Custom.NewAccount.Currency')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.currency" :columns="currencyColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handleCurrencyConfirm">
-                                        <view class="picker-value">{{ params.currency || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="password" :label="t('Custom.NewAccount.Password')"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.password" :password="true"
-                                        :placeholder="t('Custom.NewAccount.Password')"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="leverage" :label="t('Custom.NewAccount.Lever')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.leverage" :columns="leverageColumns"
-                                        :placeholder="t('placeholder.choose')" :disabled="hidden"
-                                        @confirm="handleLeverageConfirm">
-                                        <view class="picker-value">{{ params.leverage || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">{{ t('signup.form.rules.1st') }}</view>
-                                        <view :class="{ fit: rule2 }">{{ t('signup.form.rules.2nd') }}</view>
-                                        <view :class="{ fit: rule4 }">{{ t('signup.form.rules.4rd') }}</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item prop="balance" :label="t('Custom.NewAccount.Balance')" v-if="dome"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.balance" type="number"
-                                        :placeholder="t('Custom.NewAccount.BalancePlaceholder')"
-                                        @blur="handleBalanceChange"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" v-if="dome" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">0 - 100000</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item :borderBottom="false">
-                                    <uv-button type="primary" class="s-btn" @click="newAccount(7, dome ? 1 : null)">
-                                        {{ t('Btn.OpenAccount') }}
-                                    </uv-button>
-                                </uv-form-item>
-                            </uv-form>
-                        </view>
-                    </view>
-
-                    <!-- 高级账户 -->
-                    <view class="b-card" v-if="showLogin.indexOf('2') === -1">
-                        <view class="btn-tag-star" v-if="false">
-                            <text class="iconfont icon-star-on"></text>
-                        </view>
-                        <view class="card-top">
-                            <view class="header" style="width: 66.66667%;">
-                                <view class="tit">
-                                    <text>{{ t('AccountType.SeniorAccount') }}</text>
-                                </view>
-                                <view class="des">
-                                    <text>{{ t('Custom.NewAccount.DesLogin3') }}</text>
-                                </view>
-                                <view class="btn-bottom">
-                                    <text class="btn-open" @click="isOpenClose(2, null)">
-                                        <text>{{ t('Custom.NewAccount.Btn') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                    <text class="btn-try" @click="isOpenClose(2, 2)">
-                                        <text>{{ t('Custom.NewAccount.BtnDome') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                </view>
-                            </view>
-                            <view class="descending" style="width: 33.33333%;">
-                                <view><text>{{ t('Custom.NewAccount.DesLogin31') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin32') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin33') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin34') }}</text></view>
-                            </view>
-                        </view>
-
-                        <!-- 高级账户表单 -->
-                        <view class="card-bottom" v-if="isOpenAccount == 2">
-                            <uv-form :model="params" :rules="rules" ref="formRef" label-position="top">
-                                <uv-form-item prop="platform" :label="t('Custom.NewAccount.Platform')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.platform" :columns="platformColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handlePlatformConfirm">
-                                        <view class="picker-value">{{ params.platform || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="currency" :label="t('Custom.NewAccount.Currency')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.currency" :columns="currencyColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handleCurrencyConfirm">
-                                        <view class="picker-value">{{ params.currency || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="password" :label="t('Custom.NewAccount.Password')"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.password" :password="true"
-                                        :placeholder="t('Custom.NewAccount.Password')"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="leverage" :label="t('Custom.NewAccount.Lever')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.leverage" :columns="leverageColumns"
-                                        :placeholder="t('placeholder.choose')" :disabled="hidden"
-                                        @confirm="handleLeverageConfirm">
-                                        <view class="picker-value">{{ params.leverage || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">{{ t('signup.form.rules.1st') }}</view>
-                                        <view :class="{ fit: rule2 }">{{ t('signup.form.rules.2nd') }}</view>
-                                        <view :class="{ fit: rule4 }">{{ t('signup.form.rules.4rd') }}</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item prop="balance" :label="t('Custom.NewAccount.Balance')" v-if="dome"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.balance" type="number"
-                                        :placeholder="t('Custom.NewAccount.BalancePlaceholder')"
-                                        @blur="handleBalanceChange"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" v-if="dome" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">0 - 100000</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item :borderBottom="false">
-                                    <uv-button type="primary" class="s-btn" @click="newAccount(2, dome ? 1 : null)">
-                                        {{ t('Btn.OpenAccount') }}
-                                    </uv-button>
-                                </uv-form-item>
-                            </uv-form>
-                        </view>
-                    </view>
-
-                    <!-- 美分账户 -->
-                    <view class="b-card" v-if="showLogin.indexOf('8') === -1 && isTimeShow">
-                        <view class="btn-tag-star" v-if="false">
-                            <text class="iconfont icon-star-on"></text>
-                        </view>
-                        <view class="card-top">
-                            <view class="header" style="width: 66.66667%;">
-                                <view class="tit">
-                                    <text>{{ t('AccountType.CentAccount') }}</text>
-                                </view>
-                                <view class="des">
-                                    <text>{{ t('Custom.NewAccount.DesLogin8') }}</text>
-                                </view>
-                                <view class="btn-bottom">
-                                    <text class="btn-open" @click="isOpenClose(8, null)">
-                                        <text>{{ t('Custom.NewAccount.Btn') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                    <text class="btn-try" @click="isOpenClose(8, 8)">
-                                        <text>{{ t('Custom.NewAccount.BtnDome') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                </view>
-                            </view>
-                            <view class="descending" style="width: 33.33333%;">
-                                <view><text>{{ t('Custom.NewAccount.DesLogin81') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin82') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin84') }}</text></view>
-                            </view>
-                        </view>
-
-                        <!-- 美分账户表单 -->
-                        <view class="card-bottom" v-if="isOpenAccount == 8">
-                            <uv-form :model="params" :rules="rules" ref="formRef" label-position="top">
-                                <uv-form-item prop="platform" :label="t('Custom.NewAccount.Platform')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.platform" :columns="platformColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handlePlatformConfirm">
-                                        <view class="picker-value">{{ params.platform || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="currency" :label="t('Custom.NewAccount.Currency')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.currency" :columns="currencyColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handleCurrencyConfirm">
-                                        <view class="picker-value">{{ params.currency || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="password" :label="t('Custom.NewAccount.Password')"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.password" :password="true"
-                                        :placeholder="t('Custom.NewAccount.Password')"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="leverage" :label="t('Custom.NewAccount.Lever')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.leverage" :columns="leverageColumns"
-                                        :placeholder="t('placeholder.choose')" :disabled="hidden"
-                                        @confirm="handleLeverageConfirm">
-                                        <view class="picker-value">{{ params.leverage || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">{{ t('signup.form.rules.1st') }}</view>
-                                        <view :class="{ fit: rule2 }">{{ t('signup.form.rules.2nd') }}</view>
-                                        <view :class="{ fit: rule4 }">{{ t('signup.form.rules.4rd') }}</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item prop="balance" :label="t('Custom.NewAccount.Balance')" v-if="dome"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.balance" type="number"
-                                        :placeholder="t('Custom.NewAccount.BalancePlaceholder')"
-                                        @blur="handleBalanceChange"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" v-if="dome" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">0 - 100000</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item :borderBottom="false">
-                                    <uv-button type="primary" class="s-btn" @click="newAccount(8, dome ? 1 : null)">
-                                        {{ t('Btn.OpenAccount') }}
-                                    </uv-button>
-                                </uv-form-item>
-
-                                <uv-form-item :borderBottom="false">
-                                    <view style="margin: 20px 0; font-size: 14px; line-height: 1.7;">
-                                        <text>{{ t('news_add_field.OpenAccount.Des4') }}</text>
-                                        <text class="pdfLink" @click="openLink('leveragemargin')">
-                                            {{ t('news_add_field.OpenAccount.Des5') }}
-                                        </text>
-                                    </view>
-                                </uv-form-item>
-                            </uv-form>
-                        </view>
-                    </view>
-                </view>
-
-                <!-- 代理账户 -->
-                <!-- <view class="box" v-if="showLogin.indexOf('3') === -1 && !isAfterJuly28()">
-                    <view class="tit">
-                        <text class="iconfont icon-caret-right"></text>
-                        <text>{{ t('Custom.NewAccount.Title2') }}</text>
-                    </view>
-                    <view class="des">
-                        <text>{{ t('Custom.NewAccount.Des2') }}</text>
-                    </view>
-
-                    <view class="b-card">
-                        <view class="btn-tag-star" v-if="false">
-                            <text class="iconfont icon-star-on"></text>
-                        </view>
-                        <view class="card-top">
-                            <view class="header" style="width: 66.66667%;">
-                                <view class="tit">
-                                    <text>{{ t('AccountType.AgencyAccount') }}</text>
-                                </view>
-                                <view class="des">
-                                    <text>{{ t('Custom.NewAccount.DesLogin4') }}</text>
-                                </view>
-                                <view class="btn-bottom">
-                                    <text class="btn-open" @click="isOpenClose(3, null)">
-                                        <text>{{ t('Custom.NewAccount.Btn') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                </view>
-                            </view>
-                            <view class="descending" style="width: 33.33333%;">
-                                <view><text>{{ t('Custom.NewAccount.DesLogin41') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin42') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin43') }}</text></view>
-                                <view><text>{{ t('Custom.NewAccount.DesLogin44') }}</text></view>
-                            </view>
-                        </view>
-                        <view class="card-bottom" v-if="isOpenAccount == 3">
-                            <uv-form :model="params" :rules="rules" ref="formRef" label-position="top">
-                                <uv-form-item prop="platform" :label="t('Custom.NewAccount.Platform')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.platform" :columns="platformColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handlePlatformConfirm">
-                                        <view class="picker-value">{{ params.platform || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="currency" :label="t('Custom.NewAccount.Currency')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.currency" :columns="currencyColumns"
-                                        :placeholder="t('placeholder.choose')" @confirm="handleCurrencyConfirm">
-                                        <view class="picker-value">{{ params.currency || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="password" :label="t('Custom.NewAccount.Password')"
-                                    :borderBottom="false">
-                                    <uv-input v-model="params.password" :password="true"
-                                        :placeholder="t('Custom.NewAccount.Password')"></uv-input>
-                                </uv-form-item>
-
-                                <uv-form-item prop="leverage" :label="t('Custom.NewAccount.Lever')"
-                                    :borderBottom="false">
-                                    <uv-picker v-model="params.leverage" :columns="leverageColumns"
-                                        :placeholder="t('placeholder.choose')" :disabled="hidden"
-                                        @confirm="handleLeverageConfirm">
-                                        <view class="picker-value">{{ params.leverage || t('placeholder.choose') }}
-                                        </view>
-                                    </uv-picker>
-                                </uv-form-item>
-
-                                <uv-form-item prop="platform" :borderBottom="false">
-                                    <view class="pwd">
-                                        <view :class="{ fit: rule1 }">{{ t('signup.form.rules.1st') }}</view>
-                                        <view :class="{ fit: rule2 }">{{ t('signup.form.rules.2nd') }}</view>
-                                        <view :class="{ fit: rule4 }">{{ t('signup.form.rules.4rd') }}</view>
-                                    </view>
-                                </uv-form-item>
-
-                                <uv-form-item :borderBottom="false">
-                                    <uv-button type="primary" class="s-btn" @click="newAccount(3, null)">
-                                        {{ t('Btn.OpenAccount') }}
-                                    </uv-button>
-                                </uv-form-item>
-                            </uv-form>
-                        </view>
-                    </view>
-                </view> -->
-
-                <!-- 无可用账户提示 -->
-                <view class="box" v-if="
-                    showLogin.indexOf('6') !== -1 &&
-                    showLogin.indexOf('1') !== -1 &&
-                    showLogin.indexOf('2') !== -1 &&
-                    showLogin.indexOf('3') !== -1 &&
-                    showLogin.indexOf('7') !== -1 &&
-                    !(showLogin.indexOf('8') === -1 && isTimeShow)
-                ">
-                    <view style="margin: 20px 0; font-size: 14px; line-height: 1.7;">
-                        <text>{{ t('news_add_field.OpenAccount.Des3') }}</text>
-                    </view>
-                </view>
-
-                <!-- 底部说明 -->
-                <view class="box">
-                    <view style="margin: 20px 0; font-size: 14px; line-height: 1.7;">
-                        <text>{{ t('news_add_field.OpenAccount.Des1') }}</text>
-                        <text class="pdfLink" @click="openPdf('PrivacyPolicy2019_01.pdf')">
-                            {{ t('news_add_field.OpenAccount.Des2') }}
-                        </text>
-                    </view>
-                </view>
-            </view>
-
-            <!-- 提交后的弹出框 -->
-            <uv-popup :show="dialogCheck" mode="center" round="16" @close="closeDia">
-                <view class="dia-content" v-if="dialogVisible">
-                    <view class="icon">
-                        <text class="iconfont icon-success"></text>
-                    </view>
-                    <view class="des1">{{ t('ApplicationDialog.Des1') }}</view>
-                    <view class="des2">{{ t('ApplicationDialog.Des12') }}</view>
-                    <view class="dialog-footer">
-                        <uv-button type="primary" @click="closeDia">
-                            {{ t('Btn.Confirm') }}
-                        </uv-button>
-                        <uv-button @click="closeDia">
-                            {{ t('Btn.Cancel') }}
-                        </uv-button>
-                    </view>
-                </view>
-
-                <view class="dia-content" v-if="!dialogVisible">
-                    <view class="icon">
-                        <text class="iconfont icon-warning"></text>
-                    </view>
-                    <view class="des1">{{ RES }}</view>
-                    <view class="dialog-footer">
-                        <uv-button type="primary" @click="closeDia">
-                            {{ t('Btn.Confirm') }}
-                        </uv-button>
-                        <uv-button @click="closeDia">
-                            {{ t('Btn.Cancel') }}
-                        </uv-button>
-                    </view>
-                </view>
-            </uv-popup>
-
-            <!-- 账户开立上限提示弹框 -->
-            <uv-popup :show="dialogAccountLimit" mode="center" round="16" @close="closeAccountLimitDialog">
-                <view class="account-limit-content">
-                    <view class="icon">
-                        <text class="iconfont icon-warning"></text>
-                    </view>
-                    <view class="title">{{ t('accountLimit.title') }}</view>
-                    <view class="content">
-                        <view class="limit-text">
-                            <view>{{ t('accountLimit.mt4Message') }}</view>
-                            <view>
-                                <view>{{ t('accountLimit.mt4Condition1') }}</view>
-                            </view>
-                            <view>{{ t('accountLimit.mt4Action') }}</view>
-                        </view>
-                    </view>
-                    <view class="dialog-footer">
-                        <uv-button type="primary" class="confirm-btn" @click="closeAccountLimitDialog">
-                            {{ t('accountLimit.button') }}
-                        </uv-button>
-                    </view>
-                </view>
-            </uv-popup>
-        </view>
-
-    </cwg-page-wrapper>
-
-</template>
-
-<script setup>
-import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue';
-import { onLoad } from '@dcloudio/uni-app';
-import QrCode from "@/components/QrCode.vue";
-import { post } from "@/utils/request";
-import { userToken } from "@/composables/config";
-import { customApi } from "@/service/custom";
-import { ucardApi } from "@/api/ucard";
-import useUserStore from "@/stores/use-user-store";
-import useRouter from "@/hooks/useRouter";
-import { useI18n } from "vue-i18n";
-const router = useRouter();
-const { t } = useI18n();
-const userStore = useUserStore();
-// 响应式表单数据
-const cativeIndex = ref(0);
-const tabs = computed(() => ([
-    { id: 1, name: 'Step 1: Select Account' },
-    { id: 2, name: 'Step 2: Add Information' },
-    { id: 3, name: 'Step 3: Success' },
-
-]))
-
-
-// 数据定义
-const pictLoading = ref(false);
-const flag = ref(false);
-const RES = ref('');
-const dialogCheck = ref(false);
-const dialogVisible = ref(false);
-const showData = ref(null);
-const isOpenAccount = ref(0);
-const checked = ref('');
-const optionsLev = ref([]);
-const optionsCur = ref([]);
-const dome = ref(null);
-const showLogin = ref([]);
-const showPage = ref(false);
-const isTimeShow = ref(false);
-const dialogAccountLimit = ref(false);
-const limitPlatform = ref('');
-const hidden = ref(true);
-const ho = ref('');
-const language = ref('');
-
-// 表单引用
-const formRef = ref(null);
-
-// 表单数据
-const params = reactive({
-    password: '',
-    currency: '',
-    leverage: '',
-    platform: '',
-    balance: null
-});
-
-// 计算属性
-const rule1 = computed(() => {
-    if (!params.password) return false;
-    return /^.{8,15}$/.test(params.password);
-});
-
-const rule2 = computed(() => {
-    return /^(?=.*?[a-z])(?=.*?[A-Z]).*$/.test(params.password);
-});
-
-const rule4 = computed(() => {
-    return /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[~!@&%$^*./\\(\\)\\+\\=#_-])[A-Za-z0-9~!@&%$^*./\\(\\)\\+\\=#_-]{8,16}$/.test(
-        params.password
-    );
-});
-
-// 验证规则
-const rules = {
-    password: [
-        {
-            validator: (rule, value, callback) => {
-                if (/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[~!@&%$^*./\\(\\)\\+\\=#_-])[A-Za-z0-9~!@&%$^*./\\(\\)\\+\\=#_-]{8,16}$/.test(value)) {
-                    callback();
-                } else {
-                    callback(new Error(t('vaildate.password.format')));
-                }
-            },
-            trigger: 'blur',
-            required: true
-        }
-    ],
-    platform: [
-        {
-            required: true,
-            message: t('vaildate.select.empty'),
-            trigger: 'change'
-        }
-    ],
-    currency: [
-        {
-            required: true,
-            message: t('vaildate.select.empty'),
-            trigger: 'change'
-        }
-    ],
-    leverage: [
-        {
-            required: true,
-            message: t('vaildate.select.empty'),
-            trigger: 'change'
-        }
-    ],
-    balance: [
-        {
-            validator: (rule, value, callback) => {
-                if (value === null || value === undefined || value === '') {
-                    callback();
-                    return;
-                }
-                const numValue = Number(value);
-                if (isNaN(numValue)) {
-                    callback(new Error(t('vaildate.amount.format')));
-                    return;
-                }
-                if (numValue < 0 || numValue > 100000) {
-                    callback(new Error(t('vaildate.amount.amount') + '0-100000'));
-                    return;
-                }
-                callback();
-            },
-            trigger: ['blur', 'change']
-        }
-    ]
-};
-
-// 平台选项
-const platformColumns = computed(() => {
-    const columns = [];
-    if (showData.value && showData.value['mt4s'] && showData.value['mt4s'].length) {
-        columns.push({ label: 'MT4', value: 'MT4' });
-    }
-    if (showData.value && showData.value['mt5s'] && showData.value['mt5s'].length) {
-        columns.push({ label: 'MT5', value: 'MT5' });
-    }
-    return [columns];
-});
-
-// 货币选项
-const currencyColumns = computed(() => {
-    if (optionsCur.value.length) {
-        return [optionsCur.value.map(item => ({ label: item, value: item }))];
-    }
-    return [[]];
-});
-
-// 杠杆选项
-const leverageColumns = computed(() => {
-    if (optionsLev.value.length) {
-        return [optionsLev.value.map(item => ({ label: String(item), value: item }))];
-    }
-    return [[]];
-});
-
-// 方法
-const closeDia = () => {
-    if (formRef.value) {
-        formRef.value.resetFields();
-    }
-    dialogCheck.value = false;
-    dialogVisible.value = false;
-};
-
-const closeAccountLimitDialog = () => {
-    dialogAccountLimit.value = false;
-    limitPlatform.value = '';
-};
-
-const showAccountLimitDialog = (platform) => {
-    limitPlatform.value = platform;
-    dialogAccountLimit.value = true;
-};
-
-// 获取必要数据
-const getMustData = async (type, isDome) => {
-    const api = isDome ? customApi.AccountApplyDataDome : customApi.AccountApplyData;
-    const res = await api({
-        type: type
-    });
-    if (res.code === 200) {
-        showData.value = res.data;
-    } else {
-        uni.showToast({
-            title: res.msg,
-            icon: 'none'
-        });
-    }
-};
-
-// 获取显示权限
-const getExcludeShowLogin = async () => {
-    pictLoading.value = true;
-    const res = await customApi.excludeShowLogin({});
-    if (res.code === 200) {
-        showLogin.value = res.data?.excludeShowLoginTypes || [];
-        showPage.value = true;
-        pictLoading.value = false;
-    } else {
-        uni.showToast({
-            title: res.msg,
-            icon: 'none'
-        });
-        pictLoading.value = false;
-    }
-};
-
-// 提交开户
-const newAccount = async (type, isDome) => {
-    if (!formRef.value) return;
-
-    try {
-        await formRef.value.validate();
-    } catch (error) {
-        return;
-    }
-
-    if (flag.value) return;
-    flag.value = true;
-
-    const api = isDome ? customApi.AccountApplyAddDome : customApi.AccountApplyAdd;
-    const res = await api({
-        type: type,
-        ...params
-    });
-
-    if (res.code === 200) {
-        if (isDome) {
-            uni.showToast({
-                title: t('Msg.Success'),
-                icon: 'success'
-            });
-        }
-        isOpenAccount.value = 0;
-        dialogCheck.value = true;
-        dialogVisible.value = true;
-        if (formRef.value) {
-            formRef.value.resetFields();
-        }
-        flag.value = false;
-    } else if (res.code === 407) {
-        showAccountLimitDialog(params.platform);
-        flag.value = false;
-    } else {
-        RES.value = res.msg;
-        dialogCheck.value = true;
-        dialogVisible.value = false;
-        flag.value = false;
-    }
-};
-
-// 展开/关闭账户表单
-const isOpenClose = (index, isDome) => {
-    hidden.value = true;
-    if (isOpenAccount.value === index) {
-        isOpenAccount.value = 0;
-        if (formRef.value) {
-            formRef.value.resetFields();
-        }
-        return;
-    } else {
-        isOpenAccount.value = index;
-    }
-    if (formRef.value) {
-        formRef.value.resetFields();
-    }
-    dome.value = isDome;
-    optionsLev.value = [];
-    optionsCur.value = [];
-    getMustData(index, isDome);
-};
-
-// 选择平台
-const checkPlatform = (pla) => {
-    if (pla === 'mt5s') {
-        hidden.value = false;
-    } else {
-        hidden.value = true;
-    }
-    params.currency = '';
-    params.leverage = '';
-    optionsLev.value = [];
-    optionsCur.value = [];
-    const Cur = [];
-    showData.value[pla].forEach((item) => {
-        Cur.push(item.currency);
-    });
-    Cur.forEach((item) => {
-        if (!optionsCur.value.includes(item)) {
-            optionsCur.value.push(item);
-        }
-    });
-};
-
-// 平台确认
-const handlePlatformConfirm = (value) => {
-    params.platform = value.value[0];
-    const pla = params.platform === 'MT4' ? 'mt4s' : 'mt5s';
-    checkPlatform(pla);
-};
-
-// 货币确认
-const handleCurrencyConfirm = (value) => {
-    params.currency = value.value[0];
-    const pla = params.platform === 'MT4' ? 'mt4s' : 'mt5s';
-    checkCurrency(pla, params.currency);
-};
-
-// 杠杆确认
-const handleLeverageConfirm = (value) => {
-    params.leverage = value.value[0];
-};
-
-// 选择货币
-const checkCurrency = (pla, cur) => {
-    params.leverage = '';
-    optionsLev.value = [];
-    const platform = pla === 'MT4' ? 'mt4s' : 'mt5s';
-    const list = [];
-    showData.value[platform].forEach((item) => {
-        if (item.currency === cur) {
-            list.push(item.leverage);
-        }
-    });
-    params.leverage = list.reduce((a, b) => Math.max(a, b));
-    optionsLev.value = list;
-};
-
-// 时间判断
-const isAfterJuly28 = () => {
-    // 实现日期判断逻辑
-    return false;
-};
-
-const isTimeShowType8 = () => {
-    const endTime1 = '2024/9/25 00:00:00';
-    const timezone = 2;
-    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();
-    if (now > end) {
-        isTimeShow.value = true;
-    }
-};
-
-// 余额变化验证
-const handleBalanceChange = () => {
-    if (formRef.value) {
-        formRef.value.validateField('balance');
-    }
-};
-
-// 打开链接
-const openLink = (path) => {
-    uni.navigateTo({
-        url: `/pages/webview/index?url=https://www.${ho.value}.com/${path}`
-    });
-};
-
-// 打开PDF
-const openPdf = (path) => {
-    uni.navigateTo({
-        url: `/pages/webview/index?url=/pdf/${path}`
-    });
-};
-
-// 监听balance变化
-watch(() => params.balance, (newVal, oldVal) => {
-    if (newVal !== oldVal && newVal !== null && newVal !== undefined) {
-        nextTick(() => {
-            if (formRef.value) {
-                formRef.value.validateField('balance');
-            }
-        });
-    }
-});
-
-// 生命周期
-onLoad(() => {
-    const host = window?.location?.host || '';
-    ho.value = host.split('.')[1] || '';
-
-    // 获取语言
-    const locale = uni.getLocale();
-    language.value = locale;
-
-    getExcludeShowLogin();
-    isTimeShowType8();
-});
-
-onMounted(() => {
-    // 挂载后的操作
-});
-</script>
-
-<style lang="scss" scoped>
-.tit {
-    font-size: 16px;
-    font-weight: bold;
-    margin: 10px 0;
-
-    .iconfont {
-        margin-right: 6px;
-    }
-}
-
-.des {
-    font-size: 14px;
-    font-weight: bold;
-    line-height: 1.5;
-    margin-bottom: 20px;
-}
-
-#custom_newAccount {
-    width: 100%;
-    height: 100%;
-    overflow: hidden;
-    overflow-y: auto;
-
-    &.u-loading {
-        position: relative;
-
-        &::after {
-            content: '';
-            position: absolute;
-            top: 0;
-            left: 0;
-            right: 0;
-            bottom: 0;
-            background: rgba(255, 255, 255, 0.5);
-            z-index: 99;
-        }
-    }
-
-    .main-content {
-        text-align: left;
-        padding: 0 20px;
-
-        .box {
-            padding: 10px 0;
-            text-align: left;
-            background-color: #ffffff;
-            border-radius: 2px;
-            margin: 20px 0;
-
-            .pdfLink {
-                color: #42b983;
-                font-weight: bold;
-                text-decoration: underline;
-                margin-left: 4px;
-            }
-
-
-            .b-card {
-                border: 2px solid #e5e5e5;
-                margin-bottom: 20px;
-                border-radius: 2px;
-                position: relative;
-                overflow: hidden;
-
-                .btn-tag-star {
-                    position: absolute;
-                    top: 4px;
-                    left: -15px;
-                    background-color: #f56c6c;
-                    color: #ffffff;
-                    transform: rotate(-45deg);
-                    width: 60px;
-                    text-align: center;
-                    z-index: 9;
-                    padding: 1px 0;
-                }
-
-                .card-top {
-                    display: flex;
-                    border-bottom: 1px solid #e5e5e5;
-
-                    .tit {
-                        font-weight: bold;
-                    }
-
-                    .btn-bottom {
-                        font-size: 14px;
-
-                        .btn-open,
-                        .btn-try {
-                            display: inline-block;
-                            width: 150px;
-                            text-align: center;
-                            border: 1px solid #e5e5e5;
-                            padding: 8px 0;
-                            margin: 5px;
-                            color: #ffffff;
-
-                            .iconfont {
-                                margin-right: 3px;
-                                font-size: 12px;
-                            }
-                        }
-
-                        .btn-open {
-                            margin-right: 5px;
-                            background-color: #f56c6c;
-                            color: #ffffff;
-                        }
-
-                        .btn-try {
-                            background-color: #909399;
-                        }
-                    }
-
-                    .header {
-                        padding: 15px 25px;
-                    }
-
-                    .descending {
-                        padding: 10px;
-                        box-sizing: border-box;
-                        height: 100%;
-                        width: 100%;
-                        font-size: 14px;
-                        line-height: 1.2;
-                        background-color: #f5f5f5;
-                        display: flex;
-                        flex-wrap: wrap;
-                        align-items: center;
-
-                        view {
-                            width: 100%;
-                            box-sizing: border-box;
-                            text-align: center;
-                        }
-                    }
-                }
-
-                .card-bottom {
-                    padding: 20px;
-                    border-bottom: 1px solid #d5d5d5;
-
-                    .check {
-                        padding: 6px 8px;
-                        margin: 15px 15px 15px 0;
-                        border: 1px solid #d5d5d5;
-                    }
-
-                    .pwd {
-                        text-align: left;
-                        padding-left: 20px;
-                        margin-top: 15px;
-
-                        view {
-                            list-style-type: disc;
-                            line-height: 1.2;
-                            margin: 4px 0;
-                            color: #c0c4cc;
-
-                            &.fit {
-                                color: #67c23a;
-                            }
-                        }
-                    }
-
-                    .picker-value {
-                        padding: 10px 0;
-                        border-bottom: 1px solid #e5e5e5;
-                    }
-
-                    .s-btn {
-                        width: 100%;
-                        margin-top: 20px;
-                    }
-                }
-
-                &:hover {
-                    border-color: #f56c6c;
-                }
-            }
-        }
-    }
-
-    .dia-content {
-        text-align: center;
-        padding: 30px 20px;
-
-        .icon {
-            .iconfont {
-                font-size: 80px;
-
-                &.icon-warning {
-                    color: #f56c6c;
-                }
-
-                &.icon-success {
-                    color: #67c23a;
-                }
-            }
-        }
-
-        .des1 {
-            font-weight: bold;
-            font-size: 16px;
-            margin: 30px 0 15px;
-        }
-
-        .des2 {
-            font-size: 14px;
-            margin-bottom: 30px;
-        }
-
-        .dialog-footer {
-            display: flex;
-            justify-content: center;
-            gap: 20px;
-            margin-top: 20px;
-
-            .uv-button {
-                min-width: 100px;
-            }
-        }
-    }
-
-    .account-limit-content {
-        text-align: center;
-        padding: 30px 20px;
-
-        .icon {
-            margin-bottom: 20px;
-
-            .iconfont {
-                font-size: 60px;
-                color: #f56c6c;
-            }
-        }
-
-        .title {
-            font-size: 18px;
-            font-weight: bold;
-            color: #333;
-            margin-bottom: 20px;
-        }
-
-        .content {
-            text-align: center;
-            margin: 20px 0 30px;
-
-            .limit-text {
-                view {
-                    font-size: 14px;
-                    line-height: 1.6;
-                    color: #666;
-                    margin-bottom: 15px;
-                    text-align: center;
-                }
-            }
-        }
-
-        .dialog-footer {
-            text-align: center;
-            margin-top: 20px;
-
-            .confirm-btn {
-                min-width: 120px;
-                background-color: #f56c6c;
-                border: none;
-                color: #fff;
-            }
-        }
-    }
-}
-</style>

+ 169 - 181
pages/customer/create-account.vue

@@ -1,97 +1,24 @@
 <template>
-    <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
-        <uni-card class="create-content" :margin="0" :spacing="0">
-            <view class="content-title" v-t="'Custom.NewAccount.Title'"></view>
-            <view class="tit">
-                <text class="iconfont icon-caret-right"></text>
-                <text>{{ t('Custom.NewAccount.Title1') }}</text>
-            </view>
-            <view class="des">
-                <text>{{ t('Custom.NewAccount.Des1') }}</text>
-            </view>
-            <cwg-tabs :cativeIndex="cativeIndex" @tabClick="handleTabClick" :tabs="tabs" class="tabs-class" />
-            <template v-if="cativeIndex === 0">
-                <view class="box" v-if="
-                    showLogin.indexOf('6') === -1 ||
-                    showLogin.indexOf('2') === -1 ||
-                    showLogin.indexOf('7') === -1 ||
-                    (showLogin.indexOf('8') === -1 && isTimeShow)">
-                    <uni-row class="form-row uni-row1">
-                        <uni-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8" v-for="(item, index) in accountList"
-                            :key="index">
-                            <view class="b-card" v-if="item.showCondition() && !item.isHide">
-                                <view class="btn-tag-star">
-                                    <image :src="item.img" class="avatar" mode="widthFix" />
-                                </view>
-                                <view class="header">
-                                    <view class="tit">
-                                        <text v-t="item.typeKey"></text>
-                                    </view>
-                                    <view class="des">
-                                        <text v-t="item.desKey">{{ t('Custom.NewAccount.DesLogin5') }}</text>
-                                    </view>
+    <cwg-page-wrapper class="create-page " :isHeaderFixed="true">
+        <view class="create-card">
 
-                                </view>
-                                <view class="descending">
-                                    <view v-for="value in item.features" :key="value.key" class="feature">
-                                        <view class="icon-success"><cwg-icon name="crm-check" :size="16"
-                                                color="#10b981" />
-                                        </view>
-                                        <text v-t="value.key" />
-                                    </view>
-                                </view>
-                                <view class="btn-bottom">
-                                    <text class="btn-open" @click="isOpenClose(item.id, null)">
-                                        <text>{{ t('Custom.NewAccount.Btn') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                    <text class="btn-try" @click="isOpenClose(item.id, item.id)">
-                                        <text>{{ t('Custom.NewAccount.BtnDome') }}</text>
-                                        <text class="iconfont icon-arrow-right"></text>
-                                    </text>
-                                </view>
-                            </view>
-                        </uni-col>
-                    </uni-row>
-                </view>
-                <!-- 无可用账户提示 -->
-                <view class="box-text" v-if="
-                    showLogin.indexOf('6') !== -1 &&
-                    showLogin.indexOf('1') !== -1 &&
-                    showLogin.indexOf('2') !== -1 &&
-                    showLogin.indexOf('3') !== -1 &&
-                    showLogin.indexOf('7') !== -1 &&
-                    !(showLogin.indexOf('8') === -1 && isTimeShow)
-                ">
-                    <view class="text">
-                        <text>{{ t('news_add_field.OpenAccount.Des3') }}</text>
-                    </view>
-                </view>
+            <view class="card-bottom user-form crm-form">
+                <view class="tabs-class">
+                    <cwg-tabs v-model:cativeIndex="cativeIndex" :tabs="tabs" />
 
-                <!-- 底部说明 -->
-                <view class="box-text">
-                    <view class="text">
-                        <text>{{ t('news_add_field.OpenAccount.Des1') }}</text>
-                        <text class="pdfLink" @click="openPdf('PrivacyPolicy2019_01.pdf')">
-                            {{ t('news_add_field.OpenAccount.Des2') }}
-                        </text>
-                    </view>
                 </view>
-            </template>
-
-            <view class="card-bottom user-form crm-form " v-if="cativeIndex == 1">
                 <uni-forms ref="baseForm" :model="formData" labelWidth="200" label-position="top" :rules="rules"
                     class="base-info-form">
-                    <uni-row class="demo-uni-row uni-row1">
+                    <uni-row class="demo-uni-row uni-row1 uni-row2">
                         <!-- MT4/MT5 -->
-                        <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                        <uni-col :xs="24">
                             <uni-forms-item :label="t('Custom.NewAccount.Platform')">
                                 <cwg-combox :clearable="false" v-model:value="formData.platform"
                                     :options="platformColumns" :placeholder="t('placeholder.choose')" />
                             </uni-forms-item>
                         </uni-col>
                         <!-- 货币类型 -->
-                        <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                        <uni-col :xs="24">
                             <uni-forms-item :label="t('Custom.NewAccount.Currency')">
                                 <cwg-combox :clearable="false" v-model:value="formData.currency"
                                     :options="currencyColumns" :placeholder="t('placeholder.choose')" />
@@ -99,20 +26,28 @@
                         </uni-col>
 
                         <!-- 杠杆 -->
-                        <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                        <uni-col :xs="24">
                             <uni-forms-item :label="t('Custom.NewAccount.Lever')">
                                 <cwg-combox :clearable="false" :disabled="hidden" v-model:value="formData.leverage"
                                     :options="leverageColumns" :placeholder="t('placeholder.choose')" />
                             </uni-forms-item>
                         </uni-col>
+
+                        <!-- 账户余额 -->
+                        <uni-col :xs="24" v-if="dome">
+                            <uni-forms-item :label="t('Custom.NewAccount.Balance')">
+                                <uni-easyinput type="digit" :clearable="false" v-model="formData.balance"
+                                    :placeholder="t('Custom.NewAccount.BalancePlaceholder')" />
+                            </uni-forms-item>
+                        </uni-col>
                         <!-- 交易密码 -->
-                        <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                        <uni-col :xs="24">
                             <uni-forms-item :label="t('Custom.NewAccount.Password')">
                                 <uni-easyinput :clearable="false" v-model="formData.password"
                                     :placeholder="t('Custom.NewAccount.Password')" />
                             </uni-forms-item>
                         </uni-col>
-                        <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                        <uni-col :xs="24">
                             <view class="notice-list">
                                 <view v-for="(item, index) in noticeItems" :key="index"
                                     :class="['notice-item', item.valid ? 'isOK' : '']">
@@ -120,21 +55,40 @@
                                 </view>
                             </view>
                         </uni-col>
-                        <!-- 账户余额 -->
-                        <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="dome">
-                            <uni-forms-item :label="t('Custom.NewAccount.Balance')">
-                                <uni-easyinput type="digit" :clearable="false" v-model="formData.balance"
-                                    :placeholder="t('Custom.NewAccount.BalancePlaceholder')" />
-                            </uni-forms-item>
-                        </uni-col>
 
-                        <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+
+                        <uni-col :xs="24">
                             <view class="btn btn-confirm" @click="newAccount">{{ t('Btn.Application') }}</view>
                         </uni-col>
                     </uni-row>
                 </uni-forms>
             </view>
-        </uni-card>
+
+            <view class="card-content">
+                <text class="account-name" v-t="currentAccount?.name"></text>
+
+                <!-- 点差信息 -->
+                <view class="info-row">
+                    <view class="info-label">最低入金</view>
+                    <view class="info-value">{{ currentAccount?.minDeposit || '--' }}</view>
+                </view>
+                <!-- 点差信息 -->
+                <view class="info-row">
+                    <view class="info-label">最小点差</view>
+                    <view class="info-value">{{ currentAccount?.minSpread || '--' }}</view>
+                </view>
+
+                <!-- 杠杆信息 -->
+                <view class="info-row">
+                    <view class="info-label">最大杠杆</view>
+                    <view class="info-value">{{ currentAccount?.maxLeverage || '--' }}</view>
+                </view>
+                <view class="info-row">
+                    <view class="info-value"><a href="/static/pdf/PrivacyPolicy2019_01.pdf" target="_blank"
+                            v-t="'news_add_field.OpenAccount.Des2'"></a></view>
+                </view>
+            </view>
+        </view>
         <!-- 提交后的弹出框 -->
         <uni-popup :show="dialogCheck" mode="center" round="16" @close="closeDia">
             <view class="dia-content" v-if="dialogVisible">
@@ -199,111 +153,72 @@
 <script setup>
 import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue';
 import { onLoad } from '@dcloudio/uni-app';
-import { userToken } from "@/composables/config";
 import { customApi } from "@/service/custom";
-import { ucardApi } from "@/api/ucard";
 import useUserStore from "@/stores/use-user-store";
 import useRouter from "@/hooks/useRouter";
 import { useI18n } from "vue-i18n";
-import { image } from 'uview-plus/libs/function/test';
 const router = useRouter();
 const { t, locale } = useI18n();
 const userStore = useUserStore();
-// 响应式表单数据
-const cativeIndex = ref(0);
-const handleTabClick = (index) => {
-    if(index == 0){
-        cativeIndex.value = 0
-    }
-};
-const tabs = computed(() => ([
-    { id: 1, name: 'Step 1: Select Account' },
-    { id: 2, name: 'Step 2: Add Information' },
-    { id: 3, name: 'Step 3: Success' },
-]))
-
-const accountList = computed(() => ([
-    {
-        id: 6,
-        type: 'SpeedAccount',
-        typeKey: 'AccountType.SpeedAccount',
-        showCondition: () => showLogin.value.indexOf('6') === -1,
-        desKey: 'Custom.NewAccount.DesLogin1',
-        features: [
-            { key: 'Custom.NewAccount.DesLogin11', condition: true },
-            { key: 'Custom.NewAccount.DesLogin12', condition: true },
-            { key: 'Custom.NewAccount.DesLogin13', condition: true },
-            { key: 'Custom.NewAccount.DesLogin14', condition: true }
-        ],
-        hasStar: false,
-        isHide: true
-    },
-    {
-        id: 1,
-        type: 'ClassicAccount',
-        typeKey: 'AccountType.ClassicAccount',
-        showCondition: () => showLogin.value.indexOf('1') === -1,
-        desKey: 'Custom.NewAccount.DesLogin2',
-        features: [
-            { key: 'Custom.NewAccount.DesLogin21', condition: true },
-            { key: 'Custom.NewAccount.DesLogin22', condition: true },
-            {
-                key: 'Custom.NewAccount.DesLogin23',
-                condition: ['cn', 'zhHant'].indexOf(locale.value) === -1
-            },
-            { key: 'Custom.NewAccount.DesLogin24', condition: true }
-        ],
-        hasStar: false,
-        isHide: true
-    },
+// 定义账户数据类型
+const standardAccounts = ref([
     {
         id: 7,
         type: 'StandardAccount',
-        typeKey: 'AccountType.StandardAccount',
+        name: 'AccountType.StandardAccount',
         showCondition: () => showLogin.value.indexOf('7') === -1,
-        desKey: 'Custom.NewAccount.DesLogin5',
-        features: [
-            { key: 'Custom.NewAccount.DesLogin51', condition: true },
-            { key: 'Custom.NewAccount.DesLogin52', condition: true },
-            {
-                key: 'Custom.NewAccount.DesLogin53',
-                condition: ['cn', 'zhHant'].indexOf(locale.value) === -1
-            },
-            { key: 'Custom.NewAccount.DesLogin54', condition: true }
-        ],
-        hasStar: true,
-        img: '/static/images/info/bank-information-1.webp',
+        description: 'Custom.NewAccount.DesLogin5',
+        minDeposit: '50 USD',
+        minSpread: '0.01',
+        maxLeverage: '1:1000',
+        icon: '/static/images/info/bank-information-1.webp',
     },
     {
         id: 2,
         type: 'SeniorAccount',
-        typeKey: 'AccountType.SeniorAccount',
+        name: 'AccountType.SeniorAccount',
         showCondition: () => showLogin.value.indexOf('2') === -1,
-        desKey: 'Custom.NewAccount.DesLogin3',
+        description: 'Custom.NewAccount.DesLogin3',
         features: [
             { key: 'Custom.NewAccount.DesLogin31', condition: true },
             { key: 'Custom.NewAccount.DesLogin32', condition: true },
             { key: 'Custom.NewAccount.DesLogin33', condition: true },
             { key: 'Custom.NewAccount.DesLogin34', condition: true }
         ],
-        hasStar: false,
-        img: '/static/images/info/bank-information-2.webp',
+        minDeposit: '200 USD',
+        minSpread: '0.01',
+        maxLeverage: '1:2000',
+        icon: '/static/images/info/bank-information-2.webp',
     },
     {
         id: 8,
         type: 'CentAccount',
-        typeKey: 'AccountType.CentAccount',
+        name: 'AccountType.CentAccount',
         showCondition: () => showLogin.value.indexOf('8') === -1 && isTimeShow.value,
-        desKey: 'Custom.NewAccount.DesLogin8',
+        description: 'Custom.NewAccount.DesLogin8',
         features: [
             { key: 'Custom.NewAccount.DesLogin81', condition: true },
             { key: 'Custom.NewAccount.DesLogin82', condition: true },
             { key: 'Custom.NewAccount.DesLogin84', condition: true }
         ],
-        hasStar: false,
-        img: '/static/images/info/bank-information-3.webp',
+        minDeposit: '10 USD',
+        minSpread: '0.01',
+        maxLeverage: '1:1000',
+        icon: '/static/images/info/bank-information-3.webp',
     }
-]));
+])
+const cativeIndex = ref(0)
+const tabs = computed(() => ([
+    { id: 'real', name: '真实' },
+    { id: 'demo', name: '模拟' }
+]))
+
+const currentAccount = computed(() => {
+    // 从账户列表中查找匹配的账户
+    const matched = standardAccounts.value.find(account => account.id == isOpenAccount.value);
+    // 如果未找到,返回一个默认空对象或 null,模板中需做判空处理
+    return matched || null;
+});
 
 // 数据定义
 const pictLoading = ref(false);
@@ -334,7 +249,7 @@ const formData = reactive({
     currency: '',
     leverage: '',
     platform: '',
-    balance: null
+    balance: null,
 });
 
 
@@ -502,7 +417,6 @@ const newAccount = async () => {
 
     if (flag.value) return;
     flag.value = true;
-
     const api = dome.value ? customApi.AccountApplyAddDome : customApi.AccountApplyAdd;
     const res = await api({
         type: isOpenAccount.value,
@@ -516,6 +430,7 @@ const newAccount = async () => {
                 icon: 'success'
             });
         }
+        router.push('/pages/customer/index')
         isOpenAccount.value = 0;
         dialogCheck.value = true;
         dialogVisible.value = true;
@@ -534,15 +449,6 @@ const newAccount = async () => {
     }
 };
 
-// 展开/关闭账户表单
-const isOpenClose = (index, isDome) => {
-    cativeIndex.value = 1
-    isOpenAccount.value = index
-    dome.value = isDome;
-    optionsLev.value = [];
-    optionsCur.value = [];
-    getMustData(index, isDome);
-};
 
 // 选择平台
 const checkPlatform = (pla) => {
@@ -640,13 +546,20 @@ watch(() => formData.balance, (newVal, oldVal) => {
         });
     }
 });
+watch(() => cativeIndex.value, (newVal) => {
+    dome.value = newVal == 1
+});
 
 // 生命周期
-onLoad(() => {
+onLoad((e) => {
+    dome.value = e.server == 'demo'
+    cativeIndex.value = e.server == 'demo' ? 1 : 0
+    isOpenAccount.value = e.id
     const host = window?.location?.host || '';
     ho.value = host.split('.')[1] || '';
 
     getExcludeShowLogin();
+    getMustData(isOpenAccount.value, dome.value);
     isTimeShowType8();
 });
 
@@ -760,10 +673,6 @@ onMounted(() => {
         margin-bottom: px2rpx(10);
     }
 
-    .uni-easyinput__content {
-        border: none !important;
-        background-color: var(--color-zinc-100) !important;
-    }
 }
 
 .btn {
@@ -812,6 +721,85 @@ onMounted(() => {
 }
 
 .card-bottom {
+    max-width: px2rpx(566);
     margin-top: px2rpx(20);
+
+    .tabs-class {
+        margin: 0 px2rpx(10) px2rpx(20) px2rpx(10);
+    }
+}
+
+.create-card {
+    display: flex;
+    gap: px2rpx(30);
+    justify-content: space-between;
+}
+
+@media (max-width: 992px) {
+    .card-bottom {
+        width: 100%;
+        margin-top: px2rpx(20);
+    }
+
+    .create-card {
+        display: flex;
+        gap: px2rpx(30);
+        flex-wrap: wrap;
+    }
+}
+
+.card-content {
+    margin-top: px2rpx(30);
+    padding: px2rpx(16);
+    width: px2rpx(300);
+
+
+    .account-name {
+        display: block;
+        font-size: px2rpx(18);
+        font-weight: 600;
+        color: #1e2a3a;
+        padding-bottom: px2rpx(16);
+        padding-left: px2rpx(20);
+        border-left: 1px solid #f0f2f5;
+    }
+
+    .info-row {
+        padding-left: px2rpx(20);
+        padding-bottom: px2rpx(12);
+        border-left: 1px solid #f0f2f5;
+
+        .info-label {
+            font-size: px2rpx(15);
+            line-height: px2rpx(30);
+            color: #7f8c8d;
+        }
+
+        .info-value {
+            font-size: px2rpx(14);
+            font-weight: 500;
+            color: #1e2a3a;
+        }
+    }
+
+    .link-wrapper {
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        margin-top: px2rpx(8);
+        padding-top: px2rpx(8);
+        border-top: 1rpx solid #f0f2f5;
+
+        .link-text {
+            font-size: px2rpx(14);
+            color: #007aff;
+            margin-right: px2rpx(4);
+        }
+
+        .link-icon {
+            font-size: px2rpx(14);
+            color: #007aff;
+        }
+    }
 }
 </style>

+ 824 - 577
pages/customer/deposit.vue

@@ -1,431 +1,488 @@
 <template>
-    <view class="custom-deposit">
-        <!-- 标题 -->
-        <view class="crm-title-box">
-            <text class="tit">{{ t('Home.page_customer.item2') }}</text>
-        </view>
-
-        <!-- 步骤1:选择账户 -->
-        <view class="box box-step1">
-            <view class="b-card">
-                <view class="card-top">
-                    <text class="tit"><text class="iconfont icon-caret-right"></text>{{ t('Custom.Deposit.Title1')
-                        }}</text>
-                    <picker mode="selector" :range="loginOptions" :range-key="'label'" @change="onAccountChange"
-                        :value="selectedAccountIndex">
-                        <view class="picker-view">{{ selectedAccountLabel || t('placeholder.choose') }}</view>
-                    </picker>
-                </view>
-            </view>
-        </view>
-
-        <!-- 步骤2:支付通道列表(卡片布局) -->
-        <view class="box box-step2" v-if="step2">
-            <view class="b-card">
-                <view class="card-top">
-                    <text class="tit"><text class="iconfont icon-caret-right"></text>{{ t('Custom.Deposit.Title2')
-                        }}</text>
-                    <view v-for="(group, index) in sortedTableData" :key="index">
-                        <view class="channelType" v-if="group.length" v-t="groupTitleMap[group[0].type]" />
-                        <PaymentMethodsList :list="group" @select="isShowStep3" />
-                    </view>
-                    <view v-if="step3" class="reselect-btn">
-                        <button class="s-btn reselect" type="primary" @click="showTable">{{
-                            t('Custom.Deposit.Reselect') }}</button>
+    <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
+        <view class="custom-deposit">
+            <!-- 标题 -->
+            <!-- <view class="crm-title-box">
+                <text class="tit">{{ t('Home.page_customer.item2') }}</text>
+            </view> -->
+
+            <!-- 步骤1:选择账户 -->
+            <view class="box box-step1">
+                <view class="b-card">
+                    <view class="card-top">
+                        <text class="tit"><text class="iconfont icon-caret-right"></text>{{ t('Custom.Deposit.Title1')
+                            }}</text>
+                        <cwg-combox :clearable="false" v-model:value="loginValue" :options="loginComboxOptions"
+                            :placeholder="t('placeholder.choose')" @change="onAccountChange" />
                     </view>
                 </view>
             </view>
-        </view>
-
-        <!-- 步骤3:填写入金信息 -->
-        <view class="box box-step3" v-if="step3">
-            <view class="b-card">
-                <view class="card-top">
-                    <!-- 注意事项(第一步确认) -->
-                    <view v-if="!isStep3">
-                        <view class="step3-attention">
-                            <rich-text class="attention"
-                                :nodes="(locale === 'cn' || locale === 'zhHant') ? introduce.introduce : introduce.enIntroduce"></rich-text>
-                            <view class="btn-bottom">
-                                <text class="btn crm-cursor" @click="isStep3Open()">{{ t('Btn.Confirm') }}</text>
-                            </view>
-                        </view>
-                    </view>
-
-                    <!-- 表单(确认后显示) -->
-                    <form v-if="isStep3">
-                        <!-- 信用卡选择 -->
-                        <view v-if="channelData.confirmCreditCard == 1">
-                            <view class="add-back">
-                                <text>{{ t('PersonalManagement.Label.addCreditCard') }}</text>
-                                <text class="add-btn crm-cursor" @click="openAddBankCard">{{
-                                    t('Custom.Withdraw.addBank1') }}</text>
-                            </view>
-                            <picker mode="selector" :range="ruleForm.bankCredit"
-                                :range-key="(item) => item.bankUname + '-' + item.bankCardNum"
-                                @change="onCreditCardChange" :value="selectedCreditIndex">
-                                <view class="picker-view">{{ selectedCreditLabel || t('placeholder.choose') }}</view>
-                            </picker>
-                        </view>
-
-                        <!-- 银行选择(如有) -->
-                        <view v-if="bankDate.length">
-                            <text class="tit"><text class="iconfont icon-caret-right"></text>{{
-                                t('news_add_field.Label.Title4') }}</text>
-                            <picker mode="selector" :range="bankDate"
-                                :range-key="(item) => (locale === 'cn' || locale === 'zhHant') ? item.name : item.enName"
-                                @change="onBankChange" :value="selectedBankIndex">
-                                <view class="picker-view">{{ selectedBankLabel || t('placeholder.choose') }}</view>
-                            </picker>
-                        </view>
 
-                        <!-- 特别提示(B2BINPAY) -->
-                        <view v-if="bankDate.length && channelData.code == 'B2BINPAY'">
-                            <text class="tit"><text class="iconfont iconi"></text>{{ t('Custom.Deposit.Des') }}</text>
+            <!-- 步骤2:支付通道列表(卡片布局) -->
+            <view class="box box-step2" v-if="step2">
+                <view class="b-card">
+                    <view class="card-top">
+                        <text class="tit"><text class="iconfont icon-caret-right"></text>{{ t('Custom.Deposit.Title2')
+                            }}</text>
+                        <view v-for="(group, index) in sortedTableData" :key="index">
+                            <view class="channelType" v-if="group.length" v-t="groupTitleMap[group[0].type]" />
+                            <PaymentMethodsList :list="group" @select="isShowStep3" />
                         </view>
-
-                        <!-- 电汇信息展示 -->
-                        <view
-                            v-if="['UNION_PAY_TELEGRAPHIC', 'UNION_PAY_TELEGRAPHIC_SPECIAL', 'UNION_PAY_TELEGRAPHIC_TWO'].includes(channelData.code)">
-                            <text class="tit"><text class="iconfont icon-caret-right"></text>{{
-                                t('Custom.Deposit.Title5') }}</text>
-                            <view class="wire-transfer-account">
-                                <view class="row"><text class="label SpecialColor">{{ t('Custom.Deposit.bankUname')
-                                        }}</text><text class="content SpecialColor">{{ WireTransferAccount.bankUname ||
-                                            '--' }}</text></view>
-                                <view class="row"><text class="label">{{ t('Custom.Deposit.bankName') }}</text><text
-                                        class="content">{{ WireTransferAccount.bankName || '--' }}</text></view>
-                                <view class="row"><text class="label SpecialColor">{{ t('Custom.Deposit.bankCardNum')
-                                        }}</text><text class="content SpecialColor">{{ WireTransferAccount.bankCardNum
-                                            || '--' }}</text></view>
-                                <view class="row"><text class="label">{{ t('Custom.Deposit.bankAddr') }}</text><text
-                                        class="content">{{ WireTransferAccount.bankAddr || '--' }}</text></view>
-                                <view class="row"><text class="label SpecialColor">{{ t('Custom.Deposit.swiftCode')
-                                        }}</text><text class="content SpecialColor">{{ WireTransferAccount.swiftCode ||
-                                            '--' }}</text></view>
-                                <view class="row"><text class="label">{{ t('Custom.Deposit.bankCode') }}</text><text
-                                        class="content">{{ WireTransferAccount.bankCode || '--' }}</text></view>
-                                <view class="row"><text class="label SpecialColor">{{ t('Custom.Recording.Note')
-                                        }}</text><text class="content SpecialColor">{{ WireTransferAccount.bankMsg ||
-                                            '--' }}</text></view>
-                            </view>
+                        <view v-if="step3" class="reselect-btn">
+                            <button class="s-btn reselect" type="primary" @click="showTable">{{
+                                t('Custom.Deposit.Reselect') }}</button>
                         </view>
+                    </view>
+                </view>
+            </view>
 
-                        <!-- 数字货币信息展示 -->
-                        <view v-if="channelData.code && channelData.code.indexOf('DIGITAL_PAY_TYPE_KEY') === 0">
-                            <text class="tit"><text class="iconfont icon-caret-right"></text>{{
-                                t('Custom.Deposit.DigitalAcc') }}</text>
-                            <view class="wire-transfer-account">
-                                <view class="row"><text class="label SpecialColor">{{ t('Custom.Deposit.DigitalName')
-                                        }}</text><text class="content SpecialColor">{{ WireTransferAccount.name + '-' +
-                                            WireTransferAccount.type }}</text></view>
-                                <view class="row"><text class="label">{{ t('Custom.Withdraw.Title6') }}</text><text
-                                        class="content">{{ WireTransferAccount.address || '--' }}</text></view>
-                                <view class="row"><text class="label">QR Code</text>
-                                    <image :src="Host85 + WireTransferAccount.url" mode="aspectFit"
-                                        style="width: 100rpx; height: 100rpx;" />
+            <!-- 步骤3:填写入金信息 -->
+            <view class="box box-step3" v-if="step3">
+                <view class="b-card">
+                    <view class="card-top">
+                        <!-- 注意事项(第一步确认) -->
+                        <view v-if="!isStep3">
+                            <view class="step3-attention">
+                                <rich-text class="attention"
+                                    :nodes="(locale === 'cn' || locale === 'zhHant') ? introduce.introduce : introduce.enIntroduce"></rich-text>
+                                <view class="btn-bottom">
+                                    <text class="btn crm-cursor" @click="isStep3Open()">{{ t('Btn.Confirm') }}</text>
                                 </view>
                             </view>
                         </view>
 
-                        <!-- 表单字段:金额、预估金额、上传凭证、优惠码 -->
-                        <text class="tit"><text class="iconfont icon-caret-right"></text>{{ t('Custom.Deposit.Title3')
-                            }}</text>
-                        <view class="form-row">
-                            <view class="form-item">
-                                <text class="label">{{ t('Custom.Deposit.Title3') + '(' + channelData.currency + ')'
-                                    }}</text>
-                                <input class="input" v-model="params.amount" type="number" @input="onAmountInput" />
-                                <text class="error" v-if="amountError">{{ amountError }}</text>
-                            </view>
-                            <view class="form-item" v-if="channelData.rate">
-                                <text class="label">{{ t('Custom.Deposit.EstimatedAmount') + '(' +
-                                    channelData.transformCurrency + ')' }}</text>
-                                <input class="input" v-model="params.amount1" disabled />
-                                <text class="help-icon" @click="showEstimateHelp">?</text>
-                            </view>
-                            <view class="form-item" v-if="needUploadVoucher">
-                                <text class="label">{{ t('Custom.Deposit.UploadRemittanceVoucher') }}</text>
-                                <button @click="chooseImage">{{ t('upload') }}</button>
-                                <image v-if="imageUrl" :src="imageUrl" mode="aspectFit"
-                                    style="width: 100rpx; height: 100rpx;" />
-                            </view>
-                            <view class="form-item">
-                                <text class="label">{{ t('Custom.Deposit.PromoCode') }}</text>
-                                <input class="input" v-model="params.promoCode" />
-                            </view>
-                        </view>
+                        <!-- 表单(确认后显示) -->
+                        <uni-forms v-if="isStep3" ref="baseForm" :model="params" labelWidth="200" label-position="top"
+                            class="base-info-form">
+                            <uni-row class="demo-uni-row uni-row1">
+                                <!-- 信用卡选择 -->
+                                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8"
+                                    v-if="channelData.confirmCreditCard == 1">
+                                    <view class="add-back">
+                                        <text>{{ t('PersonalManagement.Label.addCreditCard') }}</text>
+                                        <text class="add-btn crm-cursor" @click="openAddBankCard">{{
+                                            t('Custom.Withdraw.addBank1') }}</text>
+                                    </view>
+                                    <uni-forms-item :label="t('PersonalManagement.Label.addCreditCard')">
+                                        <cwg-combox :clearable="false" v-model:value="myId" :options="creditCardOptions"
+                                            :placeholder="t('placeholder.choose')" @change="onCreditCardChange" />
+                                    </uni-forms-item>
+                                </uni-col>
+
+                                <!-- 银行选择(如有) -->
+                                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="bankDate.length">
+                                    <uni-forms-item :label="t('news_add_field.Label.Title4')">
+                                        <cwg-combox :clearable="false" v-model:value="selectedBankIndex"
+                                            :options="bankOptions" :placeholder="t('placeholder.choose')"
+                                            @change="onBankChange" />
+                                    </uni-forms-item>
+                                </uni-col>
+
+                                <!-- 特别提示(B2BINPAY) -->
+                                <uni-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"
+                                    v-if="bankDate.length && channelData.code == 'B2BINPAY'">
+                                    <text class="tit"><text class="iconfont iconi"></text>{{ t('Custom.Deposit.Des')
+                                        }}</text>
+                                </uni-col>
+
+                                <!-- 电汇信息展示 -->
+                                <uni-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"
+                                    v-if="['UNION_PAY_TELEGRAPHIC', 'UNION_PAY_TELEGRAPHIC_SPECIAL', 'UNION_PAY_TELEGRAPHIC_TWO'].includes(channelData.code)">
+                                    <text class="tit"><text class="iconfont icon-caret-right"></text>{{
+                                        t('Custom.Deposit.Title5') }}</text>
+                                    <view class="wire-transfer-account">
+                                        <view class="row"><text class="label SpecialColor">{{
+                                            t('Custom.Deposit.bankUname')
+                                                }}</text><text class="content SpecialColor">{{
+                                                    WireTransferAccount.bankUname
+                                                    ||
+                                                    '--' }}</text></view>
+                                        <view class="row"><text class="label">{{ t('Custom.Deposit.bankName')
+                                                }}</text><text class="content">{{ WireTransferAccount.bankName || '--'
+                                                }}</text></view>
+                                        <view class="row"><text class="label SpecialColor">{{
+                                            t('Custom.Deposit.bankCardNum')
+                                                }}</text><text class="content SpecialColor">{{
+                                                    WireTransferAccount.bankCardNum
+                                                    || '--' }}</text></view>
+                                        <view class="row"><text class="label">{{ t('Custom.Deposit.bankAddr')
+                                                }}</text><text class="content">{{ WireTransferAccount.bankAddr || '--'
+                                                }}</text></view>
+                                        <view class="row"><text class="label SpecialColor">{{
+                                            t('Custom.Deposit.swiftCode')
+                                                }}</text><text class="content SpecialColor">{{
+                                                    WireTransferAccount.swiftCode
+                                                    ||
+                                                    '--' }}</text></view>
+                                        <view class="row"><text class="label">{{ t('Custom.Deposit.bankCode')
+                                                }}</text><text class="content">{{ WireTransferAccount.bankCode || '--'
+                                                }}</text></view>
+                                        <view class="row"><text class="label SpecialColor">{{ t('Custom.Recording.Note')
+                                                }}</text><text class="content SpecialColor">{{
+                                                    WireTransferAccount.bankMsg
+                                                    ||
+                                                    '--' }}</text></view>
+                                    </view>
+                                </uni-col>
+
+                                <!-- 数字货币信息展示 -->
+                                <uni-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"
+                                    v-if="channelData.code && channelData.code.indexOf('DIGITAL_PAY_TYPE_KEY') === 0">
+                                    <text class="tit"><text class="iconfont icon-caret-right"></text>{{
+                                        t('Custom.Deposit.DigitalAcc') }}</text>
+                                    <view class="wire-transfer-account">
+                                        <view class="row"><text class="label SpecialColor">{{
+                                            t('Custom.Deposit.DigitalName')
+                                                }}</text><text class="content SpecialColor">{{ WireTransferAccount.name
+                                                    +
+                                                    '-' +
+                                                    WireTransferAccount.type }}</text></view>
+                                        <view class="row"><text class="label">{{ t('Custom.Withdraw.Title6')
+                                                }}</text><text class="content">{{ WireTransferAccount.address || '--'
+                                                }}</text></view>
+                                        <view class="row"><text class="label">QR Code</text>
+                                            <image :src="Host85 + WireTransferAccount.url" mode="aspectFit"
+                                                style="width: 100rpx; height: 100rpx;" />
+                                        </view>
+                                    </view>
+                                </uni-col>
+
+                                <!-- 表单字段:金额、预估金额、上传凭证、优惠码 -->
+                                <uni-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+                                    <text class="tit"><text class="iconfont icon-caret-right"></text>{{
+                                        t('Custom.Deposit.Title3')
+                                        }}</text>
+                                </uni-col>
+                                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                                    <uni-forms-item
+                                        :label="t('Custom.Deposit.Title3') + '(' + channelData.currency + ')'">
+                                        <uni-easyinput type="number" v-model="params.amount" @input="onAmountInput"
+                                            :placeholder="t('placeholder.input')" />
+                                        <text class="error" v-if="amountError">{{ amountError }}</text>
+                                    </uni-forms-item>
+                                </uni-col>
+                                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="channelData.rate">
+                                    <uni-forms-item>
+                                        <template #label>
+                                            <view class="label-with-icon">
+                                                <text>{{ t('Custom.Deposit.EstimatedAmount') + '(' +
+                                                    channelData.transformCurrency + ')' }}</text>
+                                                <text class="help-icon" @click="showEstimateHelp">?</text>
+                                            </view>
+                                        </template>
+                                        <uni-easyinput v-model="params.amount1" disabled
+                                            :placeholder="t('placeholder.input')" />
+                                    </uni-forms-item>
+                                </uni-col>
+                                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="needUploadVoucher">
+                                    <uni-forms-item :label="t('Custom.Deposit.UploadRemittanceVoucher')">
+                                        <view class="upload-box">
+                                            <button class="btn-upload" @click="chooseImage">{{ t('upload') }}</button>
+                                            <image v-if="imageUrl" :src="imageUrl" mode="aspectFit"
+                                                class="img-preview" />
+                                        </view>
+                                    </uni-forms-item>
+                                </uni-col>
+                                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                                    <uni-forms-item>
+                                        <template #label>
+                                            <view class="label-with-icon">
+                                                <text v-t="'Custom.Deposit.PromoCode'" />
+                                                <uni-tooltip placement="top" class="tooltip-content">
+                                                    <view class="item">?</view>
+                                                    <template #content>
+                                                        <text v-t="'news_add_field.Des.item3'"></text>
+                                                    </template>
+                                                </uni-tooltip>
+                                            </view>
+                                        </template>
+                                        <uni-easyinput v-model="params.promoCode"
+                                            :placeholder="t('placeholder.input')" />
+                                    </uni-forms-item>
+                                </uni-col>
+                            </uni-row>
+
+                            <!-- 活动勾选区域(完整保留所有原逻辑) -->
+                            <view class="activities">
+                                <!-- 10%赠金/普通活动(原代码中第一个大块) -->
+                                <view
+                                    v-if="!tableData4Flag && !tableData4TwoFlag && !tableDataNewListFlag && (country != 'CN' || (country == 'CN' && (ACCType == 1 || ACCType == 2 || ACCType == 7 || ACCType == 5 || ACCType == 6 || ACCType == 8))) && ACCType != 3">
+                                    <template v-if="isSupportedCountry && (ACCType == 2 || ACCType == 7)">
+                                        <label class="checkbox">
+                                            <checkbox :checked="params.agree2"
+                                                @click="params.agree2 = !params.agree2" />
+                                            <text>{{ t('news_add_field1.deposit.item2_1') }}</text>
+                                        </label>
+                                        <view style="line-height: 1.5; font-size: 14px" v-if="country == 'CN'">
+                                            <p style="margin-bottom: 15px" v-if="isGuoQin">
+                                                <span>{{ t('Custom.Deposit.agree21') }}</span>
+                                                <span class="clause crm-cursor">
+                                                    <a :href="`pdf/pdf4/100Bonus-en.pdf`" style="color: black">{{
+                                                        t('Custom.Deposit.agree22_2') }}</a>
+                                                </span>
+                                                <span>{{ t('Custom.Deposit.agree23_2') }}</span>
+                                            </p>
+                                            <p style="margin-bottom: 15px" v-else>
+                                                <span>{{ t('Custom.Deposit.agree21') }}</span>
+                                                <span class="clause crm-cursor">
+                                                    <a :href="`pdf/pdf4/100Bonus-en.pdf`" style="color: black">{{
+                                                        t('Custom.Deposit.agree22_2') }}</a>
+                                                </span>
+                                                <span>{{ t('Custom.Deposit.agree23_2') }}</span>
+                                            </p>
+                                        </view>
+                                        <view style="line-height: 1.5; font-size: 14px" v-if="country != 'CN'">
+                                            <p style="margin-bottom: 15px">
+                                                <span>{{ t('Custom.Deposit.agree21') }}</span>
+                                                <span class="clause crm-cursor">
+                                                    <a :href="`pdf/pdf4/100Bonus-en.pdf`" style="color: black">{{
+                                                        t('Custom.Deposit.agree22_2') }}</a>
+                                                </span>
+                                                <span>{{ t('Custom.Deposit.agree23_2') }}</span>
+                                            </p>
+                                        </view>
+                                    </template>
+                                    <template v-if="!isSupportedCountry && ACCType != 8 && !isAfterSeptember30()">
+                                        <label class="checkbox">
+                                            <checkbox :checked="params.agree2"
+                                                @click="params.agree2 = !params.agree2" />
+                                            <text>{{ t('news_add_field1.deposit.item1') }}</text>
+                                        </label>
+                                        <view style="line-height: 1.5; font-size: 14px" v-if="country == 'CN'">
+                                            <p style="margin-bottom: 15px" v-if="isGuoQin">
+                                                <span>{{ t('Custom.Deposit.agree21') }}</span>
+                                                <span class="clause crm-cursor">
+                                                    <a :href="`pdf/pdf4/${locale}.pdf`" style="color: black">{{
+                                                        t('Custom.Deposit.agree22') }}</a>
+                                                </span>
+                                                <span>{{ t('Custom.Deposit.agree23_1') }}</span>
+                                            </p>
+                                            <p style="margin-bottom: 15px" v-else>
+                                                <span>{{ t('Custom.Deposit.agree21') }}</span>
+                                                <span class="clause crm-cursor">
+                                                    <a :href="`pdf/pdf4/${locale}.pdf`" style="color: black">{{
+                                                        t('Custom.Deposit.agree22') }}</a>
+                                                </span>
+                                                <span>{{ t('Custom.Deposit.agree23') }}</span>
+                                            </p>
+                                        </view>
+                                        <view style="line-height: 1.5; font-size: 14px" v-if="country != 'CN'">
+                                            <p style="margin-bottom: 15px">
+                                                <span>{{ t('Custom.Deposit.agree21') }}</span>
+                                                <span class="clause crm-cursor">
+                                                    <a :href="`pdf/pdf4/${locale}.pdf`" style="color: black">{{
+                                                        t('Custom.Deposit.agree22') }}</a>
+                                                </span>
+                                                <span>{{ t('Custom.Deposit.agree23_1') }}</span>
+                                            </p>
+                                        </view>
+                                    </template>
+                                </view>
 
-                        <!-- 活动勾选区域(完整保留所有原逻辑) -->
-                        <view class="activities">
-                            <!-- 10%赠金/普通活动(原代码中第一个大块) -->
-                            <view
-                                v-if="!tableData4Flag && !tableData4TwoFlag && !tableDataNewListFlag && (country != 'CN' || (country == 'CN' && (ACCType == 1 || ACCType == 2 || ACCType == 7 || ACCType == 5 || ACCType == 6 || ACCType == 8))) && ACCType != 3">
-                                <template v-if="isSupportedCountry && (ACCType == 2 || ACCType == 7)">
+                                <!-- 10%赠金-年中赠金 -->
+                                <view v-if="tableData4Flag">
                                     <label class="checkbox">
-                                        <checkbox :checked="params.agree2" @click="params.agree2 = !params.agree2" />
-                                        <text>{{ t('news_add_field1.deposit.item2_1') }}</text>
+                                        <checkbox :checked="params.agree4" @click="params.agree4 = !params.agree4" />
+                                        <text>{{ t('news_add_field1.activitiesNZ.itemDeposit1') }}</text>
                                     </label>
-                                    <view style="line-height: 1.5; font-size: 14px" v-if="country == 'CN'">
-                                        <p style="margin-bottom: 15px" v-if="isGuoQin">
-                                            <span>{{ t('Custom.Deposit.agree21') }}</span>
-                                            <span class="clause crm-cursor">
-                                                <a :href="`pdf/pdf4/100Bonus-en.pdf`" style="color: black">{{
-                                                    t('Custom.Deposit.agree22_2') }}</a>
-                                            </span>
-                                            <span>{{ t('Custom.Deposit.agree23_2') }}</span>
-                                        </p>
-                                        <p style="margin-bottom: 15px" v-else>
-                                            <span>{{ t('Custom.Deposit.agree21') }}</span>
-                                            <span class="clause crm-cursor">
-                                                <a :href="`pdf/pdf4/100Bonus-en.pdf`" style="color: black">{{
-                                                    t('Custom.Deposit.agree22_2') }}</a>
-                                            </span>
-                                            <span>{{ t('Custom.Deposit.agree23_2') }}</span>
-                                        </p>
-                                    </view>
-                                    <view style="line-height: 1.5; font-size: 14px" v-if="country != 'CN'">
+                                    <view style="line-height: 1.5; font-size: 14px">
                                         <p style="margin-bottom: 15px">
-                                            <span>{{ t('Custom.Deposit.agree21') }}</span>
-                                            <span class="clause crm-cursor">
-                                                <a :href="`pdf/pdf4/100Bonus-en.pdf`" style="color: black">{{
-                                                    t('Custom.Deposit.agree22_2') }}</a>
-                                            </span>
-                                            <span>{{ t('Custom.Deposit.agree23_2') }}</span>
+                                            <span>{{ t('news_add_field1.activitiesNZ.itemDeposit2') }}</span>
+                                            <span class="clause crm-cursor" @click="dialogClauseNZ = true">{{
+                                                t('news_add_field1.activitiesNZ.itemDeposit3') }}</span>
+                                            <span>{{ t('news_add_field1.activitiesNZ.itemDeposit4') }}</span>
                                         </p>
                                     </view>
-                                </template>
-                                <template v-if="!isSupportedCountry && ACCType != 8 && !isAfterSeptember30()">
+                                </view>
+
+                                <!-- 20%赠金-年中赠金 -->
+                                <view v-if="tableData4TwoFlag">
                                     <label class="checkbox">
-                                        <checkbox :checked="params.agree2" @click="params.agree2 = !params.agree2" />
-                                        <text>{{ t('news_add_field1.deposit.item1') }}</text>
+                                        <checkbox :checked="params.agree5" @click="params.agree5 = !params.agree5" />
+                                        <text>{{ t('news_add_field1.activitiesNZTwo.itemDeposit1') }}</text>
                                     </label>
-                                    <view style="line-height: 1.5; font-size: 14px" v-if="country == 'CN'">
-                                        <p style="margin-bottom: 15px" v-if="isGuoQin">
-                                            <span>{{ t('Custom.Deposit.agree21') }}</span>
-                                            <span class="clause crm-cursor">
-                                                <a :href="`pdf/pdf4/${locale}.pdf`" style="color: black">{{
-                                                    t('Custom.Deposit.agree22') }}</a>
-                                            </span>
-                                            <span>{{ t('Custom.Deposit.agree23_1') }}</span>
-                                        </p>
-                                        <p style="margin-bottom: 15px" v-else>
-                                            <span>{{ t('Custom.Deposit.agree21') }}</span>
-                                            <span class="clause crm-cursor">
-                                                <a :href="`pdf/pdf4/${locale}.pdf`" style="color: black">{{
-                                                    t('Custom.Deposit.agree22') }}</a>
-                                            </span>
-                                            <span>{{ t('Custom.Deposit.agree23') }}</span>
-                                        </p>
-                                    </view>
-                                    <view style="line-height: 1.5; font-size: 14px" v-if="country != 'CN'">
+                                    <view style="line-height: 1.5; font-size: 14px">
                                         <p style="margin-bottom: 15px">
-                                            <span>{{ t('Custom.Deposit.agree21') }}</span>
-                                            <span class="clause crm-cursor">
-                                                <a :href="`pdf/pdf4/${locale}.pdf`" style="color: black">{{
-                                                    t('Custom.Deposit.agree22') }}</a>
-                                            </span>
-                                            <span>{{ t('Custom.Deposit.agree23_1') }}</span>
+                                            <span>{{ t('news_add_field1.activitiesNZTwo.itemDeposit2') }}</span>
+                                            <span class="clause crm-cursor" @click="dialogClauseNZTwo = true">{{
+                                                t('news_add_field1.activitiesNZTwo.itemDeposit3') }}</span>
+                                            <span>{{ t('news_add_field1.activitiesNZTwo.itemDeposit4') }}</span>
                                         </p>
                                     </view>
-                                </template>
-                            </view>
-
-                            <!-- 10%赠金-年中赠金 -->
-                            <view v-if="tableData4Flag">
-                                <label class="checkbox">
-                                    <checkbox :checked="params.agree4" @click="params.agree4 = !params.agree4" />
-                                    <text>{{ t('news_add_field1.activitiesNZ.itemDeposit1') }}</text>
-                                </label>
-                                <view style="line-height: 1.5; font-size: 14px">
-                                    <p style="margin-bottom: 15px">
-                                        <span>{{ t('news_add_field1.activitiesNZ.itemDeposit2') }}</span>
-                                        <span class="clause crm-cursor" @click="dialogClauseNZ = true">{{
-                                            t('news_add_field1.activitiesNZ.itemDeposit3') }}</span>
-                                        <span>{{ t('news_add_field1.activitiesNZ.itemDeposit4') }}</span>
-                                    </p>
                                 </view>
-                            </view>
 
-                            <!-- 20%赠金-年中赠金 -->
-                            <view v-if="tableData4TwoFlag">
-                                <label class="checkbox">
-                                    <checkbox :checked="params.agree5" @click="params.agree5 = !params.agree5" />
-                                    <text>{{ t('news_add_field1.activitiesNZTwo.itemDeposit1') }}</text>
-                                </label>
-                                <view style="line-height: 1.5; font-size: 14px">
-                                    <p style="margin-bottom: 15px">
-                                        <span>{{ t('news_add_field1.activitiesNZTwo.itemDeposit2') }}</span>
-                                        <span class="clause crm-cursor" @click="dialogClauseNZTwo = true">{{
-                                            t('news_add_field1.activitiesNZTwo.itemDeposit3') }}</span>
-                                        <span>{{ t('news_add_field1.activitiesNZTwo.itemDeposit4') }}</span>
-                                    </p>
-                                </view>
-                            </view>
-
-                            <!-- 赠送活动 -->
-                            <view v-if="tableDataNewListFlag">
-                                <label class="checkbox">
-                                    <checkbox :checked="params.agree6" @click="params.agree6 = !params.agree6" />
-                                    <text>{{ tableDataNewList.title }}</text>
-                                </label>
-                                <view style="line-height: 1.5; font-size: 14px">
-                                    <p style="margin-bottom: 15px">
-                                        <span>{{ t('news_add_field1.activitiesNewList.item1') }}</span>
-                                        <span class="clause crm-cursor" @click="dialogClauseNewList = true">{{
-                                            tableDataNewList.title }}</span>
-                                        <span>{{ t('news_add_field1.activitiesNewList.item2') }}</span>
-                                    </p>
+                                <!-- 赠送活动 -->
+                                <view v-if="tableDataNewListFlag">
+                                    <label class="checkbox">
+                                        <checkbox :checked="params.agree6" @click="params.agree6 = !params.agree6" />
+                                        <text>{{ tableDataNewList.title }}</text>
+                                    </label>
+                                    <view style="line-height: 1.5; font-size: 14px">
+                                        <p style="margin-bottom: 15px">
+                                            <span>{{ t('news_add_field1.activitiesNewList.item1') }}</span>
+                                            <span class="clause crm-cursor" @click="dialogClauseNewList = true">{{
+                                                tableDataNewList.title }}</span>
+                                            <span>{{ t('news_add_field1.activitiesNewList.item2') }}</span>
+                                        </p>
+                                    </view>
                                 </view>
-                            </view>
 
-                            <!-- 20%赠金申请 -->
-                            <view
-                                v-if="(ACCType == 1 || ACCType == 2 || ACCType == 5 || ACCType == 6 || ACCType == 7) && anshiClose">
-                                <label class="checkbox">
-                                    <checkbox :checked="params.agree3" @click="params.agree3 = !params.agree3"
-                                        :disabled="CheckExistSuccess" />
-                                    <text>{{ t('news_add_field1.deposit.item3') }}</text>
-                                </label>
-                                <view style="line-height: 1.5; font-size: 14px">
-                                    <p style="margin-bottom: 15px">
-                                        <span>{{ t('news_add_field1.deposit.item4') }}</span>
-                                        <span class="clause crm-cursor" @click="dialogClause1 = true">{{
-                                            t('news_add_field1.deposit.item5')
-                                            }}</span>
-                                        <span>{{ t('news_add_field1.deposit.item6') }}</span>
-                                    </p>
+                                <!-- 20%赠金申请 -->
+                                <view
+                                    v-if="(ACCType == 1 || ACCType == 2 || ACCType == 5 || ACCType == 6 || ACCType == 7) && anshiClose">
+                                    <label class="checkbox">
+                                        <checkbox :checked="params.agree3" @click="params.agree3 = !params.agree3"
+                                            :disabled="CheckExistSuccess" />
+                                        <text>{{ t('news_add_field1.deposit.item3') }}</text>
+                                    </label>
+                                    <view style="line-height: 1.5; font-size: 14px">
+                                        <p style="margin-bottom: 15px">
+                                            <span>{{ t('news_add_field1.deposit.item4') }}</span>
+                                            <span class="clause crm-cursor" @click="dialogClause1 = true">{{
+                                                t('news_add_field1.deposit.item5')
+                                                }}</span>
+                                            <span>{{ t('news_add_field1.deposit.item6') }}</span>
+                                        </p>
+                                    </view>
                                 </view>
                             </view>
-                        </view>
 
-                        <button class="s-btn" type="primary" @click="submitConfirm">{{ t('Btn.Submit') }}</button>
-                    </form>
+                            <button class="s-btn" type="primary" @click="submitConfirm">{{ t('Btn.Submit') }}</button>
+                        </uni-forms>
+                    </view>
                 </view>
             </view>
-        </view>
 
-        <!-- 弹窗组件(使用 uni-popup) -->
-        <uni-popup ref="popup" type="center" :mask-click="false">
-            <view class="popup-content" v-if="popupType === 'confirm'">
-                <text class="popup-title">{{ t('Home.page_customer.item2') }}</text>
-                <view class="popup-form">
-                    <view class="popup-row"><text class="label">{{ t('Custom.Deposit.Title1') }}:</text><text>{{
-                        selectedAccountLabel }}</text></view>
-                    <view class="popup-row"><text class="label">{{ t('Custom.Deposit.Title2') }}:</text><text>{{
-                        locale ==
-                            'cn' ? channelData.name : channelData.enName }}</text></view>
-                    <view class="popup-row" v-if="code"><text class="label">{{ t('news_add_field.Label.Title4')
-                            }}:</text><text>{{ selectCodes }}</text></view>
-                    <view class="popup-row"><text class="label">{{ t('Custom.Deposit.Title3') }}:</text><text>{{
-                        params.amount
-                            }}({{ channelData.currency }})</text></view>
-                    <view class="popup-row" v-if="channelData.confirmName"><text class="label">{{ t('Label.Name')
-                            }}:</text><text>{{ userName }}</text></view>
-                    <view class="popup-row" v-if="channelData.confirmAreaCode">
-                        <text class="label">{{ t('placeholder.phone') }}:</text>
-                        <input class="small-input" v-model="dialogConfirmForm.confirmAreaCode" />
-                        <text>-</text>
-                        <input class="small-input" v-model="dialogConfirmForm.confirmPhone" />
+            <!-- 弹窗组件(使用 uni-popup) -->
+            <uni-popup ref="popupRef" type="center" :mask-click="false">
+                <view class="popup-content" v-if="popupType === 'confirm'">
+                    <text class="popup-title">{{ t('Home.page_customer.item2') }}</text>
+                    <view class="popup-form">
+                        <view class="popup-row"><text class="label">{{ t('Custom.Deposit.Title1') }}:</text><text>{{
+                            selectedAccountLabel }}</text></view>
+                        <view class="popup-row"><text class="label">{{ t('Custom.Deposit.Title2') }}:</text><text>{{
+                            locale ==
+                                'cn' ? channelData.name : channelData.enName }}</text></view>
+                        <view class="popup-row" v-if="code"><text class="label">{{ t('news_add_field.Label.Title4')
+                                }}:</text><text>{{ selectCodes }}</text></view>
+                        <view class="popup-row"><text class="label">{{ t('Custom.Deposit.Title3') }}:</text><text>{{
+                            params.amount
+                                }}({{ channelData.currency }})</text></view>
+                        <view class="popup-row" v-if="channelData.confirmName"><text class="label">{{ t('Label.Name')
+                                }}:</text><text>{{ userName }}</text></view>
+                        <view class="popup-row" v-if="channelData.confirmAreaCode">
+                            <text class="label">{{ t('placeholder.phone') }}:</text>
+                            <input class="small-input" v-model="dialogConfirmForm.confirmAreaCode" />
+                            <text>-</text>
+                            <input class="small-input" v-model="dialogConfirmForm.confirmPhone" />
+                        </view>
+                    </view>
+                    <view class="popup-buttons">
+                        <button @click="closePopup">{{ t('Btn.Cancel') }}</button>
+                        <button type="primary" @click="submitDeposit">{{ t('Btn.Confirm') }}</button>
                     </view>
                 </view>
-                <view class="popup-buttons">
-                    <button @click="closePopup">{{ t('Btn.Cancel') }}</button>
-                    <button type="primary" @click="submitDeposit">{{ t('Btn.Confirm') }}</button>
+                <view class="popup-content" v-else-if="popupType === 'result'">
+                    <view class="result-icon" v-if="dialogSuccess"><text class="iconfont iconchenggong"></text></view>
+                    <view class="result-icon" v-else><text class="iconfont iconjingshi"></text></view>
+                    <text class="popup-text">{{ dialogMessage }}</text>
+                    <view class="popup-buttons">
+                        <button type="primary" @click="closeResultPopup">{{ t('Btn.Confirm') }}</button>
+                        <button v-if="!dialogSuccess" @click="closeResultPopup">{{ t('Btn.Cancel') }}</button>
+                    </view>
                 </view>
-            </view>
-            <view class="popup-content" v-else-if="popupType === 'result'">
-                <view class="result-icon" v-if="dialogSuccess"><text class="iconfont iconchenggong"></text></view>
-                <view class="result-icon" v-else><text class="iconfont iconjingshi"></text></view>
-                <text class="popup-text">{{ dialogMessage }}</text>
-                <view class="popup-buttons">
-                    <button type="primary" @click="closeResultPopup">{{ t('Btn.Confirm') }}</button>
-                    <button v-if="!dialogSuccess" @click="closeResultPopup">{{ t('Btn.Cancel') }}</button>
+                <view class="popup-content" v-else-if="popupType === 'wait'">
+                    <text class="iconfont icondengdai"></text>
+                    <text class="popup-text">{{ t('ApplicationDialog.Des38') }}</text>
                 </view>
-            </view>
-            <view class="popup-content" v-else-if="popupType === 'wait'">
-                <text class="iconfont icondengdai"></text>
-                <text class="popup-text">{{ t('ApplicationDialog.Des38') }}</text>
-            </view>
-        </uni-popup>
-
-        <!-- 其他弹窗(越南提示、年中赠金协议等)用 uni-popup 或 uni.showModal 模拟,因原结构复杂,保留基础 -->
-        <!-- 越南用户提示弹窗 -->
-        <uni-popup ref="vietnamPopup" type="center">
-            <view class="popup-content" style="width: 600rpx;">
-                <text class="popup-title">{{ t('Home.page_customer.item2') }}</text>
-                <view class="popup-text" style="text-align: left; font-size: 24rpx; line-height: 1.6;">
-                    <p><strong>Quý khách hàng thân mến:</strong></p>
-                    <p>Trước khi giao dịch, chúng tôi xin nhắc nhở bạn rằng:</p>
-                    <p>1. Vì có những rủi ro nhất định trong giao dịch, bạn nên đầu tư thích hợp theo kinh nghiệm giao
-                        dịch và
-                        thu nhập liên quan của mình, thay vì sử dụng tiền vay từ người khác.</p>
-                    <p>2. Dựa trên sự điều chỉnh đối với hệ thống kiểm soát rủi ro của ngân hàng, kênh nạp tiền có thể
-                        không
-                        được hỗ trợ hoặc hạn mức giao dịch có thể không chính xác khi bạn sẵn sàng nạp tiền (đặc biệt là
-                        vào ban
-                        đêm tại địa phương của bạn), vì vậy bạn nên sắp xếp vị thế giao dịch của mình và khoảng thời
-                        gian nạp
-                        tiền sao cho hợp lý để tránh những tổn thất không đáng có do bất kỳ sự chậm trễ nào trong việc
-                        nhận tiền
-                        nạp.</p>
-                    <p>Không bao giờ tiết lộ thông tin cá nhân nhạy cảm cho người gọi đến. CWG sẽ không bao giờ yêu cầu
-                        bất kỳ
-                        thông tin cá nhân nhạy cảm nào từ bạn qua điện thoại hoặc email cũng như không cung cấp bất kỳ
-                        lời
-                        khuyên đầu tư nào.</p>
-                    <p>Trong trường hợp có bất kỳ vấn đề gì với khoản tiền nạp của bạn, vui lòng liên hệ với trung tâm
-                        dịch vụ
-                        khách hàng chính thức của chúng tôi bất kỳ lúc nào.</p>
-                    <p>Trân trọng,</p>
-                </view>
-                <view class="popup-buttons">
-                    <button type="primary" @click="closeVietnamPopup">{{ t('Btn.Confirm') }}</button>
+            </uni-popup>
+
+            <!-- 其他弹窗(越南提示、年中赠金协议等)用 uni-popup 或 uni.showModal 模拟,因原结构复杂,保留基础 -->
+            <!-- 越南用户提示弹窗 -->
+            <uni-popup ref="vietnamPopup" type="center">
+                <view class="popup-content" style="width: 600rpx;">
+                    <text class="popup-title">{{ t('Home.page_customer.item2') }}</text>
+                    <view class="popup-text" style="text-align: left; font-size: 24rpx; line-height: 1.6;">
+                        <p><strong>Quý khách hàng thân mến:</strong></p>
+                        <p>Trước khi giao dịch, chúng tôi xin nhắc nhở bạn rằng:</p>
+                        <p>1. Vì có những rủi ro nhất định trong giao dịch, bạn nên đầu tư thích hợp theo kinh nghiệm
+                            giao
+                            dịch và
+                            thu nhập liên quan của mình, thay vì sử dụng tiền vay từ người khác.</p>
+                        <p>2. Dựa trên sự điều chỉnh đối với hệ thống kiểm soát rủi ro của ngân hàng, kênh nạp tiền có
+                            thể
+                            không
+                            được hỗ trợ hoặc hạn mức giao dịch có thể không chính xác khi bạn sẵn sàng nạp tiền (đặc
+                            biệt là
+                            vào ban
+                            đêm tại địa phương của bạn), vì vậy bạn nên sắp xếp vị thế giao dịch của mình và khoảng thời
+                            gian nạp
+                            tiền sao cho hợp lý để tránh những tổn thất không đáng có do bất kỳ sự chậm trễ nào trong
+                            việc
+                            nhận tiền
+                            nạp.</p>
+                        <p>Không bao giờ tiết lộ thông tin cá nhân nhạy cảm cho người gọi đến. CWG sẽ không bao giờ yêu
+                            cầu
+                            bất kỳ
+                            thông tin cá nhân nhạy cảm nào từ bạn qua điện thoại hoặc email cũng như không cung cấp bất
+                            kỳ
+                            lời
+                            khuyên đầu tư nào.</p>
+                        <p>Trong trường hợp có bất kỳ vấn đề gì với khoản tiền nạp của bạn, vui lòng liên hệ với trung
+                            tâm
+                            dịch vụ
+                            khách hàng chính thức của chúng tôi bất kỳ lúc nào.</p>
+                        <p>Trân trọng,</p>
+                    </view>
+                    <view class="popup-buttons">
+                        <button type="primary" @click="closeVietnamPopup">{{ t('Btn.Confirm') }}</button>
+                    </view>
                 </view>
-            </view>
-        </uni-popup>
-
-        <!-- 中国网银提示弹窗 -->
-        <uni-popup ref="chinaUnionPayPopup" type="center">
-            <view class="popup-content">
-                <text class="popup-text">{{ t('news_add_field1.deposit.item64') }}</text>
-                <view class="popup-buttons">
-                    <button type="primary" @click="closeChinaUnionPayPopup">{{ t('Btn.Confirm') }}</button>
-                    <button @click="closeChinaUnionPayPopup">{{ t('Btn.Cancel') }}</button>
+            </uni-popup>
+
+            <!-- 中国网银提示弹窗 -->
+            <uni-popup ref="chinaUnionPayPopup" type="center">
+                <view class="popup-content">
+                    <text class="popup-text">{{ t('news_add_field1.deposit.item64') }}</text>
+                    <view class="popup-buttons">
+                        <button type="primary" @click="closeChinaUnionPayPopup">{{ t('Btn.Confirm') }}</button>
+                        <button @click="closeChinaUnionPayPopup">{{ t('Btn.Cancel') }}</button>
+                    </view>
                 </view>
-            </view>
-        </uni-popup>
-
-        <!-- 不参加活动弹窗 -->
-        <uni-popup ref="dontActivePopup" type="center">
-            <view class="popup-content">
-                <text class="popup-text">{{ t('Custom.Withdraw.item9') }}</text>
-                <view class="popup-buttons">
-                    <button type="primary" @click="confirmDontActive">{{ t('Btn.Confirm') }}</button>
-                    <button @click="closeDontActivePopup">{{ t('Btn.Cancel') }}</button>
+            </uni-popup>
+
+            <!-- 不参加活动弹窗 -->
+            <uni-popup ref="dontActivePopupRef" type="center">
+                <view class="popup-content">
+                    <text class="popup-text">{{ t('Custom.Withdraw.item9') }}</text>
+                    <view class="popup-buttons">
+                        <button type="primary" @click="confirmDontActive">{{ t('Btn.Confirm') }}</button>
+                        <button @click="closeDontActivePopup">{{ t('Btn.Cancel') }}</button>
+                    </view>
                 </view>
-            </view>
-        </uni-popup>
-
-        <!-- 20%赠金协议 -->
-        <uni-popup ref="clausePopup" type="center">
-            <view class="popup-content" style="width: 700rpx;">
-                <text class="popup-title">{{ locale === 'cn' ? 'CWG 20%赠金入会礼' : '20% CASH BACK BONUS' }}</text>
-                <scroll-view scroll-y style="height: 400rpx;">
-                    <rich-text :nodes="clauseContent" class="popup-text"></rich-text>
-                </scroll-view>
-                <view class="popup-buttons">
-                    <button @click="closeClausePopup">{{ t('Btn.Cancel') }}</button>
-                    <button type="primary" @click="closeClausePopup">{{ t('Btn.Confirm') }}</button>
+            </uni-popup>
+
+            <!-- 20%赠金协议 -->
+            <uni-popup ref="clausePopup" type="center">
+                <view class="popup-content" style="width: 700rpx;">
+                    <text class="popup-title">{{ locale === 'cn' ? 'CWG 20%赠金入会礼' : '20% CASH BACK BONUS' }}</text>
+                    <scroll-view scroll-y style="height: 400rpx;">
+                        <rich-text :nodes="clauseContent" class="popup-text"></rich-text>
+                    </scroll-view>
+                    <view class="popup-buttons">
+                        <button @click="closeClausePopup">{{ t('Btn.Cancel') }}</button>
+                        <button type="primary" @click="closeClausePopup">{{ t('Btn.Confirm') }}</button>
+                    </view>
                 </view>
-            </view>
-        </uni-popup>
+            </uni-popup>
+
+            <!-- 抽屉组件 -->
+            <drawer :dialogInfoTradingAdd="dialogInfoTradingAdd" :addType="openType" @closeAdd="closeAdd"
+                @confirmToReload="confirmToReload" />
+            <view class="crm_verified_info_mask" v-if="dialogInfoTradingAdd" @click="closeDiaAdd"></view>
+        </view>
+    </cwg-page-wrapper>
 
-        <!-- 抽屉组件 -->
-        <drawer :dialogInfoTradingAdd="dialogInfoTradingAdd" :addType="openType" @closeAdd="closeAdd"
-            @confirmToReload="confirmToReload" />
-        <view class="crm_verified_info_mask" v-if="dialogInfoTradingAdd" @click="closeDiaAdd"></view>
-    </view>
 </template>
 
 <script setup>
@@ -553,6 +610,27 @@ const amountError = ref('')
 const selectedCreditIndex = ref(-1)
 const selectedCreditLabel = ref('')
 
+const loginComboxOptions = computed(() => {
+    return loginOptions.value.map((item) => ({
+        text: item.label,
+        value: item.login
+    }))
+})
+
+const creditCardOptions = computed(() => {
+    return ruleForm.bankCredit.map((item, index) => ({
+        text: `${item.bankUname}-${item.bankCardNum}`,
+        value: item.id
+    }))
+})
+
+const bankOptions = computed(() => {
+    return bankDate.value.map((item, index) => ({
+        text: (locale.value === 'cn' || locale.value === 'zhHant') ? item.name : item.enName,
+        value: index
+    }))
+})
+
 // 计算属性
 const country = computed(() => userInfo.value?.customInfo?.country || '')
 const userName = computed(() => {
@@ -806,11 +884,10 @@ const is20Open = () => {
 }
 
 // 事件处理
-const onAccountChange = (e) => {
-    const idx = e.detail.value
-    const item = loginOptions.value[idx]
+const onAccountChange = (val) => {
+    const item = loginOptions.value.find(opt => opt.login === val)
     if (item) {
-        selectedAccountIndex.value = idx
+        selectedAccountIndex.value = loginOptions.value.indexOf(item)
         selectedAccountLabel.value = item.label
         loginValue.value = item.login
         step2.value = true
@@ -902,8 +979,7 @@ const isShowStep3 = (row) => {
         doShowStep3(row)
     }
 }
-const onBankChange = (e) => {
-    const idx = e.detail.value
+const onBankChange = (idx) => {
     const item = bankDate.value[idx]
     if (item) {
         selectedBankIndex.value = idx
@@ -916,17 +992,17 @@ const onBankChange = (e) => {
         channelData.value.transformCurrency = item.currency || channelData.value.transformCurrency
     }
 }
-const onCreditCardChange = (e) => {
-    const idx = e.detail.value
-    const item = ruleForm.bankCredit[idx]
+const onCreditCardChange = (val) => {
+    const item = ruleForm.bankCredit.find(i => i.id === val)
     if (item) {
-        selectedCreditIndex.value = idx
+        selectedCreditIndex.value = ruleForm.bankCredit.indexOf(item)
         selectedCreditLabel.value = `${item.bankUname}-${item.bankCardNum}`
         myId.value = item.id
         // 填充表单(原 chooseBank 逻辑)
     }
 }
 const onAmountInput = (e) => {
+    console.log(e, e.detail.value);
     const val = e.detail.value
     params.amount = val
     if (val && channelData.value.rate) {
@@ -1024,6 +1100,7 @@ const closeDiaAdd = () => { dialogInfoTradingAdd.value = false }
 
 // 提交确认逻辑
 const submitConfirm = () => {
+    console.log(params,121212);
     // 原 openDontActive 逻辑,先判断活动冲突,然后打开确认弹窗
     if (!tableData4Flag.value && !tableData4TwoFlag.value && !tableDataNewListFlag.value &&
         (country.value != 'CN' || (country.value == 'CN' && (ACCType.value == 1 || ACCType.value == 2 || ACCType.value == 7))) &&
@@ -1390,287 +1467,457 @@ onLoad(() => {
 </script>
 
 <style lang="scss" scoped>
-// 样式保持与之前转换一致,此处只列出关键类
+@import "@/uni.scss";
+
 .custom-deposit {
-    padding: 30rpx;
-    background: #f5f7fa;
+    min-height: 100vh;
 
     .crm-title-box {
-        margin-bottom: 30rpx;
+        margin-bottom: px2rpx(20);
 
         .tit {
-            font-size: 36rpx;
-            font-weight: bold;
+            font-size: px2rpx(20);
+            font-weight: 700;
+            color: var(--color-navy-900);
         }
     }
 
     .box {
-        margin-bottom: 30rpx;
+        margin-bottom: px2rpx(20);
 
         .b-card {
             background: #fff;
-            border-radius: 16rpx;
-            padding: 30rpx;
+            border-radius: px2rpx(12);
+            padding: px2rpx(20);
+            box-shadow: 0 px2rpx(4) px2rpx(12) rgba(0, 0, 0, 0.03);
 
             .card-top {
                 .tit {
-                    font-size: 32rpx;
-                    font-weight: 500;
-                    margin-bottom: 20rpx;
+                    font-size: px2rpx(16);
+                    font-weight: 600;
+                    margin-bottom: px2rpx(16);
                     display: flex;
                     align-items: center;
-
-                    .iconfont {
-                        margin-right: 10rpx;
+                    color: var(--color-navy-900);
+
+                    position: relative;
+                    padding-left: 20px;
+
+                    &:after {
+                        content: '';
+                        position: absolute;
+                        left: 0;
+                        top: 50%;
+                        transform: translateY(-50%);
+                        width: 0;
+                        height: 0;
+                        border-top: 6px solid transparent;
+                        border-bottom: 6px solid transparent;
+                        border-left: 8px solid currentColor;
                     }
                 }
             }
-        }
-    }
 
-    .picker-view {
-        background: #f5f7fa;
-        padding: 20rpx;
-        border-radius: 8rpx;
-        margin: 20rpx 0;
+            .channelType {
+                font-size: px2rpx(15);
+                font-weight: 600;
+                margin: px2rpx(24) 0 px2rpx(12);
+                color: var(--color-navy-700);
+                padding-left: px2rpx(8);
+                border-left: px2rpx(4) solid var(--color-primary);
+            }
+        }
     }
 
-    .payment-list {
+    .reselect-btn {
+        margin-top: px2rpx(20);
         display: flex;
-        flex-wrap: wrap;
-        gap: 2%;
+        justify-content: flex-end;
 
-        .payment-card {
-            width: 47%;
-            background: #fff;
-            border-radius: 12rpx;
-            margin-bottom: 24rpx;
-            padding: 24rpx;
-            box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
-
-            .icon-wrapper {
-                width: 96rpx;
-                height: 96rpx;
-                margin-right: 24rpx;
-                background: #f0f2f5;
-                border-radius: 48rpx;
-                display: flex;
-                align-items: center;
-                justify-content: center;
-
-                .icon {
-                    width: 64rpx;
-                    height: 64rpx;
-                }
+        .reselect {
+            background-color: var(--color-zinc-100);
+            color: var(--color-navy-700);
+            border: none;
+            font-size: px2rpx(14);
+            padding: px2rpx(8) px2rpx(20);
+            border-radius: px2rpx(8);
+
+            &:active {
+                background-color: var(--color-zinc-200);
             }
+        }
+    }
 
-            .content {
-                flex: 1;
-
-                .header {
-                    display: flex;
-                    justify-content: space-between;
-                    margin-bottom: 16rpx;
-
-                    .title {
-                        font-size: 32rpx;
-                        font-weight: 600;
-                    }
-                }
-
-                .info-list {
-                    .info-item {
-                        display: flex;
-                        justify-content: space-between;
-                        margin-bottom: 12rpx;
-                        font-size: 26rpx;
-                    }
-                }
-
-                .s-btn {
-                    background: #007aff;
-                    color: #fff;
-                    border: none;
-                    padding: 10rpx 20rpx;
-                    border-radius: 8rpx;
-                    margin-top: 16rpx;
+    .s-btn[type="primary"] {
+        width: 100%;
+        height: px2rpx(48);
+        background: var(--color-navy-900);
+        color: #fff;
+        border-radius: px2rpx(12);
+        font-size: px2rpx(16);
+        font-weight: 600;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        border: none;
+        margin-top: px2rpx(30);
+        transition: all 0.2s;
 
-                    &.active {
-                        background: #4caf50;
-                    }
-                }
-            }
+        &:active {
+            transform: scale(0.98);
+            background: var(--color-navy-800);
         }
     }
 
     .add-back {
         display: flex;
         justify-content: space-between;
-        margin: 20rpx 0;
+        align-items: center;
+        margin-bottom: px2rpx(12);
+        padding: px2rpx(12) px2rpx(16);
+        background: var(--color-zinc-100);
+        border-radius: px2rpx(8);
+
+        text {
+            font-size: px2rpx(14);
+            color: var(--color-navy-700);
+            font-weight: 500;
+        }
 
         .add-btn {
-            color: #007aff;
+            color: var(--color-primary);
+            font-weight: 600;
             text-decoration: underline;
-        }
-    }
 
-    .form-row {
-        display: flex;
-        flex-wrap: wrap;
-
-        .form-item {
-            flex: 1;
-            margin: 20rpx;
-
-            .label {
-                font-size: 28rpx;
-                color: #666;
-            }
-
-            .input {
-                background: #f5f7fa;
-                padding: 20rpx;
-                border-radius: 8rpx;
-                margin-top: 10rpx;
-            }
-
-            .error {
-                color: #f56c6c;
-                font-size: 24rpx;
+            &:active {
+                opacity: 0.7;
             }
         }
     }
 
     .wire-transfer-account {
-        background: #fafafa;
-        padding: 20rpx;
-        border-radius: 8rpx;
-        margin: 20rpx 0;
+        background: var(--color-zinc-50);
+        padding: px2rpx(16);
+        border-radius: px2rpx(12);
+        margin: px2rpx(16) 0;
 
         .row {
             display: flex;
-            margin-bottom: 15rpx;
+            margin-bottom: px2rpx(12);
+            font-size: px2rpx(14);
+
+            &:last-child {
+                margin-bottom: 0;
+            }
 
             .label {
-                width: 200rpx;
+                width: px2rpx(120);
+                color: var(--color-zinc-500);
             }
 
             .content {
                 flex: 1;
+                color: var(--color-navy-900);
+                font-weight: 500;
             }
 
             .SpecialColor {
-                color: #f56c6c;
+                color: var(--color-error);
             }
         }
     }
 
     .activities {
-        margin: 30rpx 0;
+        margin: px2rpx(24) 0;
 
         .checkbox {
             display: flex;
-            align-items: center;
-            margin-bottom: 20rpx;
+            align-items: flex-start;
+            gap: px2rpx(8);
+            margin-bottom: px2rpx(12);
+
+            :deep(uni-checkbox .uni-checkbox-input) {
+                border-radius: px2rpx(4);
+                width: px2rpx(18);
+                height: px2rpx(18);
+            }
 
-            checkbox {
-                margin-right: 20rpx;
+            text {
+                font-size: px2rpx(14);
+                color: var(--color-navy-700);
+                font-weight: 500;
+                line-height: 1.5;
             }
         }
-    }
 
-    .s-btn {
-        background: #007aff;
-        color: #fff;
-        border: none;
-        padding: 20rpx;
-        border-radius: 8rpx;
-        width: 100%;
-        font-size: 32rpx;
-        margin-top: 30rpx;
-    }
-
-    .reselect-btn {
-        margin-top: 30rpx;
+        .clause-text {
+            font-size: px2rpx(13);
+            color: var(--color-zinc-500);
+            line-height: 1.6;
+            padding-left: px2rpx(26);
 
-        .reselect {
-            background: #f0f0f0;
-            color: #333;
+            .clause {
+                color: var(--color-primary);
+                text-decoration: underline;
+            }
         }
     }
 
     .step3-attention {
+        background: var(--color-error-50, #fff1f0);
+        border-radius: px2rpx(12);
+        padding: px2rpx(16);
+        margin-bottom: px2rpx(20);
+
         .attention {
-            margin: 20rpx 0;
+            font-size: px2rpx(14);
+            color: var(--color-error-600, #cf1322);
             line-height: 1.6;
         }
 
         .btn-bottom {
-            text-align: center;
+            margin-top: px2rpx(20);
+            display: flex;
+            justify-content: center;
 
             .btn {
-                display: inline-block;
-                background: #007aff;
+                background: var(--color-error-600, #cf1322);
                 color: #fff;
-                padding: 20rpx 60rpx;
-                border-radius: 40rpx;
+                padding: px2rpx(10) px2rpx(48);
+                border-radius: px2rpx(24);
+                font-size: px2rpx(15);
+                font-weight: 700;
+                box-shadow: 0 px2rpx(4) px2rpx(10) rgba(207, 19, 34, 0.2);
+                transition: all 0.2s;
+
+                &:active {
+                    transform: scale(0.96);
+                    opacity: 0.8;
+                }
             }
         }
     }
-}
 
-.popup-content {
-    background: #fff;
-    border-radius: 16rpx;
-    padding: 40rpx;
-    width: 600rpx;
-    text-align: center;
-
-    .popup-title {
-        font-size: 36rpx;
-        font-weight: bold;
-        margin-bottom: 30rpx;
-        display: block;
-    }
+    .upload-box {
+        display: flex;
+        align-items: center;
+        gap: px2rpx(12);
+
+        .btn-upload {
+            background: var(--color-zinc-100);
+            border: px2rpx(1) dashed var(--color-zinc-300);
+            border-radius: px2rpx(8);
+            height: px2rpx(44);
+            font-size: px2rpx(14);
+            color: var(--color-zinc-600);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            padding: 0 px2rpx(20);
+        }
 
-    .popup-text {
-        font-size: 28rpx;
-        line-height: 1.6;
-        margin: 20rpx 0;
+        .img-preview {
+            width: px2rpx(44);
+            height: px2rpx(44);
+            border-radius: px2rpx(4);
+            object-fit: cover;
+        }
     }
 
-    .popup-form {
+    .label-with-icon {
+        font-size: px2rpx(14);
+        color: #606266;
+        box-sizing: border-box;
+        display: flex;
+        align-items: center;
+        padding: 0 0 8px;
+        height: px2rpx(36);
+        line-height: 1.5715;
         text-align: left;
-        margin: 30rpx 0;
+        /* #ifndef APP-NVUE */
+        white-space: initial;
+        /* #endif */
+
+        .help-icon {
+            margin-left: px2rpx(8);
+            width: px2rpx(16);
+            height: px2rpx(16);
+            background: var(--color-zinc-200);
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: px2rpx(12);
+            color: var(--color-zinc-600);
+            cursor: pointer;
+        }
+    }
+
+    .tooltip-content {
+        :deep(.uni-tooltip-popup) {
+            background-color: #fff !important;
+            box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !important;
+            width: px2rpx(300) !important;
+            color: var(--color-zinc-500);
+            line-height: 1.6;
+        }
+    }
 
-        .popup-row {
-            margin-bottom: 20rpx;
+    .error {
+        color: var(--color-error);
+        font-size: px2rpx(12);
+        margin-top: px2rpx(4);
+        display: block;
+    }
 
-            .label {
-                font-weight: bold;
+    :deep(.base-info-form) {
+        .uni-row1 {
+            .uni-col {
+                padding: 0 px2rpx(10) !important;
+            }
+
+            .uni-forms-item {
+                min-height: px2rpx(79);
+                margin-bottom: px2rpx(10);
+                position: relative;
+            }
+
+            .uni-select,
+            .uni-combox,
+            .uni-easyinput__content,
+            .uni-date-editor--x {
+                border: none !important;
+                background-color: var(--color-zinc-100) !important;
+                border-radius: px2rpx(8) !important;
             }
 
-            .small-input {
-                width: 120rpx;
-                display: inline-block;
+            .uni-easyinput__content-input {
+                height: px2rpx(44) !important;
             }
         }
     }
 
-    .popup-buttons {
-        display: flex;
-        justify-content: space-around;
-        margin-top: 30rpx;
+    .popup-content {
+        background: #fff;
+        border-radius: px2rpx(20);
+        padding: px2rpx(24);
+        width: px2rpx(320);
+        text-align: center;
+
+        .popup-title {
+            font-size: px2rpx(18);
+            font-weight: 700;
+            margin-bottom: px2rpx(20);
+            color: var(--color-navy-900);
+            display: block;
+        }
+
+        .popup-text {
+            font-size: px2rpx(14);
+            line-height: 1.6;
+            color: var(--color-zinc-600);
+            margin-bottom: px2rpx(20);
+            display: block;
+        }
 
-        button {
-            flex: 1;
-            margin: 0 20rpx;
+        .popup-form {
+            background: var(--color-zinc-50);
+            border-radius: px2rpx(12);
+            padding: px2rpx(16);
+            margin-bottom: px2rpx(24);
+            text-align: left;
+
+            .popup-row {
+                display: flex;
+                justify-content: space-between;
+                margin-bottom: px2rpx(12);
+                font-size: px2rpx(14);
+
+                &:last-child {
+                    margin-bottom: 0;
+                }
+
+                .label {
+                    color: var(--color-zinc-500);
+                    font-weight: 500;
+                }
+
+                text:not(.label) {
+                    color: var(--color-navy-900);
+                    font-weight: 500;
+                }
+
+                .small-input {
+                    width: px2rpx(60);
+                    background: #fff;
+                    border: px2rpx(1) solid var(--color-zinc-200);
+                    border-radius: px2rpx(4);
+                    padding: 0 px2rpx(4);
+                    height: px2rpx(24);
+                    font-size: px2rpx(12);
+                }
+            }
+        }
+
+        .popup-buttons {
+            display: flex;
+            gap: px2rpx(12);
+
+            button {
+                flex: 1;
+                height: px2rpx(44);
+                border-radius: px2rpx(10);
+                font-size: px2rpx(15);
+                font-weight: 600;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                border: none;
+
+                &[type="primary"] {
+                    background: var(--color-navy-900);
+                    color: #fff;
+                }
+
+                &:not([type="primary"]) {
+                    background: var(--color-zinc-100);
+                    color: var(--color-zinc-600);
+                }
+            }
+        }
+
+        .result-icon {
+            display: flex;
+            justify-content: center;
+            margin-bottom: px2rpx(16);
+
+            .iconfont {
+                font-size: px2rpx(48);
+
+                &.iconchenggong {
+                    color: #52c41a;
+                }
+
+                &.iconjingshi {
+                    color: #faad14;
+                }
+
+                &.icondengdai {
+                    color: var(--color-primary);
+                    animation: rotate 2s linear infinite;
+                }
+            }
         }
     }
 
-    .result-icon {
-        font-size: 80rpx;
-        margin-bottom: 20rpx;
+    @keyframes rotate {
+        from {
+            transform: rotate(0deg);
+        }
+
+        to {
+            transform: rotate(360deg);
+        }
     }
 }
 </style>

+ 350 - 0
pages/customer/style.scss

@@ -0,0 +1,350 @@
+@import "@/uni.scss";
+
+.custom-withdraw {
+  background: var(--color-zinc-50);
+  min-height: 100vh;
+
+  .box {
+    margin-bottom: px2rpx(20);
+
+    .b-card {
+      background: #fff;
+      border-radius: px2rpx(12);
+      padding: px2rpx(20);
+      box-shadow: 0 px2rpx(4) px2rpx(12) rgba(0, 0, 0, 0.03);
+
+      .card-top {
+        .tit {
+          font-size: px2rpx(16);
+          font-weight: 600;
+          margin-bottom: px2rpx(16);
+          display: flex;
+          align-items: center;
+          color: var(--color-navy-900);
+
+          .iconfont {
+            margin-right: px2rpx(8);
+            color: var(--color-primary);
+            font-size: px2rpx(18);
+          }
+        }
+      }
+
+      .channelType {
+        font-size: px2rpx(15);
+        font-weight: 600;
+        margin: px2rpx(24) 0 px2rpx(12);
+        color: var(--color-navy-700);
+        padding-left: px2rpx(8);
+        border-left: px2rpx(4) solid var(--color-primary);
+      }
+    }
+  }
+
+  .reselect-btn {
+    margin-top: px2rpx(20);
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  .s-btn {
+    &.reselect {
+      background-color: var(--color-zinc-100);
+      color: var(--color-navy-700);
+      border: none;
+      font-size: px2rpx(14);
+      padding: px2rpx(8) px2rpx(20);
+      border-radius: px2rpx(8);
+
+      &:active {
+        background-color: var(--color-zinc-200);
+      }
+    }
+
+    &[type="primary"] {
+      width: 100%;
+      height: px2rpx(48);
+      background: var(--color-navy-900);
+      color: #fff;
+      border-radius: px2rpx(12);
+      font-size: px2rpx(16);
+      font-weight: 600;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      border: none;
+      margin-top: px2rpx(30);
+      transition: all 0.2s;
+
+      &:active {
+        transform: scale(0.98);
+        background: var(--color-navy-800);
+      }
+    }
+  }
+
+  .add-back {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: px2rpx(12);
+    padding: px2rpx(12) px2rpx(16);
+    background: var(--color-zinc-100);
+    border-radius: px2rpx(8);
+
+    text {
+      font-size: px2rpx(14);
+      color: var(--color-navy-700);
+      font-weight: 500;
+    }
+
+    .add-btn {
+      color: var(--color-primary);
+      font-weight: 600;
+      text-decoration: underline;
+
+      &:active {
+        opacity: 0.7;
+      }
+    }
+  }
+
+  .proof {
+    margin-top: px2rpx(8);
+    border: px2rpx(1) dashed var(--color-zinc-300);
+    border-radius: px2rpx(8);
+    padding: px2rpx(8);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background: var(--color-zinc-50);
+
+    .state {
+      padding: px2rpx(4) px2rpx(12);
+      border-radius: px2rpx(4);
+      font-size: px2rpx(12);
+      font-weight: bold;
+    }
+  }
+
+  .agree {
+    margin: px2rpx(24) 0;
+    display: flex;
+    align-items: flex-start;
+
+    .checkbox {
+      display: flex;
+      align-items: flex-start;
+      gap: px2rpx(8);
+
+      :deep(uni-checkbox .uni-checkbox-input) {
+        border-radius: px2rpx(4);
+        width: px2rpx(18);
+        height: px2rpx(18);
+      }
+
+      text {
+        font-size: px2rpx(13);
+        color: var(--color-zinc-500);
+        line-height: 1.5;
+      }
+    }
+  }
+
+  .step3-attention {
+    background: var(--color-error-50, #fff1f0);
+    border-radius: px2rpx(12);
+    padding: px2rpx(16);
+    margin-bottom: px2rpx(20);
+
+    .attention {
+      font-size: px2rpx(14);
+      color: var(--color-error-600, #cf1322);
+      line-height: 1.6;
+    }
+
+    .btn-bottom {
+      margin-top: px2rpx(20);
+      display: flex;
+      justify-content: center;
+
+      .btn {
+        background: var(--color-error-600, #cf1322);
+        color: #fff;
+        padding: px2rpx(10) px2rpx(48);
+        border-radius: px2rpx(24);
+        font-size: px2rpx(15);
+        font-weight: 700;
+        box-shadow: 0 px2rpx(4) px2rpx(10) rgba(207, 19, 34, 0.2);
+        transition: all 0.2s;
+
+        &:active {
+          transform: scale(0.96);
+          opacity: 0.8;
+        }
+      }
+    }
+  }
+
+  :deep(.base-info-form) {
+    .uni-row1 {
+      .uni-col {
+        padding: 0 px2rpx(10) !important;
+      }
+
+      .uni-forms-item {
+        min-height: px2rpx(79);
+        margin-bottom: px2rpx(10);
+      }
+
+      .uni-select,
+      .uni-combox,
+      .uni-easyinput__content,
+      .uni-date-editor--x {
+        border: none !important;
+        background-color: var(--color-zinc-100) !important;
+        border-radius: px2rpx(8) !important;
+      }
+
+      .uni-date-x {
+        border: none !important;
+        background-color: rgba(195, 195, 195, 0) !important;
+      }
+
+      .uni-easyinput__content-input {
+        height: px2rpx(44) !important;
+      }
+    }
+  }
+
+  /* 弹窗样式美化 */
+  :deep(.uni-popup__wrapper) {
+    .popup-content {
+      background-color: #fff;
+      border-radius: px2rpx(20);
+      padding: px2rpx(24);
+      width: px2rpx(320);
+
+      .popup-title {
+        font-size: px2rpx(18);
+        font-weight: 700;
+        text-align: center;
+        margin-bottom: px2rpx(20);
+        color: var(--color-navy-900);
+        display: block;
+      }
+
+      .popup-text {
+        font-size: px2rpx(14);
+        line-height: 1.6;
+        color: var(--color-zinc-600);
+        margin-bottom: px2rpx(20);
+        display: block;
+      }
+
+      .popup-form {
+        background: var(--color-zinc-50);
+        border-radius: px2rpx(12);
+        padding: px2rpx(16);
+        margin-bottom: px2rpx(24);
+
+        .popup-row {
+          display: flex;
+          justify-content: space-between;
+          margin-bottom: px2rpx(12);
+          font-size: px2rpx(14);
+
+          &:last-child {
+            margin-bottom: 0;
+          }
+
+          .label {
+            color: var(--color-zinc-500);
+          }
+
+          text:not(.label) {
+            color: var(--color-navy-900);
+            font-weight: 500;
+          }
+        }
+      }
+
+      .popup-buttons {
+        display: flex;
+        gap: px2rpx(12);
+
+        button {
+          flex: 1;
+          height: px2rpx(44);
+          border-radius: px2rpx(10);
+          font-size: px2rpx(15);
+          font-weight: 600;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          border: none;
+
+          &[type="primary"] {
+            background: var(--color-navy-900);
+            color: #fff;
+          }
+
+          &:not([type="primary"]) {
+            background: var(--color-zinc-100);
+            color: var(--color-zinc-600);
+          }
+        }
+      }
+
+      .result-icon {
+        display: flex;
+        justify-content: center;
+        margin-bottom: px2rpx(16);
+
+        .iconfont {
+          font-size: px2rpx(48);
+
+          &.iconchenggong {
+            color: #52c41a;
+          }
+
+          &.iconjingshi {
+            color: #faad14;
+          }
+
+          &.icondengdai {
+            color: var(--color-primary);
+            animation: rotate 2s linear infinite;
+          }
+        }
+      }
+
+      .code-input {
+        background: var(--color-zinc-100);
+        border: none;
+        border-radius: px2rpx(8);
+        padding: px2rpx(12);
+        margin-bottom: px2rpx(12);
+        font-size: px2rpx(15);
+      }
+
+      .code-timer {
+        color: var(--color-primary);
+        font-size: px2rpx(13);
+        text-align: right;
+        margin-bottom: px2rpx(20);
+        font-weight: 500;
+      }
+    }
+  }
+
+  @keyframes rotate {
+    from {
+      transform: rotate(0deg);
+    }
+
+    to {
+      transform: rotate(360deg);
+    }
+  }
+}

+ 1347 - 0
pages/customer/withdrawal.vue

@@ -0,0 +1,1347 @@
+<template>
+  <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
+    <view class="custom-withdraw">
+      <!-- 标题 -->
+      <!-- <view class="crm-title-box">
+        <text class="tit">{{ t('Custom.Withdraw.Title') }}</text>
+      </view> -->
+
+      <!-- 步骤1:选择账户 -->
+      <view class="box box-step1">
+        <view class="b-card">
+          <view class="card-top">
+            <text class="tit"><text class="iconfont icon-caret-right"></text>{{ t('Custom.Deposit.Title11') }}</text>
+            <view class="base-info-form">
+              <view class="uni-row2">
+                <cwg-combox :clearable="false" v-model:value="loginValue" :options="loginComboxOptions"
+                  :placeholder="t('placeholder.choose')" @change="onAccountChange" />
+              </view>
+            </view>
+          </view>
+        </view>
+      </view>
+
+      <!-- 步骤2:支付通道列表 -->
+      <view class="box box-step2" v-if="step2">
+        <view class="b-card">
+          <view class="card-top">
+            <text class="tit"><text class="iconfont icon-caret-right"></text>{{ t('Custom.Deposit.Title22') }}</text>
+            <view v-for="(group, groupKey) in tableData" :key="groupKey">
+              <!-- 通道分组标题 -->
+              <view class="channelType" v-if="group.length" v-t="groupTitleMap[groupKey]" />
+              <PaymentMethodsList :list="group" @select="isShowStep3" />
+            </view>
+            <view v-if="step3" class="reselect-btn">
+              <button class="s-btn reselect" type="primary" @click="showTable">{{ t('Custom.Deposit.Reselect')
+                }}</button>
+            </view>
+          </view>
+        </view>
+      </view>
+
+      <!-- 步骤3:填写出金信息 -->
+      <view class="box box-step3" v-if="step3">
+        <view class="b-card">
+          <view class="card-top">
+            <!-- 注意事项 -->
+            <view v-if="!isStep3" class="step3-attention">
+              <rich-text class="attention" :nodes="isZh ? introduce.introduce : introduce.enIntroduce"></rich-text>
+              <view class="btn-bottom">
+                <text class="btn crm-cursor" @click="isStep3 = true">{{ t('Btn.Confirm') }}</text>
+              </view>
+            </view>
+
+            <!-- 表单 -->
+            <uni-forms ref="baseForm" :model="form" labelWidth="200" label-position="top" v-if="isStep3"
+              class="base-info-form">
+              <uni-row class="demo-uni-row uni-row1">
+                <!-- 银行选择(针对有银行列表的通道) -->
+                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="bankDate.length">
+                  <uni-forms-item :label="t('Custom.Withdraw.Title5')">
+                    <cwg-combox :clearable="false" v-model:value="selectedBankIndex" :options="bankOptions"
+                      :placeholder="t('placeholder.choose')" @change="onBankChange" />
+                  </uni-forms-item>
+                </uni-col>
+
+                <!-- 电子钱包地址输入 -->
+                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8"
+                  v-if="['CHANNEL_TYPE_WALLET', 'UCARD_WALLET', 'CHANNEL_TYPE_ALI_WALLET'].includes(channelData.type)">
+                  <uni-forms-item :label="getWalletLabel">
+                    <uni-easyinput :clearable="false" v-model="form.address" :placeholder="t('placeholder.input')" />
+                  </uni-forms-item>
+                </uni-col>
+
+                <!-- 数字货币选择(从已保存地址中选择) -->
+                <uni-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="channelData.type === 'DIGITAL_CURRENCY'">
+                  <view class="add-back">
+                    <text>{{ t('blockchain.item10') }}</text>
+                    <text class="add-btn crm-cursor" @click="openAddBankCard('add_bankBlockchain')">{{
+                      t('Custom.Withdraw.addBank1') }}</text>
+                  </view>
+                  <uni-forms-item :label="t('blockchain.item10')">
+                    <cwg-combox :clearable="false" v-model:value="selectedDigitalIndex" :options="digitalOptions"
+                      :placeholder="t('placeholder.choose')" @change="onDigitalCurrencyChange"
+                      :disabled="!ruleForm.bankBlockchain.length" />
+                  </uni-forms-item>
+                  <uni-row>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                      <uni-forms-item :label="t('blockchain.item3')">
+                        <uni-easyinput disabled v-model="form.addressName" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                      <uni-forms-item :label="t('blockchain.item4')">
+                        <uni-easyinput disabled v-model="form.address" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="form.addressProve">
+                      <uni-forms-item :label="t('blockchain.item5')">
+                        <view class="proof">
+                          <template v-if="form.addressProve && (form.addressProve.slice(-3).toLowerCase() === 'pdf')">
+                            <a :href="imgUrl + form.addressProve" target="_blank" class="state crm_state_blue">PDF</a>
+                          </template>
+                          <image v-else :src="imgUrl + form.addressProve" mode="aspectFit"
+                            style="width: 100rpx; height: 100rpx;" @click="previewImage(imgUrl + form.addressProve)" />
+                        </view>
+                      </uni-forms-item>
+                    </uni-col>
+                  </uni-row>
+                  <text class="tit"><text class="iconfont iconi"></text>{{ t('Custom.Deposit.Des') }}</text>
+                </uni-col>
+
+                <!-- 银行卡/信用卡选择 -->
+                <uni-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24"
+                  v-if="['BANK', 'BANK_TELEGRAPHIC', 'CHANNEL_TYPE_CARD'].includes(channelData.type)">
+                  <view class="add-back" v-if="channelData.type === 'BANK_TELEGRAPHIC'">
+                    <text>{{ t('Custom.Withdraw.addWire') }}</text>
+                    <text class="add-btn crm-cursor" @click="openAddBankCard('add_wireTransfer')">{{
+                      t('Custom.Withdraw.addBank1') }}</text>
+                  </view>
+                  <view class="add-back" v-else-if="channelData.type === 'BANK'">
+                    <text>{{ t('Custom.Withdraw.addBank') }}</text>
+                    <text class="add-btn crm-cursor" @click="openAddBankCard('add_bankCard')">{{
+                      t('Custom.Withdraw.addBank1')
+                    }}</text>
+                  </view>
+                  <view class="add-back" v-else-if="channelData.type === 'CHANNEL_TYPE_CARD'">
+                    <text>{{ t('PersonalManagement.Label.addCreditCard') }}</text>
+                    <text class="add-btn crm-cursor" @click="openAddBankCard('add_CreditCard')">{{
+                      t('Custom.Withdraw.addBank1') }}</text>
+                  </view>
+
+                  <uni-forms-item :label="t('placeholder.choose')">
+                    <cwg-combox :clearable="false" v-model:value="selectedBankCardIndex" :options="bankCardOptions"
+                      :placeholder="t('placeholder.choose')" @change="onBankCardChange" />
+                  </uni-forms-item>
+
+                  <!-- 通用银行信息展示 -->
+                  <uni-row>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="form.bankUname">
+                      <uni-forms-item :label="t('Custom.Withdraw.UserName')">
+                        <uni-easyinput disabled v-model="form.bankUname" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="form.bankCardNum">
+                      <uni-forms-item :label="t('Custom.Withdraw.BankCardNum')">
+                        <uni-easyinput disabled v-model="form.bankCardNum" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="form.bankName">
+                      <uni-forms-item :label="t('Custom.Withdraw.BankName')">
+                        <uni-easyinput disabled v-model="form.bankName" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="form.bankBranchName">
+                      <uni-forms-item :label="t('Custom.Withdraw.bankBranchName')">
+                        <uni-easyinput disabled v-model="form.bankBranchName" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="form.swiftCode">
+                      <uni-forms-item :label="t('Custom.Withdraw.swiftCode')">
+                        <uni-easyinput disabled v-model="form.swiftCode" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="form.customBankCode">
+                      <uni-forms-item :label="t('Custom.Withdraw.bankCode')">
+                        <uni-easyinput disabled v-model="form.customBankCode" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="form.bankAddr">
+                      <uni-forms-item :label="t('Custom.Withdraw.bankAddr')">
+                        <uni-easyinput disabled v-model="form.bankAddr" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8"
+                      v-if="channelData.type === 'BANK_TELEGRAPHIC' && form.agencyNo">
+                      <uni-forms-item label="Account Agency NO">
+                        <uni-easyinput v-model="form.agencyNo" />
+                      </uni-forms-item>
+                    </uni-col>
+                    <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8"
+                      v-if="channelData.type === 'BANK_TELEGRAPHIC' && form.cpf">
+                      <uni-forms-item label="CPF">
+                        <uni-easyinput v-model="form.cpf" />
+                      </uni-forms-item>
+                    </uni-col>
+                  </uni-row>
+                </uni-col>
+
+                <!-- 出金金额 -->
+                <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="channelData.type !== 'BANK_TELEGRAPHIC'">
+                  <uni-forms-item :label="t('Custom.Withdraw.Title3') + '(' + channelData.currency + ')'">
+                    <uni-easyinput v-model="form.amount" type="number" @input="onAmountInput" />
+                  </uni-forms-item>
+                </uni-col>
+                <template v-else>
+                  <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                    <uni-forms-item :label="t('Custom.Withdraw.CurrencyType')">
+                      <cwg-combox :clearable="false" v-model:value="form.currency"
+                        :options="[{ text: 'USD', value: 'USD' }]" @change="(val) => form.currency = val" />
+                    </uni-forms-item>
+                  </uni-col>
+                  <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+                    <uni-forms-item :label="t('Custom.Withdraw.amount')">
+                      <uni-easyinput v-model="form.amount" type="number" @input="onAmountInput" />
+                    </uni-forms-item>
+                  </uni-col>
+                </template>
+
+              </uni-row>
+
+              <!-- 协议同意 -->
+              <view class="agree">
+                <label class="checkbox">
+                  <checkbox :checked="form.agree2" @click="form.agree2 = !form.agree2" />
+                  <text class="crm-cursor" style="text-decoration: underline;" @click="dialogCheckTip = true">{{
+                    t('Custom.Withdraw.Des') }}</text>
+                </label>
+              </view>
+              <view class="agree" v-if="dialogTipsIsShow">
+                <label class="checkbox">
+                  <checkbox :checked="form.agree3" @click="form.agree3 = !form.agree3" />
+                  <text>* {{ t('Custom.Withdraw.item1') }}<br>{{ t('Custom.Withdraw.item1_1') }}<br>{{
+                    t('Custom.Withdraw.item1_2') }}</text>
+                </label>
+              </view>
+
+              <button class="s-btn" type="primary" @click="openTips">{{ t('Btn.Submit') }}</button>
+            </uni-forms>
+          </view>
+        </view>
+      </view>
+
+      <!-- 弹窗:确认信息 -->
+      <uni-popup ref="confirmPopup" type="center" :mask-click="false">
+        <view class="popup-content">
+          <text class="popup-title">{{ t('Home.page_customer.item3') }}</text>
+          <view class="popup-form">
+            <view class="popup-row"><text class="label">{{ t('Custom.Deposit.Title11') }}:</text><text>{{ loginValue
+                }}</text></view>
+            <view class="popup-row"><text class="label">{{ t('Custom.Deposit.Title22') }}:</text><text>{{ (t('lang') ===
+              'cn' || t('lang') === 'zhHant') ? channelData.name : channelData.enName }}</text></view>
+            <view class="popup-row"><text class="label">{{ t('Custom.Withdraw.Title3') }}:</text><text>{{ form.amount
+                }}({{
+                  channelData.currency }})</text></view>
+            <view class="popup-row"><text class="label">{{ t('Custom.Withdraw.item7') }}:</text><text
+                v-if="FreeNumber > 0 && dialogConfirmFee > 0"><text style="text-decoration:line-through">${{
+                  dialogConfirmFee
+                  }}</text> $0.00</text><text v-else>${{ dialogConfirmFee }}</text></view>
+          </view>
+          <view class="popup-buttons">
+            <button @click="closeConfirmPopup">{{ t('Btn.Cancel') }}</button>
+            <button type="primary" @click="submitConfirm">{{ t('Btn.Confirm') }}</button>
+          </view>
+        </view>
+      </uni-popup>
+
+      <!-- 弹窗:提交前警告 -->
+      <uni-popup ref="warningPopup" type="center">
+        <view class="popup-content">
+          <text class="popup-text">{{ t('Custom.Withdraw.item2') }}</text>
+          <view class="popup-buttons">
+            <button @click="closeWarningPopup">{{ t('Custom.Withdraw.item4') }}</button>
+            <button type="primary" @click="submitAfterWarning">{{ t('Custom.Withdraw.item3') }}</button>
+          </view>
+        </view>
+      </uni-popup>
+
+      <!-- 弹窗:结果 -->
+      <uni-popup ref="resultPopup" type="center" :mask-click="false">
+        <view class="popup-content">
+          <view class="result-icon" v-if="dialogSuccess"><text class="iconfont iconchenggong"></text></view>
+          <view class="result-icon" v-else><text class="iconfont iconjingshi"></text></view>
+          <text class="popup-text">{{ dialogMessage }}</text>
+          <view class="popup-buttons">
+            <button type="primary" @click="closeResultPopup">{{ t('Btn.Confirm') }}</button>
+            <button v-if="!dialogSuccess" @click="closeResultPopup">{{ t('Btn.Cancel') }}</button>
+          </view>
+        </view>
+      </uni-popup>
+
+      <!-- 弹窗:条款 -->
+      <uni-popup ref="tipPopup" type="center">
+        <view class="popup-content">
+          <rich-text class="popup-text"
+            :nodes="(t('lang') === 'cn' || t('lang') === 'zhHant') ? introduce.introduce : introduce.enIntroduce"></rich-text>
+          <view class="popup-buttons">
+            <button @click="closeTipPopup">{{ t('Btn.Cancel') }}</button>
+            <button type="primary" @click="closeTipPopup">{{ t('Btn.Confirm') }}</button>
+          </view>
+        </view>
+      </uni-popup>
+
+      <!-- 弹窗:等待 -->
+      <uni-popup ref="waitPopup" type="center" :mask-click="false">
+        <view class="popup-content">
+          <text class="iconfont icondengdai"></text>
+          <text class="popup-text">{{ t('ApplicationDialog.Des38') }}</text>
+        </view>
+      </uni-popup>
+
+      <!-- 弹窗:验证码 -->
+      <uni-popup ref="codePopup" type="center">
+        <view class="popup-content">
+          <text class="popup-title">{{ t('signup.form.code') }}</text>
+          <input class="code-input" v-model="emailCode" :placeholder="t('signup.form.code')" />
+          <view class="code-timer" @click="getCode">{{ getCodeString }}</view>
+          <view class="popup-buttons">
+            <button @click="closeCodePopup">{{ t('Btn.Cancel') }}</button>
+            <button type="primary" @click="submitCode">{{ t('Btn.Confirm') }}</button>
+          </view>
+        </view>
+      </uni-popup>
+
+      <!-- 抽屉:新增/修改银行信息 -->
+      <!-- <drawer :dialogInfoTradingAdd="dialogInfoTradingAdd" :addType="openType" @closeAdd="closeAdd"
+      @confirmToReload="confirmToReload" /> -->
+    </view>
+  </cwg-page-wrapper>
+
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import { useI18n } from 'vue-i18n' // uni-app 中已集成,但需配置
+import { customApi } from '@/service/custom'
+import { financialApi } from '@/service/financial'
+// import {ServiceA} from '@/service/activity'
+import Config from '@/config/index'
+import Decimal from 'decimal.js'
+// import Drawer from '@/components/Drawer.vue' // 假设抽屉组件已存在
+import PaymentMethodsList from './components/PaymentMethodsList.vue'
+
+const { t, locale } = useI18n()
+
+const isZh = computed(() => ['cn', 'zhHant'].includes(locale.value))
+
+const loginComboxOptions = computed(() => {
+  return loginOptions.value.map((item, index) => ({
+    text: item.label,
+    value: item.login
+  }))
+})
+
+const bankOptions = computed(() => {
+  return bankDate.value.map((item, index) => ({
+    text: isZh.value ? item.name : item.enName,
+    value: index
+  }))
+})
+
+const digitalOptions = computed(() => {
+  return ruleForm.bankBlockchain.map((item, index) => ({
+    text: `${item.addressName}-${item.address}`,
+    value: index
+  }))
+})
+
+const bankCardOptions = computed(() => {
+  return bankList.value.map((item, index) => ({
+    text: getBankLabel(item),
+    value: index
+  }))
+})
+
+const getWalletLabel = computed(() => {
+  if (channelData.value.type === 'CHANNEL_TYPE_WALLET') return t('Custom.Withdraw.Title7')
+  if (channelData.value.type === 'UCARD_WALLET') return t('card.title')
+  if (channelData.value.type === 'CHANNEL_TYPE_ALI_WALLET') return t('Label.AliAccout')
+  return ''
+})
+
+const { Code, Host80 } = Config
+const imgUrl = Host80
+
+// 工具函数
+const Session = {
+  get: (key, parse = false) => {
+    const val = uni.getStorageSync(key)
+    return parse ? JSON.parse(val) : val
+  },
+  set: (key, val) => uni.setStorageSync(key, val)
+}
+
+// 分组标题映射
+const groupTitleMap = {
+  'Ucard_Wallet': 'card.title',
+  'Digital_Currency': 'Custom.Deposit.Channel3',
+  'China_UnionPay': 'Custom.Deposit.Channel2',
+  'Electronic_Wallet': 'Custom.Deposit.Channel4',
+  'International_Transfer': 'Custom.Deposit.Channel1',
+  'CHANNEL_TYPE_CARD': 'PersonalManagement.Label.CreditCard',
+  'CHANNEL_TYPE_ALI_WALLET': 'Label.Ali'
+}
+// 数据
+const loginOptions = ref([])
+const selectedAccountIndex = ref(-1)
+const selectedAccountLabel = ref('')
+const loginValue = ref(null)
+const step2 = ref(false)
+const step3 = ref(false)
+const isStep3 = ref(false)
+const tableData = ref({
+  Ucard_Wallet: [],
+  Digital_Currency: [],
+  China_UnionPay: [],
+  Electronic_Wallet: [],
+  International_Transfer: [],
+  CHANNEL_TYPE_CARD: [],
+  CHANNEL_TYPE_ALI_WALLET: []
+})
+const channelData = ref({})
+const introduce = ref({ introduce: '', enIntroduce: '' })
+const bankDate = ref([])
+const selectedBankIndex = ref(-1)
+const selectedBankLabel = ref('')
+const ruleForm = reactive({
+  bankInfo: [],
+  bankWrit: [],
+  xykInfo: [],
+  bankBlockchain: []
+})
+const form = reactive({
+  currency: 'USD',
+  amount: '',
+  amount1: '',
+  agree2: false,
+  agree3: false,
+  address: '',
+  addressName: '',
+  addressProve: '',
+  bankUname: '',
+  bankCardNum: '',
+  bankName: '',
+  bankBranchName: '',
+  swiftCode: '',
+  customBankCode: '',
+  bankAddr: '',
+  agencyNo: '',
+  cpf: ''
+})
+const myId = ref(null)
+const bankList = computed(() => {
+  if (channelData.value.type === 'BANK') return ruleForm.bankInfo
+  if (channelData.value.type === 'BANK_TELEGRAPHIC') return ruleForm.bankWrit
+  if (channelData.value.type === 'CHANNEL_TYPE_CARD') return ruleForm.xykInfo
+  return []
+})
+const selectedBankCardIndex = ref(-1)
+const selectedBankCardLabel = ref('')
+const selectedDigitalIndex = ref(-1)
+const selectedDigitalLabel = ref('')
+const mAmount = reactive({ minAmount: '', maxAmount: '' })
+const FreeNumber = ref(0)
+const isFree = ref(false)
+const dialogTipsIsShow = ref(true)
+const dialogConfirmFee = ref(0)
+
+// 弹窗引用
+const confirmPopup = ref(null)
+const warningPopup = ref(null)
+const resultPopup = ref(null)
+const tipPopup = ref(null)
+const waitPopup = ref(null)
+const codePopup = ref(null)
+
+// 结果状态
+const dialogSuccess = ref(false)
+const dialogMessage = ref('')
+
+// 验证码
+const emailCode = ref('')
+const getCodeString = ref('')
+let timer = null
+let countdown = 59
+
+// 抽屉
+const dialogInfoTradingAdd = ref(false)
+const openType = ref('')
+
+// 其他
+const pictLoading = ref(false)
+const isChannel = ref(true)
+const bankPayType = ref('')
+const requestUrl = ref('')
+const RES = ref('')
+const flag = ref(false)
+
+// 方法
+const getDateList = async () => {
+  const res = await customApi.CustomDropdown({ platform: '' })
+  if (res.code === Code.StatusOK) {
+    loginOptions.value = res.data.map(item => ({
+      ...item,
+      label: `${item.login} - ${groupTypeName(item.type)} - ${t('Custom.Deposit.AvailableBalance')}${groupCurrency(item.currency)}${item.balance}`
+    }))
+    const route = getCurrentPages().pop().$page.options
+    if (route.login) {
+      const found = loginOptions.value.find(opt => opt.login === Number(route.login))
+      if (found) {
+        selectedAccountIndex.value = loginOptions.value.indexOf(found)
+        selectedAccountLabel.value = found.label
+        loginValue.value = found.login
+        step2.value = true
+      }
+    }
+  } else {
+    uni.showToast({ title: res.msg, icon: 'none' })
+  }
+}
+
+const groupTypeName = (type) => {
+  const map = {
+    '1': 'AccountType.ClassicAccount',
+    '2': 'AccountType.SeniorAccount',
+    '5': 'AccountType.SpeedAccount',
+    '6': 'AccountType.SpeedAccount',
+    '7': 'AccountType.StandardAccount',
+    '8': 'AccountType.CentAccount'
+  }
+  return t(map[type] || '')
+}
+
+const groupCurrency = (type) => {
+  const symbol = { GBP: '£', USD: '$', EUR: '€', USC: '¢' }[type] || '$'
+  return `: ${symbol}`
+}
+
+const getDepositList = async () => {
+  pictLoading.value = true
+  const res = await financialApi.RemitChannelList({})
+  if (res.code === Code.StatusOK) {
+    const groups = {
+      Ucard_Wallet: [],
+      Digital_Currency: [],
+      China_UnionPay: [],
+      Electronic_Wallet: [],
+      International_Transfer: [],
+      CHANNEL_TYPE_CARD: [],
+      CHANNEL_TYPE_ALI_WALLET: []
+    }
+    res.data.forEach(item => {
+      if (item.type === 'UCARD_WALLET') groups.Ucard_Wallet.push(item)
+      if (item.type === 'DIGITAL_CURRENCY') groups.Digital_Currency.push(item)
+      if (item.type === 'BANK') groups.China_UnionPay.push(item)
+      if (item.type === 'CHANNEL_TYPE_WALLET') groups.Electronic_Wallet.push(item)
+      if (item.type === 'BANK_TELEGRAPHIC') groups.International_Transfer.push(item)
+      if (item.type === 'CHANNEL_TYPE_CARD') groups.CHANNEL_TYPE_CARD.push(item)
+      if (item.type === 'CHANNEL_TYPE_ALI_WALLET') groups.CHANNEL_TYPE_ALI_WALLET.push(item)
+    })
+    tableData.value = groups
+    pictLoading.value = false
+  } else {
+    uni.showToast({ title: res.msg, icon: 'none' })
+    pictLoading.value = false
+  }
+}
+
+const getBankList = async (row) => {
+  const res = await financialApi.BankList({ channelCode: row.code })
+  if (res.code === Code.StatusOK) {
+    const data = res.data.map(j => ({
+      ...j,
+      minAmount: j.minAmount ?? row.minAmount,
+      maxAmount: j.maxAmount ?? row.maxAmount,
+      payType: row.code
+    }))
+    bankDate.value = data
+  } else {
+    uni.showToast({ title: res.msg, icon: 'none' })
+  }
+}
+
+const getBankInfo = async () => {
+  const res = await financialApi.customBankList({})
+  if (res.code === Code.StatusOK) {
+    ruleForm.bankInfo = []
+    ruleForm.bankWrit = []
+    ruleForm.xykInfo = []
+    ruleForm.bankBlockchain = []
+    res.data.forEach(item => {
+      item.customBankCode = item.bankCode
+      item.bankCode = null
+      if (item.type === 1) ruleForm.bankInfo.push(item)
+      else if (item.type === 2) ruleForm.bankWrit.push(item)
+      else if (item.type === 3) {
+        item.expiryYearMonth = `${item.expiryYear}/${item.expiryMonth}`
+        ruleForm.xykInfo.push(item)
+      } else if (item.type === 4) ruleForm.bankBlockchain.push(item)
+    })
+    // 如果有默认选中
+    const findDefault = (list, type) => list.find(b => b.defaultBank && b.type === type)
+    const defaultBank = findDefault(ruleForm.bankInfo, 1)
+    const defaultWire = findDefault(ruleForm.bankWrit, 2)
+    const defaultCard = findDefault(ruleForm.xykInfo, 3)
+    const defaultDigital = findDefault(ruleForm.bankBlockchain, 4)
+    if (channelData.value.type === 'BANK' && defaultBank) selectBankCard(defaultBank)
+    if (channelData.value.type === 'BANK_TELEGRAPHIC' && defaultWire) selectBankCard(defaultWire)
+    if (channelData.value.type === 'CHANNEL_TYPE_CARD' && defaultCard) selectBankCard(defaultCard)
+    if (channelData.value.type === 'DIGITAL_CURRENCY' && defaultDigital && defaultDigital.authStatus === 1) selectDigital(defaultDigital)
+  } else {
+    uni.showToast({ title: res.msg, icon: 'none' })
+  }
+}
+
+const selectBankCard = (item) => {
+  const index = bankList.value.findIndex(b => b.id === item.id)
+  if (index !== -1) {
+    selectedBankCardIndex.value = index
+    selectedBankCardLabel.value = getBankLabel(item)
+    Object.assign(form, item)
+  }
+}
+
+const selectDigital = (item) => {
+  const index = ruleForm.bankBlockchain.findIndex(b => b.id === item.id)
+  if (index !== -1) {
+    selectedDigitalIndex.value = index
+    selectedDigitalLabel.value = `${item.addressName}-${item.address}`
+    form.addressName = item.addressName
+    form.address = item.address
+    form.addressProve = item.addressProve
+  }
+}
+
+const getBankLabel = (item) => {
+  if (channelData.value.type === 'BANK' || channelData.value.type === 'BANK_TELEGRAPHIC') {
+    return `${item.bankName}-${item.bankCardNum}`
+  } else if (channelData.value.type === 'CHANNEL_TYPE_CARD') {
+    return item.bankCardNum
+  }
+  return ''
+}
+
+const getFreeNumber = async () => {
+  if (!isFree.value) return
+  const res = await financialApi.remainingReductionNumber({})
+  if (res.code === Code.StatusOK) {
+    FreeNumber.value = res.data || 0
+  } else {
+    uni.showToast({ title: res.msg, icon: 'none' })
+  }
+}
+
+const isNewYear24Open = () => {
+  // 简化,原逻辑是判断活动时间
+  // 根据需求决定是否保留
+}
+
+// 事件处理
+const onAccountChange = (val) => {
+  const item = loginOptions.value.find(opt => opt.login === val)
+  if (item) {
+    selectedAccountIndex.value = loginOptions.value.indexOf(item)
+    selectedAccountLabel.value = item.label
+    loginValue.value = item.login
+    step2.value = true
+    showTable()
+  }
+}
+
+const showTable = () => {
+  myId.value = null
+  step3.value = false
+  isStep3.value = false
+  isChannel.value = true
+  getDepositList()
+  Object.assign(form, { currency: 'USD', amount: '', amount1: '', agree2: false, agree3: false, address: '', addressName: '', addressProve: '', bankUname: '', bankCardNum: '', bankName: '', bankBranchName: '', swiftCode: '', customBankCode: '', bankAddr: '', agencyNo: '', cpf: '' })
+  if (bankDate.value.length) bankDate.value = []
+  selectedBankIndex.value = -1
+  selectedBankLabel.value = ''
+  selectedBankCardIndex.value = -1
+  selectedBankCardLabel.value = ''
+  selectedDigitalIndex.value = -1
+  selectedDigitalLabel.value = ''
+}
+
+const isShowStep3 = (row) => {
+  if (row.bankValid && isChannel.value) {
+    getBankList(row)
+    isChannel.value = false
+    step3.value = true
+    channelData.value = row
+    mAmount.minAmount = row.minAmount
+    mAmount.maxAmount = row.maxAmount
+  } else {
+    step3.value = true
+    bankDate.value = []
+    channelData.value = row
+    mAmount.minAmount = row.minAmount
+    mAmount.maxAmount = row.maxAmount
+  }
+  if (row.code === 'UNION_PAY_TELEGRAPHIC') {
+    // WireTransferAccount = JSON.parse(row.property) 暂略
+  }
+  if (['BANK', 'BANK_TELEGRAPHIC', 'CHANNEL_TYPE_CARD', 'DIGITAL_CURRENCY'].includes(row.type)) {
+    getBankInfo()
+    form.login = loginValue.value
+    form.payType = row.code
+    bankPayType.value = row.code
+  }
+  // 重新组织 tableData 只显示当前选中项
+  const newGroups = {
+    Ucard_Wallet: [],
+    Digital_Currency: [],
+    China_UnionPay: [],
+    Electronic_Wallet: [],
+    International_Transfer: [],
+    CHANNEL_TYPE_CARD: [],
+    CHANNEL_TYPE_ALI_WALLET: []
+  }
+  if (row.type === 'UCARD_WALLET') newGroups.Ucard_Wallet = [row]
+  if (row.type === 'DIGITAL_CURRENCY') newGroups.Digital_Currency = [row]
+  if (row.type === 'BANK') newGroups.China_UnionPay = [row]
+  if (row.type === 'CHANNEL_TYPE_WALLET') newGroups.Electronic_Wallet = [row]
+  if (row.type === 'BANK_TELEGRAPHIC') newGroups.International_Transfer = [row]
+  if (row.type === 'CHANNEL_TYPE_CARD') newGroups.CHANNEL_TYPE_CARD = [row]
+  if (row.type === 'CHANNEL_TYPE_ALI_WALLET') newGroups.CHANNEL_TYPE_ALI_WALLET = [row]
+  tableData.value = newGroups
+  introduce.value = { introduce: row.introduce, enIntroduce: row.enIntroduce }
+}
+
+const onBankChange = (val) => {
+  const index = val
+  const item = bankDate.value[index]
+  if (item) {
+    selectedBankIndex.value = index
+    selectedBankLabel.value = (t('lang') === 'cn' || t('lang') === 'zhHant') ? item.name : item.enName
+    channelData.value.rate = item.rate
+    channelData.value.transformCurrency = item.currency
+    channelData.value.feeTypeBank = item.feeType
+    channelData.value.freeBank = item.free
+    channelData.value.feeAmountBank = item.feeAmount
+  }
+}
+
+const onBankCardChange = (val) => {
+  const index = val
+  const item = bankList.value[index]
+  if (item) {
+    selectedBankCardIndex.value = index
+    selectedBankCardLabel.value = getBankLabel(item)
+    Object.assign(form, item)
+  }
+}
+
+const onDigitalCurrencyChange = (val) => {
+  const index = val
+  const item = ruleForm.bankBlockchain[index]
+  if (item && item.authStatus === 1) {
+    selectedDigitalIndex.value = index
+    selectedDigitalLabel.value = `${item.addressName}-${item.address}`
+    form.addressName = item.addressName
+    form.address = item.address
+    form.addressProve = item.addressProve
+  } else if (item && item.authStatus === 0) {
+    uni.showToast({ title: t('Msg.item11'), icon: 'none' })
+    selectedDigitalIndex.value = -1
+    selectedDigitalLabel.value = ''
+  }
+}
+
+const onAmountInput = (val) => {
+  // val is the value from uni-easyinput
+  if (val && channelData.value.rate) {
+    if (isFree.value) {
+      let feeAmount = 0
+      if (channelData.value.feeTypeBank) {
+        if (channelData.value.feeTypeBank === 1) feeAmount = Number(val) * (Number(channelData.value.freeBank || 0) / 100)
+        else if (channelData.value.feeTypeBank === 2) feeAmount = Number(channelData.value.feeAmountBank || 0)
+      } else {
+        if (channelData.value.feeType === 1) feeAmount = Number(val) * (Number(channelData.value.free || 0) / 100)
+        else if (channelData.value.feeType === 2) feeAmount = Number(channelData.value.feeAmount || 0)
+      }
+      if (FreeNumber.value > 0) {
+        form.amount1 = new Decimal(Number(val)).mul(Number(channelData.value.rate || 0)).toNumber()
+      } else {
+        form.amount1 = new Decimal(Number(val)).sub(Number(feeAmount || 0)).mul(Number(channelData.value.rate || 0)).toNumber()
+      }
+    } else {
+      form.amount1 = (val * channelData.value.rate).toFixed(2)
+    }
+    if (['CNY', 'THB', 'VND'].includes(channelData.value.transformCurrency)) {
+      form.amount1 = parseInt(form.amount1)
+    }
+  }
+}
+
+const openTips = () => {
+  // 校验
+  if (channelData.value.type === 'DIGITAL_CURRENCY' && !myId.value) {
+    uni.showToast({ title: t('blockchain.item11'), icon: 'none' })
+    return
+  }
+  if (['BANK', 'BANK_TELEGRAPHIC', 'CHANNEL_TYPE_CARD'].includes(channelData.value.type) && !selectedBankCardIndex.value !== -1) {
+    uni.showToast({ title: t('vaildate.withdrawBank.empty'), icon: 'none' })
+    return
+  }
+  // 金额校验
+  if (!form.amount) {
+    uni.showToast({ title: t('vaildate.input.empty'), icon: 'none' })
+    return
+  }
+  if (Number(form.amount) < Number(mAmount.minAmount) || Number(form.amount) > Number(mAmount.maxAmount)) {
+    uni.showToast({ title: `${t('vaildate.amount.amount')}${mAmount.minAmount} - ${mAmount.maxAmount}`, icon: 'none' })
+    return
+  }
+  if (!/^[0-9]+([.]{1}[0-9]{1,2})?$/.test(form.amount)) {
+    uni.showToast({ title: t('vaildate.amount.format'), icon: 'none' })
+    return
+  }
+  if (!form.agree2) {
+    uni.showToast({ title: t('vaildate.agree.empty'), icon: 'none' })
+    return
+  }
+  if (dialogTipsIsShow.value && !form.agree3) {
+    uni.showToast({ title: t('vaildate.agree.empty'), icon: 'none' })
+    return
+  }
+
+  if (dialogTipsIsShow.value) {
+    warningPopup.value.open()
+  } else {
+    // 直接提交,先弹出确认框
+    prepareConfirm()
+  }
+}
+
+const prepareConfirm = () => {
+  // 计算手续费
+  let feeAmount = 0
+  if (channelData.value.feeTypeBank) {
+    if (channelData.value.feeTypeBank === 1) feeAmount = Number(form.amount) * (Number(channelData.value.freeBank || 0) / 100)
+    else if (channelData.value.feeTypeBank === 2) feeAmount = Number(channelData.value.feeAmountBank || 0)
+  } else {
+    if (channelData.value.feeType === 1) feeAmount = Number(form.amount) * (Number(channelData.value.free || 0) / 100)
+    else if (channelData.value.feeType === 2) feeAmount = Number(channelData.value.feeAmount || 0)
+  }
+  dialogConfirmFee.value = feeAmount
+  confirmPopup.value.open()
+}
+
+const submitConfirm = () => {
+  confirmPopup.value.close()
+  submit()
+}
+
+const submitAfterWarning = () => {
+  warningPopup.value.close()
+  prepareConfirm()
+}
+
+const submit = async () => {
+  if (flag.value) return
+  flag.value = true
+  waitPopup.value.open()
+
+  const params = {
+    login: loginValue.value,
+    payType: channelData.value.code,
+    ...form
+  }
+
+  // 根据不同通道类型调用不同接口
+  let res = null
+  if (channelData.value.type === 'DIGITAL_CURRENCY') {
+    if (!emailCode.value) {
+      waitPopup.value.close()
+      codePopup.value.open()
+      flag.value = false
+      return
+    }
+    params.emailCode = emailCode.value
+    res = await financialApi.WithdrawAapplyDigitalCurrency(channelData.value.requestUrl, params)
+  } else if (['CHANNEL_TYPE_WALLET', 'UCARD_WALLET', 'CHANNEL_TYPE_ALI_WALLET'].includes(channelData.value.type)) {
+    res = await financialApi.WithdrawAapplyDigitalCurrency(channelData.value.requestUrl, params)
+  } else if (['BANK', 'BANK_TELEGRAPHIC', 'CHANNEL_TYPE_CARD'].includes(channelData.value.type)) {
+    res = await financialApi.WithdrawApplyBank(channelData.value.requestUrl, params)
+  }
+
+  waitPopup.value.close()
+  if (res && res.code === Code.StatusOK) {
+    dialogSuccess.value = true
+    dialogMessage.value = t('ApplicationDialog.Des1')
+    resultPopup.value.open()
+  } else {
+    dialogSuccess.value = false
+    dialogMessage.value = res?.msg || t('ApplicationDialog.Des2')
+    resultPopup.value.open()
+  }
+  flag.value = false
+}
+
+const getCode = async () => {
+  if (getCodeString.value !== t('signup.form.getCode')) return
+  const res = await financialApi.withdrawCode({})
+  if (res.code === Code.StatusOK) {
+    uni.showToast({ title: t('Msg.CodeSuccess'), icon: 'none' })
+    startCountdown()
+  } else {
+    uni.showToast({ title: res.msg, icon: 'none' })
+  }
+}
+
+const startCountdown = () => {
+  getCodeString.value = `${t('signup.form.waitCode1')}${countdown}${t('signup.form.waitCode2')}`
+  timer = setInterval(() => {
+    countdown--
+    if (countdown <= 0) {
+      clearInterval(timer)
+      timer = null
+      countdown = 59
+      getCodeString.value = t('signup.form.getCode')
+    } else {
+      getCodeString.value = `${t('signup.form.waitCode1')}${countdown}${t('signup.form.waitCode2')}`
+    }
+  }, 1000)
+}
+
+const submitCode = () => {
+  if (!emailCode.value) {
+    uni.showToast({ title: t('vaildate.code.empty'), icon: 'none' })
+    return
+  }
+  codePopup.value.close()
+  submit()
+}
+
+const openAddBankCard = (type) => {
+  openType.value = type
+  dialogInfoTradingAdd.value = true
+}
+
+const closeAdd = (val) => {
+  dialogInfoTradingAdd.value = val
+}
+
+const confirmToReload = () => {
+  dialogInfoTradingAdd.value = false
+  getBankInfo()
+}
+
+const closeConfirmPopup = () => confirmPopup.value.close()
+const closeWarningPopup = () => warningPopup.value.close()
+const closeResultPopup = () => {
+  resultPopup.value.close()
+  if (dialogSuccess.value) {
+    // 重置状态
+    showTable()
+    step2.value = false
+    step3.value = false
+    isStep3.value = false
+    selectedAccountIndex.value = -1
+    selectedAccountLabel.value = ''
+    loginValue.value = null
+  }
+}
+const closeTipPopup = () => tipPopup.value.close()
+const closeCodePopup = () => codePopup.value.close()
+
+// 预览图片
+const previewImage = (url) => {
+  uni.previewImage({ urls: [url] })
+}
+
+// 生命周期
+onLoad(() => {
+  getDateList()
+  getFreeNumber()
+  isNewYear24Open()
+  // 计算 isFree 时间判断,原逻辑略
+  isFree.value = true // 根据实际需求
+  getDepositList()
+})
+
+onUnmounted(() => {
+  if (timer) clearInterval(timer)
+})
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+
+.custom-withdraw {
+  background: var(--color-zinc-50);
+  min-height: 100vh;
+
+  .box {
+    margin-bottom: px2rpx(20);
+
+    .b-card {
+      background: #fff;
+      border-radius: px2rpx(12);
+      padding: px2rpx(20);
+      box-shadow: 0 px2rpx(4) px2rpx(12) rgba(0, 0, 0, 0.03);
+
+      .card-top {
+        .tit {
+          font-size: px2rpx(16);
+          font-weight: 600;
+          margin-bottom: px2rpx(16);
+          display: flex;
+          align-items: center;
+          color: var(--color-navy-900);
+          position: relative;
+          padding-left: 20px;
+
+          &:after {
+            content: '';
+            position: absolute;
+            left: 0;
+            top: 50%;
+            transform: translateY(-50%);
+            width: 0;
+            height: 0;
+            border-top: 6px solid transparent;
+            border-bottom: 6px solid transparent;
+            border-left: 8px solid currentColor;
+          }
+
+          .iconfont {
+            margin-right: px2rpx(8);
+            color: var(--color-primary);
+            font-size: px2rpx(18);
+          }
+        }
+      }
+
+      .channelType {
+        font-size: px2rpx(15);
+        font-weight: 600;
+        margin: px2rpx(24) 0 px2rpx(12);
+        color: var(--color-navy-700);
+        padding-left: px2rpx(8);
+        border-left: px2rpx(4) solid var(--color-primary);
+      }
+    }
+  }
+
+  .reselect-btn {
+    margin-top: px2rpx(20);
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  .s-btn {
+    &.reselect {
+      background-color: var(--color-zinc-100);
+      color: var(--color-navy-700);
+      border: none;
+      font-size: px2rpx(14);
+      padding: px2rpx(8) px2rpx(20);
+      border-radius: px2rpx(8);
+
+      &:active {
+        background-color: var(--color-zinc-200);
+      }
+    }
+
+    &[type="primary"] {
+      width: 100%;
+      height: px2rpx(48);
+      background: var(--color-navy-900);
+      color: #fff;
+      border-radius: px2rpx(12);
+      font-size: px2rpx(16);
+      font-weight: 600;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      border: none;
+      margin-top: px2rpx(30);
+      transition: all 0.2s;
+
+      &:active {
+        transform: scale(0.98);
+        background: var(--color-navy-800);
+      }
+    }
+  }
+
+  .add-back {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: px2rpx(12);
+    padding: px2rpx(12) px2rpx(16);
+    background: var(--color-zinc-100);
+    border-radius: px2rpx(8);
+
+    text {
+      font-size: px2rpx(14);
+      color: var(--color-navy-700);
+      font-weight: 500;
+    }
+
+    .add-btn {
+      color: var(--color-primary);
+      font-weight: 600;
+      text-decoration: underline;
+
+      &:active {
+        opacity: 0.7;
+      }
+    }
+  }
+
+  .proof {
+    margin-top: px2rpx(8);
+    border: px2rpx(1) dashed var(--color-zinc-300);
+    border-radius: px2rpx(8);
+    padding: px2rpx(8);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background: var(--color-zinc-50);
+
+    .state {
+      padding: px2rpx(4) px2rpx(12);
+      border-radius: px2rpx(4);
+      font-size: px2rpx(12);
+      font-weight: bold;
+    }
+  }
+
+  .agree {
+    margin: px2rpx(24) 0;
+    display: flex;
+    align-items: flex-start;
+
+    .checkbox {
+      display: flex;
+      align-items: flex-start;
+      gap: px2rpx(8);
+
+      :deep(uni-checkbox .uni-checkbox-input) {
+        border-radius: px2rpx(4);
+        width: px2rpx(18);
+        height: px2rpx(18);
+      }
+
+      text {
+        font-size: px2rpx(13);
+        color: var(--color-zinc-500);
+        line-height: 1.5;
+      }
+    }
+  }
+
+  .step3-attention {
+    background: var(--color-error-50, #fff1f0);
+    border-radius: px2rpx(12);
+    padding: px2rpx(16);
+    margin-bottom: px2rpx(20);
+
+    .attention {
+      font-size: px2rpx(14);
+      color: var(--color-error-600, #cf1322);
+      line-height: 1.6;
+    }
+
+    .btn-bottom {
+      margin-top: px2rpx(20);
+      display: flex;
+      justify-content: center;
+
+      .btn {
+        background: var(--color-error-600, #cf1322);
+        color: #fff;
+        padding: px2rpx(10) px2rpx(48);
+        border-radius: px2rpx(24);
+        font-size: px2rpx(15);
+        font-weight: 700;
+        box-shadow: 0 px2rpx(4) px2rpx(10) rgba(207, 19, 34, 0.2);
+        transition: all 0.2s;
+
+        &:active {
+          transform: scale(0.96);
+          opacity: 0.8;
+        }
+      }
+    }
+  }
+
+  :deep(.base-info-form) {
+    .uni-row1 {
+      .uni-col {
+        padding: 0 px2rpx(10) !important;
+      }
+
+      .uni-forms-item {
+        min-height: px2rpx(79);
+        margin-bottom: px2rpx(10);
+      }
+
+      .uni-select,
+      .uni-combox,
+      .uni-easyinput__content,
+      .uni-date-editor--x {
+        border: none !important;
+        background-color: var(--color-zinc-100) !important;
+        border-radius: px2rpx(8) !important;
+      }
+
+      .uni-date-x {
+        border: none !important;
+        background-color: rgba(195, 195, 195, 0) !important;
+      }
+
+      .uni-easyinput__content-input {
+        height: px2rpx(44) !important;
+      }
+    }
+  }
+
+  /* 弹窗样式美化 */
+  :deep(.uni-popup__wrapper) {
+    .popup-content {
+      background-color: #fff;
+      border-radius: px2rpx(20);
+      padding: px2rpx(24);
+      width: px2rpx(320);
+
+      .popup-title {
+        font-size: px2rpx(18);
+        font-weight: 700;
+        text-align: center;
+        margin-bottom: px2rpx(20);
+        color: var(--color-navy-900);
+        display: block;
+      }
+
+      .popup-text {
+        font-size: px2rpx(14);
+        line-height: 1.6;
+        color: var(--color-zinc-600);
+        margin-bottom: px2rpx(20);
+        display: block;
+      }
+
+      .popup-form {
+        background: var(--color-zinc-50);
+        border-radius: px2rpx(12);
+        padding: px2rpx(16);
+        margin-bottom: px2rpx(24);
+
+        .popup-row {
+          display: flex;
+          justify-content: space-between;
+          margin-bottom: px2rpx(12);
+          font-size: px2rpx(14);
+
+          &:last-child {
+            margin-bottom: 0;
+          }
+
+          .label {
+            color: var(--color-zinc-500);
+          }
+
+          text:not(.label) {
+            color: var(--color-navy-900);
+            font-weight: 500;
+          }
+        }
+      }
+
+      .popup-buttons {
+        display: flex;
+        gap: px2rpx(12);
+
+        button {
+          flex: 1;
+          height: px2rpx(44);
+          border-radius: px2rpx(10);
+          font-size: px2rpx(15);
+          font-weight: 600;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          border: none;
+
+          &[type="primary"] {
+            background: var(--color-navy-900);
+            color: #fff;
+          }
+
+          &:not([type="primary"]) {
+            background: var(--color-zinc-100);
+            color: var(--color-zinc-600);
+          }
+        }
+      }
+
+      .result-icon {
+        display: flex;
+        justify-content: center;
+        margin-bottom: px2rpx(16);
+
+        .iconfont {
+          font-size: px2rpx(48);
+
+          &.iconchenggong {
+            color: #52c41a;
+          }
+
+          &.iconjingshi {
+            color: #faad14;
+          }
+
+          &.icondengdai {
+            color: var(--color-primary);
+            animation: rotate 2s linear infinite;
+          }
+        }
+      }
+
+      .code-input {
+        background: var(--color-zinc-100);
+        border: none;
+        border-radius: px2rpx(8);
+        padding: px2rpx(12);
+        margin-bottom: px2rpx(12);
+        font-size: px2rpx(15);
+      }
+
+      .code-timer {
+        color: var(--color-primary);
+        font-size: px2rpx(13);
+        text-align: right;
+        margin-bottom: px2rpx(20);
+        font-weight: 500;
+      }
+    }
+  }
+
+  @keyframes rotate {
+    from {
+      transform: rotate(0deg);
+    }
+
+    to {
+      transform: rotate(360deg);
+    }
+  }
+}
+</style>

+ 0 - 257
pages/login/forget.vue

@@ -1,257 +0,0 @@
-<script setup>
-import { ref, reactive, watch } from "vue";
-
-import { post, get } from "@/utils/request";
-import { useRequest } from "@/composables/useRequest";
-
-const SendCodeByPhone = (params) => post("/Common/SendCodeByPhone", params);
-const ResetPwd = (params) => post("/Login/ResetPwd", params);
-
-// 响应式表单数据
-const form = ref({
-  mobile: "",
-  code: "",
-  password: "",
-});
-// 校验规则
-const rules = {
-  mobile: [
-    {
-      required: true,
-      message: "请输入用户名或手机号",
-      trigger: ["change", "blur"],
-    },
-    {
-      // 自定义验证函数,见上说明
-      validator: (rule, value, callback) => {
-        // 上面有说,返回true表示校验通过,返回false表示不通过
-        // uni.$u.test.mobile()就是返回true或者false的
-        return uni.$u.test.mobile(value);
-      },
-      message: "手机号码不正确",
-      // 触发器可以同时用blur和change
-      trigger: ["change", "blur"],
-    },
-  ],
-  code: [
-    {
-      required: true,
-      message: "请输入验证码",
-      trigger: ["change", "blur"],
-    },
-  ],
-  password: [
-    {
-      required: true,
-      message: "请输入密码",
-      trigger: ["change", "blur"],
-    },
-  ],
-};
-
-const tips = ref("");
-const value = ref("");
-const seconds = ref(60);
-const uCodeRef = ref(null);
-
-watch(value, (newValue, oldValue) => {
-  // console.log('v-model', newValue);
-});
-
-const codeChange = (text) => {
-  tips.value = text;
-};
-
-const getCode = async () => {
-  // console.log('uCodeRef.canGetCode: ', uCodeRef.value);
-  if (uCodeRef.value.canGetCode) {
-    // 模拟向后端请求验证码
-    uni.showLoading({
-      title: "正在获取验证码",
-    });
-    const data = await SendCodeByPhone({ phone: form.value.mobile });
-    console.log("data: ", data);
-    if (data) {
-      setTimeout(() => {
-        uni.hideLoading();
-        // 这里此提示会被start()方法中的提示覆盖
-        uni.$u.toast("验证码已发送");
-        // 通知验证码组件内部开始倒计时
-        uCodeRef.value.start();
-      }, 2000);
-    } else {
-      uni.hideLoading();
-    }
-  } else {
-    uni.$u.toast("倒计时结束后再发送");
-  }
-};
-
-const uFormRef = ref(null);
-function submit() {
-  uFormRef.value
-    .validate()
-    .then((valid) => {
-      if (valid) {
-        // uni.$u.toast('校验通过');
-        refresh({
-          phone: form.value.mobile,
-          code: form.value.code,
-          newPassword: form.value.password,
-        });
-      } else {
-        // uni.$u.toast('校验失败');
-      }
-    })
-    .catch(() => {
-      // 处理验证错误
-      // uni.$u.toast('校验失败');
-    });
-}
-
-// 使用组合函数
-const { data, loading, error, refresh } = useRequest(ResetPwd, {
-  initialParams: {
-    phone: form.value.mobile,
-    code: form.value.code,
-    newPassword: form.value.password,
-  },
-  immediate: false, // 默认立即执行
-});
-const token = ref("");
-watch([loading, error], () => {
-  if (!loading.value) {
-    // 加载完成
-    if (error.value) {
-      console.log("请求失败: ", error.value); // 打印错误信息
-    } else {
-      console.log("请求成功: ", data.value); // 成功时获取数据
-      uni.$u.toast("修改成功");
-      setTimeout(() => {
-        uni.navigateBack();
-      }, 1500);
-    }
-  }
-});
-const customStyle = {
-  height: "84px",
-  "border-radius": "8px",
-  background: "#f7f8fa",
-  padding: "0 20px !important",
-  position: "relative",
-};
-</script>
-<template>
-  <view>
-    <view class="company u-flex u-flex-y-center">
-      <image src="/static/images/logo.png" class="company-icon" mode="widthFix"></image>
-      <view class="company-head">
-        <view class="name">华都渠道管家</view>
-        <view class="into">专业的房产销售管理平台</view>
-      </view>
-    </view>
-    <view class="account">
-      <view>
-        <up-form :model="form" :rules="rules" ref="uFormRef">
-          <up-form-item label="" prop="mobile">
-            <up-input :customStyle="customStyle" v-model="form.mobile" border="none" placeholder="请输入用户名或手机号" />
-          </up-form-item>
-          <up-form-item label="" prop="code">
-            <up-input :customStyle="customStyle" v-model="form.code" border="none" placeholder="请输入验证码">
-              <template #suffix>
-                <up-code ref="uCodeRef" @change="codeChange" :seconds="seconds"></up-code>
-                <up-text :text="tips" @click="getCode" class="code-text"></up-text>
-              </template>
-            </up-input>
-          </up-form-item>
-
-          <up-form-item label="" prop="password">
-            <up-input :customStyle="customStyle" v-model="form.password" type="password" border="none"
-              placeholder="新密码" />
-          </up-form-item>
-        </up-form>
-      </view>
-    </view>
-
-    <button type="primary" class="regiset-btn" @click="submit">重置密码</button>
-    <navigator url="/pages/login/regist" class="account-tip">
-      还没有账号?
-      <text>立即注册</text>
-    </navigator>
-  </view>
-</template>
-
-<style>
-page {
-  padding: px2rpx(10) px2rpx(52);
-  box-sizing: border-box;
-}
-</style>
-<style lang="scss" scoped>
-@import "@/uni.scss";
-
-button {
-  background-color: #ea002a;
-  font-size: px2rpx(14);
-  font-weight: normal;
-  height: px2rpx(84);
-  line-height: px2rpx(84);
-}
-
-.company {
-  padding: px2rpx(40) 0;
-}
-
-.company-icon {
-  width: px2rpx(104);
-  height: px2rpx(104);
-  margin-right: px2rpx(14);
-}
-
-.company-head {
-  .name {
-    font-size: px2rpx(20);
-    font-weight: 500;
-    color: #ea002a;
-    margin-bottom: px2rpx(2);
-  }
-
-  .into {
-    font-size: px2rpx(13);
-    font-weight: 350;
-    color: #222222;
-  }
-}
-
-.account {
-  .input {
-    height: px2rpx(84);
-    border-radius: px2rpx(8);
-    background: #f7f8fa;
-    padding: 0 px2rpx(20) !important;
-  }
-}
-
-.regiset-btn {
-  margin: px2rpx(20) 0;
-}
-
-.account-tip {
-  color: #666666;
-  font-size: px2rpx(13);
-  text-align: center;
-
-  text {
-    color: #ea002a;
-  }
-}
-
-.code-text {
-  padding-right: px2rpx(20);
-}
-
-:deep(.u-text__value) {
-  color: #ea002a !important;
-  font-size: px2rpx(14) !important;
-}
-</style>

+ 6 - 2
pages/login/index.vue

@@ -146,7 +146,7 @@ const inputType = ref("password");
 </script>
 
 <template>
-  <cwg-page-wrapper class="login-page" :isHeaderFixed="true" :isLoginPage="true">
+  <view class="login-page" :isHeaderFixed="true" :isLoginPage="true">
     <uni-row class="demo-uni-row">
       <cwg-match-media :min-width="991">
         <uni-col :xs="24" :sm="24" :md="12" :lg="14" :xl="16" class="left-bg">
@@ -248,12 +248,16 @@ const inputType = ref("password");
         </u-button>
       </view>
     </view>
-  </cwg-page-wrapper>
+  </view>
 </template>
 
 <style lang="scss" scoped>
 @import "@/uni.scss";
 
+:deep(uni-content) {
+  padding-left: 0 !important;
+}
+
 .login-page {
   height: 100vh;
   border: none;

+ 60 - 174
pages/login/regist.vue

@@ -1,14 +1,9 @@
 <script setup>
-import { ref, reactive, watch,onMounted } from 'vue'
-import { post, get } from '@/utils/request'
-import { useRequest } from '@/composables/useRequest'
+import { ref, watch, onMounted } from 'vue'
 import { useI18n } from 'vue-i18n'
 import { useEmailCountdown } from '@/hooks/useEmailCountdown'
 import { ucardApi } from '@/api/ucard'
 import { showToast } from '@/utils/toast'
-
-const SendCodeByPhone = (params) => post('/Common/SendCodeByPhone', params)
-const PhoneLoginReg = (params) => post('/Login/PhoneLoginReg', params)
 const { t } = useI18n()
 
 const {
@@ -22,120 +17,24 @@ const {
 // 响应式表单数据
 const formData = ref({
   country: '',
-  birthDate:'',
+  birthDate: '',
   code: '',
   password: '',
   agentId: null,
   agentValue: '',
-  userType: 4,
-  userTypeName: '全民营销',
   readName: '',
   agree: '',
 })
 const ho = ref('')
 // 账号类型
 const accountType = ref(1)
-const columnsAgent = ref([])
-const columnsType = ref([
-  {
-    text: '中介',
-    value: 3,
-  },
-  {
-    text: '全民营销',
-    value: 4,
-  },
-])
-// 校验规则
-const rules = {
-  mobile: [
-    {
-      required: true,
-      message: '请输入用户名或手机号',
-      trigger: ['change', 'blur'],
-    },
-    {
-      // 自定义验证函数,见上说明
-      validator: (rule, value, callback) => {
-        // 上面有说,返回true表示校验通过,返回false表示不通过
-        // uni.$u.test.mobile()就是返回true或者false的
-        return uni.$u.test.mobile(value)
-      },
-      message: '手机号码不正确',
-      // 触发器可以同时用blur和change
-      trigger: ['change', 'blur'],
-    },
-  ],
-  code: [
-    {
-      required: true,
-      message: '请输入验证码',
-      trigger: ['change', 'blur'],
-    },
-  ],
-  password: [
-    {
-      required: true,
-      message: '请输入密码',
-      trigger: ['change', 'blur'],
-    },
-  ],
-  readName: [
-    {
-      required: true,
-      message: '请输入真实姓名',
-      trigger: ['change', 'blur'],
-    },
-  ],
-  agentValue: [
-    {
-      required: true,
-      message: '请选择中介',
-      trigger: ['change', 'blur'],
-    },
-  ],
-}
 
-const tips = ref('')
 const value = ref('')
-const seconds = ref(60)
-const uCodeRef = ref(null)
-const timer = ref(59)
-const interval = ref(null)
 
 watch(value, (newValue, oldValue) => {
   //  console.log('v-model', newValue);
 })
 
-const codeChange = (text) => {
-  tips.value = text
-}
-
-const change = (e) => {
-  //  console.log("change", e);
-}
-const showAgent = ref(false)
-const confirmAgent = (e) => {
-  //  console.log("e: ", e);
-  form.value.agentValue = e.value[0].text
-  form.value.agentId = e.value[0].value
-  showAgent.value = false
-}
-
-const showType = ref(false)
-const confirmType = (e) => {
-  //  console.log("e: ", e);
-  form.value.userTypeName = e.value[0].text
-  form.value.userType = e.value[0].value
-  if (form.value.userType == 4) {
-    form.value.agentValue = ''
-    form.value.agentId = ''
-  }
-  showType.value = false
-}
-
-const uFormRef = ref(null)
-
 // 切换注册账号类型
 const changeAccountType = (type) => {
   if (accountType.value !== type) accountType.value = type
@@ -163,50 +62,25 @@ async function sendEmailCode() {
   }
 }
 
-const aloneChecked = ref(false)
-const getRichText = (url) => {
-  uni.navigateTo({
-    url,
-  })
-}
-const GetAgencys = (params) => get('/Buss/GetAgencys', params)
-const { data, loading, error, refresh } = useRequest(GetAgencys, {
-  initialParams: {},
-  immediate: true, // 默认立即执行
-})
-onMounted(()=>{
+
+onMounted(() => {
   const hostParts = window.location.host.split('.')
   ho.value = hostParts.length > 1 ? hostParts[1] : ''
 })
-watch([loading, error], () => {
-  if (!loading.value) {
-    // 加载完成
-    if (error.value) {
-      //  console.log("请求失败: ", error.value); // 打印错误信息
-    } else {
-      //  console.log("请求成功: ", data.value); // 成功时获取数据
-      columnsAgent.value = data.value.map((item) => {
-        return {
-          text: item.name,
-          value: item.id,
-        }
-      })
-    }
-  }
-})
+
 </script>
 <template>
-  <cwg-page-wrapper class="regist-page" :isHeaderFixed="true" :isLoginPage="true">
+  <view class="regist-page" :isHeaderFixed="true" :isLoginPage="true">
     <uni-row class="content">
-      <uni-col :span="20" :offset="2" :sm="{ span: 14 , offset:5}">
+      <uni-col :span="20" :offset="2" :sm="{ span: 14, offset: 5 }">
         <view class="logo">
           <image src="/static/images/logo.png" class="company-icon" mode="widthFix"></image>
         </view>
         <!--        账号类型-->
         <view class="account-type">
-          <view class="type-btn" @click="changeAccountType(1)" :class="{active:accountType === 1}">Open Live Account
+          <view class="type-btn" @click="changeAccountType(1)" :class="{ active: accountType === 1 }">Open Live Account
           </view>
-          <view class="type-btn" @click="changeAccountType(2)" :class="{active:accountType === 2}">Register Demo
+          <view class="type-btn" @click="changeAccountType(2)" :class="{ active: accountType === 2 }">Register Demo
             Account
           </view>
         </view>
@@ -225,26 +99,28 @@ watch([loading, error], () => {
               </uni-forms-item>
             </uni-col>
             <uni-col :xs="24" :md="12">
-              <uni-forms-item  name="phone" :label="t('newSignup.item5')">
+              <uni-forms-item name="phone" :label="t('newSignup.item5')">
                 <uni-easyinput class="formStyle" v-model="formData.phone"></uni-easyinput>
               </uni-forms-item>
             </uni-col>
             <uni-col :xs="24" :md="12">
-              <uni-forms-item  name="birthDate" :label="t('newSignup.item18')">
-                <uni-datetime-picker class="formStyle" type="date" v-model="formData.birthDate" :placeholder="t('newSignup.item19')"/>
+              <uni-forms-item name="birthDate" :label="t('newSignup.item18')">
+                <uni-datetime-picker class="formStyle" type="date" v-model="formData.birthDate"
+                  :placeholder="t('newSignup.item19')" />
               </uni-forms-item>
             </uni-col>
             <uni-col :xs="24" :md="12">
-              <uni-forms-item  name="email" :label="t('newSignup.item7')">
-                <uni-easyinput class="formStyle" v-model="formData.email" :placeholder="t('newSignup.item8')"></uni-easyinput>
+              <uni-forms-item name="email" :label="t('newSignup.item7')">
+                <uni-easyinput class="formStyle" v-model="formData.email"
+                  :placeholder="t('newSignup.item8')"></uni-easyinput>
               </uni-forms-item>
             </uni-col>
             <uni-col :xs="24" :md="12">
-              <uni-forms-item  name="code" :label="t('newSignup.item7')">
+              <uni-forms-item name="code" :label="t('newSignup.item7')">
                 <uni-easyinput class="formStyle" v-model="formData.code" :placeholder="t('newSignup.item8')">
-                    <template #right>
-                      <view class="btn-code" @click="handleGetCode">{{getCodeString}}</view>
-                    </template>
+                  <template #right>
+                    <view class="btn-code" @click="handleGetCode">{{ getCodeString }}</view>
+                  </template>
                 </uni-easyinput>
               </uni-forms-item>
             </uni-col>
@@ -254,17 +130,20 @@ watch([loading, error], () => {
         </uni-forms>
         <view class="check-box">
           <up-checkbox-group v-model="formData.agree">
-            <up-checkbox size="14" labelSize="14" labelColor="#666666" activeColor="#ea002a" v-model="formData.agree" :label="t('signup.agree')" name="" class="wcg-checkbox"></up-checkbox>
+            <up-checkbox size="14" labelSize="14" labelColor="#666666" activeColor="#ea002a" v-model="formData.agree"
+              :label="t('signup.agree')" name="" class="wcg-checkbox"></up-checkbox>
           </up-checkbox-group>
         </view>
         <view class="check-box">
           <up-checkbox-group v-model="formData.isSubscribeEmail">
-            <up-checkbox size="14" labelSize="14" labelColor="#666666" activeColor="#ea002a" v-model="formData.isSubscribeEmail" :label="t('signup.agree1')" name="" class="wcg-checkbox"></up-checkbox>
+            <up-checkbox size="14" labelSize="14" labelColor="#666666" activeColor="#ea002a"
+              v-model="formData.isSubscribeEmail" :label="t('signup.agree1')" name=""
+              class="wcg-checkbox"></up-checkbox>
           </up-checkbox-group>
         </view>
         <view>
           <u-button class="regiset-btn">
-            {{t('signup.button')}}
+            {{ t('signup.button') }}
           </u-button>
         </view>
         <view class="or-title">
@@ -275,12 +154,12 @@ watch([loading, error], () => {
         <uni-row :gutter="20">
           <uni-col :xs="24" :md="12">
             <u-button class="login-btn">
-              {{t('signup.button')}}
+              {{ t('signup.button') }}
             </u-button>
           </uni-col>
           <uni-col :xs="24" :md="12">
             <u-button class="login-btn">
-              {{t('signup.button')}}
+              {{ t('signup.button') }}
             </u-button>
           </uni-col>
         </uni-row>
@@ -289,30 +168,26 @@ watch([loading, error], () => {
     </uni-row>
     <view class="des">
       <view>
-        {{t('newSignin.item12')}}
+        {{ t('newSignin.item12') }}
       </view><br />
       <view>
-        {{t('newSignin.item10')}}
+        {{ t('newSignin.item10') }}
       </view><br />
       <view>
-        {{t('newSignin.item11')}}
+        {{ t('newSignin.item11') }}
       </view><br />
       <view>{{ t('newSignin.item13') }}</view>
-      <a
-        :href="`https://www.${ho}.com/doc/Risk-Disclosures-and-Acknowledgements-2020-08.pdf`"
-        target="_blank"
-      >
+      <a :href="`https://www.${ho}.com/doc/Risk-Disclosures-and-Acknowledgements-2020-08.pdf`" target="_blank">
         {{ t('newSignin.item13_1') }}
       </a>
       <view>{{ t('newSignin.item13_2') }}</view>
       <view>{{ t('newSignin.item13_3') }}</view>
       <view>{{ t('newSignin.item13_4') }}</view>
     </view>
-  </cwg-page-wrapper>
+  </view>
 </template>
 
-<style lang="scss">
-</style>
+<style lang="scss"></style>
 <style lang="scss" scoped>
 @import "@/uni.scss";
 
@@ -323,6 +198,7 @@ watch([loading, error], () => {
 }
 
 .content {
+
   //display: flex;
   .logo {
     width: 100%;
@@ -382,27 +258,33 @@ watch([loading, error], () => {
     color: var(--gray);
   }
 }
-.formContent{
+
+.formContent {
   padding: 0 10px;
 }
+
 // 修改表单组件高度。
-:deep(.uni-stat-box){
+:deep(.uni-stat-box) {
   height: 100%;
 }
-:deep(.uni-select){
+
+:deep(.uni-select) {
   height: 100%;
 }
-:deep(.uni-easyinput__content){
+
+:deep(.uni-easyinput__content) {
   height: 100%;
 }
-:deep(.uni-date-editor){
+
+:deep(.uni-date-editor) {
   height: 100%;
 }
-:deep(.uni-date-editor--x){
+
+:deep(.uni-date-editor--x) {
   height: 100%;
 }
 
-.btn-code{
+.btn-code {
   width: 30%;
   height: 100%;
   background-color: #102047;
@@ -413,15 +295,17 @@ watch([loading, error], () => {
   border-radius: 0 4px 4px 0;
 }
 
-.check-box{
-  padding: 0  px2rpx(10);
+.check-box {
+  padding: 0 px2rpx(10);
   margin-bottom: px2rpx(10);
-  :deep(.u-checkbox){
+
+  :deep(.u-checkbox) {
     display: flex;
     align-items: flex-start;
   }
 }
-.regiset-btn{
+
+.regiset-btn {
   width: 100%;
   height: px2rpx(40);
   border-radius: px2rpx(20);
@@ -452,7 +336,7 @@ watch([loading, error], () => {
   }
 }
 
-.login-btn{
+.login-btn {
   width: 100%;
   height: px2rpx(40);
   border-radius: px2rpx(20);
@@ -474,17 +358,19 @@ watch([loading, error], () => {
   color: #000;
   font-size: 12px;
   padding: px2rpx(20) px2rpx(30);
+
   //display: none;
-  :nth-child(n){
+  :nth-child(n) {
     display: inline;
-    word-break:break-all;
-    word-wrap:break-word;
+    word-break: break-all;
+    word-wrap: break-word;
   }
 
   a {
     color: #e61f1e;
   }
 }
+
 :deep(.u-text__value) {
   color: #ea002a !important;
   font-size: px2rpx(14) !important;

+ 1 - 2
pages/mine/improve.vue

@@ -187,8 +187,7 @@ import { Patterns, Validators } from "@/utils/validators";
 import CardWebsdkLink from "@/components/card-websdkLink.vue";
 import useRouter from "@/hooks/useRouter";
 const router = useRouter();
-const userStore = useUserStore();
-const userInfo = computed(() => userStore.userInfo);
+
 const { availableIdTypeOptions, loadIdTypesConfig } = useIdTypeOptions()
 console.log(availableIdTypeOptions, 1212121, 'storeIdTypeOptionsstoreIdTypeOptions');
 

+ 5 - 0
service/custom.ts

@@ -27,6 +27,7 @@ export const customApi = {
   ChangeDealPassword: (params = {}) => post('/account/settings/change/deal/password/add', params, 'Host80'),
   // 交易账户列表
   AccountList: (params = {}) => post('/account/list', params, 'Host80'),
+  AccountAllList: (params = {}) => post('/account/all/list', params, 'Host80'),
   // 申请账户
   AccountApplyAdd: (params = {}) => post('/account/apply/add', params, 'Host80'),
   // 申请账户-dome
@@ -97,4 +98,8 @@ export const customApi = {
   getSystemList: (params = {}) => post('/custom/system/config/all/list', params, 'Host80'),
   // 切换系统
   switchSystem: (params = {}) => post('/custom/system/config/choose', params, 'Host80'),
+  // 模拟账户
+  demoList: (params = {}) => post('/account/demo/all/list', params, 'Host80'),
+  // 修改昵称
+  updateNick: (params = {}) => post('/custom/login/update/nick/name', params, 'Host80'),
 };

+ 1 - 0
static/icons/crm-caret-right.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M441.3 299.8C451.5 312.4 450.8 330.9 439.1 342.6L311.1 470.6C301.9 479.8 288.2 482.5 276.2 477.5C264.2 472.5 256.5 460.9 256.5 448L256.5 192C256.5 179.1 264.3 167.4 276.3 162.4C288.3 157.4 302 160.2 311.2 169.3L439.2 297.3L441.4 299.7z"/></svg>

TEMPAT SAMPAH
static/pdf/Client_Agreement.pdf


TEMPAT SAMPAH
static/pdf/CopyTradeUserAgreement.pdf


TEMPAT SAMPAH
static/pdf/CopyTradeUserAgreementcn.pdf


TEMPAT SAMPAH
static/pdf/DigitalCurrency_Withdrawal_Cn.pdf


TEMPAT SAMPAH
static/pdf/DigitalCurrency_Withdrawal_En.pdf


TEMPAT SAMPAH
static/pdf/PrivacyPolicy2019_01.pdf


TEMPAT SAMPAH
static/pdf/Privacy_Policy.pdf


TEMPAT SAMPAH
static/pdf/Terms&Conditions.pdf


TEMPAT SAMPAH
static/pdf/pdf1/ar.pdf


TEMPAT SAMPAH
static/pdf/pdf1/cn.pdf


TEMPAT SAMPAH
static/pdf/pdf1/en.pdf


TEMPAT SAMPAH
static/pdf/pdf1/es.pdf


TEMPAT SAMPAH
static/pdf/pdf1/ko.pdf


TEMPAT SAMPAH
static/pdf/pdf1/pt.pdf


TEMPAT SAMPAH
static/pdf/pdf1/th.pdf


TEMPAT SAMPAH
static/pdf/pdf1/vn.pdf


TEMPAT SAMPAH
static/pdf/pdf1/zhHant.pdf


TEMPAT SAMPAH
static/pdf/pdf10/Account Type Allocation Table-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf10/Account Type Allocation Table-en.pdf


TEMPAT SAMPAH
static/pdf/pdf10/Account Type Allocation Table-zhHant.pdf


TEMPAT SAMPAH
static/pdf/pdf11/Account Type Allocation Table-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf11/Account Type Allocation Table-en.pdf


TEMPAT SAMPAH
static/pdf/pdf11/Account Type Allocation Table-zhHant.pdf


TEMPAT SAMPAH
static/pdf/pdf12/Account Type Allocation Table-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Markets Prime Bonus Application Process-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Markets Prime Bonus Application Process-en.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Markets Prime Bonus Application Process-zhHant.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-ar.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-de.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-en.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-es.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-fa.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-id.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-ko.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-ms.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-pt.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-th.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-tr.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-vn.pdf


TEMPAT SAMPAH
static/pdf/pdf12/CWG Prime Bonus-zhHant.pdf


TEMPAT SAMPAH
static/pdf/pdf13/CWG Markets Prime Bonus Application Process-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf13/CWG Prime Bonus-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf2/pdf-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf2/pdf-en.pdf


TEMPAT SAMPAH
static/pdf/pdf2/pdf-es.pdf


TEMPAT SAMPAH
static/pdf/pdf2/pdf-pt.pdf


TEMPAT SAMPAH
static/pdf/pdf2/pdf-th.pdf


TEMPAT SAMPAH
static/pdf/pdf2/pdf-vn.pdf


TEMPAT SAMPAH
static/pdf/pdf2/pdf-zhHant.pdf


TEMPAT SAMPAH
static/pdf/pdf3/pdf-cn.pdf


TEMPAT SAMPAH
static/pdf/pdf3/pdf-en.pdf


TEMPAT SAMPAH
static/pdf/pdf3/pdf-zhHant.pdf


TEMPAT SAMPAH
static/pdf/pdf4/100Bonus-ar.pdf


TEMPAT SAMPAH
static/pdf/pdf4/100Bonus-en.pdf


TEMPAT SAMPAH
static/pdf/pdf4/100Bonus-es.pdf


TEMPAT SAMPAH
static/pdf/pdf4/ar.pdf


TEMPAT SAMPAH
static/pdf/pdf4/cn.pdf


TEMPAT SAMPAH
static/pdf/pdf4/de.pdf


TEMPAT SAMPAH
static/pdf/pdf4/en.pdf


TEMPAT SAMPAH
static/pdf/pdf4/es.pdf


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini