xuxueyang
2024-08-02 802290838fd05c7236dae780900b4bacb20c82df
add 二维码格式
已修改9个文件
已添加3个文件
2691 ■■■■ 文件已修改
App.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/hj-placard/shareImages.vue 292 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/qr_code/qrcode.js 1362 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/qr_code/qrcode.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/supplier-login.vue 102 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/supplier-reg.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/user/supplier-user.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
store/index.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sub_pages/customer/customer-info/customer-info.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sub_pages/partner/partner-info/partner-code-v2.vue 754 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sub_pages/partner/partner-info/partner-code.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
App.vue
@@ -51,10 +51,18 @@
                // #endif
            }
            // #endif
            // #ifdef PUB_CUSTOMER
            uni.reLaunch({
                url: '/pages/home/home'
            })
            // #ifdef PUB_CUSTOMER
            // 需要处理一下,判断是跳转登录还是原封不动
            if(options.partnerUserId){
                //需要去注册页面
                console.log('options',options)
            }else{
                uni.reLaunch({
                    url: '/pages/home/home'
                })
            }
            // #endif
        },
components/hj-placard/shareImages.vue
对比新文件
@@ -0,0 +1,292 @@
<template>
    <view style="position: fixed;z-index: -9999;">
        <canvas id="myQrcode" :canvas-id="canvasID" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}"></canvas>
        <view v-if="qrCode == ''">
            <QRCode ref="qrcode" />
        </view>
    </view>
</template>
<script>
    import QRCode from "../qr_code/qrcode.vue"
    var _this;
    export default {
        name: 'canvas-images',
        props: {
            // canvasID 等同于 canvas-id
            canvasID: {
                Type: String,
                default: 'myQrcode'
            },
            canvasWidth: { // 画布宽度
                Type: 'int',
                default: 375
            },
            canvasHeight: { // 画布高度
                Type: 'int',
                default: 650
            },
            shareTitle: { // 分享标题
                Type: 'String',
                default: '我是这张图片的标题'
            },
            goodsTitle: { // 商品宣传标题
                Type: 'String',
                default: ''
            },
            goodsTitle2: { // 商品宣传标题
                Type: 'String',
                default: ''
            },
            shareImage: { // 分享图片
                Type: 'String',
                default: ''
            },
            qrSize: { // 二维码大小
                Type: 'int',
                default: 100
            },
            qrUrl: { // 生成二维码的链接
                Type: 'String',
                default: 'https://ext.dcloud.net.cn/plugin?id=5747'
            }
        },
        components: {
            QRCode
        },
        data() {
            return {
                qrCode: '', // 二维码
                localImgPath: '',
                canvas: undefined
            }
        },
        mounted() {
            _this = this;
        },
        methods: {
            // downloadImg() {
            //     let that = this
            //     const query = uni.createSelectorQuery()
            //     console.log('canvasID',this.canvasID)
            //     query.select('#myQrcode')
            //         .fields({
            //             node: true,
            //             size: true
            //         })
            //         .exec((res) => {
            //             console.log('query',res)
            //             var canvas = res[0].node
            //             uni.canvasToTempFilePath({
            //                 canvasId: this.canvasID,
            //                 canvas: canvas,
            //                 x: 0,
            //                 y: 0,
            //                 width: this.canvasWidth,
            //                 height: this.canvasHeight,
            //                 destWidth: this.canvasWidth,
            //                 destHeight: this.canvasHeight,
            //                 success(res) {
            //                     console.log('二维码临时路径:', res.tempFilePath)
            //                     uni.saveImageToPhotosAlbum({
            //                         filePath: res.tempFilePath,
            //                         success: function() {
            //                             console.log('save success');
            //                             uni.showToast({
            //                                 title: '保存成功'
            //                             })
            //                         },
            //                         fail(res) {
            //                             console.error(res)
            //                             uni.showToast({
            //                                 title: '保存失败。',
            //                                 icon: 'error'
            //                             })
            //                         }
            //                     })
            //                 },
            //                 fail(res) {
            //                     console.error('fail', res)
            //                     uni.showToast({
            //                         title: '保存失败',
            //                         icon: 'error'
            //                     })
            //                 }
            //             })
            //         })
            // },
            // 创建二维码
            canvasCreate() {
                this.localImgPath = this.shareImage
                console.log('this.shareImage', this.shareImage)
                if (this.shareImage && this.shareImage.startsWith('https://')) {
                    uni.getImageInfo({
                        src: _this.shareImage,
                        success(res) {
                            console.log('getImageInfo res', res)
                            _this.localImgPath = res.path
                            _this.$refs.qrcode.make({
                                    size: _this.qrSize,
                                    text: _this.qrUrl
                                })
                                .then(res => {
                                    // 返回的res与uni.canvasToTempFilePath返回一致
                                    // console.log(res)
                                    _this.qrCode = res.tempFilePath;
                                    _this.onCanvas();
                                });
                        },
                        fail(error) {
                            this.$message.showToast('加载图片错误')
                        }
                    })
                } else {
                    _this.$refs.qrcode.make({
                            size: _this.qrSize,
                            text: _this.qrUrl
                        })
                        .then(res => {
                            // 返回的res与uni.canvasToTempFilePath返回一致
                            // console.log(res)
                            _this.qrCode = res.tempFilePath;
                            _this.onCanvas();
                        });
                }
            },
            // 画图
            async onCanvas() {
                uni.showLoading({
                    title: "分享图片生成中..."
                });
                const ctx = uni.createCanvasContext(_this.canvasID, _this);
                // 设置 canvas 背景色
                ctx.setFillStyle('#FFFFFF');
                ctx.fillRect(0, 0, _this.canvasWidth, _this.canvasHeight);
                ctx.setFillStyle('#000000');
                // 背景图片
                //需要下载图片
                if (_this.localImgPath) {
                    console.log('localImgPath', _this.localImgPath)
                    ctx.drawImage(_this.localImgPath, 20, 20, 335, 500);
                }
                // ctx.setFontSize(18);
                // ctx.setTextAlign('center');
                // ctx.fillText(_this.shareTitle, _this.canvasWidth / 2, 30);
                // 左边标题
                ctx.setTextAlign('left')
                ctx.setFontSize(22)
                _this.writeTextOnCanvas(ctx, 20, 21, _this.goodsTitle, 20, 560);
                ctx.setTextAlign('left')
                ctx.setFontSize(16)
                _this.writeTextOnCanvas(ctx, 20, 21, _this.goodsTitle2, 20, 585);
                // 设置虚线
                // ctx.setStrokeStyle('#333333');
                // ctx.setLineDash([5, 10], 2);
                // ctx.beginPath();
                // ctx.moveTo(220, 340);
                // ctx.lineTo(220, 420);
                // ctx.stroke();
                // 二维码
                ctx.drawImage(_this.qrCode, 250, 520, 100, 100);
                // ctx.draw();
                // 延迟后渲染至canvas上
                let pic = await _this.setTime(ctx)
                _this.$emit('success', pic);
            },
            /**
             * @param {Object} ctx_2d    getContext("2d") 对象
             * @param {int} lineheight    段落文本行高
             * @param {int} bytelength    设置单字节文字一行内的数量
             * @param {string} text        写入画面的段落文本
             * @param {int} startleft    开始绘制文本的 x 坐标位置(相对于画布)
             * @param {int} starttop    开始绘制文本的 y 坐标位置(相对于画布)
             */
            writeTextOnCanvas(ctx_2d, lineheight, bytelength, text, startleft, starttop) {
                // 获取字符串的真实长度(字节长度)
                function getTrueLength(str) {
                    var len = str.length,
                        truelen = 0;
                    for (var x = 0; x < len; x++) {
                        if (str.charCodeAt(x) > 128) {
                            truelen += 2;
                        } else {
                            truelen += 1;
                        }
                    }
                    return truelen;
                }
                // 按字节长度截取字符串,返回substr截取位置
                function cutString(str, leng) {
                    var len = str.length,
                        tlen = len,
                        nlen = 0;
                    for (var x = 0; x < len; x++) {
                        if (str.charCodeAt(x) > 128) {
                            if (nlen + 2 < leng) {
                                nlen += 2;
                            } else {
                                tlen = x;
                                break;
                            }
                        } else {
                            if (nlen + 1 < leng) {
                                nlen += 1;
                            } else {
                                tlen = x;
                                break;
                            }
                        }
                    }
                    return tlen;
                }
                for (var i = 1; getTrueLength(text) > 0; i++) {
                    var tl = cutString(text, bytelength);
                    ctx_2d.fillText(text.substr(0, tl).replace(/^\s+|\s+$/, ""), startleft, (i - 1) * lineheight +
                        starttop);
                    text = text.substr(tl);
                }
            },
            // 彻底改成同步 防止拿到的图片地址为空
            setTime(ctx) {
                return new Promise((resole, err) => {
                    setTimeout(() => {
                        ctx.draw(false, async () => {
                            let pic = await _this.getNewPic();
                            resole(pic)
                        });
                    }, 600)
                })
            },
            // 获取新的图片地址
            getNewPic() {
                return new Promise((resolve, errs) => {
                    setTimeout(() => {
                        uni.canvasToTempFilePath({
                            canvasId: _this.canvasID,
                            quality: 1,
                            complete: (res) => {
                                // 在H5平台下,tempFilePath 为 base64
                                // 关闭showLoading
                                uni.hideLoading();
                                //  储存海报地址  也是分享的地址
                                resolve(res.tempFilePath)
                            }
                        }, _this);
                    }, 200)
                })
            },
        },
        mounted() {
            _this = this;
        }
    }
