zhb пре 1 месец
родитељ
комит
e17f89a5ea

+ 1 - 1
components/cwg-complex-search.vue

@@ -547,7 +547,7 @@ onMounted(() => {
             /* 填充样式(选中) */
             &.chip-filled {
                 background-color: #cf1322;
-                border-color: #007aff;
+                border-color: #cf1322;
                 color: #ffffff;
             }
 

+ 5 - 5
components/cwg-tabel.vue

@@ -974,8 +974,8 @@ defineExpose({
     }
 
     .page-item:not(.disabled):hover {
-        color: #007aff;
-        border-color: #007aff;
+        color: #fff;
+        border-color: #cf1322;
     }
 
     .page-item.disabled {
@@ -1009,13 +1009,13 @@ defineExpose({
     }
 
     .page-number:hover {
-        color: #007aff;
-        border-color: #007aff;
+        color: #fff;
+        border-color: #cf1322;
     }
 
     .page-number.active {
         background-color: #cf1322;
-        border-color: #007aff;
+        border-color: #cf1322;
         color: #fff;
     }
 

+ 2 - 2
pages/customer/components/Timeline.vue

@@ -666,8 +666,8 @@ defineExpose({
 
             // 颜色变体
             &.text-primary {
-                color: #007aff;
-                border-color: #007aff;
+                color: #cf1322;
+                border-color: #cf1322;
             }
 
             &.text-secondary {

+ 125 - 149
pages/follow/record.vue

@@ -6,24 +6,14 @@
                 @reset="handleReset" />
             <cwg-tabel ref="tableRef" :columns="currentColumns" :immediate="false" :queryParams="search" :api="listApi"
                 :show-operation="false">
-                <!-- 状态列自定义渲染 -->
                 <template #status="{ row }">
                     <view v-if="getStatusText(row)" class="status-tag" :class="getStatusClass(row.status)">
                         {{ getStatusText(row) }}
                     </view>
                     <view v-else></view>
                 </template>
-                <!-- 账户类型列自定义渲染 -->
                 <template #accountType="{ row }">
-                    {{ getAccountTypeText(row.type || row.loginType) }}
-                </template>
-                <!-- 金额列格式化 -->
-                <template #amount="{ row }">
-                    <view>-{{ formatNumber(row.withdrawAmount || row.amount) }}</view>
-                </template>
-                <!-- 备注列格式化 -->
-                <template #note="{ row }">
-                    <view>{{ formatNote(row.approveDesc) }}</view>
+                    {{ getAccountTypeText(row.dealLoginType || row.followAccountType) }}
                 </template>
             </cwg-tabel>
         </view>
@@ -31,23 +21,22 @@
 </template>
 
 <script setup lang="ts">
-import { computed, ref, nextTick } from 'vue';
+import { computed, ref, nextTick, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 const { t, locale } = useI18n();
-import { customApi } from '@/service/custom';
+import { documentaryApi } from '@/service/documentary';
 import useUserStore from "@/stores/use-user-store";
 const userStore = useUserStore();
 const userInfo = computed(() => userStore.userInfo);
+import { useAccountOptions } from '@/composables/useAccountOptions'
+const { loginOptions, isLoaded, isSuccess } = useAccountOptions()
 const search = ref({
-    type: 1
+    type: 1, followLogin: null,
+
 })
-const getInfoAgentTransfer = computed(() => userInfo.value.customInfo?.agentTransfer)
 const typeMap = computed(() => ([
-    { value: 1, text: t('Custom.Recording.NewAccount') },
-    { value: 2, text: t('Custom.Recording.LeverageApply') },
-    { value: 3, text: t('Custom.Recording.InternalTransfer') },
-    { value: 4, text: t('Custom.Recording.ActivitiesApply') },
-    ...(getInfoAgentTransfer.value == 1 ? [{ value: 5, text: t('Home.page_ib.item9') }] : [])
+    { value: 1, text: t('Documentary.TundManagement.item58') },
+    { value: 2, text: t('Documentary.TundManagement.item47') },
 ]));
 const isZh = computed(() => ['cn', 'zh', 'zhHant'].includes(locale.value));
 
@@ -65,176 +54,147 @@ const reasons = ref({})
 // 根据类型获取列配置
 const getColumnsByType = (type: number) => {
     switch (type) {
-        case 1: // 开户记录
+        case 1: //信号源申请
             return [
                 {
-                    prop: 'platform',
-                    label: t('Custom.Recording.Platform'),
-                    align: 'left'
-                },
-                {
-                    prop: 'type',
-                    label: t('Custom.PaymentHistory.payType'),
-                    align: 'left',
-                    slot: 'accountType'
-                },
-                {
-                    prop: 'withdrawCurrency',
-                    label: t('Custom.Recording.CurrencyType'),
-                    align: 'left',
-                    formatter: ({ row }) => row.currency || '--',
+                    prop: 'dealLogin',
+                    label: t('Documentary.TundManagement.item25'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => row.dealLogin || '--'
                 },
                 {
-                    prop: 'leverage',
-                    label: t('Custom.Recording.Lever'),
-                    formatter: ({ row }) => `1: ${row.leverage}` || '--',
-                    align: 'left'
+                    prop: 'dealPlatform',
+                    label: t('Label.Platform'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => row.dealPlatform || '--'
                 },
                 {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
+                    prop: 'dealLoginType',
+                    label: t('Label.AccountType'),
+                    align: 'center',
+                    slot: 'accountType' // 多语言枚举
                 },
                 {
-                    prop: 'status',
-                    label: t('Custom.Recording.Status'),
-                    slot: 'status',
-                    align: 'left'
+                    prop: 'dealLeverage',
+                    label: t('Label.Leverage'),
+                    align: 'center',
+                    formatter: ({ row }) => row.dealLeverage ? `1:${row.dealLeverage}` : '--'
                 },
                 {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-        case 2: // 杠杆修改记录
-            return [
-                {
-                    prop: 'login',
-                    label: t('Custom.Recording.TradingAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.login || '--'
+                    prop: 'distributionType',
+                    label: t('Documentary.TundManagement.item38'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => row.distributionType === 1 ? t('Documentary.TundManagement.item59') : '--'
                 },
                 {
-                    prop: 'oldLeverage',
-                    label: t('Custom.Recording.OldLever'),
-                    align: 'left',
-                    formatter: ({ row }) => row.oldLeverage ? `1:${row.oldLeverage}` : '--'
+                    prop: 'distributionRatio',
+                    label: t('Documentary.TundManagement.item39'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => (row.distributionRatio || '0') + '%'
                 },
                 {
-                    prop: 'newLeverage',
-                    label: t('Custom.Recording.NewLever'),
-                    align: 'left',
-                    formatter: ({ row }) => row.newLeverage ? `1:${row.newLeverage}` : '--'
+                    prop: 'settlementCycle',
+                    label: t('Documentary.TundManagement.item55'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => row.settlementCycle || '--'
                 },
                 {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
+                    prop: 'approveTime',
+                    label: t('Documentary.TundManagement.item56'),
+                    align: 'center',
+                    formatter: ({ row }) => row.approveTime || '--'
                 },
                 {
                     prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
+                    label: t('Documentary.TundManagement.item57'),
+                    align: 'center',
+                    slot: 'status' // 状态
                 },
                 {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
+                    prop: 'approveDesc',
+                    label: t('Label.Note'),
+                    align: 'center',
+                    type: 'note' // 备注多语言
                 }
             ]
-        case 3: // 转账记录
-        case 5: // 内部转账记录
+        case 2: // 取消记录
             return [
                 {
-                    prop: 'withdrawLogin',
-                    label: t('Custom.Recording.TransferAccounts'),
-                    align: 'left',
-                    formatter: ({ row }) => row.withdrawLogin || '--'
+                    prop: 'dealNickname',
+                    label: t('Documentary.tradingCenter.item1'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => row.dealNickname || '--'
                 },
                 {
-                    prop: 'depositLogin',
-                    label: t('Custom.Recording.IntoAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.depositLogin || '--',
+                    prop: 'dealLogin',
+                    label: t('Documentary.tradingCenter.item18'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => row.dealLogin || '--'
                 },
                 {
-                    prop: 'withdrawCurrency',
-                    label: t('Custom.Recording.CurrencyType'),
-                    align: 'left',
-                    formatter: ({ row }) => row.withdrawCurrency || '--',
+                    prop: 'followLogin',
+                    label: t('Documentary.console.item28'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => row.followLogin || '--'
                 },
                 {
-                    prop: 'withdrawAmount',
-                    label: t('Custom.Recording.Amount'),
-                    align: 'left',
-                    slot: 'amount'
+                    prop: 'followPlatform',
+                    label: t('Label.Platform'),
+                    align: 'center',
+                    formatter: ({ row }) => row.followPlatform || '--'
                 },
                 {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
+                    prop: 'followLoginType',
+                    label: t('Label.AccountType'),
+                    align: 'center',
+                    slot: 'followAccountType'
                 },
                 {
-                    prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-        case 4: // 活动申请记录
-            return [
-                {
-                    prop: 'login',
-                    label: t('Custom.Recording.TradingAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.login || '--'
+                    prop: 'followLeverage',
+                    label: t('Label.Leverage'),
+                    align: 'center',
+                    formatter: ({ row }) => row.followLeverage ? `1:${row.followLeverage}` : '--'
                 },
                 {
-                    prop: 'loginType',
-                    label: t('Custom.Recording.AccountType'),
-                    align: 'left',
-                    slot: 'accountType'
+                    prop: 'distributionType',
+                    label: t('Documentary.TundManagement.item38'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: () => t('Documentary.TundManagement.item59')
                 },
                 {
-                    prop: 'title',
-                    label: t('Custom.Recording.ActivityName'),
-                    align: 'left',
-                    formatter: ({ row }) => row.title || '--'
+                    prop: 'distributionRatio',
+                    label: t('Documentary.TundManagement.item39'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => (row.distributionRatio || '0') + '%'
                 },
                 {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
+                    prop: 'settlementCycle',
+                    label: t('Documentary.TundManagement.item55'),
+                    align: 'center',
+                    headerAlign: 'center',
+                    formatter: ({ row }) => row.settlementCycle || '--'
                 },
                 {
-                    prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
+                    prop: 'timeRange',
+                    label: t('Documentary.TundManagement.item51') + ' / ' + t('Documentary.TundManagement.item52'),
+                    align: 'center',
+                    slot: 'timeRange' // 开始-结束时间
                 },
                 {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
+                    prop: 'endTime',
+                    label: t('Documentary.TundManagement.item56'),
+                    align: 'center',
+                    formatter: ({ row }) => row.endTime || '--'
                 }
             ]
     }
@@ -242,6 +202,7 @@ const getColumnsByType = (type: number) => {
 // 动态传入筛选字段配置
 const filterFields = computed(() => [
     { key: 'type', type: 'select', label: t('Custom.PaymentHistory.payType'), placeholder: t('placeholder.choose'), options: typeMap.value, defaultValue: 1 },
+    isLoaded.value && isSuccess.value && { key: 'followLogin', type: 'select', label: t('Custom.PaymentHistory.TradingAccount'), placeholder: t('placeholder.login'), options: loginOptions || [], defaultValue: search?.login || undefined, clearable: true },
     { key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' }
 ])
 const searchParams = ref({})
@@ -266,9 +227,9 @@ const getStatusText = (row: any) => {
     const status = row.status
     // 根据不同记录类型处理状态
     if (search.value.type === 1) {
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2 && row.accountStatus === 2) return t('State.Completed')
-        if (status === 2 && (row.accountStatus === 1 || !row.accountStatus)) return t('State.InTheProcessing')
+        if (status === 0) return t('State.ToBeProcessed')
+        if (status === 2) return t('State.Completed')
+        if (status === 1) return t('State.InTheProcessing')
         if (status === 3) return t('State.Refused')
     } else if (search.value.type === 2) {
         if (status === 1) return t('State.ToBeProcessed')
@@ -319,7 +280,22 @@ const formatNote = (approveDesc: string) => {
     return approveDesc
 }
 const listApi = ref(null)
-listApi.value = customApi.CustomRecordAccount
+watch(() => search.value.type, (newVal) => {
+    switch (newVal) {
+        case 1:
+            search.value.status = null
+            search.value.followLogin = null
+            listApi.value = documentaryApi.followDealList
+            break
+        case 2:
+            search.value.status = null
+            search.value.followLogin = null
+            listApi.value = documentaryApi.followDealSubscribeList
+            search.value.status = 2
+            break
+    }
+}, { immediate: true })
+
 </script>
 
 <style scoped lang="scss">

+ 187 - 269
pages/follow/transfer-history.vue

@@ -1,29 +1,32 @@
 <template>
     <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
-        <cwg-header :title="t('Documentary.TundManagement.item10')" />
+        <cwg-header :title="t('Ib.Report.Tit1')" />
         <view class="info-card">
             <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch"
                 @reset="handleReset" />
-            <cwg-tabel ref="tableRef" :columns="currentColumns" :immediate="false" :queryParams="search" :api="listApi"
-                :show-operation="false">
-                <!-- 状态列自定义渲染 -->
-                <template #status="{ row }">
-                    <view v-if="getStatusText(row)" class="status-tag" :class="getStatusClass(row.status)">
-                        {{ getStatusText(row) }}
+            <cwg-tabel ref="tableRef" :columns="columns" :immediate="false" :mobilePrimaryFields="mobilePrimaryFields"
+                :queryParams="search" :api="listApi" :show-operation="false">
+                <template #symbol="{ row }">
+                    <view class="symbol-cell">
+                        <view class="pair">{{ row.ticket || '--' }}</view>
+                        <view class="desc">{{ getAccountTypeText(row.loginType) }} - {{ row.login || '--' }}</view>
+                    </view>
+                </template>
+                <template #profit="{ row }">
+                    <view class="symbol-cell">
+                        <text>{{ row.amount || 0 }}</text>
                     </view>
-                    <view v-else></view>
                 </template>
-                <!-- 账户类型列自定义渲染 -->
                 <template #accountType="{ row }">
                     {{ getAccountTypeText(row.type || row.loginType) }}
                 </template>
-                <!-- 金额列格式化 -->
-                <template #amount="{ row }">
-                    <view>-{{ formatNumber(row.withdrawAmount || row.amount) }}</view>
-                </template>
-                <!-- 备注列格式化 -->
-                <template #note="{ row }">
-                    <view>{{ formatNote(row.approveDesc) }}</view>
+                <template #status="{ row }">
+                    <view class="symbol-cell">
+                        <text v-t="'State.ToBeProcessed'" v-if="row.status == 1"></text>
+                        <text v-t="'State.InTheProcessing'" v-if="row.status == 2 && row.tradeStatus == 1"></text>
+                        <text v-t="'State.Completed'" v-if="row.status == 2 && row.tradeStatus == 2"></text>
+                        <text v-t="'State.Refused'" v-if="row.status == 3 || row.tradeStatus == 3"></text>
+                    </view>
                 </template>
             </cwg-tabel>
         </view>
@@ -31,26 +34,19 @@
 </template>
 
 <script setup lang="ts">
-import { computed, ref, nextTick } from 'vue';
+import { computed, ref, nextTick, reactive } from 'vue';
 import { useI18n } from 'vue-i18n';
+import { onLoad } from '@dcloudio/uni-app'
 const { t, locale } = useI18n();
-import { customApi } from '@/service/custom';
-import useUserStore from "@/stores/use-user-store";
-const userStore = useUserStore();
-const userInfo = computed(() => userStore.userInfo);
-const search = ref({
-    type: 1
+import { documentaryApi } from '@/service/documentary';
+import { useAccountOptions } from '@/composables/useAccountOptions'
+const { loginOptions, isLoaded, isSuccess } = useAccountOptions()
+const search = reactive({
+    login: null,
+    type: null,
+    orderStatus: null,
+    date: null
 })
-const getInfoAgentTransfer = computed(() => userInfo.value.customInfo?.agentTransfer)
-const typeMap = computed(() => ([
-    { value: 1, text: t('Custom.Recording.NewAccount') },
-    { value: 2, text: t('Custom.Recording.LeverageApply') },
-    { value: 3, text: t('Custom.Recording.InternalTransfer') },
-    { value: 4, text: t('Custom.Recording.ActivitiesApply') },
-    ...(getInfoAgentTransfer.value == 1 ? [{ value: 5, text: t('Home.page_ib.item9') }] : [])
-]));
-const isZh = computed(() => ['cn', 'zh', 'zhHant'].includes(locale.value));
-
 // 账户类型映射
 const accountTypeMap = {
     1: 'AccountType.ClassicAccount',
@@ -60,266 +56,159 @@ const accountTypeMap = {
     7: 'AccountType.StandardAccount',
     8: 'AccountType.CentAccount'
 }
-// 拒绝原因映射(示例)
-const reasons = ref({})
-// 根据类型获取列配置
-const getColumnsByType = (type: number) => {
-    switch (type) {
-        case 1: // 开户记录
-            return [
-                {
-                    prop: 'platform',
-                    label: t('Custom.Recording.Platform'),
-                    align: 'left'
-                },
-                {
-                    prop: 'type',
-                    label: t('Custom.PaymentHistory.payType'),
-                    align: 'left',
-                    slot: 'accountType'
-                },
-                {
-                    prop: 'withdrawCurrency',
-                    label: t('Custom.Recording.CurrencyType'),
-                    align: 'left',
-                    formatter: ({ row }) => row.currency || '--',
-                },
-                {
-                    prop: 'leverage',
-                    label: t('Custom.Recording.Lever'),
-                    formatter: ({ row }) => `1: ${row.leverage}` || '--',
-                    align: 'left'
-                },
-                {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
-                },
-                {
-                    prop: 'status',
-                    label: t('Custom.Recording.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-        case 2: // 杠杆修改记录
-            return [
-                {
-                    prop: 'login',
-                    label: t('Custom.Recording.TradingAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.login || '--'
-                },
-                {
-                    prop: 'oldLeverage',
-                    label: t('Custom.Recording.OldLever'),
-                    align: 'left',
-                    formatter: ({ row }) => row.oldLeverage ? `1:${row.oldLeverage}` : '--'
-                },
-                {
-                    prop: 'newLeverage',
-                    label: t('Custom.Recording.NewLever'),
-                    align: 'left',
-                    formatter: ({ row }) => row.newLeverage ? `1:${row.newLeverage}` : '--'
-                },
-                {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
-                },
-                {
-                    prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-        case 3: // 转账记录
-        case 5: // 内部转账记录
-            return [
-                {
-                    prop: 'withdrawLogin',
-                    label: t('Custom.Recording.TransferAccounts'),
-                    align: 'left',
-                    formatter: ({ row }) => row.withdrawLogin || '--'
-                },
-                {
-                    prop: 'depositLogin',
-                    label: t('Custom.Recording.IntoAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.depositLogin || '--',
-                },
-                {
-                    prop: 'withdrawCurrency',
-                    label: t('Custom.Recording.CurrencyType'),
-                    align: 'left',
-                    formatter: ({ row }) => row.withdrawCurrency || '--',
-                },
-                {
-                    prop: 'withdrawAmount',
-                    label: t('Custom.Recording.Amount'),
-                    align: 'left',
-                    slot: 'amount'
-                },
-                {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
-                },
-                {
-                    prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-        case 4: // 活动申请记录
-            return [
-                {
-                    prop: 'login',
-                    label: t('Custom.Recording.TradingAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.login || '--'
-                },
-                {
-                    prop: 'loginType',
-                    label: t('Custom.Recording.AccountType'),
-                    align: 'left',
-                    slot: 'accountType'
-                },
-                {
-                    prop: 'title',
-                    label: t('Custom.Recording.ActivityName'),
-                    align: 'left',
-                    formatter: ({ row }) => row.title || '--'
-                },
-                {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
-                },
-                {
-                    prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-    }
+// 获取账户类型文本
+const getAccountTypeText = (type: number) => {
+    const key = accountTypeMap[type as keyof typeof accountTypeMap]
+    return key ? t(key) : '--'
 }
+// 表格列配置
+const columns = computed(() => [
+    {
+        prop: 'ticket',
+        label: t('Documentary.TundManagement.item5'),
+        align: 'center',
+        formatter: ({ row }) => row.ticket || '--'
+    },
+    {
+        prop: 'login',
+        label: t('Documentary.console.item4'),
+        align: 'center',
+        formatter: ({ row }) => row.login || '--'
+    },
+    {
+        prop: 'loginType',
+        label: t('Label.Type'),
+        align: 'center',
+        slot: 'accountType'
+    },
+    {
+        prop: 'amount',
+        label: t('Label.Amount'),
+        align: 'center',
+        formatter: ({ row }) => row.amount || '0' | NumberFormat1
+    },
+    {
+        prop: 'addTime',
+        label: t('Documentary.TundManagement.item6'),
+        align: 'center',
+        formatter: ({ row }) => row.addTime || '--'
+    },
+    {
+        prop: 'approveTime',
+        label: t('Documentary.TundManagement.item7'),
+        align: 'center',
+        formatter: ({ row }) => row.approveTime || '--'
+    },
+    {
+        prop: 'status',
+        label: t('Label.State'),
+        align: 'center',
+        slot: 'status'
+    },
+    {
+        prop: 'approveDesc',
+        label: t('Label.Note'),
+        align: 'center',
+        className: 'bor-r',
+        type: 'note'
+    }
+])
+
+const mobilePrimaryFields = computed(() => [
+    {
+        prop: 'symbol',
+        label: t('Documentary.TundManagement.item5'),      // 交易品种
+        align: 'left',
+        slot: 'symbol'
+    },
+    {
+        prop: 'profit',
+        label: t('Label.Amount'),     // 利润, USD
+        slot: 'profit',
+        align: 'right'
+    },
+    {
+        prop: 'more',
+        type: 'more',
+        width: 20,
+        align: 'right'
+    },
+])
+const orderStatusMap = computed(() => ([
+    { value: null, text: t('Custom.PaymentHistory.All') },
+    { value: 0, text: t('State.ToBeProcessed') },
+    { value: 1, text: t('State.InTheProcessing') },
+    { value: 2, text: t('State.Completed') },
+    { value: 3, text: t('State.Refused') },
+]));
+const isZh = computed(() => ['cn', 'zh', 'zhHant'].includes(locale.value));
+
 // 动态传入筛选字段配置
 const filterFields = computed(() => [
-    { key: 'type', type: 'select', label: t('Custom.PaymentHistory.payType'), placeholder: t('placeholder.choose'), options: typeMap.value, defaultValue: 1 },
+    {
+        key: 'status', type: 'select', label: t('Custom.PaymentHistory.Status'), placeholder: t('placeholder.choose'), options: orderStatusMap.value, defaultValue: null
+    },
     { key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' }
 ])
 const searchParams = ref({})
 const tableRef = ref(null)
 const handleSearch = (params) => {
-    search.value = params
+    Object.assign(search, params)
+
+    // search.login = params.login && Number(params.login)
+    // console.log(params.login, 12);
+    search.platform = loginOptions.find(item => item.value == params.login)?.platform || ''
     nextTick(() => {
         tableRef.value.refreshTable()
     })
 }
 
 const handleReset = (params) => {
-    search.value = params
+    Object.assign(search, params)
+    search.platform = loginOptions.find(item => item.value == params.login)?.platform || ''
     nextTick(() => {
         tableRef.value.refreshTable()
     })
 }
-// 当前列配置
-const currentColumns = computed(() => getColumnsByType(search.value.type))
-// 获取状态文本
-const getStatusText = (row: any) => {
-    const status = row.status
-    // 根据不同记录类型处理状态
-    if (search.value.type === 1) {
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2 && row.accountStatus === 2) return t('State.Completed')
-        if (status === 2 && (row.accountStatus === 1 || !row.accountStatus)) return t('State.InTheProcessing')
-        if (status === 3) return t('State.Refused')
-    } else if (search.value.type === 2) {
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2 && row.leverageStatus === 2) return t('State.Completed')
-        if (status === 2 && row.leverageStatus === 1) return t('State.InTheProcessing')
-        if (status === 3) return t('State.Refused')
-    } else if (search.value.type === 3 || search.value.type === 5) {
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2 && row.withdrawStatus === 2 && row.depositStatus === 2) return t('State.Completed')
-        if (status === 2 && (row.withdrawStatus === 1 || row.depositStatus === 1)) return t('State.InTheProcessing')
-        if (status === 3 || row.withdrawStatus === 3 || row.depositStatus === 3) return t('State.Refused')
-    } else {
-        // 活动申请等
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2) return t('State.Completed')
-        if (status === 3) return t('State.Refused')
+const listApi = ref(null)
+listApi.value = documentaryApi.followTransferList
+
+const getSymbolParts = (sym: string) => {
+    if (!sym) return ['', '']
+    const s = String(sym).toUpperCase()
+    if (s.includes('/')) {
+        const [base, quote] = s.split('/')
+        return [base, quote]
     }
-    return ''
+    const base = s.slice(0, 3)
+    const quote = s.slice(3)
+    return [base, quote]
 }
-// 获取状态样式类
-const getStatusClass = (status: number) => {
-    const classMap: Record<number, string> = {
-        1: 'status-pending',
-        2: 'status-success',
-        3: 'status-processing',
-        4: 'status-danger'
-    }
-    return classMap[status] || ''
+const formatCmdName = (cmd: string) => {
+    const v = String(cmd || '').toLowerCase()
+    if (v.includes('sell')) return '卖出'
+    if (v.includes('buy')) return '买入'
+    return cmd || ''
 }
-// 获取账户类型文本
-const getAccountTypeText = (type: number) => {
-    const key = accountTypeMap[type as keyof typeof accountTypeMap]
-    return key ? t(key) : '--'
+const getCmdColorClass = (cmd: string) => {
+    const v = String(cmd || '').toLowerCase()
+    if (v.includes('sell')) return 'is-sell'
+    if (v.includes('buy')) return 'is-buy'
+    return ''
 }
-// 格式化数字
-const formatNumber = (value: string | number) => {
-    if (!value) return '--'
-    const num = Number(value)
-    return isNaN(num) ? '--' : num.toFixed(2)
+const getProfitColorClass = (profit: any) => {
+    const n = Number(profit)
+    if (!Number.isFinite(n) || n === 0) return ''
+    return n > 0 ? 'is-profit' : 'is-loss'
 }
-// 格式化备注
-const formatNote = (approveDesc: string) => {
-    if (!approveDesc) return '--'
-    const reason = reasons.value[approveDesc as keyof typeof reasons.value]
-    if (reason) {
-        return isZh.value ? reason.content : reason.enContent
+
+onLoad((e) => {
+    console.log(e, 'e')
+    if (e.login) {
+        // ✅ 必须转数字!你的 value 是数字类型
+        search.login = Number(e.login)
     }
-    return approveDesc
-}
-const listApi = ref(null)
-listApi.value = customApi.CustomRecordAccount
+})
 </script>
 
 <style scoped lang="scss">
@@ -385,6 +274,35 @@ listApi.value = customApi.CustomRecordAccount
     opacity: 0.5;
 }
 
+.symbol-cell {
+    display: inline-flex;
+    align-items: flex-start;
+    gap: 0.25rem;
+    flex-direction: column;
+
+    .pair {
+        font-weight: 600;
+        color: var(--color-slate-900);
+    }
+
+    .desc {
+        color: var(--color-slate-600);
+    }
+}
+
+.is-sell,
+.is-loss {
+    color: #eb483f;
+}
+
+.is-buy,
+.is-profit {
+    color: #46cd7c;
+}
+
+
+
+
 .search-bar {
     display: flex;
     align-items: center;

+ 638 - 358
pages/follow/transfer.vue

@@ -1,403 +1,683 @@
 <template>
     <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
         <cwg-header :title="t('Documentary.TundManagement.item2')" />
-        <view class="info-card">
-            <cwg-complex-search :fields="filterFields" v-model="searchParams" @search="handleSearch"
-                @reset="handleReset" />
-            <cwg-tabel ref="tableRef" :columns="currentColumns" :immediate="false" :queryParams="search" :api="listApi"
-                :show-operation="false">
-                <!-- 状态列自定义渲染 -->
-                <template #status="{ row }">
-                    <view v-if="getStatusText(row)" class="status-tag" :class="getStatusClass(row.status)">
-                        {{ getStatusText(row) }}
+        <uni-loading v-if="loading" />
+        <view id="custom_WalletTransfer" class="transfer-page" v-else>
+            <view class="main-content">
+                <view class="box box-step2">
+                    <view class="b-card">
+                        <view class="card-top">
+                            <uni-forms ref="formRef" :model="form" :rules="rules" label-position="top"
+                                validate-trigger="submit">
+
+                                <view class="card-row card-tit">
+                                    <view class="title-wrapper">
+                                        <view class="tit">
+                                            <text class="iconfont icon-caret-right"></text>
+                                            <span>{{ t('wallet.item63') }}</span>
+                                        </view>
+                                    </view>
+                                </view>
+                                <view class="card-row">
+                                    <uni-forms-item name="walletbalance">
+                                        <uni-easyinput v-model="walletbalanceDisplay" disabled class="disabled-input" />
+                                    </uni-forms-item>
+                                </view>
+
+                                <view class="card-row card-tit">
+                                    <view class="title-wrapper">
+                                        <view class="tit">
+                                            <text class="iconfont icon-caret-right"></text>
+                                            <span>{{ t('Custom.Transfer.IntoAccount') }}</span>
+                                        </view>
+                                    </view>
+                                </view>
+                                <view class="card-row">
+                                    <uni-forms-item name="login">
+                                        <cwg-combox v-model:value="form.login" :clearable="false"
+                                            :options="toOptionsDisplay" :placeholder="t('placeholder.choose')" />
+                                    </uni-forms-item>
+                                </view>
+
+                                <view class="card-row card-tit">
+                                    <view class="title-wrapper">
+                                        <view class="tit">
+                                            <text class="iconfont icon-caret-right"></text>
+                                            <span>{{ t('Label.Amount') }}</span>
+                                        </view>
+                                    </view>
+                                </view>
+                                <view class="card-row amount-box">
+                                    <uni-forms-item name="amount" :error-message="amountErrorMessage"
+                                        class="amount-input">
+                                        <uni-easyinput v-model="form.amount" :placeholder="t('placeholder.input')"
+                                            @blur="validateAmount" />
+                                    </uni-forms-item>
+                                    <view class="btn" v-t="'State.All'" @click="setAllAmount"></view>
+                                </view>
+
+                                <view class="form-row">
+                                    <button class="s-btn reselect" type="primary" @click="toTransfer">{{ t('Btn.Submit')
+                                    }}</button>
+                                </view>
+                            </uni-forms>
+                        </view>
                     </view>
-                    <view v-else></view>
-                </template>
-                <!-- 账户类型列自定义渲染 -->
-                <template #accountType="{ row }">
-                    {{ getAccountTypeText(row.type || row.loginType) }}
-                </template>
-                <!-- 金额列格式化 -->
-                <template #amount="{ row }">
-                    <view>-{{ formatNumber(row.withdrawAmount || row.amount) }}</view>
-                </template>
-                <!-- 备注列格式化 -->
-                <template #note="{ row }">
-                    <view>{{ formatNote(row.approveDesc) }}</view>
-                </template>
-            </cwg-tabel>
+                </view>
+            </view>
+            <!-- 失败弹窗 -->
+            <cwg-error-popup v-model:visible="dialogError" @confirm="closeDia" :responseMessage="RES" />
+            <!-- 成功弹窗 -->
+            <cwg-success-popup v-model:visible="dialogSuccess" @confirm="closeDia" />
+            <!-- 等待弹窗 -->
+            <cwg-wait-popup v-model:visible="dialogCheckWait" type="center" :mask-click="false" :showFooters="false" />
         </view>
     </cwg-page-wrapper>
 </template>
 
 <script setup lang="ts">
-import { computed, ref, nextTick } from 'vue';
-import { useI18n } from 'vue-i18n';
-const { t, locale } = useI18n();
-import { customApi } from '@/service/custom';
-import useUserStore from "@/stores/use-user-store";
-const userStore = useUserStore();
-const userInfo = computed(() => userStore.userInfo);
-const search = ref({
-    type: 1
+import { ref, reactive, computed, onMounted } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { customApi } from '@/service/custom'
+import { documentaryApi } from '@/service/documentary'
+import Config from '@/config/index'
+
+const { Code } = Config
+const { t } = useI18n()
+
+const loading = ref(false)
+const flag = ref(false)
+const RES = ref('')
+const walletbalance = ref('0')
+const toOptions = ref([])
+
+const form = reactive({
+    currency: 'USD',
+    login: null,
+    amount: ''
 })
-const getInfoAgentTransfer = computed(() => userInfo.value.customInfo?.agentTransfer)
-const typeMap = computed(() => ([
-    { value: 1, text: t('Custom.Recording.NewAccount') },
-    { value: 2, text: t('Custom.Recording.LeverageApply') },
-    { value: 3, text: t('Custom.Recording.InternalTransfer') },
-    { value: 4, text: t('Custom.Recording.ActivitiesApply') },
-    ...(getInfoAgentTransfer.value == 1 ? [{ value: 5, text: t('Home.page_ib.item9') }] : [])
-]));
-const isZh = computed(() => ['cn', 'zh', 'zhHant'].includes(locale.value));
-
-// 账户类型映射
-const accountTypeMap = {
-    1: 'AccountType.ClassicAccount',
-    2: 'AccountType.SeniorAccount',
-    5: 'AccountType.SpeedAccount',
-    6: 'AccountType.SpeedAccount',
-    7: 'AccountType.StandardAccount',
-    8: 'AccountType.CentAccount'
+
+const currencyOptions = [{ text: 'USD', value: 'USD' }]
+
+const walletbalanceDisplay = computed(() => `$ ${walletbalance.value}`)
+
+const groupTypeName = (type) => {
+    if (type == '1') return t("AccountType.ClassicAccount")
+    if (type == '2') return t("AccountType.SeniorAccount")
+    if (type == '5') return t("AccountType.SpeedAccount")
+    if (type == '6') return t("AccountType.SpeedAccount")
+    if (type == '7') return t("AccountType.StandardAccount")
+    if (type == '8') return t("AccountType.CentAccount")
+    return ''
 }
-// 拒绝原因映射(示例)
-const reasons = ref({})
-// 根据类型获取列配置
-const getColumnsByType = (type: number) => {
-    switch (type) {
-        case 1: // 开户记录
-            return [
-                {
-                    prop: 'platform',
-                    label: t('Custom.Recording.Platform'),
-                    align: 'left'
-                },
-                {
-                    prop: 'type',
-                    label: t('Custom.PaymentHistory.payType'),
-                    align: 'left',
-                    slot: 'accountType'
-                },
-                {
-                    prop: 'withdrawCurrency',
-                    label: t('Custom.Recording.CurrencyType'),
-                    align: 'left',
-                    formatter: ({ row }) => row.currency || '--',
-                },
-                {
-                    prop: 'leverage',
-                    label: t('Custom.Recording.Lever'),
-                    formatter: ({ row }) => `1: ${row.leverage}` || '--',
-                    align: 'left'
-                },
-                {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
-                },
-                {
-                    prop: 'status',
-                    label: t('Custom.Recording.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-        case 2: // 杠杆修改记录
-            return [
-                {
-                    prop: 'login',
-                    label: t('Custom.Recording.TradingAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.login || '--'
-                },
-                {
-                    prop: 'oldLeverage',
-                    label: t('Custom.Recording.OldLever'),
-                    align: 'left',
-                    formatter: ({ row }) => row.oldLeverage ? `1:${row.oldLeverage}` : '--'
-                },
-                {
-                    prop: 'newLeverage',
-                    label: t('Custom.Recording.NewLever'),
-                    align: 'left',
-                    formatter: ({ row }) => row.newLeverage ? `1:${row.newLeverage}` : '--'
-                },
-                {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
-                },
-                {
-                    prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-        case 3: // 转账记录
-        case 5: // 内部转账记录
-            return [
-                {
-                    prop: 'withdrawLogin',
-                    label: t('Custom.Recording.TransferAccounts'),
-                    align: 'left',
-                    formatter: ({ row }) => row.withdrawLogin || '--'
-                },
-                {
-                    prop: 'depositLogin',
-                    label: t('Custom.Recording.IntoAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.depositLogin || '--',
-                },
-                {
-                    prop: 'withdrawCurrency',
-                    label: t('Custom.Recording.CurrencyType'),
-                    align: 'left',
-                    formatter: ({ row }) => row.withdrawCurrency || '--',
-                },
-                {
-                    prop: 'withdrawAmount',
-                    label: t('Custom.Recording.Amount'),
-                    align: 'left',
-                    slot: 'amount'
-                },
-                {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
-                },
-                {
-                    prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
-                }
-            ]
-        case 4: // 活动申请记录
-            return [
-                {
-                    prop: 'login',
-                    label: t('Custom.Recording.TradingAccount'),
-                    align: 'left',
-                    formatter: ({ row }) => row.login || '--'
-                },
-                {
-                    prop: 'loginType',
-                    label: t('Custom.Recording.AccountType'),
-                    align: 'left',
-                    slot: 'accountType'
-                },
-                {
-                    prop: 'title',
-                    label: t('Custom.Recording.ActivityName'),
-                    align: 'left',
-                    formatter: ({ row }) => row.title || '--'
-                },
-                {
-                    prop: 'addTime',
-                    label: t('Custom.PaymentHistory.ApplicationDate'),
-                    type: 'date',
-                    dateFormat: 'YYYY-MM-DD HH:mm',
-                    align: 'left'
-                },
-                {
-                    prop: 'status',
-                    label: t('Custom.PaymentHistory.Status'),
-                    slot: 'status',
-                    align: 'left'
-                },
-                {
-                    prop: 'note',
-                    label: t('Custom.Recording.Note'),
-                    type: 'note',
-                    align: 'left'
+
+// 单位类型
+function groupCurrency(type) {
+    const map = { GBP: ': £', USD: ': $', EUR: ': €', USC: ': ¢' }
+    return map[type] || ': $'
+}
+const toOptionsDisplay = computed(() => {
+    return toOptions.value.map(item => ({
+        text: `${item.login} - ${groupTypeName(item.type)} - ${t('Custom.Deposit.AvailableBalance')}${groupCurrency(item.currency)}${item.balance}`,
+        value: item.login
+    }))
+})
+
+const dialogCheck = ref(false)
+const dialogVisible = ref(false)
+const dialogCheckWait = ref(false)
+
+const dialogSuccess = computed(() => dialogCheck.value && dialogVisible.value)
+const dialogError = computed(() => dialogCheck.value && !dialogVisible.value)
+
+const rules = {
+    login: {
+        rules: [{ required: true, errorMessage: t('vaildate.select.empty') }]
+    },
+    currency: {
+        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 (!/^[0-9]+([.]{1}[0-9]{1,2})?$/.test(value)) {
+                        callback(t('vaildate.amount.format'))
+                    }
+                    return true
                 }
-            ]
+            }
+        ]
     }
 }
-// 动态传入筛选字段配置
-const filterFields = computed(() => [
-    { key: 'type', type: 'select', label: t('Custom.PaymentHistory.payType'), placeholder: t('placeholder.choose'), options: typeMap.value, defaultValue: 1 },
-    { key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' }
-])
-const searchParams = ref({})
-const tableRef = ref(null)
-const handleSearch = (params) => {
-    search.value = params
-    nextTick(() => {
-        tableRef.value.refreshTable()
-    })
+const amountErrorMessage = ref('')
+const setAllAmount = () => {
+    form.amount = walletbalance.value.toFixed(2)
+    validateAmount()
 }
-
-const handleReset = (params) => {
-    search.value = params
-    nextTick(() => {
-        tableRef.value.refreshTable()
-    })
-}
-// 当前列配置
-const currentColumns = computed(() => getColumnsByType(search.value.type))
-// 获取状态文本
-const getStatusText = (row: any) => {
-    const status = row.status
-    // 根据不同记录类型处理状态
-    if (search.value.type === 1) {
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2 && row.accountStatus === 2) return t('State.Completed')
-        if (status === 2 && (row.accountStatus === 1 || !row.accountStatus)) return t('State.InTheProcessing')
-        if (status === 3) return t('State.Refused')
-    } else if (search.value.type === 2) {
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2 && row.leverageStatus === 2) return t('State.Completed')
-        if (status === 2 && row.leverageStatus === 1) return t('State.InTheProcessing')
-        if (status === 3) return t('State.Refused')
-    } else if (search.value.type === 3 || search.value.type === 5) {
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2 && row.withdrawStatus === 2 && row.depositStatus === 2) return t('State.Completed')
-        if (status === 2 && (row.withdrawStatus === 1 || row.depositStatus === 1)) return t('State.InTheProcessing')
-        if (status === 3 || row.withdrawStatus === 3 || row.depositStatus === 3) return t('State.Refused')
-    } else {
-        // 活动申请等
-        if (status === 1) return t('State.ToBeProcessed')
-        if (status === 2) return t('State.Completed')
-        if (status === 3) return t('State.Refused')
+function validateAmount() {
+    const value = form.amount
+    if (!value) {
+        amountErrorMessage.value = t('vaildate.amount.format')
+        return false
+    } else if (!/^[0-9]+([.]{1}[0-9]{1,2})?$/.test(value)) {
+        amountErrorMessage.value = t('vaildate.amount.format')
     }
-    return ''
+    amountErrorMessage.value = ''
+    return true
 }
-// 获取状态样式类
-const getStatusClass = (status: number) => {
-    const classMap: Record<number, string> = {
-        1: 'status-pending',
-        2: 'status-success',
-        3: 'status-processing',
-        4: 'status-danger'
+const formRef = ref(null)
+
+const closeDia = () => {
+    if (formRef.value) {
+        form.amount = ''
+        form.login = null
+        amountErrorMessage.value = ''
+        formRef.value.clearValidate()
     }
-    return classMap[status] || ''
+    dialogCheck.value = false
+    dialogVisible.value = false
 }
-// 获取账户类型文本
-const getAccountTypeText = (type: number) => {
-    const key = accountTypeMap[type as keyof typeof accountTypeMap]
-    return key ? t(key) : '--'
+
+const toTransfer = async () => {
+    try {
+        await formRef.value.validate()
+
+        if (walletbalance.value == '0' || Number(walletbalance.value) < Number(form.amount)) {
+            uni.showToast({ title: t('wallet.item64'), icon: 'none' })
+            return
+        }
+
+        if (flag.value) return
+        flag.value = true
+        dialogCheckWait.value = true
+
+        let res = await documentaryApi.followTransferApply({
+            transferType: 2,
+            ...form
+        })
+
+        if (res.code == Code.StatusOK) {
+            dialogCheck.value = true
+            dialogVisible.value = true
+            flag.value = false
+            getWalletList() // refresh balance after success
+        } else {
+            RES.value = res.msg
+            dialogCheck.value = true
+            dialogVisible.value = false
+            flag.value = false
+        }
+        dialogCheckWait.value = false
+    } catch (e) {
+        if (e.code == 400) {
+            dialogCheckWait.value = false
+            RES.value = e.msg
+            dialogCheck.value = true
+            dialogVisible.value = false
+            flag.value = false
+        }
+    }
 }
-// 格式化数字
-const formatNumber = (value: string | number) => {
-    if (!value) return '--'
-    const num = Number(value)
-    return isNaN(num) ? '--' : num.toFixed(2)
+
+const getToDateList = async () => {
+    loading.value = true
+    try {
+        let res = await documentaryApi.CustomDropdown({})
+        if (res.code == Code.StatusOK) {
+            toOptions.value = res.data || []
+        } else {
+            uni.showToast({ title: res.msg, icon: 'none' })
+        }
+    } catch (e) {
+        console.log(e)
+    }
+    loading.value = false
 }
-// 格式化备注
-const formatNote = (approveDesc: string) => {
-    if (!approveDesc) return '--'
-    const reason = reasons.value[approveDesc as keyof typeof reasons.value]
-    if (reason) {
-        return isZh.value ? reason.content : reason.enContent
+
+const getWalletList = async () => {
+    try {
+        let res = await documentaryApi.followWalletSingle({})
+        if (res.code == Code.StatusOK) {
+            walletbalance.value = res.data != null ? res.data.walletAmount : '0'
+        } else {
+            uni.showToast({ title: res.msg, icon: 'none' })
+        }
+    } catch (e) {
+        console.log(e)
     }
-    return approveDesc
 }
-const listApi = ref(null)
-listApi.value = customApi.CustomRecordAccount
+
+onMounted(() => {
+    getToDateList()
+    getWalletList()
+})
 </script>
 
 <style scoped lang="scss">
 @import "@/uni.scss";
 
-.avatar {
-    width: px2rpx(60);
-    height: px2rpx(60);
-    border-radius: 4px;
-}
+.transfer-page {
+    width: 100%;
+    padding-bottom: px2rpx(20);
 
-.content-title {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    font-size: px2rpx(20);
-    font-weight: 500;
-
-    .content-title-btns {
-        margin: px2rpx(8) 0;
-
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        gap: px2rpx(12);
-
-        .btn-primary {
-            min-width: px2rpx(120);
-            background-color: var(--color-error);
-            color: white;
-            padding: 0 px2rpx(12);
-            border: none;
-            font-size: px2rpx(14);
-            text-align: center;
-            cursor: pointer;
+    .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);
+
+                    .card-row {
+                        margin-bottom: px2rpx(30);
+
+                        &:last-child {
+                            margin-bottom: 0;
+                        }
+                    }
+
+                    .amount-box {
+                        display: flex;
+                        align-items: center;
+                        gap: px2rpx(12);
+
+                        .amount-input {
+                            flex: 1;
+                        }
+
+                        .btn {
+                            display: flex;
+                            align-items: center;
+                            justify-content: center;
+                            font-size: px2rpx(14);
+                            color: var(--color-zinc-600);
+                            margin-bottom: px2rpx(22);
+                            height: px2rpx(35);
+                            background-color: #cf1322;
+                            color: #fff;
+                            border-radius: px2rpx(4);
+                            font-weight: 600;
+                            display: flex;
+                            align-items: center;
+                            justify-content: center;
+                            border: none;
+                            padding: 0 px2rpx(20);
+                            cursor: pointer;
+                        }
+                    }
+
+                    .card-tit {
+                        margin-bottom: px2rpx(0) !important;
+                    }
+
+                    .tit {
+                        font-size: px2rpx(16);
+                        font-weight: 600;
+                        margin-bottom: px2rpx(16);
+                        display: flex;
+                        align-items: center;
+                        color: var(--color-navy-900);
+                        position: relative;
+                        padding-left: 20px;
+
+                        &:after {
+                            content: '';
+                            position: absolute;
+                            left: 0;
+                            top: 50%;
+                            transform: translateY(-50%);
+                            width: 0;
+                            height: 0;
+                            border-top: 6px solid transparent;
+                            border-bottom: 6px solid transparent;
+                            border-left: 8px solid currentColor;
+                        }
+
+                        .iconfont {
+                            margin-right: px2rpx(8);
+                            color: var(--color-primary);
+                            font-size: px2rpx(18);
+                        }
+                    }
+
+                    .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 #cf1322;
+
+                .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);
+        }
+    }
+
+
+    .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;
-            align-items: center;
             justify-content: center;
-            gap: px2rpx(8);
+            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);
         }
 
-        .btn-primary:active {
-            background-color: #cf1322;
-            ;
+        .icon {
+            .iconfont {
+                animation: spin 1s linear infinite;
+            }
         }
     }
 }
 
-.operation-btn {
-    :deep(span) {
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        gap: px2rpx(4);
-        cursor: pointer;
-        background-color: var(--color-slate-150);
-        padding: px2rpx(8) 0;
+// 动画
+@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);
     }
 }
 
-.operation-btn.disabled {
-    cursor: not-allowed;
-    opacity: 0.5;
+// 表单错误信息样式
+.uni-forms-item__error {
+    font-size: px2rpx(12);
+    color: #f56c6c;
+    margin-top: px2rpx(4);
 }
 
-.search-bar {
-    display: flex;
-    align-items: center;
-    justify-content: flex-start;
-    flex-wrap: wrap;
-    gap: px2rpx(16);
-    margin: px2rpx(16) 0;
-
-    .cwg-combox,
-    .uni-easyinput,
-    .uni-date {
-        width: px2rpx(240) !important;
-        flex: none;
+// 适配不同屏幕尺寸(媒体查询中的 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>