li.shaoyi 2 anos atrás
pai
commit
bf2978fbc2

Diferenças do arquivo suprimidas por serem muito extensas
+ 319 - 219
package-lock.json


+ 3 - 2
package.json

@@ -23,18 +23,19 @@
     "long": "^5.2.0",
     "moment": "^2.29.3",
     "protobufjs": "^6.11.2",
+    "qrcode": "^1.5.1",
     "sortablejs": "^1.15.0",
     "uuid": "^8.3.2",
     "vant": "^4.0.3",
     "vue": "^3.2.13",
     "vue-class-component": "^8.0.0-0",
     "vue-i18n": "^9.2.2",
-    "vue-qr": "^4.0.9",
     "vue-router": "^4.0.3",
     "vuedraggable": "^4.1.0"
   },
   "devDependencies": {
     "@types/crypto-js": "^4.1.1",
+    "@types/qrcode": "^1.5.0",
     "@types/sortablejs": "^1.13.0",
     "@types/uuid": "^8.3.4",
     "@typescript-eslint/eslint-plugin": "^5.4.0",
@@ -55,4 +56,4 @@
     "vconsole": "^3.14.6",
     "worker-loader": "^3.0.8"
   }
-}
+}

+ 2 - 1
src/business/login/index.ts

@@ -76,7 +76,8 @@ export function useLogin() {
                         eventBus.$emit('LogoutNotify')
                     }
                 }
-            } else if (token.value) {
+            }
+            if (token.value) {
                 await loadUserData()
             }
         } finally {

+ 89 - 0
src/components/base/qrcode/index.vue

@@ -0,0 +1,89 @@
+<template>
+    <canvas ref="canvasRef"></canvas>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, onMounted } from 'vue'
+import { fillRoundRect } from '@/utils/canvas'
+import QRCode from 'qrcode'
+
+const props = defineProps({
+    modelValue: String,
+    text: {
+        type: String,
+        required: true,
+    },
+    width: {
+        type: Number,
+        default: 320
+    },
+    margin: {
+        type: Number,
+        default: 2
+    },
+    logo: String,
+    logoWidth: Number,
+    logoBackground: String,
+})
+
+const emit = defineEmits(['update:modelValue'])
+const canvasRef = shallowRef<HTMLCanvasElement>()
+
+// const getImageBlob = (url: string) => {
+//     return new Promise<string>((resolve, reject) => {
+//         const xhr = new XMLHttpRequest()
+//         xhr.open('GET', url, true)
+//         xhr.responseType = 'blob'
+//         xhr.onload = () => {
+//             if (xhr.status === 200) {
+//                 resolve(URL.createObjectURL(xhr.response))
+//             } else {
+//                 reject(xhr.statusText)
+//             }
+//         }
+//         xhr.send()
+//     })
+// }
+
+onMounted(async () => {
+    const canvas = canvasRef.value
+    if (canvas) {
+        QRCode.toCanvas(canvas, props.text, { width: props.width, margin: props.margin, })
+        const drawQRcodeLogo = (imageSrc: string, crossOrigin = true) => {
+            return new Promise<void>((resolve) => {
+                const image = new Image()
+                if (crossOrigin) {
+                    image.crossOrigin = 'Anonymous'
+                }
+                image.src = imageSrc
+                image.onload = () => {
+                    const ctx = canvas.getContext('2d')
+                    if (ctx) {
+                        // 绘制背景
+                        const width = props.logoWidth ?? 56 // 背景宽高
+                        const x = (canvas.width - width) / 2
+                        const y = (canvas.height - width) / 2
+                        fillRoundRect(ctx, x, y, width, width, 8, props.logoBackground ?? '#fff')
+                        // 插入图像
+                        const imageWidth = width * 0.9 // 图像宽高
+                        const dx = (canvas.width - imageWidth) / 2
+                        const dy = (canvas.height - imageWidth) / 2
+                        ctx.drawImage(image, dx, dy, imageWidth, imageWidth)
+                    }
+                    resolve()
+                }
+                image.onerror = async () => {
+                    resolve()
+                    if (crossOrigin) {
+                        drawQRcodeLogo(imageSrc, false)
+                    }
+                }
+            })
+        }
+        if (props.logo) {
+            await drawQRcodeLogo(props.logo)
+        }
+        emit('update:modelValue', canvas.toDataURL())
+    }
+})
+</script>

