Browse Source

Merge branch 'admin_dev' into admin_dev_ocr

ljc 1 week ago
parent
commit
e11b02ba62

+ 40 - 62
components/cwg-file-picker-wrapper.vue

@@ -456,13 +456,12 @@ const handleFile = async (fileData) => {
     }
 
   } catch (e) {
-
+    const errMsg = e?.message || (typeof e === 'string' ? e : '文件处理失败')
+    console.error('handleFile failed:', e)
     uni.showToast({
-      title: '文件处理失败',
+      title: errMsg,
       icon: 'none'
     })
-
-    console.error(e)
   }
 }
 const startUpload = async () => {
@@ -645,71 +644,50 @@ const uploadBase64 = (fileItem) => {
 }
 
 
-const base64ToTempFile = (base64, fileName = 'file.png') => {
+/** 从 data URL 中取出 base64 正文,避免对大字符串做正则匹配 */
+const getBase64Body = (dataUrl) => {
+  if (!dataUrl || typeof dataUrl !== 'string') return ''
+  const marker = 'base64,'
+  const markerIdx = dataUrl.indexOf(marker)
+  if (markerIdx !== -1) {
+    return dataUrl.substring(markerIdx + marker.length)
+  }
+  const commaIdx = dataUrl.indexOf(',')
+  return commaIdx !== -1 ? dataUrl.substring(commaIdx + 1) : dataUrl
+}
 
+const base64ToTempFile = (base64, fileName = 'file.png') => {
   return new Promise((resolve, reject) => {
+    // #ifndef APP-PLUS
+    reject(new Error('仅 APP 环境支持'))
+    return
+    // #endif
 
-    const matches = base64.match(/^data:(.+);base64,(.+)$/)
-
-    if (!matches) {
-      reject('base64格式错误')
+    const base64Data = getBase64Body(base64)
+    if (!base64Data) {
+      reject(new Error('base64格式错误'))
       return
     }
 
-    const base64Data = matches[2]
-
-    const filePath =
-      `${plus.io.convertLocalFileSystemURL('_doc/')}${Date.now()}_${fileName}`
-
-    plus.io.resolveLocalFileSystemURL(
-      '_doc/',
-      (entry) => {
-
-        entry.getFile(
-          `${Date.now()}_${fileName}`,
-          { create: true },
-
-          (fileEntry) => {
-
-            fileEntry.createWriter((writer) => {
-
-              writer.onwrite = () => {
-                resolve(fileEntry.toLocalURL())
-              }
+    const safeName = `${Date.now()}_${(fileName || 'file').replace(/[/\\]/g, '_')}`
+    const dirName = 'cwg_upload'
 
-              writer.onerror = reject
-
-              const bitmap = new plus.nativeObj.Bitmap()
-
-              bitmap.loadBase64Data(
-                base64,
-
-                () => {
-
-                  bitmap.save(
-                    fileEntry.toLocalURL(),
-
-                    {},
-
-                    () => {
-                      resolve(fileEntry.toLocalURL())
-                    },
-
-                    reject
-                  )
-                },
-
-                reject
-              )
-            })
-          },
-
-          reject
-        )
-      },
-
-      reject
-    )
+    plus.io.resolveLocalFileSystemURL('_doc', (docEntry) => {
+      docEntry.getDirectory(dirName, { create: true, exclusive: false }, (dirEntry) => {
+        dirEntry.getFile(safeName, { create: true, exclusive: false }, (fileEntry) => {
+          fileEntry.createWriter((writer) => {
+            writer.onwrite = () => {
+              resolve(fileEntry.toLocalURL())
+            }
+            writer.onerror = (err) => {
+              reject(err || new Error('写入临时文件失败'))
+            }
+            writer.seek(0)
+            writer.writeAsBinary(base64Data)
+          }, reject)
+        }, reject)
+      }, reject)
+    }, reject)
   })
 }
 

+ 5 - 5
composables/useAccountOptions.js

@@ -57,11 +57,11 @@ export function useAccountOptions() {
     onMounted(() => {
       // console.log('hook useAccountOptions mounted')
       // console.log(loginOptions?.length)
-        if (loginOptions && loginOptions?.length > 0) {
-            isLoaded.value = true
-            isSuccess.value = true
-            return
-        }
+        // if (loginOptions && loginOptions?.length > 0) {
+        //     isLoaded.value = true
+        //     isSuccess.value = true
+        //     return
+        // }
         getDateList()
     })
 

+ 1 - 1
config/index.ts

@@ -40,7 +40,7 @@ const config = {
     Email: /^[\w.%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i,
     Phone: /^1[3-9]\d{9}$/,
     Pin: /^(?!(\d)\1{5})(?!012345)(?!123456)(?!234567)(?!345678)(?!456789)(?!987654)(?!876543)(?!765432)(?!654321)(?!543210)\d{6}$/,
-    Password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,16}$/,
+    Password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d!@#$%^&*()_+\-=\[\]{}|;:,.<>?/~]{8,16}$/,
     Tel: /^0[1-9]{2,3}-\d{5,10}$/,
     Num: /\d/,
     NonNegInt: /^\d+$/, // 非负整数

+ 25 - 9
pages/customer/payment-history.vue

@@ -117,7 +117,7 @@
 </template>
 
 <script setup lang="ts">
-import { computed, ref, nextTick, reactive } from 'vue';
+import { computed, ref, nextTick, reactive, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { onLoad } from '@dcloudio/uni-app'
 const { t, locale } = useI18n();
@@ -243,23 +243,27 @@ const filterFields = computed(() => [
     {
         key: 'orderStatus', type: 'select', label: t('Custom.PaymentHistory.Status'), placeholder: t('placeholder.choose'), options: orderStatusMap.value, defaultValue: null
     },
-    isLoaded.value && isSuccess.value && { key: 'login', type: 'select', label: t('Custom.PaymentHistory.TradingAccount'), placeholder: t('placeholder.login'), options: loginOptions || [], defaultValue: search.login || undefined, clearable: true },
+    isLoaded.value && isSuccess.value && { key: 'login', type: 'select', label: t('Custom.PaymentHistory.TradingAccount'), placeholder: t('placeholder.login'), options: loginOptions || [], defaultValue: undefined, clearable: true },
     { key: 'date', label: t('placeholder.Start') + ' - ' + t('placeholder.End'), type: 'daterange' }
 ])
 
 const searchParams = ref({})
 
-const handleSearch = (params) => {
+const handleSearch = (params, type) => {
     Object.assign(search, params)
-    search.platform = loginOptions.find(item => item.value === params.login)?.platform || ''
-    nextTick(() => {
+    search.platform = loginOptions?.find(item => item.value === params.login)?.platform || ''
+    search.login = params.login && Number(params.login)
+
+    setTimeout(() => {
+        console.log(search, params, 10000, type);
         tableRef.value.refreshTable()
-    })
+    }, 10)
 }
 
 const handleReset = (params) => {
     Object.assign(search, params)
-    search.platform = loginOptions.find(item => item.value === params.login)?.platform || ''
+    search.platform = loginOptions?.find(item => item.value === params.login)?.platform || ''
+    search.login = params.login && Number(params.login)
     nextTick(() => {
         tableRef.value.refreshTable()
     })
@@ -332,10 +336,22 @@ const cancle = async (id, type) => {
         console.log('取消删除')
     }
 }
-onLoad((e) => {
+onLoad(async (e) => {
+    let targetLogin: number | null = null
     if (e.login) {
-        search.login = Number(e.login)
+        targetLogin = Number(e.login)
     }
+    await new Promise<void>(resolve => {
+        const stopWatch = watch([isLoaded, isSuccess], ([loaded, success]) => {
+            if (loaded && success) {
+                stopWatch()
+                resolve()
+            }
+        })
+    })
+    searchParams.value.login = targetLogin
+    search.platform = loginOptions?.find(item => item.value === searchParams.value.login)?.platform || ''
+    search.login = searchParams.value.login && Number(searchParams.value.login)
 })
 </script>
 

+ 1 - 0
pages/customer/wallet-transfer.vue

@@ -124,6 +124,7 @@ const rules = computed(() => ({
             { required: true, errorMessage: t('vaildate.amount.format') },
             {
                 validateFunction: (rule, value, data, callback) => {
+                    value = Number(value)
                     if (!value) {
                         callback(t('vaildate.amount.format'))
                     } else if (!/^[0-9]+([.]{1}[0-9]{1,2})?$/.test(value)) {

+ 22 - 9
pages/follow/components/applySignalDialog.vue

@@ -1,5 +1,6 @@
 <template>
-  <cwg-popup :title="t('Documentary.TundManagement.item41')" :visible="visible" @close="closeDia" @confirm="confirmDia" width="700px">
+  <cwg-popup :title="t('Documentary.TundManagement.item41')" :visible="visible" @close="closeDia" @confirm="confirmDia"
+    width="700px">
     <uni-forms ref="formRef" :model="formData" :rules="rules" labelWidth="200" label-position="top" class="crm-form">
       <view class="dia-content">
         <!-- 名片信息 -->
@@ -139,8 +140,7 @@
           <view class="form-col">
             <view class="form-item">
               <uni-forms-item :label="t('Documentary.tradingCenter.item32')" name="settlementCycle">
-                <cwg-combox v-model:value="formData.settlementCycle"
-                  :options="optList1"
+                <cwg-combox v-model:value="formData.settlementCycle" :options="optList1"
                   :placeholder="t('placeholder.choose')" />
               </uni-forms-item>
             </view>
@@ -157,8 +157,8 @@
                   {{ t('Documentary.TundManagement.item42') }}
                   <cwg-link type="pdf" class="a" v-if="['cn', 'zhHant'].indexOf(locale) != -1"
                     url="pdf/CopyTradeUserAgreementcn.pdf" target="_blank" title="Documentary.TundManagement.item43" />
-                  <cwg-link type="pdf" class="a" v-else url="pdf/CopyTradeUserAgreement.pdf"
-                    target="_blank" title="Documentary.TundManagement.item43" />
+                  <cwg-link type="pdf" class="a" v-else url="pdf/CopyTradeUserAgreement.pdf" target="_blank"
+                    title="Documentary.TundManagement.item43" />
                   {{ t('Documentary.TundManagement.item42_2') }}
                 </text>
               </label>
@@ -180,7 +180,7 @@ import { ref, computed, watch } from 'vue'
 import { useI18n } from 'vue-i18n'
 import Config from '@/config/index'
 import { documentaryApi } from '@/service/documentary'
-import {useFollowEnum} from '@/pages/follow/const/enum'
+import { useFollowEnum } from '@/pages/follow/const/enum'
 import { useFilters } from '@/composables/useFilters'
 const { numberDecimal } = useFilters()
 
@@ -192,7 +192,7 @@ const props = defineProps({
 const emit = defineEmits(['close', 'confirm'])
 const { t, locale } = useI18n()
 const { Code } = Config
-const {optList1} = useFollowEnum()
+const { optList1 } = useFollowEnum()
 
 const formRef = ref(null)
 const formData = ref({
@@ -474,7 +474,7 @@ const rules = computed(() => ({
 }));
 
 watch(locale, () => {
-    formRef.value?.clearValidate()
+  formRef.value?.clearValidate()
 })
 
 const filterChineseEnglishOnly = (field, value) => {
@@ -623,6 +623,18 @@ watch(() => props.visible, (val) => {
     }
   }
 
+  @media screen and (max-width: 768px) {
+    .delete-item {
+      &:first-child {
+        padding-right: px2rpx(0);
+      }
+
+      &:last-child {
+        padding-left: px2rpx(0);
+      }
+    }
+  }
+
   .delete-label {
     font-size: px2rpx(14);
     color: var(--bs-body-color);
@@ -655,7 +667,8 @@ watch(() => props.visible, (val) => {
     display: flex;
     align-items: flex-start;
     gap: px2rpx(8);
-    :deep(.uni-checkbox-input){
+
+    :deep(.uni-checkbox-input) {
       margin-top: px2rpx(3);
       width: px2rpx(18);
       height: px2rpx(18);

+ 20 - 4
pages/follow/trading-management.vue

@@ -29,8 +29,12 @@
                             - {{ item.dealLogin || "--" }}
                         </view>
                         <view class="caozuo">
-                            <cwg-icon class="cwg-cursor cursor-pointer" :data-tooltip="t('Documentary.TundManagement.item28')" name="crm-trash-can" @click="dialogFllowDele(item)" />
-                            <cwg-icon class="cwg-cursor cursor-pointer" :data-tooltip="t('Documentary.TundManagement.item31')" name="cog-outline" @click="dialogFllowUpdate(item)" />
+                            <cwg-icon class="cwg-cursor cursor-pointer"
+                                :data-tooltip="t('Documentary.TundManagement.item28')" name="crm-trash-can"
+                                @click="dialogFllowDele(item)" />
+                            <cwg-icon class="cwg-cursor cursor-pointer"
+                                :data-tooltip="t('Documentary.TundManagement.item31')" name="cog-outline"
+                                @click="dialogFllowUpdate(item)" />
                         </view>
                     </view>
                     <view class="account-grid">
@@ -150,7 +154,8 @@
                         </view>
                         <view class="delete-item">
                             <text class="delete-label">{{ t('Documentary.tradingCenter.item32') }}</text>
-                            <text class="delete-value">{{ optObj[dialogFllowDataDelete.settlementCycle] || '--' }}</text>
+                            <text class="delete-value">{{ optObj[dialogFllowDataDelete.settlementCycle] || '--'
+                            }}</text>
                         </view>
                     </view>
                 </view>
@@ -940,7 +945,7 @@ const ApplyFllow = async () => {
             flag.value = false;
         }
     } catch (error) {
-        uni.showToast({title:error.msg, icon: 'none'});
+        uni.showToast({ title: error.msg, icon: 'none' });
     } finally {
         flag.value = false;
     }
@@ -1355,6 +1360,17 @@ onMounted(() => {
         }
     }
 
+    @media screen and (max-width: 768px) {
+        .delete-item {
+            &:first-child {
+                padding-right: px2rpx(0);
+            }
+            &:last-child {
+                padding-left: px2rpx(0);
+            }
+        }
+    }
+
     .delete-label {
         font-size: px2rpx(14);
         color: var(--bs-body-color);

+ 1 - 1
pages/ib/components/linkDetailDialog.vue

@@ -177,7 +177,7 @@
     }
   }
   .label {
-    color: #6c8595;
+    color: var(--bs-emphasis-color);
     font-size: px2rpx(14);
     line-height: px2rpx(24);
   }

+ 2 - 2
pages/ib/recording.vue

@@ -43,9 +43,9 @@
             <text v-if="row.status == 5">
               {{ t('State.Cancelled') }}
             </text>
-            <button class="cancel-btn btn btn-gray" v-if="row.status == 1" @click.stop="cancel(row.id)">
+            <view class="cancel-btn btn btn-gray" v-if="row.status == 1" @click.stop="cancel(row.id)">
               {{ t('Btn.Cancel') }}
-            </button>
+            </view>
           </view>
 
         </template>