zhb 3 miesięcy temu
rodzic
commit
529a5f092f

+ 19 - 11
components/QrCode.vue

@@ -153,18 +153,26 @@ function drawLogo(ctx) {
     ctx.setFillStyle('#ffffff')
     ctx.fillRect(dx, dy, logoSize, logoSize)
 
-    // 在真机上,确保图片已加载再绘制
-    const img = new Image()
-    img.src = props.logo
-    img.onload = () => {
-        ctx.drawImage(props.logo, dx, dy, logoSize, logoSize)
-        ctx.draw(true)
-    }
-    img.onerror = () => {
-        console.error('Logo图片加载失败:', props.logo)
-    }
+    // #ifdef H5
+    // H5端可直接用图片url
+    ctx.drawImage(props.logo, dx, dy, logoSize, logoSize)
+    ctx.draw(true)
+    // #endif
+
+    // #ifndef H5
+    // 小程序/APP端需先下载图片到本地再绘制
+    uni.getImageInfo({
+        src: props.logo,
+        success(res) {
+            ctx.drawImage(res.path, dx, dy, logoSize, logoSize)
+            ctx.draw(true)
+        },
+        fail() {
+            console.error('Logo图片加载失败:', props.logo)
+        }
+    })
+    // #endif
 }
-
 /** 下载二维码 */
 function download() {
     uni.canvasToTempFilePath({

+ 59 - 0
components/cwg-match-media.vue

@@ -0,0 +1,59 @@
+<template>
+    <!-- #ifdef H5 -->
+    <view>
+        <match-media v-bind="mediaAttrs">
+            <slot />
+        </match-media>
+    </view>
+    <!-- #endif -->
+    <!-- #ifdef APP-PLUS -->
+    <view v-if="shouldShow">
+        <slot />
+    </view>
+    <!-- #endif -->
+</template>
+
+<script setup lang="ts">
+import { ref, computed, onMounted, onUnmounted } from 'vue';
+
+const props = defineProps({
+    minWidth: {
+        type: Number,
+        default: undefined
+    },
+    maxWidth: {
+        type: Number,
+        default: undefined
+    }
+})
+
+const shouldShow = ref(true)
+
+const mediaAttrs = computed(() => {
+    const attrs: Record<string, number> = {};
+    if (props.minWidth !== undefined) attrs['min-width'] = props.minWidth;
+    if (props.maxWidth !== undefined) attrs['max-width'] = props.maxWidth;
+    return attrs;
+	
+})
+
+function checkWidth() {
+    const width = uni.getSystemInfoSync().windowWidth
+    shouldShow.value = (props.minWidth === undefined || width >= props.minWidth) && (props.maxWidth === undefined || width <= props.maxWidth)
+}
+// #ifdef APP-PLUS
+checkWidth()
+let resizeListener: any
+onMounted(() => {
+    resizeListener = () => checkWidth()
+    uni.onWindowResize && uni.onWindowResize(resizeListener)
+})
+onUnmounted(() => {
+    uni.offWindowResize && uni.offWindowResize(resizeListener)
+})
+// #endif
+</script>
+
+<style lang="scss" scoped>
+@import "@/uni.scss";
+</style>

+ 18 - 22
components/cwg-page-wrapper.vue

@@ -1,34 +1,36 @@
 <template>
-  <view class="page-wrapper">
-    <match-media :min-width="991" v-if="!isLoginPage">
+  <view :class="['page-wrapper', { dark: isDark }]">
+    <cwg-match-media :min-width="991" v-if="!isLoginPage">
       <view class="left-sidebar">
         <cwg-sidebar />
-        <cwg-submenu v-if="sidebarVisible" :items="submenuItems" @submenu-click="onSubmenuClick" />
+        <cwg-submenu v-if="sidebarVisible" @submenu-click="onSubmenuClick" />
       </view>
-    </match-media>
+    </cwg-match-media>
     <cwg-progress />
     <view class="page-content">
-      <match-media :min-width="991" v-if="!isLoginPage">
+      <cwg-match-media :min-width="991" v-if="!isLoginPage">
         <cwg-pc-header @toggle-sidebar="toggleSidebar" />
-      </match-media>
-      <match-media :max-width="991">
+      </cwg-match-media>
+      <cwg-match-media :max-width="991">
         <cwg-header v-if="!isHeaderFixed" />
-      </match-media>
+      </cwg-match-media>
       <view class="content-wrapper">
         <slot />
       </view>
       <view :style="{ height: isTabBarPage ? '60px' : '0px' }" />
     </view>
-    <match-media :max-width="991">
+    <cwg-match-media :max-width="991">
       <cwg-tab-bar v-model:isTabBarPage="isTabBarPage" />
-    </match-media>
+    </cwg-match-media>
   </view>
 </template>
 
 <script setup lang="ts">
-import { ref } from "vue";
+import { ref, watch, computed } from "vue";
 import { onLoad, onShow } from '@dcloudio/uni-app'
 import { updateRoute } from '@/hooks/useRoute'
+import useGlobalStore from '@/stores/use-global-store'
+const globalStore = useGlobalStore()
 interface MenuItem {
   key: string;
   label: string;
@@ -37,27 +39,21 @@ interface MenuItem {
 }
 
 const props = defineProps({
+  // 是否固定顶部导航栏
   isHeaderFixed: {
     type: Boolean,
     default: false
   },
+  // 是否登录页,登录页不显示侧边栏和顶部导航,注册忘记密码等页面
   isLoginPage: {
     type: Boolean,
     default: false
   }
 })
+const isDark = computed(() => globalStore.theme === 'dark')
 const isTabBarPage = ref(false)
-const submenuItems = ref<MenuItem[]>([{ key: 'client', label: 'Client Zone', icon: 'icon-client' },
-{ key: 'promotion', label: 'Promotion Center', icon: 'icon-promotion' },
-{ key: 'deposit', label: 'Deposit', icon: 'icon-deposit' },
-{ key: 'withdrawal', label: 'Withdrawal', icon: 'icon-withdrawal' },
-{ key: 'payment', label: 'Payment History', icon: 'icon-payment' },
-{ key: 'transfer', label: 'Internal Transfer', icon: 'icon-transfer' },
-{ key: 'application', label: 'Application History', icon: 'icon-application' },
-{ key: 'ib', label: 'IB Zone', icon: 'icon-ib' },
-{ key: 'copy', label: 'Copy Trading', icon: 'icon-copy' },
-{ key: 'platform', label: 'Trading Platform', icon: 'icon-platform' },
-{ key: 'chat', label: 'Online Chat', icon: 'icon-chat' },])
+
+
 const sidebarVisible = ref(true)
 
 function toggleSidebar() {

+ 26 - 13
components/cwg-pc-header.vue

@@ -1,29 +1,42 @@
 <template>
     <header class="cwg-pc-header">
         <div class="left">
-            <span class="back-arrow" @click="$emit('toggle-sidebar')">&#8592;</span>
+            <text class="back-arrow" @click="$emit('toggle-sidebar')">&#8592;</text>
         </div>
         <div class="center"></div>
         <div class="right">
             <div class="lang-select">
-                <img src="/static/flag-en.png" alt="en" class="flag" />
-                <span>English</span>
-                <span class="arrow">▼</span>
+                <image class="img flag" src="/static/flag-en.png" alt="en" />
+                <text>English</text>
+                <text class="arrow">▼</text>
             </div>
-            <span class="icon sun">🌞</span>
-            <span class="icon bell">🔔<span class="dot"></span></span>
-            <span class="icon avatar"><img src="/static/avatar.png" alt="avatar" /></span>
-            <span class="icon logo"><img src="/static/logo.png" alt="logo" /></span>
+            <text class="icon sun" @click="toggleTheme">🌞</text>
+            <text class="icon bell">🔔<text class="dot"></text></text>
+            <text class="icon avatar">
+                <image class="img" src="/static/avatar.png" alt="avatar" />
+            </text>
+            <text class="icon logo" @click="goUserInfo">
+                <image class="img" src="/static/logo.png" alt="logo" />
+            </text>
         </div>
     </header>
 </template>
 
 <script setup lang="ts">
-// 可根据需要添加交互逻辑
-// 通过 $emit('toggle-sidebar') 触发父组件事件
+import useGlobalStore from '@/stores/use-global-store'
+const globalStore = useGlobalStore()
+import useRouter from "@/hooks/useRouter";
+const router = useRouter();
+function toggleTheme() {
+    globalStore.setGlobalTheme(globalStore.theme === 'light' ? 'dark' : 'light');
+}
+
+function goUserInfo() {
+    router.push('/pages/mine/info')
+}
 </script>
 
-<style scoped>
+<style scoped lang="scss">
 .cwg-pc-header {
     display: flex;
     align-items: center;
@@ -96,14 +109,14 @@
     display: inline-block;
 }
 
-.avatar img {
+.avatar .img {
     width: 32px;
     height: 32px;
     border-radius: 50%;
     background: #eee;
 }
 
-.logo img {
+.logo .img {
     width: 36px;
     height: 36px;
     border-radius: 50%;

+ 3 - 4
components/cwg-sidebar.vue

@@ -11,24 +11,23 @@
 
 <script lang="ts" setup>
 import { ref } from 'vue';
+import useRouter from "@/hooks/useRouter";
+const router = useRouter();
 interface MenuItem {
     key: string;
     label: string;
     icon?: string;
     children?: MenuItem[];
 }
-
 const emit = defineEmits(['menu-click']);
-
 const menu = ref<MenuItem[]>([
     { key: 'client', label: 'Client Zone', icon: 'icon-client' },
     { key: 'promotion', label: 'Promotion Center', icon: 'icon-promotion' },
     { key: 'deposit', label: 'Deposit', icon: 'icon-deposit' },
     { key: 'withdrawal', label: 'Withdrawal', icon: 'icon-withdrawal' },
 ]);
-
 function handleClick(item: MenuItem) {
-    emit('menu-click', item);
+    router.push(item.key);
 }
 </script>
 

+ 23 - 13
components/cwg-submenu.vue

@@ -6,7 +6,7 @@
             </text>
         </view>
         <view class="submenu">
-            <view class="cwg-submenu-item" v-for="item in items" :key="item.key" @click="handleClick(item)">
+            <view class="cwg-submenu-item" v-for="item in submenuItems" :key="item.key" @click="handleClick(item)">
                 <text>{{ item.label }}</text>
             </view>
         </view>
@@ -14,16 +14,30 @@
 </template>
 
 <script lang="ts" setup>
+import { ref } from 'vue';
+import useRouter from "@/hooks/useRouter";
+const router = useRouter();
 interface MenuItem {
     key: string;
     label: string;
     icon?: string;
     children?: MenuItem[];
 }
-const props = defineProps<{ items: MenuItem[] }>();
+
+const submenuItems = ref<MenuItem[]>([{ key: 'client', label: 'Client Zone', icon: 'icon-client' },
+{ key: 'promotion', label: 'Promotion Center', icon: 'icon-promotion' },
+{ key: 'deposit', label: 'Deposit', icon: 'icon-deposit' },
+{ key: 'withdrawal', label: 'Withdrawal', icon: 'icon-withdrawal' },
+{ key: 'payment', label: 'Payment History', icon: 'icon-payment' },
+{ key: 'transfer', label: 'Internal Transfer', icon: 'icon-transfer' },
+{ key: 'application', label: 'Application History', icon: 'icon-application' },
+{ key: 'ib', label: 'IB Zone', icon: 'icon-ib' },
+{ key: 'copy', label: 'Copy Trading', icon: 'icon-copy' },
+{ key: 'platform', label: 'Trading Platform', icon: 'icon-platform' },
+{ key: 'chat', label: 'Online Chat', icon: 'icon-chat' },])
 const emit = defineEmits(['submenu-click']);
 function handleClick(item: MenuItem) {
-    emit('submenu-click', item);
+    router.push(item.key);
 }
 </script>
 
@@ -37,12 +51,12 @@ function handleClick(item: MenuItem) {
 
     padding: 0;
     margin: 0;
-    box-shadow: 4px 0 12px rgba(15, 23, 43, 0.08);
+    box-shadow: px2rpx(4) 0 px2rpx(12) rgba(15, 23, 43, 0.08);
     border-left: 1px solid #E2E8F0;
 
     .cwg-submenu-title {
-        padding: 20px;
-        font-size: 16px;
+        padding: px2rpx(20);
+        font-size: px2rpx(16);
         font-weight: 700;
         border-bottom: 1px solid #E2E8F0;
         color: #0F172B;
@@ -54,20 +68,16 @@ function handleClick(item: MenuItem) {
     }
 
     .cwg-submenu-item {
-        padding: 20px 0px;
+        padding: px2rpx(20) 0px;
         cursor: pointer;
         color: #0F172B;
         font-weight: 600;
         transition: background 0.2s;
         display: flex;
         align-items: center;
-        gap: 10px;
-        font-size: 14px;
+        gap: px2rpx(10);
+        font-size: px2rpx(14);
         border-bottom: 1px solid #E2E8F0;
     }
-
-    .cwg-submenu-item:hover {
-        // background: #f0f0f0;
-    }
 }
 </style>

+ 6 - 0
config/index.ts

@@ -1,7 +1,13 @@
+// #ifdef H5
 let ht = window.location.protocol;
 let ho = window.location.host.split('.')[1];
 ht = ht == 'http:' ? 'https:' : ht;
 ho = ho == '168' ? '44a5c8109e4' : ho;
+// #else
+let ht = 'https:';
+let ho = '44a5c8109e4'; // 默认主域名或可根据实际APP环境配置
+// #endif
+
 const config = {
 
   HostWs: "wss://ws." + ho + ".com",

+ 0 - 1
pages/apply-record/components/ApplyRecord.vue

@@ -170,7 +170,6 @@ import { useI18n } from "vue-i18n";
 import useCardStore from "@/stores/use-card-store";
 import QrCode from "@/components/QrCode.vue";
 import { ucardApi } from "@/api/ucard";
-import { Image } from "vant";
 
 const props = defineProps({
   id: String,

+ 2 - 1
pages/mine/index.vue

@@ -167,7 +167,8 @@ onMounted(() => {
 	}
 
 	.phone {
-		color: #1a1a1a;
+		// 1a1a1a
+		color: var(--primary-color);
 		font-family: Roboto;
 		font-size: px2rpx(22);
 		font-style: normal;

+ 36 - 0
static/scss/global/global.scss

@@ -5,6 +5,10 @@
 }
 
 :root {
+    --primary-color: #ea002a;
+    --success-color: #4CD964;
+    --warning-color: #F0AD4E;
+    --error-color: #DD524D;
     --main-bg: #fff;
     --card-bg: #222;
     --action-bg: #fff;
@@ -33,6 +37,38 @@
     --font-size-40: px2rpx(40);
 }
 
+.dark {
+    --primary-color: #1a1a1a;
+    --success-color: #4CD964;
+    --warning-color: #F0AD4E;
+    --error-color: #DD524D;
+    --main-bg: #181a1b;
+    --card-bg: #222;
+    --action-bg: #232323;
+    --main-yellow: #ea002a;
+    --main-yellow-dark: rgb(15 120 71);
+    --white: #fff;
+    --lable: #aaa;
+    --gray: #aaa;
+    --border: #333;
+    --black: #000;
+    --font-size-10: 10px;
+    --font-size-12: 12px;
+    --font-size-13: 13px;
+    --font-size-14: 14px;
+    --font-size-15: 15px;
+    --font-size-16: 16px;
+    --font-size-18: 18px;
+    --font-size-20: 20px;
+    --font-size-22: 22px;
+    --font-size-24: 24px;
+    --font-size-26: 26px;
+    --font-size-28: 28px;
+    --font-size-32: 32px;
+    --font-size-36: 36px;
+    --font-size-40: 40px;
+}
+
 
 body {
     min-height: 100vh;

+ 2 - 3
stores/use-global-store.ts

@@ -8,9 +8,8 @@ const useStore = defineStore("globalStore", () => {
     requestLoading: false,
     fullScreenLoading: false,
     isPageSwitching: false,
-    theme: "light",
-    statusBarHeight: 0
-    // theme: 'dark',
+    statusBarHeight: 0,
+    theme: "light"
   });
 
   const setGlobalTheme = (payload: string) => {