+ 0 - 13
src/packages/mobile/components/base/qrcode/index.less

@@ -1,13 +0,0 @@
-.app-qrcode {
-    .van-dialog__content {
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        padding: .32rem;
-
-        img {
-            width: 4rem;
-            height: 4rem;
-        }
-    }
-}

+ 0 - 44
src/packages/mobile/components/base/qrcode/index.vue

@@ -1,44 +0,0 @@
-<template>
-    <Dialog class="app-qrcode" v-model:show="showDialog" :show-confirm-button="showConfirmButton"
-        confirm-button-text="保存" show-cancel-button @confirm="onConfirm">
-        <vue-qr ref="qrRef" :size="400" :logoSrc="require('@mobile/assets/logo.svg')" :text="content" />
-    </Dialog>
-</template>
-
-<script lang="ts" setup>
-import { computed, shallowRef } from 'vue'
-import { Dialog } from 'vant'
-import plus from '@/utils/h5plus'
-import VueQr from 'vue-qr/src/packages/vue-qr.vue'
-
-const props = defineProps({
-    show: {
-        type: Boolean,
-        default: false
-    },
-    content: String,
-    fileName: String
-})
-
-const emit = defineEmits(['update:show'])
-const showConfirmButton = shallowRef(false)
-const qrRef = shallowRef()
-
-const showDialog = computed({
-    get: () => props.show,
-    set: (val) => emit('update:show', val)
-})
-
-// 保存二维码
-const onConfirm = () => {
-    plus.saveImage(qrRef.value.imgUrl, 'thj_' + (props.fileName ?? new Date().getTime()))
-}
-
-plus.onPlusReady(() => {
-    showConfirmButton.value = true
-})
-</script>
-
-<style lang="less">
-@import './index.less';
-</style>

+ 20 - 0
src/packages/mobile/components/modules/register-code/index.less

@@ -0,0 +1,20 @@
+.app-register-code {
+    &__wrapper {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        min-height: 4rem;
+        padding: .32rem;
+    }
+
+    &__qrcode {
+        max-width: 4.8rem;
+        max-height: 4.8rem;
+    }
+
+    &__content {
+        font-size: .32rem;
+        font-weight: bold;
+    }
+}

+ 63 - 0
src/packages/mobile/components/modules/register-code/index.vue

@@ -0,0 +1,63 @@
+<template>
+    <Dialog class="app-register-code" teleport="body" v-model:show="showDialog" :show-confirm-button="showConfirmButton"
+        confirm-button-text="保存" show-cancel-button @confirm="onConfirm">
+        <div class="app-register-code__wrapper">
+            <div class="app-register-code__canvas">
+                <app-qrcode class="app-register-code__qrcode" v-model="base64Data" :text="qrContent"
+                    :logo="require('@mobile/assets/logo.svg')" />
+            </div>
+            <div class="app-register-code__content" :data-clipboard-text="props.text" v-copy="onCopy">{{ props.text }}</div>
+        </div>
+    </Dialog>
+</template>
+
+<script lang="ts" setup>
+import { computed, shallowRef } from 'vue'
+import { Dialog, showFailToast, showSuccessToast } from 'vant'
+import { getServiceUrl } from '@/services/http'
+import plus from '@/utils/h5plus'
+import AppQrcode from '@/components/base/qrcode/index.vue'
+
+const props = defineProps({
+    show: {
+        type: Boolean,
+        default: false
+    },
+    text: String,
+})
+
+const emit = defineEmits(['update:show'])
+const showConfirmButton = shallowRef(false)
+const base64Data = shallowRef('')
+
+const qrContent = computed(() => {
+    const url = getServiceUrl('mobileOpenUrl')
+    return url + '/#/?code=' + props.text
+})
+
+const showDialog = computed({
+    get: () => props.show,
+    set: (val) => emit('update:show', val)
+})
+
+const onCopy = (status: boolean) => {
+    if (status) {
+        showSuccessToast('复制成功')
+    } else {
+        showFailToast('复制失败')
+    }
+}
+
+// 保存二维码
+const onConfirm = () => {
+    plus.saveImage(base64Data.value, 'thj_' + (props.text ?? new Date().getTime()))
+}
+
+plus.onPlusReady(() => {
+    showConfirmButton.value = true
+})
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 4 - 1
src/packages/mobile/views/credit/signin/index.vue

