소스 검색

将提示类弹窗整理出来

zhb 2 달 전
부모
커밋
73deab0a99

+ 123 - 0
components/cwg-asset-tabs.vue

@@ -0,0 +1,123 @@
+<template>
+  <view class="asset-tabs">
+    <!-- PC/平板 标签栏 -->
+    <view class="tab-list">
+      <view
+        v-for="tab in tabs"
+        :key="tab.value"
+        class="tab-item"
+        :class="{ active: currentValue === tab.value }"
+        @click="handleClick(tab.value)"
+      >
+        <text class="tab-label">{{ tab.text }}</text>
+      </view>
+    </view>
+
+    <!-- 移动端 下拉选择器 -->
+    <cwg-combox
+      v-model:value="currentValue"
+      :clearable="false"
+      :options="tabs"
+      :placeholder="t('placeholder.choose')"
+      class="tab-picker"
+    />
+  </view>
+</template>
+
+<script setup>
+import { ref, watch } from 'vue'
+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()
+
+// Props 定义
+const props = defineProps({
+  tabs: {
+    type: Array,
+    required: true
+  },
+  // v-model 绑定的值
+  modelValue: {
+    type: [String, Number],
+    required: true
+  }
+})
+
+// Emits 定义
+const emit = defineEmits(['update:modelValue'])
+
+// 内部状态,同步 props.modelValue
+const currentValue = ref(props.modelValue)
+
+// 监听 props.modelValue 变化,更新内部状态
+watch(() => props.modelValue, (newVal) => {
+  if (newVal !== currentValue.value) {
+    currentValue.value = newVal
+  }
+})
+
+// 监听内部状态变化,触发 update:modelValue 事件
+watch(currentValue, (newVal) => {
+  emit('update:modelValue', newVal)
+})
+
+// 点击标签切换
+const handleClick = (value) => {
+  if (value === currentValue.value) return
+  currentValue.value = value
+}
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+
+.asset-tabs {
+  position: relative;
+  width: 100%;
+  margin-bottom: px2rpx(24);
+  background-color: #fff;
+}
+
+.tab-list {
+  display: flex;
+  gap: px2rpx(20);
+  margin: 0;
+  padding: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+
+.tab-item {
+  text-align: center;
+  cursor: pointer;
+  padding: px2rpx(12) 0;
+}
+
+.tab-label {
+  font-size: px2rpx(14);
+  color: #666;
+  transition: all 0.3s;
+}
+
+.tab-item.active .tab-label {
+  color: var(--color-primary);
+  font-weight: 500;
+  border-bottom: 2px solid var(--color-primary);
+  padding-bottom: px2rpx(10);
+}
+
+.tab-picker {
+  display: none;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+@media (max-width: 768px) {
+  .tab-list {
+    display: none;
+  }
+
+  .tab-picker {
+    display: block;
+  }
+}
+</style>

+ 197 - 0
components/cwg-check-popup.vue

@@ -0,0 +1,197 @@
+<template>
+    <cwg-popup v-model:visible="visible" type="center" :mask-click="false" :show-footers="true">
+        <view class="popup-content" v-if="isSuccess">
+            <view class="icon"><cwg-icon name="verified" :size="80" color="#009933" /></view>
+            <view class="des1">{{ t('ApplicationDialog.Des1') }}</view>
+        </view>
+        <view class="popup-content" v-else>
+            <view class="icon"><cwg-icon name="gy" :size="80" color="#eb3f57" /></view>
+            <view class="des1">{{ responseMessage }}</view>
+        </view>
+        <template #footer>
+            <button type="primary" @click="closeDia">{{ t('Btn.Confirm') }}</button>
+            <button @click="closeDia">{{ t('Btn.Cancel') }}</button>
+        </template>
+    </cwg-popup>
+</template>
+
+<script setup>
+import { computed } from 'vue';
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    },
+    isSuccess: {
+        type: Boolean,
+        default: true
+    },
+    responseMessage: {
+        type: String,
+        default: ''
+    }
+});
+
+const emit = defineEmits(['update:visible', 'confirm']);
+
+const { t } = useI18n();
+
+// Watch for changes in visible prop and emit update event
+const visible = computed({
+    get: () => props.visible,
+    set: (value) => emit('update:visible', value)
+});
+const closeDia = () => {
+    visible.value = false;
+    emit('confirm');
+}
+</script>
+
+<style lang="scss" scoped>
+.clause-popup {
+    width: 90%;
+    max-width: 800px;
+    max-height: 80vh;
+    overflow: hidden;
+
+    .clause-content {
+        padding: 20px;
+
+        scroll-view {
+            width: 100%;
+
+            h4 {
+                font-size: 16px;
+                font-weight: 600;
+                color: #303133;
+                margin-bottom: 12px;
+            }
+
+            ul {
+                margin-bottom: 20px;
+
+                li {
+                    margin-bottom: 8px;
+                    line-height: 1.5;
+                    color: #606266;
+                }
+            }
+
+            table {
+                margin: 16px 0;
+                width: 100%;
+                border-collapse: collapse;
+
+                th,
+                td {
+                    padding: 10px;
+                    text-align: center;
+                    border: 1px solid #dcdfe6;
+                    font-size: 14px;
+                }
+
+                th {
+                    background: #f5f7fa;
+                    font-weight: 600;
+                    color: #303133;
+                }
+
+                td {
+                    color: #606266;
+                }
+            }
+
+            // Handle v-html content
+            div {
+                line-height: 1.6;
+                color: #606266;
+
+                p {
+                    margin-bottom: 12px;
+                }
+
+                h1,
+                h2,
+                h3,
+                h4,
+                h5,
+                h6 {
+                    margin: 16px 0 8px 0;
+                    color: #303133;
+                }
+
+                ul,
+                ol {
+                    margin-left: 20px;
+                    margin-bottom: 12px;
+                }
+
+                li {
+                    margin-bottom: 4px;
+                }
+            }
+        }
+    }
+
+    .clause-footer {
+        padding: 16px 20px;
+        border-top: 1px solid #e4e7ed;
+        display: flex;
+        justify-content: center;
+
+        button {
+            min-width: 120px;
+            padding: 10px 20px;
+            border-radius: 4px;
+        }
+    }
+}
+
+// Responsive styles
+@media (max-width: 768px) {
+    .clause-popup {
+        width: 95%;
+        max-height: 85vh;
+
+        .clause-header {
+            padding: 12px 16px;
+
+            .clause-title {
+                font-size: 16px;
+            }
+        }
+
+        .clause-content {
+            padding: 16px;
+
+            scroll-view {
+                height: 50vh;
+
+                h4 {
+                    font-size: 14px;
+                }
+
+                table {
+
+                    th,
+                    td {
+                        padding: 8px;
+                        font-size: 12px;
+                    }
+                }
+            }
+        }
+
+        .clause-footer {
+            padding: 12px 16px;
+
+            button {
+                min-width: 100px;
+                padding: 8px 16px;
+            }
+        }
+    }
+}
+</style>

+ 1 - 0
components/cwg-custom-footer.vue

@@ -32,6 +32,7 @@ const linkList = [
     { text: 'signup.agreemnet2', url: 'pdf/Client_Agreement.pdf' },
     { text: 'signup.agreemnet4', url: 'pdf/Terms&Conditions.pdf' },
     { text: 'signup.agreemnet6', url: 'pdf/Privacy_Policy.pdf' },
+    { text: 'news_add_field.OpenAccount.Des2', url: 'pdf/PrivacyPolicy2019_01.pdf' }
 ]
 const openLink = (url) => {
     openLocalPdf(url)

+ 185 - 0
components/cwg-dont-active-popup.vue

@@ -0,0 +1,185 @@
+<template>
+    <cwg-popup v-model:visible="visible" type="center" :mask-click="false" :show-footers="true">
+        <view class="popup-content">
+            <view class="des1" style="font-size: 16px; line-height: 1.6; margin: 30px 0 50px">{{
+                t('Custom.Withdraw.item9') }}</view>
+        </view>
+        <template #footer>
+            <button type="primary" @click="tosubmitConfirm">{{ t('Btn.Confirm') }}</button>
+            <button @click="visible = false">{{ t('Btn.Cancel') }}</button>
+        </template>
+    </cwg-popup>
+</template>
+
+<script setup>
+import { computed } from 'vue';
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    }
+});
+
+const emit = defineEmits(['update:visible', 'confirm']);
+
+const { t } = useI18n();
+
+// Watch for changes in visible prop and emit update event
+const visible = computed({
+    get: () => props.visible,
+    set: (value) => emit('update:visible', value)
+});
+const tosubmitConfirm = () => {
+    visible.value = false;
+    emit('confirm');
+}
+</script>
+
+<style lang="scss" scoped>
+.clause-popup {
+    width: 90%;
+    max-width: 800px;
+    max-height: 80vh;
+    overflow: hidden;
+
+    .clause-content {
+        padding: 20px;
+
+        scroll-view {
+            width: 100%;
+
+            h4 {
+                font-size: 16px;
+                font-weight: 600;
+                color: #303133;
+                margin-bottom: 12px;
+            }
+
+            ul {
+                margin-bottom: 20px;
+
+                li {
+                    margin-bottom: 8px;
+                    line-height: 1.5;
+                    color: #606266;
+                }
+            }
+
+            table {
+                margin: 16px 0;
+                width: 100%;
+                border-collapse: collapse;
+
+                th,
+                td {
+                    padding: 10px;
+                    text-align: center;
+                    border: 1px solid #dcdfe6;
+                    font-size: 14px;
+                }
+
+                th {
+                    background: #f5f7fa;
+                    font-weight: 600;
+                    color: #303133;
+                }
+
+                td {
+                    color: #606266;
+                }
+            }
+
+            // Handle v-html content
+            div {
+                line-height: 1.6;
+                color: #606266;
+
+                p {
+                    margin-bottom: 12px;
+                }
+
+                h1,
+                h2,
+                h3,
+                h4,
+                h5,
+                h6 {
+                    margin: 16px 0 8px 0;
+                    color: #303133;
+                }
+
+                ul,
+                ol {
+                    margin-left: 20px;
+                    margin-bottom: 12px;
+                }
+
+                li {
+                    margin-bottom: 4px;
+                }
+            }
+        }
+    }
+
+    .clause-footer {
+        padding: 16px 20px;
+        border-top: 1px solid #e4e7ed;
+        display: flex;
+        justify-content: center;
+
+        button {
+            min-width: 120px;
+            padding: 10px 20px;
+            border-radius: 4px;
+        }
+    }
+}
+
+// Responsive styles
+@media (max-width: 768px) {
+    .clause-popup {
+        width: 95%;
+        max-height: 85vh;
+
+        .clause-header {
+            padding: 12px 16px;
+
+            .clause-title {
+                font-size: 16px;
+            }
+        }
+
+        .clause-content {
+            padding: 16px;
+
+            scroll-view {
+                height: 50vh;
+
+                h4 {
+                    font-size: 14px;
+                }
+
+                table {
+
+                    th,
+                    td {
+                        padding: 8px;
+                        font-size: 12px;
+                    }
+                }
+            }
+        }
+
+        .clause-footer {
+            padding: 12px 16px;
+
+            button {
+                min-width: 100px;
+                padding: 8px 16px;
+            }
+        }
+    }
+}
+</style>

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

@@ -26,7 +26,9 @@
 
         <view class="content-wrapper" :class="{ 'content-wrapper-padding': isContentPadding }">
           <!-- <cwg-header /> -->
-          <slot />
+          <view>
+            <slot />
+          </view>
           <cwg-custom-footer />
         </view>
       </view>
@@ -185,6 +187,10 @@ onShow(() => {
   width: 100%;
   margin: 0 auto;
   box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  min-height: calc(100vh - 56px);
   // border: 1px solid rgba(108, 133, 149, 0.12);
 }
 

+ 3 - 98
components/cwg-popup.vue

@@ -11,9 +11,8 @@
             <view class="dialog-content">
                 <slot />
             </view>
-
             <!-- 底部按钮区域 - 支持多种模式 -->
-            <view class="dialog-footer" v-if="showFooter">
+            <view class="dialog-footer" v-if="props.showFooters">
                 <!-- 自定义底部插槽 -->
                 <template v-if="$slots.footer">
                     <slot name="footer" />
@@ -64,7 +63,7 @@ const props = defineProps({
         default: ''
     },
     // 是否显示底部
-    showFooter: {
+    showFooters: {
         type: Boolean,
         default: true
     },
@@ -120,7 +119,7 @@ const props = defineProps({
         })
     }
 })
-
+console.log('props.showFooters:', props.showFooters)
 const emit = defineEmits(['update:visible', 'confirm', 'close', 'single-click'])
 
 // 弹窗引用
@@ -213,98 +212,4 @@ defineExpose({
     }
 }
 