</script>
components/qr_code/qrcode.js
对比新文件
@@ -0,0 +1,1362 @@
//---------------------------------------------------------------------
// github https://github.com/Sansnn/uQRCode
// version 2.0.2
//---------------------------------------------------------------------
let uQRCode = {};
(function() {
    //---------------------------------------------------------------------
    // QRCode for JavaScript
    //
    // Copyright (c) 2009 Kazuhiko Arase
    //
    // URL: http://www.d-project.com/
    //
    // Licensed under the MIT license:
    //   http://www.opensource.org/licenses/mit-license.php
    //
    // The word "QR Code" is registered trademark of
    // DENSO WAVE INCORPORATED
    //   http://www.denso-wave.com/qrcode/faqpatent-e.html
    //
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------
    // QR8bitByte
    //---------------------------------------------------------------------
    function QR8bitByte(data) {
        this.mode = QRMode.MODE_8BIT_BYTE;
        this.data = data;
    }
    QR8bitByte.prototype = {
        getLength: function(buffer) {
            return this.data.length;
        },
        write: function(buffer) {
            for (var i = 0; i < this.data.length; i++) {
                // not JIS ...
                buffer.put(this.data.charCodeAt(i), 8);
            }
        }
    };
    //---------------------------------------------------------------------
    // QRCode
    //---------------------------------------------------------------------
    function QRCode(typeNumber, errorCorrectLevel) {
        this.typeNumber = typeNumber;
        this.errorCorrectLevel = errorCorrectLevel;
        this.modules = null;
        this.moduleCount = 0;
        this.dataCache = null;
        this.dataList = new Array();
    }
    QRCode.prototype = {
        addData: function(data) {
            var newData = new QR8bitByte(data);
            this.dataList.push(newData);
            this.dataCache = null;
        },
        isDark: function(row, col) {
            if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
                throw new Error(row + "," + col);
            }
            return this.modules[row][col];
        },
        getModuleCount: function() {
            return this.moduleCount;
        },
        make: function() {
            // Calculate automatically typeNumber if provided is < 1
            if (this.typeNumber < 1) {
                var typeNumber = 1;
                for (typeNumber = 1; typeNumber < 40; typeNumber++) {
                    var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
                    var buffer = new QRBitBuffer();
                    var totalDataCount = 0;
                    for (var i = 0; i < rsBlocks.length; i++) {
                        totalDataCount += rsBlocks[i].dataCount;
                    }
                    for (var i = 0; i < this.dataList.length; i++) {
                        var data = this.dataList[i];
                        buffer.put(data.mode, 4);
                        buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
                        data.write(buffer);
                    }
                    if (buffer.getLengthInBits() <= totalDataCount * 8)
                        break;
                }
                this.typeNumber = typeNumber;
            }
            this.makeImpl(false, this.getBestMaskPattern());
        },
        makeImpl: function(test, maskPattern) {
            this.moduleCount = this.typeNumber * 4 + 17;
            this.modules = new Array(this.moduleCount);
            for (var row = 0; row < this.moduleCount; row++) {
                this.modules[row] = new Array(this.moduleCount);
                for (var col = 0; col < this.moduleCount; col++) {
                    this.modules[row][col] = null; //(col + row) % 3;
                }
            }
            this.setupPositionProbePattern(0, 0);
            this.setupPositionProbePattern(this.moduleCount - 7, 0);
            this.setupPositionProbePattern(0, this.moduleCount - 7);
            this.setupPositionAdjustPattern();
            this.setupTimingPattern();
            this.setupTypeInfo(test, maskPattern);
            if (this.typeNumber >= 7) {
                this.setupTypeNumber(test);
            }
            if (this.dataCache == null) {
                this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
            }
            this.mapData(this.dataCache, maskPattern);
        },
        setupPositionProbePattern: function(row, col) {
            for (var r = -1; r <= 7; r++) {
                if (row + r <= -1 || this.moduleCount <= row + r) continue;
                for (var c = -1; c <= 7; c++) {
                    if (col + c <= -1 || this.moduleCount <= col + c) continue;
                    if ((0 <= r && r <= 6 && (c == 0 || c == 6)) ||
                        (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
                        (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
                        this.modules[row + r][col + c] = true;
                    } else {
                        this.modules[row + r][col + c] = false;
                    }
                }
            }
        },
        getBestMaskPattern: function() {
            var minLostPoint = 0;
            var pattern = 0;
            for (var i = 0; i < 8; i++) {
                this.makeImpl(true, i);
                var lostPoint = QRUtil.getLostPoint(this);
                if (i == 0 || minLostPoint > lostPoint) {
                    minLostPoint = lostPoint;
                    pattern = i;
                }
            }
            return pattern;
        },
        createMovieClip: function(target_mc, instance_name, depth) {
            var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
            var cs = 1;
            this.make();
            for (var row = 0; row < this.modules.length; row++) {
                var y = row * cs;
                for (var col = 0; col < this.modules[row].length; col++) {
                    var x = col * cs;
                    var dark = this.modules[row][col];
                    if (dark) {
                        qr_mc.beginFill(0, 100);
                        qr_mc.moveTo(x, y);
                        qr_mc.lineTo(x + cs, y);
                        qr_mc.lineTo(x + cs, y + cs);
                        qr_mc.lineTo(x, y + cs);
                        qr_mc.endFill();
                    }
                }
            }
            return qr_mc;
        },
        setupTimingPattern: function() {
            for (var r = 8; r < this.moduleCount - 8; r++) {
                if (this.modules[r][6] != null) {
                    continue;
                }
                this.modules[r][6] = (r % 2 == 0);
            }
            for (var c = 8; c < this.moduleCount - 8; c++) {
                if (this.modules[6][c] != null) {
                    continue;
                }
                this.modules[6][c] = (c % 2 == 0);
            }
        },
        setupPositionAdjustPattern: function() {
            var pos = QRUtil.getPatternPosition(this.typeNumber);
            for (var i = 0; i < pos.length; i++) {
                for (var j = 0; j < pos.length; j++) {
                    var row = pos[i];
                    var col = pos[j];
                    if (this.modules[row][col] != null) {
                        continue;
                    }
                    for (var r = -2; r <= 2; r++) {
                        for (var c = -2; c <= 2; c++) {
                            if (r == -2 || r == 2 || c == -2 || c == 2 ||
                                (r == 0 && c == 0)) {
                                this.modules[row + r][col + c] = true;
                            } else {
                                this.modules[row + r][col + c] = false;
                            }
                        }
                    }
                }
            }
        },
        setupTypeNumber: function(test) {
            var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
            for (var i = 0; i < 18; i++) {
                var mod = (!test && ((bits >> i) & 1) == 1);
                this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
            }
            for (var i = 0; i < 18; i++) {
                var mod = (!test && ((bits >> i) & 1) == 1);
                this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
            }
        },
        setupTypeInfo: function(test, maskPattern) {
            var data = (this.errorCorrectLevel << 3) | maskPattern;
            var bits = QRUtil.getBCHTypeInfo(data);
            // vertical
            for (var i = 0; i < 15; i++) {
                var mod = (!test && ((bits >> i) & 1) == 1);
                if (i < 6) {
                    this.modules[i][8] = mod;
                } else if (i < 8) {
                    this.modules[i + 1][8] = mod;
                } else {
                    this.modules[this.moduleCount - 15 + i][8] = mod;
                }
            }
            // horizontal
            for (var i = 0; i < 15; i++) {
                var mod = (!test && ((bits >> i) & 1) == 1);
                if (i < 8) {
                    this.modules[8][this.moduleCount - i - 1] = mod;
                } else if (i < 9) {
                    this.modules[8][15 - i - 1 + 1] = mod;
                } else {
                    this.modules[8][15 - i - 1] = mod;
                }
            }
            // fixed module
            this.modules[this.moduleCount - 8][8] = (!test);
        },
        mapData: function(data, maskPattern) {
            var inc = -1;
            var row = this.moduleCount - 1;
            var bitIndex = 7;
            var byteIndex = 0;
            for (var col = this.moduleCount - 1; col > 0; col -= 2) {
                if (col == 6) col--;
                while (true) {
                    for (var c = 0; c < 2; c++) {
                        if (this.modules[row][col - c] == null) {
                            var dark = false;
                            if (byteIndex < data.length) {
                                dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
                            }
                            var mask = QRUtil.getMask(maskPattern, row, col - c);
                            if (mask) {
                                dark = !dark;
                            }
                            this.modules[row][col - c] = dark;
                            bitIndex--;
                            if (bitIndex == -1) {
                                byteIndex++;
                                bitIndex = 7;
                            }
                        }
                    }
                    row += inc;
                    if (row < 0 || this.moduleCount <= row) {
                        row -= inc;
                        inc = -inc;
                        break;
                    }
                }
            }
        }
    };
    QRCode.PAD0 = 0xEC;
    QRCode.PAD1 = 0x11;
    QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
        var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
        var buffer = new QRBitBuffer();
        for (var i = 0; i < dataList.length; i++) {
            var data = dataList[i];
            buffer.put(data.mode, 4);
            buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
            data.write(buffer);
        }
        // calc num max data.
        var totalDataCount = 0;
        for (var i = 0; i < rsBlocks.length; i++) {
            totalDataCount += rsBlocks[i].dataCount;
        }
        if (buffer.getLengthInBits() > totalDataCount * 8) {
            throw new Error("code length overflow. (" +
                buffer.getLengthInBits() +
                ">" +
                totalDataCount * 8 +
                ")");
        }
        // end code
        if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
            buffer.put(0, 4);
        }
        // padding
        while (buffer.getLengthInBits() % 8 != 0) {
            buffer.putBit(false);
        }
        // padding
        while (true) {
            if (buffer.getLengthInBits() >= totalDataCount * 8) {
                break;
            }
            buffer.put(QRCode.PAD0, 8);
            if (buffer.getLengthInBits() >= totalDataCount * 8) {
                break;
            }
            buffer.put(QRCode.PAD1, 8);
        }
        return QRCode.createBytes(buffer, rsBlocks);
    }
    QRCode.createBytes = function(buffer, rsBlocks) {
        var offset = 0;
        var maxDcCount = 0;
        var maxEcCount = 0;
        var dcdata = new Array(rsBlocks.length);
        var ecdata = new Array(rsBlocks.length);
        for (var r = 0; r < rsBlocks.length; r++) {
            var dcCount = rsBlocks[r].dataCount;
            var ecCount = rsBlocks[r].totalCount - dcCount;
            maxDcCount = Math.max(maxDcCount, dcCount);
            maxEcCount = Math.max(maxEcCount, ecCount);
            dcdata[r] = new Array(dcCount);
            for (var i = 0; i < dcdata[r].length; i++) {
                dcdata[r][i] = 0xff & buffer.buffer[i + offset];
            }
            offset += dcCount;
            var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
            var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
            var modPoly = rawPoly.mod(rsPoly);
            ecdata[r] = new Array(rsPoly.getLength() - 1);
            for (var i = 0; i < ecdata[r].length; i++) {
                var modIndex = i + modPoly.getLength() - ecdata[r].length;
                ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
            }
        }
        var totalCodeCount = 0;
        for (var i = 0; i < rsBlocks.length; i++) {
            totalCodeCount += rsBlocks[i].totalCount;
        }
        var data = new Array(totalCodeCount);
        var index = 0;
        for (var i = 0; i < maxDcCount; i++) {
            for (var r = 0; r < rsBlocks.length; r++) {
                if (i < dcdata[r].length) {
                    data[index++] = dcdata[r][i];
                }
            }
        }
        for (var i = 0; i < maxEcCount; i++) {
            for (var r = 0; r < rsBlocks.length; r++) {
                if (i < ecdata[r].length) {
                    data[index++] = ecdata[r][i];
                }
            }
        }
        return data;
    }
    //---------------------------------------------------------------------
    // QRMode
    //---------------------------------------------------------------------
    var QRMode = {
        MODE_NUMBER: 1 << 0,
        MODE_ALPHA_NUM: 1 << 1,
        MODE_8BIT_BYTE: 1 << 2,
        MODE_KANJI: 1 << 3
    };
    //---------------------------------------------------------------------
    // QRErrorCorrectLevel
    //---------------------------------------------------------------------
    var QRErrorCorrectLevel = {
        L: 1,
        M: 0,
        Q: 3,
        H: 2
    };
    //---------------------------------------------------------------------
    // QRMaskPattern
    //---------------------------------------------------------------------
    var QRMaskPattern = {
        PATTERN000: 0,
        PATTERN001: 1,
        PATTERN010: 2,
        PATTERN011: 3,
        PATTERN100: 4,
        PATTERN101: 5,
        PATTERN110: 6,
        PATTERN111: 7
    };
    //---------------------------------------------------------------------
    // QRUtil
    //---------------------------------------------------------------------
    var QRUtil = {
        PATTERN_POSITION_TABLE: [
            [],
            [6, 18],
            [6, 22],
            [6, 26],
            [6, 30],
            [6, 34],
            [6, 22, 38],
            [6, 24, 42],
            [6, 26, 46],
            [6, 28, 50],
            [6, 30, 54],
            [6, 32, 58],
            [6, 34, 62],
            [6, 26, 46, 66],
            [6, 26, 48, 70],
            [6, 26, 50, 74],
            [6, 30, 54, 78],
            [6, 30, 56, 82],
            [6, 30, 58, 86],
            [6, 34, 62, 90],
            [6, 28, 50, 72, 94],
            [6, 26, 50, 74, 98],
            [6, 30, 54, 78, 102],
            [6, 28, 54, 80, 106],
            [6, 32, 58, 84, 110],
            [6, 30, 58, 86, 114],
            [6, 34, 62, 90, 118],
            [6, 26, 50, 74, 98, 122],
            [6, 30, 54, 78, 102, 126],
            [6, 26, 52, 78, 104, 130],
            [6, 30, 56, 82, 108, 134],
            [6, 34, 60, 86, 112, 138],
            [6, 30, 58, 86, 114, 142],
            [6, 34, 62, 90, 118, 146],
            [6, 30, 54, 78, 102, 126, 150],
            [6, 24, 50, 76, 102, 128, 154],
            [6, 28, 54, 80, 106, 132, 158],
            [6, 32, 58, 84, 110, 136, 162],
            [6, 26, 54, 82, 110, 138, 166],
            [6, 30, 58, 86, 114, 142, 170]
        ],
        G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
        G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
        G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
        getBCHTypeInfo: function(data) {
            var d = data << 10;
            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
                d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
            }
            return ((data << 10) | d) ^ QRUtil.G15_MASK;
        },
        getBCHTypeNumber: function(data) {
            var d = data << 12;
            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
                d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
            }
            return (data << 12) | d;
        },
        getBCHDigit: function(data) {
            var digit = 0;
            while (data != 0) {
                digit++;
                data >>>= 1;
            }
            return digit;
        },
        getPatternPosition: function(typeNumber) {
            return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
        },
        getMask: function(maskPattern, i, j) {
            switch (maskPattern) {
                case QRMaskPattern.PATTERN000:
                    return (i + j) % 2 == 0;
                case QRMaskPattern.PATTERN001:
                    return i % 2 == 0;
                case QRMaskPattern.PATTERN010:
                    return j % 3 == 0;
                case QRMaskPattern.PATTERN011:
                    return (i + j) % 3 == 0;
                case QRMaskPattern.PATTERN100:
                    return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
                case QRMaskPattern.PATTERN101:
                    return (i * j) % 2 + (i * j) % 3 == 0;
                case QRMaskPattern.PATTERN110:
                    return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
                case QRMaskPattern.PATTERN111:
                    return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
                default:
                    throw new Error("bad maskPattern:" + maskPattern);
            }
        },
        getErrorCorrectPolynomial: function(errorCorrectLength) {
            var a = new QRPolynomial([1], 0);
            for (var i = 0; i < errorCorrectLength; i++) {
                a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
            }
            return a;
        },
        getLengthInBits: function(mode, type) {
            if (1 <= type && type < 10) {
                // 1 - 9
                switch (mode) {
                    case QRMode.MODE_NUMBER:
                        return 10;
                    case QRMode.MODE_ALPHA_NUM:
                        return 9;
                    case QRMode.MODE_8BIT_BYTE:
                        return 8;
                    case QRMode.MODE_KANJI:
                        return 8;
                    default:
                        throw new Error("mode:" + mode);
                }
            } else if (type < 27) {
                // 10 - 26
                switch (mode) {
                    case QRMode.MODE_NUMBER:
                        return 12;
                    case QRMode.MODE_ALPHA_NUM:
                        return 11;
                    case QRMode.MODE_8BIT_BYTE:
                        return 16;
                    case QRMode.MODE_KANJI:
                        return 10;
                    default:
                        throw new Error("mode:" + mode);
                }
            } else if (type < 41) {
                // 27 - 40
                switch (mode) {
                    case QRMode.MODE_NUMBER:
                        return 14;
                    case QRMode.MODE_ALPHA_NUM:
                        return 13;
                    case QRMode.MODE_8BIT_BYTE:
                        return 16;
                    case QRMode.MODE_KANJI:
                        return 12;
                    default:
                        throw new Error("mode:" + mode);
                }
            } else {
                throw new Error("type:" + type);
            }
        },
        getLostPoint: function(qrCode) {
            var moduleCount = qrCode.getModuleCount();
            var lostPoint = 0;
            // LEVEL1
            for (var row = 0; row < moduleCount; row++) {
                for (var col = 0; col < moduleCount; col++) {
                    var sameCount = 0;
                    var dark = qrCode.isDark(row, col);
                    for (var r = -1; r <= 1; r++) {
                        if (row + r < 0 || moduleCount <= row + r) {
                            continue;
                        }
                        for (var c = -1; c <= 1; c++) {
                            if (col + c < 0 || moduleCount <= col + c) {
                                continue;
                            }
                            if (r == 0 && c == 0) {
                                continue;
                            }
                            if (dark == qrCode.isDark(row + r, col + c)) {
                                sameCount++;
                            }
                        }
                    }
                    if (sameCount > 5) {
                        lostPoint += (3 + sameCount - 5);
                    }
                }
            }
            // LEVEL2
            for (var row = 0; row < moduleCount - 1; row++) {
                for (var col = 0; col < moduleCount - 1; col++) {
                    var count = 0;
                    if (qrCode.isDark(row, col)) count++;
                    if (qrCode.isDark(row + 1, col)) count++;
                    if (qrCode.isDark(row, col + 1)) count++;
                    if (qrCode.isDark(row + 1, col + 1)) count++;
                    if (count == 0 || count == 4) {
                        lostPoint += 3;
                    }
                }
            }
            // LEVEL3
            for (var row = 0; row < moduleCount; row++) {
                for (var col = 0; col < moduleCount - 6; col++) {
                    if (qrCode.isDark(row, col) &&
                        !qrCode.isDark(row, col + 1) &&
                        qrCode.isDark(row, col + 2) &&
                        qrCode.isDark(row, col + 3) &&
                        qrCode.isDark(row, col + 4) &&
                        !qrCode.isDark(row, col + 5) &&
                        qrCode.isDark(row, col + 6)) {
                        lostPoint += 40;
                    }
                }
            }
            for (var col = 0; col < moduleCount; col++) {
                for (var row = 0; row < moduleCount - 6; row++) {
                    if (qrCode.isDark(row, col) &&
                        !qrCode.isDark(row + 1, col) &&
                        qrCode.isDark(row + 2, col) &&
                        qrCode.isDark(row + 3, col) &&
                        qrCode.isDark(row + 4, col) &&
                        !qrCode.isDark(row + 5, col) &&
                        qrCode.isDark(row + 6, col)) {
                        lostPoint += 40;
                    }
                }
            }
            // LEVEL4
            var darkCount = 0;
            for (var col = 0; col < moduleCount; col++) {
                for (var row = 0; row < moduleCount; row++) {
                    if (qrCode.isDark(row, col)) {
                        darkCount++;
                    }
                }
            }
            var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
            lostPoint += ratio * 10;
            return lostPoint;
        }
    };
    //---------------------------------------------------------------------
    // QRMath
    //---------------------------------------------------------------------
    var QRMath = {
        glog: function(n) {
            if (n < 1) {
                throw new Error("glog(" + n + ")");
            }
            return QRMath.LOG_TABLE[n];
        },
        gexp: function(n) {
            while (n < 0) {
                n += 255;
            }
            while (n >= 256) {
                n -= 255;
            }
            return QRMath.EXP_TABLE[n];
        },
        EXP_TABLE: new Array(256),
        LOG_TABLE: new Array(256)
    };
    for (var i = 0; i < 8; i++) {
        QRMath.EXP_TABLE[i] = 1 << i;
    }
    for (var i = 8; i < 256; i++) {
        QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^
            QRMath.EXP_TABLE[i - 5] ^
            QRMath.EXP_TABLE[i - 6] ^
            QRMath.EXP_TABLE[i - 8];
    }
    for (var i = 0; i < 255; i++) {
        QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
    }
    //---------------------------------------------------------------------
    // QRPolynomial
    //---------------------------------------------------------------------
    function QRPolynomial(num, shift) {
        if (num.length == undefined) {
            throw new Error(num.length + "/" + shift);
        }
        var offset = 0;
        while (offset < num.length && num[offset] == 0) {
            offset++;
        }
        this.num = new Array(num.length - offset + shift);
        for (var i = 0; i < num.length - offset; i++) {
            this.num[i] = num[i + offset];
        }
    }
    QRPolynomial.prototype = {
        get: function(index) {
            return this.num[index];
        },
        getLength: function() {
            return this.num.length;
        },
        multiply: function(e) {
            var num = new Array(this.getLength() + e.getLength() - 1);
            for (var i = 0; i < this.getLength(); i++) {
                for (var j = 0; j < e.getLength(); j++) {
                    num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
                }
            }
            return new QRPolynomial(num, 0);
        },
        mod: function(e) {
            if (this.getLength() - e.getLength() < 0) {
                return this;
            }
            var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
            var num = new Array(this.getLength());
            for (var i = 0; i < this.getLength(); i++) {
                num[i] = this.get(i);
            }
            for (var i = 0; i < e.getLength(); i++) {
                num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
            }
            // recursive call
            return new QRPolynomial(num, 0).mod(e);
        }
    };
    //---------------------------------------------------------------------
    // QRRSBlock
    //---------------------------------------------------------------------
    function QRRSBlock(totalCount, dataCount) {
        this.totalCount = totalCount;
        this.dataCount = dataCount;
    }
    QRRSBlock.RS_BLOCK_TABLE = [
        // L
        // M
        // Q
        // H
        // 1
        [1, 26, 19],
        [1, 26, 16],
        [1, 26, 13],
        [1, 26, 9],
        // 2
        [1, 44, 34],
        [1, 44, 28],
        [1, 44, 22],
        [1, 44, 16],
        // 3
        [1, 70, 55],
        [1, 70, 44],
        [2, 35, 17],
        [2, 35, 13],
        // 4
        [1, 100, 80],
        [2, 50, 32],
        [2, 50, 24],
        [4, 25, 9],
        // 5
        [1, 134, 108],
        [2, 67, 43],
        [2, 33, 15, 2, 34, 16],
        [2, 33, 11, 2, 34, 12],
        // 6
        [2, 86, 68],
        [4, 43, 27],
        [4, 43, 19],
        [4, 43, 15],
        // 7
        [2, 98, 78],
        [4, 49, 31],
        [2, 32, 14, 4, 33, 15],
        [4, 39, 13, 1, 40, 14],
        // 8
        [2, 121, 97],
        [2, 60, 38, 2, 61, 39],
        [4, 40, 18, 2, 41, 19],
        [4, 40, 14, 2, 41, 15],
        // 9
        [2, 146, 116],
        [3, 58, 36, 2, 59, 37],
        [4, 36, 16, 4, 37, 17],
        [4, 36, 12, 4, 37, 13],
        // 10
        [2, 86, 68, 2, 87, 69],
        [4, 69, 43, 1, 70, 44],
        [6, 43, 19, 2, 44, 20],
        [6, 43, 15, 2, 44, 16],
        // 11
        [4, 101, 81],
        [1, 80, 50, 4, 81, 51],
        [4, 50, 22, 4, 51, 23],
        [3, 36, 12, 8, 37, 13],
        // 12
        [2, 116, 92, 2, 117, 93],
        [6, 58, 36, 2, 59, 37],
        [4, 46, 20, 6, 47, 21],
        [7, 42, 14, 4, 43, 15],
        // 13
        [4, 133, 107],
        [8, 59, 37, 1, 60, 38],
        [8, 44, 20, 4, 45, 21],
        [12, 33, 11, 4, 34, 12],
        // 14
        [3, 145, 115, 1, 146, 116],
        [4, 64, 40, 5, 65, 41],
        [11, 36, 16, 5, 37, 17],
        [11, 36, 12, 5, 37, 13],
        // 15
        [5, 109, 87, 1, 110, 88],
        [5, 65, 41, 5, 66, 42],
        [5, 54, 24, 7, 55, 25],
        [11, 36, 12],
        // 16
        [5, 122, 98, 1, 123, 99],
        [7, 73, 45, 3, 74, 46],
        [15, 43, 19, 2, 44, 20],
        [3, 45, 15, 13, 46, 16],
        // 17
        [1, 135, 107, 5, 136, 108],
        [10, 74, 46, 1, 75, 47],
        [1, 50, 22, 15, 51, 23],
        [2, 42, 14, 17, 43, 15],
        // 18
        [5, 150, 120, 1, 151, 121],
        [9, 69, 43, 4, 70, 44],
        [17, 50, 22, 1, 51, 23],
        [2, 42, 14, 19, 43, 15],
        // 19
        [3, 141, 113, 4, 142, 114],
        [3, 70, 44, 11, 71, 45],
        [17, 47, 21, 4, 48, 22],
        [9, 39, 13, 16, 40, 14],
        // 20
        [3, 135, 107, 5, 136, 108],
        [3, 67, 41, 13, 68, 42],
        [15, 54, 24, 5, 55, 25],
        [15, 43, 15, 10, 44, 16],
        // 21
        [4, 144, 116, 4, 145, 117],
        [17, 68, 42],
        [17, 50, 22, 6, 51, 23],
        [19, 46, 16, 6, 47, 17],
        // 22
        [2, 139, 111, 7, 140, 112],
        [17, 74, 46],
        [7, 54, 24, 16, 55, 25],
        [34, 37, 13],
        // 23
        [4, 151, 121, 5, 152, 122],
        [4, 75, 47, 14, 76, 48],
        [11, 54, 24, 14, 55, 25],
        [16, 45, 15, 14, 46, 16],
        // 24
        [6, 147, 117, 4, 148, 118],
        [6, 73, 45, 14, 74, 46],
        [11, 54, 24, 16, 55, 25],
        [30, 46, 16, 2, 47, 17],
        // 25
        [8, 132, 106, 4, 133, 107],
        [8, 75, 47, 13, 76, 48],
        [7, 54, 24, 22, 55, 25],
        [22, 45, 15, 13, 46, 16],
        // 26
        [10, 142, 114, 2, 143, 115],
        [19, 74, 46, 4, 75, 47],
        [28, 50, 22, 6, 51, 23],
        [33, 46, 16, 4, 47, 17],
        // 27
        [8, 152, 122, 4, 153, 123],
        [22, 73, 45, 3, 74, 46],
        [8, 53, 23, 26, 54, 24],
        [12, 45, 15, 28, 46, 16],
        // 28
        [3, 147, 117, 10, 148, 118],
        [3, 73, 45, 23, 74, 46],
        [4, 54, 24, 31, 55, 25],
        [11, 45, 15, 31, 46, 16],
        // 29
        [7, 146, 116, 7, 147, 117],
        [21, 73, 45, 7, 74, 46],
        [1, 53, 23, 37, 54, 24],
        [19, 45, 15, 26, 46, 16],
        // 30
        [5, 145, 115, 10, 146, 116],
        [19, 75, 47, 10, 76, 48],
        [15, 54, 24, 25, 55, 25],
        [23, 45, 15, 25, 46, 16],
        // 31
        [13, 145, 115, 3, 146, 116],
        [2, 74, 46, 29, 75, 47],
        [42, 54, 24, 1, 55, 25],
        [23, 45, 15, 28, 46, 16],
        // 32
        [17, 145, 115],
        [10, 74, 46, 23, 75, 47],
        [10, 54, 24, 35, 55, 25],
        [19, 45, 15, 35, 46, 16],
        // 33
        [17, 145, 115, 1, 146, 116],
        [14, 74, 46, 21, 75, 47],
        [29, 54, 24, 19, 55, 25],
        [11, 45, 15, 46, 46, 16],
        // 34
        [13, 145, 115, 6, 146, 116],
        [14, 74, 46, 23, 75, 47],
        [44, 54, 24, 7, 55, 25],
        [59, 46, 16, 1, 47, 17],
        // 35
        [12, 151, 121, 7, 152, 122],
        [12, 75, 47, 26, 76, 48],
        [39, 54, 24, 14, 55, 25],
        [22, 45, 15, 41, 46, 16],
        // 36
        [6, 151, 121, 14, 152, 122],
        [6, 75, 47, 34, 76, 48],
        [46, 54, 24, 10, 55, 25],
        [2, 45, 15, 64, 46, 16],
        // 37
        [17, 152, 122, 4, 153, 123],
        [29, 74, 46, 14, 75, 47],
        [49, 54, 24, 10, 55, 25],
        [24, 45, 15, 46, 46, 16],
        // 38
        [4, 152, 122, 18, 153, 123],
        [13, 74, 46, 32, 75, 47],
        [48, 54, 24, 14, 55, 25],
        [42, 45, 15, 32, 46, 16],
        // 39
        [20, 147, 117, 4, 148, 118],
        [40, 75, 47, 7, 76, 48],
        [43, 54, 24, 22, 55, 25],
        [10, 45, 15, 67, 46, 16],
        // 40
        [19, 148, 118, 6, 149, 119],
        [18, 75, 47, 31, 76, 48],
        [34, 54, 24, 34, 55, 25],
        [20, 45, 15, 61, 46, 16]
    ];
    QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
        var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
        if (rsBlock == undefined) {
            throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" +
                errorCorrectLevel);
        }
        var length = rsBlock.length / 3;
        var list = new Array();
        for (var i = 0; i < length; i++) {
            var count = rsBlock[i * 3 + 0];
            var totalCount = rsBlock[i * 3 + 1];
            var dataCount = rsBlock[i * 3 + 2];
            for (var j = 0; j < count; j++) {
                list.push(new QRRSBlock(totalCount, dataCount));
            }
        }
        return list;
    }
    QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
        switch (errorCorrectLevel) {
            case QRErrorCorrectLevel.L:
                return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
            case QRErrorCorrectLevel.M:
                return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
            case QRErrorCorrectLevel.Q:
                return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
            case QRErrorCorrectLevel.H:
                return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
            default:
                return undefined;
        }
    }
    //---------------------------------------------------------------------
    // QRBitBuffer
    //---------------------------------------------------------------------
    function QRBitBuffer() {
        this.buffer = new Array();
        this.length = 0;
    }
    QRBitBuffer.prototype = {
        get: function(index) {
            var bufIndex = Math.floor(index / 8);
            return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
        },
        put: function(num, length) {
            for (var i = 0; i < length; i++) {
                this.putBit(((num >>> (length - i - 1)) & 1) == 1);
            }
        },
        getLengthInBits: function() {
            return this.length;
        },
        putBit: function(bit) {
            var bufIndex = Math.floor(this.length / 8);
            if (this.buffer.length <= bufIndex) {
                this.buffer.push(0);
            }
            if (bit) {
                this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
            }
            this.length++;
        }
    };
    //---------------------------------------------------------------------
    // Support Chinese
    //---------------------------------------------------------------------
    function utf16To8(text) {
        var result = '';
        var c;
        for (var i = 0; i < text.length; i++) {
            c = text.charCodeAt(i);
            if (c >= 0x0001 && c <= 0x007F) {
                result += text.charAt(i);
            } else if (c > 0x07FF) {
                result += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
                result += String.fromCharCode(0x80 | c >> 6 & 0x3F);
                result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
            } else {
                result += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
                result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
            }
        }
        return result;
    }
    uQRCode = {
        errorCorrectLevel: QRErrorCorrectLevel,
        defaults: {
            size: 354,
            margin: 0,
            backgroundColor: '#ffffff',
            foregroundColor: '#000000',
            fileType: 'png', // 'jpg', 'png'
            errorCorrectLevel: QRErrorCorrectLevel.H,
            typeNumber: -1,
            enableDelay: false // 启用延迟绘制
        },
        getModules: function(options) {
            options = Object.assign(this.defaults, options);
            var qrcode = new QRCode(options.typeNumber, options.errorCorrectLevel);
            qrcode.addData(utf16To8(options.text));
            qrcode.make();
            return qrcode.modules;
        },
        make: function(options, componentInstance) {
            return new Promise((reslove, reject) => {
                options = Object.assign(this.defaults, options);
                if (!options.canvasId) {
                    throw new Error('uQRCode: Please set canvasId!');
                }
                var modules = this.getModules(options);
                var tileW = (options.size - options.margin * 2) / modules.length;
                var tileH = tileW;
                var delay = 0;
                var ctx = uni.createCanvasContext(options.canvasId, componentInstance);
                ctx.setFillStyle(options.backgroundColor);
                ctx.fillRect(0, 0, options.size, options.size);
                for (var row = 0; row < modules.length; row++) {
                    for (var col = 0; col < modules.length; col++) {
                        delay = options.enableDelay ? row * modules.length + col + 1 : 0;
                        setTimeout(function(row, col) {
                            // 计算每一个小块的位置
                            var x = Math.round(col * tileW) + options.margin;
                            var y = Math.round(row * tileH) + options.margin;
                            var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
                            var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
                            var style = modules[row][col] ? options.foregroundColor :
                                options.backgroundColor;
                            ctx.setFillStyle(style);
                            ctx.fillRect(x, y, w, h);
                        }, delay, row, col);
                    }
                }
                // 耗时
                var time = options.enableDelay ? delay + options.size * 2 + options.margin * 2 + options.text.length : 0;
                setTimeout(function() {
                    ctx.draw(false, function() {
                        uni.canvasToTempFilePath({
                            canvasId: options.canvasId,
                            fileType: options.fileType,
                            width: options.size,
                            height: options.size,
                            destWidth: options.size,
                            destHeight: options.size,
                            success: function(res) {
                                reslove(Object.assign(res, {
                                    time
                                }));
                            },
                            fail: function(err) {
                                reject(err);
                            }
                        }, componentInstance);
                    });
                }, time);
            });
        }
    }
})();
export default uQRCode;
components/qr_code/qrcode.vue
对比新文件
@@ -0,0 +1,27 @@
<template>
    <view class="qrcode">
        <canvas id="qrcode" canvas-id="qrcode" :style="{'width': `${options.size}px`, 'height': `${options.size}px`}" />
    </view>
