xiebaomin 1 jaar geleden
bovenliggende
commit
66a7289c17
35 gewijzigde bestanden met toevoegingen van 3528 en 105 verwijderingen
  1. 169 0
      components/cm-share-popup/cm-seller-modal.vue
  2. 259 0
      components/cm-share-popup/cm-share-popup.vue
  3. 229 0
      components/cm-share-popup/draw-poster.js
  4. 139 0
      components/cm-share-popup/simple-share-popup/simple-share-popup.vue
  5. 45 0
      components/cm-share-popup/uni-popup/keypress.js
  6. 26 0
      components/cm-share-popup/uni-popup/popup.js
  7. 437 0
      components/cm-share-popup/uni-popup/uni-popup.vue
  8. 1 1
      manifest.json
  9. 49 2
      pages.json
  10. 105 0
      pages/goods/mixins/share.helper.js
  11. 34 5
      pages/goods/product.vue
  12. 109 89
      pages/seller/club/list.vue
  13. 226 0
      pages/seller/components/message.vue
  14. 11 1
      pages/seller/components/user.vue
  15. 34 3
      pages/seller/index/index.vue
  16. 97 0
      pages/seller/notice/components/notice-cell.vue
  17. 75 0
      pages/seller/notice/components/time-axis.vue
  18. 71 0
      pages/seller/notice/components/trajectory.vue
  19. 91 0
      pages/seller/notice/components/visits-cell.vue
  20. 141 0
      pages/seller/notice/mixins/notice.mixins.js
  21. 47 0
      pages/seller/notice/service/Institutional_visits.vue
  22. 165 0
      pages/seller/notice/service/service.vue
  23. 55 0
      pages/seller/notice/service/visits_details.vue
  24. 108 0
      pages/seller/remarks/business-card.vue
  25. 83 0
      pages/seller/remarks/components/activity-analysis.vue
  26. 71 0
      pages/seller/remarks/components/analysis-card-item.vue
  27. 81 0
      pages/seller/remarks/components/analysis-card.vue
  28. 137 0
      pages/seller/remarks/components/countUp.vue
  29. 118 0
      pages/seller/remarks/components/mine-card.vue
  30. 141 0
      pages/seller/remarks/institutional-activity-analysis.vue
  31. 34 0
      pages/seller/remarks/mine-card.vue
  32. 86 0
      pages/seller/remarks/mine-qrcode.vue
  33. 11 3
      pages/tabBar/home/index.vue
  34. 15 1
      services/sellse.service.js
  35. 28 0
      store/index.js

+ 169 - 0
components/cm-share-popup/cm-seller-modal.vue

