WebApp【公共组件库】@前端(For Git Submodule)
Tevin
2022-08-26 4b774f04653a89513bc8f847920529c08507f564
Merge branch 'master' of ssh://dev.zhiheiot.com:29418/mob-components

# Conflicts:
# common/Tools.js
8 files added
2 files modified
61595 ■■■■■ changed files
common/Tools.js 21 ●●●●● patch | view | raw | blame | history
layout/loading/CLoading.vue 5 ●●●● patch | view | raw | blame | history
layout/numerical/CNumerical.vue 74 ●●●●● patch | view | raw | blame | history
layout/numerical/cNumerical.scss 26 ●●●●● patch | view | raw | blame | history
layout/numerical/index.js 10 ●●●●● patch | view | raw | blame | history
plugins/echarts/CECharts.weapp.vue 208 ●●●●● patch | view | raw | blame | history
plugins/echarts/cECharts.scss 14 ●●●●● patch | view | raw | blame | history
plugins/echarts/echarts.js 61116 ●●●●● patch | view | raw | blame | history
plugins/echarts/index.js 10 ●●●●● patch | view | raw | blame | history
plugins/echarts/wxCanvas.js 111 ●●●●● patch | view | raw | blame | history
common/Tools.js
@@ -517,11 +517,28 @@
    }
    /**
     * 转换周数到日期
     * @param year
     * @param week
     * @param weekDay 需要输出星期几对应的日期 (1~7)
     * @return {Date}
     */
    static transWeekIndexToDate(year, week, weekDay) {
        const yearStart = moment([year, 0, 1]);
        const dayLong = 24 * 60 * 60 * 1000;
        const firstWeekLong = (7 - yearStart.day()) * dayLong;
        const weeksLong = (week - 1) * 7 * dayLong;
        const weekDayLong = weekDay * dayLong;
        const dayTimestamp = yearStart.valueOf() + firstWeekLong + weeksLong + weekDayLong;
        return moment(dayTimestamp).format('YYYY-MM-DD');
    }
    /**
     * 显示调试面板(仅支持H5)
     * @param cssSelector
     * @param callback
     */
    static showDevConsole(cssSelector, callback) {
    static $_showDevConsole(cssSelector, callback) {
        // 只支持 h5 编译
        if (process.env.TARO_ENV !== 'h5') {
            return;
@@ -576,3 +593,5 @@
        console.info(Math.round(px) + 'px');
    };
}
global.Tools = Tools;
layout/loading/CLoading.vue
@@ -4,10 +4,7 @@
 */
<template>
    <view
        class="c-loading"
        @tap="evt => handleGoTo()"
    >
    <view class="c-loading">
        <AtActivityIndicator
            :isOpened="show"
            mode="center"
layout/numerical/CNumerical.vue
New file
@@ -0,0 +1,74 @@
/**
 * CNumerical - 数值显示
 * @author Tevin
 */
<template>
    <view class="c-numerical at-row at-row--wrap">
        <view
            class="at-col"
            v-for="(item,index) in values2"
            :key="index"
            :class="'at-col-' + valueFlex[index]"
        >
            <view class="c-numerical-value">
                <text>{{item.integer}}</text>
                <text
                    class="c-numerical-decimal"
                    :class="item.integer.length>6?'small':''"
                    v-if="item.decimal.length>0"
                >.{{item.decimal}}</text>
            </view>
            <view class="c-numerical-title">{{item.title}}</view>
        </view>
    </view>
</template>
<script>
import Taro from '@tarojs/taro';
import {} from 'taro-ui-vue';
import './cNumerical.scss';
export default {
    name: 'CNumerical',
    components: {},
    props: {
        values: Array,
    },
    computed: {
        values2() {
            return (
                this.values.map(item => ({
                    ...item,
                    integer: (item.value + '').split('.')[0] || '',
                    decimal: (item.value + '').split('.')[1] || '',
                })) || []
            );
        },
        valueFlex() {
            return this.values.map((item, index) => {
                const surplus = this.values.length % 3;
                if (surplus === 0) {
                    return 4;
                } else if (surplus === 1) {
                    if (index === this.values.length - 1) {
                        return 12;
                    } else {
                        return 4;
                    }
                } else if (surplus === 2) {
                    if (index >= this.values.length - 2) {
                        return 6;
                    } else {
                        return 4;
                    }
                }
            });
        },
    },
    data() {
        return {};
    },
    methods: {},
};
</script>
layout/numerical/cNumerical.scss
New file
@@ -0,0 +1,26 @@
/**
 * CNumerical - 数值显示
 * @author Tevin
 */
@import "../../common/sassMixin";
.c-numerical {
    text-align: center;
    .at-col {
        padding: 10px 0;
    }
    .c-numerical-value {
        font-size: 40px;
        line-height: 60px;
        .c-numerical-decimal {
            &.small {
                font-size: 30px;
            }
        }
    }
    .c-numerical-title {
        font-size: 30px;
        color: #666;
    }
}
layout/numerical/index.js
New file
@@ -0,0 +1,10 @@
/**
 * CNumerical
 * @author Tevin
 */
import CNumerical from '@components/layout/numerical/CNumerical.vue';
export {
    CNumerical,
}
plugins/echarts/CECharts.weapp.vue
New file
@@ -0,0 +1,208 @@
/**
 * CECharts
 * @author Tevin
 */
<template>
    <view class="c-echarts">
        <canvas
            class="c-echarts-canvas"
            type="2d"
            :id="canvasId"
            :canvasId="canvasId"
            @touchstart="evt => disableTouch ? null : touchStart(evt)"
            @touchmove="evt => disableTouch ? null : touchMove(evt)"
            @touchend="evt => disableTouch ? null : touchEnd(evt)"
        ></canvas>
    </view>
</template>
<script>
import WxCanvas from './wxCanvas';
import * as echarts from './echarts';
import './cECharts.scss';
let canvasCount = 0;
const wrapTouch = event => {
    for (let i = 0; i < event.touches.length; ++i) {
        const touch = event.touches[i];
        touch.offsetX = touch.x;
        touch.offsetY = touch.y;
    }
    return event;
};
export default {
    name: 'CECharts',
    components: {},
    props: {
        canvasId: {
            type: String,
            default: () =>
                'ec-canvas-' + ++canvasCount + '-' + parseInt(Math.random() * 10000),
        },
        disableTouch: {
            type: Boolean,
            default: false,
        },
        onReady: Function,
    },
    data() {
        return {};
    },
    methods: {
        init(callback) {
            // 基础库必须 2.9.0 以上,使用 <canvas type="2d"></canvas>,不支持旧版
            const query = wx.createSelectorQuery();
            query
                .select('#' + this.canvasId)
                .fields({ node: true, size: true })
                .exec(res => {
                    const canvasNode = res[0].node;
                    this.canvasNode = canvasNode;
                    const canvasDpr = wx.getSystemInfoSync().pixelRatio;
                    const canvasWidth = res[0].width;
                    const canvasHeight = res[0].height;
                    const ctx = canvasNode.getContext('2d');
                    const canvas = new WxCanvas(ctx, this.canvasId, true, canvasNode);
                    echarts.setCanvasCreator(() => {
                        return canvas;
                    });
                    if (typeof callback === 'function') {
                        callback(canvas, canvasWidth, canvasHeight, canvasDpr);
                    } else {
                        this.triggerEvent('init', {
                            canvas: canvas,
                            width: canvasWidth,
                            height: canvasHeight,
                            dpr: canvasDpr,
                        });
                    }
                });
        },
        canvasToTempFilePath(opt) {
            const query = wx.createSelectorQuery().in(this);
            query
                .select('#' + this.canvasId)
                .fields({ node: true, size: true })
                .exec(res => {
                    const canvasNode = res[0].node;
                    opt.canvas = canvasNode;
                    wx.canvasToTempFilePath(opt);
                });
        },
        touchStart(e) {
            if (this.chart && e.touches.length > 0) {
                const touch = e.touches[0];
                const handler = this.chart.getZr().handler;
                handler.dispatch('mousedown', {
                    zrX: touch.x,
                    zrY: touch.y,
                    preventDefault: () => {},
                    stopImmediatePropagation: () => {},
                    stopPropagation: () => {},
                });
                handler.dispatch('mousemove', {
                    zrX: touch.x,
                    zrY: touch.y,
                    preventDefault: () => {},
                    stopImmediatePropagation: () => {},
                    stopPropagation: () => {},
                });
                handler.processGesture(wrapTouch(e), 'start');
            }
        },
        touchMove(e) {
            if (this.chart && e.touches.length > 0) {
                const touch = e.touches[0];
                const handler = this.chart.getZr().handler;
                handler.dispatch('mousemove', {
                    zrX: touch.x,
                    zrY: touch.y,
                    preventDefault: () => {},
                    stopImmediatePropagation: () => {},
                    stopPropagation: () => {},
                });
                handler.processGesture(wrapTouch(e), 'change');
            }
        },
        touchEnd(e) {
            if (this.chart) {
                const touch = e.changedTouches ? e.changedTouches[0] : {};
                const handler = this.chart.getZr().handler;
                handler.dispatch('mouseup', {
                    zrX: touch.x,
                    zrY: touch.y,
                    preventDefault: () => {},
                    stopImmediatePropagation: () => {},
                    stopPropagation: () => {},
                });
                handler.dispatch('click', {
                    zrX: touch.x,
                    zrY: touch.y,
                    preventDefault: () => {},
                    stopImmediatePropagation: () => {},
                    stopPropagation: () => {},
                });
                handler.processGesture(wrapTouch(e), 'end');
            }
        },
    },
    mounted() {
        // Disable prograssive because drawImage doesn't support DOM as parameter
        // See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
        echarts.registerPreprocessor(option => {
            if (option && option.series) {
                if (option.series.length > 0) {
                    option.series.forEach(series => {
                        series.progressive = 0;
                    });
                } else if (typeof option.series === 'object') {
                    option.series.progressive = 0;
                }
            }
        });
        setTimeout(() => {
            this.init((canvas, width, height, dpr) => {
                this.chart = echarts.init(canvas, null, {
                    width: width,
                    height: height,
                    devicePixelRatio: dpr, // 像素
                });
                canvas.setChart(this.chart);
                this.onReady && this.onReady(this.chart);
                this.chart.setOption({
                    tooltip: {
                        backgroundColor: 'rgba(50,50,50,0.7)',
                        textStyle: {
                            color: '#ffffff',
                        },
                        // 重新修正浮窗位置
                        position: (pos, params, dom, rect, size) => {
                            const [pX, pY] = pos;
                            const [contX, contY] = size.contentSize;
                            const [viewX, viewY] = size.viewSize;
                            const contentPoint = {};
                            // 鼠标在左侧时 tooltip 显示到右侧
                            if (pX < viewX / 2) {
                                contentPoint.right = Math.max(viewX - pX - contX, 0);
                            }
                            // 鼠标在右侧时 tooltip 显示到左侧。
                            else {
                                contentPoint.left = Math.max(pX - contX, 0);
                            }
                            // 限制不超过底部边界
                            if (pY + contY <= viewY) {
                                contentPoint.top = pY;
                            } else {
                                contentPoint.top = viewY - contY;
                            }
                            return contentPoint;
                        },
                    },
                });
            });
        }, 100);
    },
};
</script>
plugins/echarts/cECharts.scss
New file
@@ -0,0 +1,14 @@
/**
 * CECharts
 * @author Tevin
 */
@import "../../common/sassMixin";
.c-echarts {
    .c-echarts-canvas {
        display: block;
        width: 100%;
        height: 100%;
    }
}
plugins/echarts/echarts.js
New file
Diff too large
plugins/echarts/index.js
New file
@@ -0,0 +1,10 @@
/**
 * qrcode
 * @author Tevin
 */
import CECharts from '@components/plugins/echarts/CECharts';
export {
    CECharts
}
plugins/echarts/wxCanvas.js
New file
@@ -0,0 +1,111 @@
export default class WxCanvas {
  constructor(ctx, canvasId, isNew, canvasNode) {
    this.ctx = ctx;
    this.canvasId = canvasId;
    this.chart = null;
    this.isNew = isNew
    if (isNew) {
      this.canvasNode = canvasNode;
    }
    else {
      this._initStyle(ctx);
    }
    // this._initCanvas(zrender, ctx);
    this._initEvent();
  }
  getContext(contextType) {
    if (contextType === '2d') {
      return this.ctx;
    }
  }
  // canvasToTempFilePath(opt) {
  //   if (!opt.canvasId) {
  //     opt.canvasId = this.canvasId;
  //   }
  //   return wx.canvasToTempFilePath(opt, this);
  // }
  setChart(chart) {
    this.chart = chart;
  }
  addEventListener() {
    // noop
  }
  attachEvent() {
    // noop
  }
  detachEvent() {
    // noop
  }
  _initCanvas(zrender, ctx) {
    zrender.util.getContext = function () {
      return ctx;
    };
    zrender.util.$override('measureText', function (text, font) {
      ctx.font = font || '12px sans-serif';
      return ctx.measureText(text);
    });
  }
  _initStyle(ctx) {
    ctx.createRadialGradient = () => {
      return ctx.createCircularGradient(arguments);
    };
  }
  _initEvent() {
    this.event = {};
    const eventNames = [{
      wxName: 'touchStart',
      ecName: 'mousedown'
    }, {
      wxName: 'touchMove',
      ecName: 'mousemove'
    }, {
      wxName: 'touchEnd',
      ecName: 'mouseup'
    }, {
      wxName: 'touchEnd',
      ecName: 'click'
    }];
    eventNames.forEach(name => {
      this.event[name.wxName] = e => {
        const touch = e.touches[0];
        this.chart.getZr().handler.dispatch(name.ecName, {
          zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
          zrY: name.wxName === 'tap' ? touch.clientY : touch.y,
          preventDefault: () => {},
          stopImmediatePropagation: () => {},
          stopPropagation: () => {}
        });
      };
    });
  }
  set width(w) {
    if (this.canvasNode) this.canvasNode.width = w
  }
  set height(h) {
    if (this.canvasNode) this.canvasNode.height = h
  }
  get width() {
    if (this.canvasNode)
      return this.canvasNode.width
    return 0
  }
  get height() {
    if (this.canvasNode)
      return this.canvasNode.height
    return 0
  }
}