Przeglądaj źródła

Merge remote-tracking branch 'origin/admin_dev' into admin_dev

ljc 2 miesięcy temu
rodzic
commit
d0b231d0cd

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

@@ -85,6 +85,7 @@ const openLink = (url) => {
             font-size: px2rpx(12);
             letter-spacing: px2rpx(0.5);
             color: #0066cc;
+            text-decoration: underline;
             cursor: pointer;
 
             &:active {

+ 5 - 11
components/cwg-empty-state.vue

@@ -2,22 +2,16 @@
   <view class="empty-state">
     <image class="img" src="/static/images/undraw.png" alt="" />
     <view class="r">
-      <view class="title">{{ t('Documentary.tradingCenter.item131') }}</view>
+      <view class="title" v-if="title" v-t="title" />
+      <view class="title" v-else v-t="'Documentary.tradingCenter.item143'" />
     </view>
   </view>
 </template>
 
 <script setup lang="ts">
-import { useI18n } from 'vue-i18n';
-const { t } = useI18n();
-withDefaults(
-  defineProps<{
-    text?: string;
-  }>(),
-  {
-    text: "",
-  }
-);
+const props = defineProps({
+  title: { type: String, default: '' }
+});
 </script>
 
 <style scoped lang="scss">

+ 13 - 6
composables/useMenuSplit.ts

@@ -181,7 +181,7 @@ export function useMenuSplit() {
             isOpenMenu: false,
             submenuHeight: 0,
             path: '/',
-            label: 'Latest.PaymentWallet',
+            label: 'vu.item6',
             icon: 'crm-payment',
             children: [
                 { path: '/pages/customer/deposit', label: 'Home.page_customer.item2', icon: 'icon-deposit' },
@@ -190,10 +190,17 @@ export function useMenuSplit() {
                 { path: '/pages/customer/transfer', label: 'Custom.Index.Transfer', icon: 'icon-transfer' },
             ],
         },
+        {
+            path: '/pages/activities/index',
+            isOpenMenu: false,
+            label: 'Home.page_customer.item6',
+            icon: 'crm-hd',
+            children: [],
+        },
         {
             path: '/',
             isOpenMenu: false,
-            label: 'News.News',
+            label: 'vu.item5',
             icon: 'crm-chart-area',
             children: [
                 { path: '/pages/analytics/analystViews', label: 'News.Announcement', icon: 'icon-application' },
@@ -207,7 +214,7 @@ export function useMenuSplit() {
             ],
         },
         {
-            path: '/pages/customer/withdrawal',
+            path: '/pages/common/download',
             isOpenMenu: false,
             label: 'Downloadpage.item1',
             icon: 'crm-download',
@@ -238,8 +245,8 @@ export function useMenuSplit() {
     const ibBaseMenus = computed<MenuItem[]>(() => [
         {
             isOpenMenu: false,
-            path: '/pages/ib/index',
-            label: 'Home.page_ib.item1',
+            path: '/',
+            label: 'Documentary.console.item1',
             icon: 'crm-mb',
         },
         {
@@ -257,7 +264,7 @@ export function useMenuSplit() {
             isOpenMenu: false,
             submenuHeight: 0,
             path: '/',
-            label: 'Latest.PaymentWallet',
+            label: 'vu.item6',
             icon: 'crm-payment',
             children: [
                 { path: '/pages/ib/transfer', label: 'Home.page_ib.item4', icon: 'icon-payment' },

+ 12 - 2
locale/ar.json

@@ -1,5 +1,14 @@
 {
-    "common": {
+  "vu": {
+    "item1": "حقيقي",
+    "item2": "عينة",
+    "item3": "تغيير كلمة مرور التداول",
+    "item4": "تغيير كلمة مرور المستثمر",
+    "item5": "تحليل",
+    "item6": "الدفع والمحفظة",
+    "item7": "المزيد"
+  },
+  "common": {
     "confirm": "تأكيد",
     "cancel": "إلغاء",
     "loading": "جارٍ التحميل...",
@@ -905,7 +914,8 @@
       "item139": "منحنى القيمة الصافية",
       "item140": "منحنى الترتيب",
       "item141": "النتيجة الإجمالية",
-      "item142": "سبب التوصية"
+      "item142": "سبب التوصية",
+      "item143": "لا توجد بيانات"
     },
     "TundManagement": {
       "item1": "الإيداع",

+ 11 - 5
locale/cn.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "真实",
+    "item2": "模拟",
+    "item3": "修改交易密码",
+    "item4": "修改投资者密码",
+    "item5": "分析",
+    "item6": "支付与钱包",
+    "item7": "更多"
+  },
   "common": {
     "confirm": "确认",
     "cancel": "取消",
@@ -18,10 +27,6 @@
     "day": "日",
     "upload": "上传"
   },
-  "Latest": {
-    "PaymentWallet": "支付与钱包",
-    "More": "更多"
-  },
   "pages": {
     "login": {
       "index": "登录",
@@ -959,7 +964,8 @@
       "item139": "净值曲线",
       "item140": "排名曲线",
       "item141": "综合分",
-      "item142": "推荐理由"
+      "item142": "推荐理由",
+      "item143": "暂无数据"
     },
     "TundManagement": {
       "item1": "存入",

+ 11 - 1
locale/de.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "Echt",
+    "item2": "Demo",
+    "item3": "Handels Passwort ändern",
+    "item4": "Investor Passwort ändern",
+    "item5": "Analyse",
+    "item6": "Zahlung & Wallet",
+    "item7": "Mehr"
+  },
   "common": {
     "confirm": "Bestätigen",
     "cancel": "Abbrechen",
@@ -905,7 +914,8 @@
       "item139": "Nettowertkurve",
       "item140": "Rangfolgekurve",
       "item141": "Gesamtpunktzahl",
-      "item142": "Empfehlungsgrund"
+      "item142": "Empfehlungsgrund",
+      "item143": "Keine Daten"
     },
     "TundManagement": {
       "item1": "Einzahlung",

+ 11 - 1
locale/en.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "Real",
+    "item2": "Demo",
+    "item3": "Change Trading Password",
+    "item4": "Change Investor Password",
+    "item5": "Analysis",
+    "item6": "Payment & Wallet",
+    "item7": "More"
+  },
   "common": {
     "confirm": "Confirm",
     "cancel": "Cancel",
@@ -938,7 +947,8 @@
       "item139": "Net Value Curve",
       "item140": "Ranking Curve",
       "item141": "Total Score",
-      "item142": "Recommend Reason"
+      "item142": "Recommend Reason",
+      "item143": "No data "
     },
     "TundManagement": {
       "item1": "Deposit",

+ 11 - 1
locale/es.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "Real",
+    "item2": "Demo",
+    "item3": "Cambiar Contraseña de Trading",
+    "item4": "Cambiar Contraseña de Inversor",
+    "item5": "Análisis",
+    "item6": "Pago & Billetera",
+    "item7": "Más"
+  },
   "common": {
     "confirm": "Confirmar",
     "cancel": "Cancelar",
@@ -905,7 +914,8 @@
       "item139": "Curva de Valor Neto",
       "item140": "Curva de Clasificación",
       "item141": "Puntuación Total",
-      "item142": "Razón de Recomendación"
+      "item142": "Razón de Recomendación",
+      "item143": "Sin datos"
     },
     "TundManagement": {
       "item1": "Depósito",

+ 11 - 1
locale/fa.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "حقیقی",
+    "item2": "دمو",
+    "item3": "تغییر رمز عبور معاملاتی",
+    "item4": "تغییر رمز عبور инвестور",
+    "item5": "تحلیل",
+    "item6": "پرداخت و کیف پول",
+    "item7": "بیشتر"
+  },
   "common": {
     "confirm": "تأیید",
     "cancel": "لغو",
@@ -905,7 +914,8 @@
       "item139": "منحنی ارزش خالص",
       "item140": "منحنی رتبه‌بندی",
       "item141": "امتیاز کل",
-      "item142": "دلیل توصیه"
+      "item142": "دلیل توصیه",
+      "item143": "بدون داده"
     },
     "TundManagement": {
       "item1": "واریز",

+ 11 - 1
locale/id.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "Real",
+    "item2": "Demo",
+    "item3": "Ubah Kata Sandi Trading",
+    "item4": "Ubah Kata Sandi Investor",
+    "item5": "Analisis",
+    "item6": "Pembayaran & Dompet",
+    "item7": "Lebih Banyak"
+  },
   "common": {
     "confirm": "Konfirmasi",
     "cancel": "Batal",
@@ -856,7 +865,8 @@
       "item139": "Kurva Nilai Bersih",
       "item140": "Kurva Peringkat",
       "item141": "Total Skor",
-      "item142": "Alasan Rekomendasi"
+      "item142": "Alasan Rekomendasi",
+      "item143": "Tidak ada data"
     },
     "TundManagement": {
       "item1": "Deposit",

+ 11 - 1
locale/ko.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "실제",
+    "item2": "데모",
+    "item3": "거래 비밀번호 변경",
+    "item4": "투자자 비밀번호 변경",
+    "item5": "분석",
+    "item6": "결제 및 지갑",
+    "item7": "더 보기"
+  },
   "common": {
     "confirm": "확인",
     "cancel": "취소",
@@ -905,7 +914,8 @@
       "item139": "순자산 곡선",
       "item140": "순위 곡선",
       "item141": "종합 점수",
-      "item142": "추천 이유"
+      "item142": "추천 이유",
+      "item143": "데이터 없음"
     },
     "TundManagement": {
       "item1": "예금",

+ 11 - 1
locale/ms.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "Real",
+    "item2": "Demo",
+    "item3": "Tukar Kata Laluan Perdagangan",
+    "item4": "Tukar Kata Laluan Pelabur",
+    "item5": "Analisis",
+    "item6": "Pembayaran & Dompet",
+    "item7": "Lebih Banyak"
+  },
   "common": {
     "confirm": "Sahkan",
     "cancel": "Batal",
@@ -905,7 +914,8 @@
       "item139": "Lengkung Nilai Bersih",
       "item140": "Lengkung Kedudukan",
       "item141": "Jumlah Markah",
-      "item142": "Sebab Cadangan"
+      "item142": "Sebab Cadangan",
+      "item143": "Tiada data"
     },
     "TundManagement": {
       "item1": "Deposit",

+ 11 - 1
locale/pt.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "Real",
+    "item2": "Demo",
+    "item3": "Alterar Senha de Trading",
+    "item4": "Alterar Senha do Investidor",
+    "item5": "Análise",
+    "item6": "Pagamento & Carteira",
+    "item7": "Mais"
+  },
   "common": {
     "confirm": "Confirmar",
     "cancel": "Cancelar",
@@ -905,7 +914,8 @@
       "item139": "Curva de Valor Líquido",
       "item140": "Curva de Classificação",
       "item141": "Pontuação Total",
-      "item142": "Razão da Recomendação"
+      "item142": "Razão da Recomendação",
+      "item143": "Sem dados"
     },
     "TundManagement": {
       "item1": "Depósito",

+ 11 - 1
locale/th.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "จริง",
+    "item2": "แบบจำลอง",
+    "item3": "เปลี่ยนรหัสผ่านการเทรด",
+    "item4": "เปลี่ยนรหัสผ่านนักลงทุน",
+    "item5": "วิเคราะห์",
+    "item6": "การชำระเงินและกระเป๋าเงิน",
+    "item7": "อื่น ๆ"
+  },
   "common": {
     "confirm": "ยืนยัน",
     "cancel": "ยกเลิก",
@@ -905,7 +914,8 @@
       "item139": "เส้นโค้งมูลค่าสุทธิ",
       "item140": "เส้นโค้งการจัดอันดับ",
       "item141": "คะแนนรวม",
-      "item142": "เหตุผลในการแนะนำ"
+      "item142": "เหตุผลในการแนะนำ",
+      "item143": "ไม่มีข้อมูล"
     },
     "TundManagement": {
       "item1": "ฝากเงิน",

+ 11 - 1
locale/tr.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "Gerçek",
+    "item2": "Demo",
+    "item3": "Ticaret Şifresini Değiştir",
+    "item4": "Yatırımcı Şifresini Değiştir",
+    "item5": "Analiz",
+    "item6": "Ödeme ve Cüzdan",
+    "item7": "Daha Fazla"
+  },
   "common": {
     "confirm": "Onayla",
     "cancel": "İptal",
@@ -905,7 +914,8 @@
       "item139": "Net Değer Eğrisi",
       "item140": "Sıralama Eğrisi",
       "item141": "Toplam Skor",
-      "item142": "Öneri Nedeni"
+      "item142": "Öneri Nedeni",
+      "item143": "Veri Yok"
     },
     "TundManagement": {
       "item1": "Depozito",

+ 11 - 1
locale/vn.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "Thực tế",
+    "item2": "Demo",
+    "item3": "Đổi mật khẩu giao dịch",
+    "item4": "Đổi mật khẩu nhà đầu tư",
+    "item5": "Phân tích",
+    "item6": "Thanh toán và Ví",
+    "item7": "Thêm"
+  },
   "common": {
     "confirm": "Xác nhận",
     "cancel": "Hủy",
@@ -905,7 +914,8 @@
       "item139": "Đường cong Giá trị Ròng",
       "item140": "Đường cong Xếp hạng",
       "item141": "Tổng điểm",
-      "item142": "Lý do đề xuất"
+      "item142": "Lý do đề xuất",
+      "item143": "Không có dữ liệu"
     },
     "TundManagement": {
       "item1": "Tiền vào",

+ 11 - 1
locale/zhHant.json

@@ -1,4 +1,13 @@
 {
+  "vu": {
+    "item1": "真實",
+    "item2": "模擬",
+    "item3": "修改交易密碼",
+    "item4": "修改投資者密碼",
+    "item5": "分析",
+    "item6": "支付與錢包",
+    "item7": "更多"
+  },
   "common": {
     "confirm": "確認",
     "cancel": "取消",
@@ -908,7 +917,8 @@
       "item139": "淨值曲線",
       "item140": "排名曲線",
       "item141": "綜合分",
-      "item142": "推薦理由"
+      "item142": "推薦理由",
+      "item143": "暫無數據"
     },
     "TundManagement": {
       "item1": "存入",

+ 21 - 0
pages.json

@@ -100,6 +100,20 @@
         "navigationStyle": "custom"
       }
     },
+    {
+      "path": "pages/activities/monthly-list",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/activities/surplus-list",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/activities/detail",
       "style": {
@@ -282,6 +296,13 @@
         "navigationStyle": "custom"
       }
     },
+    {
+      "path": "pages/common/download",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/common/notice",
       "style": {

+ 40 - 21
pages/activities/components/ActivityCard.vue

@@ -5,24 +5,20 @@
             <view v-if="config.hot" class="btn-tag-star">
                 <uni-icons type="star-filled" size="16" color="#ffd700"></uni-icons>
             </view>
-
             <!-- 图片区域 -->
             <view class="img crm-cursor" @click="handleClick">
                 <image :src="imageSrc" mode="widthFix" />
-                <!-- <view v-if="config.imageTitle" class="imgTitle">{{ t(config.imageTitle) }}</view> -->
             </view>
-
             <!-- 内容区域 -->
             <view class="content">
                 <view class="content-box">
                     <view v-if="config.time" class="time">{{ config.time }}</view>
                     <view class="title" @click="handleClick">{{ t(config.title) }}</view>
                     <view v-if="config.description" class="des crm-one-font">{{ t(config.description) }}</view>
-
                     <!-- 按钮区域 -->
                     <view class="bottom">
                         <template v-for="(btn, index) in config.buttons" :key="index">
-                            <span v-if="shouldShowButton(btn)" :class="['btn', getButtonType(btn)]"
+                            <text v-if="shouldShowButton(btn)" :class="['btn', getButtonType(btn)]"
                                 @click="handleButtonClick(btn)">
                                 {{ t(btn.text) }}
                                 <template v-if="btn.suffix && state[btn.suffix]">
@@ -31,10 +27,10 @@
                                 <template v-if="btn.suffixText">
                                     {{ t(btn.suffixText) }}
                                 </template>
-                            </span>
-                            <span v-else-if="btn.elseType && btn.condition" :class="['btn', btn.elseType]">
+                            </text>
+                            <text v-else-if="btn.elseType && btn.condition" :class="['btn', btn.elseType]">
                                 {{ t(btn.text) }}
-                            </span>
+                            </text>
                         </template>
                     </view>
                 </view>
@@ -48,7 +44,6 @@ import { computed } from 'vue'
 import { useI18n } from 'vue-i18n'
 
 const { t, locale } = useI18n()
-
 const props = defineProps<{
     config: any
     state?: Record<string, any>
@@ -58,6 +53,7 @@ const emit = defineEmits(['action'])
 
 // 图片源
 const imageSrc = computed(() => {
+
     if (typeof props.config.image === 'object') {
         const lang = locale.value || 'en'
         return props.config.image[lang] || props.config.image.default
@@ -90,11 +86,36 @@ const shouldShowButton = (btn: any): boolean => {
         return false
     }
 }
+// 判断按钮是否灰色
+const shouldClassCondition = (btn: any): boolean => {
+    if (!btn.classCondition) return true
+    if (!props.state) return false
+
+    try {
+        const conditionStr = btn.classCondition
+        const evalStr = conditionStr.replace(/([a-zA-Z_][a-zA-Z0-9_.]*)/g, (match) => {
+            if (match.includes('.')) {
+                const parts = match.split('.')
+                let value: any = props.state
+                for (const part of parts) {
+                    value = value?.[part]
+                }
+                return JSON.stringify(value)
+            }
+            return JSON.stringify(props.state[match])
+        })
+        const fn = new Function(`return ${evalStr}`)
+        return fn()
+    } catch (error) {
+        console.error('按钮条件评估失败:', error, btn.condition)
+        return false
+    }
+}
 
 // 获取按钮类型
 const getButtonType = (btn: any): string => {
     if (btn.type === 'dynamic') {
-        return shouldShowButton(btn) ? 'red' : 'gray'
+        return shouldShowButton(btn) && shouldClassCondition(btn) ? 'red' : 'red gray'
     }
     return btn.type
 }
@@ -128,7 +149,6 @@ const handleButtonClick = (btn: any) => {
     position: relative;
     margin-bottom: px2rpx(20);
     padding: 0;
-    // overflow: hidden;
     aspect-ratio: 3 / 4;
 
     .btn-tag-star {
@@ -241,25 +261,24 @@ const handleButtonClick = (btn: any) => {
                 white-space: nowrap;
                 letter-spacing: px2rpx(1);
                 text-transform: uppercase;
+                padding: px2rpx(8) px2rpx(16);
+                box-sizing: border-box;
+                cursor: pointer;
 
                 &.red {
                     width: 100%;
                     background-color: var(--color-secondary);
-                    border: 1px solid #333333;
-                }
-
-                &.gray {
-                    padding: px2rpx(8) px2rpx(16);
-                    font-size: px2rpx(11);
-                    background-color: var(--color-navy-200);
-                    border: 1px solid var(--color-sky-100);
                 }
 
                 &.check {
-                    padding: px2rpx(8) px2rpx(16);
                     font-size: px2rpx(11);
                     background-color: var(--color-error);
                 }
+
+                &.gray {
+                    cursor: not-allowed;
+                    background-color: var(--color-navy-200);
+                }
             }
         }
     }
@@ -296,7 +315,7 @@ const handleButtonClick = (btn: any) => {
     .active-box {
 
         .title {
-            width: px2rpx(200)  !important;
+            width: px2rpx(200) !important;
         }
     }
 }

+ 338 - 0
pages/activities/components/GiftApplicationPopup.vue

@@ -0,0 +1,338 @@
+<template>
+  <cwg-popup v-model:visible="visible" type="center" :mask-click="false" :showFooters="true" :showClose="false"
+    :title="title">
+    <view class="popup-content">
+      <uni-forms ref="formRef" :model="giftForm" :rules="rules" label-position="top" validate-trigger="submit">
+        <view class="form-row">
+          <view class="form-col-full">
+            <uni-forms-item :label="t('UtaskList.item18')" name="giveCode">
+              <cwg-combox v-model:value="giftForm.giveCode" :clearable="false" :options="giftOptions"
+                :placeholder="t('UtaskList.item19')" @change="handleGiftChange" />
+            </uni-forms-item>
+          </view>
+        </view>
+        <view class="form-row">
+          <view class="form-col-full">
+            <uni-forms-item :label="t('UtaskList.item20')" name="giveAddress">
+              <uni-easyinput v-model="giftForm.giveAddress" :placeholder="t('UtaskList.item21')" />
+            </uni-forms-item>
+          </view>
+        </view>
+        <view class="form-row">
+          <view class="form-col-full">
+            <uni-forms-item :label="t('UtaskList.item24')" name="giveAcceptName">
+              <uni-easyinput v-model="giftForm.giveAcceptName" :placeholder="t('UtaskList.item25')" />
+            </uni-forms-item>
+          </view>
+        </view>
+        <view class="form-row">
+          <view class="form-col-full">
+            <uni-forms-item :label="t('UtaskList.item22')" name="givePhone">
+              <uni-easyinput v-model="giftForm.givePhone" :placeholder="t('UtaskList.item23')" />
+            </uni-forms-item>
+          </view>
+        </view>
+      </uni-forms>
+    </view>
+    <template #footer>
+      <button @click="cancel">{{ t('Btn.Cancel') }}</button>
+      <button type="primary" @click="submit" :loading="submitting">{{ t('Btn.Confirm') }}</button>
+    </template>
+  </cwg-popup>
+</template>
+
+<script setup>
+import { ref, computed, reactive, watch } from 'vue';
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+  visible: { type: Boolean, default: false },
+  title: { type: String, default: '' },
+  giftList: { type: Array, default: () => [] },
+  giftForm: { type: Object, default: () => ({}) }
+});
+const emit = defineEmits(['update:visible', 'confirm', 'cancel']);
+const { t, locale } = useI18n();
+
+const visible = computed({
+  get: () => props.visible,
+  set: (value) => emit('update:visible', value)
+});
+
+// 表单数据
+const giftForm = reactive({
+  giveCode: props.giftForm.giveCode || '',
+  giveAddress: props.giftForm.giveAddress || '',
+  giveAcceptName: props.giftForm.giveAcceptName || '',
+  givePhone: props.giftForm.givePhone || ''
+});
+
+// 表单引用
+const formRef = ref(null);
+// 提交状态
+const submitting = ref(false);
+
+// 礼物选项
+const giftOptions = computed(() => {
+  return props.giftList.map(gift => ({
+    text: `${gift.giveCode} - ${gift.giveName}`,
+    value: gift.giveCode
+  }));
+});
+
+// 表单验证规则
+const rules = {
+  giveCode: {
+    rules: [
+      {
+        required: true,
+        errorMessage: t("UtaskList.item19")
+      }
+    ]
+  },
+  giveAddress: {
+    rules: [
+      {
+        required: true,
+        errorMessage: t("UtaskList.item21")
+      }
+    ]
+  },
+  giveAcceptName: {
+    rules: [
+      {
+        required: true,
+        errorMessage: t("UtaskList.item25")
+      }
+    ]
+  },
+  givePhone: {
+    rules: [
+      {
+        required: true,
+        errorMessage: t("UtaskList.item23")
+      }
+    ]
+  }
+};
+
+const cancel = () => {
+  visible.value = false;
+  emit('cancel');
+};
+
+const handleGiftChange = (value) => {
+  giftForm.giveCode = value;
+};
+
+const submit = async () => {
+  if (submitting.value) return;
+  submitting.value = true;
+
+  try {
+    // 表单验证
+    await formRef.value?.validate();
+
+    visible.value = false;
+    emit('confirm', giftForm);
+  } catch (error) {
+    console.log('Form validation failed:', error);
+  } finally {
+    submitting.value = false;
+  }
+};
+watch(() => props.visible, (newVal) => {
+  if (newVal) {
+    giftForm.giveCode = ''
+    giftForm.giveAddress = ''
+    giftForm.giveAcceptName = ''
+    giftForm.givePhone = ''
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+
+.popup-content {
+  padding: px2rpx(20);
+
+  .form-row {
+    margin-bottom: px2rpx(20);
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  .form-col-full {
+    width: 100%;
+  }
+
+  :deep(.uni-forms) {
+    width: 100%;
+
+    :deep(.uni-forms-item) {
+      margin-bottom: px2rpx(16);
+
+      :deep(.uni-forms-item__label) {
+        font-size: px2rpx(14);
+        color: #606266;
+        margin-bottom: px2rpx(8);
+      }
+
+      :deep(.uni-forms-item__error) {
+        font-size: px2rpx(12);
+        color: #f56c6c;
+        margin-top: px2rpx(4);
+      }
+
+      :deep(.uni-easyinput) {
+        width: 100%;
+
+        :deep(input) {
+          width: 100%;
+          height: px2rpx(40);
+          padding: 0 px2rpx(12);
+          border: 1px solid #dcdfe6;
+          border-radius: px2rpx(4);
+          font-size: px2rpx(14);
+          transition: border-color 0.3s;
+
+          &:focus {
+            outline: none;
+            border-color: #409eff;
+            box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+          }
+        }
+      }
+
+      :deep(.cwg-combox) {
+        width: 100%;
+
+        :deep(.uni-select) {
+          width: 100%;
+
+          :deep(.uni-select-input) {
+            width: 100%;
+            height: px2rpx(40);
+            padding: 0 px2rpx(12);
+            border: 1px solid #dcdfe6;
+            border-radius: px2rpx(4);
+            font-size: px2rpx(14);
+            transition: border-color 0.3s;
+
+            &:focus {
+              outline: none;
+              border-color: #409eff;
+              box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .tips {
+    background-color: #f5f7fa;
+    border-radius: px2rpx(8);
+    padding: px2rpx(16);
+    margin-bottom: px2rpx(20);
+
+    .title {
+      font-size: px2rpx(14);
+      font-weight: 600;
+      color: #303133;
+      margin-bottom: px2rpx(8);
+    }
+
+    view {
+      font-size: px2rpx(13);
+      color: #606266;
+      line-height: 1.5;
+      margin-bottom: px2rpx(8);
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+    }
+  }
+
+  button {
+    width: 100%;
+    height: px2rpx(44);
+    border-radius: px2rpx(4);
+    font-size: px2rpx(16);
+    font-weight: 500;
+    transition: all 0.3s;
+
+    &.reselect {
+      background-color: #409eff;
+      color: #ffffff;
+      border: none;
+
+      &:hover {
+        background-color: #66b1ff;
+      }
+
+      &:active {
+        background-color: #3a8ee6;
+      }
+
+      &[disabled] {
+        background-color: #c6e2ff;
+        cursor: not-allowed;
+      }
+    }
+  }
+}
+
+@media (max-width: 768px) {
+  .popup-content {
+    padding: px2rpx(16);
+
+    .form-row {
+      margin-bottom: px2rpx(16);
+    }
+
+    :deep(.uni-forms) {
+      :deep(.uni-forms-item) {
+        margin-bottom: px2rpx(12);
+
+        :deep(.uni-easyinput) {
+          :deep(input) {
+            height: px2rpx(36);
+            font-size: px2rpx(13);
+          }
+        }
+
+        :deep(.cwg-combox) {
+          :deep(.uni-select) {
+            :deep(.uni-select-input) {
+              height: px2rpx(36);
+              font-size: px2rpx(13);
+            }
+          }
+        }
+      }
+    }
+
+    .tips {
+      padding: px2rpx(12);
+
+      .title {
+        font-size: px2rpx(13);
+      }
+
+      view {
+        font-size: px2rpx(12);
+      }
+    }
+
+    button {
+      height: px2rpx(40);
+      font-size: px2rpx(15);
+    }
+  }
+}
+</style>

+ 4 - 4
pages/activities/composables/useActivityActions.ts

@@ -126,7 +126,7 @@ export function useActivityActions(
     }
 
     const toActivity24Trading = () => {
-        uni.navigateTo({ url: '/pages/customer/new' })
+        uni.navigateTo({ url: '/pages/analytics/new' })
     }
 
     const toHistoryLuckyDraw = () => {
@@ -134,15 +134,15 @@ export function useActivityActions(
     }
 
     const toTaskList = () => {
-        uni.navigateTo({ url: '/pages/customer/task/list' })
+        uni.navigateTo({ url: '/pages/customer/task-list' })
     }
 
     const goSurplusTaskList = () => {
-        uni.navigateTo({ url: '/pages/customer/surplus/list' })
+        uni.navigateTo({ url: '/pages/activities/surplus-list' })
     }
 
     const goMonthlyTaskList = () => {
-        uni.navigateTo({ url: '/pages/customer/monthly/list' })
+        uni.navigateTo({ url: '/pages/activities/monthly-list' })
     }
 
     const toDocumentary = () => {

+ 75 - 80
pages/activities/composables/useActivityData.ts

@@ -1,11 +1,11 @@
 import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
 import { useI18n } from 'vue-i18n'
-import {activityApi} from '@/service/activity'
-import {customApi} from '@/service/custom'
+import { activityApi } from '@/service/activity'
+import { customApi } from '@/service/custom'
 import Config from '@/config/index'
 import type { ActivityState, PagerInfo, AccountInfo } from '../types/activity'
-
-const { Code, Host80 } = Config
+import useUserStore from "@/stores/use-user-store";
+const { Code, Host05 } = Config
 
 // 国家列表
 const countries = [
@@ -21,28 +21,20 @@ const countries = [
 
 export function useActivityData() {
     const { t, locale } = useI18n()
-    
+    const userStore = useUserStore();
     // ==================== 用户信息 ====================
-    const userInfo = computed(() => {
-        try {
-            return JSON.parse(uni.getStorageSync('user') || '{}')
-        } catch {
-            return { customInfo: {} }
-        }
-    })
-    
-    const country = computed(() => userInfo.value.customInfo?.country || '')
-    const myCid = computed(() => userInfo.value.customInfo?.cId || '')
-    
+    const country = computed(() => userStore?.userInfo?.customInfo?.country || '')
+    const myCid = computed(() => userStore?.userInfo?.customInfo?.cId || '')
+
     // ==================== 加载状态 ====================
     const pictLoading = ref(false)
     const flag = ref(false)
-    
+
     // ==================== 活动数据 ====================
     const tableData = ref<any[]>([])
     const tableDataGive = ref<any[]>([])
     const singleData = ref<any>({})
-    
+
     // 分页
     const pagerInfo = ref<PagerInfo>({
         row: 10,
@@ -50,11 +42,19 @@ export function useActivityData() {
         pageTotal: 0,
         rowTotal: 0
     })
-    
+
     // 账户列表
     const loginOptions = ref<AccountInfo[]>([])
     const loginOptions1 = ref<AccountInfo[]>([])
-    
+
+    // 判断匠鑫活动是否报名结束
+    const timeExpireJx = (endTime: string) => {
+        if (!endTime) return false
+        const endTime1 = endTime.replace(/-/g, '/').split(' ')[0]
+        const now = getCurrentTime(2).getTime()
+        const end = new Date(endTime1).getTime()
+        return now < end
+    }
     // ==================== 活动特定状态 ====================
     const activityState = reactive<ActivityState>({
         tableDataNewYear24Flag: false,
@@ -96,25 +96,26 @@ export function useActivityData() {
         country: country.value,
         lang: locale.value,
         isGuoQin: false,
-        isSupportedCountry: false
+        isSupportedCountry: false,
+        timeExpireJx: timeExpireJx
     })
-    
+
     // 交易大赛参数
     const tableDataCptFlagCode = ref('')
-    
+
     // 新年庆典数据
     const NewYear24DataBalance = ref('')
     const NewYear24Data = ref({ balance: 0, income: 0 })
-    
+
     // 定时器
     const interval = ref<any>(null)
-    
+
     // ==================== 计算属性 ====================
     // 是否支持的国家
     const isSupportedCountry = computed(() => {
         return countries.includes(country.value)
     })
-    
+
     // 国庆节判断
     const isGuoQin = computed(() => {
         const startTime1 = '2024/10/01 00:00:00'
@@ -127,7 +128,7 @@ export function useActivityData() {
         const start = new Date(startTime1).getTime()
         return now > start && now < end
     })
-    
+
     // ==================== 工具函数 ====================
     // 获取当前时间(带时区)
     const getCurrentTime = (timezone: number = 2) => {
@@ -135,12 +136,12 @@ export function useActivityData() {
         const nowDate = new Date().getTime()
         return new Date(nowDate + offset_GMT * 60 * 1000 + timezone * 60 * 60 * 1000)
     }
-    
+
     // 时间补0
     const getzero = (time: number) => {
         return time > 9 ? time : '0' + time
     }
-    
+
     // 时间格式转换
     const timeConvert = (val: string) => {
         if (!val) return ''
@@ -152,7 +153,7 @@ export function useActivityData() {
         if (date < 10) date = '0' + date
         return year + '年' + month + '月' + date + '日'
     }
-    
+
     // 货币符号
     const groupCurrency = (type: string) => {
         const map: Record<string, string> = {
@@ -163,7 +164,7 @@ export function useActivityData() {
         }
         return map[type] || ': $'
     }
-    
+
     // 账户类型名称
     const groupTypeName = (type: string) => {
         const map: Record<string, string> = {
@@ -177,7 +178,7 @@ export function useActivityData() {
         }
         return map[type] ? t(map[type]) : ''
     }
-    
+
     // 判断活动是否在有效期内
     const overdue = (startTime: string, endTime: string) => {
         if (!startTime || !endTime) return false
@@ -188,21 +189,13 @@ export function useActivityData() {
         const end = new Date(endTime1).getTime()
         return start < now && now < end
     }
-    
-    // 判断匠鑫活动是否报名结束
-    const timeExpireJx = (endTime: string) => {
-        if (!endTime) return false
-        const endTime1 = endTime.replace(/-/g, '/').split(' ')[0]
-        const now = getCurrentTime(2).getTime()
-        const end = new Date(endTime1).getTime()
-        return now < end
-    }
-    
+
+
     // 判断是否在9月30日之后
     const isAfterSeptember30 = () => {
         return true // 根据实际需求修改
     }
-    
+
     // ==================== API 请求函数 ====================
     // 获取账户信息
     const getDateList = async () => {
@@ -217,13 +210,13 @@ export function useActivityData() {
             console.error('获取账户信息失败', error)
         }
     }
-    
+
     // 获取活动列表
     const searchFunc = async (page: number = 1) => {
         if (flag.value) return
         flag.value = true
         pictLoading.value = true
-        
+
         try {
             const res = await activityApi.ActivityExtensionIist({
                 hot: '',
@@ -234,7 +227,7 @@ export function useActivityData() {
                     row: pagerInfo.value.row
                 }
             })
-            
+
             if (res.code == Code.StatusOK) {
                 tableData.value = res.data
                 pagerInfo.value.rowTotal = res.page.rowTotal
@@ -249,7 +242,7 @@ export function useActivityData() {
             flag.value = false
         }
     }
-    
+
     // 获取赠送活动列表
     const searchFunc1 = async () => {
         pictLoading.value = true
@@ -261,7 +254,9 @@ export function useActivityData() {
                 }
             })
             if (res.code == Code.StatusOK) {
-                tableDataGive.value = res.data
+                tableDataGive.value = res.data.map((i) => {
+                    return { ...i, image: Host05 + i.coverUrl }
+                })
                 pagerInfo.value.rowTotal = res.page.rowTotal
                 pagerInfo.value.pageTotal = res.page.pageTotal
             } else {
@@ -273,7 +268,7 @@ export function useActivityData() {
             pictLoading.value = false
         }
     }
-    
+
     // 获取单个活动详情
     const getSingle = async (id: string) => {
         try {
@@ -287,7 +282,7 @@ export function useActivityData() {
             console.error('获取活动详情失败', error)
         }
     }
-    
+
     // 获取赠送活动详情
     const getSingle1 = async (id: string) => {
         try {
@@ -301,7 +296,7 @@ export function useActivityData() {
             console.error('获取赠送活动详情失败', error)
         }
     }
-    
+
     // 2023迎新活动数据
     const Activity23HundredInfo = async () => {
         try {
@@ -313,7 +308,7 @@ export function useActivityData() {
                     const nowTime = getCurrentTime(2).getTime()
                     const startTime = new Date(activityState.tableData2.activityStartTime.replace(/-/g, '/')).getTime()
                     const endTime = new Date(activityState.tableData2.activityEndTime.replace(/-/g, '/')).getTime()
-                    
+
                     if (nowTime < endTime && nowTime > startTime) {
                         if (activityState.tableData2.status == 2 && activityState.tableData2.activityStatus == 0) {
                             activityState.isTransform = 1
@@ -327,7 +322,7 @@ export function useActivityData() {
                     } else {
                         activityState.isTransform = 2
                     }
-                    
+
                     if (activityState.tableData2.status == 2 && activityState.tableData2.activityStatus == 2) {
                         activityState.isTransform = null
                         if (activityState.tableData2.realizationStatus == 0) {
@@ -354,7 +349,7 @@ export function useActivityData() {
             console.error('获取2023迎新活动数据失败', error)
         }
     }
-    
+
     // 2023匠鑫活动数据
     const Activity23JiangxinInfo = async () => {
         try {
@@ -384,7 +379,7 @@ export function useActivityData() {
             console.error('获取2023匠鑫活动数据失败', error)
         }
     }
-    
+
     // 2023匠鑫活动数据Vip
     const Activity23JiangxinInfoVip = async () => {
         try {
@@ -414,7 +409,7 @@ export function useActivityData() {
             console.error('获取2023匠鑫活动数据Vip失败', error)
         }
     }
-    
+
     // 2023年中赠金活动数据-10
     const Activity24nianzhongInfo = async () => {
         try {
@@ -433,7 +428,7 @@ export function useActivityData() {
             console.error('获取年中赠金活动数据失败', error)
         }
     }
-    
+
     // 2023年中赠金活动数据-20
     const Activity24nianzhongTwoInfo = async () => {
         try {
@@ -452,7 +447,7 @@ export function useActivityData() {
             console.error('获取年中赠金活动数据-20失败', error)
         }
     }
-    
+
     // 交易大赛数据-参数
     const GetActivityCptCode = async () => {
         try {
@@ -469,7 +464,7 @@ export function useActivityData() {
             console.error('获取交易大赛参数失败', error)
         }
     }
-    
+
     // 交易大赛数据
     const ActivityCptInfo = async (code: string) => {
         try {
@@ -484,7 +479,7 @@ export function useActivityData() {
             console.error('获取交易大赛数据失败', error)
         }
     }
-    
+
     // 24精英杯活动
     const Activity24JYBInfoVip = async () => {
         try {
@@ -514,7 +509,7 @@ export function useActivityData() {
             console.error('获取24精英杯活动数据失败', error)
         }
     }
-    
+
     // 24无忧交易
     const ActivityNoWorriesInfo = async () => {
         try {
@@ -526,7 +521,7 @@ export function useActivityData() {
                     const nowTime = getCurrentTime(2).getTime()
                     const startTime = new Date(activityState.tableDataNoWorries.compensateTime.replace(/-/g, '/')).getTime()
                     const endTime = new Date(activityState.tableDataNoWorries.revokeTime.replace(/-/g, '/')).getTime()
-                    
+
                     if (nowTime < endTime && nowTime > startTime &&
                         (activityState.tableDataNoWorries.status == 0 || activityState.tableDataNoWorries.status == 3) &&
                         activityState.tableDataNoWorries.compensateStatus == 2 &&
@@ -547,7 +542,7 @@ export function useActivityData() {
             console.error('获取无忧交易数据失败', error)
         }
     }
-    
+
     // CWG 现金嘉年华-新任务
     const ActivitYdepositRaffleAim = async () => {
         try {
@@ -564,7 +559,7 @@ export function useActivityData() {
             console.error('获取新任务数据失败', error)
         }
     }
-    
+
     // CWG 现金嘉年华-抽奖次数
     const ActivitYdepositRaffleinfo = async () => {
         try {
@@ -578,7 +573,7 @@ export function useActivityData() {
             console.error('获取抽奖次数失败', error)
         }
     }
-    
+
     // 抽奖活动是否到期
     const isRaffleOpen = () => {
         const endTime1 = '2025/9/30 23:59:59'
@@ -586,14 +581,14 @@ export function useActivityData() {
         const now = getCurrentTime(2).getTime()
         const end = new Date(endTime1).getTime()
         const start = new Date(startTime1).getTime()
-        
+
         if (now < end && start < now) {
             activityState.choujiaClose = true
             ActivitYdepositRaffleAim()
             ActivitYdepositRaffleinfo()
         }
     }
-    
+
     // 新年庆典是否到期
     const isNewYear24Open = () => {
         const endTime1 = '2025/3/31 23:59:59'
@@ -601,12 +596,12 @@ export function useActivityData() {
         const now = getCurrentTime(2).getTime()
         const end = new Date(endTime1).getTime()
         const start = new Date(startTime1).getTime()
-        
+
         if (now < end && start < now) {
             ActivityNewYear24()
         }
     }
-    
+
     // 新年庆典数据
     const ActivityNewYear24 = async () => {
         try {
@@ -621,7 +616,7 @@ export function useActivityData() {
             console.error('获取新年庆典数据失败', error)
         }
     }
-    
+
     // 限时活动
     const ActivityRequiteInfo = async () => {
         try {
@@ -635,7 +630,7 @@ export function useActivityData() {
             console.error('获取限时活动数据失败', error)
         }
     }
-    
+
     // 获取活动显示信息
     const getActivityShowsInfo = async () => {
         try {
@@ -655,7 +650,7 @@ export function useActivityData() {
             activityState.monthlyGive = false
         }
     }
-    
+
     // 20赠金是否到期
     const is20Open = () => {
         const endTime1 = '2023/04/30 23:59:59'
@@ -665,7 +660,7 @@ export function useActivityData() {
             activityState.anshiClose = false
         }
     }
-    
+
     // 20赠金活动数据
     const getActivityPercentageGiveInfo = async () => {
         try {
@@ -678,7 +673,7 @@ export function useActivityData() {
             console.error('获取20赠金活动数据失败', error)
         }
     }
-    
+
     // 刷新所有活动数据
     const refreshAllActivities = () => {
         is20Open()
@@ -696,21 +691,21 @@ export function useActivityData() {
         ActivityRequiteInfo()
         getActivityShowsInfo()
     }
-    
+
     // 分页处理
     const handlePageChange = (page: number) => {
         pagerInfo.value.current = page
         searchFunc(page)
         searchFunc1()
     }
-    
+
     // 清理定时器
     onUnmounted(() => {
         if (interval.value) {
             clearInterval(interval.value)
         }
     })
-    
+
     return {
         // 状态
         pictLoading,
@@ -725,13 +720,13 @@ export function useActivityData() {
         tableDataCptFlagCode,
         NewYear24DataBalance,
         NewYear24Data,
-        
+
         // 计算属性
         country,
         myCid,
         isSupportedCountry,
         isGuoQin,
-        
+
         // 工具函数
         getCurrentTime,
         getzero,
@@ -741,7 +736,7 @@ export function useActivityData() {
         overdue,
         timeExpireJx,
         isAfterSeptember30,
-        
+
         // API函数
         getDateList,
         searchFunc,

+ 51 - 447
pages/activities/config/activityConfigs.ts

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

+ 7 - 4
pages/activities/content.vue

@@ -21,8 +21,7 @@
                     !ActivitySingleNewYear24">
                     <view class="img">
                         <cwg-image :lazy="false"
-                            :a='imgUrl + (singleData.activityImage ? singleData.activityImage : singleData.coverImage)'
-                            src="https://file.44a5c8109e4.com/file//444/info/b5a55df62bdb407792c5bbcd7766631c.png">
+                            :src="imgUrl + (singleData.activityImage ? singleData.activityImage : singleData.coverImage)">
                         </cwg-image>
                     </view>
                     <view v-html="singleData.content" />
@@ -1042,7 +1041,7 @@ import Config from "@/config/index"
 import { useI18n } from 'vue-i18n'
 const { t, locale } = useI18n()
 
-const { Code, Host80 } = Config
+const { Code, Host05 } = Config
 const isZh = computed(() => ['cn', 'zhHant'].includes(locale.value))
 // ==================== 路由参数 ====================
 const myId = ref('')
@@ -1050,7 +1049,7 @@ const type = ref('')
 const active = ref('')
 
 // ==================== 响应式数据 ====================
-const imgUrl = Host80
+const imgUrl = Host05
 const imgContent = ref('https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg')
 const singleData = ref<any>([])
 
@@ -1435,7 +1434,11 @@ onUnmounted(() => {
     line-height: 2;
 
     .img {
+        display: flex;
+        align-items: center;
+        justify-content: center;
         margin-bottom: 20px;
+
     }
 }
 

+ 124 - 128
pages/activities/index.vue

@@ -23,17 +23,17 @@
 
                                 <!-- 遍历静态活动配置 -->
                                 <ActivityCard v-for="activity in visibleStaticActivities" :key="activity.id"
-                                    :config="activity" :state="activityState" :lang="lang"
+                                    :config="activity" :state="activityState" :lang="locale"
                                     @action="handleActivityAction" />
 
                                 <!-- 动态活动列表 -->
                                 <ActivityCard v-for="item in tableData" :key="'dynamic-' + item.id"
-                                    :config="createDynamicConfig(item)" :state="activityState" :lang="lang"
+                                    :config="createDynamicConfig(item)" :state="activityState" :lang="locale"
                                     @action="handleActivityAction" />
 
                                 <!-- 赠送活动列表 -->
                                 <ActivityCard v-for="item in tableDataGive" :key="'give-' + item.id"
-                                    :config="createGiveConfig(item)" :state="activityState" :lang="lang"
+                                    :config="createGiveConfig(item)" :state="activityState" :lang="locale"
                                     @action="handleActivityAction" />
                             </uni-row>
 
@@ -97,7 +97,7 @@ import { useActivityActions } from './composables/useActivityActions'
 import { staticActivityConfigs } from './config/activityConfigs'
 import Config from '@/config/index'
 
-const { t } = useI18n()
+const { t, locale } = useI18n()
 const { Host80 } = Config
 
 // ==================== 数据逻辑 ====================
@@ -108,7 +108,6 @@ const {
     pagerInfo,
     loginOptions,
     activityState,
-    lang,
     country,
     isSupportedCountry,
     isGuoQin,
@@ -291,7 +290,7 @@ const createDynamicConfig = (item: any) => {
         id: item.id,
         title: item.title,
         description: item.subTitle,
-        image: Host80 + item.coverImage,
+        image: item.image,
         time: item.deliveryTime?.split(' ')[0],
         hot: item.hot,
         onClick: 'toSingle',
@@ -324,7 +323,7 @@ const createGiveConfig = (item: any) => {
         id: item.id,
         title: item.title,
         description: item.subTitle,
-        image: Host80 + item.coverUrl,
+        image: item.image,
         time: item.revokeDate?.split(' ')[0],
         hot: item.hot,
         onClick: 'toSingle',
@@ -333,8 +332,7 @@ const createGiveConfig = (item: any) => {
             {
                 type: item.valid === 1 ? 'red' : 'gray',
                 text: 'Custom.Activity.Apply',
-                action: 'toActivity24nianzhong',
-                condition: item.valid === 1
+                action: 'toActivity24nianzhong'
             },
             {
                 type: 'check',
@@ -426,123 +424,123 @@ const handleDialogAction = (action: string, data?: any) => {
 
 // ==================== 活动操作处理 ====================
 const handleActivityAction = ({ type, params }: { type: string; params?: any[] }) => {
-    // switch (type) {
-    //     case 'toSingle':
-    //         toSingle(...(params || []))
-    //         break
-    //     case 'openCalculator':
-    //         openCalculatorFlag.value = true
-    //         break
-    //     case 'openPdf':
-    //         openPdf(params?.[0] || type)
-    //         break
-    //     case 'openSurplusActivityDialog':
-    //         dialogSurplusActivity.value = true
-    //         break
-    //     case 'openSurplusActivityDialog1':
-    //         dialogSurplusActivity1.value = true
-    //         break
-    //     case 'goMonthlyTaskList':
-    //         goMonthlyTaskList()
-    //         break
-    //     case 'goSurplusTaskList':
-    //         goSurplusTaskList()
-    //         break
-    //     case 'toHistoryLuckyDraw':
-    //         toHistoryLuckyDraw()
-    //         break
-    //     case 'toOpenTask':
-    //         dialogNewTaskDraw.value = true
-    //         break
-    //     case 'toNewTask':
-    //         dialogNewTask.value = true
-    //         break
-    //     case 'toTaskList':
-    //         toTaskList()
-    //         break
-    //     case 'toApplyNoWorriesOpen':
-    //         dialogDealResultNoWorries.value = true
-    //         break
-    //     case 'toRealizationNoWorries':
-    //         dialogNoWorries.value = true
-    //         break
-    //     case 'toActivity24Trading':
-    //         toActivity24Trading()
-    //         break
-    //     case 'toActivity24nianzhong':
-    //         toActivity24nianzhong()
-    //         break
-    //     case 'toApply23Open':
-    //         toApply23Open()
-    //         break
-    //     case 'toTransform':
-    //         toTransform()
-    //         break
-    //     case 'toRealization':
-    //         toRealization()
-    //         break
-    //     case 'toApplyCptOpen':
-    //         dialogDealResultCpt.value = true
-    //         break
-    //     case 'toOpenSingle':
-    //         // 处理打开外部链接
-    //         break
-    //     case 'toApply24JYBOpenVip':
-    //         dialogDealResultJxJYB.value = true
-    //         break
-    //     case 'toRealization24JYBVip':
-    //         // 处理变现
-    //         break
-    //     case 'applications':
-    //         // 处理申请
-    //         break
-    //     case 'checkActivity':
-    //         // 处理查看活动
-    //         break
-    //     case 'openDialog':
-    //         if (params?.[0]) {
-    //             updateDialogVisible(params[0], true)
-    //         }
-    //         break
-    //     case 'cashBack':
-    //         // 处理返现
-    //         break
-    //     case 'toApply23JxOpen':
-    //         dialogDealResultJx.value = true
-    //         break
-    //     case 'toApply23JxOpenVip':
-    //         dialogDealResultJxVip.value = true
-    //         break
-    //     case 'toApplyCptOpen':
-    //         dialogDealResultCpt.value = true
-    //         break
-    //     case 'toApply24JYBOpenVip':
-    //         dialogDealResultJxJYB.value = true
-    //         break
-    //     case 'toApplyNoWorriesOpen':
-    //         dialogDealResultNoWorries.value = true
-    //         break
-    //     case 'toRealizationJx':
-    //         toRealizationJx()
-    //         break
-    //     case 'toRealizationJxVip':
-    //         toRealizationJxVip()
-    //         break
-    //     case 'toRealization24JYBVip':
-    //         toRealization24JYBVip()
-    //         break
-    //     case 'toRealizationNoWorries':
-    //         dialogNoWorries.value = true
-    //         break
-    //     case 'toOpenSingle':
-    //         toOpenSingle(params?.[0])
-    //         break
-    //     case 'cashBack':
-    //         cashBack()
-    //         break
-    //     default:
-    //         console.warn('未知操作类型:', type)
-    // }
+    switch (type) {
+        case 'toSingle':
+            toSingle(...(params || []))
+            break
+        case 'openCalculator':
+            openCalculatorFlag.value = true
+            break
+        case 'openPdf':
+            openPdf(params?.[0] || type)
+            break
+        case 'openSurplusActivityDialog':
+            dialogSurplusActivity.value = true
+            break
+        case 'openSurplusActivityDialog1':
+            dialogSurplusActivity1.value = true
+            break
+        case 'goMonthlyTaskList':
+            goMonthlyTaskList()
+            break
+        case 'goSurplusTaskList':
+            goSurplusTaskList()
+            break
+        case 'toHistoryLuckyDraw':
+            toHistoryLuckyDraw()
+            break
+        case 'toOpenTask':
+            dialogNewTaskDraw.value = true
+            break
+        case 'toNewTask':
+            dialogNewTask.value = true
+            break
+        case 'toTaskList':
+            toTaskList()
+            break
+        case 'toApplyNoWorriesOpen':
+            dialogDealResultNoWorries.value = true
+            break
+        case 'toRealizationNoWorries':
+            dialogNoWorries.value = true
+            break
+        case 'toActivity24Trading':
+            toActivity24Trading()
+            break
+        case 'toActivity24nianzhong':
+            toActivity24nianzhong()
+            break
+        case 'toApply23Open':
+            toApply23Open()
+            break
+        case 'toTransform':
+            toTransform()
+            break
+        case 'toRealization':
+            toRealization()
+            break
+        case 'toApplyCptOpen':
+            dialogDealResultCpt.value = true
+            break
+        case 'toOpenSingle':
+            // 处理打开外部链接
+            break
+        case 'toApply24JYBOpenVip':
+            dialogDealResultJxJYB.value = true
+            break
+        case 'toRealization24JYBVip':
+            // 处理变现
+            break
+        case 'applications':
+            // 处理申请
+            break
+        case 'checkActivity':
+            // 处理查看活动
+            break
+        case 'openDialog':
+            if (params?.[0]) {
+                updateDialogVisible(params[0], true)
+            }
+            break
+        case 'cashBack':
+            // 处理返现
+            break
+        case 'toApply23JxOpen':
+            dialogDealResultJx.value = true
+            break
+        case 'toApply23JxOpenVip':
+            dialogDealResultJxVip.value = true
+            break
+        case 'toApplyCptOpen':
+            dialogDealResultCpt.value = true
+            break
+        case 'toApply24JYBOpenVip':
+            dialogDealResultJxJYB.value = true
+            break
+        case 'toApplyNoWorriesOpen':
+            dialogDealResultNoWorries.value = true
+            break
+        case 'toRealizationJx':
+            toRealizationJx()
+            break
+        case 'toRealizationJxVip':
+            toRealizationJxVip()
+            break
+        case 'toRealization24JYBVip':
+            toRealization24JYBVip()
+            break
+        case 'toRealizationNoWorries':
+            dialogNoWorries.value = true
+            break
+        case 'toOpenSingle':
+            toOpenSingle(params?.[0])
+            break
+        case 'cashBack':
+            cashBack()
+            break
+        default:
+            console.warn('未知操作类型:', type)
+    }
 }
 
 // ==================== 生命周期 ====================
@@ -566,10 +564,8 @@ onReachBottom(() => {
 @import "@/uni.scss";
 
 .custom_activities {
-    height: 100vh;
     display: flex;
     flex-direction: column;
-    background-color: #f5f5f5;
 
     .crm-title-box {
         padding: 20rpx 30rpx;

+ 708 - 0
pages/activities/monthly-list.vue

@@ -0,0 +1,708 @@
+<template>
+    <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
+        <cwg-header :title="t('wallet.item52')" />
+
+        <view id="custom_history" class="">
+            <view class="main-content">
+                <!-- 无任务列表提示 -->
+                <cwg-empty-state v-if="!tableData || tableData.length === 0" title="UtaskList.item12" />
+                <!-- 数据卡片展示 -->
+                <view class="outer-card" v-for="(item, index) in tableData" :key="index"
+                    v-show="tableData && tableData.length > 0">
+                    <view class="data-cards">
+                        <!-- 第一行:总数据 -->
+                        <view class="total-data-row">
+                            <view class="data-card total-card">
+                                <view class="card-content">
+                                    <view class="card-title">{{ t("UtaskList.item13") }}</view>
+                                    <view class="card-value" style="color: #ff4d4f">
+                                        {{ item.depositAmount || 0 }}
+                                    </view>
+                                </view>
+                            </view>
+                            <view class="data-card total-card">
+                                <view class="card-content">
+                                    <view class="card-title">{{ t("UtaskList.item3") }}</view>
+                                    <view class="card-value" style="color: #ff4d4f">
+                                        {{ item.completeVolume || 0 }}
+                                    </view>
+                                </view>
+                            </view>
+                            <view class="data-card total-card">
+                                <view class="card-content">
+                                    <view class="card-title">{{ t("Label.State") }}</view>
+                                    <view class="card-value" :style="getStatusStyle(item.status)">
+                                        {{ getStatusText(item.status) }}
+                                    </view>
+                                </view>
+                            </view>
+
+                            <view class="data-card total-card" v-if="item.status === 2">
+                                <view class="card-content">
+                                    <view class="card-title">
+                                        {{ t("MonthlyActivities.item4") }}
+                                    </view>
+                                    <view class="card-value" :style="getGiveStatusStyle(item.giveStatus)">
+                                        {{ getGiveStatusText(item.giveStatus) }}
+                                    </view>
+                                </view>
+                            </view>
+                        </view>
+
+                        <!-- 第二行:分数据 -->
+                        <view class="sub-data-row">
+                            <view class="data-card">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.endDate }}</view>
+                                    <view class="card-desc">{{ t("UtaskList.item10") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card" v-if="item.status === 2">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.applyTime }}</view>
+                                    <view class="card-desc">{{ t("MonthlyActivities.item6") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card" v-if="item.status === 2">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.grantTime }}</view>
+                                    <view class="card-desc">{{ t("MonthlyActivities.item7") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card" v-if="item.logisticsOrder">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.logisticsOrder }}</view>
+                                    <view class="card-desc">{{ t("MonthlyActivities.item9") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card btn-card" v-show="shouldShowCard(item, item)">
+                                <!-- 取消按钮 - status为1时显示 -->
+                                <button v-if="item.status === 1" type="danger" size="small" @click="cancelTask(item.id)"
+                                    :loading="loadingStates[item.id] === 'cancel'">
+                                    {{ t("Btn.Cancel") }}
+                                </button>
+                                <!-- 礼物申请按钮 - status为2且giveStatus为1时显示 -->
+                                <button v-if="item.status === 2 && item.giveStatus === 1 && lang1" type="primary"
+                                    size="small" @click="applyGift(item.id)"
+                                    :loading="loadingStates[item.id] === 'applyGift'">
+                                    {{ t("Btn.Application") }}
+                                </button>
+                            </view>
+                        </view>
+
+                        <!-- 提示信息 -->
+                        <view class="tip-info" style="padding: 10px 0; color: #909399; font-size: 14px">
+                            {{ t("MonthlyActivities.item10") }}
+                        </view>
+                    </view>
+                </view>
+            </view>
+
+            <!-- 礼物申请对话框 -->
+            <GiftApplicationPopup v-model:visible="dialogGiftApplication" :title="t('Btn.Application')"
+                :giftList="giftList" :giftForm="giftForm" @confirm="submitGiftApply" />
+        </view>
+    </cwg-page-wrapper>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, onMounted, watch } from 'vue'
+import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
+import { useI18n } from 'vue-i18n'
+import { activityApi } from "@/service/activity"
+import Config from "@/config/index"
+import GiftApplicationPopup from "./components/GiftApplicationPopup.vue"
+import { useConfirm } from '@/hooks/useConfirm'
+const confirm = useConfirm()
+const { t, locale } = useI18n()
+let { Code } = Config
+
+// ---------- 存储辅助函数(模拟原 Session) ----------
+const Session = {
+    Get(key: string, parse = false) {
+        const value = uni.getStorageSync(key)
+        if (parse && value) {
+            try {
+                return JSON.parse(value)
+            } catch {
+                return value
+            }
+        }
+        return value
+    }
+}
+
+// ---------- 响应式数据 ----------
+const flag = ref(false)
+const reasons = ref({})
+const pictLoading = ref(false)
+const tableData = ref<any[]>([])
+const time = ref("")
+const loadingStates = ref<Record<string, string | null>>({}) // 用于跟踪每个任务的加载状态
+
+// 卡片数据
+const totalTasks = ref(0)
+const totalRewards = ref(0)
+const completionRate = ref("0")
+const inProgressTasks = ref(0)
+const completedTasks = ref(0)
+const expiredTasks = ref(0)
+const rejectedTasks = ref(0)
+const todayRewards = ref(0)
+const weekRewards = ref(0)
+const monthRewards = ref(0)
+const activityLevel = ref("0")
+
+// 礼物申请对话框相关
+const dialogGiftApplication = ref(false)
+const giftList = ref<any[]>([])
+const giftForm = ref({
+    id: null as number | null,
+    giveCode: "",
+    giveName: "",
+    giveAddress: "",
+    givePhone: "",
+    giveAcceptName: "",
+})
+const giftSubmitting = ref(false)
+
+// 原 watch 中依赖的 search(保留)
+const search = ref({ type: "" })
+
+// ---------- 计算属性 ----------
+const expireTime = computed(() => {
+    return Session.Get("user", true)
+})
+
+const lang = computed(() => {
+    return (Session.Get("lang") == "en" && document.body.clientWidth < 1330)
+})
+// 注意:document 在 uni-app 中不可用,此处保留原逻辑但需注意运行环境
+// 若需兼容,可改用 uni.getSystemInfoSync().windowWidth
+
+const lang1 = computed(() => {
+    const user = Session.Get("user", true)
+    return user?.customInfo?.country == "CN"
+})
+
+
+
+// ---------- 方法 ----------
+const getStatus = (status: number) => {
+    if (status == 1) {
+        return t("State.Ongoing")
+    } else if (status == 2) {
+        return t("State.Completed")
+    } else if (status == 3) {
+        return t("State.Cancelled")
+    } else if (status == 4) {
+        return t("State.expireTime")
+    }
+}
+
+const getStatusText = (status: number) => {
+    if (status == 1) {
+        return t("State.InTask")
+    } else if (status == 2) {
+        return t("UtaskList.item6")
+    } else if (status == 3) {
+        return t("State.Cancelled")
+    } else if (status == 4) {
+        return t("State.Ended")
+    }
+    return ""
+}
+
+const getStatusStyle = (status: number) => {
+    if (status == 1) {
+        return "color: #ffd591;"
+    } else if (status == 2) {
+        return "color: #52c41a;"
+    } else if (status == 3) {
+        return "color: #999999;"
+    } else if (status == 4) {
+        return "color: #999999;"
+    }
+    return "color: #333;"
+}
+
+const getGiveStatusText = (giveStatus: number) => {
+    if (giveStatus == 1) {
+        return t("State.NotApply")
+    } else if (giveStatus == 2) {
+        return t("State.Applied")
+    } else if (giveStatus == 3) {
+        return t("State.Granted")
+    }
+    return ""
+}
+
+const getGiveStatusStyle = (giveStatus: number) => {
+    if (giveStatus == 1) {
+        return "color: #999999;"
+    } else if (giveStatus == 2) {
+        return "color: #1890ff;"
+    } else if (giveStatus == 3) {
+        return "color: #52c41a;"
+    }
+    return "color: #333;"
+}
+
+const canPerformAction = (task: any) => {
+    return task.status === 1 || (task.status === 2 && task.withdrawStatus === 1)
+}
+
+const shouldShowCard = (el: any) => {
+    const hasCancelButton = el.status === 1
+    const hasGiftApplyButton = el.status === 2 && el.giveStatus === 1 && lang1.value
+    return hasCancelButton || hasGiftApplyButton
+}
+
+// 恢复信用(原 completeTask)
+const completeTask = async (id: number) => {
+    return new Promise(async (resolve) => {
+        const resConfirm = await uni.showModal({
+            title: t("Msg.SystemPrompt"),
+            content: t("surplusList.item9"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+        if (!resConfirm.confirm) return resolve(null)
+
+        loadingStates.value[id] = "complete"
+        try {
+            const res = await activityApi.ActivitySurplusRecoverCredit({ id })
+            if (res.code == Code.StatusOK) {
+                uni.showToast({ title: t("Msg.Success"), icon: "success" })
+                searchFunc()
+            } else {
+                uni.showToast({ title: res.msg, icon: "none" })
+            }
+        } catch (error) {
+            uni.showToast({ title: t("Msg.Fail"), icon: "none" })
+        } finally {
+            loadingStates.value[id] = null
+            resolve(null)
+        }
+    })
+}
+
+// 提现
+const withdrawTask = async (id: number) => {
+    return new Promise(async (resolve) => {
+        const resConfirm = await uni.showModal({
+            title: t("Msg.SystemPrompt"),
+            content: t("UtaskList.item15"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+        if (!resConfirm.confirm) return resolve(null)
+
+        loadingStates.value[id] = "withdraw"
+        try {
+            const res = await activityApi.UcoinWithdraw({ id })
+            if (res.code == Code.StatusOK) {
+                searchFunc()
+            } else {
+                uni.showToast({ title: res.msg, icon: "none" })
+            }
+        } catch (error) {
+            uni.showToast({ title: t("Msg.Fail"), icon: "none" })
+        } finally {
+            loadingStates.value[id] = null
+            resolve(null)
+        }
+    })
+}
+
+// 取消任务
+const cancelTask = async (id: number) => {
+    try {
+        await confirm({
+            title: t("Msg.SystemPrompt"),
+            content: t("UtaskList.item8"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+        const res = await activityApi.ActivityMonthlyCancel({ id })
+        if (res.code == Code.StatusOK) {
+            uni.showToast({ title: t("UtaskList.item9"), icon: "success" })
+            searchFunc()
+        } else {
+            uni.showToast({ title: res.msg, icon: "none" })
+        }
+    } catch (error) {
+        if (error?.msg) uni.showToast({ title: error.msg, icon: "none" })
+    }
+}
+
+// 礼物申请 - 打开对话框并获取礼品列表
+const applyGift = async (id: number) => {
+    // 重置表单
+    giftForm.value = {
+        id: id,
+        giveCode: "",
+        giveName: "",
+        giveAddress: "",
+        givePhone: "",
+        giveAcceptName: "",
+    }
+    giftList.value = []
+
+    // 获取礼品列表
+    try {
+        const res = await activityApi.ActivityMonthlyGiveList({ id })
+        if (res.code == Code.StatusOK) {
+            giftList.value = res.data || []
+            dialogGiftApplication.value = true
+        } else {
+            uni.showToast({ title: res.msg, icon: "none" })
+        }
+    } catch (error) {
+        uni.showToast({ title: t("Msg.Fail"), icon: "none" })
+    }
+}
+
+// 处理礼品选择变化
+const handleGiftChange = (giveCode: string) => {
+    const selectedGift = giftList.value.find(gift => gift.giveCode === giveCode)
+    if (selectedGift) {
+        giftForm.value.giveName = selectedGift.giveName
+    }
+}
+
+// 提交礼物申请
+const submitGiftApply = async (form) => {
+    // 表单验证(假设模板中有 ref="giftForm" 的 uni-forms 组件)
+    // 这里需要适配实际验证方式,简化起见调用一个验证函数,若验证失败则返回
+    // 由于 uni-app 中没有直接提供 validate,需根据实际组件实现,此处保留原逻辑结构
+    // 实际使用时请配合 uni-forms 或自定义验证
+    const valid = true // 占位,实际需调用 this.$refs.giftForm.validate()
+    if (!valid) return
+
+    const resConfirm = await uni.showModal({
+        title: t("Msg.SystemPrompt"),
+        content: t("MonthlyActivities.item10"),
+        confirmText: t("Btn.Confirm"),
+        cancelText: t("Btn.Cancel"),
+    })
+    if (!resConfirm.confirm) return
+
+    giftSubmitting.value = true
+    try {
+        const res = await activityApi.ActivityMonthlyGiveApply({
+            id: giftForm.value.id,
+            giveCode: form.giveCode,
+            giveName: form.giveName,
+            giveAddress: form.giveAddress.trim(),
+            givePhone: form.givePhone.trim(),
+        })
+        if (res.code == Code.StatusOK) {
+            uni.showToast({ title: t("Msg.Success"), icon: "success" })
+            dialogGiftApplication.value = false
+            searchFunc()
+        } else {
+            uni.showToast({ title: res.msg, icon: "none" })
+        }
+    } catch (error) {
+        uni.showToast({ title: t("Msg.Fail"), icon: "none" })
+    } finally {
+        giftSubmitting.value = false
+    }
+}
+
+// 查看任务进度
+const viewTaskProgress = async (id: number) => {
+    loadingStates.value[id] = "progress"
+    try {
+        const res = await activityApi.UcoinProgress()
+        if (res.code == Code.StatusOK) {
+            uni.showToast({ title: res.msg, icon: "none" })
+        } else {
+            uni.showToast({ title: res.msg, icon: "none" })
+        }
+    } catch (error) {
+        uni.showToast({ title: t("Msg.Fail"), icon: "none" })
+    } finally {
+        loadingStates.value[id] = null
+    }
+}
+
+// 计算卡片数据(保留原方法体)
+const calculateCardData = () => {
+    // 可根据需求实现
+}
+
+// 返回活动
+const backActivity = () => {
+    uni.navigateBack()
+}
+
+// 获取列表
+const searchFunc = async () => {
+    if (flag.value) return
+    flag.value = true
+
+    pictLoading.value = true
+    let res = await activityApi.ActivityMonthlyTaskList()
+    if (res.code == Code.StatusOK) {
+        tableData.value = res.data
+        calculateCardData()
+        uni.showToast({ title: t("Msg.SearchSuccess"), icon: "success" })
+        pictLoading.value = false
+        flag.value = false
+    } else {
+        uni.showToast({ title: res.msg, icon: "none" })
+        pictLoading.value = false
+        flag.value = false
+    }
+}
+
+// ---------- 生命周期与监听 ----------
+onMounted(() => {
+    searchFunc()
+})
+
+// 原 watch(保留)
+watch(
+    () => search.value.type,
+    () => {
+        searchFunc()
+    }
+)
+
+// 若需要 uni-app 页面生命周期可额外添加 onShow 等
+// onShow(() => {})
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+
+#custom_history {
+    width: 100%;
+    height: 100%;
+
+    .no-data-container {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        height: px2rpx(300);
+
+        .no-data-content {
+            text-align: center;
+            color: #999;
+
+            i {
+                font-size: px2rpx(48);
+                margin-bottom: px2rpx(16);
+                display: block;
+            }
+
+            p {
+                font-size: px2rpx(16);
+                margin: 0;
+            }
+        }
+    }
+
+    .main-content {
+        width: 100%;
+        height: calc(100% - 50px);
+        // @include bg_white();
+        padding: px2rpx(20);
+        box-sizing: border-box;
+        overflow: hidden;
+        overflow-y: auto;
+    }
+
+    .state.btn {
+        background: #eb3f57;
+        color: white;
+        padding: px2rpx(3) px2rpx(15);
+        border-radius: px2rpx(4);
+    }
+
+    .action-buttons {
+        display: flex;
+        flex-direction: column;
+        gap: px2rpx(8);
+        align-items: center;
+
+        .el-button {
+            min-width: px2rpx(80);
+            font-size: px2rpx(12);
+        }
+
+        .status-text {
+            font-size: px2rpx(14);
+            color: #666;
+            font-weight: 500;
+        }
+    }
+
+    // 外层卡片样式
+    .outer-card {
+        background: #ffffff;
+        border-radius: px2rpx(16);
+        padding: px2rpx(24);
+        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+        border: 1px solid #f0f0f0;
+        margin-bottom: px2rpx(30);
+    }
+
+    // 数据卡片样式
+    .data-cards {
+        display: flex;
+        flex-direction: column;
+        gap: px2rpx(20);
+
+        .total-data-row {
+            display: grid;
+            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+            gap: px2rpx(15);
+        }
+
+        .sub-data-row {
+            display: grid;
+            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+            gap: px2rpx(15);
+        }
+
+        .data-card {
+            background: #ffffff;
+            border-radius: px2rpx(12);
+            padding: px2rpx(24);
+            //   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+            border: 1px solid #f0f0f0;
+            transition: all 0.3s ease;
+            text-align: center;
+
+            &:hover {
+                transform: translateY(-2px);
+                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
+            }
+
+            // 根据状态设置背景色
+            &.status-1 {
+                background: #fff7e6; // 任务中 - 黄色背景
+                border-color: #ffd591;
+            }
+
+            &.status-2 {
+                background: #f6ffed; // 已完成 - 绿色背景
+                border-color: #b7eb8f;
+            }
+
+            &.status-3,
+            &.status-4 {
+                background: #f5f5f5; // 已取消/已结束 - 灰色背景
+                border-color: #d9d9d9;
+            }
+
+            &.total-card {
+                background: #ffffff;
+                color: #333;
+
+                // border: 1px solid gray;
+                .card-value {
+                    color: #333;
+                }
+
+                .card-desc {
+                    color: #999;
+                }
+
+                // 状态卡片的特殊样式
+                &.status-1 {
+                    background: #fff7e6;
+                    border-color: #ffd591;
+                }
+
+                &.status-2 {
+                    background: #f6ffed;
+                    border-color: #b7eb8f;
+                }
+
+                &.status-3,
+                &.status-4 {
+                    background: #f5f5f5;
+                    border-color: #d9d9d9;
+                }
+            }
+
+            &.sub-card {
+                background: #ffffff;
+                border-left: px2rpx(4) solid #667eea;
+
+                &:nth-child(2) {
+                    border-left-color: #52c41a;
+                }
+
+                &:nth-child(3) {
+                    border-left-color: #faad14;
+                }
+
+                &:nth-child(4) {
+                    border-left-color: #ff4d4f;
+                }
+            }
+
+            .card-content {
+                .card-title {
+                    font-size: px2rpx(16);
+                    color: #666;
+                    margin-bottom: px2rpx(8);
+                    font-weight: 500;
+                }
+
+                .card-value {
+                    font-size: px2rpx(18);
+                    font-weight: 700;
+                    color: #333;
+                    margin-bottom: px2rpx(4);
+                    line-height: 1;
+                }
+
+                .card-desc {
+                    font-size: px2rpx(12);
+                    color: #999;
+                    line-height: 1.4;
+                }
+            }
+        }
+
+        .btn-card {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            flex-direction: column;
+            gap: px2rpx(10);
+
+            button {
+                width: 100%;
+            }
+        }
+    }
+
+    // 响应式设计
+    @media (max-width: 768px) {
+        .data-cards {
+
+            .total-data-row,
+            .sub-data-row {
+                grid-template-columns: 1fr;
+            }
+
+            .data-card {
+                padding: px2rpx(16);
+
+                .card-content {
+                    .card-value {
+                        font-size: px2rpx(24);
+                    }
+                }
+            }
+        }
+    }
+}
+</style>

+ 549 - 0
pages/activities/surplus-list.vue

@@ -0,0 +1,549 @@
+<template>
+    <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
+        <cwg-header :title="t('wallet.item52')" />
+        <view id="custom_history" class="">
+
+            <view class="main-content">
+                <!-- 无任务列表提示 -->
+                <cwg-empty-state v-if="!tableData || tableData.length === 0" title="UtaskList.item12" />
+                <!-- 数据卡片展示 -->
+                <view class="outer-card" v-for="(item, index) in tableData" :key="index"
+                    v-show="tableData && tableData.length > 0">
+                    <view class="data-cards">
+                        <!-- 第一行:总数据 -->
+                        <view class="total-data-row">
+                            <view class="data-card total-card">
+                                <view class="card-content">
+                                    <view class="card-title">{{ t("UtaskList.item13") }}</view>
+                                    <view class="card-value" style="color: #ff4d4f">
+                                        {{ item.depositAmount || 0 }}
+                                    </view>
+                                </view>
+                            </view>
+                            <view class="data-card total-card">
+                                <view class="card-content">
+                                    <view class="card-title">{{ t("UtaskList.item3") }}</view>
+                                    <view class="card-value" style="color: #ff4d4f">
+                                        {{ item.completeVolume || 0 }}
+                                    </view>
+                                </view>
+                            </view>
+                            <view class="data-card total-card">
+                                <view class="card-content">
+                                    <view class="card-title">{{ t("surplusList.item8") }}</view>
+                                    <view class="card-value" style="color: #ff4d4f">
+                                        {{ item.amount }}
+                                    </view>
+                                </view>
+                            </view>
+                            <view class="data-card total-card">
+                                <view class="card-content">
+                                    <view class="card-title">{{ t("Label.State") }}</view>
+                                    <view class="card-value" :style="item.status == 1 ? 'color: #ffd591;' : 'color: #52c41a;'
+                                        ">
+                                        {{ item.status == 1 ? t("State.Ongoing") : t("State.Completed") }}
+                                    </view>
+                                </view>
+                            </view>
+                        </view>
+
+                        <!-- 第二行:分数据 -->
+                        <view class="sub-data-row">
+                            <view class="data-card">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.revokeCredit == 1 ? t("surplusList.Item5") :
+                                        t("surplusList.item6") }}</view>
+                                    <view class="card-desc">{{ t("surplusList.item4") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.needVolume || 0 }}</view>
+                                    <view class="card-desc">{{ t("UtaskList.Item5") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.amount }}</view>
+                                    <view class="card-desc">{{ t("UtaskList.item14") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.endTime }}</view>
+                                    <view class="card-desc">{{ t("wallet.item55") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card">
+                                <view class="card-content">
+                                    <view class="card-value">{{ item.endDate }}</view>
+                                    <view class="card-desc">{{ t("UtaskList.item10") }}</view>
+                                </view>
+                            </view>
+                            <view class="data-card" v-show="shouldShowCard(item, item)">
+                                <button v-if="item.status === 1 && item.revokeCredit === 2" type="primary" size="small"
+                                    @click="completeTask(item.id)" :loading="loadingStates[item.id] === 'complete'">
+                                    {{ t("surplusList.item7") }}
+                                </button>
+                                <button v-if="item.status === 1" type="danger" size="small" @click="cancelTask(item.id)"
+                                    :loading="loadingStates[item.id] === 'cancel'">
+                                    {{ t("Btn.Cancel") }}
+                                </button>
+                            </view>
+                        </view>
+                    </view>
+                </view>
+            </view>
+        </view>
+    </cwg-page-wrapper>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, onMounted, watch } from 'vue'
+import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
+import { useI18n } from 'vue-i18n'
+import { activityApi } from "@/service/activity"
+import Config from "@/config/index"
+import { useConfirm } from '@/hooks/useConfirm'
+const confirm = useConfirm()
+const { t, locale } = useI18n()
+let { Code } = Config
+
+// ---------- 存储辅助函数(模拟原 Session) ----------
+const Session = {
+    Get(key: string, parse = false) {
+        const value = uni.getStorageSync(key)
+        if (parse && value) {
+            try {
+                return JSON.parse(value)
+            } catch {
+                return value
+            }
+        }
+        return value
+    }
+}
+
+// ---------- 响应式数据 ----------
+const flag = ref(false)
+const reasons = ref({})
+const pictLoading = ref(false)
+const tableData = ref<any[]>([])
+const time = ref("")
+const loadingStates = ref<Record<string, string | null>>({})
+
+// 卡片数据
+const totalTasks = ref(0)
+const totalRewards = ref(0)
+const completionRate = ref("0")
+const inProgressTasks = ref(0)
+const completedTasks = ref(0)
+const expiredTasks = ref(0)
+const rejectedTasks = ref(0)
+const todayRewards = ref(0)
+const weekRewards = ref(0)
+const monthRewards = ref(0)
+const activityLevel = ref("0")
+
+// 原 watch 中依赖的 search(保留)
+const search = ref({ type: "" })
+
+// ---------- 计算属性 ----------
+const expireTime = computed(() => {
+    return JSON.parse(Session.Get("user", true))
+})
+
+// 注意:document.body.clientWidth 在 uni-app 中不可用,改为获取屏幕宽度
+const getScreenWidth = () => {
+    const systemInfo = uni.getSystemInfoSync()
+    return systemInfo.windowWidth
+}
+
+const lang = computed(() => {
+    return (Session.Get("lang") == "en" && getScreenWidth() < 1330)
+})
+
+// ---------- 方法 ----------
+const getStatus = (status: number) => {
+    if (status == 1) {
+        return t("State.Ongoing")
+    } else if (status == 2) {
+        return t("State.Completed")
+    } else if (status == 3) {
+        return t("State.Cancelled")
+    } else if (status == 4) {
+        return t("State.expireTime")
+    }
+}
+
+const canPerformAction = (task: any) => {
+    return task.status === 1 || (task.status === 2 && task.withdrawStatus === 1)
+}
+
+const shouldShowCard = (el: any) => {
+    const hasRecoverCreditButton = el.status === 1 && el.revokeCredit === 2
+    const hasCancelButton = el.status === 1
+    return hasRecoverCreditButton || hasCancelButton
+}
+
+// 恢复信用
+const completeTask = async (id: number) => {
+    try {
+        await confirm({
+            title: t("Msg.SystemPrompt"),
+            content: t("surplusList.item9"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+        const res = await activityApi.ActivitySurplusRecoverCredit({ id })
+        if (res.code == Code.StatusOK) {
+            uni.showToast({ title: t("UtaskList.item9"), icon: "success" })
+            searchFunc()
+        } else {
+            uni.showToast({ title: res.msg, icon: "none" })
+        }
+    } catch (error) {
+        if (error?.msg) uni.showToast({ title: error.msg, icon: "none" })
+    }
+}
+
+// 提现
+const withdrawTask = async (id: number) => {
+    return new Promise(async (resolve) => {
+        const resConfirm = await uni.showModal({
+            title: t("Msg.SystemPrompt"),
+            content: t("UtaskList.item15"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+        if (!resConfirm.confirm) return resolve(null)
+
+        loadingStates.value[id] = "withdraw"
+        try {
+            const res = await activityApi.UcoinWithdraw({ id })
+            if (res.code == Code.StatusOK) {
+                uni.showToast({ title: t("Msg.Success"), icon: "success" })
+                searchFunc()
+            } else {
+                uni.showToast({ title: res.msg, icon: "none" })
+            }
+        } catch (error) {
+            uni.showToast({ title: t("Msg.Fail"), icon: "none" })
+        } finally {
+            loadingStates.value[id] = null
+            resolve(null)
+        }
+    })
+}
+// 取消任务
+const cancelTask = async (id: number) => {
+    try {
+        await confirm({
+            title: t("Msg.SystemPrompt"),
+            content: t("UtaskList.item8"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+        const res = await activityApi.ActivityMonthlyCancel({ id })
+        if (res.code == Code.StatusOK) {
+            uni.showToast({ title: t("UtaskList.item9"), icon: "success" })
+            searchFunc()
+        } else {
+            uni.showToast({ title: res.msg, icon: "none" })
+        }
+    } catch (error) {
+        if (error?.msg) uni.showToast({ title: error.msg, icon: "none" })
+    }
+}
+
+// 查看任务进度
+const viewTaskProgress = async (id: number) => {
+    loadingStates.value[id] = "progress"
+    try {
+        const res = await activityApi.UcoinProgress()
+        if (res.code == Code.StatusOK) {
+            uni.showToast({ title: res.msg, icon: "none" })
+        } else {
+            uni.showToast({ title: res.msg, icon: "none" })
+        }
+    } catch (error) {
+        uni.showToast({ title: t("Msg.Fail"), icon: "none" })
+    } finally {
+        loadingStates.value[id] = null
+    }
+}
+
+// 计算卡片数据
+const calculateCardData = () => {
+    // 可根据需求实现
+}
+
+// 返回活动
+const backActivity = () => {
+    uni.navigateTo({ url: "/customer/activities" })
+}
+
+// 获取列表
+const searchFunc = async () => {
+    if (flag.value) return
+    flag.value = true
+
+    pictLoading.value = true
+    let res = await activityApi.ActivitySurplusTaskList()
+    if (res.code == Code.StatusOK) {
+        tableData.value = res.data
+        calculateCardData()
+        pictLoading.value = false
+        flag.value = false
+    } else {
+        uni.showToast({ title: res.msg, icon: "none" })
+        pictLoading.value = false
+        flag.value = false
+    }
+}
+
+// ---------- 生命周期与监听 ----------
+onMounted(() => {
+    searchFunc()
+})
+
+// 原 watch(保留)
+watch(
+    () => search.value.type,
+    () => {
+        searchFunc()
+    }
+)
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+
+#custom_history {
+    width: 100%;
+    height: 100%;
+
+    .no-data-container {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        height: px2rpx(300);
+
+        .no-data-content {
+            text-align: center;
+            color: #999;
+
+            i {
+                font-size: px2rpx(48);
+                margin-bottom: px2rpx(16);
+                display: block;
+            }
+
+            p {
+                font-size: px2rpx(16);
+                margin: 0;
+            }
+        }
+    }
+
+    .main-content {
+        width: 100%;
+        height: calc(100% - 50px);
+        // @include bg_white();
+        padding: px2rpx(20);
+        box-sizing: border-box;
+        overflow: hidden;
+        overflow-y: auto;
+    }
+
+    .state.btn {
+        background: #eb3f57;
+        color: white;
+        padding: px2rpx(3) px2rpx(15);
+        border-radius: px2rpx(4);
+    }
+
+    .action-buttons {
+        display: flex;
+        flex-direction: column;
+        gap: px2rpx(8);
+        align-items: center;
+
+        .el-button {
+            min-width: px2rpx(80);
+            font-size: px2rpx(12);
+        }
+
+        .status-text {
+            font-size: px2rpx(14);
+            color: #666;
+            font-weight: 500;
+        }
+    }
+
+    // 外层卡片样式
+    .outer-card {
+        background: #ffffff;
+        border-radius: px2rpx(16);
+        padding: px2rpx(24);
+        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+        border: 1px solid #f0f0f0;
+        margin-bottom: px2rpx(30);
+    }
+
+    // 数据卡片样式
+    .data-cards {
+        display: flex;
+        flex-direction: column;
+        gap: px2rpx(20);
+
+        .total-data-row {
+            display: grid;
+            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+            gap: px2rpx(15);
+        }
+
+        .sub-data-row {
+            display: grid;
+            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+            gap: px2rpx(15);
+        }
+
+        .data-card {
+            background: #ffffff;
+            border-radius: px2rpx(12);
+            padding: px2rpx(24);
+            //   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+            border: 1px solid #f0f0f0;
+            transition: all 0.3s ease;
+            text-align: center;
+
+            &:hover {
+                transform: translateY(-2px);
+                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
+            }
+
+            // 根据状态设置背景色
+            &.status-1 {
+                background: #fff7e6; // 任务中 - 黄色背景
+                border-color: #ffd591;
+            }
+
+            &.status-2 {
+                background: #f6ffed; // 已完成 - 绿色背景
+                border-color: #b7eb8f;
+            }
+
+            &.status-3,
+            &.status-4 {
+                background: #f5f5f5; // 已取消/已结束 - 灰色背景
+                border-color: #d9d9d9;
+            }
+
+            &.total-card {
+                background: #ffffff;
+                color: #333;
+
+                // border: 1px solid gray;
+                .card-value {
+                    color: #333;
+                }
+
+                .card-desc {
+                    color: #999;
+                }
+
+                // 状态卡片的特殊样式
+                &.status-1 {
+                    background: #fff7e6;
+                    border-color: #ffd591;
+                }
+
+                &.status-2 {
+                    background: #f6ffed;
+                    border-color: #b7eb8f;
+                }
+
+                &.status-3,
+                &.status-4 {
+                    background: #f5f5f5;
+                    border-color: #d9d9d9;
+                }
+            }
+
+            &.sub-card {
+                background: #ffffff;
+                border-left: px2rpx(4) solid #667eea;
+
+                &:nth-child(2) {
+                    border-left-color: #52c41a;
+                }
+
+                &:nth-child(3) {
+                    border-left-color: #faad14;
+                }
+
+                &:nth-child(4) {
+                    border-left-color: #ff4d4f;
+                }
+            }
+
+            .card-content {
+                .card-title {
+                    font-size: px2rpx(16);
+                    color: #666;
+                    margin-bottom: px2rpx(8);
+                    font-weight: 500;
+                }
+
+                .card-value {
+                    font-size: px2rpx(18);
+                    font-weight: 700;
+                    color: #333;
+                    margin-bottom: px2rpx(4);
+                    line-height: 1;
+                }
+
+                .card-desc {
+                    font-size: px2rpx(12);
+                    color: #999;
+                    line-height: 1.4;
+                }
+            }
+        }
+
+        .btn-card {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            flex-direction: column;
+            gap: px2rpx(10);
+
+            button {
+                width: 100%;
+            }
+        }
+    }
+
+    // 响应式设计
+    @media (max-width: 768px) {
+        .data-cards {
+
+            .total-data-row,
+            .sub-data-row {
+                grid-template-columns: 1fr;
+            }
+
+            .data-card {
+                padding: px2rpx(16);
+
+                .card-content {
+                    .card-value {
+                        font-size: px2rpx(24);
+                    }
+                }
+            }
+        }
+    }
+}
+</style>

+ 0 - 15
pages/analytics/components/List.vue

@@ -62,11 +62,6 @@ const load = async () => {
   loading.value = true
   finished.value = false
   page.value = 1
-  console.log('load 请求参数', {
-    lang: locale.value == 'vn' ? 'vi' : locale.value,
-    page: { current: page.value, row: props.queryParams?.pageSize || props.pageSize },
-    ...props.queryParams
-  })
 
   try {
     const res = await props.fetchData({
@@ -99,29 +94,20 @@ const loadMore = async () => {
       page: { current: nextPage, row: props.queryParams?.pageSize || props.pageSize },
       ...props.queryParams
     }
-    console.log('loadMore 请求参数', params)  // ① 查看请求参数
-
     const res = await props.fetchData(params)
-    console.log('loadMore 响应结果', res)      // ② 查看完整响应
-
     if (res.code === 200) {
       const newList = res.data || []
-      console.log('newList 长度', newList.length, newList) // ③ 查看新数据
-
       if (newList.length > 0) {
         list.value.push(...newList)
         page.value = nextPage
-        console.log('当前列表长度', list.value.length)
       }
       // 更新 finished 状态
       const totalRows = res.page?.rowTotal || total.value
       finished.value = list.value.length >= totalRows
-      console.log('finished', finished.value, '总条数', totalRows)
     } else {
       throw new Error(res.msg || '请求失败')
     }
   } catch (err) {
-    console.error('加载更多失败', err)
     uni.showToast({ title: err.message || '加载更多失败', icon: 'none' })
   } finally {
     loadingMore.value = false
@@ -132,7 +118,6 @@ const handleItemClick = (item) => {
 }
 const lang = computed(() => uni.getLocale())
 watch(lang, (val) => {
-  console.log('lang 变化', val)
   load()
 }, { immediate: true })
 defineExpose({ load, loadMore })

+ 915 - 0
pages/common/download.vue

@@ -0,0 +1,915 @@
+<template>
+    <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
+        <cwg-header :title="t('Downloadpage.item1')" />
+        <view id="custom_Downloadpage">
+            <view class="main-content">
+                <cwg-asset-tabs v-model="activeName" :tabs="tabsConfig" />
+                <view v-if="activeName == 'MT4'">
+                    <view class="download-section">
+                        <view class="section-header">
+                            <view class="section-title" v-t="'Downloadpage.item2'" />
+                            <view class="section-subtitle" v-t="'Downloadpage.item3'" />
+                        </view>
+                        <view class="download-cards">
+                            <a class="download-card" :href="myLink + '/mt/cwgmarketssvgltd4setup.exe'"
+                                download="cwgmarketssvgltd4setup.exe">
+                                <image class="card-icon" src="/static/images/windows-os-1-48.png" alt=""
+                                    mode="widthFix" />
+                                <view class="card-info">
+                                    <view class="card-title" v-t="'Downloadpage.item4'" />
+                                    <view class="card-desc" v-t="'Downloadpage.item5'" />
+                                </view>
+                                <view class="download-badge">Windows</view>
+                            </a>
+                            <a class="download-card" :href="myLink + '/mt/mt4.zip'" download="mt4.zip">
+                                <image class="card-icon" src="/static/images/windows-os-1-48.png" alt=""
+                                    mode="widthFix" />
+                                <view class="card-info">
+                                    <view class="card-title" v-t="'Downloadpage.item4-1'" />
+                                    <view class="card-desc" v-t="'Downloadpage.item5'" />
+                                </view>
+                                <view class="download-badge">ZIP</view>
+                            </a>
+                            <a class="download-card" :href="myLink + '/mt/MetaTrader4.pkg'" download="MetaTrader4.pkg">
+                                <image class="card-icon" src="/static/images/apple-os-1-48.png" alt=""
+                                    mode="widthFix" />
+                                <view class="card-info">
+                                    <view class="card-title" v-t="'Downloadpage.item6'" />
+                                    <view class="card-desc" v-t="'Downloadpage.item5'" />
+                                </view>
+                                <view class="download-badge download-badge-apple">macOS</view>
+                            </a>
+                        </view>
+                    </view>
+                    <view class="download-section web-section">
+                        <view class="section-header">
+                            <view class="section-title" v-t="'Downloadpage.item38'" />
+                        </view>
+                        <view class="download-cards">
+                            <a class="download-card download-card-web" target="_blank"
+                                :href="'https://www.' + link + '.com/' + getLang(lang) + '/mt4/web'">
+                                <view class="card-info">
+                                    <view class="card-title" v-t="'Downloadpage.item40'" />
+                                </view>
+                                <text class="icon-arrow">→</text>
+                            </a>
+                        </view>
+                    </view>
+                    <view class="download-section mobile-section">
+                        <view class="section-header">
+                            <view class="section-title" v-t="'Downloadpage.item7'" />
+                        </view>
+                        <view class="mobile-cards">
+                            <view class="mobile-card">
+                                <view class="mobile-card-header">
+                                    <image class="card-icon" src="/static/images/android-os-3-72.png" alt=""
+                                        mode="widthFix" />
+                                    <view class="card-info">
+                                        <view class="card-title" v-t="'Downloadpage.item8'" />
+                                        <view class="card-desc" v-t="'Downloadpage.item9'" />
+                                    </view>
+                                </view>
+                                <view class="qr-codes">
+                                    <view class="qr-item">
+                                        <view class="qr-label">Google Play</view>
+                                        <QrCode :text="mt41" :logoImage="logoImage"></QrCode>
+                                    </view>
+                                    <view class="qr-item">
+                                        <view class="qr-label">MetaTrader .Apk</view>
+                                        <QrCode :text="mt42" :logoImage="logoImage"></QrCode>
+                                    </view>
+                                </view>
+                            </view>
+                            <view class="mobile-card">
+                                <view class="mobile-card-header">
+                                    <image class="card-icon" src="/static/images/apple-os-3-72.png" alt=""
+                                        mode="widthFix" />
+                                    <view class="card-info">
+                                        <view class="card-title" v-t="'Downloadpage.item8'" />
+                                        <view class="card-desc" v-t="'Downloadpage.item10'" />
+                                    </view>
+                                </view>
+                                <view class="qr-codes qr-codes-single">
+                                    <view class="qr-item">
+                                        <view class="qr-label">App Store</view>
+                                        <QrCode :text="mt43" :logoImage="logoImage"></QrCode>
+                                    </view>
+                                </view>
+                            </view>
+                        </view>
+                    </view>
+
+                </view>
+                <view v-if="activeName == 'MT5'">
+                    <view class="download-section">
+                        <view class="section-header">
+                            <view class="section-title" v-t="'Downloadpage.item11'" />
+                            <view class="section-subtitle" v-t="'Downloadpage.item12'" />
+                        </view>
+                        <view class="download-cards">
+                            <a class="download-card" :href="myLink + '/mt/cwgmarketssvg5setup.exe'"
+                                download="cwgmarketssvg5setup.exe">
+                                <image class="card-icon" src="/static/images/windows-os-1-48.png" alt=""
+                                    mode="widthFix" />
+                                <view class="card-info">
+                                    <view class="card-title" v-t="'Downloadpage.item4'" />
+                                    <view class="card-desc" v-t="'Downloadpage.item5'" />
+                                </view>
+                                <view class="download-badge">Windows</view>
+                            </a>
+                            <a class="download-card" :href="myLink + '/mt/mt5.zip'" download="mt5.zip">
+                                <image class="card-icon" src="/static/images/windows-os-1-48.png" alt=""
+                                    mode="widthFix" />
+                                <view class="card-info">
+                                    <view class="card-title" v-t="'Downloadpage.item4-1'" />
+                                    <view class="card-desc" v-t="'Downloadpage.item5'" />
+                                </view>
+                                <view class="download-badge">ZIP</view>
+                            </a>
+                            <a class="download-card" :href="myLink + '/mt/MetaTrader5.pkg'" download="MetaTrader5.dmg">
+                                <image class="card-icon" src="/static/images/apple-os-1-48.png" alt=""
+                                    mode="widthFix" />
+                                <view class="card-info">
+                                    <view class="card-title" v-t="'Downloadpage.item6'" />
+                                    <view class="card-desc" v-t="'Downloadpage.item5'" />
+                                </view>
+                                <view class="download-badge download-badge-apple">macOS</view>
+                            </a>
+                        </view>
+                    </view>
+                    <view class="download-section web-section">
+                        <view class="section-header">
+                            <view class="section-title" v-t="'Downloadpage.item39'" />
+                        </view>
+                        <view class="download-cards">
+                            <a class="download-card download-card-web" target="_blank"
+                                :href="'https://www.' + link + '.com/' + getLang(lang) + '/mt5/web'">
+                                <view class="card-info">
+                                    <view class="card-title" v-t="'Downloadpage.item40'" />
+                                </view>
+                                <text class="icon-arrow">→</text>
+                            </a>
+                        </view>
+                    </view>
+                    <view class="download-section mobile-section">
+                        <view class="section-header">
+                            <view class="section-title" v-t="'Downloadpage.item13'" />
+                        </view>
+                        <view class="mobile-cards">
+                            <view class="mobile-card">
+                                <view class="mobile-card-header">
+                                    <image class="card-icon" src="/static/images/android-os-3-72.png" alt=""
+                                        mode="widthFix" />
+                                    <view class="card-info">
+                                        <view class="card-title" v-t="'Downloadpage.item8'" />
+                                        <view class="card-desc" v-t="'Downloadpage.item14'" />
+                                    </view>
+                                </view>
+                                <view class="qr-codes">
+                                    <view class="qr-item">
+                                        <view class="qr-label">Google Play</view>
+                                        <QrCode :text="mt51" :logoImage="logoImage"></QrCode>
+                                    </view>
+                                    <view class="qr-item">
+                                        <view class="qr-label">MetaTrader .Apk</view>
+                                        <QrCode :text="mt52" :logoImage="logoImage"></QrCode>
+                                    </view>
+                                </view>
+                            </view>
+                            <view class="mobile-card">
+                                <view class="mobile-card-header">
+                                    <image class="card-icon" src="/static/images/apple-os-3-72.png" alt=""
+                                        mode="widthFix" />
+                                    <view class="card-info">
+                                        <view class="card-title" v-t="'Downloadpage.item8'" />
+                                        <view class="card-desc" v-t="'Downloadpage.item15'" />
+                                    </view>
+                                </view>
+                                <view class="qr-codes qr-codes-single">
+                                    <view class="qr-item">
+                                        <view class="qr-label">App Store</view>
+                                        <QrCode :text="mt53" :logoImage="logoImage"></QrCode>
+                                    </view>
+                                </view>
+                            </view>
+                        </view>
+                    </view>
+                </view>
+                <view v-if="activeName == 'Instruments'">
+                    <view class="instruments-banner">
+                        <view class="banner-content">
+                            <view class="banner-title" v-t="'Downloadpage.item18'" />
+                            <view class="banner-subtitle" v-t="'Downloadpage.item19'" />
+                        </view>
+                        <view class="banner-buttons">
+                            <a class="banner-btn" style="padding: 10px 25px;min-width: 220px;"
+                                href="https://mt.tradingcentral.cn/download"
+                                v-if="['cn', 'zhHant'].indexOf(Session.Get('lang')) != -1">
+                                <view v-t="'Downloadpage.item20'" />
+                                <view class="btn-tag">中国大陆用户</view>
+                            </a>
+                            <a class="banner-btn" style="padding: 10px 25px;min-width: 220px;"
+                                href="https://mt.tradingcentral.com/download"
+                                v-if="['cn', 'zhHant'].indexOf(Session.Get('lang')) != -1">
+                                <view v-t="'Downloadpage.item20'" />
+                                <view class="btn-tag">港澳台地区及海外用户</view>
+                            </a>
+                            <a class="banner-btn" href="https://mt.tradingcentral.com/download"
+                                v-if="['cn', 'zhHant'].indexOf(Session.Get('lang')) == -1">
+                                <span v-t="'Downloadpage.item20'"></span>
+                            </a>
+                        </view>
+                    </view>
+                    <view class="features-grid">
+                        <view class="feature-item">
+                            <view class="feature-icon">
+                                <i class="iconfenxi1 iconfont"></i>
+                            </view>
+                            <view class="feature-content">
+                                <view class="feature-title" v-t="'Downloadpage.item21'" />
+                                <view class="feature-desc" v-t="'Downloadpage.item22'" />
+                            </view>
+                        </view>
+                        <view class="feature-item">
+                            <view class="feature-icon">
+                                <i class="iconlazhutu iconfont"></i>
+                            </view>
+                            <view class="feature-content">
+                                <view class="feature-title" v-t="'Downloadpage.item23'" />
+                                <view class="feature-desc" v-t="'Downloadpage.item24'" />
+                            </view>
+                        </view>
+                        <view class="feature-item">
+                            <view class="feature-icon">
+                                <i class="iconzhibiao iconfont"></i>
+                            </view>
+                            <view class="feature-content">
+                                <view class="feature-title" v-t="'Downloadpage.item25'" />
+                                <view class="feature-desc" v-t="'Downloadpage.item26'" />
+                            </view>
+                        </view>
+                    </view>
+                    <view class="info-section">
+                        <view class="info-block">
+                            <view class="info-title"><span v-t="'Downloadpage.item27'"></span></view>
+                            <view class="info-content">
+                                <view class="info-item">
+                                    <view v-t="'Downloadpage.item28'" class="info-label" />
+                                    <view v-t="'Downloadpage.item29'" class="info-text" />
+                                </view>
+                                <view class="info-item info-item-border">
+                                    <view v-t="'Downloadpage.item30'" class="info-label" />
+                                    <view v-t="'Downloadpage.item31'" class="info-text" />
+                                </view>
+                            </view>
+                        </view>
+                    </view>
+                    <view class="info-section">
+                        <view class="info-block">
+                            <view class="info-title"><span v-t="'Downloadpage.item32'"></span></view>
+                            <view class="info-subtitle" v-t="'Downloadpage.item33'" />
+                            <view class="info-content">
+                                <view class="info-item">
+                                    <view v-t="'Downloadpage.item34'" class="info-label" />
+                                    <view v-t="'Downloadpage.item35'" class="info-text" />
+                                    <view class="info-image">
+                                        <image src="/static/images/tc-bg1.jpg" alt="" mode="widthFix" />
+                                    </view>
+                                </view>
+                                <view class="info-item">
+                                    <view v-t="'Downloadpage.item36'" class="info-label" />
+                                    <view v-t="'Downloadpage.item37'" class="info-text" />
+                                </view>
+                            </view>
+                        </view>
+                    </view>
+                </view>
+            </view>
+        </view>
+    </cwg-page-wrapper>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, onMounted } from 'vue'
+import QrCode from "@/components/QRCode.vue"
+// import logoImage from "@/assets/images/MTBG.jpg"
+import { useI18n } from 'vue-i18n'
+
+const { t, locale } = useI18n()
+
+// ---------- 存储辅助函数(模拟原 Session) ----------
+const Session = {
+    Get(key: string, parse = false) {
+        const value = uni.getStorageSync(key)
+        if (parse && value) {
+            try {
+                return JSON.parse(value)
+            } catch {
+                return value
+            }
+        }
+        return value
+    }
+}
+
+// ---------- 响应式数据 ----------
+const activeName = ref('MT4')
+const link = ref('')
+const myLink = ref('')
+const logoImageRef = ref('')  // 保持变量名 logoImage
+const mt41 = ref('https://www.metatrader4.com/en/download#download-block-android?server=CWGMarketsSVGLtd-Demo,CWGMarketsSVGLtd-Live')
+const mt42 = ref('')  // 稍后动态计算
+const mt43 = ref('https://apps.apple.com/us/app/metatrader-4/id496212596?server=CWGMarketsSVGLtd-Demo,CWGMarketsSVGLtd-Live')
+const mt51 = ref('https://download.metatrader.com/cdn/mobile/mt5/android?server=CWGMarketsSVG-Demo,CWGMarketsSVG-Live')
+const mt52 = ref('')
+const mt53 = ref('https://download.metatrader.com/cdn/mobile/mt5/ios?server=CWGMarketsSVG-Demo,CWGMarketsSVG-Live')
+
+// ---------- 辅助函数:获取当前域名主体(兼容 H5) ----------
+const getDomainMain = () => {
+    // 在 uni-app H5 环境下可使用 window.location
+    // 若在其他环境(如 App 内嵌 webview)可能没有 window,这里做兼容
+    if (typeof window !== 'undefined' && window.location && window.location.host) {
+        const parts = window.location.host.split('.')
+        return parts.length > 1 ? parts[1] : ''
+    }
+    // 降级方案:从配置或空字符串
+    return ''
+}
+
+const getOrigin = () => {
+    if (typeof window !== 'undefined' && window.location && window.location.origin) {
+        return window.location.origin
+    }
+    return ''
+}
+const tabsConfig = computed(() => [
+    { text: 'MT4', value: 'MT4' },
+    { text: 'MT5', value: 'MT5' },
+])
+// ---------- 计算属性 ----------
+const country = computed(() => {
+    const user = Session.Get("user", true)
+    return user?.customInfo?.country
+})
+
+const lang = computed(() => {
+    return Session.Get('lang')
+})
+
+// ---------- 方法 ----------
+const getLang = (lang: string) => {
+    let val = 'en'
+    if (lang == 'cn') {
+        val = 'cn'
+    } else if (lang == 'zhHant') {
+        val = 'zh'
+    } else {
+        val = 'en'
+    }
+    return val
+}
+
+// ---------- 生命周期 ----------
+onMounted(() => {
+    // 计算动态链接
+    const domainMain = getDomainMain()
+    const origin = getOrigin()
+
+    link.value = domainMain
+    myLink.value = origin
+
+    // 原 mt42 动态拼接
+    mt42.value = `https://secure.${domainMain}.com/metatrader/metatrader4.apk`
+    // 原 mt52 动态拼接
+    mt52.value = `${origin}/mt/metatrader5.apk`
+})
+
+// 组件导出(可选,defineOptions 保留组件名)
+defineOptions({
+    name: "custom_Downloadpage"
+})
+</script>
+<style lang="scss" scoped>
+@import "@/uni.scss";
+
+#custom_Downloadpage {
+    width: 100%;
+    height: 100%;
+
+    .main-content {
+        width: 100%;
+        height: calc(100% - px2rpx(50));
+        padding: px2rpx(10);
+        box-sizing: border-box;
+        overflow-y: auto;
+    }
+
+    .download-section {
+        background: #fff;
+        border-radius: px2rpx(12);
+        padding: px2rpx(24) px2rpx(20);
+        margin-bottom: px2rpx(16);
+        box-shadow: 0 px2rpx(2) px2rpx(12) rgba(0, 0, 0, 0.06);
+
+        .section-header {
+            text-align: center;
+            margin-bottom: px2rpx(24);
+        }
+
+        .section-title {
+            font-size: px2rpx(20);
+            font-weight: 600;
+            color: #333;
+            margin-bottom: px2rpx(8);
+        }
+
+        .section-subtitle {
+            font-size: px2rpx(14);
+            color: #666;
+            line-height: 1.5;
+        }
+    }
+
+    .download-cards {
+        display: flex;
+        justify-content: center;
+        flex-wrap: wrap;
+        gap: px2rpx(16);
+    }
+
+    .download-card {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        padding: px2rpx(24) px2rpx(20);
+        background: linear-gradient(135deg, #4990EF 0%, #3A7BE0 100%);
+        color: #fff;
+        border-radius: px2rpx(12);
+        min-width: px2rpx(160);
+        max-width: px2rpx(200);
+        text-decoration: none;
+        transition: all 0.3s ease;
+        position: relative;
+        overflow: hidden;
+
+        &::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            bottom: 0;
+            background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, transparent 100%);
+        }
+
+        &:hover {
+            transform: translateY(px2rpx(-4));
+            box-shadow: 0 px2rpx(8) px2rpx(24) rgba(73, 144, 239, 0.35);
+        }
+
+        &:active {
+            transform: translateY(px2rpx(-2));
+        }
+
+        .card-icon {
+            width: px2rpx(48);
+            height: px2rpx(48);
+            margin-bottom: px2rpx(16);
+            position: relative;
+            z-index: 1;
+        }
+
+        .card-info {
+            text-align: center;
+            position: relative;
+            z-index: 1;
+
+            .card-title {
+                font-size: px2rpx(15);
+                font-weight: 500;
+                margin-bottom: px2rpx(4);
+            }
+
+            .card-desc {
+                font-size: px2rpx(12);
+                opacity: 0.85;
+            }
+        }
+
+        .download-badge {
+            margin-top: px2rpx(12);
+            padding: px2rpx(4) px2rpx(12);
+            background: rgba(255, 255, 255, 0.2);
+            border-radius: px2rpx(20);
+            font-size: px2rpx(11);
+            font-weight: 500;
+            position: relative;
+            z-index: 1;
+        }
+
+        .download-badge-apple {
+            background: rgba(0, 0, 0, 0.25);
+        }
+    }
+
+    .download-card-web {
+        flex-direction: row;
+        justify-content: space-between;
+        padding: px2rpx(20) px2rpx(24);
+        min-width: px2rpx(280);
+        max-width: 100%;
+        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+
+        .card-info {
+            text-align: left;
+        }
+
+        .icon-arrow {
+            font-size: px2rpx(20);
+            opacity: 0.9;
+        }
+
+        &:hover {
+            .icon-arrow {
+                transform: translateX(px2rpx(4));
+                transition: transform 0.3s ease;
+            }
+        }
+    }
+
+    .mobile-section {
+        .mobile-cards {
+            display: flex;
+            flex-direction: column;
+            gap: px2rpx(20);
+        }
+
+        .mobile-card {
+            background: #f8f9fa;
+            border-radius: px2rpx(12);
+            padding: px2rpx(20);
+            border: px2rpx(1) solid #eee;
+        }
+
+        .mobile-card-header {
+            display: flex;
+            align-items: center;
+            margin-bottom: px2rpx(20);
+
+            .card-icon {
+                width: px2rpx(40);
+                height: px2rpx(40);
+                margin-right: px2rpx(16);
+            }
+
+            .card-info {
+                text-align: left;
+
+                .card-title {
+                    font-size: px2rpx(16);
+                    font-weight: 600;
+                    color: #333;
+                    margin-bottom: px2rpx(4);
+                }
+
+                .card-desc {
+                    font-size: px2rpx(13);
+                    color: #666;
+                }
+            }
+        }
+
+        .qr-codes {
+            display: flex;
+            justify-content: space-around;
+            flex-wrap: wrap;
+            gap: px2rpx(16);
+
+            &.qr-codes-single {
+                justify-content: center;
+            }
+        }
+
+        .qr-item {
+            text-align: center;
+
+            .qr-label {
+                font-weight: 600;
+                font-size: px2rpx(13);
+                color: #333;
+                margin-bottom: px2rpx(10);
+                line-height: 2;
+            }
+        }
+    }
+
+    .instruments-banner {
+        width: 100%;
+        padding: px2rpx(40) px2rpx(20);
+        background-image: url('/static/images/tc_bg.png');
+        background-size: cover;
+        background-repeat: no-repeat;
+        background-position: center;
+        color: #fff;
+        text-align: center;
+        border-radius: px2rpx(12);
+        margin-bottom: px2rpx(16);
+        box-sizing: border-box;
+
+        .banner-content {
+            margin-bottom: px2rpx(24);
+        }
+
+        .banner-title {
+            font-size: px2rpx(22);
+            font-weight: 600;
+            margin-bottom: px2rpx(8);
+        }
+
+        .banner-subtitle {
+            font-size: px2rpx(14);
+            opacity: 0.9;
+        }
+
+        .banner-buttons {
+            display: flex;
+            justify-content: center;
+            flex-wrap: wrap;
+            gap: px2rpx(12);
+        }
+
+        .banner-btn {
+            display: inline-flex;
+            flex-direction: column;
+            align-items: center;
+            padding: px2rpx(14) px2rpx(25);
+            background-color: #EB3F57;
+            color: #fff;
+            font-size: px2rpx(14);
+            text-decoration: none;
+            border-radius: px2rpx(8);
+            transition: all 0.3s ease;
+            min-width: px2rpx(200);
+
+            &:hover {
+                background-color: #d6364d;
+                transform: translateY(px2rpx(-2));
+                box-shadow: 0 px2rpx(4) px2rpx(12) rgba(235, 63, 87, 0.4);
+            }
+
+            .btn-tag {
+                font-size: px2rpx(12);
+                opacity: 0.85;
+                margin-top: px2rpx(4);
+            }
+        }
+    }
+
+    .features-grid {
+        background: #fff;
+        border-radius: px2rpx(12);
+        padding: px2rpx(24) px2rpx(20);
+        margin-bottom: px2rpx(16);
+        box-shadow: 0 px2rpx(2) px2rpx(12) rgba(0, 0, 0, 0.06);
+
+        .feature-item {
+            display: flex;
+            align-items: center;
+            padding: px2rpx(20) 0;
+            border-bottom: px2rpx(1) solid #f0f0f0;
+
+            &:last-child {
+                border-bottom: none;
+            }
+        }
+
+        .feature-icon {
+            width: px2rpx(64);
+            height: px2rpx(64);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            background: linear-gradient(135deg, #fef0f0 0%, #ffe8e8 100%);
+            border-radius: px2rpx(12);
+            margin-right: px2rpx(16);
+            flex-shrink: 0;
+
+            i {
+                font-size: px2rpx(32);
+                color: #EB3F57;
+            }
+        }
+
+        .feature-content {
+            flex: 1;
+        }
+
+        .feature-title {
+            font-size: px2rpx(16);
+            font-weight: 600;
+            color: #333;
+            margin-bottom: px2rpx(6);
+        }
+
+        .feature-desc {
+            font-size: px2rpx(14);
+            color: #666;
+            line-height: 1.6;
+        }
+    }
+
+    .info-section {
+        background: #fff;
+        border-radius: px2rpx(12);
+        padding: px2rpx(24) px2rpx(20);
+        margin-bottom: px2rpx(16);
+        box-shadow: 0 px2rpx(2) px2rpx(12) rgba(0, 0, 0, 0.06);
+
+        .info-block {
+            .info-title {
+                font-size: px2rpx(20);
+                font-weight: 600;
+                text-align: center;
+                margin-bottom: px2rpx(20);
+
+                span {
+                    border-bottom: px2rpx(3) solid #EB3F57;
+                    padding: 0 px2rpx(8) px2rpx(8);
+                }
+            }
+
+            .info-subtitle {
+                font-size: px2rpx(14);
+                color: #666;
+                text-align: center;
+                margin-bottom: px2rpx(24);
+            }
+        }
+
+        .info-content {
+            .info-item {
+                padding: px2rpx(20) 0;
+                border-bottom: px2rpx(1) dashed #e0e0e0;
+
+                &:last-child {
+                    border-bottom: none;
+                }
+
+                &.info-item-border {
+                    border-top: px2rpx(1) dashed #e0e0e0;
+                }
+            }
+
+            .info-label {
+                font-size: px2rpx(15);
+                font-weight: 600;
+                color: #333;
+                margin-bottom: px2rpx(8);
+            }
+
+            .info-text {
+                font-size: px2rpx(14);
+                color: #666;
+                line-height: 1.6;
+            }
+
+            .info-image {
+                display: flex;
+                justify-content: center;
+                padding-top: px2rpx(24);
+
+                image {
+                    max-width: 100%;
+                    border-radius: px2rpx(8);
+                }
+            }
+        }
+    }
+
+    @media (max-width: 768px) {
+        .download-section {
+            padding: px2rpx(16) px2rpx(12);
+            border-radius: px2rpx(8);
+
+            .section-title {
+                font-size: px2rpx(18);
+            }
+        }
+
+        .download-cards {
+            gap: px2rpx(12);
+        }
+
+        .download-card {
+            min-width: px2rpx(140);
+            padding: px2rpx(16) px2rpx(12);
+
+            .card-icon {
+                width: px2rpx(40);
+                height: px2rpx(40);
+            }
+
+            .card-info {
+                .card-title {
+                    font-size: px2rpx(13);
+                }
+
+                .card-desc {
+                    font-size: px2rpx(11);
+                }
+            }
+        }
+
+        .download-card-web {
+            width: 100%;
+        }
+
+        .mobile-section {
+            .mobile-card {
+                padding: px2rpx(16);
+            }
+
+            .qr-codes {
+                gap: px2rpx(12);
+            }
+        }
+
+        .instruments-banner {
+            padding: px2rpx(24) px2rpx(16);
+            border-radius: px2rpx(8);
+
+            .banner-title {
+                font-size: px2rpx(18);
+            }
+
+            .banner-btn {
+                min-width: px2rpx(160);
+                padding: px2rpx(12) px2rpx(20);
+            }
+        }
+
+        .features-grid {
+            padding: px2rpx(16) px2rpx(12);
+            border-radius: px2rpx(8);
+
+            .feature-item {
+                flex-direction: column;
+                text-align: center;
+                padding: px2rpx(16) 0;
+            }
+
+            .feature-icon {
+                margin-right: 0;
+                margin-bottom: px2rpx(12);
+            }
+        }
+
+        .info-section {
+            padding: px2rpx(16) px2rpx(12);
+            border-radius: px2rpx(8);
+
+            .info-block {
+                .info-title {
+                    font-size: px2rpx(18);
+                }
+            }
+        }
+    }
+
+    :deep(.el-tabs) {
+        .el-tabs__header {
+            margin-bottom: px2rpx(20);
+        }
+
+        .el-tabs__nav-wrap::after {
+            height: px2rpx(1);
+        }
+
+        .el-tabs__item {
+            font-size: px2rpx(15);
+            color: #999;
+            padding: 0 px2rpx(20);
+            height: px2rpx(44);
+            line-height: px2rpx(44);
+
+            &.is-active {
+                color: #4990EF;
+                font-weight: 600;
+            }
+        }
+
+        .el-tabs__active-bar {
+            height: px2rpx(3);
+            border-radius: px2rpx(3);
+        }
+    }
+
+    :deep(uni-image),
+    :deep(img) {
+        width: px2rpx(30);
+        height: px2rpx(30);
+        object-fit: cover;
+        border-radius: px2rpx(6);
+    }
+}
+</style>

+ 24 - 23
pages/customer/components/AccountCard.vue

@@ -46,7 +46,7 @@
                         <view class="circle-icon">
                             <cwg-icon name="crm-ellipsis-vertical" :size="16" color="#2e3a47" />
                         </view>
-                        <text class="circle-label" v-t="'Latest.More'" />
+                        <text class="circle-label" v-t="'vu.item7'" />
                     </view>
                 </cwg-dropdown>
             </view>
@@ -56,9 +56,9 @@
                 <template v-for="(item, index) in actionButtons" :key="index">
                     <view class="action-btn" :class="{ 'primary': item.primary, 'is-disabled': item.disabled }"
                         @click="handleAction1(item)" v-if="!item.needDemo">
-                        <span class="btn-icon">
+                        <text class="btn-icon">
                             <cwg-icon :name="item.icon" :size="16" :color="item.color" />
-                        </span>
+                        </text>
                         <text v-t="item.label" />
                     </view>
                 </template>
@@ -78,21 +78,22 @@
             <view class="info-section">
                 <view class="info-column">
                     <cwg-label-line-value :label="t('Label.Leverage')" :value="account.actualLeverage" />
-                    <cwg-label-line-value label="浮动盈/亏" :value="account.floatingPL" />
+                    <cwg-label-line-value :label="t('Documentary.console.item5')" :value="account.floatingPL" />
                     <cwg-label-line-value :label="t('Label.Balance')" :value="account.balanceWithSymbol" />
                 </view>
                 <view class="info-column">
                     <cwg-label-line-value :label="t('Label.Equity')" :value="account.equityWithSymbol" />
                     <cwg-label-line-value :label="t('Label.Credit')" :value="account.creditWithSymbol" />
-                    <cwg-label-line-value label="平台" :value="account.platform" />
+                    <cwg-label-line-value :label="t('Documentary.console.item3')" :value="account.platform" />
                 </view>
             </view>
             <!-- 额外操作行(服务器、登录、更改密码,折叠时隐藏) -->
             <view class="extra-actions">
                 <!-- 登录复制行 -->
                 <view class="copy-row">
-                    <span class="label">{{ account.platform }} 登陆</span>
-                    <span class="value">{{ account.login }}</span>
+                    <text class="label">{{ account.platform }}</text>
+                    <text class="label" v-t="'signin.title'" />
+                    <text class="value">{{ account.login }}</text>
                     <view class="copy-btn" @click="copy(account.login)">
                         <cwg-icon name="copy" :size="16" color="#2e3a47" />
                     </view>
@@ -100,10 +101,10 @@
 
                 <!-- 更改交易密码按钮 -->
                 <view class="change-password-btn" @click="handleAction('changePassword1')" v-if="!isDemo">
-                    <span class="btn-icon">
+                    <text class="btn-icon">
                         <cwg-icon name="crm-xg" :size="16" color="#2e3a47" />
-                    </span>
-                    更改交易密码
+                    </text>
+                    <text v-t="'vu.item3'" />
                 </view>
             </view>
         </view>
@@ -112,9 +113,9 @@
         <view class="notificators"></view>
         <TerminalDialog v-model:visible="terminalDialogVisible" />
         <TerminalChangePasswordDialog v-model:visible="terminalChangePasswordDialogVisible" :pwdType="pwdType"
-            :account="account" />
+            :account="account" :accountLabel="t('Documentary.tradingCenter.item29') + ' # '" />
         <TerminalInfoDialog v-model:visible="terminalInfoDialogVisible" :accountNumber="accountInfo.login"
-            :form="accountInfo" :fieldList="fieldList" />
+            :form="accountInfo" :fieldList="fieldList" :title="t('Documentary.TundManagement.item29')" :accountLabel="t('Documentary.tradingCenter.item29') + ' # '" />
     </view>
 </template>
 
@@ -151,7 +152,6 @@ export interface Account {
 }
 const isDemo = computed(() => accountInfo.value.listType == 'demo')
 const closeFunctionOpen = (code) => {
-    console.log(code, 121212);
     const closeFunctions = accountInfo.value.closeFunctions || ""
 
     if (closeFunctions == null || closeFunctions === "") {
@@ -175,14 +175,14 @@ const actionButtons = computed(() => [
     { key: 'transfer', label: 'Custom.Index.Transfer', icon: 'crm-transfer', color: '#2e3a47', primary: false, action: 'transfer', needDemo: isDemo.value, disabled: !(closeFunctionOpen('5') && closeFunctionOpen('6') && closeFunctionOpen('3')) }
 ])
 const fieldList = ref([
-    { label: '账户类型', key: 'nickname', copyable: false },
-    { label: t('Label.Leverage'), key: 'actualLeverage', copyable: false },
-    { label: '浮动盈/亏', key: 'floatingPL', copyable: false },
-    { label: t('Label.Balance'), key: 'balanceWithSymbol', copyable: false },
-    { label: t('Label.Equity'), key: 'equityWithSymbol', copyable: false },
-    { label: t('Label.Credit'), key: 'creditWithSymbol', copyable: false },
-    { label: '平台', key: 'platform', copyable: false },
-    { label: '账号', key: 'login', copyable: true }
+    { label: 'Custom.PaymentHistory.AccountType', key: 'nickname', copyable: false },
+    { label: 'Label.Leverage', key: 'actualLeverage', copyable: false },
+    { label: 'Documentary.console.item5', key: 'floatingPL', copyable: false },
+    { label: 'Label.Balance', key: 'balanceWithSymbol', copyable: false },
+    { label: 'Label.Equity', key: 'equityWithSymbol', copyable: false },
+    { label: 'Label.Credit', key: 'creditWithSymbol', copyable: false },
+    { label: 'Documentary.console.item3', key: 'platform', copyable: false },
+    { label: 'Documentary.console.item4', key: 'login', copyable: true }
 ])
 const nickName = ref(accountInfo.value.nickName)
 
@@ -261,7 +261,7 @@ const handleAction = (type: string) => {
     }
 };
 
-const customMenuList = computed(() => !isDemo.value ? [{ label: '修改交易密码', type: 'changePassword1' }, { label: '修改投资者密码', type: 'changePassword2' }, { label: '账户信息', type: 'info' }] : [{ label: '账户信息', type: 'info' }])
+const customMenuList = computed(() => !isDemo.value ? [{ label: t('vu.item3'), type: 'changePassword1' }, { label: t('vu.item4'), type: 'changePassword2' }, { label: t('Documentary.TundManagement.item29'), type: 'info' }] : [{ label: t('Documentary.TundManagement.item29'), type: 'info' }])
 const handleCustomClick = (item, index) => {
     handleAction(item.value.type)
 }
@@ -418,6 +418,7 @@ onBeforeUnmount(() => {
                     justify-content: center;
                     color: #2e3a47;
                     transition: background-color 0.2s;
+
                     &.primary {
                         background-color: var(--color-navy-700);
                         color: #fff;
@@ -562,7 +563,7 @@ onBeforeUnmount(() => {
 
             .label {
                 color: #6c8595;
-                min-width: px2rpx(70);
+                min-width: px2rpx(30);
             }
 
             .value {

+ 6 - 6
pages/customer/components/AccountList.vue

@@ -11,8 +11,8 @@
         </view>
         <view class="tabs-class"><cwg-tabs v-model:cativeIndex="cativeIndex" :tabs="tabs" /></view>
         <view v-if="accounts.length">
-            <AccountCard v-for="acc in accounts" :zhtype="cativeIndex" :key="acc.accountNumber" :account="acc" @action="handleAction"
-                @copy="handleCopy" @change-password="handleChangePassword" />
+            <AccountCard v-for="acc in accounts" :zhtype="cativeIndex" :key="acc.accountNumber" :account="acc"
+                @action="handleAction" @copy="handleCopy" @change-password="handleChangePassword" />
         </view>
         <cwg-empty-state v-else />
         <DeleteAccountDialogs ref="deleteAccountDialogRef" v-model:visible="deleteAccountDialogVisible" />
@@ -56,8 +56,8 @@ const typeMap = computed(() => ({
 }));
 const cativeIndex = ref(0)
 const tabs = computed(() => ([
-    { id: 'real', name: '真实' },
-    { id: 'demo', name: '模拟' }
+    { id: 'real', name: t('vu.item1') },
+    { id: 'demo', name: t('vu.item2') }
 ]))
 
 const tableRef = ref(null)
@@ -201,8 +201,8 @@ const accounts = computed(() =>
     AccountList.value && AccountList.value.length != 0 ? AccountList.value.map((acc, index) => {
         const currency = acc.currency || 'USD';
         const floating = acc.floating ?? 0;
-        let labels = ['真实', 'MT4', 'Standard'];
-        labels[0] = cativeIndex.value == 1 ? '模拟' : '真实';
+        let labels = [t('vu.item1'), 'MT4', 'Standard'];
+        labels[0] = cativeIndex.value == 1 ? t('vu.item2') : t('vu.item1');
         labels[1] = acc.platform || 'MT4';
         labels[2] = typeMap.value[acc.type];
         let nickname = typeMap.value[acc.type];

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

@@ -1,6 +1,6 @@
 <template>
     <cwg-popup :title="props.pwdType == 1 ? t('Custom.Settings.LoginPwd') : t('Custom.Settings.InvestorPwd')"
-        :visible="props.visible" :showFooters="false" @update:visible="$emit('update:visible', $event)">
+        :visible="props.visible" :showFooter="false" @update:visible="$emit('update:visible', $event)">
         <view class="popup-content">
             <text class="account-number">{{ accountLabel }} {{ account.login }}</text>
 

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

@@ -25,19 +25,6 @@
                         </view>
                     </template>
                 </cwg-label-line-value>
-                <!-- <text class="label">{{ field.label }}</text>
-                <view class="value-wrapper">
-                    <text class="value">{{ getFieldValue(field.key) || '--' }}</text>
-                    <view v-if="field.copyable" class="copy-btn" @click="copyValue(getFieldValue(field.key))">
-                        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
-                            stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
-                            <path
-                                d="M7 7m0 2.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667z" />
-                            <path
-                                d="M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1" />
-                        </svg>
-                    </view>
-                </view> -->
             </view>
         </view>
     </cwg-popup>

+ 1 - 1
pages/customer/transfer.vue

@@ -362,7 +362,7 @@ const withdrawDisplayList = computed(() => {
 const transferTypeOptions = computed(() => [
     { value: 'internal', text: t('Home.page_customer.item5') },
     ...(getInfoAgentTransfer.value ? [{ value: 'agent', text: t('Home.page_ib.item9') }] : []),
-    ...(systemTransferType.value === 1 ? [{ value: 'system', text: t('Custom.Transfer.SystemTransfer') }] : []),
+    // ...(systemTransferType.value === 1 ? [{ value: 'system', text: t('Home.page_ib.item9') }] : []),
 ]);
 const currencyOptions = ref([{ value: 'USD', text: 'USD' }])
 // 转入账户列表 

+ 5 - 4
pages/customer/withdrawal.vue

@@ -29,7 +29,7 @@
             </view>
             <view v-if="step3" class="reselect-btn">
               <button class="s-btn reselect" type="primary" @click="showTable">{{ t('Custom.Deposit.Reselect')
-                }}</button>
+              }}</button>
             </view>
           </view>
         </view>
@@ -41,6 +41,7 @@
           <view class="card-top">
             <!-- 注意事项 -->
             <view v-if="!isStep3" class="step3-attention">
+              {{ introduce.value }}
               <view class="tips" v-if="(introduce.introduce || introduce.enIntroduce)">
                 <view>
                   <rich-text class="attention" :nodes="isZh ? introduce.introduce : introduce.enIntroduce" />
@@ -120,7 +121,7 @@
                     <text>{{ t('Custom.Withdraw.addBank') }}</text>
                     <text class="add-btn crm-cursor" @click="openAddBankCard('add_bankCard')">{{
                       t('Custom.Withdraw.addBank1')
-                    }}</text>
+                      }}</text>
                   </view>
                   <view class="add-back" v-else-if="channelData.type === 'CHANNEL_TYPE_CARD'">
                     <text>{{ t('PersonalManagement.Label.addCreditCard') }}</text>
@@ -1362,7 +1363,8 @@ function isShowStep3(row) {
   if (row.type === 'BANK_TELEGRAPHIC') tableData.International_Transfer = [row]
   if (row.type === 'CHANNEL_TYPE_CARD') tableData.CHANNEL_TYPE_CARD = [row]
   if (row.type === 'CHANNEL_TYPE_ALI_WALLET') tableData.CHANNEL_TYPE_ALI_WALLET = [row]
-  introduce.value = { introduce: row.introduce, enIntroduce: row.enIntroduce }
+  introduce.introduce = row.introduce
+  introduce.enIntroduce = row.enIntroduce
 }
 //更换支付方式
 function showTable() {
@@ -1799,7 +1801,6 @@ onMounted(() => {
       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;

+ 1 - 0
static/icons/crm-hd.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-award"><path d="M12 9m-6 0a6 6 0 1 0 12 0a6 6 0 1 0 -12 0"></path><path d="M12 15l3.4 5.89l1.598 -3.233l3.598 .232l-3.4 -5.889"></path><path d="M6.802 12l-3.4 5.89l3.598 -.233l1.598 3.232l3.4 -5.889"></path></svg>

+ 8 - 0
static/svg-icons-lib.js

@@ -143,6 +143,10 @@ const collections = {
         "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 640\"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path fill=\"#22ac38\" d=\"M259.1 73.5c3-14.8 16.1-25.5 31.3-25.5h59.8c15.2 0 28.3 10.7 31.3 25.5l14.5 70c14.1 6 27.3 13.7 39.3 22.8l67.8-22.5c14.4-4.8 30.2 1.2 37.8 14.4l29.9 51.8c7.6 13.2 4.9 29.8-6.5 39.9L511 297.3c.9 7.4 1.3 15 1.3 22.7s-.5 15.3-1.3 22.7l53.4 47.5c11.4 10.1 14 26.8 6.5 39.9L541 481.9c-7.6 13.1-23.4 19.2-37.8 14.4l-67.8-22.5c-12.1 9.1-25.3 16.7-39.3 22.8l-14.4 69.9c-3.1 14.9-16.2 25.5-31.3 25.5h-59.8c-15.2 0-28.3-10.7-31.3-25.5l-14.4-69.9c-14.1-6-27.2-13.7-39.3-22.8l-68.1 22.5c-14.4 4.8-30.2-1.2-37.8-14.4l-29.9-51.8c-7.6-13.2-4.9-29.8 6.5-39.9l53.4-47.5c-.9-7.4-1.3-15-1.3-22.7s.5-15.3 1.3-22.7l-53.4-47.5c-11.4-10.1-14-26.8-6.5-39.9l29.9-51.8c7.6-13.2 23.4-19.2 37.8-14.4l67.8 22.5c12.1-9.1 25.3-16.7 39.3-22.8zM320.3 400c44.2-.2 79.9-36.1 79.7-80.3s-36.1-79.9-80.3-79.7-79.9 36.1-79.7 80.3 36.1 79.9 80.3 79.7\"/></svg>",
         2
       ],
+      "crm-hd": [
+        "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#22ac38\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" class=\"tabler-icon tabler-icon-award\" viewBox=\"0 0 24 24\"><path d=\"M6 9a6 6 0 1 0 12 0A6 6 0 1 0 6 9\"/><path d=\"m12 15 3.4 5.89 1.598-3.233 3.598.232-3.4-5.889M6.802 12l-3.4 5.89L7 17.657l1.598 3.232 3.4-5.889\"/></svg>",
+        2
+      ],
       "crm-headset": [
         "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 640\"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path fill=\"#22ac38\" d=\"M320 128c-79 0-144.7 57.3-157.7 132.7 9.3-3 19.3-4.7 29.7-4.7h16c26.5 0 48 21.5 48 48v96c0 26.5-21.5 48-48 48h-16c-53 0-96-43-96-96v-64C96 164.3 196.3 64 320 64s224 100.3 224 224v168.1c0 66.3-53.8 120-120.1 120L336 576h-32c-26.5 0-48-21.5-48-48s21.5-48 48-48h32c26.5 0 48 21.5 48 48h40c39.8 0 72-32.2 72-72v-20.9c-14.1 8.2-30.5 12.8-48 12.8h-16c-26.5 0-48-21.5-48-48v-96c0-26.5 21.5-48 48-48h16c10.4 0 20.3 1.6 29.7 4.7-13-75.3-78.6-132.7-157.7-132.7z\"/></svg>",
         2
@@ -184,6 +188,10 @@ const collections = {
         "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 640\"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path fill=\"#22ac38\" d=\"M64 480V184c0-13.3 10.7-24 24-24s24 10.7 24 24v288c0 13.3 10.7 24 24 24s24-10.7 24-24V160c0-35.3 28.7-64 64-64h288c35.3 0 64 28.7 64 64v320c0 35.3-28.7 64-64 64H128c-35.3 0-64-28.7-64-64m160-288v64c0 17.7 14.3 32 32 32h64c17.7 0 32-14.3 32-32v-64c0-17.7-14.3-32-32-32h-64c-17.7 0-32 14.3-32 32m24 240c-13.3 0-24 10.7-24 24s10.7 24 24 24h240c13.3 0 24-10.7 24-24s-10.7-24-24-24zm-24-72c0 13.3 10.7 24 24 24h240c13.3 0 24-10.7 24-24s-10.7-24-24-24H248c-13.3 0-24 10.7-24 24m200-120c-13.3 0-24 10.7-24 24s10.7 24 24 24h64c13.3 0 24-10.7 24-24s-10.7-24-24-24z\"/></svg>",
         2
       ],
+      "crm-option": [
+        "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 640\"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path fill=\"#22ac38\" d=\"M96 128c-17.7 0-32 14.3-32 32s14.3 32 32 32h86.7c12.3 28.3 40.5 48 73.3 48s61-19.7 73.3-48H544c17.7 0 32-14.3 32-32s-14.3-32-32-32H329.3C317 99.7 288.8 80 256 80s-61 19.7-73.3 48zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32h246.7c12.3 28.3 40.5 48 73.3 48s61-19.7 73.3-48H544c17.7 0 32-14.3 32-32s-14.3-32-32-32h-54.7c-12.3-28.3-40.5-48-73.3-48s-61 19.7-73.3 48zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32h54.7c12.3 28.3 40.5 48 73.3 48s61-19.7 73.3-48H544c17.7 0 32-14.3 32-32s-14.3-32-32-32H297.3c-12.3-28.3-40.5-48-73.3-48s-61 19.7-73.3 48z\"/></svg>",
+        2
+      ],
       "crm-payment": [
         "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#22ac38\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" class=\"tabler-icon tabler-icon-wallet\" viewBox=\"0 0 24 24\"><path d=\"M17 8V5a1 1 0 0 0-1-1H6a2 2 0 0 0 0 4h12a1 1 0 0 1 1 1v3m0 4v3a1 1 0 0 1-1 1H6a2 2 0 0 1-2-2V6\"/><path d=\"M20 12v4h-4a2 2 0 0 1 0-4z\"/></svg>",
         2