zhb 1 月之前
父節點
當前提交
95901c375c

+ 72 - 54
components/cwg-confirm-popup.vue

@@ -1,79 +1,97 @@
 <template>
-    <cwg-popup v-model:visible="visible" type="center" :mask-click="false" :show-footers="true">
-        <view class="popup-content">
-            <view class="confirm-title">{{ title }}</view>
-            <view class="confirm-content">{{ content }}</view>
-        </view>
-        <template #footer>
-            <button @click="cancel">{{ cancelText }}</button>
-            <button type="primary" @click="confirm">{{ confirmText }}</button>
-        </template>
-    </cwg-popup>
+  <cwg-popup v-model:visible="visible" type="center" :mask-click="false" :show-footers="true">
+    <view class="popup-content">
+      <view class="confirm-title">{{ title }}</view>
+      <view class="confirm-content">{{ content }}</view>
+    </view>
+    <template #footer>
+      <button @click="handleCancel">{{ cancelText }}</button>
+      <button type="primary" @click="handleConfirm">{{ confirmText }}</button>
+    </template>
+  </cwg-popup>
 </template>
+
 <script setup>
-import { ref, onMounted, onUnmounted, watch, computed } from 'vue'
-import { useI18n } from 'vue-i18n';
-const { t } = useI18n();
-const title = ref(t('Msg.SystemPrompt'))
-const content = ref('')
-const confirmText = ref(t('Btn.Confirm'))
-const cancelText = ref(t('Btn.Cancel'))
+import { ref, onMounted, onUnmounted } from 'vue'
+import { useI18n } from 'vue-i18n'
+const { t } = useI18n()
+
+const visible = ref(false)
 let currentEventId = null
+let isShowing = false // 单例锁,永远只弹一个
 
+const title = ref('')
+const content = ref('')
+const confirmText = ref('')
+const cancelText = ref('')
+
+// 显示弹窗
 const handleShowConfirm = (options) => {
-    title.value = options.title || title.value
-    content.value = options.content || ''
-    confirmText.value = options.confirmText || t('Btn.Confirm')
-    cancelText.value = options.cancelText || t('Btn.Cancel')
-    currentEventId = options.eventId
-    visible.value = true
+  if (isShowing || visible.value) return
+
+  isShowing = true
+  currentEventId = options.eventId
+
+  title.value = options.title || t('Msg.SystemPrompt')
+  content.value = options.content || ''
+  confirmText.value = options.confirmText || t('Btn.Confirm')
+  cancelText.value = options.cancelText || t('Btn.Cancel')
+
+  visible.value = true
 }
 
-const closeAndResult = (result) => {
-    visible.value = false
-    if (currentEventId) {
-        uni.$emit(`confirmResult_${currentEventId}`, result)
-        currentEventId = null
-    }
+// 关闭并返回结果 + 强制清空所有状态
+const close = (result) => {
+  visible.value = false
+  isShowing = false
+
+  if (currentEventId) {
+    uni.$emit(`confirmResult_${currentEventId}`, result)
+  }
+
+  // 🔥 强制清空,永不残留
+  currentEventId = null
+  title.value = ''
+  content.value = ''
+  confirmText.value = ''
+  cancelText.value = ''
 }
 
-const confirm = () => closeAndResult(true)
-const cancel = () => closeAndResult(false)
+const handleConfirm = () => close(true)
+const handleCancel = () => close(false)
 
 onMounted(() => {
-    uni.$on('showConfirm', handleShowConfirm)
+  uni.$on('showConfirm', handleShowConfirm)
 })
+
 onUnmounted(() => {
-    uni.$off('showConfirm', handleShowConfirm)
-})
-const visible = ref(false)
-watch(visible, (value) => {
-    if (!value) closeAndResult(false)
+  uni.$off('showConfirm', handleShowConfirm)
+  visible.value = false
+  isShowing = false
+  currentEventId = null
 })
 </script>
 
 <style scoped lang="scss">
 @import "@/uni.scss";
 :deep(.cwg-dialog) {
-    width: px2rpx(500);
-    background-color: #fff;
-    border-radius: px2rpx(16);
-    text-align: center;
-    box-shadow: 0 px2rpx(10) px2rpx(20) rgba(0, 0, 0, 0.1);
+  width: px2rpx(500);
+  background-color: #fff;
+  border-radius: px2rpx(16);
+  text-align: center;
+  box-shadow: 0 px2rpx(10) px2rpx(20) rgba(0, 0, 0, 0.1);
 }
 .confirm-title {
-    font-size: px2rpx(24);
-    font-weight: 600;
-    color: #333;
-    margin-bottom: px2rpx(30);
+  font-size: px2rpx(24);
+  font-weight: 600;
+  color: #333;
+  margin-bottom: px2rpx(30);
 }
-
 .confirm-content {
-    font-size: px2rpx(20);
-    color: #666;
-    margin-bottom: px2rpx(30);
-    line-height: 1.5;
-    word-break: break-word;
+  font-size: px2rpx(20);
+  color: #666;
+  margin-bottom: px2rpx(30);
+  line-height: 1.5;
+  word-break: break-word;
 }
-
-</style>
+</style>

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

@@ -10,7 +10,6 @@
     </cwg-match-media>
     <cwg-language style="width: 0;display: none;" />
     <cwg-progress />
-    <cwg-confirm-popup />
 
     <view class="page-content" :style="{ backgroundColor: bgColor }">
       <cwg-match-media :max-width="991" v-if="!isLoginPage">

+ 5 - 5
components/cwg-sidebar.vue

@@ -91,7 +91,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, computed, watch, onMounted } from 'vue'
+import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
 import useUserStore from '@/stores/use-user-store'
 import { useMenuSplit } from '@/composables/useMenuSplit'
 import { storeToRefs } from 'pinia'
