zhb 1 месяц назад
Родитель
Сommit
98af1d5266

+ 1 - 1
components/QrCode.vue

@@ -71,7 +71,7 @@ const props = defineProps({
         default: 0.22
     }
 })
-const canvasId = `qr_${Date.now()}`
+const canvasId = `qr_${Date.now()}_${Math.floor(Math.random() * 10000000000).toString().padStart(10, '0')}`
 
 /** 绘制二维码 */
 async function drawQr() {

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

@@ -48,7 +48,9 @@ const linkList = [
     display: grid;
     grid-template-columns: 1fr;
     margin: px2rpx(16) px2rpx(24);
-    margin: px2rpx(64) 0px;
+    padding: px2rpx(64) 0px;
+    border-top: 1px solid #e4e7ed;
+    box-sizing: border-box;
 
     .footer-description {
         .desc-block {

+ 5 - 5
components/cwg-file-picker-wrapper.vue

@@ -167,7 +167,7 @@ function formatValue(val) {
   if (typeof val === 'string') {
     return [{
       path: val,
-      url: val.startsWith('http') ? val : config.Host80 + val,
+      url: val.startsWith('http') ? val : config.Host05 + val,
       name: val.split('/').pop(),
       status: 'success'
     }]
@@ -179,7 +179,7 @@ function formatValue(val) {
     return [{
       ...val,
       path,
-      url: val.url || (path.startsWith('http') ? path : config.Host80 + path),
+      url: val.url || (path.startsWith('http') ? path : config.Host05 + path),
       name: val.name || path.split('/').pop(),
       status: 'success'
     }]
@@ -191,7 +191,7 @@ function formatValue(val) {
       if (typeof item === 'string') {
         return {
           path: item,
-          url: item.startsWith('http') ? item : config.Host80 + item,
+          url: item.startsWith('http') ? item : config.Host05 + item,
           name: item.split('/').pop(),
           status: 'success'
         }
@@ -200,7 +200,7 @@ function formatValue(val) {
         return {
           ...item,
           path,
-          url: item?.url || (path.startsWith('http') ? path : config.Host80 + path),
+          url: item?.url || (path.startsWith('http') ? path : config.Host05 + path),
           name: item?.name || path.split('/').pop(),
           status: 'success'
         }
@@ -383,7 +383,7 @@ const uploadFile = (fileItem) => {
         if (result.success) {
           innerFileList.value[index].progress = 100
           innerFileList.value[index].status = 'success'
-          innerFileList.value[index].url = config.Host80 + result.path
+          innerFileList.value[index].url = config.Host05 + result.path
           innerFileList.value[index].path = result.path
           emit('success', innerFileList.value[index])
         } else {

+ 14 - 2
components/cwg-right-drawer.vue

@@ -10,7 +10,7 @@
                         <image class="avatar" src="/static/images/avatars.png" mode="aspectFill" />
                         <view class="user-info">
                             <text class="name">{{ _displayName }}</text>
-                            <text class="cid">CID: {{ _displayCid }}</text>
+                            <text class="cid">CID: <text class="cwg-cursor" @click="copy(_displayCid)">{{ _displayCid }}</text></text>
                         </view>
                     </view>
                     <view class="menu-list">
@@ -52,7 +52,19 @@ const menuList = ref([])
 const _displayName = ref('--')
 const _displayCid = ref('--')
 const _activePath = ref('')
-
+// 复制文本
+const copy = (text: string) => {
+    uni.setClipboardData({
+        data: text,
+        success: function () {
+            uni.showToast({
+                title: t('Btn.item8'),
+                icon: 'none',
+                duration: 2000
+            });
+        }
+    });
+};
 // 初始化菜单
 function initMenu() {
     menuList.value = [

+ 37 - 29
pages/analytics/detail.vue

@@ -39,7 +39,7 @@
             <view class="content crm-border-radius" v-if="type === 7">
                 <text class="con-title">{{ info.subject }}</text>
                 <view class="rich-text-wrapper">
-                    <cwg-rich-text :nodes="info.content" />
+                    <cwg-rich-text :nodes="info.content1" />
                 </view>
             </view>
 
@@ -85,6 +85,7 @@ import { onLoad } from '@dcloudio/uni-app'
 import { useI18n } from 'vue-i18n'
 import { newsApi } from '@/service/news'
 import Config from '@/config/index'
+import { adaptCWGEmailForUniApp } from '@/utils/emailAdapter.js';
 
 const { t } = useI18n()
 const { Code, Host80, Host05 } = Config
@@ -154,7 +155,7 @@ const getNewsSingle = async () => {
         case 7: // 通知
             const noticeRes = await newsApi.newsNoticeSingle({ id: id.value })
             if (noticeRes.code === Code.StatusOK && noticeRes.data) {
-                info.value = noticeRes.data
+                info.value = { ...noticeRes.data, content1: adaptCWGEmailForUniApp(noticeRes.data.content) }
                 uni.$emit('open-notice')
             } else {
                 uni.showToast({ title: noticeRes.msg, icon: 'none' })
@@ -241,6 +242,7 @@ onUnmounted(() => {
 </script>
 
 <style lang="scss" scoped>
+@import "@/uni.scss";
 #News_Content {
     height: 100%;
 
@@ -248,12 +250,13 @@ onUnmounted(() => {
         display: flex;
         justify-content: space-between;
         align-items: center;
-        padding: 10rpx 15rpx;
+        padding: px2rpx(10);
+        box-sizing: border-box;
         background-color: #fff;
         border-bottom: 1px solid #eee;
 
         .tit {
-            font-size: 16rpx;
+            font-size: px2rpx(16);
             font-weight: bold;
         }
 
@@ -262,8 +265,8 @@ onUnmounted(() => {
             align-items: center;
 
             .icon-back {
-                font-size: 18rpx;
-                margin-right: 4rpx;
+                font-size: px2rpx(18);
+                margin-right: px2rpx(4);
             }
         }
     }
@@ -274,12 +277,16 @@ onUnmounted(() => {
         background-color: #fff;
         overflow: hidden;
         text-align: left;
-        padding: 10rpx 15rpx;
+        padding: px2rpx(10);
         box-sizing: border-box;
         line-height: 1.8;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+
 
         .img {
-            margin-bottom: 10rpx;
+            margin-bottom: px2rpx(10);
 
             image {
                 width: 100%;
@@ -287,31 +294,32 @@ onUnmounted(() => {
         }
 
         .con-title {
-            font-size: 18rpx;
+            font-size: px2rpx(18);
             font-weight: bold;
-            margin: 10rpx 0;
+            margin: px2rpx(10) 0;
+            text-align: center;
         }
 
         .con-time {
-            margin-bottom: 10rpx;
-            font-size: 12rpx;
+            margin-bottom: px2rpx(10);
+            font-size: px2rpx(12);
             color: #999;
         }
 
         .con-des {
-            margin: 10rpx 0;
-            font-size: 14rpx;
+            margin: px2rpx(10) 0;
+            font-size: px2rpx(14);
         }
 
         .video-player {
             width: 100%;
-            height: 400rpx;
+            height: px2rpx(400);
         }
 
         .webview {
             width: 100%;
             height: 100%;
-            min-height: 1200rpx;
+            min-height: px2rpx(1200);
         }
 
         .ebookBox {
@@ -325,10 +333,10 @@ onUnmounted(() => {
 
             .ebook-cover {
                 width: 100%;
-                max-width: 360rpx;
+                max-width: px2rpx(360);
                 height: auto;
                 margin-right: 0;
-                margin-bottom: 15rpx;
+                margin-bottom: px2rpx(15);
 
                 @media (min-width: 768px) {
                     margin-right: 25rpx;
@@ -338,20 +346,20 @@ onUnmounted(() => {
 
             .news-title {
                 color: #EB3F57;
-                font-size: 44rpx;
+                font-size: px2rpx(44);
                 font-weight: bold;
-                margin-bottom: 10rpx;
+                margin-bottom: px2rpx(10);
             }
 
             .news-status {
-                margin-top: 10rpx;
+                margin-top: px2rpx(10);
 
                 a {
                     display: inline-block;
                     background-color: #EB3F57;
                     color: #fff;
-                    padding: 8rpx 30rpx;
-                    border-radius: 8rpx;
+                    padding: px2rpx(4) px2rpx(30);
+                    border-radius: px2rpx(8);
                     font-weight: bold;
                 }
             }
@@ -364,13 +372,13 @@ onUnmounted(() => {
     table {
         border-collapse: collapse !important;
         width: 100% !important;
-        margin: 10px 0 !important;
+        margin: px2rpx(10) 0 !important;
     }
 
     th,
     td {
         border: 1px solid #dcdfe6 !important;
-        padding: 8px !important;
+        padding: px2rpx(8) !important;
         text-align: left !important;
     }
 
@@ -396,8 +404,8 @@ onUnmounted(() => {
 <style>
 /* 覆盖 rich-text 内所有段落样式 */
 uni-rich-text p {
-    margin: 12rpx 0 !important;
-    font-size: 14rpx !important;
+    margin: px2rpx(12) 0 !important;
+    font-size: px2rpx(14) !important;
     /* 对应 14px */
     line-height: 1.6 !important;
     color: #333;
@@ -405,13 +413,13 @@ uni-rich-text p {
 
 /* 覆盖 span 样式,移除固定字体和大小 */
 uni-rich-text span {
-    font-size: 14rpx !important;
+    font-size: px2rpx(14) !important;
     font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
 }
 
 /* 图片自适应 */
 uni-rich-text img {
     max-width: 100% !important;
-    height: auto !important;
+    height: auto;
 }
 </style>

+ 7 - 43
pages/common/download.vue

@@ -50,7 +50,7 @@
                         </view>
                         <view class="download-cards">
                             <cwg-link type="html" class="download-card download-card-web" target="_blank"
-                                :url="'https://www.' + config.host + '.com/' + locale + '/mt4/web'">
+                                :url="'https://www.' + config.host + '.com/' + locale + '/vu-mt4-web-trading/web'">
                                 <view class="card-info">
                                     <view class="card-title" v-t="'Downloadpage.item40'" />
                                 </view>
@@ -75,23 +75,11 @@
                                 <view class="qr-codes">
                                     <view class="qr-item">
                                         <view class="qr-label">Google Play</view>
-										// #ifdef H5
-										<QrCode v-if="showQrcode && mt41" :key="mt41" :text="mt41"></QrCode>
-										// #endif
-										// #ifdef APP-PLUS
-                                        <image class="mt" src="/static/images/mt/mt41.png" alt=""
-                                            mode="widthFix" />
-										// #endif
+										<QrCode :text="mt41"></QrCode>
                                     </view>
                                     <view class="qr-item">
                                         <view class="qr-label">MetaTrader .Apk</view>
-										// #ifdef H5
-										<QrCode v-if="showQrcode && mt42" :key="mt41" :text="mt42"></QrCode>
-										// #endif
-										// #ifdef APP-PLUS
-                                        <image class="mt" src="/static/images/mt/mt42.png" alt=""
-                                            mode="widthFix" />
-										// #endif
+										<QrCode :text="mt42"></QrCode>
                                     </view>
                                 </view>
                             </view>
@@ -107,13 +95,7 @@
                                 <view class="qr-codes qr-codes-single">
                                     <view class="qr-item">
                                         <view class="qr-label">App Store</view>
-										// #ifdef H5
-										<QrCode v-if="showQrcode && mt43" :key="mt43" :text="mt43"></QrCode>
-										// #endif
-										// #ifdef APP-PLUS
-                                        <image class="mt" src="/static/images/mt/mt43.png" alt=""
-                                            mode="widthFix" />
-										// #endif
+										<QrCode :text="mt43"></QrCode>
                                     </view>
                                 </view>
                             </view>
@@ -192,23 +174,11 @@
                                 <view class="qr-codes">
                                     <view class="qr-item">
                                         <view class="qr-label">Google Play</view>
-										// #ifdef H5
-										<QrCode v-if="showQrcode && mt51" :key="mt51" :text="mt51"></QrCode>
-										// #endif
-										// #ifdef APP-PLUS
-                                        <image class="mt" src="/static/images/mt/mt51.png" alt=""
-                                            mode="widthFix" />
-										// #endif
+										<QrCode :text="mt51"></QrCode>
                                     </view>
                                     <view class="qr-item">
                                         <view class="qr-label">MetaTrader .Apk</view>
-										// #ifdef H5
-										<QrCode v-if="showQrcode && mt52" :key="mt52" :text="mt52"></QrCode>
-										// #endif
-										// #ifdef APP-PLUS
-                                        <image class="mt" src="/static/images/mt/mt52.png" alt=""
-                                            mode="widthFix" />
-										// #endif
+										<QrCode :text="mt52"></QrCode>
                                     </view>
                                 </view>
                             </view>
@@ -224,13 +194,7 @@
                                 <view class="qr-codes qr-codes-single">
                                     <view class="qr-item">
                                         <view class="qr-label">App Store</view>
-										// #ifdef H5
-										<QrCode v-if="showQrcode && mt53" :key="mt53" :text="mt53"></QrCode>
-										// #endif
-										// #ifdef APP-PLUS
-                                        <image class="mt" src="/static/images/mt/mt53.png" alt=""
-                                            mode="widthFix" />
-										// #endif
+										<QrCode :text="mt53"></QrCode>
                                     </view>
                                 </view>
                             </view>

+ 2 - 1
pages/customer/components/TerminalDialog.vue

@@ -169,7 +169,8 @@ const handleWebClick = () => {
     })
     // #endif
     // #ifdef H5
-    window.location.href = webUrl.value
+    window.open(webUrl.value, '_blank')
+
     // #endif
 }
 

+ 1 - 1
pages/customer/composables/TerminalMap.ts

@@ -28,7 +28,7 @@ export const TerminalMap = {
             ]
         },
         "web": {
-            "url": "https://www.{domain}.com/{lang}/mt4/web",
+            "url": "https://www.{domain}.com/{lang}/vu-mt4-web-trading/web",
             "descriptionKey": "Downloadpage.item40"
         },
         "mobile": {

+ 23 - 1
pages/customer/transfer.vue

@@ -102,9 +102,11 @@
             <!-- 等待弹窗 -->
             <cwg-wait-popup v-model:visible="dialogCheckWait" type="center" :mask-click="false" :showFooters="false" />
         </view>
+        <cwg-confirm-popup />
     </cwg-page-wrapper>
 </template>
 
+
 <script setup>
 import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue'
 import { useI18n } from 'vue-i18n'
@@ -121,7 +123,8 @@ const customInfo = computed(() => {
     return userStore?.userInfo?.customInfo || {}
 })
 import Config from '@/config/index'
-
+import { useConfirm } from '@/hooks/useConfirm'
+const confirm = useConfirm()
 const { Code } = Config
 const { t } = useI18n()
 
@@ -465,6 +468,24 @@ function handleRouteParams() {
 
     updateToOptions()
 }
+const showCentAccountTransferTip = (login) => {
+    const selectedAccount = loginOptions.value.find(
+        (item) => item.login == login,
+    );
+    if (!selectedAccount) {
+        return;
+    }
+    const isCentAccount =
+        selectedAccount.type == "8" || selectedAccount.currency === "USC";
+    if (isCentAccount) {
+        confirm({
+            title: t("Msg.SystemPrompt"),
+            content: t("vu.item14") + t("vu.item15") + t("vu.item16"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+    }
+}
 onMounted(() => {
     getDateList()
     getAmount()
@@ -490,6 +511,7 @@ watch(loginValue, (newVal) => {
         form.depositLogin = null
         form.amount = ''
         amountErrorMessage.value = ''
+        showCentAccountTransferTip(newVal)
         toOptions.value = []
         if (transferType.value === 'internal') {
             // 内部转账逻辑

+ 23 - 2
pages/ib/agent-transfer.vue

@@ -159,9 +159,11 @@
             <BonusAgreementPopup v-model:visible="dialogClauseNewList" :title="tableDataNewList.title"
                 :content="tableDataNewList.content" type="newList" />
         </view>
+        <cwg-confirm-popup />
     </cwg-page-wrapper>
 </template>
 
+
 <script setup>
 import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue'
 import { useI18n } from 'vue-i18n'
@@ -173,7 +175,8 @@ import { financialApi } from '@/service/financial'
 import Config from '@/config/index'
 import useUserStore from '@/stores/use-user-store'
 import BonusAgreementPopup from './components/BonusAgreementPopup.vue'
-
+import { useConfirm } from '@/hooks/useConfirm'
+const confirm = useConfirm()
 const userStore = useUserStore()
 const ibInfo = computed(() => {
     return userStore?.userInfo?.ibInfo || {}
@@ -559,12 +562,30 @@ async function getActivityExtensionGiveLoginJoin() {
         giveLoginJoin.value = ''
     }
 }
-
+const showCentAccountTransferTip = (login) => {
+    const selectedAccount = loginOptions.value.find(
+        (item) => item.login == login,
+    );
+    if (!selectedAccount) {
+        return;
+    }
+    const isCentAccount =
+        selectedAccount.type == "8" || selectedAccount.currency === "USC";
+    if (isCentAccount) {
+        confirm({
+            title: t("Msg.SystemPrompt"),
+            content: t("vu.item14") + t("vu.item15") + t("vu.item16"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+    }
+}
 // 监听 loginValue 变化
 watch(loginValue, (newVal) => {
     if (newVal != null) {
         step2.value = true
         form.withdrawLogin = Number(newVal)
+        showCentAccountTransferTip(newVal)
         form.depositLogin = null
         form.depositLogin1 = null
         form.amount = ''

+ 127 - 0
utils/emailAdapter.js

@@ -0,0 +1,127 @@
+/**
+ * UniApp APP 邮件模板适配器
+ * 适用于 cwg-rich-text 组件展示邮件内容
+ * rich-text组件对HTML支持有限,需要简化处理
+ * @param {string} html - 原始邮件HTML字符串
+ * @returns {string} - 适配后的HTML字符串
+ */
+export function adaptCWGEmailForUniApp(html) {
+  if (!html || typeof html !== 'string') return '';
+
+  let result = html;
+
+  // ==============================================
+  // 1. 【修复HTML语法错误】处理不规范的标签
+  // ==============================================
+  // 修复 <img ... / style="..."> 的问题 - 移除斜杠后的空格
+  result = result.replace(/<img([^>]*?)\s*\/\s*style=/gi, '<img$1 style=');
+
+  // ==============================================
+  // 2. 【宽度适配】修复640px固定宽度导致的横向滚动问题
+  // ==============================================
+  // 将最外层的width:640px改为100%
+  result = result.replace(/<div\s+style="([^"]*?)width:\s*640px([^"]*?)"/gi, function (_, before, after) {
+    return `<div style="${before}width:100%;max-width:640px;margin:0 auto;${after}"`;
+  });
+
+  // 处理内联样式中的width:640px
+  result = result.replace(/width:\s*640px/gi, 'width:100%;max-width:640px');
+
+  // ==============================================
+  // 3. 【图片响应式】确保所有图片自适应
+  // ==============================================
+  result = result.replace(/<img([^>]*?)>/gi, function (match, attrs) {
+    // 提取现有样式
+    const styleMatch = attrs.match(/style=["']([^"']*)["']/i);
+    let existingStyle = styleMatch ? styleMatch[1] : '';
+
+    // 添加响应式样式
+    let newStyle = existingStyle;
+
+    // 确保样式末尾有分号
+    if (newStyle && !newStyle.endsWith(';')) {
+      newStyle += ';';
+    }
+
+    // 添加缺失的样式
+    if (!existingStyle.includes('max-width')) {
+      newStyle += 'max-width:100%;';
+    }
+    if (!existingStyle.includes('height:')) {
+      newStyle += 'height:auto;';
+    }
+    if (!existingStyle.includes('display:')) {
+      newStyle += 'display:block;';
+    }
+
+    // 移除多余的分号
+    newStyle = newStyle.replace(/;;+/g, ';');
+
+    if (styleMatch) {
+      return match.replace(/style=["']([^"']*)["']/i, `style="${newStyle}"`);
+    } else {
+      // 确保标签正确闭合
+      if (attrs.trim().endsWith('/')) {
+        return `<img${attrs.replace(/\s*\/$/, '')} style="${newStyle}" />`;
+      } else {
+        return `<img${attrs} style="${newStyle}" />`;
+      }
+    }
+  });
+
+  // ==============================================
+  // 4. 【容器适配】移除大尺寸固定宽度限制
+  // ==============================================
+  result = result.replace(/style="([^"]*?)width:\s*(\d+)px([^"]*?)"/gi, function (match, before, width, after) {
+    // 保留小尺寸的宽度(如logo等),只处理大尺寸
+    if (parseInt(width) > 200) {
+      let newStyle = `${before}width:100%;max-width:${width}px;${after}`;
+      newStyle = newStyle.replace(/;;+/g, ';');
+      return `style="${newStyle}"`;
+    }
+    return match;
+  });
+
+  // ==============================================
+  // 5. 【清理多余分号】修复样式中的双分号问题
+  // ==============================================
+  result = result.replace(/style="([^"]*)"/gi, function (_, style) {
+    return `style="${style.replace(/;;+/g, ';').replace(/;$/, '')}"`;
+  });
+
+  // ==============================================
+  // 6. 【修复特殊字符】处理HTML实体
+  // ==============================================
+  result = result.replace(/&rsquo;/g, "'");
+  result = result.replace(/&nbsp;/g, ' ');
+  result = result.replace(/&amp;/g, '&');
+
+  // ==============================================
+  // 7. 【移除script/style标签】rich-text不支持
+  // ==============================================
+  result = result.replace(/<script[\s\S]*?<\/script>/gi, '');
+  result = result.replace(/<style[\s\S]*?<\/style>/gi, '');
+
+  // ==============================================
+  // 8. 【简化标签】移除rich-text不支持的标签
+  // ==============================================
+  // 移除HTML文档结构标签
+  result = result.replace(/<\/?html[^>]*>/gi, '');
+  result = result.replace(/<\/?head[^>]*>/gi, '');
+  result = result.replace(/<\/?body[^>]*>/gi, '');
+  result = result.replace(/<meta[^>]*>/gi, '');
+  result = result.replace(/<!DOCTYPE[^>]*>/gi, '');
+
+  // ==============================================
+  // 9. 【添加内联样式包装】确保容器不溢出
+  // ==============================================
+  result = `
+    <div style="width:100%;max-width:640px;margin:0 auto;background:#fff;border-radius:8px;overflow:hidden;">
+      <div style="padding:8px;">
+        ${result}
+      </div>
+    </div>
+  `;
+
+  return result;
+}