-.dialog-footer {
-    padding: px2rpx(20) px2rpx(30) px2rpx(30);
-    border-top: 1px solid #f0f0f0;
-
-    // 双按钮模式
-    &:not(:has(button:only-child)):has(button) {
-        display: flex;
-        justify-content: flex-end;
-        gap: px2rpx(20);
-    }
-
-    // 单按钮模式
-    &:has(button:only-child) {
-        display: flex;
-        justify-content: center;
-    }
-
-    .footer-line {
-        height: 1px;
-        background-color: #f0f0f0;
-        margin: px2rpx(-20) 0 0;
-    }
-
-    button {
-        min-width: px2rpx(120);
-        height: px2rpx(40);
-        border-radius: px2rpx(4);
-        font-size: px2rpx(16);
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        border: none;
-        cursor: pointer;
-        transition: all 0.3s ease;
-
-        &:active {
-            opacity: 0.8;
-            transform: scale(0.98);
-        }
-
-        &:disabled {
-            opacity: 0.5;
-            cursor: not-allowed;
-        }
-    }
-
-    .cancel-btn {
-        background-color: #f5f5f5;
-        color: #666;
-
-        &:active {
-            background-color: #e8e8e8;
-        }
-    }
-
-    .confirm-btn {
-        &.primary {
-            background-color: #007aff;
-            color: #fff;
-
-            &:active {
-                background-color: #0056b3;
-            }
-        }
-
-        &.danger {
-            background-color: #ff6b6b;
-            color: #fff;
-
-            &:active {
-                background-color: #ff5252;
-            }
-        }
-    }
-
-    .single-btn {
-        min-width: px2rpx(200);
-
-        &.primary {
-            background-color: #007aff;
-            color: #fff;
-        }
-
-        &.danger {
-            background-color: #ff6b6b;
-            color: #fff;
-        }
-
-        &.default {
-            background-color: #f5f5f5;
-            color: #666;
-        }
-    }
-}
 </style>

+ 177 - 0
components/cwg-wait-popup.vue

@@ -0,0 +1,177 @@
+<template>
+    <cwg-popup v-model:visible="visible" type="center" :mask-click="false" :showFooters="false">
+        <view class="popup-content wait-popup">
+            <view class="icon"><cwg-icon name="icon_history" :size="80" color="#eb3f57" /></view>
+            <view class="des1">{{ t('ApplicationDialog.Des38') }}</view>
+        </view>
+    </cwg-popup>
+</template>
+
+<script setup>
+import { computed } from 'vue';
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    }
+});
+
+const emit = defineEmits(['update:visible']);
+
+const { t } = useI18n();
+
+// Watch for changes in visible prop and emit update event
+const visible = computed({
+    get: () => props.visible,
+    set: (value) => emit('update:visible', value)
+});
+</script>
+
+<style lang="scss" scoped>
+.clause-popup {
+    width: 90%;
+    max-width: 800px;
+    max-height: 80vh;
+    overflow: hidden;
+
+    .clause-content {
+        padding: 20px;
+
+        scroll-view {
+            width: 100%;
+
+            h4 {
+                font-size: 16px;
+                font-weight: 600;
+                color: #303133;
+                margin-bottom: 12px;
+            }
+
+            ul {
+                margin-bottom: 20px;
+
+                li {
+                    margin-bottom: 8px;
+                    line-height: 1.5;
+                    color: #606266;
+                }
+            }
+
+            table {
+                margin: 16px 0;
+                width: 100%;
+                border-collapse: collapse;
+
+                th,
+                td {
+                    padding: 10px;
+                    text-align: center;
+                    border: 1px solid #dcdfe6;
+                    font-size: 14px;
+                }
+
+                th {
+                    background: #f5f7fa;
+                    font-weight: 600;
+                    color: #303133;
+                }
+
+                td {
+                    color: #606266;
+                }
+            }
+
+            // Handle v-html content
+            div {
+                line-height: 1.6;
+                color: #606266;
+
+                p {
+                    margin-bottom: 12px;
+                }
+
+                h1,
+                h2,
+                h3,
+                h4,
+                h5,
+                h6 {
+                    margin: 16px 0 8px 0;
+                    color: #303133;
+                }
+
+                ul,
+                ol {
+                    margin-left: 20px;
+                    margin-bottom: 12px;
+                }
+
+                li {
+                    margin-bottom: 4px;
+                }
+            }
+        }
+    }
+
+    .clause-footer {
+        padding: 16px 20px;
+        border-top: 1px solid #e4e7ed;
+        display: flex;
+        justify-content: center;
+
+        button {
+            min-width: 120px;
+            padding: 10px 20px;
+            border-radius: 4px;
+        }
+    }
+}
+
+// Responsive styles
+@media (max-width: 768px) {
+    .clause-popup {
+        width: 95%;
+        max-height: 85vh;
+
+        .clause-header {
+            padding: 12px 16px;
+
+            .clause-title {
+                font-size: 16px;
+            }
+        }
+
+        .clause-content {
+            padding: 16px;
+
+            scroll-view {
+                height: 50vh;
+
+                h4 {
+                    font-size: 14px;
+                }
+
+                table {
+
+                    th,
+                    td {
+                        padding: 8px;
+                        font-size: 12px;
+                    }
+                }
+            }
+        }
+
+        .clause-footer {
+            padding: 12px 16px;
+
+            button {
+                min-width: 100px;
+                padding: 8px 16px;
+            }
+        }
+    }
+}
+</style>

+ 132 - 70
pages/customer/account-select.vue

@@ -1,68 +1,74 @@
 <template>
     <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
+        <cwg-header :title="t('Custom.Withdraw.Title1')" />
         <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>
+            <template v-if="loading">
+            </template>
+            <template v-else-if="standardAccounts.length > 0">
+                <!-- 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>
-            </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)"
+                    <!-- 标准账户行 -->
+                    <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 }">
-                            <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 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>
-                    </swiper-item>
-                </swiper>
-            </view>
-        </view>
-        <!-- 继续按钮 -->
-        <view class="action-button">
-            <view class="btn" @click="handleContinue">
-                <text class="button-text">继续</text>
-            </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 class="action-button">
+                    <view class="btn" @click="handleContinue">
+                        <text class="button-text">继续</text>
+                    </view>
+                </view>
+            </template>
         </view>
+
         <!-- 条款说明 -->
         <view class="terms-section">
             <text v-t="'news_add_field.OpenAccount.Des1'"></text>
@@ -77,32 +83,27 @@
 
 
 <script setup>
-import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue';
+import { ref, computed, onMounted, } 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 { t } = useI18n();
 const server = ref('')
-const showLogin = ref([])
+const showLogin = ref(null)
 const isTimeShow = ref(true)
+const loading = ref(true)
 
 onLoad((e) => {
     server.value = e.server
 })