</template>
<script>
    import qrcode from './qrcode'
    export default {
        name: 'qrcode',
        data() {
            return {
                options: {
                    canvasId: 'qrcode',
                    size: 354,
                    margin: 10,
                    text: ''
                }
            }
        },
        methods: {
            make(options) {
                return qrcode.make(Object.assign(this.options, options), this)
            }
        }
    }
</script>
pages/home/home.vue
@@ -184,7 +184,13 @@
        //     };
        // },
        onLoad() {
        onLoad(options) {
            // if(options.partnerUserId){
            //     //需要前往注册了
            //     uni.navigateTo({
            //         url: '/pages/login/supplier-login'
            //     })
            // }
            // console.log('home created')
            //这里进行一次初始化即可
            // this.$http.request('get', '/api/school/area/list', {
pages/login/supplier-login.vue
@@ -50,8 +50,10 @@
                    <button @tap="login()" class="bottom-button">登 录</button>
                    <view class="flex">
                        <view class="topic-font" v-if="loginType=='pwd'&&apitype!=='loginAdmin'" @click="loginType='code'">手机验证码登录</view>
                        <view class="topic-font" v-if="loginType=='code'&&apitype!=='loginAdmin'" @click="loginType='pwd'">账号密码登录</view>
                        <view class="topic-font" v-if="loginType=='pwd'&&apitype!=='loginAdmin'"
                            @click="loginType='code'">手机验证码登录</view>
                        <view class="topic-font" v-if="loginType=='code'&&apitype!=='loginAdmin'"
                            @click="loginType='pwd'">账号密码登录</view>
                        <view class="topic-font m-l-a m-r-0" v-if="apitype!=='loginAdmin'" @click="toReg">前往注册</view>
@@ -61,7 +63,7 @@
                        <!-- #ifdef PUB_PARTNER -->
                        <view class="topic-font m-l-a m-r-0" @click="()=>{
                            if(apitype==='loginPartner'){
                                apitype = 'loginAdmin'
                                apitype = 'loginAdmin'
                                loginType = 'pwd'
                            }else{
                                apitype = 'loginPartner'
@@ -78,28 +80,78 @@
    </view>
</template>
<script>
    // import util from '@/utils/util.js'
    // import gzmzApi from '@/api/gzmzApi.js'
    // import myCache from '@/utils/myCache.js'
    export default {
        // props: {
        //     // apitype: 'loginSupplier',
        //     apitype: {
        //         type: String,
        //         default () {
        //             // #ifdef PUB_SUPPLIER
        //             return 'loginSupplier'
        //             // #endif
        //             // #ifdef PUB_PARTNER
        //             return 'loginPartner'
        //             // #endif
        //             // #ifdef PUB_CUSTOMER
        //             return 'loginCustomer'
        //             // #endif
        //             // return 'loginPartner'
        //         }
        //     },
        // },
        onLoad(options) {
            // #ifdef PUB_CUSTOMER
            if (options.partnerUserId) {
                if (this.$storage.getItem('token')) {
                    this.$message.showLoading()
                    //稍微等一会,避免currentInfo还在同步
                    let tmp = this
                    setTimeout(() => {
                        tmp.$message.hideLoading()
                        if (tmp.currentInfo.id || tmp.$storage.getItem('token')) {
                            //这种已经登录的
                            //确定是注册绑定还是重新绑定
                            var t = {
                                title: '提示,您已登录,是否退出并注册绑定合伙人',
                                content: '',
                                showCancel: true,
                                cancelText: '使用当前账号绑定合伙人',
                                cancelColor: '#000000',
                                confirmText: '退出当前账号并注册、绑定',
                                confirmColor: '#20613D'
                            }
                            uni.showModal({
                                ...t,
                                success: (res) => {
                                    if (res.confirm) {
                                        //清空登录信息,
                                        this.$store.commit('updateLogin', false)
                                        setTimeout(() => {
                                            uni.navigateTo({
                                                url: `/sub_pages/customer/customer-info/customer-info?source=step&partnerUserId=${options.partnerUserId}&partnerUserName=${options.partnerUserName}`
                                            })
                                        }, 200)
                                    }
                                    if (res.cancel) {
                                        if (!tmp.currentInfo.customer) {
                                            tmp.$message.showToast('您尚未完善信息无法绑定')
                                            return
                                        } else {
                                            if (tmp.currentInfo.customer.partnerId) {
                                                tmp.$message.showToast('您已绑定,请联系客服解除绑定')
                                                return
                                            } else {
                                                //前往绑定页面
                                                uni.reLaunch({
                                                    url: `/pages/user/supplier-user?partnerUserId=${options.partnerUserId}&partnerUserName=${options.partnerUserName}`
                                                })
                                            }
                                        }
                                    }
                                }
                            })
                        } else {
                            //退出登录了,或者失效了
                            uni.navigateTo({
                                url: `/sub_pages/customer/customer-info/customer-info?source=step&partnerUserId=${options.partnerUserId}&partnerUserName=${options.partnerUserName}`
                            })
                        }
                    }, 2000)
                } else {
                    uni.navigateTo({
                        url: `/sub_pages/customer/customer-info/customer-info?source=step&partnerUserId=${options.partnerUserId}&partnerUserName=${options.partnerUserName}`
                    })
                }
            }
            // #endif
        },
        data() {
            return {
                openId: '-1',
@@ -243,7 +295,7 @@
                            icon: 'none'
                        });
                        return;
                    }
                    }
                    that.phoneNumber = ''
                }
                if (this.loginType == 'code') {
pages/login/supplier-reg.vue
@@ -142,6 +142,17 @@
        },
        onLoad(options) {
            this.source = options.source || ''
            // #ifdef PUB_CUSTOMER
            var tjson = this.$storage.getItem('cache_customer_info')
            if (tjson) {
                var dto = JSON.parse(tjson)
                if (dto.partnerUserId) {
                    this.partnerId = dto.partnerUserId || ''
                    this.partnerName = dto.partnerUserName || '佚名'
                }
            }
            // #endif
        },
        methods: {
            async scanPartnerCode() {
@@ -153,7 +164,23 @@
                        console.log('条码内容:' + res.result);
                        var dto = undefined
                        try {
                            dto = JSON.parse(res.result)
                            if (res.result && res.result.startsWith('http://') && res.result.indexOf(
                                    'partnerUserId') >= 0) {
                                var arr = res.result.split("?")[1].split("&")
                                dto = {}
                                for (var item of arr) {
                                    var tarr = item.split("=")
                                    if (tarr[1]) {
                                        dto[tarr[0]] = dto[tarr[1]]
                                    }
                                }
                                dto['name'] = dto['partnerUserName'] || dto['partnerUserId'] || '佚名'
                                dto['userId'] = dto['partnerUserId'] || ''
                            } else {
                                dto = JSON.parse(res.result)
                            }
                            if (!!dto['userId']) {
                                that.partnerName = dto['name'] || ''
                                that.partnerId = dto['userId'] || ''
pages/user/supplier-user.vue
@@ -179,13 +179,13 @@
                <view class="right-icon">
                    <uni-icons type="right"></uni-icons>
                </view>
            </view>
        <!--     <view class="user-util m-t-12 flex" v-if="selftype==='partner'"
                @click="goto('/sub_pages/partner/partner-info/partner-code-v2',true)">
                <view class="title">测试二维码</view>
                <view class="right-icon">
                    <uni-icons type="right"></uni-icons>
                </view>
            </view>
        <!--     <view class="user-util m-t-12 flex" v-if="selftype==='partner'"
                @click="goto('/sub_pages/partner/partner-info/partner-code-v2',true)">
                <view class="title">测试二维码</view>
                <view class="right-icon">
                    <uni-icons type="right"></uni-icons>
                </view>
            </view> -->
            <!-- #endif -->
            <!-- #ifdef PUB_CUSTOMER -->
@@ -343,7 +343,11 @@
        onLoad(options) {
            // const url = options.q ? decodeURIComponent(options.q) : '';
            // const urlcode = options.url && decodeURIComponent(options.url) || ''
            // #ifdef PUB_CUSTOMER
            if (options.partnerUserId) {
                this.bindPartnerUser(options.partnerUserId, options.partnerUserName)
            }
            // #endif
        },
@@ -355,8 +359,25 @@
            uni.stopPullDownRefresh()
        },
        methods: {
            async bindPartnerUser(userId, name) {
                await this.$message.confirm(`确定要绑定${name}合伙人吗?`)
                //调用接口绑定
                this.$message.showLoading()
                const {
                    code,
                    data
                } = await this.$http.request('post', '/api/customer/bind/partner', {
                    data: {
                        partnerUserId: userId
                    }
                })
                this.$message.hideLoading()
                if (code == 0) {
                    this.$message.showToast(`绑定合伙人${name}成功`)
                    await this.$store.dispatch('getCurrentInfo')
                }
            },
            async scanPartnerCode() {
                await this.$message.confirm('确定要绑定合伙人吗?')
                //扫二维码确认
                let that = this
                uni.scanCode({
@@ -364,31 +385,28 @@
                        console.log('条码内容:' + res.result);
                        var dto = undefined
                        try {
                            dto = JSON.parse(res.result)
                            if (res.result && res.result.startsWith('http://') && res.result.indexOf(
                                    'partnerUserId') >= 0) {
                                var arr = res.result.split("?")[1].split("&")
                                dto = {}
                                for (var item of arr) {
                                    var tarr = item.split("=")
                                    if (tarr[1]) {
                                        dto[tarr[0]] = dto[tarr[1]]
                                    }
                                }
                                dto['name'] = dto['partnerUserName'] || dto['partnerUserId'] || '佚名'
                                dto['userId'] = dto['partnerUserId'] || ''
                            } else {
                                dto = JSON.parse(res.result)
                            }
                            if (!!dto['userId']) {
                                var partnerName = dto['name'] || ''
                                var partnerId = dto['userId'] || ''
                                //调用接口绑定
                                that.$message.showLoading()
                                const {
                                    code,
                                    data
                                } = await that.$http.request('post', '/api/customer/bind/partner', {
                                    data: {
                                        partnerUserId: partnerId
                                    }
                                })
                                that.$message.hideLoading()
                                if (code == 0) {
                                    that.$message.showToast(`绑定合伙人${partnerName}成功`)
                                    await that.$store.dispatch('getCurrentInfo')
                                that.bindPartnerUser(partnerId, partnerName)
                                    // setTimeout(async () => {
                                    //     that.$message.showLoading()
                                    //     that.$message.hideLoading()
                                    // }, 1000)
                                }
                            } else {
                                that.$message.showToast('二维码格式不正确扫码失败')
                            }
@@ -402,6 +420,8 @@
                    }
                });
            },
            toInfo() {
                var url = ''
                if (this.currentInfo.id) {
store/index.js
@@ -40,6 +40,7 @@
            console.log('updateLogin', provider)
            state.hasLogin = provider && true || false;
            if (!state.hasLogin) {
                state.currentInfo = {}
                storage.removeItem('token')
            }
        },
@@ -53,15 +54,9 @@
            state.currentInfo = {}
            storage.removeItem('token')
            message.showToast('退出登录成功')
            // #ifdef APP
            var KeepAliveModule = uni.requireNativePlugin("yh-nl") //保活组件
            let ret = KeepAliveModule.stopLocation();
            console.log('ret', ret)
            // #endif
            uni.redirectTo({
                url: '/views/login/login'
            })
            // uni.redirectTo({
            //     url: '/views/login/login'
            // })
        },
        setOpenid(state, openid) {
            state.openid = openid
sub_pages/customer/customer-info/customer-info.vue
@@ -138,6 +138,12 @@
                        ...JSON.parse(tjson)
                    }
                }
                if(options.partnerUserId){
                    this.dto.partnerUserId = options.partnerUserId || ''
                }
                if(options.partnerUserName){
                    this.dto.partnerUserName = options.partnerUserName || ''
                }
            } else {
                this.getCurrentInfo()
            }
sub_pages/partner/partner-info/partner-code-v2.vue
@@ -1,688 +1,112 @@
<template>
    <view class="product-detail-page">
        <scroll-view enable-back-to-top scroll-y="true" class="product-detail-page__scroll">
            <view class="product-detail-page__scroll__swiper" v-if="info.ImageUrlList&&info.ImageUrlList.length>0">
                <swiper @change="onSwiperChange" :current="currentIndex" class="product-detail-page__scroll__swiper__target">
                    <swiper-item class="product-detail-page__scroll__swiper__target__item" v-for="(item,index) in info.ImageUrlList"
                     :key="index">
                        <image mode="aspectFit" :src="item" class="product-detail-page__scroll__swiper__target__item__img" lazy-load></image>
                    </swiper-item>
                </swiper>
                <view class="product-detail-page__scroll__swiper__page">{{currentIndex+1}}/{{info.ImageUrlList.length}}</view>
                <button v-if="info.Id" @click="shareDetail" class="evan-share">
                    <image src="/static/images/common/share_icon.png" class="evan-share__icon"></image>
                    <view class="evan-share__text">分享</view>
                </button>
            </view>
            <image v-else mode="aspectFill" class="product-detail-page__scroll__default-image" src="/static/images/common/default_image_horizontal.png"></image>
            <view class="product-detail-page__scroll__info">
                <view class="product-detail-page__scroll__info__title">{{info.Name||''}}</view>
                <view class="product-detail-page__scroll__info__desc">{{info.Introduction||''}}</view>
                <!-- <view class="product-detail-page__scroll__info__bulter">管家提成比例:</view> -->
                <view class="product-detail-page__scroll__info__tags">
                    <view class="product-detail-page__scroll__info__tags__item" v-for="(item,index) in tags" :key="index">
                        <image class="product-detail-page__scroll__info__tags__item__icon" :src="item.icon"></image>
                        <view class="product-detail-page__scroll__info__tags__item__text">{{item.text}}</view>
                    </view>
                    <view v-if="!isGroup" class="product-detail-page__scroll__info__tags__count">已售{{info.SaleCount||0}}</view>
                </view>
            </view>
            <view class="product-detail-page__scroll__team" v-if="isGroup">
                <view class="product-detail-page__scroll__team__title">批购进度及商品价格区间</view>
                <view class="product-detail-page__scroll__team__main">
                    <view v-if="!info.GroupRules||info.GroupRules.length===0" class="product-detail-page__scroll__team__main__progress"></view>
                    <view v-else class="product-detail-page__scroll__team__main__progress">
                        <view class="product-detail-page__scroll__team__main__progress__active" :style="{width:getPercent()+'rpx'}"></view>
                    </view>
            <!--         <template v-if="info.GroupRules&&info.GroupRules.length>0">
                        <view v-for="(item,index) in info.GroupRules" :key="index" class="product-detail-page__scroll__team__main__price"
                         :style="{top:'80rpx',left:`${630 * 0.8 / lastInfo.GroupCountStart * item.GroupCountStart}rpx`}">
                            <view class="product-detail-page__scroll__team__main__price__line"></view>
                            <view class="product-detail-page__scroll__team__main__price__target">{{item.GroupCountStart}}件</view>
                            <view class="product-detail-page__scroll__team__main__price__target">{{item.Amount}}元</view>
                        </view>
                    </template> -->
                    <view v-if="!$utils.isTrueEmpty(info.GroupCount)" class="product-detail-page__scroll__team__main__price" :style="{bottom:'80rpx',left:getLeftValue()+'rpx'}">
                        <view class="product-detail-page__scroll__team__main__price__current">已批{{info.GroupCount}}件</view>
                        <view class="product-detail-page__scroll__team__main__price__line current"></view>
                    </view>
                </view>
            </view>
            <view class="product-detail-page__scroll__team-intro" v-if="isGroup">
                <view class="product-detail-page__scroll__team-intro__target">批购说明:参与购买的人数越多,商品价格越实惠</view>
                <view class="product-detail-page__scroll__team-intro__target">根据批购最终参与购买的人数,来确定你需要支付的最终价格</view>
            </view>
            <view class="product-detail-page__scroll__desc">
                <view class="product-detail-page__scroll__desc__title">商品详情</view>
                <u-parse :content="info.ProductDesc" />
            </view>
        </scroll-view>
        <view class="evan-buy-bottom">
            <view class="evan-buy-bottom__item evan-buy-bottom__item--left">
                <view class="evan-buy-bottom__item__price">
                    <view v-if="isGroup||info.PayType===1" class="evan-buy-bottom__item__price__unit">¥</view>
                    <!-- <view class="evan-buy-bottom__item__price__current">{{showPrice}}</view> -->
                    <view v-if="!isGroup&&info.PayType===1&&info.MarketPrice" class="evan-buy-bottom__item__price__old">¥{{info.MarketPrice}}</view>
                </view>
                <view v-if="info.GiveAwayHuidouCount" class="evan-buy-bottom__item__tip">赠送{{info.GiveAwayHuidouCount}}汇豆</view>
            </view>
            <view @tap="buy" class="evan-buy-bottom__item evan-buy-bottom__item--right">立即购买</view>
    <view>
        <view class="button p-t-12 bg-white">
            <button :disabled="canvasImages == '' ? true : false" type="primary" @click="downloadImg">下载二维码</button>
            <button :disabled="canvasImages != '' ? false : true" @click="previewHandle">预览二维码</button>
            <!-- #ifdef MP-WEIXIN -->
            <!-- <button type="warn" :disabled="canvasImages != '' ? false : true" open-type="share">分享给朋友</button> -->
            <!-- #endif -->
        </view>
        <hjg-spec @confirm="onSpecConfirm" :changeCount="!isNewUserProduct" :specs="info.SpecInfos" ref="spec"></hjg-spec>
        <view @tap="hideBarcode" class="evan-poster__mask" :class="{hide:!showBarcode}" :style="{paddingTop:posterPadding}">
            <canvas class="evan-poster__mask__canvas" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}" canvas-id="barcode"></canvas>
            <view @tap.stop.prevent="stopPop" class="evan-poster__mask__bottom">
                <button open-type="share" class="evan-poster__mask__bottom__item">
                    <view class="evan-poster__mask__bottom__item__text">分享好友</view>
                </button>
                <button @tap="saveToAlbum" class="evan-poster__mask__bottom__item">
                    <view class="evan-poster__mask__bottom__item__text">保存海报</view>
                </button>
            </view>
        </view>
        <shareImages ref="canvas" :canvasWidth="canvasWidth" :canvasHeight="canvasHeight" :shareTitle="shareTitle"
            :goodsTitle="goodsTitle" :shareImage="shareImage" :goodsTitle2="goodsTitle2" :qrSize="qrSize" :qrUrl="qrUrl"
            @success="shareSuccess" :canvasID="canvasID">
        </shareImages>
    </view>
</template>
<script>
    import {
        mapGetters,
        mapState
    } from 'vuex'
    let ENV = 'prod'
    import shareImages from '@/components/hj-placard/shareImages.vue'
    export default {
        components: {
        },
        computed: {
            shareImages
        },
        data() {
            return {
                memberId: '',
                headUrl: '',
                nickName: '',
                id: null,
                info: {},
                currentIndex: 0,
                tags: [{
                        icon: '/static/images/home/qqzx.png',
                        text: '全球精品'
                    },
                    {
                        icon: '/static/images/home/jyps.png',
                        text: '正品保证'
                    },
                    {
                        icon: '/static/images/home/shwy.png',
                        text: '商品包邮'
                    }
                ],
                isGroup: false,
                groupId: null,
                canvasWidth: 242,
                canvasHeight: 430,
                showBarcode: false,
                ratio: 430 / 1920,
                posterPadding: 0,
                filePath: '',
                isNewUserProduct: false,
                canBuy: false
                name: '',
                canvasID: "myQrcode",
                canvasImages: '',
                canvasWidth: 375, // 宽度
                canvasHeight: 650, // 高度
                shareTitle: '我是这张图片的标题', // 分享标题
                goodsTitle: '\n', // 商品宣传标题
                goodsTitle2: '',
                shareImage: 'https://hmy-flower.oss-cn-shanghai.aliyuncs.com/d4/d43cdefc7b8f4c3e91fb451a236a4435WechatIMG2882.jpg', // 背景图片
                qrSize: 100, // 二维码大小
                qrUrl: 'http://www.hmyxianhua.com/wx/jump?partnerUserId=1&partnerUserName=', // 生成二维码的链接
            }
        },
        onLoad() {
            if (!this.currentInfo.partnerDTO) {
                this.$message.showToast('请先完善合伙人信息')
                return
            }
            this.name = this.currentInfo.partnerDTO.name || '佚名'
            this.qrUrl =
                `http://www.hmyxianhua.com/wx/jump?partnerUserId=${this.currentInfo.id||'-'}&partnerUserName=${this.name||'-'}`
            this.goodsTitle = `${this.name||'-'}的推广二维码`
            this.goodsTitle2 = `扫码注册绑定合伙人`
            this.$message.showLoading()
            setTimeout(() => {
                this.createsShareImage()
            }, 500)
            setTimeout(() => {
                this.$message.hideLoading()
            }, 2000)
        },
        methods: {
            async getDetail() {
                // const {
                //     code,
                //     data
                // } = await productService.getDetail(this.id)
                // if (code === 0) {
                //     this.info = data
                //     this.isNewUserProduct = data.IsNewUserTopic === 1
            // 生成分享图片
            createsShareImage() {
                // console.log(this.$refs.canvas)
                this.$refs.canvas.canvasCreate();
            },
            // 预览图片
            previewHandle() {
                uni.previewImage({
                    urls: [this.canvasImages],
                });
            },
            // 回调图片地址
            shareSuccess(e) {
                // console.log('地址',e)
                this.canvasImages = e
            },
            downloadImg() {
                // this.$refs.canvas.downloadImg();
                uni.saveImageToPhotosAlbum({
                    filePath: this.canvasImages,
                    success: function() {
                        console.log('save success');
                        uni.showToast({
                            title: '保存成功'
                        })
                    },
                    fail(res) {
                        console.error(res)
                        uni.showToast({
                            title: '保存失败。',
                            icon: 'error'
                        })
                    }
                })
            },
            // 分享
            onShareAppMessage(res) {
                // if (res.from === 'button') {
                //     console.log(res.target)
                // }
            },
            async getGroupDetail() {
                const {
                    code,
                    data
                } = await assembleService.getAssembleDetail(this.id, this.groupId)
                if (code === 0) {
                    this.info = data
                return {
                    title: `${this.name||'-'}的推广二维码`,
                    path: this.canvasImages
                }
            },
            onSwiperChange(e) {
                this.currentIndex = e.detail.current
            },
            async buy() {
            },
            onSpecConfirm(e) {
                let specList = []
                if (Array.isArray(e.specs)) {
                    specList = e.specs.map((item) => {
                        return {
                            SpecName: item.SpecName,
                            SpecValue: item.SpecValue
                        }
                    })
                }
                let orderInfo = {
                    ProductId: this.info.Id,
                    ProductSpecList: specList,
                    ProductCount: e.count,
                    ProductSaleType: this.isGroup ? 2 : 1,
                    ProductPayType: this.isGroup ? 1 : this.info.PayType
                }
                if (this.isGroup) {
                    orderInfo.GroupId = this.groupId
                    orderInfo.BookAmount = this.info.BookAmount
                } else {
                    if (orderInfo.ProductPayType === 1) {
                        orderInfo.SaleAmount = this.info.SalePrice
                    } else {
                        orderInfo.SaleAmount = this.info.HuidouCount
                    }
                }
                uni.navigateTo({
                    url: `./order?orderInfo=${JSON.stringify(orderInfo)}`
                })
            },
            getPercent() {
                if (!this.info.GroupRules || this.info.GroupRules.length === 0) {
                    return 0
                }
                if (this.info.GroupCount > this.info.GroupRules[this.info.GroupRules.length - 1].GroupCountStart) {
                    return 0.85 * 630
                } else {
                    return this.info.GroupCount / this.info.GroupRules[this.info.GroupRules.length - 1].GroupCountStart *
                        0.8 * 630
                }
            },
            getLeftValue() {
                if (!this.info.GroupRules || this.info.GroupRules.length === 0) {
                    if (this.info.GroupCount === 0) {
                        return 0
                    } else {
                        return 630 * 0.8
                    }
                } else {
                    if (this.info.GroupCount > this.info.GroupRules[this.info.GroupRules.length - 1].GroupCountStart) {
                        return 630 * 0.85
                    } else {
                        return 630 * 0.8 / Math.max(this.info.GroupRules[this.info.GroupRules.length - 1].GroupCountStart /
                            this.info.GroupCount, 1)
                    }
                }
            },
            formatCanvasSize(size) {
                return Math.floor(this.ratio * size)
            },
            async shareDetail() {
                if (this.memberId) {
                    // #ifdef MP-WEIXIN
                    let params = `id=${this.info.Id}`
                    if (this.isGroup) {
                        params += `&groupId=${this.groupId}`
                    }
                    if (this.memberId) {
                        params += `&inviteId=${this.memberId}`
                    }
                    const {
                        code: sceneCode,
                        data: sceneData
                    } = await commonService.saveScene(encodeURIComponent(params))
                    if (sceneCode === 0) {
                        const {
                            code,
                            data
                        } = await commonService.getUnlimitedBarcode('pages/home/product/detail', `posterId=${sceneData}`)
                        if (code === 0) {
                            const fsm = wx.getFileSystemManager()
                            this.filePath = `${wx.env.USER_DATA_PATH}/barcode_tmp_${(new Date).getTime()}.png`
                            fsm.writeFile({
                                filePath: this.filePath,
                                data: data,
                                encoding: 'binary',
                                success: async () => {
                                    const context = uni.createCanvasContext('barcode')
                                    const headSize = this.formatCanvasSize(105)
                                    const productSize = this.formatCanvasSize(540)
                                    const canvasWidth = this.canvasWidth
                                    const canvasHeight = this.canvasHeight
                                    const headPath = await this.getImageInfo(this.headUrl)
                                    const productPath = await this.getImageInfo(this.info.ImageUrlList[0])
                                    // 背景
                                    context.drawImage('/pages/home/static/images/sharebg.jpg', 0, 0, canvasWidth,
                                        canvasHeight)
                                    // 头像
                                    context.drawImage(headPath, this.formatCanvasSize(80), this.formatCanvasSize(70), headSize, headSize)
                                    // 昵称
                                    context.font = `bold ${this.formatCanvasSize(40)}px system-ui`
                                    context.setFillStyle('#000')
                                    this.fillTextByLength(context, this.nickName, 20, this.formatCanvasSize(198),
                                        this.formatCanvasSize(110))
                                    // 产品图
                                    context.drawImage(productPath, this.formatCanvasSize(260), this.formatCanvasSize(440), productSize,
                                        productSize)
                                    // 价格
                                    const priceWidth = this.formatCanvasSize(150)
                                    const priceTop = this.formatCanvasSize(1240)
                                    const priceLeft = this.formatCanvasSize(141)
                                    // 当前价格
                                    if (this.showPrice) {
                                        const price = (this.isGroup || this.info.PayType === 1) ? `¥${this.showPrice}` : this.showPrice
                                        context.font = `bold ${this.formatCanvasSize(84)}px system-ui`
                                        context.setFillStyle('#d92c21')
                                        context.fillText(price, priceLeft, priceTop, priceWidth)
                                    }
                                    // 市场价格
                                    if (!this.isGroup && this.info.PayType === 1 && this.info.MarketPrice) {
                                        context.font = `normal ${this.formatCanvasSize(54)}px system-ui`
                                        context.setFillStyle('#61605e')
                                        context.fillText(`¥${this.info.MarketPrice}`, priceLeft + priceWidth + 5, priceTop, priceWidth)
                                        context.moveTo(priceLeft + priceWidth + 5, priceTop - this.formatCanvasSize(20))
                                        context.lineTo(priceLeft + priceWidth + 5 + context.measureText(`¥${this.info.MarketPrice}`).width + 2,
                                            priceTop - this.formatCanvasSize(20))
                                        context.setStrokeStyle('#61605e')
                                        context.stroke()
                                    }
                                    // 赠送汇豆
                                    if (this.info.GiveAwayHuidouCount) {
                                        context.font = `normal ${this.formatCanvasSize(36)}px system-ui`
                                        context.setFillStyle('#61605e')
                                        context.fillText(`赠送${this.info.GiveAwayHuidouCount}汇豆`, priceLeft, priceTop + this.formatCanvasSize(36) +
                                            5,
                                            priceWidth * 2)
                                    }
                                    // 商品名称
                                    let nameLeft = priceLeft + 2 * priceWidth + 10
                                    let nameTop = this.formatCanvasSize(1230)
                                    context.font = `bold ${this.formatCanvasSize(50)}px system-ui`
                                    context.setFillStyle('#000')
                                    let nameWidth = 0
                                    // 换行次数
                                    let breakLineCount = 0
                                    for (let i = 0; i < this.info.Name.length; i++) {
                                        const str = this.info.Name[i]
                                        nameWidth += context.measureText(str).width
                                        if (nameWidth > 80 && breakLineCount > 0) {
                                            context.fillText('...', nameLeft, nameTop)
                                            break
                                        }
                                        if (nameWidth > 90) {
                                            nameTop += this.formatCanvasSize(74)
                                            nameLeft = priceLeft + 2 * priceWidth + 10
                                            nameWidth = context.measureText(str).width
                                            breakLineCount++
                                        }
                                        context.fillText(str, nameLeft, nameTop)
                                        nameLeft += context.measureText(str).width + 2
                                    }
                                    // 二维码
                                    const barcodeSize = this.formatCanvasSize(250)
                                    const barcodeLeft = this.formatCanvasSize(740)
                                    const barcodeTop = this.formatCanvasSize(1500)
                                    context.drawImage(this.filePath, barcodeLeft, barcodeTop,
                                        barcodeSize,
                                        barcodeSize)
                                    this.showBarcode = true
                                    this.$nextTick(() => {
                                        context.draw(false, () => {})
                                    })
                                },
                                fail: (err) => {
                                    this.$message.showToast('写入文件失败')
                                }
                            })
                        }
                    }
                    // #endif
                } else {
                    this.$message.confirm('登录后才能分享,是否立即登录?').then(() => {
                        uni.navigateTo({
                            url: '/pages/account/login'
                        })
                    }).catch(() => {})
                }
            },
            fillTextSingleLine(context, text, maxLength, startLeft, startTop) {
                let nameWidth = 0
                for (let i = 0; i < text.length; i++) {
                    const str = text[i]
                    nameWidth += context.measureText(str).width
                    if (nameWidth > maxLength - 10) {
                        context.fillText('...', startLeft, startTop)
                        break
                    } else {
                        context.fillText(str, startLeft, startTop)
                        startLeft += context.measureText(str).width + 2
                    }
                }
            },
            fillTextByLength(context, text, len, startLeft, startTop) {
                if (text.length > len - 3) {
                    text = text.substr(0, len - 3) + '...'
                }
                context.fillText(text, startLeft, startTop)
            },
            getImageInfo(url) {
                if (ENV === 'prod') {
                    url = url.replace(/http:\/\//g, 'https://')
                }
                return new Promise((resolve, reject) => {
                    uni.getImageInfo({
                        src: url,
                        success: (res) => {
                            resolve(res.path)
                        },
                        fail: (e) => {
                            reject(e)
                        }
                    })
                })
            },
            saveToAlbum() {
                uni.canvasToTempFilePath({
                    x: 0,
                    y: 0,
                    width: this.canvasWidth,
                    height: this.canvasHeight,
                    canvasId: 'barcode',
                    success: (res) => {
                        uni.saveImageToPhotosAlbum({
                            filePath: res.tempFilePath,
                            success: () => {
                                this.$message.showToast('已为您保存至相册')
                            }
                        })
                    }
                })
            },
            hideBarcode() {
                this.showBarcode = false
                if (this.filePath) {
                    const fsm = wx.getFileSystemManager()
                    fsm.unlink({
                        filePath: this.filePath,
                        success: () => {
                            this.filePath = ''
                        }
                    })
                }
            },
            stopPop() {
                // do nothing
            },
            async getScene(id) {
                const {
                    code,
                    data
                } = await commonService.getScene(id)
                if (code === 0) {
                    const productId = this.$utils.getBarcodeQueryString(data, 'id')
                    const inviteId = this.$utils.getBarcodeQueryString(data, 'inviteId')
                    const groupId = this.$utils.getBarcodeQueryString(data, 'groupId')
                    if (productId) {
                        this.id = productId
                        if (inviteId) {
                            this.$store.commit('account/SET_INVITEID', inviteId)
                        }
                        if (groupId) {
                            this.isGroup = true
                            this.groupId = groupId
                            this.getGroupDetail()
                        } else {
                            this.getDetail()
                        }
                    }
                }
            },
            setPosterPadding() {
                const windowHeight = uni.getSystemInfoSync().windowHeight
                this.posterPadding = (windowHeight - 126 - this.canvasHeight) / 2 + 'px'
            }
        },
        async onLoad(options) {
            this.setPosterPadding()
            this.id = options.id || ''
        },
        onUnload() {
        },
        onShareAppMessage() {
            let params = `id=${this.info.Id}`
            if (this.isGroup) {
                params += `&groupId=${this.groupId}`
            }
            if (this.memberId) {
                params += `&inviteId=${this.memberId}`
            }
            let path = `/pages/home/product/detail?${params}`
            return {
                title: this.info.Name,
                path: path
            }
        }
    }
</script>
<style lang="scss">
    .product-detail-page {
        height: 100%;
<style scoped>
    .button {
        display: flex;
        flex-direction: column;
        &__scroll {
            flex: 1;
            overflow: auto;
            &__swiper {
                position: relative;
                width: 100%;
                height: 446rpx;
                background-color: #fff;
                &__target {
                    height: 100%;
                    &__item {
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        &__img {
                            width: 400rpx;
                            height: 400rpx;
                        }
                    }
                }
                &__page {
                    position: absolute;
                    bottom: 14rpx;
                    right: 40rpx;
                    height: 40rpx;
                    border-radius: 20rpx;
                    background-color: rgba(0, 0, 0, 0.6);
                    padding: 0 14rpx;
                    font-size: 28rpx;
                    color: #fff;
                }
            }
            &__default-image {
                width: 100%;
                height: 446rpx;
            }
            &__info {
                background-color: #fff;
                padding: 18rpx 30rpx 28rpx 30rpx;
                &__title {
                    font-size: 32rpx;
                    color: #000;
                    font-weight: 500;
                    line-height: 44rpx;
                    margin-bottom: 14rpx;
                }
                &__desc {
                    font-size: 28rpx;
                    color: #666;
                    line-height: 40rpx;
                    margin-bottom: 10rpx;
                }
                &__bulter {
                    font-size: 28rpx;
                    color: #000;
                    line-height: 40rpx;
                }
                &__tags {
                    display: flex;
                    align-items: center;
                    margin-top: 10rpx;
                    &__item {
                        display: flex;
                        align-items: center;
                        margin-right: 44rpx;
                        &__icon {
                            width: 28rpx;
                            height: 28rpx;
                            margin-right: 4rpx;
                        }
                        &__text {
                            font-size: 24rpx;
                            color: #000;
                        }
                    }
                    &__count {
                        flex: 1;
                        text-align: right;
                        font-size: 24rpx;
                        color: #666;
                    }
                }
            }
            &__desc {
                padding: 30rpx;
                background-color: #fff;
                margin-top: 24rpx;
                &__title {
                    font-size: 36rpx;
                    color: #000;
                    font-weight: 500;
                    line-height: 50rpx;
                    margin-bottom: 26rpx;
                }
            }
            &__team {
                background-color: #fff;
                padding-bottom: 48rpx;
                &__title {
                    font-size: 28rpx;
                    color: #000;
                    padding: 0 30rpx;
                    font-weight: bold;
                }
                &__main {
                    width: 750rpx;
                    padding: 60rpx 0;
                    position: relative;
                    display: flex;
                    justify-content: center;
                    &__progress {
                        width: 630rpx;
                        height: 20rpx;
                        background-color: #d8d8d8;
                        border-radius: 16rpx;
                        &__active {
                            height: 100%;
                            background-color: #d51d1d;
                            border-radius: 16rpx;
                        }
                    }
                    &__price {
                        display: flex;
                        flex-direction: column;
                        align-items: center;
                        position: absolute;
                        min-width: 120rpx;
                        &__line {
                            width: 2rpx;
                            height: 24rpx;
                            background-color: #979797;
                            &.current {
                                background-color: #d51d1d;
                            }
                        }
                        &__target {
                            font-size: 24rpx;
                            color: #000;
                            font-weight: bold;
                        }
                        &__current {
                            font-size: 20rpx;
                            color: #d51d1d;
                        }
                    }
                }
            }
            &__team-intro {
                padding: 8rpx 30rpx;
                background-color: #EDE0CC;
                margin-top: 24rpx;
                &__target {
                    font-size: 24rpx;
                    color: #9C753B;
                    font-weight: bold;
                    &:not(:first-child) {
                        margin-top: 8rpx;
                    }
                }
            }
            &__team-info {
                padding: 16rpx 30rpx 0 16rpx;
                &__line {
                    display: flex;
                    align-items: flex-start;
                    margin-bottom: 8rpx;
                    &__label {
                        font-size: 28rpx;
                        color: #000;
                    }
                    &__value {
                        font-size: 28rpx;
                        color: #000;
                        flex: 1;
                    }
                }
            }
        }
    }
</style>
</style>
sub_pages/partner/partner-info/partner-code.vue
@@ -3,7 +3,7 @@
    <!--  -->
    <view class="contact-container">
        <view class="container" @click="saveCode">
            <canvas type="2d" id="myQrcode" class="code"></canvas>
            <view class="info">
                <view class="desc">