@@ -263,10 +263,10 @@ const getPay = (newMode) => {
   }
 }
 watch(() => mode.value, (newMode) => {
-    if (!userToken.value) return
-    console.log(newMode, 'mode')
-    getPay(newMode)
-  },
+  if (!userToken.value) return
+  console.log(newMode, 'mode')
+  getPay(newMode)
+},
   { immediate: true })
 onMounted(() => {
   uni.$on('updatePayment', () => {

+ 1 - 0
composables/useMenuSplit.ts

@@ -264,6 +264,7 @@ export function useMenuSplit(handleClick1: (item: MenuItem) => void) {
             path: '/',
             label: 'Home.page_ib.item12',
             icon: 'crm-bulletin',
+            submenuHeight: 1 * ((40 + 8)) + 8,
             children: [
                 { path: '/pages/ib/promotion', label: 'Home.page_ib.item13', icon: 'icon-withdrawal' },
             ],

+ 32 - 13
hooks/useConfirm.ts

@@ -1,24 +1,43 @@
 export function useConfirm() {
   const confirm = (options) => {
     return new Promise((resolve, reject) => {
-      const eventId = Date.now() + '_' + Math.random()
+      // 唯一ID,彻底隔离每个弹窗
+      const eventId = Date.now() + '_' + Math.random().toString(36).substr(2, 9)
       const resultEvent = `confirmResult_${eventId}`
-      
-      const handler = (result) => {
-        uni.$off(resultEvent, handler)
+
+      let isFinished = false
+      let timeoutTimer = null
+
+      // 接收结果
+      const handleResult = (result) => {
+        if (isFinished) return
+        isFinished = true
+
+        clearTimeout(timeoutTimer)
+        uni.$off(resultEvent, handleResult)
+
         if (result) resolve(true)
-        else reject(false)
+        else reject(new Error('cancel'))
       }
-      
-      uni.$on(resultEvent, handler)
-      uni.$emit('showConfirm', { ...options, eventId })
-      
-      // 超时处理
-      setTimeout(() => {
-        uni.$off(resultEvent, handler)
-        reject(new Error('确认弹窗超时'))
+
+      // 监听自己的结果
+      uni.$on(resultEvent, handleResult)
+
+      // 打开全局弹窗
+      uni.$emit('showConfirm', {
+        ...options,
+        eventId
+      })
+
+      // 超时保护
+      timeoutTimer = setTimeout(() => {
+        if (isFinished) return
+        isFinished = true
+        uni.$off(resultEvent, handleResult)
+        reject(new Error('timeout'))
       }, 60000)
     })
   }
+
   return confirm
 }

+ 4 - 2
pages/activities/index.vue

@@ -2553,7 +2553,9 @@ onReachBottom(() => {
 
     .form-item {
         display: flex;
-        align-items: center;
+        flex-direction: column;
+        align-items: flex-start;
+        justify-content: flex-start;
         margin-bottom: 20px;
         gap: 16px;
 
@@ -2566,7 +2568,7 @@ onReachBottom(() => {
 
         :deep(.cwg-combox) {
             flex: 1;
-            min-width: 300px;
+            width: 100%;
 
             .el-input__wrapper {
                 border-radius: 4px;

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

@@ -102,6 +102,7 @@
             <GiftApplicationPopup v-model:visible="dialogGiftApplication" :title="t('Btn.Application')"
                 :giftList="giftList" :giftForm="giftForm" @confirm="submitGiftApply" />
         </view>
+        <cwg-confirm-popup />
     </cwg-page-wrapper>
 </template>
 

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

@@ -95,6 +95,7 @@
                 </view>
             </view>
         </view>
+        <cwg-confirm-popup />
     </cwg-page-wrapper>
 </template>
 

+ 4 - 4
pages/customer/account-select.vue

@@ -55,10 +55,10 @@
                                 </view>
                                 <p class="card-desc" v-t="account.description"></p>
                                 <view class="card-info-stack">
-                                    <cwg-label-line-value :label="'vu.item9'" :value="account.minDeposit" />
-                                    <cwg-label-line-value :label="'vu.item10'" :value="account.minSpread" />
-                                    <cwg-label-line-value :label="'vu.item11'" :value="account.maxLeverage" />
-                                    <!-- <cwg-label-line-value :label="'vu.item12'" :value="account.minSpread" /> -->
+                                    <cwg-label-line-value :label="t('vu.item9')" :value="account.minDeposit" />
+                                    <cwg-label-line-value :label="t('vu.item10')" :value="account.minSpread" />
+                                    <cwg-label-line-value :label="t('vu.item11')" :value="account.maxLeverage" />
+                                    <!-- <cwg-label-line-value :label="t('vu.item12')" :value="account.minSpread" /> -->
                                 </view>
                             </view>
                         </swiper-item>

+ 1 - 0
pages/customer/payment-history.vue

@@ -112,6 +112,7 @@
                 </template>
             </cwg-tabel>
         </view>
+        <cwg-confirm-popup />
     </cwg-page-wrapper>
 </template>
 

+ 3 - 2
pages/customer/wallet-transfer.vue

@@ -154,7 +154,7 @@ const rules = {
 }
 const amountErrorMessage = ref('')
 const setAllAmount = () => {
-    form.amount = walletbalance.value.toFixed(2)
+    form.amount = Number(walletbalance.value)
     validateAmount()
 }
 function validateAmount() {
@@ -201,6 +201,7 @@ const toTransfer = async () => {
             dialogVisible.value = true
             flag.value = false
             getWalletList() // refresh balance after success
+            uni.$emit('updatePayment')
         } else {
             RES.value = res.msg
             dialogCheck.value = true
@@ -236,7 +237,7 @@ const getWalletList = async () => {
     try {
         let res = await drawApi.walletbalance({})
         if (res.code == Code.StatusOK) {
-            walletbalance.value = res.data != null ? res.data : '0'
+            walletbalance.value = res.data != null ? Number(res.data).toFixed(2) : '0'
         } else {
             uni.showToast({ title: res.msg, icon: 'none' })
         }

+ 2 - 1
pages/follow/transfer.vue

@@ -58,7 +58,7 @@
 
                                 <view class="form-row">
                                     <button class="s-btn reselect" type="primary" @click="toTransfer">{{ t('Btn.Submit')
-                                    }}</button>
+                                        }}</button>
                                 </view>
                             </uni-forms>
                         </view>
@@ -205,6 +205,7 @@ const toTransfer = async () => {
             dialogVisible.value = true
             flag.value = false
             getWalletList() // refresh balance after success
+            uni.$emit('updatePayment')
         } else {
             RES.value = res.msg
             dialogCheck.value = true

+ 1 - 0
pages/ib/recording.vue

@@ -48,6 +48,7 @@
         </template>
       </cwg-tabel>
     </view>
+    <cwg-confirm-popup />
   </cwg-page-wrapper>
 </template>
 

+ 2 - 0
pages/ib/transfer.vue

@@ -130,6 +130,7 @@
             <BonusAgreementPopup v-model:visible="dialogClauseNewList" :title="tableDataNewList.title"
                 :content="tableDataNewList.content" type="newList" />
         </view>
+        <cwg-confirm-popup />
     </cwg-page-wrapper>
 </template>
 
@@ -526,6 +527,7 @@ async function transferConfig() {
         resetForm()
         if (dialogCheckWait.value) dialogCheckWait.value = false
         getDateList()
+        uni.$emit('updatePayment')
     }
 }
 

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

@@ -75,6 +75,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=\"M335.9 84.2c-9.8-5.6-21.9-5.6-31.8 0l-224 128c-12.6 7.2-18.8 22-15.1 36S81.5 272 96 272h32v208l-51.2 38.4c-8.1 6-12.8 15.5-12.8 25.6 0 17.7 14.3 32 32 32h448c17.7 0 32-14.3 32-32 0-10.1-4.7-19.6-12.8-25.6L512 480V272h32c14.5 0 27.2-9.8 30.9-23.8s-2.5-28.8-15.1-36l-224-128zM464 272v208h-64V272zm-112 0v208h-64V272zm-112 0v208h-64V272zm80-112c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32\"/></svg>",
         2
       ],
+      "crm-bulletin": [
+        "<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=\"M525.2 82.9C536.7 88 544 99.4 544 112v416c0 12.6-7.3 24-18.8 29.1s-24.8 3.2-34.3-5.1l-46.6-40.7c-43.6-38.1-98.7-60.3-156.4-63V544c0 17.7-14.3 32-32 32h-32c-17.7 0-32-14.3-32-32v-96C121.3 448 64 390.7 64 320s57.3-128 128-128h84.5c61.8-.2 121.4-22.7 167.9-63.3L491 88c9.4-8.3 22.9-10.2 34.3-5.1zM288 384v.2c70.3 2.7 137.8 28.5 192 73.4V182.3c-54.2 44.9-121.7 70.7-192 73.4z\"/></svg>",
+        2
+      ],
       "crm-card": [
         "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"#22ac38\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" class=\"tabler-icon tabler-icon-layout-grid\" viewBox=\"0 0 24 24\"><path d=\"M4 5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1zm10 0a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1zM4 15a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1zm10 0a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1z\"/></svg>",
         2
@@ -280,6 +284,10 @@ const collections = {
         "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\"><path fill=\"#22ac38\" d=\"M5 22q-.824 0-1.412-.587A1.93 1.93 0 0 1 3 20V6q0-.824.587-1.412A1.93 1.93 0 0 1 5 4h1V3q0-.424.287-.712A.97.97 0 0 1 7 2q.424 0 .713.288Q8 2.575 8 3v1h8V3q0-.424.288-.712A.97.97 0 0 1 17 2q.424 0 .712.288Q18 2.575 18 3v1h1q.824 0 1.413.588Q21 5.175 21 6v14q0 .824-.587 1.413A1.93 1.93 0 0 1 19 22zm0-2h14V10H5zM5 8h14V6H5zm7 6a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 13q0-.424.287-.713A.97.97 0 0 1 12 12q.424 0 .713.287.287.288.287.713 0 .424-.287.713A.97.97 0 0 1 12 14m-4 0a.97.97 0 0 1-.713-.287A.97.97 0 0 1 7 13q0-.424.287-.713A.97.97 0 0 1 8 12q.424 0 .713.287Q9 12.576 9 13t-.287.713A.97.97 0 0 1 8 14m8 0a.97.97 0 0 1-.713-.287A.97.97 0 0 1 15 13q0-.424.287-.713A.97.97 0 0 1 16 12q.424 0 .712.287.288.288.288.713 0 .424-.288.713A.97.97 0 0 1 16 14m-4 4a.97.97 0 0 1-.713-.288A.97.97 0 0 1 11 17q0-.424.287-.712A.97.97 0 0 1 12 16q.424 0 .713.288.287.287.287.712 0 .424-.287.712A.97.97 0 0 1 12 18m-4 0a.97.97 0 0 1-.713-.288A.97.97 0 0 1 7 17q0-.424.287-.712A.97.97 0 0 1 8 16q.424 0 .713.288Q9 16.575 9 17q0 .424-.287.712A.97.97 0 0 1 8 18m8 0a.97.97 0 0 1-.713-.288A.97.97 0 0 1 15 17q0-.424.287-.712A.97.97 0 0 1 16 16q.424 0 .712.288.288.287.288.712 0 .424-.288.712A.97.97 0 0 1 16 18\"/></svg>",
         2
       ],
+      "cwg-chart": [
+        "<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=\"M128 128c0-17.7-14.3-32-32-32s-32 14.3-32 32v336c0 44.2 35.8 80 80 80h400c17.7 0 32-14.3 32-32s-14.3-32-32-32H144c-8.8 0-16-7.2-16-16zm406.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L384 274.7l-57.4-57.3c-12.5-12.5-32.8-12.5-45.3 0l-96 96c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l73.4-73.4 57.4 57.4c12.5 12.5 32.8 12.5 45.3 0l128-128z\"/></svg>",
+        2
+      ],
       "cwg-close": [
         "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" class=\"icon\" viewBox=\"0 0 1024 1024\"><path fill=\"#272536\" d=\"m851.416 217.84-45.256-45.248L512 466.744l-294.152-294.16-45.256 45.256L466.744 512 172.592 806.16l45.248 45.256L512 557.256l294.16 294.16 45.256-45.256L557.256 512z\"/></svg>",
         11