@@ -0,0 +1,169 @@
+<template>
+    <view class="seller-card" v-if="sellerUserId !== 0">
+        <view class="seller-card-mine" v-if="!modal" @click="modal=true"></view>
+        <tui-modal class="sellerMode" @click="handleClick" @cancel="hideModal" :show="modal" custom>
+            <view class="tui-modal-custom">
+                <view class="close" @click="modal=false">
+                    <image src="https://static.caimei365.com/app/img/supplier-login/close.png" style="width: 100%;height: 100%;" mode=""></image>
+                </view>
+                <view class="card" :style="{backgroundImage: `url(${imgUrl})`, backgroundSize: '100% 100%'}">
+                    <view class="logo">
+                        <image src="https://static.caimei365.com/app/img/icon/logo-fanbai.png" mode="" class="titleImgUrl"></image>
+                    </view>
+                    <view class="card-contain">
+                        <view style="display: flex;">
+                            <view class="card-head">
+                                <image src="https://static.caimei365.com/app/img/icon/default-head.png" mode="" class="head"></image>
+                            </view>
+                            <view class="card-info">
+                                <view class="card-info-head">
+                                    <view class="card-name">
+                                        未知
+                                    </view>
+                                    <view class="card-info-tab">
+                                        客户经理
+                                    </view>
+                                </view>
+                                <view class="card-info-iphone">
+                                    158-8958-6633
+                                </view>
+                            </view>
+                        </view>
+                        <view class="card-qrcode">
+                            <view class="qrcode-message">
+                                <image :show-menu-by-longpress="true" src="" class="qrcode" mode=""></image>
+                            </view>
+                            <view class="tips">
+                                长按或扫二维码
+                                联系我
+                            </view>
+                        </view>
+                    </view>
+                </view>
+            </view>
+        </tui-modal>
+    </view>
+</template>
+
+<script>
+export default {
+    props: {
+        sellerUserId: {
+            type: Number,
+            default: 0
+        }
+    },
+    data() {
+        return {
+            modal: false,
+            imgUrl: 'https://static.caimei365.com/app/img/icon/bg-card.png',
+        }
+    },
+    mounted() {
+        this.initData()
+    },
+    methods: {
+        handleClick() {},
+        hideModal() {
+            this.modal = false
+        },
+        initData() {
+            if(this.sellerUserId > 0) {
+                this.modal = true
+            }
+        },
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.seller-card-mine {
+    position: fixed;
+    right: 20rpx;
+    width: 80rpx;
+    height: 80rpx;
+    border: 1px solid;
+    z-index: 99;
+    bottom: 500rpx;
+    border-radius: 50%;
+}
+.tui-modal-custom {
+    .close {
+        position: fixed;
+        right: -20px;
+        top: -200rpx;
+        width: 60rpx;
+        height: 60rpx;
+    }
+}
+.card {
+    position: fixed;
+    left: -34rpx;
+    top: -150%;
+    width: 702rpx;
+    height: 340rpx;
+    background: #FF5B00;
+    border-radius: 16rpx;
+    opacity: 1;
+    margin: 0 auto;
+    box-sizing: border-box;
+    padding: 16rpx 32rpx;
+    .titleImgUrl {
+        width: 241rpx;
+        height: 80rpx;
+    }
+    .card-contain {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        .head {
+            width: 128rpx;
+            height: 128rpx;
+            border-radius: 50%;
+            object-fit: contain;
+        }
+        .card-info {
+            height: 128rpx;
+            margin-left: 30rpx;
+        }
+        .card-info-head {
+            display: flex;
+            align-items: center;
+            margin-bottom: 13rpx;
+            .card-name {
+                color: #FFFFFF;
+                font-size: 40rpx;
+                font-weight: bold;
+            }
+            .card-info-tab {
+                width: 88rpx;
+                height: 31rpx;
+                background-color: #FFBB00;
+                color: #fff;
+                font-size: 22rpx;
+                padding: 0 8rpx;
+                margin-left: 10rpx;
+            }
+        }
+        .card-info-iphone {
+            color: #FFFFFF;
+            font-size: 28rpx;
+        }
+        .card-qrcode {
+            .qrcode {
+                width: 126rpx;
+                height: 126rpx;
+                object-fit: contain;
+                margin-bottom: 6rpx;
+            }
+            .tips {
+                font-size: 18rpx;
+                color: #fff;
+                text-align: center;
+                width: 126rpx;
+                line-height: 24rpx;
+            }
+        }
+    }
+}
+</style>

+ 259 - 0
components/cm-share-popup/cm-share-popup.vue

@@ -0,0 +1,259 @@
+<template>
+    <view class="cm-share-popup">
+        <!-- 分享弹窗 -->
+        <simple-share-popup ref="sharePopup" :posterUrl="posterUrl" @click="onPopupClick" @close="onClose">
+            <slot name="title"></slot>
+        </simple-share-popup>
+        <!-- 海报画布 -->
+        <canvas canvas-id="poster" class="poster-canvas"></canvas>
+    </view>
+</template>
+
+<script>
+import DrawPoster from './draw-poster.js'
+import {mapState} from 'vuex'
+import { codeQueryStr } from '@/pages/goods/mixins/share.helper.js'
+import simpleSharePopup from './simple-share-popup/simple-share-popup.vue'
+export default {
+    name: 'cm-share-popup',
+    components: {
+        simpleSharePopup
+    },
+    props: {
+        data: {
+            type: Object,
+            default: () => {}
+        },
+        type: {
+            type: String,
+            default: 'normal',
+            validator: value => {
+                return ['product', 'normal', 'activity'].indexOf(value) > -1
+            }
+        }
+    },
+    data() {
+        return {
+            posterUrl: '',
+            posterData: {
+                /* 用户信息 */
+                image: '', // 用户头像
+                qrCode: '', // 用户二维码
+                linkMan: '', // 用户名
+                contractMobile: '', // 用户手机号
+                /* 页面参数 */
+                query: '/', // 查询参数字符串
+                path: '', // 页面路径
+                qrCodeImage: '', //页面二维码,小程序二维码
+
+                /* 产品参数 */
+                porductName: '', // 产品名
+                productPrice: '', // 产品价格
+                productOriginPrice: '', // 产品原价
+                productImage: '', // 产品图片
+
+                /* 活动参数 */
+                activityName: '', // 活动名称
+                activityImage: 'https://picsum.photos/400/400' //活动封面
+            }
+        }
+    },
+    computed: {
+        ...mapState(['userInfo'])
+    },
+    methods: {
+        // 分享操作
+        onPopupClick(e) {
+            if (e.type === 'create-poster') {
+                console.log('生成海报')
+                this.createPoster()
+            } else {
+                console.log('普通分享')
+                this.$refs.sharePopup.close()
+                this.onShare()
+            }
+        },
+        // 打开弹窗
+        open() {
+            this.$refs.sharePopup.open()
+            this.$emit('open')
+        },
+        close() {
+            this.$refs.sharePopup.close()
+        },
+        onClose() {
+            uni.hideLoading()
+            this.$emit('close')
+        },
+        onShare() {
+            this.$emit('share')
+            console.log('分享')
+        },
+        // 创建海报
+        async createPoster() {
+            try {
+                uni.showLoading({ title: '正在生成海报' })
+                if (!this.posterUrl) {
+                    this.posterData = { ...this.posterData, ...this.data }
+                    const userProfile = await this.SellerService.GetSellerHome({ userId: this.userInfo.userId })
+                    console.log('userProfile', userProfile)
+                    this.posterData.image = '' // 用户头像
+                    this.posterData.qrCode = '' // 用户二维码
+                    this.posterData.linkMan = '' // 用户名
+                    this.posterData.contractMobile = '' // 用户手机号
+                    // const { data: qrCodeImage } = await this.SellerService.wxUnlimited({
+                    //     page: this.posterData.path || 'pages/index/index',
+                    //     scene: codeQueryStr(this.posterData.query),
+                    //     check_path: process.env.NODE_ENV === 'production', // 是否校验页面
+                    //     env_version: process.env.NODE_ENV === 'production' ? 'release' : 'trial', // 正式版 or 开发版
+                    //     width: 200, // 二维码宽度
+                    //     auto_color: false, // 自动颜色
+                    //     line_color: { 'r': 0, 'g': 0, 'b': 0 }, // 线条颜色
+                    //     is_hyaline: true // 透明底
+                    // })
+                    // const { data: qrCodeImage } = await generateWxUnlimited({
+                    //     pagePath: this.posterData.path,
+                    //     queryStr: this.posterData.query
+                    // })
+                    // this.posterData.qrCodeImage = qrCodeImage
+                    // this.posterData.qrCodeImage = ''
+
+                    switch (this.type) {
+                        case 'product':
+                            await this.createProductPoster()
+                            break
+                        case 'activity':
+                            await this.createActivityPoster()
+                            break
+                        default:
+                            await this.createNormalPoster()
+                    }
+
+                    // const {tempFilePath} = await this.canvasToTempFilePath()
+                    // this.posterUrl = tempFilePath
+                }
+                uni.hideLoading()
+                // 下载完成后转发
+                // wx.showShareImageMenu({ path: this.posterUrl })
+                this.onShare()
+                // console.log(this.posterUrl)
+            } catch (e) {
+                console.log(e)
+            } finally {
+                uni.hideLoading()
+            }
+        },
+
+        // 画布转图片临时链接
+        canvasToTempFilePath() {
+            return new Promise((resolve, reject) => {
+                uni.canvasToTempFilePath(
+                    {
+                        canvasId: 'poster',
+                        success: res => {
+                            resolve(res)
+                        },
+                        fail() {
+                            reject(false)
+                        }
+                    },
+                    this
+                )
+            })
+        },
+
+        // 生成绘制文本数组
+        generateTextArray() {
+            const textArray = []
+            const { productPrice, productOriginPrice, productName, activityName } = this.posterData
+
+            // 处理价格
+            let priceText = ''
+            if (this.type === 'product') {
+                if (productPrice) {
+                    priceText += productPrice
+                }
+                if (productOriginPrice) {
+                    priceText += '¥' + productOriginPrice
+                }
+            }
+            textArray.push(priceText)
+            console.log(this.posterData)
+            // 处理产品名称
+            if (productName) {
+                const nameStr = productName || activityName
+                textArray.push(nameStr.substring(0, 12))
+                if (nameStr.length > 24) {
+                    textArray.push(nameStr.substring(12, 23) + '...')
+                } else {
+                    textArray.push(nameStr.substring(12))
+                }
+            }
+            return textArray
+        },
+
+        // 商品海报
+        async createProductPoster() {
+            try {
+                const ctx = uni.createCanvasContext('poster', this)
+                const drawPoster = new DrawPoster(ctx, {
+                    avatarUrl: this.posterData.avatar,
+                    userName: this.posterData.username,
+                    subTitle: '强烈为你推荐该商品',
+                    coverUrl: this.posterData.productImage,
+                    // ewmUrl: this.posterData.qrCodeImage,
+                    textArray: this.generateTextArray()
+                })
+                return await drawPoster.draw()
+            } catch (e) {
+                throw e
+            }
+        },
+
+        // 活动页面
+        async createActivityPoster() {
+            try {
+                const ctx = uni.createCanvasContext('poster', this)
+                const drawPoster = new DrawPoster(ctx, {
+                    avatarUrl: this.posterData.avatar,
+                    userName: this.posterData.username,
+                    subTitle: '强烈为你推荐该活动',
+                    coverUrl: this.posterData.activityImage,
+                    ewmUrl: this.posterData.qrCodeImage,
+                    textArray: this.generateTextArray()
+                })
+                return await drawPoster.draw()
+            } catch (e) {
+                throw e
+            }
+        },
+
+        // 普通海报
+        async createNormalPoster() {
+            try {
+                const ctx = uni.createCanvasContext('poster', this)
+                const drawPoster = new DrawPoster(ctx, {
+                    avatarUrl: this.posterData.avatar,
+                    userName: this.posterData.username,
+                    subTitle: '强烈为你推荐该商城',
+                    textArray: ['', '护肤上颜选,正品', '有好货~~']
+                })
+                return await drawPoster.draw()
+            } catch (e) {
+                throw e
+            }
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.poster-canvas {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 375px;
+    height: 610px;
+    border: 1px solid;
+}
+</style>

+ 229 - 0
components/cm-share-popup/draw-poster.js

@@ -0,0 +1,229 @@
+// 默认配置参数
+const defaultOptions = () => ({
+    avatarUrl: 'https://static.caimei365.com/app/mini-hehe/icon/icon-join-us.png',
+    userName: '采美',
+    subTitle: '强烈为你推荐该商城',
+    coverUrl: 'https://static.caimei365.com/app/mini-hehe/icon/icon-share.png',
+    bgImageUrl: 'https://static.caimei365.com/app/mini-hehe/icon/bg-share-01.png',
+    userBg: 'https://static.caimei365.com/app/img/icon/bg-card.png',
+    userTitleBg: 'https://static.caimei365.com/app/img/icon/logo-fanbai.png',
+    // ewmUrl: 'https://static.caimei365.com/app/mini-hehe/icon/icon-ewm-hehe.jpg',
+    textArray: [],
+    scale: 0.5,
+})
+// 绘制海报
+export default class DrawPoster {
+    constructor(ctx, options = {}) {
+        this.ctx = ctx
+        this.options = Object.assign(defaultOptions(), options)
+        console.log('配置信息为:', this.options)
+    }
+    // 开始绘制
+    draw() {
+        return new Promise(async (resolve, reject) => {
+            try {
+                await this.drawBgImage()
+                // await this.drawHeader()
+                await this.drawUserCoverImage()
+                await this.drawCenterInfo()
+            } catch (e) {
+                console.log(e)
+                reject(e)
+            } finally {
+                this.ctx.draw(true, res => {
+                    resolve(true)
+                })
+            }
+        })
+    }
+    // 绘制海报头部(用户信息区域)
+    async drawHeader() {
+        try {
+            const { avatarUrl, userName, scale, subTitle } = this.options
+            const [error, result] = await uni.downloadFile({ url: avatarUrl })
+            if (error) return
+
+            // 绘制用户头像
+            this.ctx.beginPath()
+            this.ctx.arc(116 * scale, 108 * scale, 60 * scale, 0, 2 * Math.PI)
+            this.ctx.setFillStyle('#fff')
+            this.ctx.fill()
+            this.ctx.clip()
+            this.ctx.drawImage(result.tempFilePath, 56 * scale, 48 * scale, 120 * scale, 120 * scale)
+            this.ctx.restore()
+
+            // 绘制用户名和推荐语
+            this.ctx.setFillStyle('#FFFFFF')
+            this.ctx.font = 'bold 10px sans-serif'
+            this.ctx.setFontSize(40 * scale)
+            this.ctx.fillText(userName, 205 * scale, 96 * scale, 350 * scale)
+            this.ctx.font = 'normal 10px sans-serif'
+            this.ctx.setFontSize(26 * scale)
+            this.ctx.fillText(subTitle, 205 * scale, 150 * scale, 350 * scale)
+
+            this.ctx.save()
+            return Promise.resolve(true)
+        } catch (e) {
+            return Promise.reject(e)
+        }
+    }
+    // 绘制背景
+    async drawBgImage() {
+        try {
+            const { bgImageUrl, scale } = this.options
+            const [error, result] = await uni.downloadFile({ url: bgImageUrl })
+            if (error) return
+            this.ctx.setFillStyle('#999999')
+            // this.ctx.drawImage(result.tempFilePath, 0, 0, 750 * scale, 1220 * scale)
+            this.ctx.save()
+            return Promise.resolve(true)
+        } catch (e) {
+            return Promise.reject(e)
+        }
+    }
+    // 绘制圆角矩形
+    async drawRoundRect(x, y, w, h, r) {
+        this.ctx.beginPath()
+        this.ctx.moveTo(x + r , y)
+        this.ctx.arcTo(x + w, y, x + w, y + h, r)
+        this.ctx.arcTo(x + w, y + h, x , y + h, r)
+        this.ctx.arcTo(x, y + h, x, y, r)
+        this.ctx.arcTo(x, y, x + w, y , r)
+        this.ctx.setFillStyle('#FFFFFF')
+        this.ctx.fill()
+        this.ctx.clip()
+    }
+    // 绘制中心区域
+    async drawCenterInfo() {
+        try {
+            const { scale } = this.options
+
+            this.ctx.beginPath()
+            this.drawRoundRect(28 * scale, 28 * scale, 694 * scale, 878 * scale, 8)
+            // this.ctx.rect(28 * scale, 28 * scale, 694 * scale, 878 * scale)
+            await this.drawCoverImage()
+            await this.drawFooterText()
+            await this.drawEwmImage()
+            return Promise.resolve(true)
+        } catch (e) {
+            return Promise.reject(e)
+        }
+    }
+    // 绘制封面图片
+    async drawCoverImage() {
+        try {
+            const { coverUrl, scale } = this.options
+            const [error, result] = await uni.downloadFile({ url: coverUrl })
+            if (error) return
+            this.ctx.drawImage(result.tempFilePath, 56 * scale, 24 * scale, 638 * scale, 678 * scale)
+            return Promise.resolve(true)
+        } catch (e) {
+            return Promise.reject(e)
+        }
+    }
+    // 绘制名片封面
+    async drawUserCoverImage() {
+        try {
+            const { userBg, scale } = this.options
+            const [error, result] = await uni.downloadFile({ url: userBg })
+            if (error) return
+            this.drawBorderReduisImage(result.tempFilePath, 28 * scale, 920 * scale, 694 * scale, 290 * scale, 8)
+            await this.drawUserCardInner() // 绘制名片内容
+            return Promise.resolve(true)
+        } catch (e) {
+            return Promise.reject(e)
+        }
+    }
+    async drawUserCardInner() {
+        try {
+            const { userTitleBg, scale, avatarUrl } = this.options
+            const [error, result] = await uni.downloadFile({ url: userTitleBg })
+            
+            if (error) return
+            // this.drawBorderReduisImage(result.tempFilePath, 28 * scale, 920 * scale, 694 * scale, 280 * scale, 8)
+            this.ctx.drawImage(result.tempFilePath, 56 * scale, 940 * scale, 200 * scale, 70 * scale)
+            await this.drawCircleImg(avatarUrl, 170 * scale, 1000 * scale, 50)
+            return Promise.resolve(true)
+        } catch (e) {
+            return Promise.reject(e)
+        }
+    }
+    
+    async drawCircleImg(img, x, y, r) {
+        const [error, result] = await uni.downloadFile({ url: img })
+        if (error) return
+        this.ctx.save()
+        this.ctx.beginPath()
+        let size = 2 * r
+        this.ctx.arc(x, y, r, 0, 2 * Math.PI)
+        this.ctx.clip()
+        this.ctx.drawImage(result.tempFilePath, x - r, y - r, size, size)
+        this.ctx.restore()
+    }
+    drawBorderReduisImage(imgUrl, bg_x, bg_y, bg_w, bg_h, bg_r) {
+        this.ctx.save()
+        this.ctx.beginPath()
+        this.ctx.arc(bg_x + bg_r, bg_y + bg_r, bg_r, Math.PI, Math.PI*1.5)
+        this.ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_r, bg_r, Math.PI * 1.5, Math.PI * 2)
+        this.ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_h - bg_r, bg_r, 0, Math.PI * 0.5)
+        this.ctx.arc(bg_x + bg_r, bg_y + bg_h - bg_r, bg_r, Math.PI * 0.5, Math.PI)
+        this.ctx.clip()
+        this.ctx.drawImage(imgUrl, bg_x, bg_y, bg_w, bg_h)
+        this.ctx.restore()
+    }
+    // 绘制底部
+    drawFooterText(callback) {
+        const { scale, textArray } = this.options
+        if (callback) {
+            callback({ scale, ctx: this.ctx, textArray })
+        } else {
+            textArray.forEach((txt, index) => {
+                this.ctx.setFontSize(30 * scale)
+                this.ctx.setFillStyle('#333')
+
+                if (txt && index === 0) {
+                    this.drawPrice(txt)
+                } else {
+                    this.ctx.fillText(txt, 56 * scale, (678 + 56 * index) * scale)
+                }
+            })
+        }
+    }
+
+    drawPrice(txt) {
+        const { scale } = this.options
+        const txts = (txt.startsWith('¥') ? txt.slice(1) : txt).split('¥')
+        let txtLeft = 60 * scale
+        txts.forEach((priceText, index) => {
+            if (index === 0) {
+                this.ctx.setFillStyle('#FF457B')
+                this.ctx.setFontSize(24 * scale)
+                this.ctx.fillText('¥', txtLeft, 954 * scale)
+                const m1 = this.ctx.measureText('¥')
+                this.ctx.setFontSize(40 * scale)
+                this.ctx.fillText(priceText, txtLeft + m1.width, 954 * scale)
+                const m2 = this.ctx.measureText(priceText)
+                txtLeft = txtLeft + m1.width + m2.width + 8
+            } else {
+                this.ctx.setFillStyle('#999')
+                this.ctx.setFontSize(24 * scale)
+                this.ctx.fillText('¥' + priceText, txtLeft, 954 * scale)
+                let m = this.ctx.measureText('¥' + priceText)
+                this.ctx.fillRect(txtLeft, 946 * scale, m.width + 4, 1)
+            }
+        })
+    }
+
+    // 绘制底部二维码
+    async drawEwmImage() {
+        try {
+            const { ewmUrl, scale } = this.options
+            const [error, result] = await uni.downloadFile({ url: ewmUrl })
+            if (error) return
+            this.ctx.drawImage(result.tempFilePath, 524 * scale, 678 * scale, 160 * scale, 160 * scale)
+            return Promise.resolve(true)
+        } catch (e) {
+            return Promise.reject(e)
+        }
+    }
+}

+ 139 - 0
components/cm-share-popup/simple-share-popup/simple-share-popup.vue

@@ -0,0 +1,139 @@
+<template>
+    <view class="simple-share-popup">
+        <cm-popup ref="sharePopup" type="bottom" :safe-area="safeArea">
+            <!-- 操作栏 -->
+            <view class="share-popup__control" @click.stop>
+                <view class="share-popup__slot"><slot></slot></view>
+                <view class="share-popup__row share-popup__items">
+                    <button
+                        open-type="share"
+                        class="share-popup__item share-popup__button share-popup__default"
+                        @click="onClick('share')"
+                    >
+                        <view class="share-popup__icon"><image :src="baseUrl + 'icon-share-wechat.png'"></image></view>
+                        <text class="share-popup__label">分享给好友</text>
+                    </button>
+                    <view class="share-popup__item share-popup__button" @click="onClick('create-poster')">
+                        <view class="share-popup__icon"><image :src="baseUrl + 'icon-poster.png'"></image></view>
+                        <text class="share-popup__label">生成海报</text>
+                    </view>
+                </view>
+                <view class="share-popup__row"><view class="share-popup__cancel" @click.stop="close">取消</view></view>
+            </view>
+        </cm-popup>
+    </view>
+</template>
+<script>
+    import cmPopup from '../uni-popup/uni-popup.vue'
+export default {
+    props: {
+        baseUrl: {
+            type: String,
+            default: 'https://static.caimei365.com/app/mini-hehe/icon/'
+        },
+        safeArea: {
+            type: Boolean,
+            default: true
+        }
+    },
+    components: {
+        cmPopup
+    },
+    methods: {
+        open() {
+            this.$refs.sharePopup.open()
+            this.$emit('open')
+        },
+        close() {
+            this.$refs.sharePopup.close()
+            this.$emit('close')
+        },
+        onClick(type) {
+            this.$emit('click', { type })
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.simple-share-popup {
+    .share-popup__control {
+        width: 100%;
+        background-color: #fff;
+        border-radius: 16rpx 16rpx 0 0;
+        padding-top: 40rpx;
+
+        &.share-popup__no__safeArea {
+            transform: translateY(34px);
+        }
+
+        &::after {
+            content: '';
+            position: absolute;
+            width: 100%;
+            height: 38px;
+            bottom: -38px;
+            background-color: #fff;
+        }
+
+        .share-popup__row {
+            display: flex;
+            justify-content: space-evenly;
+            align-items: center;
+        }
+
+        .share-popup__items {
+            padding-bottom: 40rpx;
+        }
+
+        .share-popup__button {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            flex-direction: column;
+
+            &.share-popup__default {
+                line-height: inherit;
+                padding: 0;
+                margin: 0;
+                border: 0;
+                background: transparent;
+                &::after {
+                    border: 0;
+                }
+            }
+
+            .share-popup__icon {
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                width: 100rpx;
+                height: 100rpx;
+                border-radius: 50%;
+                background-color: #f7f7f7;
+
+                image {
+                    width: 64rpx;
+                    height: 64rpx;
+                }
+            }
+
+            .share-popup__label {
+                font-size: 26rpx;
+                color: #333;
+                margin-top: 16rpx;
+            }
+        }
+
+        .share-popup__cancel {
+            width: 100%;
+            padding: 32rpx 0;
+            border-top: 1rpx solid #e1e1e1;
+            font-size: 28rpx;
+            color: #666;
+            font-weight: bold;
+            text-align: center;
+        }
+    }
+}
+</style>

+ 45 - 0
components/cm-share-popup/uni-popup/keypress.js

@@ -0,0 +1,45 @@
+// #ifdef H5
+export default {
+  name: 'Keypress',
+  props: {
+    disable: {
+      type: Boolean,
+      default: false
+    }
+  },
+  mounted () {
+    const keyNames = {
+      esc: ['Esc', 'Escape'],
+      tab: 'Tab',
+      enter: 'Enter',
+      space: [' ', 'Spacebar'],
+      up: ['Up', 'ArrowUp'],
+      left: ['Left', 'ArrowLeft'],
+      right: ['Right', 'ArrowRight'],
+      down: ['Down', 'ArrowDown'],
+      delete: ['Backspace', 'Delete', 'Del']
+    }
+    const listener = ($event) => {
+      if (this.disable) {
+        return
+      }
+      const keyName = Object.keys(keyNames).find(key => {
+        const keyName = $event.key
+        const value = keyNames[key]
+        return value === keyName || (Array.isArray(value) && value.includes(keyName))
+      })
+      if (keyName) {
+        // 避免和其他按键事件冲突
+        setTimeout(() => {
+          this.$emit(keyName, {})
+        }, 0)
+      }
+    }
+    document.addEventListener('keyup', listener)
+    // this.$once('hook:beforeDestroy', () => {
+    //   document.removeEventListener('keyup', listener)
+    // })
+  },
+	render: () => {}
+}
+// #endif

+ 26 - 0
components/cm-share-popup/uni-popup/popup.js

@@ -0,0 +1,26 @@
+
+export default {
+	data() {
+		return {
+			
+		}
+	},
+	created(){
+		this.popup = this.getParent()
+	},
+	methods:{
+		/**
+		 * 获取父元素实例
+		 */
+		getParent(name = 'uniPopup') {
+			let parent = this.$parent;
+			let parentName = parent.$options.name;
+			while (parentName !== name) {
+				parent = parent.$parent;
+				if (!parent) return false
+				parentName = parent.$options.name;
+			}
+			return parent;
+		},
+	}
+}

+ 437 - 0
components/cm-share-popup/uni-popup/uni-popup.vue

@@ -0,0 +1,437 @@
+<template>
+	<view v-if="showPopup" class="uni-popup" :class="[popupstyle, isDesktop ? 'fixforpc-z-index' : '']" @touchmove.stop.prevent="clear">
+		<view @touchstart="touchstart" >
+			<uni-transition key="1" v-if="maskShow" name="mask" mode-class="fade" :styles="maskClass" :duration="duration" :show="showTrans" @click="onTap" />
+			<uni-transition key="2" :mode-class="ani" name="content" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
+				<view class="uni-popup__wrapper" :style="{ backgroundColor: bg }" :class="[popupstyle]" @click="clear"><slot /></view>
+			</uni-transition>
+		</view>
+		<!-- #ifdef H5 -->
+		<keypress v-if="maskShow" @esc="onTap" />
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+// #ifdef H5
+import keypress from './keypress.js'
+// #endif
+
+/**
+ * PopUp 弹出层
+ * @description 弹出层组件,为了解决遮罩弹层的问题
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+ * @property {String} type = [top|center|bottom|left|right|message|dialog|share] 弹出方式
+ * 	@value top 顶部弹出
+ * 	@value center 中间弹出
+ * 	@value bottom 底部弹出
+ * 	@value left		左侧弹出
+ * 	@value right  右侧弹出
+ * 	@value message 消息提示
+ * 	@value dialog 对话框
+ * 	@value share 底部分享示例
+ * @property {Boolean} animation = [true|false] 是否开启动画
+ * @property {Boolean} maskClick = [true|false] 蒙版点击是否关闭弹窗(废弃)
+ * @property {Boolean} isMaskClick = [true|false] 蒙版点击是否关闭弹窗
+ * @property {String}  backgroundColor 主窗口背景色
+ * @property {String}  maskBackgroundColor 蒙版颜色
+ * @property {Boolean} safeArea		   是否适配底部安全区
+ * @event {Function} change 打开关闭弹窗触发,e={show: false}
+ * @event {Function} maskClick 点击遮罩触发
+ */
+
+export default {
+	name: 'uniPopup',
+	components: {
+		// #ifdef H5
+		keypress
+		// #endif
+	},
+	emits:['change','maskClick'],
+	props: {
+		// 开启动画
+		animation: {
+			type: Boolean,
+			default: true
+		},
+		// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
+		// message: 消息提示 ; dialog : 对话框
+		type: {
+			type: String,
+			default: 'center'
+		},
+		// maskClick
+		isMaskClick: {
+			type: Boolean,
+			default: null
+		},
+		// TODO 2 个版本后废弃属性 ,使用 isMaskClick
+		maskClick: {
+			type: Boolean,
+			default: null
+		},
+		backgroundColor: {
+			type: String,
+			default: 'none'
+		},
+		safeArea:{
+			type: Boolean,
+			default: true
+		},
+		maskBackgroundColor: {
+			type: String,
+			default: 'rgba(0, 0, 0, 0.4)'
+		},
+	},
+
+	watch: {
+		/**
+		 * 监听type类型
+		 */
+		type: {
+			handler: function(type) {
+				if (!this.config[type]) return
+				this[this.config[type]](true)
+			},
+			immediate: true
+		},
+		isDesktop: {
+			handler: function(newVal) {
+				if (!this.config[newVal]) return
+				this[this.config[this.type]](true)
+			},
+			immediate: true
+		},
+		/**
+		 * 监听遮罩是否可点击
+		 * @param {Object} val
+		 */
+		maskClick: {
+			handler: function(val) {
+				this.mkclick = val
+			},
+			immediate: true
+		},
+		isMaskClick: {
+			handler: function(val) {
+				this.mkclick = val
+			},
+			immediate: true
+		},
+		// H5 下禁止底部滚动
+		showPopup(show) {
+			// #ifdef H5
+			// fix by mehaotian 处理 h5 滚动穿透的问题
+			document.getElementsByTagName('body')[0].style.overflow = show ? 'hidden' : 'visible'
+			// #endif
+		}
+	},
+	data() {
+		return {
+			duration: 300,
+			ani: [],
+			showPopup: false,
+			showTrans: false,
+			popupWidth: 0,
+			popupHeight: 0,
+			config: {
+				top: 'top',
+				bottom: 'bottom',
+				center: 'center',
+				left: 'left',
+				right: 'right',
+				message: 'top',
+				dialog: 'center',
+				share: 'bottom'
+			},
+			maskClass: {
+				position: 'fixed',
+				bottom: 0,
+				top: 0,
+				left: 0,
+				right: 0,
+				backgroundColor: 'rgba(0, 0, 0, 0.4)'
+			},
+			transClass: {
+				position: 'fixed',
+				left: 0,
+				right: 0
+			},
+			maskShow: true,
+			mkclick: true,
+			popupstyle: this.isDesktop ? 'fixforpc-top' : 'top'
+		}
+	},
+	computed: {
+		isDesktop() {
+			return this.popupWidth >= 500 && this.popupHeight >= 500
+		},
+		bg() {
+			if (this.backgroundColor === '' || this.backgroundColor === 'none') {
+				return 'transparent'
+			}
+			return this.backgroundColor
+		}
+	},
+	mounted() {
+		const fixSize = () => {
+			const { windowWidth, windowHeight, windowTop, safeArea,screenHeight ,safeAreaInsets } = uni.getSystemInfoSync()
+			this.popupWidth = windowWidth
+			this.popupHeight = windowHeight + windowTop
+			// TODO fix by mehaotian 是否适配底部安全区 ,目前微信ios 、和 app ios 计算有差异,需要框架修复
+			if(safeArea){
+				// #ifdef MP-WEIXIN
+				this.safeAreaInsets = screenHeight - safeArea.bottom
+				// #endif
+				// #ifndef MP-WEIXIN
+				this.safeAreaInsets = safeAreaInsets.bottom
+				// #endif
+			}else{
+				this.safeAreaInsets = 0
+			}
+		}
+		fixSize()
+		// #ifdef H5
+		// window.addEventListener('resize', fixSize)
+		// this.$once('hook:beforeDestroy', () => {
+		// 	window.removeEventListener('resize', fixSize)
+		// })
+		// #endif
+	},
+	created() {
+		// this.mkclick =  this.isMaskClick || this.maskClick
+		if(this.isMaskClick === null && this.maskClick === null){
+			this.mkclick  = true
+		}else{
+			this.mkclick = this.isMaskClick !== null ? this.isMaskClick : this.maskClick
+		}
+		if (this.animation) {
+			this.duration = 300
+		} else {
+			this.duration = 0
+		}
+		// TODO 处理 message 组件生命周期异常的问题
+		this.messageChild = null
+		// TODO 解决头条冒泡的问题
+		this.clearPropagation = false
+		this.maskClass.backgroundColor = this.maskBackgroundColor
+	},
+	methods: {
+		/**
+		 * 公用方法,不显示遮罩层
+		 */
+		closeMask() {
+			this.maskShow = false
+		},
+		/**
+		 * 公用方法,遮罩层禁止点击
+		 */
+		disableMask() {
+			this.mkclick = false
+		},
+		// TODO nvue 取消冒泡
+		clear(e) {
+			// #ifndef APP-NVUE
+			e.stopPropagation()
+			// #endif
+			this.clearPropagation = true
+		},
+
+		open(direction) {
+			let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share']
+			if (!(direction && innerType.indexOf(direction) !== -1)) {
+				direction = this.type
+			}
+			if (!this.config[direction]) {
+				console.error('缺少类型:', direction)
+				return
+			}
+			this[this.config[direction]]()
+			this.$emit('change', {
+				show: true,
+				type: direction
+			})
+		},
+		close(type) {
+			this.showTrans = false
+			this.$emit('change', {
+				show: false,
+				type: this.type
+			})
+			clearTimeout(this.timer)
+			// // 自定义关闭事件
+			// this.customOpen && this.customClose()
+			this.timer = setTimeout(() => {
+				this.showPopup = false
+			}, 300)
+		},
+		// TODO 处理冒泡事件,头条的冒泡事件有问题 ,先这样兼容
+		touchstart(){
+			this.clearPropagation = false
+		},
+
+		onTap() {
+			if (this.clearPropagation) {
+				// fix by mehaotian 兼容 nvue
+				this.clearPropagation = false
+				return
+			}
+			this.$emit('maskClick')
+			if (!this.mkclick) return
+			this.close()
+		},
+		/**
+		 * 顶部弹出样式处理
+		 */
+		top(type) {
+			this.popupstyle = this.isDesktop ? 'fixforpc-top' : 'top'
+			this.ani = ['slide-top']
+			this.transClass = {
+				position: 'fixed',
+				left: 0,
+				right: 0,
+				backgroundColor: this.bg
+			}
+			// TODO 兼容 type 属性 ,后续会废弃
+			if (type) return
+			this.showPopup = true
+			this.showTrans = true
+			this.$nextTick(() => {
+				if (this.messageChild && this.type === 'message') {
+					this.messageChild.timerClose()
+				}
+			})
+		},
+		/**
+		 * 底部弹出样式处理
+		 */
+		bottom(type) {
+			this.popupstyle = 'bottom'
+			this.ani = ['slide-bottom']
+			this.transClass = {
+				position: 'fixed',
+				left: 0,
+				right: 0,
+				bottom: 0,
+				paddingBottom: this.safeAreaInsets+'px',
+				backgroundColor: this.bg
+			}
+			// TODO 兼容 type 属性 ,后续会废弃
+			if (type) return
+			this.showPopup = true
+			this.showTrans = true
+		},
+		/**
+		 * 中间弹出样式处理
+		 */
+		center(type) {
+			this.popupstyle = 'center'
+			this.ani = ['zoom-out', 'fade']
+			this.transClass = {
+				position: 'fixed',
+				/* #ifndef APP-NVUE */
+				display: 'flex',
+				flexDirection: 'column',
+				/* #endif */
+				bottom: 0,
+				left: 0,
+				right: 0,
+				top: 0,
+				justifyContent: 'center',
+				alignItems: 'center'
+			}
+			// TODO 兼容 type 属性 ,后续会废弃
+			if (type) return
+			this.showPopup = true
+			this.showTrans = true
+		},
+		left(type) {
+			this.popupstyle = 'left'
+			this.ani = ['slide-left']
+			this.transClass = {
+				position: 'fixed',
+				left: 0,
+				bottom: 0,
+				top: 0,
+				backgroundColor: this.bg,
+				/* #ifndef APP-NVUE */
+				display: 'flex',
+				flexDirection: 'column'
+				/* #endif */
+			}
+			// TODO 兼容 type 属性 ,后续会废弃
+			if (type) return
+			this.showPopup = true
+			this.showTrans = true
+		},
+		right(type) {
+			this.popupstyle = 'right'
+			this.ani = ['slide-right']
+			this.transClass = {
+				position: 'fixed',
+				bottom: 0,
+				right: 0,
+				top: 0,
+				backgroundColor: this.bg,
+				/* #ifndef APP-NVUE */
+				display: 'flex',
+				flexDirection: 'column'
+				/* #endif */
+			}
+			// TODO 兼容 type 属性 ,后续会废弃
+			if (type) return
+			this.showPopup = true
+			this.showTrans = true
+		}
+	}
+}
+</script>
+<style lang="scss" >
+.uni-popup {
+	position: fixed;
+	/* #ifndef APP-NVUE */
+	z-index: 99;
+	/* #endif */
+	&.top,
+	&.left,
+	&.right {
+		/* #ifdef H5 */
+		top: var(--window-top);
+		/* #endif */
+		/* #ifndef H5 */
+		top: 0;
+		/* #endif */
+	}
+	.uni-popup__wrapper {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: relative;
+		/* iphonex 等安全区设置,底部安全区适配 */
+		/* #ifndef APP-NVUE */
+		// padding-bottom: constant(safe-area-inset-bottom);
+		// padding-bottom: env(safe-area-inset-bottom);
+		/* #endif */
+		&.left,
+		&.right {
+			/* #ifdef H5 */
+			padding-top: var(--window-top);
+			/* #endif */
+			/* #ifndef H5 */
+			padding-top: 0;
+			/* #endif */
+			flex: 1;
+		}
+	}
+}
+
+.fixforpc-z-index {
+	/* #ifndef APP-NVUE */
+	z-index: 999;
+	/* #endif */
+}
+
+.fixforpc-top {
+	top: 0;
+}
+</style>

+ 1 - 1
manifest.json

@@ -90,4 +90,4 @@
     "uniStatistics" : {
         "version" : "1"
     }
-}
+}

+ 49 - 2
pages.json

@@ -909,8 +909,55 @@
 					"style": {
 						"navigationBarTitleText": "关联咨询记录"
 					}
-				}
-			]
+				},
+                {
+                	"path": "remarks/business-card",
+                	"style": {
+                		"navigationBarTitleText": "我的名片"
+                	}
+                },
+                {
+                	"path": "remarks/mine-qrcode",
+                	"style": {
+                		"navigationBarTitleText": "二维码"
+                	}
+                },
+                {
+                	"path": "remarks/mine-card",
+                	"style": {
+                		"navigationBarTitleText": "我的名片"
+                	}
+                },
+                {
+                	"path": "remarks/institutional-activity-analysis",
+                	"style": {
+                		"navigationBarTitleText": "机构活跃分析",
+                        "enablePullDownRefresh": true,
+                        "navigationStyle": "custom"
+                	}
+                },
+                {
+                    "path" : "notice/service/service",
+                    "style" : {
+                        "navigationBarTitleText": "服务通知",
+                        "enablePullDownRefresh": true
+                    }
+                },
+                {
+                    "path" : "notice/service/Institutional_visits",
+                    "style" : {
+                        "navigationBarTitleText": "机构访问通知",
+                        "enablePullDownRefresh": true
+                    }
+                },
+                {
+                    "path" : "notice/service/visits_details",
+                    "style" : {
+                        "navigationBarTitleText": "访问详情",
+                        "enablePullDownRefresh": true
+                    }
+                }
+            ]
 		},
 		{
 			"root": "pages/h5/", //活动分包模块

+ 105 - 0
pages/goods/mixins/share.helper.js

@@ -0,0 +1,105 @@
+// import { encrypt } from '@/common/crypto.js'
+/* 小程序码 */
+import store from '@/store/index.js'
+import { wxUnlimited } from '@/services/sellse.service.js'
+const fs = uni.getFileSystemManager()
+const qrcodePath = `${wx.env.USER_DATA_PATH}/qrcodePath`
+
+const defalutOptions = {
+    title: '护肤上颜选,正品有好货~',
+    path: '/pages/index/index',
+    imageUrl: 'https://static.caimei365.com/app/mini-hehe/icon/icon-share.png'
+}
+
+export function shareDataResult(shareData, title, coverUrl) {
+    const state_str = encodeURIComponent(encrypt(shareData))
+    const result = {
+        title: title || defalutOptions.title,
+        path: `${defalutOptions.path}?state_str=${state_str}`,
+        imageUrl: coverUrl || defalutOptions.imageUrl
+    }
+    return result
+}
+
+const queryKeyOfMap = {
+    'type': 't',
+    'inviteUserId': 'i',
+    'activityId': 'a',
+    'dealerUserId': 'd',
+    'keyWord': 'k',
+    'productId': 'p',
+    'jumpState': 'j',
+    'collageId': 'c'
+}
+
+const enQueryKeyOfMap = {
+    't': 'type',
+    'i': 'inviteUserId',
+    'a': 'activityId',
+    'd': 'dealerUserId',
+    'k': 'keyWord',
+    'p': 'productId',
+    'j': 'jumpState',
+    'c': 'collageId'
+}
+
+// 创建二维码保存路径
+function createQrcodeDir(callback) {
+    try {
+        fs.accessSync(qrcodePath)
+        console.log('已存在文件夹')
+        callback(qrcodePath)
+    } catch (e) {
+        fs.mkdirSync(qrcodePath)
+        console.log('不存在文件夹')
+        callback(qrcodePath)
+    }
+}
+
+
+/* 生成二维码链接 */
+export const generateWxUnlimited = async (params) => {
+    try {
+        // 从服务端获取二维码arrayBuffer
+        return await this.SellerService.wxUnlimited({
+            page: params.pagePath || 'pages/index/index',
+            scene: codeQueryStr(params.queryStr),
+            check_path: process.env.NODE_ENV === 'production', // 是否校验页面
+            env_version: process.env.NODE_ENV === 'production' ? 'release' : 'trial', // 正式版 or 开发版
+            width: 200, // 二维码宽度
+            auto_color: false, // 自动颜色
+            line_color: { 'r': 0, 'g': 0, 'b': 0 }, // 线条颜色
+            is_hyaline: true // 透明底
+        })
+    } catch (e) {
+        return Promise.reject(e)
+    }
+}
+
+// 编码查询参数
+export function codeQueryStr(query = '') {
+    const keys = Object.keys(queryKeyOfMap)
+    return query.split('&').map(str => {
+        return str.split('=').map((substr, index) => {
+            if (!index) {
+                return queryKeyOfMap[keys.find(item => substr === item)]
+            } else {
+                return substr
+            }
+        }).join('=')
+    }).join('&')
+}
+
+// 反编码查询参数
+export function enCodeQueryStr(query) {
+    const keys = Object.keys(enQueryKeyOfMap)
+    return query.split('&').map(str => {
+        return str.split('=').map((substr, index) => {
+            if (!index) {
+                return enQueryKeyOfMap[keys.find(item => substr === item)]
+            } else {
+                return substr
+            }
+        }).join('=')
+    }).join('&')
+}

+ 34 - 5
pages/goods/product.vue

@@ -138,10 +138,14 @@
 									<view class="p-title-name" :class="product.beautyActFlag == '1' ? 'indent' : ''">
 										{{ product.name == undefined ? '' : product.name }}
 									</view>
-									<button open-type="share" class="p-title-share tui-share-position" @tap="onShare">
+		<!-- 							<button open-type="share" class="p-title-share tui-share-position" @tap="onShare">
 										<view class=""><text class="iconfont icon-fenxiang1"></text></view>
 										<view class="">分享</view>
-									</button>
+									</button> -->
+                                    <button class="p-title-share tui-share-position" @click="handleShare">
+                                        <view class=""><text class="iconfont icon-fenxiang1"></text></view>
+                                        <view class="">分享</view>
+                                    </button>
 								</view>
 								<view class="wrap-label" v-if="product.tagsList && product.tagsList.length > 0">
 									<view
@@ -592,6 +596,12 @@
 		/>
 		<!-- ross弹窗 -->
 		<cmRossPopup v-if="showRossHtml" :popupShow="showRossHtml"></cmRossPopup>
+        
+        <!-- 分享弹窗 -->
+        <cm-share-popup ref="sharePopup" :data="posterData" type="product"></cm-share-popup>
+        
+        <!-- 协销名片 -->
+        <cm-seller-modal :sellerUserId="sellerUserId"></cm-seller-modal>
 	</view>
 </template>
 
@@ -617,6 +627,8 @@ import payMixins from '@/mixins/payMixins.js'
 import proMixins from './mixins/proMixins.js'
 import cmSrsMixins from '@/utils/cmSrsMixins.js'
 import thorui from '@/components/clipboard/clipboard.thorui.js'
+import cmSharePopup from '@/components/cm-share-popup/cm-share-popup.vue'
+import cmSellerModal from '@/components/cm-share-popup/cm-seller-modal.vue'
 var isPreviewImg
 export default {
 	mixins: [payMixins,proMixins,cmSrsMixins],
@@ -633,7 +645,9 @@ export default {
 		cmUnitPopup,
 		cmProductModal,
 		cmRossPopup,
-        cmReturnInstructions
+        cmReturnInstructions,
+        cmSharePopup,
+        cmSellerModal
 	},
 	data() {
 		return {
@@ -744,10 +758,12 @@ export default {
 			unitPopupType: 0 ,// 选择类型 1 点击加入购物车  立即购买  2:点击规格选择
             returnGoodsStutas: false,
             helpContent: '',
+            posterData: {}, // 商品详情
+            sellerUserId: 0, // 协销id
 		}
 	},
 	computed: {
-		...mapState(['hasLogin', 'clubType', 'identity', 'isIphoneX'])
+		...mapState(['hasLogin', 'clubType', 'identity', 'isIphoneX', 'userInfo'])
 	},
 	filters: {
 		TypeFormat(value) {
@@ -793,6 +809,8 @@ export default {
 		if (option.page == 2) {
 			this.backPage = option.page
 		}
+        console.log('options', option)
+        this.sellerUserId = option.sellerUserId
 		this.getWinHeight()
 	},
 	onReady() {
@@ -1355,6 +1373,16 @@ export default {
 				imageUrl: `${this.productImage[0]}`
 			}
 		},
+        // 分享海报
+        handleShare() {
+            this.posterData = {
+                productName: this.product.name,
+                productImage: this.productImage[0],
+                sellerUserId: this.sellerUserId,
+                path: 'pages/goods/product'
+            }
+            this.$refs.sharePopup.open()
+        },
 		handleCollection() {
 			// 收藏
 			if (this.hasLogin) {
@@ -1539,9 +1567,10 @@ export default {
 		if (res.from === 'button') {
 			// 来自页面内转发按钮
 		}
+        console.log('path', `pages/goods/product?type=share&id=${this.productId}&sellerUserId=${this.userInfo.userIdentity === 1 ? this.userInfo.userId : 0}`)
 		return {
 			title: `${this.product.name}`,
-			path: `pages/goods/product?type=share&id=${this.productId}`,
+			path: `pages/goods/product?type=share&id=${this.productId}&sellerUserId=${this.userInfo.userIdentity === 1 ? this.userInfo.userId : 0}`,
 			imageUrl: `${this.productImage[0]}`
 		}
 	},

+ 109 - 89
pages/seller/club/list.vue

@@ -13,44 +13,52 @@
 					<text v-if="isShowIndex" @click="handleNavigateIndex" class="iconfont icon-shouye"></text>
 					<text v-else @click="handleNavigateBack" class="iconfont icon-fanhui"></text>
 				</view>
-				<view
-					class="search-from name"
-					:style="{ height: capsule.height + 'px', borderRadius: capsule.height / 2 + 'px' }"
-				>
-					<text
-						:style="{
-							width: capsule.height + 'px',
-							height: capsule.height + 'px',
-							lineHeight: capsule.height + 'px;'
-						}"
-						class="iconfont icon-iconfonticonfontsousuo1"
-					></text>
-					<input
-						class="input"
-						type="text"
-						confirm-type="search"
-						v-model="listQuery.name"
-						@input="onShowClose"
-						@confirm="GetSellerClubList()"
-						placeholder="机构名称/联系人/手机号"
-						maxlength="16"
-						:style="{ lineHeight: capsule.height + 'px' }"
-					/>
-					<text class="iconfont icon-shanchu1" v-if="isShowClose" @click="delInputText()"></text>
-				</view>
-				<view
-					class="search-btn"
-					:style="{
-						width: CustomBar - StatusBar + 'px',
-						height: capsule.height + 'px',
-						lineHeight: capsule.height + 'px;'
-					}"
-					v-if="isManage && tabSmallCurrentIndex == 1"
-					@click="showRightDrawer"
-				>
-					<text class="iconfont icon-shaixuan"></text>
-				</view>
+                <view class="title">
+                    机构列表
+                </view>
 			</view>
+            <view style="display: flex;align-items: center;">
+                <view
+                	class="search-from name"
+                	:style="{ height: capsule.height + 'px', borderRadius: capsule.height / 2 + 'px' }"
+                >
+                	<text
+                		:style="{
+                			width: capsule.height + 'px',
+                			height: capsule.height + 'px',
+                			lineHeight: capsule.height + 'px;'
+                		}"
+                		class="iconfont icon-iconfonticonfontsousuo1"
+                	></text>
+                	<input
+                		class="input"
+                		type="text"
+                		confirm-type="search"
+                		v-model="listQuery.name"
+                		@input="onShowClose"
+                		@confirm="GetSellerClubList()"
+                		placeholder="机构名称/联系人/手机号"
+                		maxlength="16"
+                		:style="{ lineHeight: capsule.height + 'px' }"
+                	/>
+                	<text class="iconfont icon-shanchu1" v-if="isShowClose" @click="delInputText()"></text>
+                </view>
+                <view
+                	class="search-btn"
+                	:style="{
+                		width: CustomBar - StatusBar + 'px',
+                		height: capsule.height + 'px',
+                		lineHeight: capsule.height + 'px;'
+                	}"
+                	v-if="isManage && tabSmallCurrentIndex == 1"
+                	@click="showRightDrawer"
+                >
+                	<text class="iconfont icon-shaixuan"></text>
+                </view>
+                <view class="search-btn" v-if="!isManage || tabSmallCurrentIndex != 1">
+                    搜索
+                </view>
+            </view>
 			<view class="search-tab">
 				<view
 					class="tab-item"
@@ -62,7 +70,7 @@
 					<text class="item-text">{{ item.name }}<text class="line"></text></text>
 				</view>
 			</view>
-			<view class="search-smalltab" v-if="isManage">
+			<view class="search-smalltab">
 				<view
 					class="tab-item"
 					v-for="(item, index) in listItemTab"
@@ -74,7 +82,7 @@
 				</view>
 			</view>
 		</view>
-		<view class="club-main" :style="{ paddingTop: isManage ? '374rpx' : '254rpx' }">
+		<view class="club-main" style="margin-top: 508rpx;">
 			<view v-if="isEmpty" class="empty-container">
 				<image
 					class="club-empty-image"
@@ -261,7 +269,7 @@ export default {
 	data() {
 		return {
 			listTab: [{ name: '个人机构' }, { name: '资质机构' }],
-			listItemTab: [{ name: '我的机构' }, { name: '组员机构' }],
+			listItemTab: [{ name: '我的机构' }, { name: '组员机构' }, {name: '新分配机构'}],
 			listQuery: Object.assign({}, defaultListQuery),
 			isShowClose: false,
 			isEmpty: false,
@@ -296,6 +304,9 @@ export default {
 		if (option.type === 'wechat') {
 			this.isShowIndex = true
 		}
+        if (!this.isManage) {
+            this.listItemTab = this.listItemTab.filter((e, i) => i === 2)
+        }
 	},
 	computed: {
 		...mapState(['isManage'])
@@ -534,7 +545,7 @@ export default {
 			this.$api.navigateBack(1)
 		},
 		handleNavigateIndex() {
-			this.$api.navigateTo(`/pages/seller/index/index`)
+			this.$api.navigateTo('/pages/seller/index/index')
 		},
 		handleShowBubble(club, index) {
 			this.currentIndex = index
@@ -582,6 +593,13 @@ page,
 		display: flex;
 		align-items: center;
 		box-sizing: border-box;
+        position: relative;
+        .title {
+            position: absolute;
+            left: 50%;
+            top: 50%;
+            transform: translate(-50%, -50%);
+        }
 		.search-icon {
 			text-align: center;
 			float: left;
@@ -594,50 +612,50 @@ page,
 				color: #333333;
 			}
 		}
-		.search-from {
-			width: 382rpx;
-			background: #f7f7f7;
-			float: left;
-			position: relative;
-			.input {
-				width: 300rpx;
-				height: 100%;
-				float: left;
-				color: $text-color;
-				font-size: $font-size-24;
-			}
-			.icon-iconfonticonfontsousuo1 {
-				text-align: center;
-				display: block;
-				font-size: $font-size-38;
-				float: left;
-				color: #999999;
-			}
-			.icon-shanchu1 {
-				font-size: $font-size-32;
-				color: #999999;
-				position: absolute;
-				width: 64rpx;
-				height: 64rpx;
-				line-height: 64rpx;
-				text-align: center;
-				top: 0;
-				right: 0;
-				z-index: 10;
-			}
-		}
-		.search-btn {
-			text-align: center;
-			font-size: $font-size-28;
-			color: $color-system;
-			float: left;
-			background: #ffffff;
-			.icon-shaixuan {
-				font-size: 44rpx;
-				color: #333333;
-			}
-		}
 	}
+    .search-from {
+    	background: #f7f7f7;
+    	position: relative;
+        width: 604rpx;
+        margin: 50rpx 20rpx 40rpx 24rpx;
+    	.input {
+    		width: 300rpx;
+    		height: 100%;
+    		float: left;
+    		color: $text-color;
+    		font-size: $font-size-24;
+    	}
+    	.icon-iconfonticonfontsousuo1 {
+    		text-align: center;
+    		display: block;
+    		font-size: $font-size-38;
+    		float: left;
+    		color: #999999;
+    	}
+    	.icon-shanchu1 {
+    		font-size: $font-size-32;
+    		color: #999999;
+    		position: absolute;
+    		width: 64rpx;
+    		height: 64rpx;
+    		line-height: 64rpx;
+    		text-align: center;
+    		top: 0;
+    		right: 0;
+    		z-index: 10;
+    	}
+    }
+    .search-btn {
+    	text-align: center;
+    	font-size: $font-size-28;
+    	color: $color-system;
+    	float: left;
+    	background: #ffffff;
+    	.icon-shaixuan {
+    		font-size: 44rpx;
+    		color: #333333;
+    	}
+    }
 	.search-tab {
 		height: 80rpx;
 		display: flex;
@@ -677,19 +695,21 @@ page,
 		height: 104rpx;
 		background: #ffffff;
 		box-sizing: border-box;
-		padding: 20rpx 10rpx;
+		padding: 20rpx 24rpx;
 		.tab-item {
-			width: 180rpx;
+			width: 168rpx;
 			height: 64rpx;
 			line-height: 64rpx;
 			text-align: center;
 			color: $text-color;
 			font-size: $font-size-28;
 			float: left;
+            border-radius: 32rpx;
+            border: 1px solid #B2B2B2;
+            margin-right: 32rpx;
 			&.current {
-				background-color: $color-system;
-				color: #fff;
-				border-radius: 32rpx;
+				color: #FF5B00;
+                border: 1px solid #FF5B00;
 			}
 		}
 	}

+ 226 - 0
pages/seller/components/message.vue

@@ -0,0 +1,226 @@
+<template>
+    <view class="notice clearfix" :style="{ paddingTop: CustomBar + 'px' }">
+    	<tui-skeleton
+    		v-if="skeletonShow"
+    		backgroundColor="#fafafa"
+    		borderRadius="10rpx"
+    		:isLoading="true"
+    		:loadingType="5"
+    	></tui-skeleton>
+    	<view v-else>
+    		<view class="navbar-wrap" :style="{ height: CustomBar + 'px', paddingTop: StatusBar + 'px' }">
+    			<view
+    				class="navbar-text"
+    				:style="{ lineHeight: CustomBar - StatusBar + 'px;', fontSize: fontSizeSetting + 'px;' }"
+    			>
+    				消息 <text @click="clearNews" class="iconfont icon-qingli"></text>
+    			</view>
+    		</view>
+    		<view class="container-notice">
+    			<view class="notice-cell" @click="$api.navigateTo('/pages/seller/notice/service/service?messageType=1')">
+    				<view class="notice-cell-icon">
+    					<image class="icon-image" :src="StaticUrl + 'icon/icon-notice-serve@2x.png'" mode=""></image>
+    				</view>
+    				<view class="notice-cell-text"> 服务通知 <text class="cell-text">官方</text> </view>
+    				<view class="notice-cell-badge" v-if="notificationCount > 0">
+    					<text class="uni-badge uni-badge-error uni-small uni-badge--small icon-num">
+    						{{ notificationCount | BadgeType }}
+    					</text>
+    				</view>
+    			</view>
+    		</view>
+    	</view>
+    </view>
+</template>
+
+<script>
+    import { mapState, mapMutations } from 'vuex'
+    export default {
+        data() {
+            return {
+                CustomBar: this.CustomBar,
+                StatusBar: this.StatusBar,
+                StaticUrl: this.$Static,
+                notificationCount: 100,
+                skeletonShow: false,
+                clubId: 0,
+                allCount:0,
+                tradeCount: 0,
+                accountCount: 0,
+                promotionCount: 0
+            }
+        },
+        filters: {
+        	BadgeType(value) {
+        		if (value) {
+        			return value > 99 ? '99+' : value
+        		}
+        	}
+        },
+        computed: {
+        	...mapState(['hasLogin', 'userInfo'])
+        },
+        onPullDownRefresh() {
+        	//下拉刷新
+        	this.initData()
+        	uni.stopPullDownRefresh()
+        },
+        mounted() {
+            this.initData()
+        },
+        methods: {
+            ...mapMutations(['updateSellerNoticeNum']),
+            initData() {
+                this.updateSellerNoticeNum()
+            },
+            // 请求信息列表
+            async getMessageList(){
+                console.log(1111)
+            },
+            // 清理未读消息
+            clearNews() {
+            	// 标记消息已读
+            	if(this.allCount == 0){
+            		this.$util.msg('暂无未读消息', 2000)
+            		return
+            	}
+            	this.UserService.authUpdateMessageAsRead({ commonId:this.clubId,messageType: '' })
+                .then(response => {
+                    uni.vibrateShort({
+                        success: function() {
+                            console.log('success')
+                        }
+                    })
+                    this.initData()
+                    this.$util.msg('已将所有消息标记为已读', 2000)
+                })
+                .catch(error => {
+                    console.log('标记通知消息已读', error.msg)
+                })
+            },
+            // 协销账户
+            getUserAuthClubMessageCount() {
+            	//供应商详情
+            	this.UserService.getUserAuthClubMessageCount({ commonId: this.clubId })
+            		.then(response => {
+            			this.allCount = response.data.count
+            			this.tradeCount = response.data.tradeCount // 交易物流
+            			this.accountCount = response.data.account // 账户通知
+            			this.notificationCount = response.data.notificationCount // 服务通知
+            			this.promotionCount = response.data.promotionCount // 优惠促销
+            			this.skeletonShow = false //预加载圆圈隐藏
+            		})
+            		.catch(error => {
+            			this.$util.msg(error.msg, 2000)
+            		})
+            	this.skeletonShow = false
+            },
+        }
+    }
+</script>
+
+<style lang="scss" scoped>
+.navbar-wrap {
+	position: fixed;
+	width: 100%;
+	top: 0;
+	z-index: 100000;
+	box-sizing: border-box;
+	background: #ffffff;
+	.navbar-text {
+		font-size: 30rpx;
+		color: #000000;
+		font-weight: 500;
+		text-align: center;
+		.iconfont {
+			display: inline-block;
+			width: 48rpx;
+			height: 48rpx;
+			border-radius: 50%;
+			background-color: #f5f5f5;
+			text-align: center;
+			line-height: 48rpx;
+			color: #666666;
+			font-size: 30rpx;
+			margin-left: 20rpx;
+		}
+	}
+}
+.container-notice {
+    width: 100%;
+    height: auto;
+    box-sizing: border-box;
+    padding: 0 24rpx;
+    padding-top: 20rpx;
+    .notice-cell {
+        width: 100%;
+        height: 130rpx;
+        box-sizing: border-box;
+        padding: 19rpx 0;
+        border-bottom: 1px solid #e1e1e1;
+        .notice-cell-icon {
+            width: 92rpx;
+            height: 92rpx;
+            float: left;
+            .icon-image {
+                width: 92rpx;
+                height: 92rpx;
+                display: block;
+            }
+        }
+        .notice-cell-text {
+            width: 400rpx;
+            height: 100%;
+            line-height: 92rpx;
+            font-size: 34rpx;
+            text-align: left;
+            margin-left: 24rpx;
+            float: left;
+            .cell-text {
+                display: inline-block;
+                height: 32rpx;
+                padding: 0 11rpx;
+                line-height: 32rpx;
+                border-radius: 20rpx;
+                text-align: center;
+                border: 1px solid #FF5B00;
+                font-size: 24rpx;
+                color: #FF5B00;
+                margin-left: 10rpx;
+            }
+        }
+        .notice-cell-badge {
+            width: 92rpx;
+            height: 92rpx;
+            float: right;
+            box-sizing: border-box;
+            padding: 25rpx 15rpx;
+            text-align: right;
+        }
+    }
+}
+.uni-badge--small {
+    -webkit-transform: scale(0.8);
+    -ms-transform: scale(0.8);
+    transform: scale(0.8);
+    -webkit-transform-origin: center center;
+    -ms-transform-origin: center center;
+    transform-origin: center center;
+}
+.uni-badge {
+    font-family: 'Helvetica Neue', Helvetica, sans-serif;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+    font-size: 12px;
+    line-height: 1;
+    display: inline-block;
+    padding: 3px 6px;
+    color: #333;
+    border-radius: 100px;
+    background-color: #f1f1f1;
+}
+.uni-badge-error {
+    color: #fff;
+    background-color: #ff2a2a;
+}
+</style>

+ 11 - 1
pages/seller/components/user.vue

@@ -241,7 +241,17 @@ export default {
 					name: '客户咨询记录',
 					path: '/pages/seller/remarks/list',
 					icon: 'https://static.caimei365.com/app/img/icon/icon_seller_7@2x.png'
-				}
+				},
+                {
+                	name: '机构活跃分析',
+                	path: '/pages/seller/remarks/institutional-activity-analysis',
+                	icon: 'https://static.caimei365.com/app/img/icon/icon_seller_7@2x.png'
+                },
+                {
+                	name: '我的名片',
+                	path: '/pages/seller/remarks/business-card',
+                	icon: 'https://static.caimei365.com/app/img/icon/icon_seller_7@2x.png'
+                }
 			]
 		}
 	},

+ 34 - 3
pages/seller/index/index.vue

@@ -8,6 +8,10 @@
 		<view :style="{ display: show_index == 1 ? 'block' : 'none' }">
 			<seller-category ref="category" v-if="isCategory"></seller-category>
 		</view>
+        <!-- 消息 -->
+        <view :style="{ display: show_index == 3 ? 'block' : 'none' }">
+        	<seller-message ref="message" v-if="isMessage"></seller-message>
+        </view>
 		<!-- 账户中心 -->
 		<view :style="{ display: show_index == 2 ? 'flex' : 'none' }">
 			<seller-user ref="user" v-if="isUserData"></seller-user>
@@ -30,11 +34,14 @@
 import sellerHome from '../components/home.vue'
 import sellerUser from '../components/user.vue'
 import sellerCategory from '../components/category.vue'
+import sellerMessage from '../components/message.vue'
+import { mapMutations, mapState } from 'vuex'
 export default {
 	components: {
 		sellerHome, //采美采购商城 0
 		sellerUser, //账户中心     1
-		sellerCategory //商品分类 2
+		sellerCategory, //商品分类 2
+        sellerMessage, //信息中心 3
 	},
 	data() {
 		return {
@@ -42,6 +49,7 @@ export default {
 			isUserData: false,
 			isCategory: false,
 			isHomeData: false,
+            isMessage: false,
 			isIphoneX: this.$store.state.isIphone,
 			tab_nav_list: [
 				//菜单列表
@@ -57,6 +65,12 @@ export default {
 					icon: 'https://static.caimei365.com/app/img/icon/icon-sort@3x.png',
 					iconAc: 'https://static.caimei365.com/app/img/icon/icon-sort-active@3x.png'
 				},
+                {
+                	id: 3,
+                	name: '消息',
+                	icon: 'https://static.caimei365.com/app/img/icon/icon-user@3x.png',
+                	iconAc: 'https://static.caimei365.com/app/img/icon/icon-user-active@3x.png'
+                },
 				{
 					id: 2,
 					name: '我的',
@@ -83,7 +97,14 @@ export default {
 			}, 100)
 		})
 	},
+    computed: {
+        ...mapState(['userInfo'])
+    },
+    onShow() {
+        this.updateSellerNoticeNum() // 消息通知
+    },
 	methods: {
+        ...mapMutations(['updateSellerNoticeNum']),
 		// 切换组件
 		cut_index(type) {
 			this.show_index = type
@@ -91,14 +112,22 @@ export default {
 				this.isHomeData = true
 				this.isUserData = false
 				this.isCategory = false
+                this.isMessage = false
 			} else if (this.show_index == 1) {
 				this.isHomeData = false
 				this.isUserData = false
 				this.isCategory = true
+                this.isMessage = false
 			} else if (this.show_index == 2) {
 				this.isHomeData = false
 				this.isUserData = true
 				this.isCategory = false
+                this.isMessage = false
+			} else if (this.show_index == 3) {
+				this.isHomeData = false
+				this.isUserData = false
+                this.isCategory = false
+				this.isMessage = true
 			}
 		},
 		onPullDownRefresh() {
@@ -106,7 +135,9 @@ export default {
 				this.$refs.home.getHomeInformation()
 			} else if (this.show_index == 2) {
 				this.$refs.user.initData()
-			}
+			} else if (this.show_index == 3) {
+                this.$refs.message.getMessageList()
+            }
 			uni.stopPullDownRefresh()
 		}
 	},
@@ -117,7 +148,7 @@ export default {
 		}
 		return {
 			title: '生美医美正品采购服务平台',
-			path: 'pages/tabBar/home/index',
+			path: `pages/tabBar/home/index?sellerUserId=${this.userInfo.userIdentity === 1 ? this.userInfo.userId : 0}`,
 			imageUrl: 'https://static.caimei365.com/app/img/bg/min-banner.jpg'
 		}
 	}

+ 97 - 0
pages/seller/notice/components/notice-cell.vue

@@ -0,0 +1,97 @@
+<template name="notice-cell">
+	<!-- 通知消息 -->
+	<view>
+		<!-- 服务通知 -->
+		<template v-if="cellType === 1">
+			<view class="tui-notice-cell clearfix">
+				<view class="tui-cell-top">
+					<view class="cell-title"> {{ cell.messageType | noticeUsersFilters }} </view>
+					<view class="cell-time"> {{ cell.time }} </view>
+				</view>
+                <view class="cell-info" v-if="false">
+                    <view class="club-cell">
+                        机构名称:<text>西安聚美汇医疗美容</text>
+                    </view>
+                    <view class="club-cell">
+                        联系人:<text>西安聚美汇医疗美容</text>
+                    </view>
+                    <view class="club-cell">
+                        手机号:<text>西安聚美汇医疗美容</text>
+                    </view>
+                    <view class="club-cell">
+                        上一任销售:<text></text>
+                    </view>
+                </view>
+                <view class="cell-info" v-else>
+                    昨日【广州市美洋阳医疗美容...】等5家机构客户访问
+                    了采美商城
+                </view>
+				<view class="tui-cell-content"> 
+					{{ noticeUsersText(cell)}}
+				</view> 
+                <view class="tui-cell-button">
+                    <button @click="$emit('trampInfo', cell.id)">立即查看</button>
+                </view>
+			</view>
+		</template>
+	</view>
+</template>
+
+<script>
+import { mapState, mapMutations } from 'vuex'
+import noticeMixins from '../mixins/notice.mixins.js'
+export default {
+	mixins: [noticeMixins],
+	name: 'notice-cell',
+	props: {
+		cellType:{
+			type:Number
+		},
+		cell: {
+			type: Object
+		}
+	},
+	data() {
+		return {
+			
+		}
+	},
+	created() {
+		
+	},
+	methods: {
+		
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.cell-info {
+    padding: 33rpx 0;
+    line-height: 48rpx;
+    color: #666666;
+}
+.club-cell {
+    font-size: 28rpx;
+    color: #333333;
+    font-weight: bold;
+    text {
+        color: #666666;
+        font-weight: 400;
+    }
+}
+.tui-cell-button {
+    padding: 15rpx 0;
+    height: 95rpx;
+    box-sizing: border-box;
+    button {
+        width: 160rpx;
+        height: 64rpx;
+        border: 1rpx solid #999999;
+        line-height: 64rpx;
+        text-align: center;
+        border-radius: 32rpx;
+        float: right;
+    }
+}
+</style>

+ 75 - 0
pages/seller/notice/components/time-axis.vue

@@ -0,0 +1,75 @@
+<template>
+    <view class="time-axis">
+        <view class="time-axis-item" :style="{width: StyleModel.width, fontSize: StyleModel.fontSize, height: StyleModel.height}">
+            <view class="time-axis-title">
+                <slot name="title"></slot>
+            </view>
+            <view class="time-axis-content">
+                <slot name="content"></slot>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+export default {
+    props: {
+        StyleModel: {
+            type: Object,
+            default: () => ({
+                fontSize: '26rpx',
+                color: '#333333',
+                fontWeight: 400,
+                width: '616rpx',
+                height: '244rpx'
+            })
+        }
+    },
+    data() {
+        return {}
+    },
+}
+</script>
+
+<style lang="scss">
+.time-axis {
+    background-color: #fff;
+    .time-axis-item {
+        display: flex;
+        margin: 0 auto;
+        border-left: 1px solid #E1E1E1;
+        align-items: center;
+        position: relative;
+        box-sizing: border-box;
+        padding-left: 30rpx;
+        .time-axis-title {
+            position: absolute;
+            left: 30rpx;
+            top: 0;
+            color: #999999;
+        }
+        &::before {
+            content: '';
+            background-color: #E8E8E8;
+            width: 28rpx;
+            height: 28rpx;
+            border-radius: 50%;
+            position: absolute;
+            top: 0;
+            left: 0;
+            transform: translate(-50%, 0);
+        }
+        &::after {
+            content: '';
+            background-color: #999999;
+            width: 12rpx;
+            height: 12rpx;
+            border-radius: 50%;
+            position: absolute;
+            top: 0;
+            left: 0;
+            transform: translate(-50%, 8rpx);
+        }
+    }
+}
+</style>

+ 71 - 0
pages/seller/notice/components/trajectory.vue

@@ -0,0 +1,71 @@
+<template>
+    <view class="trajectory">
+        <view class="title">
+            访问轨迹
+        </view>
+        <time-axis>
+            <template #title>
+                <text>08-28   18:30</text>
+            </template>
+            <template #content>
+                <view class="time-axis-content">
+                    <image src="../../../../static/temp/icon-new@2x.png" class="axis-product" mode=""></image>
+                                    <view class="axis-product-info">
+                                        <view class="product-title">【商品】</view>
+                                        <view class="product-info">Prostrolane Nature-B 珀洛丽肽焕活
+                    修颜精华液</view>
+                                    </view>
+                </view>
+            </template>
+        </time-axis>
+    </view>
+</template>
+
+<script>
+import TimeAxis from './time-axis.vue'
+export default {
+    props: {},
+    components: {
+        TimeAxis,
+    },
+    data() {
+        return {}
+    },
+}
+</script>
+
+<style lang="scss">
+.trajectory {
+    margin: 24rpx auto;
+    width: 702rpx;
+    background-color: #fff;
+    border-radius: 16rpx;
+    padding: 40rpx 32rpx;
+    box-sizing: border-box;
+    .title {
+        color: #333333;
+        font-size: 28rpx;
+        font-weight: bold;
+        margin-bottom: 30rpx;
+    }
+}
+.axis-product {
+    width: 136rpx;
+    height: 136rpx;
+    object-fit: contain;
+}
+.axis-product-info {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    height: 136rpx;
+    width: 426rpx;
+    color: #333333;
+    font-size: 26rpx;
+    margin-left: 24rpx;
+}
+.time-axis-content {
+    display: flex;
+    align-items: center;
+}
+</style>

+ 91 - 0
pages/seller/notice/components/visits-cell.vue

@@ -0,0 +1,91 @@
+<template>
+    <view class="visits-cell" @click="$emit('handlerVisits', visitsInfo.id)">
+        <view class="visits-club">
+            <image src="/static/icon-user-active@3x.png" mode="" class="visits-author"></image>
+            <view>广州市渼洋阳医疗美容诊所有限公司</view>
+        </view>
+        <view class="visits-content">
+            <view class="container">
+                <view class="visits-name">
+                    李淑霞
+                </view>
+                <view class="visits-phone">
+                    13922400399
+                </view>
+            </view>
+            <view class="container">
+                <view class="visits-name concern">
+                    关注点:
+                </view>
+                <view class="visits-concern">
+                    黄金微针,水光针,微针,小气泡,热玛吉
+                    激光,光子嫩肤
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+export default {
+    props: {
+        visitsInfo: {
+            type: Object,
+            default: () => {}
+        }
+    }
+}
+</script>
+
+<style scoped lang="scss">
+.visits-cell {
+    margin: 0 auto 24rpx auto;
+    width: 702rpx;
+    border-radius: 16rpx;
+    padding: 35rpx 32rpx;
+    background-color: #fff;
+    box-sizing: border-box;
+    .visits-club {
+        height: 70rpx;
+        font-size: 32rpx;
+        font-weight: bold;
+        color:#333333;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        display: flex;
+        align-items: center;
+        border-bottom: 1rpx solid #E1E1E1;
+        padding-bottom: 18rpx;
+        .visits-author {
+            width: 56rpx;
+            height: 56rpx;
+            border-radius: 50%;
+            object-fit: contain;
+            margin-right: 16rpx;
+            background-color: #FFF0E2;
+        }
+    }
+    .visits-content {
+        padding: 40rpx 0 0 0;
+        .container {
+            display: flex;
+            font-size: 28rpx;
+            .visits-name {
+                white-space: nowrap;
+                color: #333333;
+            }
+            .concern {
+                font-weight: bold;
+            }
+            .visits-phone {
+                margin-left: 28rpx;
+                margin-bottom: 24rpx;
+            }
+            .visits-concern {
+                line-height: 48rpx;
+            }
+        }
+    }
+}
+</style>

+ 141 - 0
pages/seller/notice/mixins/notice.mixins.js

@@ -0,0 +1,141 @@
+// 机构通知消息 
+const noticeMixins = {
+    data() {
+
+    },
+    filters: {
+       noticeUsersFilters(value) {
+           // 账户通知状态 1.注册成功通知 2.购买超级会员成功 3.超级会员到期提醒 4.超级会员到期提醒 5.升级资质机构成功 6.升级资质机构失败 7.成为机构运营人员通知
+           const map = {
+               1: '注册成功通知',
+               2: '购买超级会员成功',
+               3: '超级会员到期提醒',
+               4: '系统赠送超级会员',
+               5: '升级资质机构成功',
+               6: '升级资质机构失败',
+               7: '成为机构运营人员通知'
+           }
+           return map[value]
+       },
+    },
+    methods: {
+        getUserAuthClubMessageList() {
+            this.UserService.getUserAuthClubMessageList(this.listQuery)
+                .then(response => {
+                    let data = response.data
+                    this.hasNextPage = response.data.hasNextPage
+                    if (data.list && data.list.length > 0) {
+                        this.isEmpty = false
+                        this.list = [...data.list]
+                        this.pullFlag = false
+                        setTimeout(() => {
+                            this.pullFlag = true
+                        }, 500)
+                        if (this.hasNextPage) {
+                            this.pullUpOn = false
+                            this.nomoreText = '上拉显示更多'
+                        } else {
+                            if (this.list.length < 5) {
+                                this.pullUpOn = true
+                                this.loadding = false
+                            } else {
+                                this.pullUpOn = false
+                                this.loadding = false
+                                this.nomoreText = '到底了~'
+                            }
+                        }
+                    } else {
+                        this.isEmpty = true
+                    }
+                    this.skeletonShow = false
+                })
+                .catch(error => {
+                    this.$util.msg(error.msg, 2000)
+                })
+        },
+        getReachBottomData() {
+            //上拉加载
+            this.listQuery.pageNum += 1
+            this.UserService.getUserAuthClubMessageList(this.listQuery)
+                .then(response => {
+                    let data = response.data
+                    if (data.list && data.list.length > 0) {
+                        this.hasNextPage = data.hasNextPage
+                        this.list = this.list.concat(data.list)
+                        this.pullFlag = false // 防上拉暴滑
+                        setTimeout(() => {
+                            this.pullFlag = true
+                        }, 500)
+                        if (this.hasNextPage) {
+                            this.pullUpOn = false
+                            this.nomoreText = '上拉显示更多'
+                        } else {
+                            this.pullUpOn = false
+                            this.loadding = false
+                            this.nomoreText = '到底了~'
+                        }
+                    }
+                })
+                .catch(error => {
+                    this.$util.msg(error.msg, 2000)
+                })
+        },
+        deleteBtn(id,index) {
+            // 删除通知消息
+            this.UserService.authDeleteMessage({ id: id })
+                .then(response => {
+                    let _this = this
+                    uni.vibrateShort({
+                        success: function() {
+                            _this.listQuery.pageNum = 1
+                            _this.getUserAuthClubMessageList()
+                            // _this.list.splice(index, 1) 
+                        }
+                    })
+                })
+                .catch(error => {
+                    console.log('error=>', error.msg)
+                })
+        },
+        noticeOrderText(cell) { // 交易物流通知文案
+            const map = {
+                1: '您已成功下单!',
+                2: '您的订单已支付完成,将立即安排发货!',
+                3: `您的订单已${cell.refundType === 1 ? '部分退' : '全部退'}款/货成功!退款金额¥${cell.content},到账时间可能存在延迟,具体以支付方通知为准。`,
+                4: `${cell.content}`,
+                5: '您的订单已发货,请您留意物流变化!',
+                6: '您的订单因超时已被系统自动确认收货!'
+            }
+            return map[cell.orderMessageType]
+        },
+        noticeUsersText(cell) { // 账户通知文案
+            const map = {
+                1: '欢迎成为采美机构用户,祝您开启愉快的采购之旅。',
+                2: `您已成功购买${cell.content}采美平台超级会员服务,在服务期内每月可领多张大额优惠券,还有更多超级会员专属权益等您体验,快去看看吧 >>>`,
+                3: `您的超级会员服务将于${cell.content}到期,到期后将无法享受专属会员权益,赶快去续费吧 >>>`,
+                4: `您已获得采美平台赠送的${cell.content}超级会员,在服务期内每月可领多张大额优惠券,还有更多超级会员专属权益等您体验,快去看看吧 >>>`,
+                5: '恭喜您成功升级为资质机构用户!现在可以查看更多商品的信息啦,采美平台也将为您提供更多专业服务。',
+                6: '您的账号升级资质机构失败!赶快去修改资料重新提交吧 >>>',
+                7: `恭喜您(微信昵称:${cell.content})成功成为机构运营人员,祝您开启愉快的采购之旅。`
+            }
+            return map[cell.accountType]
+        },
+        // noticeCouponText(cell) { // 优惠促销通知文案
+        //     const copunMap = {
+        //         0: `采美平台送您${cell.couponFee}元优惠券,众多大牌正品等着您,赶快去领取下单吧 >>>`,
+        //         1: `采美平台${cell.content}类商品大优惠,特送您${cell.couponFee}元优惠券,赶快去领取下单吧 >>>`,
+        //         2: `为了答谢您对采美平台的支持,采美送您${cell.couponFee}元优惠券,赶快去领取下单吧 >>>`,
+        //         3: `【${cell.content}】赠送您${cell.couponFee}元的店铺专属优惠券,众多火爆商品等您来!赶快去领取下单吧 >>>`,
+        //         4: `恭喜成功注册采美平台,现赠送您${cell.couponFee}元新用户优惠券,赶快去领取下单吧 >>>`,
+        //     }
+        //     const map = {
+        //         1: copunMap[cell.couponType],
+        //         2: `您有${cell.couponFee}元优惠券将于${cell.content}过期,赶快去查看使用吧 >>>`,
+        //         3: `您有${cell.couponFee}元优惠券尚未领取,优惠券将于${cell.content}后下架,赶快去领取下单吧 >>>`,
+        //     }
+        //     return map[cell.couponMessageType]
+        // }
+    }
+}
+
+export default noticeMixins

+ 47 - 0
pages/seller/notice/service/Institutional_visits.vue

@@ -0,0 +1,47 @@
+<template>
+    <view class="visitor">
+        <view class="visits-time">
+            2023-08-28
+        </view>
+        <template>
+            <view>
+                <visits-cell @handlerVisits="handlerVisits" :visits-info="visitsInfo"/>
+            </view>
+        </template>
+    </view>
+</template>
+
+<script>
+import VisitsCell from '../components/visits-cell.vue'
+export default {
+    components: {
+        VisitsCell
+    },
+    data() {
+        return {
+            visitsInfo: {
+                id: 1
+            }
+        }
+    },
+    methods: {
+        handlerVisits($event) {
+            this.$api.navigateTo('/pages/seller/notice/service/visits_details?id=' + $event)
+        }
+    }
+}
+</script>
+
+<style lang="scss">
+page {
+	background-color: #f7f7f7;
+}
+.visitor {
+    .visits-time {
+        font-size: 32rpx;
+        font-weight: bold;
+        color: #333333;
+        padding: 40rpx 0 24rpx 16rpx;
+    }
+}
+</style>

+ 165 - 0
pages/seller/notice/service/service.vue

@@ -0,0 +1,165 @@
+<template>
+    <view class="service">
+        <tui-skeleton
+        	v-if="skeletonShow"
+        	backgroundColor="#fafafa"
+        	borderRadius="10rpx"
+        	:isLoading="true"
+        	:loadingType="5"
+        ></tui-skeleton>
+        <view class="container">
+            <view v-for="(cell, index) in messageList" class="info-card" :key="index">
+                <view class="tui-notice clearfix">
+                	<tui-swipe-action :operateWidth="80" :backgroundColor="'#F7F7F7'">
+                		<template v-slot:content>
+                			<notice-cell :cellType="1" :cell="cell" @trampInfo="trampInfo"></notice-cell>
+                		</template>
+                		<template v-slot:button>
+                			<view class="tui-custom-btn_box">
+                				<view class="tui-custom-btn" @click.stop="deleteBtn(cell.id,index)">
+                					<text class="iconfont icon-shanchu3"></text>
+                				</view>
+                			</view>
+                		</template>
+                	</tui-swipe-action>
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+import { mapState, mapMutations } from 'vuex'
+import noticeCell from '../components/notice-cell.vue'
+export default {
+    components: {
+        noticeCell
+    },
+    data() {
+        return {
+            skeletonShow: false, // 刷新
+            messageList: [
+                {
+                    id: 1,
+                    messageType: 1,
+                    time: '2023年8月29日',
+                    accountType: 1,
+                    content: '大黄蜂'
+                }
+            ], // 信息列表
+        }
+    },
+    methods: {
+        // 请求信息列表
+        async getMessageList(){
+            console.log(1111)
+        },
+        // 删除
+        deleteBtn() {},
+        // 详情
+        trampInfo($event) {
+            this.$api.navigateTo('/pages/seller/notice/service/Institutional_visits?id=' + $event)
+        }
+    },
+    onPullDownRefresh() {
+        console.log('刷新')
+        uni.stopPullDownRefresh()
+    },
+    onReachBottom() {
+        console.log('到底了')
+    }
+}
+</script>
+
+<style scopde lang="scss">
+.container {
+    padding: 24rpx;
+    box-sizing: border-box;
+}
+.info-card {
+    margin-bottom: 24rpx;
+    box-sizing: border-box;
+}
+page {
+	background-color: #f7f7f7;
+}
+.container-main {
+	width: 100%;
+	box-sizing: border-box;
+	padding: 24rpx 0;
+	.empty-container-image {
+		width: 260rpx;
+		height: 260rpx;
+		margin-top: -300rpx;
+	}
+}
+.tui-swipeout-content{
+	white-space:normal !important;
+}
+.tui-notice{
+	margin-bottom: 24rpx;
+}
+.tui-notice-cell {
+	width: 702rpx;
+	height: auto;
+	background-color: #ffffff;
+	border-radius: 16rpx;
+	box-sizing: border-box;
+	padding:0 24rpx;
+	margin: 0 auto;
+	.tui-cell-top{
+		width: 100%;
+		height: 105rpx;
+		line-height: 105rpx;
+        border-bottom: 1px solid #ccc;
+		.cell-title{
+			font-size: 32rpx;
+			color: #333333;
+			float: left;
+			font-weight: bold;
+		}
+		.cell-time{
+			font-size: 24rpx;
+			color: #999999;
+			float: right;
+		}
+	}
+	.tui-cell-content{
+		width: 100%;
+		height: auto;
+		box-sizing: border-box;
+		border-radius: 8rpx;
+		line-height: 44rpx;
+		padding: 24rpx;
+		background-color: #F7F7F7;
+		font-size: 28rpx;
+		color: #333333;
+		text-align: justify;
+	}
+}
+.tui-custom-btn_box {
+	width: 80px;
+	height: 100%;
+	padding: 0 20rpx;
+	box-sizing: border-box;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	background-color: #f7f7f7;
+}
+
+.tui-custom-btn {
+	width: 56rpx;
+	height: 56rpx;
+	border-radius: 50%;
+	background-color: #f94b4b;
+	color: #ffffff;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	flex-shrink: 0;
+	.icon-shanchu3 {
+		font-size: 32rpx;
+	}
+}
+</style>

+ 55 - 0
pages/seller/notice/service/visits_details.vue

@@ -0,0 +1,55 @@
+<template>
+    <view class="details">
+        <view class="visits-time">
+            2023-08-28
+        </view>
+        <template>
+            <view class="details-title">
+                <visits-cell @handlerVisits="handlerVisits" :visits-info="visitsInfo"/>
+            </view>
+        </template>
+        <view class="trajectory">
+            <Trajectory />
+        </view>
+    </view>
+</template>
+
+<script>
+import VisitsCell from '../components/visits-cell.vue'
+import Trajectory from '../components/trajectory.vue'
+export default {
+    components: {
+        VisitsCell,
+        Trajectory
+    },
+    data() {
+        return {
+            visitsInfo: {
+                id: 1
+            }
+        }
+    },
+    methods: {
+        handlerVisits($event) {
+            this.$api.navigateTo('/pages/seller/notice/service/visits_details?id=' + $event)
+        }
+    }
+}
+</script>
+
+<style lang="scss">
+page {
+    background-color: #f7f7f7;
+}
+.details {
+    .visits-time {
+        font-size: 32rpx;
+        font-weight: bold;
+        color: #333333;
+        padding: 40rpx 0 24rpx 16rpx;
+    }
+    .details-title {
+        margin-bottom: 24rpx;
+    }
+}
+</style>

+ 108 - 0
pages/seller/remarks/business-card.vue

@@ -0,0 +1,108 @@
+<template>
+    <view class="business-card">
+        <view class="select-item" @click.native="showActionSheet = true">
+            <view class="select-title">
+                头像
+            </view>
+            <view class="select-content">
+                <image class="aov" src="../../../static/icon-user@3x.png" mode=""></image>
+                <text class="cell-more iconfont icon-xiayibu"></text>
+            </view>
+        </view>
+        <view class="select-item" @click.native="$api.navigateTo('/pages/seller/remarks/mine-qrcode')">
+            <view class="select-title">
+                二维码
+            </view>
+            <view class="select-content">
+                <image class="aov" src="../../../static/icon-user@3x.png" mode=""></image>
+                <text class="cell-more iconfont icon-xiayibu"></text>
+            </view>
+        </view>
+        <tui-actionsheet  
+         :show="showActionSheet" 
+         :item-list="itemList" 
+         @click="itemClick" 
+         :isCancel="fasle"
+         @cancel="closeActionSheet">
+        </tui-actionsheet>
+    </view>
+</template>
+
+<script>
+import { uploadFileImage } from '@/services/public.js'
+export default {
+    data() {
+        return {
+            userInfo: {
+                photo: ''
+            },
+            showActionSheet: false,
+            itemList: [{
+               text: '手机相册',
+            },
+            {
+               text: '取消',
+            }],
+        }
+    },
+    methods: {
+        itemClick(e) {
+            if (e.index === 1) {
+                return (this.showActionSheet = false)
+            } else {
+                uploadFileImage().then(res => {
+                    this.userInfo.photo = JSON.parse(res.data).data
+                    this.showActionSheet = false
+                })
+            }
+        },
+        closeActionSheet() {
+            this.showActionSheet = false
+        },
+    }
+}
+</script>
+
+<style lang="scss">
+@import '@/uni.scss';
+.business-card {
+    padding: 0 32rpx;
+    box-sizing: border-box;
+    .select-item {
+        display: flex;
+        justify-content: space-between;
+        height: 100rpx;
+        border-bottom: 1rpx solid #E1E1E1;
+        margin-top: 30rpx;
+        position: relative;
+        .select-title {
+            color: #666666;
+            font-size: 28rpx;
+        }
+        .select-content {
+            display: flex;
+            align-items: center;
+            .aov {
+                width: 90rpx;
+                height: 90rpx;
+                border-radius: 50%;
+                object-fit: contain;
+            }
+        }
+    }
+}
+.cell-more {
+    width: 20rpx;
+    height: 100rpx;
+    line-height: 100rpx;
+    text-align: right;
+    right: 0;
+    top: 0;
+    font-size: $font-size-28;
+    color: #666666;
+    .txt {
+        color: #fb4343;
+        padding-right: 10rpx;
+    }
+}
+</style>

+ 83 - 0
pages/seller/remarks/components/activity-analysis.vue

@@ -0,0 +1,83 @@
+<template>
+    <view class="activity-analysis">
+        <image src="../../../../static/icon-user-active@3x.png" class="analysis-img" mode=""></image>
+        <view class="analysis-content">
+            <view class="analysis-club">
+                韩国恩盛仪器美容院
+            </view>
+            <view class="analysis-tab">
+                <view class="tab-item">
+                    忠诚用户
+                </view>
+                <view class="tab-item">
+                    忠诚用户
+                </view>
+            </view>
+            <view class="analysis-info">
+                <view>
+                    张顺星
+                </view>
+                <view>
+                    15889586666
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+export default {
+    props: {},
+    data() {
+        return {}
+    },
+}
+</script>
+
+<style lang="scss">
+.activity-analysis {
+    padding: 30rpx 0;
+    display: flex;
+    border-bottom: 1px solid #E5E5E5;
+    .analysis-img {
+        width: 140rpx;
+        height: 140rpx;
+        background: #FFF2E6;
+        border-radius: 16rpx 16rpx 16rpx 16rpx;
+        opacity: 1;
+    }
+    .analysis-content {
+        margin-left: 16rpx;
+        .analysis-club {
+            color: #333333;
+            font-size: 30rpx;
+            margin-bottom: 16rpx;
+        }
+        .analysis-tab {
+            display: flex;
+            margin-bottom: 16rpx;
+            .tab-item {
+                margin-right: 16rpx;
+                width: 136rpx;
+                height: 40rpx;
+                background: #FAEDE5;
+                border-radius: 8rpx 8rpx 8rpx 8rpx;
+                opacity: 1;
+                text-align: center;
+                line-height: 40rpx;
+                font-size: 22rpx;
+                color: #FF5B00;
+            }
+        }
+        .analysis-info {
+            display: flex;
+            align-items: center;
+            font-size: 26rpx;
+            color: #333333;
+            view:nth-child(2) {
+                margin-left: 32rpx;
+            }
+        }
+    }
+}
+</style>

+ 71 - 0
pages/seller/remarks/components/analysis-card-item.vue

@@ -0,0 +1,71 @@
+<template>
+    <view class="analysis-card-item">
+        <view class="analysis-card-title">
+            <slot name="title"></slot>
+        </view>
+        <view class="analysis-card-title" v-if="isSubtitle">
+            <slot name="subtitle"></slot>
+        </view>
+        <view class="analysis-card-num">
+            <count-up 
+                :num="num"
+                :width="24"
+                :height="56"
+                :fontSize="40"
+                color="#333333"/>
+            <text v-if="isPercentage">%</text>
+        </view>
+    </view>
+</template>
+
+<script>
+import countUp from './countUp.vue'
+export default {
+    components: {
+        countUp
+    },
+    props: {
+        isPercentage: {
+            type: Boolean,
+            default: false
+        },
+        isSubtitle: {
+            type: Boolean,
+            default: false
+        },
+        num: {
+            type: Number,
+            default: 60
+        }
+    },
+}
+</script>
+
+<style lang="scss">
+.analysis-card-item {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    height: 210rpx;
+    align-items: center;
+    box-sizing: border-box;
+    .analysis-card-num {
+        color: #333333;
+        font-weight: bold;
+        font-size: 40rpx;
+        display: flex;
+        align-items: center;
+    }
+}
+.analysis-card-title {
+    margin-bottom: 16rpx;
+}
+.analysis-card-title:nth-child(1) {
+    font-size: 28rpx;
+    color: #333333;
+}
+.analysis-card-title:nth-child(2) {
+    font-size: 24rpx;
+    color: #999999;
+}
+</style>

+ 81 - 0
pages/seller/remarks/components/analysis-card.vue

@@ -0,0 +1,81 @@
+<template>
+    <view class="analysis-card">
+        <analysis-card-item :isSubtitle="true">
+            <template #title>
+                <view>活跃机构</view>
+            </template>
+            <template #subtitle>
+                <view>(6个月内有登录商城等行为)</view>
+            </template>
+        </analysis-card-item>
+        <analysis-card-item :isSubtitle="true">
+            <template #title>
+                <view>不活跃机构</view>
+            </template>
+            <template #subtitle>
+                <view>(6个月内未登录商城等行为)</view>
+            </template>
+        </analysis-card-item>
+        <analysis-card-item :isPercentage="true">
+            <template #title>
+                <view>活跃机构占比</view>
+            </template>
+        </analysis-card-item>
+        <analysis-card-item :isPercentage="true">
+            <template #title>
+                <view>不活跃机构占比</view>
+            </template>
+        </analysis-card-item>
+    </view>
+</template>
+
+<script>
+import analysisCardItem from './analysis-card-item.vue'
+export default {
+    components: {
+        analysisCardItem
+    },
+    props: {
+        analysisInfo: {
+            type: Object,
+            default: () => ({})
+        }
+    },
+    data() {
+        return {}
+    },
+}
+</script>
+
+<style lang="scss">
+.analysis-card {
+    width: 702rpx;
+    display: grid;
+    position: relative;
+    grid-template-columns: repeat(2, 1fr);
+    grid-template-rows: repeat(2, 1fr);
+    background-color: #fff;
+    border-radius: 16rpx;
+    margin: 0 auto;
+    &::before {
+        width: 1px;
+        height: 200rpx;
+        content: '';
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        background-color: #E5E5E5;
+        transform: translate(-50%, -50%);
+    }
+    &::after {
+        width: 660rpx;
+        height: 1px;
+        content: '';
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        background-color: #E5E5E5;
+        transform: translate(-50%, -50%);
+    }
+}
+</style>

+ 137 - 0
pages/seller/remarks/components/countUp.vue

@@ -0,0 +1,137 @@
+<template>
+    <view class="number-box">
+        <block v-for="(myIndex, index) in indexArr" :key="index">
+            <swiper
+                class="swiper"
+                vertical="true"
+                :current="myIndex"
+                circular="true"
+                v-bind:style="{
+                    color: color,
+                    width: myIndex == 10 ? '7px' : width + 'rpx',
+                    height: height + 'rpx',
+                    fontSize: fontSize + 'rpx',
+                    fontWeight
+                }"
+            >
+                <swiper-item><view class="swiper-item">0</view></swiper-item>
+                <swiper-item><view class="swiper-item">1</view></swiper-item>
+                <swiper-item><view class="swiper-item">2</view></swiper-item>
+                <swiper-item><view class="swiper-item">3</view></swiper-item>
+                <swiper-item><view class="swiper-item">4</view></swiper-item>
+                <swiper-item><view class="swiper-item">5</view></swiper-item>
+                <swiper-item><view class="swiper-item">6</view></swiper-item>
+                <swiper-item><view class="swiper-item">7</view></swiper-item>
+                <swiper-item><view class="swiper-item">8</view></swiper-item>
+                <swiper-item><view class="swiper-item">9</view></swiper-item>
+                <swiper-item><view class="swiper-item">.</view></swiper-item>
+            </swiper>
+        </block>
+    </view>
+</template>
+
+<script>
+export default {
+    props: {
+        num: [String, Number],
+        color: {
+            type: String,
+            default: '#000000'
+        },
+        width: {
+            type: String,
+            default: '15'
+        },
+        height: {
+            type: String,
+            default: '15'
+        },
+        fontSize: {
+            type: String,
+            default: '15'
+        },
+        fontWeight: {
+            type: String,
+            default: 'bold'
+        }
+    },
+    data() {
+        return {
+            indexArr: []
+        }
+    },
+    created() {
+        let { num } = this
+        console.log('初始数据', num)
+        let arr = new Array(num.toString().length)
+        arr.fill(0)
+        this.indexArr = arr
+    },
+    watch: {
+        num: function(val, oldVal) {
+            // 处理新老数据长度不一样的情况
+            let arr = Array.prototype.slice.apply(this.indexArr)
+            let newLen = val.toString().length
+            let oldLen = oldVal.toString().length
+            if (newLen > oldLen) {
+                for (let i = 0; i < newLen - oldLen; i++) {
+                    arr.push(0)
+                }
+                this.indexArr = arr
+            }
+            if (newLen < oldLen) {
+                for (let i = 0; i < oldLen - newLen; i++) {
+                    arr.pop()
+                }
+                this.indexArr = arr
+            }
+            this.numChange(val)
+        }
+    },
+    mounted() {
+        //定时器作用:app显示数字滚动
+        this._time = setTimeout(() => {
+            this.numChange(this.num)
+            clearTimeout(this.time)
+        }, 50)
+    },
+    methods: {
+        /**
+         * 数字改变
+         * @value 数字
+         */
+        numChange(num) {
+            let { indexArr } = this
+            let copyIndexArr = Array.prototype.slice.apply(indexArr)
+            let _num = num.toString()
+            for (let i = 0; i < _num.length; i++) {
+                if (_num[i] === '.') {
+                    copyIndexArr[i] = 10
+                } else {
+                    copyIndexArr[i] = Number(_num[i])
+                }
+            }
+            this.indexArr = copyIndexArr
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.number-box {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: center;
+}
+.swiper {
+    position: relative;
+}
+.swiper:after {
+    content: '';
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+}
+</style>

+ 118 - 0
pages/seller/remarks/components/mine-card.vue

@@ -0,0 +1,118 @@
+<template>
+    <view class="card" :style="{backgroundImage: `url(${imgUrl})`, backgroundSize: '100% 100%'}">
+        <view class="logo">
+            <image src="https://static.caimei365.com/app/img/icon/logo-fanbai.png" mode="" class="titleImgUrl"></image>
+        </view>
+        <view class="card-contain">
+            <view style="display: flex;">
+                <view class="card-head">
+                    <image src="https://static.caimei365.com/app/img/icon/default-head.png" mode="" class="head"></image>
+                </view>
+                <view class="card-info">
+                    <view class="card-info-head">
+                        <view class="card-name">
+                            未知
+                        </view>
+                        <view class="card-info-tab">
+                            客户经理
+                        </view>
+                    </view>
+                    <view class="card-info-iphone">
+                        158-8958-6633
+                    </view>
+                </view>
+            </view>
+            <view class="card-qrcode">
+                <view class="qrcode-message">
+                    <image :show-menu-by-longpress="true" src="" class="qrcode" mode=""></image>
+                </view>
+                <view class="tips">
+                    长按或扫二维码
+                    联系我
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+export default {
+    data() {
+        return {
+            imgUrl: 'https://static.caimei365.com/app/img/icon/bg-card.png',
+        }
+    },
+    mounted() {},
+    methods: {},
+}
+</script>
+
+<style lang="scss">
+.card {
+    width: 702rpx;
+    height: 340rpx;
+    background: #FF5B00;
+    border-radius: 16rpx;
+    opacity: 1;
+    margin: 0 auto;
+    box-sizing: border-box;
+    padding: 16rpx 32rpx;
+    .titleImgUrl {
+        width: 241rpx;
+        height: 80rpx;
+    }
+    .card-contain {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        .head {
+            width: 128rpx;
+            height: 128rpx;
+            border-radius: 50%;
+            object-fit: contain;
+        }
+        .card-info {
+            height: 128rpx;
+            margin-left: 30rpx;
+        }
+        .card-info-head {
+            display: flex;
+            align-items: center;
+            margin-bottom: 13rpx;
+            .card-name {
+                color: #FFFFFF;
+                font-size: 40rpx;
+                font-weight: bold;
+            }
+            .card-info-tab {
+                width: 88rpx;
+                height: 31rpx;
+                background-color: #FFBB00;
+                color: #fff;
+                font-size: 22rpx;
+                padding: 0 8rpx;
+                margin-left: 10rpx;
+            }
+        }
+        .card-info-iphone {
+            color: #FFFFFF;
+            font-size: 28rpx;
+        }
+        .card-qrcode {
+            .qrcode {
+                width: 126rpx;
+                height: 126rpx;
+                object-fit: contain;
+                margin-bottom: 6rpx;
+            }
+            .tips {
+                font-size: 18rpx;
+                color: #fff;
+                text-align: center;
+                width: 126rpx;
+                line-height: 24rpx;
+            }
+        }
+    }
+}
+</style>

+ 141 - 0
pages/seller/remarks/institutional-activity-analysis.vue

@@ -0,0 +1,141 @@
+<template>
+    <view class="container club clearfix">
+        <view
+            class="club-search clearfix"
+            :style="{ paddingTop: StatusBar + 'px', backgroundImage: `url(${imgUrl})`, backgroundSize: '100% 100%' }"
+        >
+    		      <view class="search-top" :style="{ height: CustomBar - StatusBar + 'px' }">
+                <view
+                    class="search-icon"
+                    :style="{
+                        width: CustomBar - StatusBar + 'px',
+                   		   height: CustomBar - StatusBar + 'px',
+                        lineHeight: CustomBar - StatusBar + 'px;'
+                    }"
+                >
+                    <text @click="handleNavigateBack" class="iconfont icon-fanhui"></text>
+                </view>
+                <view class="title">机构活跃分析</view>
+            </view>
+            <analysis-card />
+        </view>
+        <view class="analysis-list">
+            <view class="analysis-tabs">
+                <view
+                    class="analysis-tab"
+                    :class="currentTab === index && 'active'"
+                    v-for="(item, index) in tabs"
+                    :key="index"
+                    @click="handleChangeActive(index)"
+                >
+                    {{ item.name }}
+                </view>
+            </view>
+            <view class="list">
+                <activity-analysis />
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+import analysisCard from './components/analysis-card.vue'
+import activityAnalysis from './components/activity-analysis.vue'
+export default {
+    components: {
+        analysisCard,
+        activityAnalysis
+    },
+    data() {
+        return {
+            isIphoneX: this.$store.state.isIphoneX,
+            CustomBar: this.CustomBar,
+            StatusBar: this.StatusBar,
+            capsule: this.capsule,
+            imgUrl: 'https://static.caimei365.com/app/img/icon/analysis-bg.png',
+            currentTab: 0,
+            tabs: [
+                {
+                    name: '活跃机构'
+                },
+                {
+                    name: '不活跃机构'
+                }
+            ]
+        }
+    },
+    mounted() {},
+    methods: {
+        handleChangeActive(e) {
+            this.currentTab = e
+        },
+        handleNavigateBack() {
+            this.$api.navigateBack(1)
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.container {
+    background: #ffffff;
+    position: relative;
+}
+.club-search {
+    height: 700rpx;
+    width: 100%;
+    background: #ffffff;
+    display: flex;
+    flex-direction: column;
+    position: sticky;
+    top: 0;
+    left: 0;
+    z-index: 99;
+    box-sizing: border-box;
+    .search-top {
+        display: flex;
+        align-items: center;
+        box-sizing: border-box;
+        position: relative;
+        margin-bottom: 80rpx;
+        .title {
+            position: absolute;
+            left: 50%;
+            top: 50%;
+            transform: translate(-50%, -50%);
+        }
+        .search-icon {
+            text-align: center;
+            float: left;
+            .icon-fanhui {
+                font-size: 44rpx;
+                color: #333333;
+            }
+            .icon-shouye {
+                font-size: 44rpx;
+                color: #333333;
+            }
+        }
+    }
+}
+.analysis-list {
+    padding: 38rpx 24rpx;
+    box-sizing: border-box;
+    .analysis-tabs {
+        color: #666666;
+        display: flex;
+        align-items: center;
+        margin-bottom: 12rpx;
+        .analysis-tab {
+            font-size: 32rpx;
+            height: 54rpx;
+            margin-right: 80rpx;
+            &.active {
+                color: #ff5b00;
+                border-bottom: 2px solid #ff5b00;
+                font-weight: bold;
+            }
+        }
+    }
+}
+</style>

+ 34 - 0
pages/seller/remarks/mine-card.vue

@@ -0,0 +1,34 @@
+<template>
+    <view class="mine-card">
+        <mine-card></mine-card>
+        <view class="tips">
+            商城名片(方便买家在商城联系您)
+        </view>
+    </view>
+</template>
+
+<script>
+import MineCard from './components/mine-card.vue'
+export default {
+    components: {
+        MineCard,
+    },
+    data() {
+        return {}
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.mine-card {
+    width: 100vw;
+    height: 100vh;
+    padding: 48rpx 24rpx;
+    box-sizing: border-box;
+    .tips {
+        color: #999999;
+        font-size: 24rpx;
+        margin-top: 24rpx;
+    }
+}
+</style>

+ 86 - 0
pages/seller/remarks/mine-qrcode.vue

@@ -0,0 +1,86 @@
+<template>
+    <view class="mine-qrcode">
+        <view class="handlerUpload">
+            <image src="" mode="" v-if="userInfo.qrcode"></image>
+            <text v-else>
+                请点击上传二维码
+            </text>
+        </view>
+        <button class="upload">上传二维码</button>
+        <button class="save-qrcode" :class="active && 'active'" @click="handlerSave">保存</button>
+    </view>
+</template>
+
+<script>
+export default {
+    data() {
+        return {
+            active: true,
+            userInfo: {
+                qrcode: ''
+            }
+        }
+    },
+    watch: {
+        'userInfo.qrcode': {
+            handler(val) {
+                if (val) {
+                    this.active = true
+                }
+            },
+            immediate: true,
+            deep: true
+        }
+    },
+    methods: {
+        handlerSave() {
+            if (this.active) {
+                this.$api.navigateTo('/pages/seller/remarks/mine-card')
+            }
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.mine-qrcode {
+    width: 100vw;
+    height: 100vh;
+    .handlerUpload {
+        width: 420rpx;
+        height: 420rpx;
+        border: 1px dotted #B2B2B2;
+        margin: 120rpx auto 0 auto;
+        text-align: center;
+        line-height: 420rpx;
+        color: #B2B2B2;
+        font-size: 24rpx;
+        border-radius: 16rpx;
+    }
+    .upload {
+        margin: 101rpx auto 0 auto;
+        width: 600rpx;
+        height: 90rpx;
+        border-radius: 45rpx;
+        opacity: 1;
+        border: 1rpx solid #FF5B00;
+        color: #FF5B00;
+        line-height: 90rpx;
+        text-align: center;
+    }
+    .save-qrcode {
+        margin: 24rpx auto 0 auto;
+        width: 600rpx;
+        height: 90rpx;
+        border-radius: 45rpx;
+        opacity: 1;
+        color: #FFFFFF;
+        line-height: 90rpx;
+        text-align: center;
+        background-color: #E1E1E1;
+    }
+    .active {
+        background: linear-gradient(90deg, #FF9300 0%, #FF5B00 100%);
+    }
+}
+</style>

+ 11 - 3
pages/tabBar/home/index.vue

@@ -49,6 +49,7 @@
 			:beanNumber="beanNumber"
 			@cancel="handleBeanlClick"
 		></activityBean>
+        <cm-seller-modal :sellerUserId="sellerUserId"></cm-seller-modal>
 	</view>
 </template>
 
@@ -67,6 +68,7 @@ import supplierList from '@/components/cm-module/homeIndex/supplierList.vue'
 import activityAlert from '@/components/cm-module/activity/activity.vue'
 import activityBean from '@/components/cm-module/activity/activityBean.vue'
 import quickOpera from '@/components/cm-module/homeIndex/quickOperation.vue'
+import cmSellerModal from '@/components/cm-share-popup/cm-seller-modal.vue'
 import homeMiXins from './index.js'
 export default {
 	mixins: [ homeMiXins ], 
@@ -83,7 +85,8 @@ export default {
 		supplierList,
 		activityAlert,
 		activityBean,
-        quickOpera
+        quickOpera,
+        cmSellerModal
 	},
 	data() {
 		return {
@@ -123,10 +126,15 @@ export default {
 			beanNumber: 50,
 			couponEntry: 2,
 			autoplay: true,
-            isScroll: false
+            isScroll: false,
+            sellerUserId: 0, // 协销id
 		}
 	},
-	onLoad() {},
+	onLoad(options) {
+        if (options.sellerUserId) {
+            this.sellerUserId = options.sellerUserId
+        }
+    },
     computed: {
         ...mapState(['hasLogin', 'userInfo'])
     },

+ 15 - 1
services/sellse.service.js

@@ -379,5 +379,19 @@ export default class SellerService {
 	           
 	    })
     }
-	
+	/**
+     * 协销分享海报
+     */
+    wxUnlimited (data = {}) {
+	    return this.AjaxService.post({ 
+	        url:'/user/wxacode', 
+	        data, 
+	        isLoading: true ,
+	           
+	    })
+    }
+    /**
+     * 机构活跃分析
+     */
+    
 }

+ 28 - 0
store/index.js

@@ -108,6 +108,34 @@ const store = new Vuex.Store({
                     })
                 })
         },
+        async updateSellerNoticeNum(state) { // 更新通知消息数量
+            const userInfo = await caimeiApi.getStorage()
+            const commonId = userInfo.clubId ? userInfo.clubId : 0
+            getUserService.getAuthClubCount({ commonId: commonId })
+                .then(response => {
+                    state.noticeNum = response.data.count
+                    if (state.noticeNum >= 100) {
+                        uni.setTabBarBadge({
+                            index: 2,
+                            text: '99+'
+                        })
+                    } else if (state.noticeNum > 0) {
+                        uni.setTabBarBadge({
+                            index: 2,
+                            text: String(state.noticeNum)
+                        })
+                    } else {
+                        uni.removeTabBarBadge({
+                            index: 2,
+                        })
+                    }
+                })
+                .catch(error => {
+                    uni.removeTabBarBadge({
+                        index: 2,
+                    })
+                })
+        },
         async updateRossShow(state){
             const USER_EVEN = await caimeiApi.getStorage()
             if(USER_EVEN.userIdentity === 1) { return }