-
-// 定义账户数据类型
-const standardAccounts = ref([
+const typeList = computed(() => [
     {
         id: 7,
         type: 'StandardAccount',
         name: 'AccountType.StandardAccount',
-        showCondition: () => showLogin.value.indexOf('7') === -1,
+        showCondition: () => showLogin.value && showLogin.value.indexOf('7') == -1,
         description: 'Custom.NewAccount.DesLogin5',
         minDeposit: '50 USD',
         minSpread: '0.01',
@@ -113,7 +114,7 @@ const standardAccounts = ref([
         id: 2,
         type: 'SeniorAccount',
         name: 'AccountType.SeniorAccount',
-        showCondition: () => showLogin.value.indexOf('2') === -1,
+        showCondition: () => showLogin.value && showLogin.value.indexOf('2') == -1,
         description: 'Custom.NewAccount.DesLogin3',
         minDeposit: '200 USD',
         minSpread: '0.01',
@@ -124,7 +125,7 @@ const standardAccounts = ref([
         id: 8,
         type: 'CentAccount',
         name: 'AccountType.CentAccount',
-        showCondition: () => showLogin.value.indexOf('8') === -1 && isTimeShow.value,
+        showCondition: () => showLogin.value && showLogin.value.indexOf('8') == -1 && isTimeShow.value,
         description: 'Custom.NewAccount.DesLogin8',
         minDeposit: '10 USD',
         minSpread: '0.01',
@@ -132,7 +133,30 @@ const standardAccounts = ref([
         icon: '/static/images/info/bank-information-3.webp',
     }
 ])
+// 定义账户数据类型
+const standardAccounts = computed(() => typeList.value.filter(account => account.showCondition()))
+
 
+const getExcludeShowLogin = async () => {
+    try {
+        let res = await customApi.excludeShowLogin({});
+        if (res.code == 200) {
+            if (res.data == null) {
+                showLogin.value = [];
+            } else {
+                showLogin.value = res.data.excludeShowLoginTypes;
+            }
+        } else {
+            console.error('获取账户显示权限失败:', res.msg);
+            showLogin.value = [];
+        }
+    } catch (error) {
+        console.error('获取账户显示权限出错:', error);
+        showLogin.value = [];
+    } finally {
+        loading.value = false;
+    }
+}
 // 过滤后的账户列表
 const filteredAccounts = computed(() => {
     return standardAccounts.value.filter(account => account.showCondition())
@@ -168,6 +192,10 @@ const handleContinue = () => {
         query: { id: selectedAccountId.value, server: server.value },
     });
 }
+//获取显示权限
+onMounted(() => {
+    getExcludeShowLogin()
+})
 </script>
 
 <style lang="scss" scoped>
@@ -176,6 +204,40 @@ const handleContinue = () => {
 .account-selector {
     background-color: #fff;
     overflow: hidden;
+    min-height: 400px;
+}
+
+.loading-container {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    height: 400px;
+
+    .loading-spinner {
+        width: 40px;
+        height: 40px;
+        border: 3px solid #f3f3f3;
+        border-top: 3px solid #1e2a3a;
+        border-radius: 50%;
+        animation: spin 1s linear infinite;
+        margin-bottom: 16px;
+    }
+
+    .loading-text {
+        font-size: 14px;
+        color: #606266;
+    }
+}
+
+@keyframes spin {
+    0% {
+        transform: rotate(0deg);
+    }
+
+    100% {
+        transform: rotate(360deg);
+    }
 }
 
 .table-wrapper {

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

@@ -1,5 +1,6 @@
 <template>
     <cwg-page-wrapper class="create-page " :isHeaderFixed="true">
+        <cwg-header :title="t('Custom.Index.AddAccount')" />
         <view class="create-card">
 
             <view class="card-bottom user-form crm-form">
@@ -419,7 +420,7 @@ const newAccount = async () => {
     flag.value = true;
     const api = dome.value ? customApi.AccountApplyAddDome : customApi.AccountApplyAdd;
     const res = await api({
-        type: isOpenAccount.value,
+        type: Number(isOpenAccount.value),
         ...formData
     });
 

+ 4 - 5
pages/customer/transfer.vue

@@ -555,7 +555,6 @@ watch(transferType, (newVal) => {
 
     .main-content {
         text-align: left;
-        padding: px2rpx(10);
 
         .box {
             padding-top: px2rpx(5);
@@ -569,7 +568,6 @@ watch(transferType, (newVal) => {
 
                 &:hover {
                     box-shadow: 0 px2rpx(2) px2rpx(8) 0 rgba(0, 0, 0, 0.1);
-                    transform: translateY(px2rpx(-1));
                 }
 
                 .card-top {
@@ -610,6 +608,7 @@ watch(transferType, (newVal) => {
                 flex-wrap: wrap;
                 margin: 0 px2rpx(-5);
                 margin-bottom: px2rpx(12);
+                gap: px2rpx(12);
 
                 &:last-child {
                     margin-bottom: 0;
@@ -617,10 +616,10 @@ watch(transferType, (newVal) => {
 
                 .form-col {
                     flex: 1;
-                    padding: 0 px2rpx(5);
                     min-width: px2rpx(140);
 
-                    @media (max-width: 750rpx) {
+                    @media screen and (max-width: 991px) {
+                        flex: 0 0 100%;
                         width: 100%;
                     }
                 }
@@ -734,7 +733,7 @@ watch(transferType, (newVal) => {
         max-width: 80%;
         margin: 0 auto;
 
-        @media (max-width: 750rpx) {
+        @media screen and (max-width: 991px) {
             min-width: 80%;
             max-width: 90%;
             margin: 0 px2rpx(10);

+ 1076 - 8
pages/ib/agent-transfer.vue

@@ -1,23 +1,1091 @@
 <template>
     <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
         <cwg-header :title="t('Home.page_ib.item9')" />
-        <view class="account-section">
+        <view id="custom_IbTransfer" class="transfer-page">
+            <view class="main-content">
+                <!-- 步骤1:选择转出账户 -->
+                <view class="box box-step1">
+                    <view class="b-card">
+                        <view class="card-top">
+                            <view class="card-row">
+                                <view class="tit">
+                                    <text class="iconfont icon-caret-right"></text>
+                                    <span>{{ t('Custom.Transfer.Title1') }}</span>
+                                </view>
+                            </view>
+                            <view class="card-row">
+                                <cwg-combox v-model:value="loginValue" :clearable="false" :options="withdrawDisplayList"
+                                    :placeholder="t('placeholder.choose')" />
+                            </view>
+                        </view>
+                    </view>
+                </view>
+
+                <!-- 步骤2:转账表单 -->
+                <view class="box box-step2" v-if="step2">
+                    <view class="b-card">
+                        <view class="card-top">
+                            <view class="card-row card-tit">
+                                <view class="title-wrapper">
+                                    <view class="tit">
+                                        <text class="iconfont icon-caret-right"></text>
+                                        <span>{{ t('Custom.Transfer.Title2') }}</span>
+                                    </view>
+                                </view>
+                            </view>
+
+                            <uni-forms ref="formRef" :model="form" :rules="rules" label-width="300" label-position="top"
+                                validate-trigger="submit">
+                                <view class="form-row">
+                                    <view class="form-col">
+                                        <!-- 转出账户 -->
+                                        <uni-forms-item :label="t('Custom.Transfer.TransferAccounts')"
+                                            name="withdrawLogin">
+                                            <cwg-combox :disabled="true" v-model:value="form.withdrawLogin"
+                                                :clearable="false" :options="withdrawDisplayList"
+                                                :placeholder="t('placeholder.choose')" />
+                                        </uni-forms-item>
+                                    </view>
+
+                                </view>
+
+                                <view class="form-row">
+                                    <view class="form-col">
+                                        <!-- 转入账户 -->
+                                        <uni-forms-item :label="t('Custom.Transfer.IntoAccount')" name="depositLogin"
+                                            :error-message="depositErrorMessage">
+                                            <cwg-combox v-model:value="form.depositLogin" :clearable="false"
+                                                :options="depositDisplayList" :placeholder="t('placeholder.choose')" />
+                                        </uni-forms-item>
+                                    </view>
+                                    <view class="form-col">
+                                        <!-- 确认转入账户 -->
+                                        <uni-forms-item :label="t('Custom.Transfer.ConfirmIntoAccount')"
+                                            name="depositLogin1" :error-message="depositLogin1ErrorMessage">
+                                            <cwg-combox v-model:value="form.depositLogin1" :clearable="false"
+                                                :options="depositDisplayList" :placeholder="t('placeholder.choose')" />
+                                        </uni-forms-item>
+                                    </view>
+
+                                </view>
+
+                                <view class="form-row">
+                                    <view class="form-col">
+                                        <!-- 货币类型 -->
+                                        <uni-forms-item :label="t('Custom.Transfer.CurrencyType')" name="currency">
+                                            <cwg-combox v-model:value="form.currency" :clearable="false"
+                                                :options="currencyOptions" :placeholder="t('placeholder.choose')" />
+                                        </uni-forms-item>
+                                    </view>
+                                    <view class="form-col">
+                                        <!-- 转账金额 -->
+                                        <uni-forms-item :label="t('Custom.Transfer.Amount')" name="amount"
+                                            :error-message="amountErrorMessage">
+                                            <uni-easyinput v-model="form.amount" :placeholder="t('placeholder.input')"
+                                                @blur="validateAmount" />
+                                        </uni-forms-item>
+                                    </view>
+                                </view>
+
+                                <!-- 20%赠金-年中赠金 -->
+                                <view class="form-row" v-if="tableData4TwoFlag">
+                                    <view class="form-col-full">
+                                        <uni-forms-item class="agree" name="agree5">
+                                            <view class="agree-content">
+                                                <checkbox :checked="form.agree5" @click="form.agree5 = !form.agree5" />
+                                                <view class="agree-text">
+                                                    <view class="agree-title">{{
+                                                        t('news_add_field1.activitiesNZTwo.itemDeposit1') }}</view>
+                                                </view>
+                                            </view>
+                                        </uni-forms-item>
+                                        <view class="agree-detail">
+                                            <text>{{ t('news_add_field1.activitiesNZTwo.itemDeposit2') }}</text>
+                                            <text class="clause" @click="dialogClauseNZTwo = true">{{
+                                                t('news_add_field1.activitiesNZTwo.itemDeposit3') }}</text>
+                                            <text>{{ t('news_add_field1.activitiesNZTwo.itemDeposit4') }}</text>
+                                        </view>
+                                    </view>
+                                </view>
+
+                                <!-- 赠送活动 -->
+                                <view class="form-row" v-if="tableDataNewListFlag">
+                                    <view class="form-col-full">
+                                        <uni-forms-item class="agree" name="agree6">
+                                            <view class="agree-content">
+                                                <checkbox :checked="form.agree6" @click="form.agree6 = !form.agree6" />
+                                                <view class="agree-text">
+                                                    <view class="agree-title">{{ tableDataNewList.title }}</view>
+                                                </view>
+                                            </view>
+                                        </uni-forms-item>
+                                        <view class="agree-detail">
+                                            <text>{{ t('news_add_field1.activitiesNewList.item1') }}</text>
+                                            <text class="clause" @click="dialogClauseNewList = true">{{
+                                                tableDataNewList.title }}</text>
+                                            <text>{{ t('news_add_field1.activitiesNewList.item2') }}</text>
+                                        </view>
+                                    </view>
+                                </view>
+
+                                <view class="form-row">
+                                    <view class="form-col-full">
+                                        <uni-forms-item>
+                                            <view class="tips">
+                                                <view class="title">{{ t('Custom.Transfer.Tips') }}</view>
+                                                <view>{{ t('Custom.Transfer.Tips1') }}</view>
+                                                <view>{{ t('Custom.Transfer.Tips5') }}</view>
+                                                <view>{{ t('Custom.Transfer.Tips3') }}</view>
+                                                <view>{{ t('Custom.Transfer.Tips4') }}</view>
+                                            </view>
+                                        </uni-forms-item>
+                                    </view>
+                                </view>
+
+                                <view class="form-row">
+                                    <view class="form-col-full">
+                                        <button class="s-btn" type="primary" @click="toTransfer" :disabled="submitting">
+                                            <span v-if="locale === 'es'">Enviar solicitud</span>
+                                            <span v-else>{{ t('Btn.Submit') }}</span>
+                                        </button>
+                                    </view>
+                                </view>
+                            </uni-forms>
+                        </view>
+                    </view>
+                </view>
+            </view>
+
+            <!-- 成功/失败弹窗 -->
+            <cwg-popup v-model:visible="dialogCheck" ref="resultPopup" type="center" :mask-click="false"
+                :showFooter="false">
+                <view class="popup-content" v-if="dialogVisible">
+                    <view class="icon"><cwg-icon name="verified" :size="80" color="#009933" /></view>
+                    <view class="des1">{{ t('ApplicationDialog.Des1') }}</view>
+                    <view class="dialog-footer">
+                        <button type="primary" @click="closeDia">{{ t('Btn.Confirm') }}</button>
+                        <button @click="closeDia">{{ t('Btn.Cancel') }}</button>
+                    </view>
+                </view>
+                <view class="popup-content" v-else>
+                    <view class="icon"><cwg-icon name="gy" :size="80" color="#eb3f57" /></view>
+                    <view class="des1">{{ responseMessage }}</view>
+                    <view class="dialog-footer">
+                        <button type="primary" @click="closeDia">{{ t('Btn.Confirm') }}</button>
+                        <button @click="closeDia">{{ t('Btn.Cancel') }}</button>
+                    </view>
+                </view>
+            </cwg-popup>
+
+            <!-- 等待弹窗 -->
+            <cwg-popup v-model:visible="dialogCheckWait" type="center" :mask-click="false" :showFooter="false">
+                <view class="popup-content wait-popup">
+                    <view class="icon"><cwg-icon name="icon_history" :size="80" color="#eb3f57" /></view>
+                    <view class="des1">{{ t('ApplicationDialog.Des38') }}</view>
+                </view>
+            </cwg-popup>
+
+            <!-- 不参加活动弹出框 -->
+            <cwg-popup v-model:visible="dialogDontActive" type="center" :mask-click="false" :showFooter="false">
+                <view class="popup-content">
+                    <view class="des1" style="font-size: 16px; line-height: 1.6; margin: 30px 0 50px">{{
+                        t('Custom.Withdraw.item9') }}</view>
+                    <view class="dialog-footer">
+                        <button type="primary" @click="tosubmitConfirm">{{ t('Btn.Confirm') }}</button>
+                        <button @click="dialogDontActive = false">{{ t('Btn.Cancel') }}</button>
+                    </view>
+                </view>
+            </cwg-popup>
+
+            <!-- 功能关闭弹出 -->
+            <cwg-popup v-model:visible="InfoStatus5" type="center" :mask-click="false" :showFooter="false">
+                <view class="popup-content">
+                    <view class="icon"><cwg-icon name="gy" :size="80" color="#eb3f57" /></view>
+                    <view class="des1">{{ t('news_add_field.Des.item1') }}</view>
+                    <view class="dialog-footer">
+                        <button type="primary" @click="toHome">{{ t('Btn.Confirm') }}</button>
+                    </view>
+                </view>
+            </cwg-popup>
+
+            <!-- 赠金协议20年中 -->
+            <BonusAgreementPopup v-model:visible="dialogClauseNZTwo" :title="t('news_add_field1.activitiesNZTwo.item6')"
+                :type="nzTwo" :tableData4Two="tableData4Two" />
+            <!-- 赠送活动协议 -->
+            <BonusAgreementPopup v-model:visible="dialogClauseNewList" :title="tableDataNewList.title"
+                :content="tableDataNewList.content" :type="newList" />
         </view>
     </cwg-page-wrapper>
 </template>
 
-<script setup lang="ts">
-import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
+<script setup>
+import { ref, reactive, computed, onMounted, watch } from 'vue'
+import { useI18n } from 'vue-i18n'
 import { onLoad } from '@dcloudio/uni-app'
-import { useI18n } from 'vue-i18n' // uni-app 中已集成,但需配置
-import { customApi } from '@/service/custom'
+import { getCurrentInstance } from 'vue'
+import { ibApi } from '@/service/ib'
+import { activityApi } from '@/service/activity'
 import { financialApi } from '@/service/financial'
 import Config from '@/config/index'
-import AddBankDialog from '@/components/AddBankDialog.vue';
-import PaymentMethodsList from './components/PaymentMethodsList.vue'
+import useUserStore from '@/stores/use-user-store'
+import BonusAgreementPopup from './components/BonusAgreementPopup.vue'
+
+const userStore = useUserStore()
+const ibInfo = computed(() => {
+    return userStore?.userInfo?.ibInfo || {}
+})
+
+const { Code } = Config
 const { t, locale } = useI18n()
-const isZh = computed(() => ['cn', 'zhHant'].includes(locale.value))
+
+// 获取全局实例(用于访问 Session、$pigeon 等)
+const { proxy } = getCurrentInstance()
+const $pigeon = proxy?.$pigeon
+
+// 响应式数据
+const loginValue = ref('')
+const flag = ref(false)
+const responseMessage = ref('') // 弹窗响应信息
+const giveLoginJoin = ref('')
+const loginOptions = ref([])
+const toOptions = ref([])
+const step2 = ref(false)
+const amountLimits = reactive({
+    minAmount: '',
+    maxAmount: '',
+})
+const form = reactive({
+    currency: 'USD',
+    depositLogin: null,
+    depositLogin1: null,
+    withdrawLogin: null,
+    amount: '',
+    agree5: false,
+    agree6: false,
+})
+const dialogCheck = ref(false)
+const dialogVisible = ref(false)
+const dialogCheckWait = ref(false)
+const InfoStatus5 = ref(false)
+const dialogClauseNZTwo = ref(false)
+const tableData4TwoFlag = ref(false)
+const tableData4Two = ref({})
+const dialogClauseNewList = ref(false)
+const tableDataNewListFlag = ref(false)
+const tableDataNewList = ref({})
+const dialogDontActive = ref(false)
+const submitting = ref(false)
+
+// 错误信息
+const depositErrorMessage = ref('')
+const depositLogin1ErrorMessage = ref('')
+const amountErrorMessage = ref('')
+
+// 表单验证规则
+const rules = {
+    withdrawLogin: {
+        rules: [
+            {
+                required: true,
+                errorMessage: t('vaildate.select.empty')
+            },
+        ],
+    },
+    depositLogin: {
+        rules: [
+            {
+                required: true,
+                errorMessage: t('vaildate.select.empty')
+            },
+        ],
+    },
+    depositLogin1: {
+        rules: [
+            {
+                required: true,
+                errorMessage: t('Custom.Transfer.ConfirmIntoAccount1')
+            },
+            {
+                validateFunction: (rule, value, data, callback) => {
+                    if (value !== form.depositLogin) {
+                        callback(t('Custom.Transfer.ConfirmIntoAccount1'))
+                    }
+                    return true
+                }
+            },
+        ],
+    },
+    amount: {
+        rules: [
+            {
+                required: true,
+                errorMessage: t('vaildate.amount.format'),
+            },
+            {
+                validateFunction: (rule, value, data, callback) => {
+                    if (!value) {
+                        callback(t('vaildate.amount.format'))
+                    } else if (
+                        amountLimits.minAmount &&
+                        amountLimits.maxAmount &&
+                        (parseFloat(amountLimits.minAmount) > parseFloat(value) ||
+                            parseFloat(amountLimits.maxAmount) < parseFloat(value))
+                    ) {
+                        callback(t('vaildate.amount.amount') +
+                            amountLimits.minAmount +
+                            '-' +
+                            amountLimits.maxAmount)
+                    } else if (!/^[0-9]+([.]{1}[0-9]{1,2})?$/.test(value)) {
+                        callback(t('vaildate.amount.format'))
+                    }
+                    return true
+                }
+            },
+        ],
+    }
+}
+
+function validateAmount() {
+    const amount = form.amount
+    if (!amount) {
+        amountErrorMessage.value = t('vaildate.amount.format')
+        return false
+    }
+    const numValue = parseFloat(amount)
+    if (isNaN(numValue)) {
+        amountErrorMessage.value = t('vaildate.amount.format')
+        return false
+    }
+    if (amountLimits.minAmount && numValue < parseFloat(amountLimits.minAmount)) {
+        amountErrorMessage.value = t('vaildate.amount.amount') + amountLimits.minAmount + '-' + amountLimits.maxAmount
+        return false
+    }
+    if (amountLimits.maxAmount && numValue > parseFloat(amountLimits.maxAmount)) {
+        amountErrorMessage.value = t('vaildate.amount.amount') + amountLimits.minAmount + '-' + amountLimits.maxAmount
+        return false
+    }
+    if (!/^[0-9]+([.]{1}[0-9]{1,2})?$/.test(amount)) {
+        amountErrorMessage.value = t('vaildate.amount.format')
+        return false
+    }
+    amountErrorMessage.value = ''
+    return true
+}
+
+// 模板引用
+const formRef = ref(null)
+
+// 计算属性
+const getInfoStatus5 = computed(() => {
+    if (ibInfo.value?.closeFunctions) {
+        return ibInfo.value.closeFunctions.indexOf('5') !== -1
+    }
+    return false
+})
+
+// 单位类型
+function groupCurrency(type) {
+    const map = { GBP: ': £', USD: ': $', EUR: ': €', USC: ': ¢' }
+    return map[type] || ': $'
+}
+
+function groupCurrency1(type) {
+    const map = { GBP: '£', USD: '$', EUR: '€', USC: '¢' }
+    return map[type] || '$'
+}
+
+// 账户类型
+function groupTypeName(type) {
+    const typeMap = {
+        '1': t('AccountType.ClassicAccount'),
+        '2': t('AccountType.SeniorAccount'),
+        '5': t('AccountType.SpeedAccount'),
+        '6': t('AccountType.SpeedAccount'),
+        '7': t('AccountType.StandardAccount'),
+        '8': t('AccountType.CentAccount')
+    }
+    return typeMap[type] || ''
+}
+
+// 转出账户列表
+const withdrawDisplayList = computed(() => {
+    return loginOptions.value.map(item => ({
+        text: `${item.login} - ${groupTypeName(item.type)} - ${t('Custom.Deposit.AvailableBalance')}${groupCurrency(item.currency)}${item.balance}`,
+        value: item.login,
+        disable: item.closeFunctions?.indexOf('3') != -1 || item.closeFunctions?.indexOf('5') != -1
+    }))
+})
+
+// 转入账户列表
+const depositDisplayList = computed(() => {
+    return toOptions.value.map(item => ({
+        text: `${item.login} - ${item.cId || '--'} - ${groupTypeName(item.type)} - ${t('Custom.Deposit.AvailableBalance')}${groupCurrency(item.currency)}${item.balance}`,
+        value: item.login
+    }))
+})
+
+const currencyOptions = ref([{ value: 'USD', text: 'USD' }])
+
+function toHome() {
+    uni.navigateTo({ url: '/pages/ib/index' })
+    InfoStatus5.value = false
+}
+
+function closeDia() {
+    formRef.value?.resetFields?.()
+    step2.value = false
+    loginValue.value = ''
+    dialogCheck.value = false
+    dialogVisible.value = false
+    tableData4TwoFlag.value = false
+    tableDataNewListFlag.value = false
+}
+
+// 内转
+async function toTransfer() {
+    if (submitting.value) return
+    try {
+        const valid = await formRef.value?.validate()
+        if (!valid) {
+            console.log('表单验证失败')
+            return
+        }
+        openDontActive()
+    } catch (error) {
+        console.error('验证失败:', error)
+    }
+}
+
+// 打开不参加活动弹窗
+function openDontActive() {
+    tosubmitConfirm()
+}
+
+function tosubmitConfirm() {
+    dialogDontActive.value = false
+    transferConfig()
+}
+async function transferConfig() {
+    if (submitting.value) return
+    submitting.value = true
+    try {
+        if (flag.value) {
+            return
+        }
+        flag.value = true
+        form.activityTwoPercentGive = form.agree5 ? 1 : 0
+        form.activityGive = form.agree6 ? 1 : 0
+        dialogCheckWait.value = true
+        const res = await ibApi.agentTransferApply({ ...form })
+        dialogCheckWait.value = false
+        if (res.code == Code.StatusOK) {
+            dialogCheck.value = true
+            dialogVisible.value = true
+            flag.value = false
+        } else {
+            responseMessage.value = res.msg
+            dialogCheck.value = true
+            dialogVisible.value = false
+            flag.value = false
+        }
+    } catch (error) {
+        console.error('转账失败:', error)
+        responseMessage.value = error.msg || t('Msg.Fail')
+        dialogCheck.value = true
+        dialogVisible.value = false
+    } finally {
+        submitting.value = false
+        flag.value = false
+        if (dialogCheckWait.value) dialogCheckWait.value = false
+    }
+}
+// 取消
+function cancle() {
+    step2.value = false
+    loginValue.value = ''
+}
+// 获取账户信息
+async function getDateList() {
+    const res = await ibApi.CustomDropdown({ platform: '' })
+    if (res.code == Code.StatusOK) {
+        loginOptions.value = res.data
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+
+// 获取转入账户信息
+async function getToDateList() {
+    const res = await ibApi.accountCustomList({})
+    if (res.code == Code.StatusOK) {
+        toOptions.value = res.data
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+
+// 获取内转数额区间
+async function getAmount() {
+    const res = await financialApi.transferInfo({})
+    if (res.code == Code.StatusOK) {
+        Object.assign(amountLimits, res.data)
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+
+async function Activity24nianzhongTwoInfo() {
+    const res = await activityApi.Activity23nianzhongTwoInfo({})
+    if (res.code == Code.StatusOK) {
+        tableData4Two.value = res.data
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+// 活动相关方法
+function togetActivity() {
+    get23nianzhongTwoLogin()
+    getActivityExtensionGiveLogin()
+    getActivityExtensionGiveLoginJoin()
+}
+
+async function get23nianzhongTwoLogin() {
+    const res = await activityApi.Activity23nianzhongTwoLogin({
+        login: form.depositLogin,
+    })
+    if (res.code == Code.StatusOK) {
+        tableData4Two.value = res.data
+        if (tableData4Two.value.show == 1) {
+            tableData4TwoFlag.value = true
+        } else if (tableData4Two.value.show == 0) {
+            tableData4TwoFlag.value = false
+        }
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+
+async function getActivityExtensionGiveLogin() {
+    const res = await activityApi.ActivityExtensionGiveLogin({
+        login: form.depositLogin,
+    })
+    if (res.code == Code.StatusOK) {
+        tableDataNewList.value = res.data
+        if (tableDataNewList.value.show == 1) {
+            tableDataNewListFlag.value = true
+        } else if (tableDataNewList.value.show == 0) {
+            tableDataNewListFlag.value = false
+        }
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+
+async function getActivityExtensionGiveLoginJoin() {
+    const res = await activityApi.ActivityExtensionGiveLoginJoin({
+        login: form.depositLogin,
+    })
+    if (res.code == Code.StatusOK) {
+        giveLoginJoin.value = res.data
+    } else {
+        $pigeon?.MessageError(res.msg)
+        giveLoginJoin.value = ''
+    }
+}
+
+// 监听 loginValue 变化
+watch(loginValue, (newVal) => {
+    if (newVal) {
+        step2.value = true
+        form.withdrawLogin = newVal
+    }
+})
+// 监听 loginValue 变化
+watch(form.depositLogin, (newVal) => {
+    if (newVal) {
+        togetActivity()
+    }
+})
+
+// 监听 agree6 变化
+watch(() => form.agree6, (newVal) => {
+    if (newVal && giveLoginJoin.value?.flag === false) {
+        let tips = ''
+        if (giveLoginJoin.value.promptType == 1) {
+            tips = t('surplusList.item10')
+        } else {
+            tips = t('surplusList.item11')
+        }
+
+        return
+        // 活动相关方法,后续需要在调整
+        if (giveLoginJoin.value.activityCategory == 1) {
+            $pigeon?.MessageConfirm(
+                tips,
+                t('Msg.SystemPrompt'),
+                t('surplusList.item12'),
+                t('Home.msg.item3'),
+                () => {
+                    $pigeon?.MessageConfirm(
+                        t('surplusList.item13'),
+                        t('Msg.SystemPrompt'),
+                        t('Btn.Confirm'),
+                        t('Btn.Cancel'),
+                        async () => {
+                            try {
+                                const res = await activityApi.ActivityGiveCancel({
+                                    login: loginValue.value,
+                                })
+                                if (res.code == Code.StatusOK) {
+                                    $pigeon?.MessageOK(res.msg || t('Msg.Success'))
+                                } else {
+                                    $pigeon?.MessageError(res.msg)
+                                }
+                            } catch (error) {
+                                $pigeon?.MessageError(t('Msg.Fail'))
+                            }
+                        },
+                        () => {
+                            form.agree6 = false
+                        }
+                    )
+                },
+                () => {
+                    form.agree6 = false
+                }
+            )
+        } else {
+            $pigeon?.MessageConfirm(
+                tips,
+                t('Msg.SystemPrompt'),
+                t('Btn.Confirm'),
+                t('Btn.Cancel'),
+                () => { },
+                () => {
+                    form.agree6 = false
+                }
+            )
+        }
+    }
+})
+onMounted(() => {
+    if (getInfoStatus5.value) {
+        InfoStatus5.value = true
+    }
+
+    getDateList()
+    getToDateList()
+    getAmount()
+    // Activity24nianzhongTwoInfo()
+})
+
+onLoad((options) => {
+    if (options?.login) {
+        loginValue.value = options.login
+        step2.value = true
+        form.withdrawLogin = options.login
+    }
+})
 </script>
+
 <style lang="scss" scoped>
 @import "@/uni.scss";
+
+.transfer-page {
+    width: 100%;
+    padding-bottom: px2rpx(20);
+
+    .main-content {
+        text-align: left;
+
+        .box {
+            padding-top: px2rpx(5);
+            color: #303133;
+
+            .b-card {
+                background-color: #fff;
+                margin-bottom: px2rpx(10);
+                border-radius: px2rpx(6);
+                box-shadow: 0 px2rpx(1) px2rpx(6) 0 rgba(0, 0, 0, 0.05);
+
+                &:hover {
+                    box-shadow: 0 px2rpx(2) px2rpx(8) 0 rgba(0, 0, 0, 0.1);
+                }
+
+                .card-top {
+                    padding: px2rpx(15) px2rpx(20);
+                    box-sizing: border-box;
+
+                    .card-row {
+                        margin-bottom: px2rpx(12);
+
+                        &:last-child {
+                            margin-bottom: 0;
+                        }
+                    }
+
+                    .tit {
+                        font-size: px2rpx(16);
+                        margin-bottom: px2rpx(12);
+                        font-weight: 600;
+
+                        .iconfont {
+                            font-size: px2rpx(18);
+                            margin-right: px2rpx(8);
+                            color: #409eff;
+                        }
+                    }
+
+                    .title-wrapper {
+                        display: flex;
+                        justify-content: space-between;
+                        align-items: center;
+                    }
+                }
+            }
+        }
+
+        .box-step2 {
+            .form-row {
+                display: flex;
+                flex-wrap: wrap;
+                margin-bottom: px2rpx(12);
+                gap: px2rpx(12);
+
+                &:last-child {
+                    margin-bottom: 0;
+                }
+
+                .form-col {
+                    flex: 1;
+                    min-width: px2rpx(140);
+
+                    @media screen and (max-width: 991px) {
+                        flex: 0 0 100%;
+                        width: 100%;
+                    }
+                }
+
+                .form-col-full {
+                    width: 100%;
+                    padding: 0 px2rpx(5);
+                }
+            }
+
+            .tips {
+                line-height: 1.8;
+                font-size: px2rpx(12);
+                color: #909399;
+                background-color: #f9f9f9;
+                padding: px2rpx(12);
+                border-radius: px2rpx(4);
+                border-left: px2rpx(2) solid #409eff;
+
+                .title {
+                    font-weight: 600;
+                    margin-bottom: px2rpx(6);
+                    color: #606266;
+                }
+            }
+        }
+    }
+
+    .picker-select {
+        background-color: #f5f7fa;
+        border: 1px solid #dcdfe6;
+        border-radius: px2rpx(4);
+        padding: px2rpx(12) px2rpx(14);
+        font-size: px2rpx(14);
+        color: #606266;
+        line-height: 1.4;
+        width: 100%;
+        box-sizing: border-box;
+
+        &:hover {
+            border-color: #409eff;
+        }
+
+        &.picker-disabled {
+            background-color: #f5f7fa;
+            color: #c0c4cc;
+            cursor: not-allowed;
+        }
+    }
+
+    .disabled-input {
+        background-color: #f5f7fa;
+        border: 1px solid #dcdfe6;
+        border-radius: px2rpx(4);
+        padding: px2rpx(12) px2rpx(14);
+        font-size: px2rpx(14);
+        color: #606266;
+        width: 100%;
+        box-sizing: border-box;
+    }
+
+    .m-input {
+        background-color: #f5f7fa;
+        border: 1px solid #dcdfe6;
+        border-radius: px2rpx(4);
+        padding: px2rpx(12) px2rpx(14);
+        font-size: px2rpx(14);
+        width: 100%;
+        box-sizing: border-box;
+
+        &:focus {
+            border-color: #409eff;
+            outline: none;
+            box-shadow: 0 0 0 px2rpx(1) rgba(64, 158, 255, 0.2);
+        }
+    }
+
+    .s-btn {
+        width: 100%;
+        padding: px2rpx(12) px2rpx(20);
+        border-radius: px2rpx(4);
+        margin: px2rpx(10) 0;
+        background-color: #409eff;
+        color: #fff;
+        border: none;
+        font-size: px2rpx(15);
+        font-weight: 500;
+        cursor: pointer;
+
+        &:hover {
+            background-color: #66b1ff;
+            transform: translateY(px2rpx(-1));
+            box-shadow: 0 px2rpx(2) px2rpx(6) 0 rgba(64, 158, 255, 0.3);
+        }
+
+        &:active {
+            background-color: #3a8ee6;
+            transform: translateY(0);
+        }
+
+        &[disabled] {
+            opacity: 0.6;
+            cursor: not-allowed;
+        }
+    }
+
+    .popup-content {
+        padding: px2rpx(30) px2rpx(20);
+        text-align: center;
+        min-width: px2rpx(250);
+        max-width: 80%;
+        margin: 0 auto;
+
+        @media screen and (max-width: 991px) {
+            min-width: 80%;
+            max-width: 90%;
+            margin: 0 px2rpx(10);
+        }
+
+        position: relative;
+
+        .icon {
+            .iconfont {
+                font-size: px2rpx(60);
+                display: block;
+                margin: 0 auto;
+            }
+
+            .icon-chenggong {
+                color: #67c23a;
+            }
+
+            .icon-jingshi {
+                color: #f56c6c;
+            }
+
+            .icon-dengdai {
+                color: #e6a23c;
+            }
+        }
+
+        .des1 {
+            font-weight: 600;
+            font-size: px2rpx(16);
+            margin: px2rpx(20) 0 px2rpx(15);
+            color: #303133;
+            line-height: 1.4;
+            padding: 0 px2rpx(10);
+        }
+
+        .dialog-footer {
+            display: flex;
+            justify-content: center;
+            gap: px2rpx(10);
+            margin-top: px2rpx(10);
+
+            @media (max-width: 750rpx) {
+                flex-direction: column;
+                align-items: center;
+                gap: px2rpx(6);
+            }
+
+            button {
+                min-width: px2rpx(90);
+                padding: 0 px2rpx(12);
+                border-radius: px2rpx(4);
+                font-size: px2rpx(14);
+                transition: all 0.3s ease;
+                cursor: pointer;
+
+                &[type="primary"] {
+                    background-color: #409eff;
+                    color: #fff;
+                    border: none;
+
+                    &:hover {
+                        background-color: #66b1ff;
+                        transform: translateY(px2rpx(-1));
+                        box-shadow: 0 px2rpx(2) px2rpx(6) 0 rgba(64, 158, 255, 0.3);
+                    }
+
+                    &:active {
+                        background-color: #3a8ee6;
+                        transform: translateY(0);
+                    }
+                }
+
+                &:not([type="primary"]) {
+                    background-color: #fff;
+                    border: 1px solid #dcdfe6;
+                    color: #606266;
+
+                    &:hover {
+                        border-color: #409eff;
+                        color: #409eff;
+                        transform: translateY(px2rpx(-1));
+                    }
+
+                    &:active {
+                        transform: translateY(0);
+                    }
+                }
+            }
+        }
+    }
+
+    .wait-popup {
+        .des1 {
+            margin-top: px2rpx(10);
+        }
+
+        .icon {
+            .iconfont {
+                animation: spin 1s linear infinite;
+            }
+        }
+    }
+}
+
+// 动画
+@keyframes popupFadeIn {
+    from {
+        opacity: 0;
+        transform: scale(0.9);
+    }
+
+    to {
+        opacity: 1;
+        transform: scale(1);
+    }
+}
+
+@keyframes fadeIn {
+    from {
+        opacity: 0;
+        transform: translateY(px2rpx(10));
+    }
+
+    to {
+        opacity: 1;
+        transform: translateY(0);
+    }
+}
+
+@keyframes pulse {
+    0% {
+        transform: scale(1);
+    }
+
+    50% {
+        transform: scale(1.05);
+    }
+
+    100% {
+        transform: scale(1);
+    }
+}
+
+@keyframes spin {
+    from {
+        transform: rotate(0deg);
+    }
+
+    to {
+        transform: rotate(360deg);
+    }
+}
+
+// 表单错误信息样式
+.uni-forms-item__error {
+    font-size: px2rpx(12);
+    color: #f56c6c;
+    margin-top: px2rpx(4);
+}
+
+// 适配不同屏幕尺寸(媒体查询中的 750rpx 保持不变)
+@media (max-width: 750rpx) {
+    .transfer-page {
+        .main-content {
+            padding: px2rpx(8);
+
+            .box {
+                .b-card {
+                    .card-top {
+                        padding: px2rpx(12) px2rpx(16);
+
+                        .tit {
+                            font-size: px2rpx(14);
+
+                            .iconfont {
+                                font-size: px2rpx(16);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        .s-btn {
+            font-size: px2rpx(14);
+            padding: px2rpx(10) px2rpx(16);
+        }
+
+        .popup-content {
+            padding: px2rpx(20) px2rpx(16);
+
+            .icon {
+                .iconfont {
+                    font-size: px2rpx(50);
+                }
+            }
+
+            .des1 {
+                font-size: px2rpx(14);
+                margin: px2rpx(15) 0 px2rpx(10);
+            }
+
+            .dialog-footer {
+                button {
+                    min-width: px2rpx(80);
+                    font-size: px2rpx(13);
+                }
+            }
+        }
+    }
+}
 </style>

+ 270 - 0
pages/ib/components/BonusAgreementPopup.vue

@@ -0,0 +1,270 @@
+<template>
+    <cwg-popup v-model:visible="visible" type="center" :title="title" :mask-click="false" :showFooter="false">
+        <view class="popup-content clause-popup">
+            <view class="clause-content" id="Agreement">
+                <scroll-view scroll-y="true" style="height: 60vh;">
+                    <view v-if="type === 'nzTwo'">
+                        <h4>{{ t('news_add_field1.activitiesNZTwo.item8') }}{{ tableData4Two.applicationStartTime }} -
+                            {{ tableData4Two.applicationEndTime }}</h4>
+                        <h4 style="margin-top: 20px">{{ t('news_add_field1.activitiesNZTwo.item10') }}</h4>
+                        <ul style="margin-left: 15px; font-size: 14px">
+                            <li>{{ t('news_add_field1.activitiesNZTwo.item11') }}</li>
+                            <li>{{ t('news_add_field1.activitiesNZTwo.item12') }}</li>
+                            <li>{{ t('news_add_field1.activitiesNZTwo.item13') }}</li>
+                            <li>{{ t('news_add_field1.activitiesNZTwo.item14') }}</li>
+                            <li v-t="'news_add_field1.activitiesNZTwo.item15'"></li>
+                            <li v-t="'news_add_field1.activitiesNZTwo.item16'"></li>
+                            <table class="nz_table" border="1" cellpadding="10" cellspacing="0" width="100%">
+                                <tr>
+                                    <th v-t="'news_add_field1.activitiesNZTwo.item31'"></th>
+                                    <th v-t="'news_add_field1.activitiesNZTwo.item41'"></th>
+                                    <th v-t="'news_add_field1.activitiesNZTwo.item51'"></th>
+                                    <th v-t="'news_add_field1.activitiesNZTwo.item61'"></th>
+                                    <th v-t="'news_add_field1.activitiesNZTwo.item71'"></th>
+                                    <th v-t="'news_add_field1.activitiesNZTwo.item81'"></th>
+                                    <th v-t="'news_add_field1.activitiesNZTwo.item91'"></th>
+                                </tr>
+                                <tr>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item32'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item42'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item52'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item62'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item72'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item82'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item92'"></td>
+                                </tr>
+                                <tr>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item33'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item43'"></td>
+                                    <td>
+                                        <span style="color: #f56c6c"
+                                            v-t="'news_add_field1.activitiesNZTwo.item53'"></span>
+                                    </td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item63'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item73'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item83'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item93'"></td>
+                                </tr>
+                                <tr>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item34'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item44'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item54'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item64'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item74'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item84'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item94'"></td>
+                                </tr>
+                                <tr>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item35'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item45'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item55'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item65'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item75'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item85'"></td>
+                                    <td v-t="'news_add_field1.activitiesNZTwo.item95'"></td>
+                                </tr>
+                            </table>
+                            <li v-t="'news_add_field1.activitiesNZTwo.item17'"></li>
+                            <li v-t="'news_add_field1.activitiesNZTwo.item18'"></li>
+                            <li v-t="'news_add_field1.activitiesNZTwo.item19'"></li>
+                            <li v-t="'news_add_field1.activitiesNZTwo.item20'"></li>
+                            <li v-t="'news_add_field1.activitiesNZTwo.item21'"></li>
+                        </ul>
+                    </view>
+                    <view v-else-if="type === 'newList'">
+                        <div v-html="content"></div>
+                    </view>
+                </scroll-view>
+            </view>
+            <view class="clause-footer">
+                <button type="primary" @click="visible = false">{{ t('Btn.Confirm') }}</button>
+            </view>
+        </view>
+    </cwg-popup>
+</template>
+
+<script setup>
+import { computed } from 'vue';
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    },
+    type: {
+        type: String,
+        default: 'nzTwo',
+        validator: (value) => ['nzTwo', 'newList'].includes(value)
+    },
+    title: {
+        type: String,
+        default: ''
+    },
+    tableData4Two: {
+        type: Object,
+        default: () => ({})
+    },
+    content: {
+        type: String,
+        default: ''
+    }
+});
+
+const emit = defineEmits(['update:visible']);
+
+const { t } = useI18n();
+
+// Watch for changes in visible prop and emit update event
+const visible = computed({
+    get: () => props.visible,
+    set: (value) => emit('update:visible', value)
+});
+</script>
+
+<style lang="scss" scoped>
+.clause-popup {
+    width: 90%;
+    max-width: 800px;
+    max-height: 80vh;
+    overflow: hidden;
+
+    .clause-content {
+        padding: 20px;
+
+        scroll-view {
+            width: 100%;
+
+            h4 {
+                font-size: 16px;
+                font-weight: 600;
+                color: #303133;
+                margin-bottom: 12px;
+            }
+
+            ul {
+                margin-bottom: 20px;
+
+                li {
+                    margin-bottom: 8px;
+                    line-height: 1.5;
+                    color: #606266;
+                }
+            }
+
+            table {
+                margin: 16px 0;
+                width: 100%;
+                border-collapse: collapse;
+
+                th,
+                td {
+                    padding: 10px;
+                    text-align: center;
+                    border: 1px solid #dcdfe6;
+                    font-size: 14px;
+                }
+
+                th {
+                    background: #f5f7fa;
+                    font-weight: 600;
+                    color: #303133;
+                }
+
+                td {
+                    color: #606266;
+                }
+            }
+
+            // Handle v-html content
+            div {
+                line-height: 1.6;
+                color: #606266;
+
+                p {
+                    margin-bottom: 12px;
+                }
+
+                h1,
+                h2,
+                h3,
+                h4,
+                h5,
+                h6 {
+                    margin: 16px 0 8px 0;
+                    color: #303133;
+                }
+
+                ul,
+                ol {
+                    margin-left: 20px;
+                    margin-bottom: 12px;
+                }
+
+                li {
+                    margin-bottom: 4px;
+                }
+            }
+        }
+    }
+
+    .clause-footer {
+        padding: 16px 20px;
+        border-top: 1px solid #e4e7ed;
+        display: flex;
+        justify-content: center;
+
+        button {
+            min-width: 120px;
+            padding: 10px 20px;
+            border-radius: 4px;
+        }
+    }
+}
+
+// Responsive styles
+@media (max-width: 768px) {
+    .clause-popup {
+        width: 95%;
+        max-height: 85vh;
+
+        .clause-header {
+            padding: 12px 16px;
+
+            .clause-title {
+                font-size: 16px;
+            }
+        }
+
+        .clause-content {
+            padding: 16px;
+
+            scroll-view {
+                height: 50vh;
+
+                h4 {
+                    font-size: 14px;
+                }
+
+                table {
+
+                    th,
+                    td {
+                        padding: 8px;
+                        font-size: 12px;
+                    }
+                }
+            }
+        }
+
+        .clause-footer {
+            padding: 12px 16px;
+
+            button {
+                min-width: 100px;
+                padding: 8px 16px;
+            }
+        }
+    }
+}
+</style>

+ 1032 - 10
pages/ib/transfer.vue

@@ -1,23 +1,1045 @@
 <template>
     <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
-        <cwg-header :title="t('Home.page_ib.item4')" />
-        <view class="account-section">
+        <cwg-header :title="t('Home.page_ib.item9')" />
+        <view id="custom_IbTransfer" class="transfer-page">
+            <view class="main-content">
+                <!-- 步骤1:选择转出账户 -->
+                <cwg-asset-tabs v-model="activeTab" :tabs="tabsConfig" />
+
+                <!-- 步骤2:转账表单 -->
+                <view class="box box-step2">
+                    <view class="b-card">
+                        <view class="card-top">
+                            <uni-forms ref="formRef" :model="form" :rules="rules" label-width="300" label-position="top"
+                                validate-trigger="submit">
+                                <view class="form-row">
+                                    <view class="form-col">
+                                        <!-- 转出账户 -->
+                                        <uni-forms-item :label="t('Custom.Transfer.TransferAccounts')">
+                                            <uni-easyinput v-model="fromInfo" disabled
+                                                :placeholder="t('placeholder.input')" @blur="validateAmount" />
+                                        </uni-forms-item>
+                                    </view>
+                                    <view class="form-col">
+                                        <!-- 转入账户 -->
+                                        <uni-forms-item :label="toLabel" name="to"
+                                            :error-message="deposittoErrorMessage">
+                                            <cwg-combox v-model:value="form.to" :clearable="false"
+                                                :options="depositDisplayList" :placeholder="t('placeholder.choose')" />
+                                        </uni-forms-item>
+                                    </view>
+                                </view>
+
+                                <view class="form-row">
+                                    <view class="form-col">
+                                        <!-- 货币类型 -->
+                                        <uni-forms-item :label="t('Custom.Transfer.CurrencyType')" name="currency">
+                                            <cwg-combox v-model:value="form.currency" :clearable="false"
+                                                :options="currencyOptions" :placeholder="t('placeholder.choose')" />
+                                        </uni-forms-item>
+                                    </view>
+                                    <view class="form-col">
+                                        <!-- 转账金额 -->
+                                        <uni-forms-item :label="t('Custom.Transfer.Amount')" name="amount"
+                                            :error-message="amountErrorMessage">
+                                            <uni-easyinput v-model="form.amount" :placeholder="t('placeholder.input')"
+                                                @blur="validateAmount" />
+                                        </uni-forms-item>
+                                    </view>
+                                </view>
+
+                                <!-- 20%赠金-年中赠金 -->
+                                <view class="form-row" v-if="tableData4TwoFlag">
+                                    <view class="form-col-full">
+                                        <uni-forms-item class="agree" name="agree5">
+                                            <view class="agree-content">
+                                                <checkbox :checked="form.agree5" @click="form.agree5 = !form.agree5" />
+                                                <view class="agree-text">
+                                                    <view class="agree-title">{{
+                                                        t('news_add_field1.activitiesNZTwo.itemDeposit1') }}</view>
+                                                </view>
+                                            </view>
+                                        </uni-forms-item>
+                                        <view class="agree-detail">
+                                            <text>{{ t('news_add_field1.activitiesNZTwo.itemDeposit2') }}</text>
+                                            <text class="clause" @click="dialogClauseNZTwo = true">{{
+                                                t('news_add_field1.activitiesNZTwo.itemDeposit3') }}</text>
+                                            <text>{{ t('news_add_field1.activitiesNZTwo.itemDeposit4') }}</text>
+                                        </view>
+                                    </view>
+                                </view>
+
+                                <!-- 赠送活动 -->
+                                <view class="form-row" v-if="tableDataNewListFlag">
+                                    <view class="form-col-full">
+                                        <uni-forms-item class="agree" name="agree6">
+                                            <view class="agree-content">
+                                                <checkbox :checked="form.agree6" @click="form.agree6 = !form.agree6" />
+                                                <view class="agree-text">
+                                                    <view class="agree-title">{{ tableDataNewList.title }}</view>
+                                                </view>
+                                            </view>
+                                        </uni-forms-item>
+                                        <view class="agree-detail">
+                                            <text>{{ t('news_add_field1.activitiesNewList.item1') }}</text>
+                                            <text class="clause" @click="dialogClauseNewList = true">{{
+                                                tableDataNewList.title }}</text>
+                                            <text>{{ t('news_add_field1.activitiesNewList.item2') }}</text>
+                                        </view>
+                                    </view>
+                                </view>
+
+                                <view class="form-row">
+                                    <view class="form-col-full">
+                                        <button class="s-btn" type="primary" @click="toTransfer" :disabled="submitting">
+                                            <span v-if="locale === 'es'">Enviar solicitud</span>
+                                            <span v-else>{{ t('Btn.Submit') }}</span>
+                                        </button>
+                                    </view>
+                                </view>
+                            </uni-forms>
+                        </view>
+                    </view>
+                </view>
+            </view>
+
+
+
+
+            <!-- 成功/失败弹窗 -->
+            <cwg-popup v-model:visible="dialogCheck" ref="resultPopup" type="center" :mask-click="false"
+                :showFooter="false">
+                <view class="popup-content" v-if="dialogVisible">
+                    <view class="icon"><cwg-icon name="verified" :size="80" color="#009933" /></view>
+                    <view class="des1">{{ t('ApplicationDialog.Des1') }}</view>
+                    <view class="dialog-footer">
+                        <button type="primary" @click="closeDia">{{ t('Btn.Confirm') }}</button>
+                        <button @click="closeDia">{{ t('Btn.Cancel') }}</button>
+                    </view>
+                </view>
+                <view class="popup-content" v-else>
+                    <view class="icon"><cwg-icon name="gy" :size="80" color="#eb3f57" /></view>
+                    <view class="des1">{{ responseMessage }}</view>
+                    <view class="dialog-footer">
+                        <button type="primary" @click="closeDia">{{ t('Btn.Confirm') }}</button>
+                        <button @click="closeDia">{{ t('Btn.Cancel') }}</button>
+                    </view>
+                </view>
+            </cwg-popup>
+
+            <!-- 等待弹窗 -->
+            <cwg-popup v-model:visible="dialogCheckWait" type="center" :mask-click="false" :showFooter="false">
+                <view class="popup-content wait-popup">
+                    <view class="icon"><cwg-icon name="icon_history" :size="80" color="#eb3f57" /></view>
+                    <view class="des1">{{ t('ApplicationDialog.Des38') }}</view>
+                </view>
+            </cwg-popup>
+
+            <!-- 不参加活动弹出框 -->
+            <cwg-popup v-model:visible="dialogDontActive" type="center" :mask-click="false" :showFooter="false">
+                <view class="popup-content">
+                    <view class="des1" style="font-size: 16px; line-height: 1.6; margin: 30px 0 50px">{{
+                        t('Custom.Withdraw.item9') }}</view>
+                    <view class="dialog-footer">
+                        <button type="primary" @click="tosubmitConfirm">{{ t('Btn.Confirm') }}</button>
+                        <button @click="dialogDontActive = false">{{ t('Btn.Cancel') }}</button>
+                    </view>
+                </view>
+            </cwg-popup>
+
+            <!-- 功能关闭弹出 -->
+            <cwg-popup v-model:visible="InfoStatus5" type="center" :mask-click="false" :showFooter="false">
+                <view class="popup-content">
+                    <view class="icon"><cwg-icon name="gy" :size="80" color="#eb3f57" /></view>
+                    <view class="des1">{{ t('news_add_field.Des.item1') }}</view>
+                    <view class="dialog-footer">
+                        <button type="primary" @click="toHome">{{ t('Btn.Confirm') }}</button>
+                    </view>
+                </view>
+            </cwg-popup>
+
+            <!-- 赠金协议20年中 -->
+            <BonusAgreementPopup v-model:visible="dialogClauseNZTwo" :title="t('news_add_field1.activitiesNZTwo.item6')"
+                :type="nzTwo" :tableData4Two="tableData4Two" />
+            <!-- 赠送活动协议 -->
+            <BonusAgreementPopup v-model:visible="dialogClauseNewList" :title="tableDataNewList.title"
+                :content="tableDataNewList.content" :type="newList" />
         </view>
     </cwg-page-wrapper>
 </template>
 
-<script setup lang="ts">
-import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
+<script setup>
+import { ref, reactive, computed, onMounted, watch } from 'vue'
+import { useI18n } from 'vue-i18n'
 import { onLoad } from '@dcloudio/uni-app'
-import { useI18n } from 'vue-i18n' // uni-app 中已集成,但需配置
-import { customApi } from '@/service/custom'
-import { financialApi } from '@/service/financial'
+import { getCurrentInstance } from 'vue'
+import { ibApi } from '@/service/ib'
+import { activityApi } from '@/service/activity'
 import Config from '@/config/index'
-import AddBankDialog from '@/components/AddBankDialog.vue';
-import PaymentMethodsList from './components/PaymentMethodsList.vue'
+import useUserStore from '@/stores/use-user-store'
+import BonusAgreementPopup from './components/BonusAgreementPopup.vue'
+
+const userStore = useUserStore()
+const ibInfo = computed(() => {
+    return userStore?.userInfo?.ibInfo || {}
+})
+
+const { Code } = Config
 const { t, locale } = useI18n()
-const isZh = computed(() => ['cn', 'zhHant'].includes(locale.value))
+const activeTab = ref(1)
+const tabsConfig = computed(() => [
+    { text: t('Ib.Transfer.CommissionTransfer'), value: 1, type: 'commission' },
+    { text: t('Ib.Transfer.CommissionIssue'), value: 2, type: 'commissionIssue' },
+    { text: t('Ib.Transfer.IbAccountTransfer'), value: 3, type: 'ib' },
+])
+
+const toLabel = computed(() => activeTab.value == '1' || activeTab.value == '2' ? t('Label.IntoAccount') : t('Ib.Transfer.IbAccountTransfer'))
+
+// 获取全局实例(用于访问 Session、$pigeon 等)
+const { proxy } = getCurrentInstance()
+const $pigeon = proxy?.$pigeon
+
+// 响应式数据
+const loginValue = ref('')
+const flag = ref(false)
+const responseMessage = ref('') // 弹窗响应信息
+const giveLoginJoin = ref('')
+const step2 = ref(false)
+const amountLimits = reactive({
+    minAmount: '',
+    maxAmount: '',
+})
+const form = reactive({
+    currency: 'USD',
+    depositLogin: null,
+    to: null,
+    amount: '',
+    agree5: false,
+    agree6: false,
+})
+const dialogCheck = ref(false)
+const dialogVisible = ref(false)
+const dialogCheckWait = ref(false)
+const InfoStatus5 = ref(false)
+const dialogClauseNZTwo = ref(false)
+const tableData4TwoFlag = ref(false)
+const tableData4Two = ref({})
+const dialogClauseNewList = ref(false)
+const tableDataNewListFlag = ref(false)
+const tableDataNewList = ref({})
+const dialogDontActive = ref(false)
+const submitting = ref(false)
+
+// 错误信息
+const depositErrorMessage = ref('')
+const depositLogin1ErrorMessage = ref('')
+const amountErrorMessage = ref('')
+
+// 表单验证规则
+const rules = {
+    withdrawLogin: {
+        rules: [
+            {
+                required: true,
+                errorMessage: t('vaildate.select.empty')
+            },
+        ],
+    },
+    to: {
+        rules: [
+            {
+                required: true,
+                errorMessage: t('vaildate.select.empty')
+            },
+        ],
+    },
+    amount: {
+        rules: [
+            {
+                required: true,
+                errorMessage: t('vaildate.amount.format'),
+            },
+            {
+                validateFunction: (rule, value, data, callback) => {
+                    if (!value) {
+                        callback(t('vaildate.amount.format'))
+                    } else if (
+                        amountLimits.minAmount &&
+                        amountLimits.maxAmount &&
+                        (parseFloat(amountLimits.minAmount) > parseFloat(value) ||
+                            parseFloat(amountLimits.maxAmount) < parseFloat(value))
+                    ) {
+                        callback(t('vaildate.amount.amount') +
+                            amountLimits.minAmount +
+                            '-' +
+                            amountLimits.maxAmount)
+                    } else if (!/^[0-9]+([.]{1}[0-9]{1,2})?$/.test(value)) {
+                        callback(t('vaildate.amount.format'))
+                    }
+                    return true
+                }
+            },
+        ],
+    }
+}
+
+function validateAmount() {
+    const amount = form.amount
+    if (!amount) {
+        amountErrorMessage.value = t('vaildate.amount.format')
+        return false
+    }
+    const numValue = parseFloat(amount)
+    if (isNaN(numValue)) {
+        amountErrorMessage.value = t('vaildate.amount.format')
+        return false
+    }
+    if (amountLimits.minAmount && numValue < parseFloat(amountLimits.minAmount)) {
+        amountErrorMessage.value = t('vaildate.amount.amount') + amountLimits.minAmount + '-' + amountLimits.maxAmount
+        return false
+    }
+    if (amountLimits.maxAmount && numValue > parseFloat(amountLimits.maxAmount)) {
+        amountErrorMessage.value = t('vaildate.amount.amount') + amountLimits.minAmount + '-' + amountLimits.maxAmount
+        return false
+    }
+    if (!/^[0-9]+([.]{1}[0-9]{1,2})?$/.test(amount)) {
+        amountErrorMessage.value = t('vaildate.amount.format')
+        return false
+    }
+    amountErrorMessage.value = ''
+    return true
+}
+
+// 模板引用
+const formRef = ref(null)
+
+// 计算属性
+const getInfoStatus5 = computed(() => {
+    if (ibInfo.value?.closeFunctions) {
+        return ibInfo.value.closeFunctions.indexOf('5') !== -1
+    }
+    return false
+})
+
+// 转入账户列表
+const depositDisplayList = computed(() => {
+    if (activeTab.value != 3) {
+        return toInfo.value.map(item => ({
+            text: [item.login, item.platform, item.cId, item.balance, item.groupTypeName].filter(field => field !== null && field !== undefined && field !== '').join('-'),
+            value: item.login
+        }))
+    } else {
+        return agentInfo.value.map(item => ({
+            text: `${item.ibNo} - ${item.name}`,
+            value: item.id
+        }))
+    }
+})
+
+const fromInfo = ref('')
+const toInfo = ref([])
+const agentInfo = ref([])
+//转出账户信息
+const ransferInfo = async function () {
+    let res = await ibApi.agentBalanceTransferFrom({});
+    if (res.code == Code.StatusOK) {
+        fromInfo.value =
+            res.data.ibNo +
+            " - " +
+            t("Custom.Deposit.AvailableBalance") +
+            ": $" +
+            (res.data.balance ? res.data.balance : 0);
+    } else {
+        $pigeon.MessageError(res.msg);
+    }
+}
+//转入账户信息
+const ransferToInfo = async function () {
+    let res;
+    // 佣金内转使用新接口 /account/dropdown
+    if (activeTab.value == 1) {
+        res = await ibApi.CustomDropdown({ platform: "" });
+    } else {
+        // 佣金下发和其他情况使用原接口
+        res = await ibApi.agentTransferToList({});
+    }
+    if (res.code == Code.StatusOK) {
+        toInfo.value = res.data || [];
+        toInfo.value.forEach((item) => {
+            if (item.closeFunctions && item.closeFunctions.length > 0) {
+                const targetValues = ["7", "5", "9"];
+                const hasTargetValue = item.closeFunctions.some(func => targetValues.includes(func));
+                if (hasTargetValue) {
+                    item.status = true;
+                }
+            }
+        })
+
+    } else {
+        $pigeon.MessageError(res.msg);
+    }
+}
+//获取代理账户信息
+const getAgentInfo = async function () {
+    let res = await ibApi.ibTreeForTransfer({});
+    if (res.code == Code.StatusOK) {
+        agentInfo.value = res.data || [];
+    } else {
+        $pigeon.MessageError(res.msg);
+    }
+}
+
+const currencyOptions = ref([{ value: 'USD', text: 'USD' }])
+
+function toHome() {
+    uni.navigateTo({ url: '/pages/ib/index' })
+    InfoStatus5.value = false
+}
+
+function closeDia() {
+    formRef.value?.resetFields?.()
+    step2.value = false
+    loginValue.value = ''
+    dialogCheck.value = false
+    dialogVisible.value = false
+    tableData4TwoFlag.value = false
+    tableDataNewListFlag.value = false
+    form.to = ''
+    form.amount = ''
+    form.withdrawLogin = ''
+    form.agree5 = false
+    form.agree6 = false
+}
+
+// 内转
+async function toTransfer() {
+    if (submitting.value) return
+    try {
+        const valid = await formRef.value?.validate()
+        if (!valid) {
+            console.log('表单验证失败')
+            return
+        }
+        openDontActive()
+    } catch (error) {
+        console.error('验证失败:', error)
+    }
+}
+
+// 打开不参加活动弹窗
+function openDontActive() {
+    tosubmitConfirm()
+}
+
+function tosubmitConfirm() {
+    dialogDontActive.value = false
+    transferConfig()
+}
+async function transferConfig() {
+    if (submitting.value) return
+    submitting.value = true
+    try {
+        if (flag.value) {
+            return
+        }
+        flag.value = true
+        form.activityTwoPercentGive = form.agree5 ? 1 : 0
+        form.activityGive = form.agree6 ? 1 : 0
+        dialogCheckWait.value = true
+        let api
+        if (activeTab.value != 3) {
+            api = ibApi.agentBalanceTransfer
+        } else {
+            api = ibApi.agentBalanceCommissionAdd
+        }
+        const res = await api({ ...form })
+        dialogCheckWait.value = false
+        if (res.code == Code.StatusOK) {
+            dialogCheck.value = true
+            dialogVisible.value = true
+            flag.value = false
+        } else {
+            responseMessage.value = res.msg
+            dialogCheck.value = true
+            dialogVisible.value = false
+            flag.value = false
+        }
+    } catch (error) {
+        console.error('转账失败:', error)
+        responseMessage.value = error.msg || t('Msg.Fail')
+        dialogCheck.value = true
+        dialogVisible.value = false
+    } finally {
+        submitting.value = false
+        flag.value = false
+        if (dialogCheckWait.value) dialogCheckWait.value = false
+    }
+}
+
+async function Activity24nianzhongTwoInfo() {
+    const res = await activityApi.Activity23nianzhongTwoInfo({})
+    if (res.code == Code.StatusOK) {
+        tableData4Two.value = res.data
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+// 活动相关方法
+function togetActivity() {
+    get23nianzhongTwoLogin()
+    getActivityExtensionGiveLogin()
+    getActivityExtensionGiveLoginJoin()
+}
+
+async function get23nianzhongTwoLogin() {
+    const res = await activityApi.Activity23nianzhongTwoLogin({
+        login: form.to,
+    })
+    if (res.code == Code.StatusOK) {
+        tableData4Two.value = res.data
+        if (tableData4Two.value.show == 1) {
+            tableData4TwoFlag.value = true
+        } else if (tableData4Two.value.show == 0) {
+            tableData4TwoFlag.value = false
+        }
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+
+async function getActivityExtensionGiveLogin() {
+    const res = await activityApi.ActivityExtensionGiveLogin({
+        login: form.to,
+    })
+    if (res.code == Code.StatusOK) {
+        tableDataNewList.value = res.data
+        if (tableDataNewList.value.show == 1) {
+            tableDataNewListFlag.value = true
+        } else if (tableDataNewList.value.show == 0) {
+            tableDataNewListFlag.value = false
+        }
+    } else {
+        $pigeon?.MessageError(res.msg)
+    }
+}
+
+async function getActivityExtensionGiveLoginJoin() {
+    const res = await activityApi.ActivityExtensionGiveLoginJoin({
+        login: form.to,
+    })
+    if (res.code == Code.StatusOK) {
+        giveLoginJoin.value = res.data
+    } else {
+        $pigeon?.MessageError(res.msg)
+        giveLoginJoin.value = ''
+    }
+}
+
+// 监听 activeTab 变化
+watch(activeTab, (newVal) => {
+    if (newVal) {
+        console.log(newVal, 1212);
+        if (newVal == 3) {
+            getAgentInfo()
+        } else {
+            ransferToInfo()
+        }
+        form.to = ''
+        form.amount = ''
+    }
+})
+// 
+watch(loginValue, (newVal) => {
+    if (newVal) {
+        step2.value = true
+        form.withdrawLogin = newVal
+    }
+})
+watch(() => form.to, (newVal) => {
+    if (activeTab.value == 3) {
+        getAgentInfo()
+    } else {
+        togetActivity()
+    }
+})
+// 监听 agree6 变化
+watch(() => form.agree6, (newVal) => {
+    if (newVal && giveLoginJoin.value?.flag === false) {
+        let tips = ''
+        if (giveLoginJoin.value.promptType == 1) {
+            tips = t('surplusList.item10')
+        } else {
+            tips = t('surplusList.item11')
+        }
+
+        return
+        // 活动相关方法,后续需要在调整
+        if (giveLoginJoin.value.activityCategory == 1) {
+            $pigeon?.MessageConfirm(
+                tips,
+                t('Msg.SystemPrompt'),
+                t('surplusList.item12'),
+                t('Home.msg.item3'),
+                () => {
+                    $pigeon?.MessageConfirm(
+                        t('surplusList.item13'),
+                        t('Msg.SystemPrompt'),
+                        t('Btn.Confirm'),
+                        t('Btn.Cancel'),
+                        async () => {
+                            try {
+                                const res = await activityApi.ActivityGiveCancel({
+                                    login: loginValue.value,
+                                })
+                                if (res.code == Code.StatusOK) {
+                                    $pigeon?.MessageOK(res.msg || t('Msg.Success'))
+                                } else {
+                                    $pigeon?.MessageError(res.msg)
+                                }
+                            } catch (error) {
+                                $pigeon?.MessageError(t('Msg.Fail'))
+                            }
+                        },
+                        () => {
+                            form.agree6 = false
+                        }
+                    )
+                },
+                () => {
+                    form.agree6 = false
+                }
+            )
+        } else {
+            $pigeon?.MessageConfirm(
+                tips,
+                t('Msg.SystemPrompt'),
+                t('Btn.Confirm'),
+                t('Btn.Cancel'),
+                () => { },
+                () => {
+                    form.agree6 = false
+                }
+            )
+        }
+    }
+})
+onMounted(() => {
+    if (getInfoStatus5.value) {
+        InfoStatus5.value = true
+    }
+
+    ransferInfo();
+    ransferToInfo();
+    // Activity24nianzhongTwoInfo()
+})
+
+onLoad((options) => {
+    if (options?.login) {
+        loginValue.value = options.login
+        step2.value = true
+        form.withdrawLogin = options.login
+    }
+})
 </script>
+
 <style lang="scss" scoped>
 @import "@/uni.scss";
+
+.transfer-page {
+    width: 100%;
+    padding-bottom: px2rpx(20);
+
+    .main-content {
+        text-align: left;
+
+        .box {
+            padding-top: px2rpx(5);
+            color: #303133;
+
+            .b-card {
+                background-color: #fff;
+                margin-bottom: px2rpx(10);
+                border-radius: px2rpx(6);
+                box-shadow: 0 px2rpx(1) px2rpx(6) 0 rgba(0, 0, 0, 0.05);
+
+                &:hover {
+                    box-shadow: 0 px2rpx(2) px2rpx(8) 0 rgba(0, 0, 0, 0.1);
+                }
+
+                .card-top {
+                    padding: px2rpx(15) px2rpx(20);
+                    box-sizing: border-box;
+
+                    .card-row {
+                        margin-bottom: px2rpx(12);
+
+                        &:last-child {
+                            margin-bottom: 0;
+                        }
+                    }
+
+                    .tit {
+                        font-size: px2rpx(16);
+                        margin-bottom: px2rpx(12);
+                        font-weight: 600;
+
+                        .iconfont {
+                            font-size: px2rpx(18);
+                            margin-right: px2rpx(8);
+                            color: #409eff;
+                        }
+                    }
+
+                    .title-wrapper {
+                        display: flex;
+                        justify-content: space-between;
+                        align-items: center;
+                    }
+                }
+            }
+        }
+
+        .box-step2 {
+            .form-row {
+                display: flex;
+                flex-wrap: wrap;
+                margin-bottom: px2rpx(12);
+                gap: px2rpx(12);
+
+                &:last-child {
+                    margin-bottom: 0;
+                }
+
+                .form-col {
+                    flex: 1;
+                    min-width: px2rpx(140);
+
+                    @media screen and (max-width: 991px) {
+                        flex: 0 0 100%;
+                        width: 100%;
+                    }
+                }
+
+                .form-col-full {
+                    width: 100%;
+                    padding: 0 px2rpx(5);
+                }
+            }
+
+            .tips {
+                line-height: 1.8;
+                font-size: px2rpx(12);
+                color: #909399;
+                background-color: #f9f9f9;
+                padding: px2rpx(12);
+                border-radius: px2rpx(4);
+                border-left: px2rpx(2) solid #409eff;
+
+                .title {
+                    font-weight: 600;
+                    margin-bottom: px2rpx(6);
+                    color: #606266;
+                }
+            }
+        }
+    }
+
+    .picker-select {
+        background-color: #f5f7fa;
+        border: 1px solid #dcdfe6;
+        border-radius: px2rpx(4);
+        padding: px2rpx(12) px2rpx(14);
+        font-size: px2rpx(14);
+        color: #606266;
+        line-height: 1.4;
+        width: 100%;
+        box-sizing: border-box;
+
+        &:hover {
+            border-color: #409eff;
+        }
+
+        &.picker-disabled {
+            background-color: #f5f7fa;
+            color: #c0c4cc;
+            cursor: not-allowed;
+        }
+    }
+
+    .disabled-input {
+        background-color: #f5f7fa;
+        border: 1px solid #dcdfe6;
+        border-radius: px2rpx(4);
+        padding: px2rpx(12) px2rpx(14);
+        font-size: px2rpx(14);
+        color: #606266;
+        width: 100%;
+        box-sizing: border-box;
+    }
+
+    .m-input {
+        background-color: #f5f7fa;
+        border: 1px solid #dcdfe6;
+        border-radius: px2rpx(4);
+        padding: px2rpx(12) px2rpx(14);
+        font-size: px2rpx(14);
+        width: 100%;
+        box-sizing: border-box;
+
+        &:focus {
+            border-color: #409eff;
+            outline: none;
+            box-shadow: 0 0 0 px2rpx(1) rgba(64, 158, 255, 0.2);
+        }
+    }
+
+    .s-btn {
+        width: 100%;
+        padding: px2rpx(12) px2rpx(20);
+        border-radius: px2rpx(4);
+        margin: px2rpx(10) 0;
+        background-color: #409eff;
+        color: #fff;
+        border: none;
+        font-size: px2rpx(15);
+        font-weight: 500;
+        cursor: pointer;
+
+        &:hover {
+            background-color: #66b1ff;
+            transform: translateY(px2rpx(-1));
+            box-shadow: 0 px2rpx(2) px2rpx(6) 0 rgba(64, 158, 255, 0.3);
+        }
+
+        &:active {
+            background-color: #3a8ee6;
+            transform: translateY(0);
+        }
+
+        &[disabled] {
+            opacity: 0.6;
+            cursor: not-allowed;
+        }
+    }
+
+    .popup-content {
+        padding: px2rpx(30) px2rpx(20);
+        text-align: center;
+        min-width: px2rpx(250);
+        max-width: 80%;
+        margin: 0 auto;
+
+        @media screen and (max-width: 991px) {
+            min-width: 80%;
+            max-width: 90%;
+            margin: 0 px2rpx(10);
+        }
+
+        position: relative;
+
+        .icon {
+            .iconfont {
+                font-size: px2rpx(60);
+                display: block;
+                margin: 0 auto;
+            }
+
+            .icon-chenggong {
+                color: #67c23a;
+            }
+
+            .icon-jingshi {
+                color: #f56c6c;
+            }
+
+            .icon-dengdai {
+                color: #e6a23c;
+            }
+        }
+
+        .des1 {
+            font-weight: 600;
+            font-size: px2rpx(16);
+            margin: px2rpx(20) 0 px2rpx(15);
+            color: #303133;
+            line-height: 1.4;
+            padding: 0 px2rpx(10);
+        }
+
+        .dialog-footer {
+            display: flex;
+            justify-content: center;
+            gap: px2rpx(10);
+            margin-top: px2rpx(10);
+
+            @media (max-width: 750rpx) {
+                flex-direction: column;
+                align-items: center;
+                gap: px2rpx(6);
+            }
+
+            button {
+                min-width: px2rpx(90);
+                padding: 0 px2rpx(12);
+                border-radius: px2rpx(4);
+                font-size: px2rpx(14);
+                transition: all 0.3s ease;
+                cursor: pointer;
+
+                &[type="primary"] {
+                    background-color: #409eff;
+                    color: #fff;
+                    border: none;
+
+                    &:hover {
+                        background-color: #66b1ff;
+                        transform: translateY(px2rpx(-1));
+                        box-shadow: 0 px2rpx(2) px2rpx(6) 0 rgba(64, 158, 255, 0.3);
+                    }
+
+                    &:active {
+                        background-color: #3a8ee6;
+                        transform: translateY(0);
+                    }
+                }
+
+                &:not([type="primary"]) {
+                    background-color: #fff;
+                    border: 1px solid #dcdfe6;
+                    color: #606266;
+
+                    &:hover {
+                        border-color: #409eff;
+                        color: #409eff;
+                        transform: translateY(px2rpx(-1));
+                    }
+
+                    &:active {
+                        transform: translateY(0);
+                    }
+                }
+            }
+        }
+    }
+
+    .wait-popup {
+        .des1 {
+            margin-top: px2rpx(10);
+        }
+
+        .icon {
+            .iconfont {
+                animation: spin 1s linear infinite;
+            }
+        }
+    }
+}
+
+// 动画
+@keyframes popupFadeIn {
+    from {
+        opacity: 0;
+        transform: scale(0.9);
+    }
+
+    to {
+        opacity: 1;
+        transform: scale(1);
+    }
+}
+
+@keyframes fadeIn {
+    from {
+        opacity: 0;
+        transform: translateY(px2rpx(10));
+    }
+
+    to {
+        opacity: 1;
+        transform: translateY(0);
+    }
+}
+
+@keyframes pulse {
+    0% {
+        transform: scale(1);
+    }
+
+    50% {
+        transform: scale(1.05);
+    }
+
+    100% {
+        transform: scale(1);
+    }
+}
+
+@keyframes spin {
+    from {
+        transform: rotate(0deg);
+    }
+
+    to {
+        transform: rotate(360deg);
+    }
+}
+
+// 表单错误信息样式
+.uni-forms-item__error {
+    font-size: px2rpx(12);
+    color: #f56c6c;
+    margin-top: px2rpx(4);
+}
+
+// 适配不同屏幕尺寸(媒体查询中的 750rpx 保持不变)
+@media (max-width: 750rpx) {
+    .transfer-page {
+        .main-content {
+            padding: px2rpx(8);
+
+            .box {
+                .b-card {
+                    .card-top {
+                        padding: px2rpx(12) px2rpx(16);
+
+                        .tit {
+                            font-size: px2rpx(14);
+
+                            .iconfont {
+                                font-size: px2rpx(16);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        .s-btn {
+            font-size: px2rpx(14);
+            padding: px2rpx(10) px2rpx(16);
+        }
+
+        .popup-content {
+            padding: px2rpx(20) px2rpx(16);
+
+            .icon {
+                .iconfont {
+                    font-size: px2rpx(50);
+                }
+            }
+
+            .des1 {
+                font-size: px2rpx(14);
+                margin: px2rpx(15) 0 px2rpx(10);
+            }
+
+            .dialog-footer {
+                button {
+                    min-width: px2rpx(80);
+                    font-size: px2rpx(13);
+                }
+            }
+        }
+    }
+}
 </style>

+ 182 - 1
static/scss/global/global.scss

@@ -243,7 +243,7 @@
     --color-error: #e32326;
     --color-error-focus: #f03000;
     --color-gray-second: #6B7188;
-  --color-bg-main: #f8f9f9;
+    --color-bg-main: #f8f9f9;
 
     --text-tiny: .625rem;
     --text-tiny--line-height: .8125rem;
@@ -1162,4 +1162,185 @@ uni-content {
         background: rgba(108, 133, 149, 0.12);
         border-color: rgb(145, 163, 176);
     }
+}
+
+.popup-content {
+    padding: px2rpx(30) px2rpx(20);
+    text-align: center;
+    min-width: px2rpx(250);
+    max-width: 80%;
+    margin: 0 auto;
+
+    @media screen and (max-width: 991px) {
+        min-width: 80%;
+        max-width: 90%;
+        margin: 0 px2rpx(10);
+    }
+
+    position: relative;
+
+    .icon {
+        .iconfont {
+            font-size: px2rpx(60);
+            display: block;
+            margin: 0 auto;
+        }
+
+        .icon-chenggong {
+            color: #67c23a;
+        }
+
+        .icon-jingshi {
+            color: #f56c6c;
+        }
+
+        .icon-dengdai {
+            color: #e6a23c;
+        }
+    }
+
+    .des1 {
+        font-weight: 600;
+        font-size: px2rpx(16);
+        margin: px2rpx(20) 0 px2rpx(15);
+        color: #303133;
+        line-height: 1.4;
+        padding: 0 px2rpx(10);
+    }
+
+}
+
+
+.dialog-footer {
+    padding: px2rpx(20) px2rpx(30) px2rpx(30);
+    border-top: 1px solid #f0f0f0;
+
+    // 双按钮模式
+    &:not(:has(button:only-child)):has(button) {
+        display: flex;
+        justify-content: center;
+        gap: px2rpx(20);
+    }
+
+    // 单按钮模式
+    &:has(button:only-child) {
+        display: flex;
+        justify-content: center;
+    }
+
+    .footer-line {
+        height: 1px;
+        background-color: #f0f0f0;
+        margin: px2rpx(-20) 0 0;
+    }
+
+    button {
+        min-width: px2rpx(120);
+        height: px2rpx(40);
+        border-radius: px2rpx(4);
+        font-size: px2rpx(16);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        border: none;
+        cursor: pointer;
+        transition: all 0.3s ease;
+        margin: 0;
+
+        &:active {
+            opacity: 0.8;
+            transform: scale(0.98);
+        }
+
+        &:disabled {
+            opacity: 0.5;
+            cursor: not-allowed;
+        }
+    }
+
+    .cancel-btn {
+        background-color: #f5f5f5;
+        color: #666;
+
+        &:active {
+            background-color: #e8e8e8;
+        }
+    }
+
+    .confirm-btn {
+        &.primary {
+            background-color: #007aff;
+            color: #fff;
+
+            &:active {
+                background-color: #0056b3;
+            }
+        }
+
+        &.danger {
+            background-color: #ff6b6b;
+            color: #fff;
+
+            &:active {
+                background-color: #ff5252;
+            }
+        }
+    }
+
+    .single-btn {
+        min-width: px2rpx(200);
+
+        &.primary {
+            background-color: #007aff;
+            color: #fff;
+        }
+
+        &.danger {
+            background-color: #ff6b6b;
+            color: #fff;
+        }
+
+        &.default {
+            background-color: #f5f5f5;
+            color: #666;
+        }
+    }
+}
+
+
+.wait-popup {
+    .des1 {
+        margin-top: px2rpx(10);
+    }
+
+    .icon {
+        .iconfont {
+            animation: spin 1s linear infinite;
+        }
+    }
+}
+
+// 适配不同屏幕尺寸(媒体查询中的 750rpx 保持不变)
+@media (max-width: 750rpx) {
+    .popup-content {
+        padding: px2rpx(20) px2rpx(16);
+
+        .icon {
+            .iconfont {
+                font-size: px2rpx(50);
+            }
+        }
+
+        .des1 {
+            font-size: px2rpx(14);
+            margin: px2rpx(15) 0 px2rpx(10);
+        }
+
+        .dialog-footer {
+            button {
+                min-width: px2rpx(80);
+                font-size: px2rpx(13);
+            }
+        }
+    }
 }