@@ -69,7 +69,7 @@
                         </div>
                     </div>
                     <div class="list-item__button">
-                        <Button type="primary" @click="routerTo('mine-generalize')" round>去完成</Button>
+                        <Button type="primary" @click="showQRCode = true" round>去完成</Button>
                     </div>
                 </dd>
                 <dd class="list-item">
@@ -102,6 +102,7 @@
                 </dd>
             </dl>
         </div>
+        <app-register-code v-model:show="showQRCode" :text="userAccount.refernum" />
     </app-view>
 </template>
 
@@ -114,12 +115,14 @@ import { queryUserAccount } from '@/services/api/account'
 import { queryTHJScoreConfig } from '@/services/api/credit'
 import { signin } from '@/services/api/common'
 import { useNavigation } from '@/hooks/navigation'
+import AppRegisterCode from '@mobile/components/modules/register-code/index.vue'
 
 const { userId } = loginStore.$mapGetters()
 const { routerTo, routerBack } = useNavigation()
 const headerRef = shallowRef<HTMLDivElement>()
 const userAccount = shallowRef<Partial<Model.UserAccount>>({})
 const scoreConfig = shallowRef<Model.THJScoreConfigRsp[]>([])
+const showQRCode = shallowRef(false)
 
 const onReady = (el: HTMLDivElement) => {
     // 设置背景图位置

+ 2 - 8
src/packages/mobile/views/mine/generalize/index.vue

@@ -50,7 +50,7 @@
         </div>
         <trade-data :marketid="selectedType" v-if="selectedMenu === 0" />
         <promotion :status="selectedType" v-if="selectedMenu === 1" />
-        <app-qrcode v-model:show="showQRCode" :content="qrContent" :file-name="userAccount.refernum" />
+        <app-register-code v-model:show="showQRCode" :text="userAccount.refernum" />
     </app-view>
 </template>
 
@@ -60,10 +60,9 @@ import { DropdownItem, DropdownMenu, Progress } from 'vant'
 import { loginStore } from '@/stores'
 import { queryUserLevelInfo } from '@/services/api/common'
 import { queryUserAccount } from '@/services/api/account'
-import AppQrcode from '@mobile/components/base/qrcode/index.vue'
+import AppRegisterCode from '@mobile/components/modules/register-code/index.vue'
 import TradeData from './components/tradedata/index.vue'
 import Promotion from './components/promotion/index.vue'
-import { getServiceUrl } from '@/services/http'
 import { Market, getTHJMarketList } from '@/constants/market'
 
 const { userId } = loginStore.$mapGetters()
@@ -101,11 +100,6 @@ const dropdownTypes = computed(() => {
     return []
 })
 
-const qrContent = computed(() => {
-    const url = getServiceUrl('mobileOpenUrl')
-    return url + '/#/?code=' + userAccount.value.refernum
-})
-
 // 切换菜单
 const onMenuChange = () => {
     if (selectedMenu.value === 0) {

+ 8 - 2
src/packages/mobile/views/mine/main/index.vue

@@ -50,9 +50,9 @@
     </div>
     <app-block class="mine-iconbar">
       <ul>
-        <li @click="routerTo('mine-generalize')">
+        <li @click="showQRCode = true">
           <img src="@mobile/assets/icons/generalize.png" />
-          <span>我的推广</span>
+          <span>注册编码</span>
         </li>
         <li @click="routerTo('my-order')">
           <img src="@mobile/assets/icons/order.png" />
@@ -112,6 +112,7 @@
     <div class="mine-footer">
       <Button class="button-logout" type="primary" size="small" round @click="userLogout">退出登录</Button>
     </div>
+    <app-register-code v-model:show="showQRCode" :text="registerCode" />
   </app-view>
 </template>
 
@@ -127,14 +128,18 @@ import { useBankAccountSign } from '@/business/bank'
 import { queryUserAccount } from '@/services/api/account'
 import { AuthStatus, getAuthStatusName } from '@/constants/account'
 import eventBus from '@/services/bus'
+import AppRegisterCode from '@mobile/components/modules/register-code/index.vue'
 
 const { router, routerTo } = useNavigation()
 const { userId, loginId, firstAccountId } = loginStore.$mapGetters()
 const { userInfo } = userStore.$mapGetters()
 const { getBankAccountList, bankInfo } = useBankAccountSign()
 const { accountInfo, freezeMargin, avaiableMoney } = accountStore.$mapGetters()
+
 const authStatus = shallowRef(AuthStatus.Uncertified) // 实名认证状态
+const registerCode = shallowRef('') // 注册编码
 const headerRef = shallowRef<HTMLDivElement>()
+const showQRCode = shallowRef(false)
 
 // 用户头像
 const userAvatar = computed(() => {
@@ -199,6 +204,7 @@ onActivated(() => {
       },
       success: (res) => {
         authStatus.value = res.data.hasauth
+        registerCode.value = res.data.refernum
       }
     })
   }

+ 1 - 2
src/shims-vue.d.ts

@@ -18,5 +18,4 @@ declare module 'worker-loader!*' {
 }
 
 declare module 'mockjs'
-declare module 'protobufjs'
-declare module 'qrcodejs2'
+declare module 'protobufjs'

+ 75 - 0
src/utils/canvas/index.ts

@@ -0,0 +1,75 @@
+/**
+ * 绘制填充色圆角矩形
+ * @param cxt 
+ * @param x 
+ * @param y 
+ * @param width 
+ * @param height 
+ * @param radii 
+ * @param fillColor 
+ * @returns 
+ */
+export function fillRoundRect(cxt: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radii: number, fillColor: string) {
+    //圆的直径必然要小于矩形的宽高          
+    if (2 * radii > width || 2 * radii > height) { return false; }
+    cxt.save();
+    cxt.translate(x, y);
+    //绘制圆角矩形的各个边  
+    drawRoundRectPath(cxt, width, height, radii);
+    cxt.fillStyle = fillColor || "#000"; //若是给定了值就用给定的值否则给予默认值  
+    cxt.fill();
+    cxt.restore();
+}
+
+/**
+ * 绘制圆角矩形 
+ * @param cxt 
+ * @param x 
+ * @param y 
+ * @param width 
+ * @param height 
+ * @param radii 
+ * @param lineWidth 
+ * @param strokeColor 
+ * @returns 
+ */
+export function strokeRoundRect(cxt: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radii: number, lineWidth: number, strokeColor: string) {
+    //圆的直径必然要小于矩形的宽高          
+    if (2 * radii > width || 2 * radii > height) { return false; }
+    cxt.save();
+    cxt.translate(x, y);
+    //绘制圆角矩形的各个边  
+    drawRoundRectPath(cxt, width, height, radii);
+    cxt.lineWidth = lineWidth || 2; //若是给定了值就用给定的值否则给予默认值2  
+    cxt.strokeStyle = strokeColor || "#000";
+    cxt.stroke();
+    cxt.restore();
+}
+
+/**
+ * 绘制圆角路径
+ * @param cxt 
+ * @param width 
+ * @param height 
+ * @param radius 
+ */
+export function drawRoundRectPath(cxt: CanvasRenderingContext2D, width: number, height: number, radius: number) {
+    cxt.beginPath();
+    //从右下角顺时针绘制,弧度从0到1/2PI  
+    cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
+    //矩形下边线  
+    cxt.lineTo(radius, height);
+    //左下角圆弧,弧度从1/2PI到PI  
+    cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
+    //矩形左边线  
+    cxt.lineTo(0, radius);
+    //左上角圆弧,弧度从PI到3/2PI  
+    cxt.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
+    //上边线  
+    cxt.lineTo(width - radius, 0);
+    //右上角圆弧  
+    cxt.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
+    //右边线  
+    cxt.lineTo(width, height - radius);
+    cxt.closePath();
+}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff