he wei
2021-07-29 310e692a29317f823a40a195bfe97fd9ce0c12b9
U 充放电一体机实时页面
8个文件已添加
5个文件已修改
4403 ■■■■■ 已修改文件
src/assets/js/const/const_aio.js 272 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/tools/Timeout.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/diagram/diagram.vue 652 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/diagram/index.vue 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/diagram/js/common.js 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/diagram/js/diagram.js 1206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/diagram/js/json.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/dataTest/components/activateDialogContent.vue 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/dataTest/components/chargeDialogContent.vue 452 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/dataTest/components/dischargeDialogContent.vue 476 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/dataTest/js/draw_diagram.js 486 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/dataTest/realTimeAio.vue 448 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目需求.md 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/const/const_aio.js
@@ -1,5 +1,5 @@
export default {
    // workstates: ["在线浮充","预充电","核容测试","停电放电","内阻测试","K1/D1测试", '离线养护测试', '未知'],
    workstates: ["停止", "暂停放电", "放电测试", "暂停充电", "正在充电"],
    // alarmstates: ["继电器K1告警","通讯告警","设备过温告警","二极管D1告警"],
    // stopreasons: {
    //     0:'设备掉电',1:'手动终止',2:'放电时间到',3:'放电容量到',4:'单体电压下限到',5:'单体温度上限到',6:'组端电压下限到',
@@ -74,6 +74,8 @@
    ],
    // æ”¾ç”µå°æ—¶çއ
    HourRate: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20],
    // æ’流总阶段数
    flowOverCount: [1, 2, 3],
    dischargeRules: {
        //浮充电压(V)
        AutoTestStartVol: {
@@ -144,72 +146,72 @@
            pattern: /^[0-9]{1,4}$/,
            regVal: true,
            min: 1,
            max: 2000,
            msg: '取值范围1~2000(整数)'
            max: 9999,
            msg: '取值范围1~9999(整数)'
        },
        // æ”¾ç”µç”µæµ
        DisCurr: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
            max: 150,
            msg: '取值范围1~150(整数)'
        },
        //预放功率
        DisPower: {
            pattern: /^[0-9]{1,3}$/,
            pattern: /^[0-9]{1}(\.[0-9]{0,1})?$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
            min: 0,
            max: 7.5,
            msg: '取值范围0~7.5 (保留一位小数)'
        },
        //放电阻值
        DisPreRes: {
            pattern: /^[0-9]{1,3}$/,
            pattern: /^[0-9]{1,3}(\.[0-9]{0,2})?$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
            min: 0.05,
            max: 655,
            msg: '取值范围0.05~655(保留两位小数)'
        },
        //放电时长
        DisTime: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            min: 0,
            max: 500,
            msg: '取值范围1~500(整数)'
            msg: '取值范围0~500(整数)'
        },
        //充完静置
        DisWaitTime: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            min: 0,
            max: 500,
            msg: '取值范围1~500(整数)'
            msg: '取值范围0~500(整数)'
        },
        //浮充时长
        FloatCharTimeLong: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        // //浮充时长
        // FloatCharTimeLong: {
        //     pattern: /^[0-9]{1,3}$/,
        //     regVal: true,
        //     min: 1,
        //     max: 300,
        //     msg: '取值范围1~300(整数)'
        // },
        //组端下限
        GroupVol_Low: {
            pattern: /^[0-9]+(\.[0-9]{0,1})?$/,
            regVal: true,
            min: 43,
            max: 54,
            msg: '取值范围43.0~54.0'
            min: 1,
            max: 285,
            msg: '取值范围1~285'
        },
        //单体上限
        MonVolHightLimit: {
            pattern: /^[0-9]{1,3}$/,
            pattern: /^[0-9]{1,2}(\.[0-9]{0,2})?$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
            max: 16,
            msg: '取值范围1~16(保留两位小数)'
        },
        //单体上限数量
        MonVolHightLimitCount: {
@@ -223,7 +225,7 @@
        MonomerLowCount: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 0,
            min: 1,
            max: 240,
            msg: '取值范围0~240(整数)'
        },
@@ -239,9 +241,9 @@
        MonomerVol_Low: {
            pattern: /^[0-9]{1,2}(\.[0-9]{0,2})?$/,
            regVal: true,
            min: 1.8,
            max: 2.25,
            msg: '取值范围1.80~2.25(保留两位小数)'
            min: 0,
            max: 20,
            msg: '取值范围0~20(保留两位小数)'
        },
        //活化次数
        OffLineYHTimes: {
@@ -256,108 +258,108 @@
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 125,
            msg: '取值范围1~125(整数)'
            max: 285,
            msg: '取值范围1~285(整数)'
        }
    },
    // stateList: [
    //     {
    //         id: 1,
    //         name: "workState",
    //         type: "",
    //         icon: "",
    //         text: "设备工作状态:",
    //         value: "在线浮充",
    //         show: false
    //     },
    //     {
    //         id: 2,
    //         name: "connect",
    //         type: "",
    //         icon: "el-icon-tongxun",
    //         text: "设备通讯:",
    //         value: "正常",
    //         show: false
    //     },
    //     {
    //         id: 3,
    //         name: "devTemp",
    //         type: "",
    //         icon: "el-icon-wendu",
    //         text: "设备温度:",
    //         value: "正常",
    //         show: false
    //     },
    //     {
    //         id: 4,
    //         name: "contact",
    //         type: "",
    //         icon: "el-icon-fenxiang",
    //         text: "干接点:",
    //         value: "正常",
    //         show: false
    //     },
    //     {
    //         id: 5,
    //         name: "stopReason",
    //         type: "",
    //         icon: "",
    //         text: "核容终止原因:",
    //         value: "未知",
    //         show: false
    //     },
    //     {
    //         id: 6,
    //         name: "failReason",
    //         type: "",
    //         icon: "",
    //         text: "操作失败原因:",
    //         value: "未知",
    //         show: false
    //     },
    //     {
    //         id: 7,
    //         name: "resDay",
    //         type: "",
    //         icon: "",
    //         text: "剩余天数:",
    //         value: "0",
    //         notShow: true,
    //         show: false
    //     },
    //     {
    //         id: 8,
    //         name: "workMode",
    //         type: "",
    //         icon: "",
    //         text: "工作模式:",
    //         value: "停止",
    //         notShow: true,
    //         show: false
    //     },
    //     {
    //         id: 9,
    //         name: "groupVol",
    //         type: "",
    //         icon: "",
    //         text: "组端电压:",
    //         value: "0",
    //         unit: "V",
    //         notShow: true,
    //         show: false
    //     },
    //     {
    //         id: 10,
    //         name: "peakVol",
    //         type: "",
    //         icon: "",
    //         text: "峰值电压:",
    //         value: "0",
    //         unit: "V",
    //         notShow: true,
    //         show: false
    //     }
    // ],
    stateList: [
        {
            id: 1,
            name: "workState",
            type: "",
            icon: "",
            text: "设备工作状态:",
            value: "在线浮充",
            show: false
        },
        {
            id: 2,
            name: "connect",
            type: "",
            icon: "el-icon-tongxun",
            text: "设备通讯:",
            value: "正常",
            show: false
        },
        {
            id: 3,
            name: "devTemp",
            type: "",
            icon: "el-icon-wendu",
            text: "设备温度:",
            value: "正常",
            show: false
        },
        {
            id: 4,
            name: "contact",
            type: "",
            icon: "el-icon-fenxiang",
            text: "干接点:",
            value: "正常",
            show: false
        },
        {
            id: 5,
            name: "stopReason",
            type: "",
            icon: "",
            text: "核容终止原因:",
            value: "未知",
            show: false
        },
        {
            id: 6,
            name: "failReason",
            type: "",
            icon: "",
            text: "操作失败原因:",
            value: "未知",
            show: false
        },
        {
            id: 7,
            name: "resDay",
            type: "",
            icon: "",
            text: "剩余天数:",
            value: "0",
            notShow: true,
            show: false
        },
        {
            id: 8,
            name: "workMode",
            type: "",
            icon: "",
            text: "工作模式:",
            value: "停止",
            notShow: true,
            show: false
        },
        {
            id: 9,
            name: "groupVol",
            type: "",
            icon: "",
            text: "组端电压:",
            value: "0",
            unit: "V",
            notShow: true,
            show: false
        },
        {
            id: 10,
            name: "peakVol",
            type: "",
            icon: "",
            text: "峰值电压:",
            value: "0",
            unit: "V",
            notShow: true,
            show: false
        }
    ],
    // getItemByName(name, list) {
    //     let result = false;
    //     for(let i=0; i<list.length; i++) {
src/assets/js/tools/Timeout.js
@@ -51,4 +51,17 @@
    this.workState = false;
};
// è®¾ç½®å¾ªçޝ体 ä½†ä¸å¼€å§‹
Timeout.prototype.init = function (callback, time) {
    this.callback = callback;
    this.time = time;
    this.workState = true;
};
// å…³é—­åŽé‡å¯è®¡æ—¶å™¨
Timeout.prototype.restart = function() {
    this.workState = true;
    this.open();
};
export default Timeout;
src/components/diagram/diagram.vue
New file
@@ -0,0 +1,652 @@
<template>
  <div class="contain">
    <!-- canvas -->
    <!-- è°ƒè¯•模式时 æ˜¾ç¤ºå–坐标 å’Œåæ ‡å®šä½ æµ®çª—显示放大细节 ç‚¹å‡»å…ƒç´ ï¼Œæ‰“印元素对象信息 -->
    <div class="main">
        <div class="tools-handle"
            v-if="debug"
            @click="showDebug = !showDebug"
            >&bull;&bull;&bull;</div>
      <div class="tools" v-show="showDebug">
          <!-- æ˜¾ç¤ºé¼ æ ‡åå­—线 -->
          <div class="btn" :class="{'active': showCross}" @click="showCrossClick">取坐标</div>
          <div class="btn" :class="{active: setCross}" @click="setCrossClick">坐标定位</div>
      </div>
      <div class="wraper" ref="wraper">
          <div class="canvas-container"
            :class="canvasWrapClass"
            ref="can"
            :style="canvasStyle"
            @click="wrapClick"
            >
            <canvas
                v-for="(item, idx) in levelArr"
                :key="'level_' + idx"
                :width="width"
                :height="height"
                :ref="item"></canvas>
            <!-- <canvas
                :width="width"
                :height="height"
                ref="stateL"></canvas>
            <canvas
                :width="width"
                :height="height"
                ref="flushL"></canvas>
            <slot></slot> -->
          </div>
        <!-- <canvas ref='can'
          class="can"
          :width="width"
          :height="height"
          ></canvas> -->
        <!-- é¼ æ ‡å–点十字光标 -->
        <div :class="['line-h', {'hide': !showCross && !setCross}]" :style="{left: 0, top: crossTop}"></div>
        <div :class="['line-v', {'hide': !showCross && !setCross}]" :style="{left: crossLeft, top: 0}"></div>
        <div class="pos_contain" :style="canvasStyle">
          <slot></slot>
        </div>
      </div>
    </div>
    <!-- é¼ æ ‡å–canvas坐标 -->
    <div :class="['mouseInfo', {'hide': !showCross}]" :style="posObj">
      é¼ æ ‡å–点x坐标:<span>{{pointX}}</span><br />
      é¼ æ ‡å–点y坐标:<span>{{pointY}}</span>
    </div>
    <!-- åæ ‡å®šä½ -->
    <div :class="['setInfo', {'hide': !setCross}]" :style="posObj">
      x坐标: <input type="text" v-model="inputX"><div class="_btn" @click="sub('inputX')">-</div><div class="_btn" @click="add('inputX')">+</div><br />
      y坐标: <input type="text" v-model="inputY"><div class="_btn" @click="sub('inputY')">-</div><div class="_btn" @click="add('inputY')">+</div>
    </div>
    <!-- æ”¾å¤§é•œ -->
    <div :class="['magnify', {'hide': !showCross && !setCross}]" :style="[posObj, bgObj]"></div>
  </div>
</template>
<script>
//   import Draw from './js/draw';
  import common from './js/common';
  let {
    transSize
    ,throttle
  } = common;
  export default {
    gridWidth: 10
    ,lineWidth: 4
    ,strokeStyle: '#00f7f9'
    // ç¦»å±canvas
    ,offscreenCanvas: null
    ,dataTransfer: null
    // ç”»å¸ƒçš„css尺寸
    ,canvasW: 0
    ,canvasH: 0
    // é™æ€å±‚çš„base64图 è°ƒè¯•用作放大镜图
    ,canvasImg: ''
    ,props: {
        width: {
            type: Number
            ,default: 1800
        }
        ,height: {
            type: Number
            ,default: 880
        }
        ,debug: {
            type: Boolean
            ,default: false
        }
        ,wrapClass: {
            type: [String, Array]
            ,default: ''
        }
        ,levelArr: {
          type: Array
          ,default () {
            return ['staticL'];
          }
        }
        //
        ,hasFlush: {
          type: Boolean
          ,default: false
        }
    }
    ,data() {
      return {
        // æ˜¯å¦æ˜¾ç¤ºè°ƒè¯•工具
        showDebug: false
        ,posObj: {
            left: 'auto'
            ,right: 'auto'
            ,top: 'auto'
            ,bottom: 'auto'
            ,'--trans': 90 + 'px'
        }
        ,testSrc: ''
        ,isMounted: false
        ,resizeF: false
        ,ratio: 1
        // æ˜¯å¦æ˜¾ç¤ºé¼ æ ‡åå­—线 è°ƒè¯•用
        ,showCross: false
        ,setCross: false
        // æ˜¯å¦è‡ªç”±ç”»çº¿ é»˜è®¤ä¸ºfalse
        // ,freeLine: false
        // canvas里的对象是否可拖动
        // ,canvas_dragable: true
        // canvas ä¸­è¢«é€‰ä¸­æ‹–拽的对象
        // ,canvas_select_obj: null
        // å½“前canvas_obj_id
        // ,canvas_select_obj_id: false
        // ç‚¹å‡»ä½ç½®ç›¸å¯¹å¯¹è±¡çš„偏移
        // ,offsetX: 0
        // ,offsetY: 0
        // ç”»å¸ƒä¸Šé¼ æ ‡åæ ‡
        // ,mouseX: 0
        // ,mouseY: 0
        // è°ƒè¯•用的 é¼ æ ‡ç‚¹å–çš„canvas坐标
        ,pointX: 0
        ,pointY: 0
        // è¾“入坐标定位
        ,inputX: 0
        ,inputY: 0
        ,mouseTop: 0
        ,mouseLeft: 0
      };
    }
    ,computed: {
      wrapWidth: {
        get () {
          // æ·»åŠ ä¾æ‡’
          this.resizeF;
          if (this.isMounted) {
            let rect = this.$refs.wraper.getBoundingClientRect();
            // console.log(rect, '00000');
            return rect.width;
          } else {
            return 0;
          }
        }
      }
      ,wrapHeight () {
        // æ·»åŠ ä¾æ‡’
        this.resizeF;
        if (this.isMounted) {
          let rect = this.$refs.wraper.getBoundingClientRect();
          // console.log(rect, '00000');
          return rect.height;
        } else {
          return 0;
        }
      }
      ,canvasStyle () {
        if (!this.isMounted) return {};
        let obj = transSize(
          this.wrapWidth,
          this.wrapHeight
          ,this.width
          ,this.height
          ,{
            width: this.width
            ,height: this.height
            ,left: 0
            ,top: 0
            ,right: 0
            ,bottom: 0
          });
        // console.log(obj, '==');
        return {
          width: obj.width + 'px'
          ,height: obj.height + 'px'
        }
      }
      // æ”¾å¤§é•œèƒŒæ™¯
      ,bgObj () {
        let res = {};
        if (this.isMounted && this.debug) {
          // console.log(this.$refs[this.levelArr[0]][0].toDataURL());
          // debugger;
          res.backgroundImage = 'url(' + this.$refs[this.levelArr[0]][0].toDataURL() + ')';
          res.backgroundPosition = (this.pointX * 2 - 100) * -1 + 'px ' + (this.pointY * 2 - 100) * -1 + 'px';
          res.backgroundSize = this.width * 2 + 'px ' + this.height * 2 + 'px';
        }
        return res;
      }
      // obj set
      ,transObj: {
        get () {
          return null;
        }
        ,set (val) {
          // console.log('transObj set', val);
          this.ratio = val.width / this.width;
          this.$emit('ratioChanged', this.ratio);
        //   $can && $can.setRatio(this.ratio);
          this.recycleStyle = {
            // width: val.width + 'px'
            height: val.height + 'px'
            ,left: (this.wrapWidth - val.width) / 2 + 'px'
          };
          this.$options.canvasW = val.width;
          this.$options.canvasH = val.height;
          // console.log(this.ratio, 'ratio');
        }
      }
      ,crossLeft () {
        return this.mouseLeft + (this.wrapWidth - this.$options.canvasW) / 2 + 'px';
      }
      ,crossTop () {
        return this.mouseTop + (this.wrapHeight - this.$options.canvasH) / 2 + 'px';
      }
      ,canvasWrapClass () {
          if ('string' == typeof(this.wrapClass)) {
              return this.wrapClass.split(/\s+/);
          } else {
              return this.wrapClass;
          }
      }
    }
    ,watch: {
      wrapWidth (n) {
        if (n) {
          this.transObj = transSize(
            this.wrapWidth,
            this.wrapHeight
            ,this.width
            ,this.height
            ,{
              width: this.width
              ,height: this.height
              ,left: 0
              ,top: 0
              ,right: 0
              ,bottom: 0
            });
        }
      }
      ,wrapHeight (n) {
        if (n) {
          this.transObj = transSize(
            this.wrapWidth,
            this.wrapHeight
            ,this.width
            ,this.height
            ,{
              width: this.width
              ,height: this.height
              ,left: 0
              ,top: 0
              ,right: 0
              ,bottom: 0
            });
        }
      }
    //   ,canvas_select_obj (n) {
    //     // console.log($can, 'select changed');
    //     if (n) {
    //       this.canvas_select_obj_id = n.id;
    //       $can && $can.setSelectedId(n.id);
    //     } else {
    //       this.canvas_select_obj_id = false;
    //       $can && $can.setSelectedId(-1);
    //     }
    //   }
      ,inputX (n) {
        this.mouseLeft = n * this.ratio;
        this.pointX = n * 1;
        if (!this.debug) {
            return false;
        }
        if (n < this.width / 2) {
            this.posObj.left = 'auto';
            this.posObj.right = 20 + 'px';
        } else {
            this.posObj.right = 'auto';
            this.posObj.left = 20 + 'px';
        }
      }
      ,inputY (n) {
        this.mouseTop = n * this.ratio;
        this.pointY = n * 1;
        if (!this.debug) {
            return false;
        }
        if (n < this.height / 2) {
            this.posObj.top = 'auto';
            this.posObj.bottom = 20 + 'px';
            this.posObj['--trans'] = -90 + 'px';
        } else {
            this.posObj.bottom = 'auto';
            this.posObj.top = 20 + 'px';
            this.posObj['--trans'] = 90 + 'px';
        }
      }
    }
    ,methods: {
      resizeHandle () {
        this.resizeF = !this.resizeF;
      }
      ,showCrossClick () {
          this.setCross = false;
          this.showCross = !this.showCross;
      }
      ,setCrossClick () {
          this.showCross = false;
          this.setCross = !this.setCross;
          this.inputX = 0;
          this.inputY = 0;
      }
      ,canvasMouseMoveHandle (e) {
        if (this.showCross) {
          this.pointX = Math.round(e.offsetX / this.ratio);
          this.pointY = Math.round(e.offsetY / this.ratio);
          // this.mouseLeft = Math.round(e.offsetX / this.ratio);
          // this.mouseTop = Math.round(e.offsetY / this.ratio);
          this.mouseTop = e.offsetY;
          this.mouseLeft = e.offsetX;
        //   // é¼ æ ‡åœ¨ç”»å¸ƒçš„第1象限 å®šä½åœ¨ç¬¬3象限
        //     if (this.pointX > this.width / 2
        //         && this.pointY < this.height / 2) {
        //         this.posObj = {
        //             left: 20 + 'px'
        //             ,bottom: 20 + 'px'
        //         };
        //     }
        //   // é¼ æ ‡åœ¨ç”»å¸ƒçš„第2象限 å®šä½åœ¨ç¬¬4象限
        //   if (this.pointX < this.width / 2
        //         && this.pointY < this.height / 2) {
        //         this.posObj = {
        //             right: 20 + 'px'
        //             ,bottom: 20 + 'px'
        //         };
        //     }
        //   // é¼ æ ‡åœ¨ç”»å¸ƒçš„第3象限 å®šä½åœ¨ç¬¬1象限
        //     if (this.pointX < this.width / 2
        //         && this.pointY > this.height / 2) {
        //         this.posObj = {
        //             right: 20 + 'px'
        //             ,top: 20 + 'px'
        //         };
        //     }
        //   // é¼ æ ‡åœ¨ç”»å¸ƒçš„第4象限 å®šä½åœ¨ç¬¬2象限
        //   if (this.pointX > this.width / 2
        //         && this.pointY > this.height / 2) {
        //         this.posObj = {
        //             left: 20 + 'px'
        //             ,top: 20 + 'px'
        //         };
        //     }
            if (this.pointX > this.width / 2) {
                this.posObj.right = 'auto';
                this.posObj.left = 20 + 'px';
            } else {
                this.posObj.left = 'auto';
                this.posObj.right = 20 + 'px';
            }
            if (this.pointY > this.height / 2) {
                this.posObj.bottom = 'auto';
                this.posObj.top = 20 + 'px';
                this.posObj['--trans'] = 90 + 'px';
            } else {
                this.posObj.top = 'auto';
                this.posObj.bottom = 20 + 'px';
                this.posObj['--trans'] = -90 + 'px';
            }
        }
      }
      // ç”»å¸ƒåˆå§‹åŒ–
      // ,init () {
        // let can = this.$refs.can;
        // $can = new Draw(can, {gridWidth: this.$options.gridWidth});
      // }
      // ç”»å¸ƒåŒºåŸŸç‚¹å‡» debug
      ,wrapClick (e) {
          if (!this.debug) {
              return false;
          }
          this.$emit('debugClick', e);
      }
      // å·¥å…·é€‰æ‹© åˆ‡æ¢æ¨¡å¼
      ,changeMode (obj) {
        this.activeMode = obj.name;
      }
      ,getStyle (obj) {
        return {
          left: obj.position.left + 'px',
          top: obj.position.top + 'px',
          width: obj.position.width + 'px',
          height: obj.position.height + 'px'
        }
      }
      ,sub (obj) {
        if (this[obj] > 0) {
          this[obj]--;
        }
      }
      ,add (obj) {
        if ((obj == 'inputX' && this[obj] < this.width) || (obj == 'inputY' && this[obj] < this.height)) {
          this[obj]++;
        }
      }
    }
    ,mounted () {
      this.isMounted = true;
      this.$nextTick(() => {
        this.resizeHandle();
      });
      window.addEventListener('resize', this.resizeHandle);
      let can = this.$refs.can;
      // $can.drawGrid(can.getContext('2d'));
      // $can.drawSeparateLine(can.getContext('2d'));
    //   can.addEventListener('mousedown', this.canvasMouseDownHandle);
        can.addEventListener('mousemove', throttle((e) => {this.canvasMouseMoveHandle(e)}, 100));
    //   window.addEventListener('mouseup', this.canvasMouseUpHandle);
    }
    ,beforeDestroy () {
    //   window.removeEventListener('mouseup', this.canvasMouseUpHandle);
      window.removeEventListener('resize', this.resizeHandle);
    }
  };
</script>
<style scoped>
  .contain {
    width: 100%;
    height: 100%;
    display: -webkit-flex;
    display: flex;
    overflow: hidden;
    position: relative;
    user-select: none;
    -moz-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    text-align: center;
  }
  .main {
    flex: 1;
    display: -webkit-flex;
    display: flex;
    flex-direction: column;
  }
  .wraper {
    flex: 1;
    background: rgba(0,0,0,.25);
    position: relative;
  }
  .canvas-container {
    /*background: gray;*/
    /* background: rgba(66,66,66, 1); */
    position: absolute;
    left: 50%;
    top: 50%;
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
    z-index: 1;
  }
  .canvas-container canvas {
      position: absolute;
      left: 0;
      top: 0;
      right: 0;
      bottom: 0;
      width: 100%;
      height: 100%;
  }
  .pos {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 0;
    height: 0;
    z-index: -999;
  }
  .btn {
    background: #00f7f9;
    border-radius: 6px;
    margin: 6px;
  }
  .wrap_res {
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    display: -webkit-flex;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 99;
    background: rgba(30, 30, 30, .6);
  }
  .tools-handle {
      background: rgba(128, 128, 128, .2);
      height: 12px;
      font-size: 12px;
      cursor: pointer;
  }
  .tools {
    position: absolute;
    padding: 6px;
    z-index: 99;
  }
  .tools .btn {
    width: 60px;
    height: 60px;
    border-radius: 6px;
    border: 2px #ccc solid;
    margin-left: 4px;
    background-color: transparent;
    display: -webkit-flex;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .tools .btn.active {
    background-color: rgba(200, 200, 200, .6);
  }
.setInfo,
.mouseInfo {
  position: absolute;
  /* top: 20px;
  right: 20px; */
  padding: 20px;
  -webkit-border-radius: 8px;
  border-radius: 8px;
  background: rgba(0, 0, 0, .8);
  z-index: 99;
}
.setInfo {
  /* right: 300px; */
}
.magnify.hide,
.setInfo.hide,
.mouseInfo.hide {
  display: none;
}
.setInfo input,
.mouseInfo span {
  color: #090;
  font-weight: 700;
  padding-left: .6em;
}
.line-h,
.line-v {
  position: absolute;
  left: 50px;
  background: #0f0;
  z-index: 2;
}
.line-h.hide,
.line-v.hide {
  display: none;
}
.magnify {
    width: 200px; /* no */
    height: 200px; /* no */
    position: absolute;
    background: rgba(0, 0, 0, .8);
    border: 1px #00f7f9 solid;
    transform: translateY(var(--trans));
    z-index: 99;
}
.magnify::before,
.magnify::after {
  content: '';
  position: absolute;
  background: #0f0;
}
.magnify::before {
  width: 1px;
  height: 100%;
  left: 50%;
  top: 0;
  transform: translateX(-50%) scaleX(.5);
}
.magnify::after {
  width: 100%;
  height: 1px;
  left: 0;
  top: 50%;
  transform: translateY(-50%) scaleY(.5);
}
.line-v {
  height: 100%;
  width: 1px;
}
.line-h {
  width: 100%;
  height: 1px;
}
.pos_contain {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  /* z-index: -1; */
}
._btn {
  display: inline-block;
  margin-left: 1em;
  width: 20px;
  height: 20px;
}
</style>
src/components/diagram/index.vue
New file
@@ -0,0 +1,136 @@
<template>
  <div class="contain">
    <diagram
      wrap-class="wrap"
      :width="$options.width"
      :height="$options.height"
      :debug="true"
      @ratioChanged="ratioChanged"
      @debugClick="debugClick"
      >
      <canvas
        :width="$options.width"
        :height="$options.height"
        ref="staticL"></canvas>
      <canvas
        :width="$options.width"
        :height="$options.height"
        ref="stateL"></canvas>
      <canvas
        :width="$options.width"
        :height="$options.height"
        ref="flushL"></canvas>
      </diagram>
  </div>
</template>
<script>
  import diagram from './diagram.vue';
  import Diagram from './js/diagram';
  import Timeout from '@/assets/js/Timeout';
  import {
    list
    ,update
    ,updateBalls
  } from './js/draw_diagram';
  let staticL, stateL, flushL;
  export default {
    width: 1200
    ,height: 800
    ,components: {
      diagram
    }
    ,data() {
      return {
        timer: new Timeout()
        ,moveBall: null
      };
    }
    ,methods: {
      ratioChanged (ratio) {
        // console.log(ratio);
        staticL && staticL.setRatio(ratio);
        flushL && flushL.setRatio(ratio);
        stateL && stateL.setRatio(ratio);
      }
      ,init () {
        staticL = new Diagram(this.$refs.staticL);
        stateL = new Diagram(this.$refs.stateL);
        flushL = new Diagram(this.$refs.flushL);
        this.moveBall = updateBalls(flushL);
      }
      ,drawStatic () {
        staticL.importObjList(list);
        staticL.drawAll();
      }
      ,drawFlush () {
      }
      // è°ƒè¯•时的点击
      ,debugClick (o) {
          let point = {
            x: o.offsetX
            ,y: o.offsetY
          };
          let inObj = staticL.mousePointInObj([point.x, point.y], undefined);
          let canvas_obj_id_arr = staticL.getObjIdArr();
          let canvas_obj = staticL.getObjList();
          if (inObj) {
            for (let i = 0, j = canvas_obj_id_arr.length; i < j; i++) {
              let id = canvas_obj_id_arr[i];
              let _inObj = staticL.mousePointInObj([point.x, point.y], id);
              if (_inObj) {
                let _obj = canvas_obj[id];
                console.log('----obj', _obj, id);
                break;
              }
            }
          }
      }
      ,getRTData () {
        return new Promise((resolve, reject) => {
          let res = {
            Q1: Math.random() > 0.5
            ,Q2: Math.random() > 0.5
            ,Q3: Math.random() > 0.5
            ,Q4: Math.random() > 0.5
            ,Q5: Math.random() > 0.5
          };
          setTimeout(() => {
            resolve(res);
          }, 300);
        });
      }
      ,loop () {
        this.timer.start(() => {
          this.getRTData().then((res) => {
            update(this.moveBall, stateL, res);
          }).catch((err) => {
            console.error(err);
            this.timer.open();
          });
          this.timer.open();
        }, 1000);
      }
    }
    ,mounted () {
      this.init();
      this.drawStatic();
      this.loop();
    }
    ,beforeDestroy () {
      this.timer.stop();
    }
  };
</script>
<style>
  .contain {
    widows: 100%;
    height: 100%;
  }
  .wrap {
    background: rgba(66, 66, 66, 1);
  }
</style>
src/components/diagram/js/common.js
New file
@@ -0,0 +1,110 @@
/**
 * è½¬æ¢å°ºå¯¸ canvas缩放后 è¿”回的尺寸不对 è¦åšè°ƒæ•´
 * @param  {[type]} width  canvas的CSS宽度
 * @param  {[type]} height canvas的CSS高度
 * @param  {[type]} canvasWidth  canvas的画布宽度
 * @param  {[type]} canvasHeight  canvas的画布高度
 * @param  {[type]} obj    éœ€è¦è½¬æ¢çš„尺寸对象
 * @return {[type]}        è½¬æ¢åŽçš„尺寸对象
 */
const transSize = function (width, height, canvasWidth, canvasHeight, obj) {
    if (!obj) {
        return {
            width: 0
            ,height: 0
            ,left: 0
            ,top: 0
            ,right: 0
            ,bottom: 0
        }
    }
    let res = {},
        _ratio,
        ratio = canvasWidth / canvasHeight;
    // å¦‚果宽高比大于画布的宽高比 åˆ™æ¯”例以高度来计算 åä¹‹ä»¥å®½åº¦è®¡ç®—
    if (width / height > ratio) {
        _ratio = height / canvasHeight;
        let _width = (width - height * ratio) / 2;
        res.width = 'number' == typeof obj.width ? obj.width * _ratio : obj.width;
        res.height = 'number' == typeof obj.height ? obj.height * _ratio : obj.height;
        res.top = obj.top * _ratio;
        res.bottom = obj.bottom * _ratio;
        res.left = obj.left * _ratio + _width;
        res.right = obj.right * _ratio + _width;
    } else {
        _ratio = width / canvasWidth;
        let _height = (height - width / ratio) / 2;
        res.width = 'number' == typeof obj.width ? obj.width * _ratio : obj.width;
        res.height = 'number' == typeof obj.height ? obj.height * _ratio : obj.height;
        res.top = obj.top * _ratio + _height;
        res.bottom = obj.bottom * _ratio + _height;
        res.left = obj.left * _ratio;
        res.right = obj.right * _ratio;
    }
    // console.log('trans', res, 'obj', obj);
    // console.trace('transSize callStack');
    return res;
}
// é˜²æŠ–
const debounce = function (fn, delay = 500) {
  var timer = null;
  return function () {
    var _this = this;
    var args = arguments;
    if (timer) clearTimeout(timer);
    timer = setTimeout(function () {
      fn.apply(_this, args);
    }, delay);
  };
}
// èŠ‚æµ
const throttle = function (fn, delay = 300){
  var lastTime, timer;
  return function () {
    var _this = this;
    var args = arguments;
    var nowTime = Date.now();
    if(lastTime && nowTime - lastTime < delay){
      if (timer) clearTimeout(timer);
      timer = setTimeout(function () {
        lastTime = nowTime;
        fn.apply(_this, args);
      }, delay)
    }else{
      lastTime = nowTime;
      fn.apply(_this, args);
    }
  }
}
/**
 * æ‰§è¡ŒæŒ‡å®šæ¬¡æ•°çš„定时器
 * @param {回调} func
 * @param {等待时间} w
 * @param {重复次数} t
 */
const interval = function (func, w, t){
    let interv = function () {
        if(typeof t === "undefined" || t-- > 0){
            setTimeout(interv, w);
            try{
                func.call(null);
            }
            catch (e) {
                t = 0;
                throw e.toString();
            }
        }
    }
    setTimeout(interv, w);
}
export default {
    debounce,
    interval,
    throttle,
    transSize
}
src/components/diagram/js/diagram.js
New file
@@ -0,0 +1,1206 @@
// è®°æ•°å™¨é—­åŒ…
function counter (start) {
  let count = start || 0;
  return function () {
    return count++;
  }
}
/**
 * ç§æœ‰æ–¹æ³•
 */
// ç”ŸæˆId
const createObjId = Symbol('createObjId');
// ç”Ÿæˆæˆ–返回计数器
const createCounter = Symbol('createCounter');
// æ·»åŠ obj到对象数组
const addToObj = Symbol('addToObj');
/**
 * ç§æœ‰å±žæ€§
 */
// ç”¨æ¥å­˜å‚¨å…ƒç´ Id
const objIdArr = Symbol('objIdArr');
// é”®ä¸ºå…ƒç´ Id值为元素的返回对象
const objList = Symbol('objList');
// è®¡æ•°å™¨åˆ—表
const counterList = Symbol('counterList');
/**
 * canvas ç”»æ‹“扑图的类
 */
export default class Diagram {
  constructor ($$el, opts) {
    let defaults = {
      strokeStyle: '#50cef5'
      ,fillStyle: '#50cef5'
      // ,lineWidth: 4
      ,lineWidth: 2
      ,gridWidth: 50
    };
    opts = Object.assign({}, defaults, opts);
    this.canvas = $$el;
    this.width = this.canvas.width;
    this.height = this.canvas.height;
    this.context = this.canvas.getContext('2d');
    this.gridWidth = opts.gridWidth;
    // ç”¨æ¥å­˜å‚¨å…ƒç´ Id
    this[objIdArr] = [];
    // é”®ä¸ºå…ƒç´ Id值为元素的返回对象
    this[objList] = {};
    // è®¡æ•°å™¨åˆ—表
    this[counterList] = {};
    // åˆå§‹åŒ–
    this.lineWidth = opts.lineWidth;
    this.context.lineWidth = opts.lineWidth;
    // ç¼©æ”¾æ¯”例
    this.ratio = 1;
    // é€‰ä¸­çš„对象的id
    this.selected_obj_id = -1;
    // this.context.strokeStyle = '#000';
    // this.context.fillStyle = "#000";
    this.strokeStyle = opts.strokeStyle;
    this.context.strokeStyle = opts.strokeStyle;
    this.fillStyle = opts.fillStyle;
    this.context.fillStyle = opts.fillStyle;
    // ç”¨æ¥å­˜æ”¾å¿«ç…§ åˆå§‹1px * 1px
    // this.imageData = this.context.createImageData(1, 1);
    // ç”¨æ¥å­˜æ”¾ç¦»å±canvas快照 æ€§èƒ½æ¯”getImageData好
    // åšç§»åŠ¨å°çƒçš„æ—¶å€™ç§»åŠ¨ä¸€æ¡çº¿æ®µæ‰€éœ€è¦çš„åˆ·æ–°æ¬¡æ•° é»˜è®¤40
    this.COUNT = opts.count || 40;
    this.offscreenCanvas = null;
  }
  /**
   * ç”»ç¦»å±canvas çº¿æ®µ  ä¸ä¼ å‚时画所有线段 ä¼ å¯¹è±¡id åˆ™ç”»æŒ‡å®šçº¿æ®µå¯¹è±¡
   */
  getLineOffscreenCanvas (id) {
    let offscreenCanvas = document.createElement('canvas');
    let offscreenCanvasContext = offscreenCanvas.getContext('2d');
    let ratio = this.ratio;
    offscreenCanvas.width = this.width;
    offscreenCanvas.height = this.height;
    if (id) {
      this.drawObj(offscreenCanvasContext, id);
    } else {
      this[objIdArr].forEach((v) => {
        let obj = this[objList][v];
        if (obj.type == 'line') {
          this.drawObj(offscreenCanvasContext, obj.id);
        }
      });
    }
    return offscreenCanvas;
  }
  // æ›´æ–° select_obj_id
  setSelectedId (id) {
    // console.log(id, this[objList][id], 'selected');
    if (!id || !this[objList][id]) {
      return false;
    }
    this.selected_obj_id = id;
  }
  // èŽ·å–objList
  getObjList () {
    return this[objList];
  }
  // èŽ·å–objIdArr
  getObjIdArr () {
    return this[objIdArr];
  }
  // æ¸…除画布
  clearCanvas () {
    this[objList] = {};
    this[objIdArr] = [];
    this[counterList] = {};
    this.context.clearRect(0, 0, this.width, this.height);
  }
  // ç”Ÿæˆå¯¹è±¡çš„Id
  [createObjId] (type) {
    let counter = this[counterList]['counter_' + type].counter();
    return type + '_' + counter;
  }
  // ç”Ÿæˆæˆ–返回计数器
  [createCounter] (type, start) {
    if (!this[counterList]['counter_' + type]) {
      this[counterList]['counter_' + type] = {
        counter: counter(start)
      }
    }
  }
  // å¯¼å…¥å¤–部对象列表
  importObjList (list) {
    this[objIdArr] = Object.keys(list);
    this[objList] = list;
    this.initCounter();
  }
  // åˆå§‹åŒ–计数器 ä»Žå¤–部导入后调用;
  initCounter () {
    let reg = /^(\S+)_(\d+)$/;
    let obj = {};
    this[objIdArr].forEach((v) => {
      let res = reg.exec(v);
      obj[res[1]] = obj[res[1]] || {max: 0};
      obj[res[1]]['max'] = res[2] > obj[res[1]]['max'] ? res[2] * 1 : obj[res[1]]['max'];
    });
    Object.keys(obj).forEach((v) => {
      this[createCounter](v, obj[v].max + 1);
    });
  }
  // æ·»åŠ ç›¸å…³ä¿¡æ¯åˆ°objList
  [addToObj] (type, opts) {
    this[createCounter](type);
    let id = this[createObjId](type);
    this[objIdArr].push(id);
    // console.log(this[objIdArr]);
// debugger;
    opts['id'] = id;
    this[objList][id] = opts;
  }
  updateCanvas () {
    this.context.save();
    this.context.fillStyle = "rgba(0, 0, 0, 0.85)";
    this.context.globalCompositeOperation = 'destination-in';
    this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
    this.context.restore();
  }
  // å¿«ç…§
  snapshoot (canvas) {
    this.offscreenCanvas = canvas;
  }
  // è®¾ç½®å¯¹è±¡çš„参数
  setOption (id, attr, value) {
    if (!this[objList][id]) {
      return false;
    }
    this[objList][id][attr] = value;
  }
  // è¯»å–对象的参数
  // getOption (id) {
  //   let res = false;
  //   let list = this[objIdArr];
  //   for (let i = 0, j = list.length; i < j; i++) {
  //     if (this[objList][list[i]].id == id) {
  //       res = this[objList][]
  //     }
  //   }
  // }
  setRatio (ratio) {
    this.ratio = ratio;
  }
  drawObj (ctx, id) {
    let obj = this[objList][id];
    if (!obj) {
      return false;
    }
    // debugger;
    // ç»˜åˆ¶å¯¹è±¡
    this[obj.method](ctx, obj);
  }
  removeObj (id) {
    this[objIdArr] = this[objIdArr].filter((v) => {
      return id != v;
    });
    delete this[objList][id];
    this.drawAll();
  }
  /**
   * ç»˜åˆ¶çº¿æ¡ æ ¹æ®å¯¹è±¡é‡Œçš„method属性来调用的
   */
  drawLine (ctx, opts) {
    ctx.save();
    ctx.lineWidth = opts.lineWidth || this.lineWidth;
    ctx.strokeStyle = opts.color || this.strokeStyle;
    ctx.globalCompositeOperation = "destination-over";
    ctx.beginPath();
    for (let i = 0, j = opts.points.length - 1; i < j; i++) {
      if (i == 0) {
        ctx.moveTo(opts.points[i][0], opts.points[i][1]);
      }
      ctx.lineTo(opts.points[i + 1][0], opts.points[i + 1][1]);
    }
    ctx.stroke();
    ctx.closePath();
    ctx.restore();
  }
  // ç”»åœ†ç‚¹
  drawPoint (ctx, opts) {
    ctx.save();
    ctx.strokeStyle = opts.strokeStyle;
    ctx.fillStyle = opts.fillStyle;
    ctx.beginPath();
    ctx.arc(opts.x, opts.y, opts.r, 0, 2 * Math.PI);
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  }
  /**
   * ç»˜åˆ¶è®¾å¤‡ å›¾åƒ  æ ¹æ®å¯¹è±¡é‡Œçš„method属性来调用
   */
  drawDevImg (ctx, opts) {
    ctx.save();
    ctx.lineWidth = this.lineWidth;
    ctx.strokeStyle = this.strokeStyle;
    ctx.translate(opts.x, opts.y);
    ctx.beginPath();
    let img = opts.img;
    // console.log(Date.now());
    // let img = new Image();
    // img.src = opts.src;
    // console.log(img, Date.now())
    // ctx.drawImage(img, opts.x, opts.y, opts.width, opts.height);
    if (img.complete) {
      // ctx.drawImage(img, opts.x, opts.y, opts.width, opts.height);
      ctx.drawImage(img, 0, 0, opts.width, opts.height);
    } else {
      img.addEventListener('load', () => {
        console.log(img.complete, Date.now(), '??');
        // ctx.drawImage(img, 0, 0, opts.width, opts.height);
        this.drawDevImg(ctx, opts);
        // setTimeout(() => {
        //   ctx.drawImage(img, opts.x, opts.y, opts.width, opts.height);
        // }, 500);
      });
    }
    ctx.closePath();
    ctx.restore();
  }
  /**
   * æ ¹æ®json ç»˜åˆ¶å¼€å…³
   */
  drawSwitch (ctx, opts) {
    // ç”»åœ†åœˆ
    let r = 4;
    let color = '#50cef5';
    ctx.save();
    ctx.translate(opts.x, opts.y);
    ctx.fillStyle = color;
    ctx.strokeStyle = color;
    ctx.beginPath();
    ctx.arc(0, 0, r, 0, Math.PI * 2);
    ctx.closePath();
    ctx.stroke();
    ctx.beginPath();
    if ('ver' == opts.direction) {
      ctx.arc(0, opts.distance, r, 0, Math.PI * 2);
    } else {
      ctx.arc(opts.distance, 0, r, 0, Math.PI * 2);
    }
    ctx.closePath();
    ctx.stroke();
    ctx.fillStyle = '#fff';
    ctx.font = '16px Arial';
    if ('ver' == opts.direction) {
      if (opts.name) {
        ctx.textAlign = 'start';
        ctx.textBaseline = 'bottom';
        ctx.fillText(opts.name, 10, -10);
      }
      if (opts.description) {
        ctx.textAlign = 'end';
        ctx.textBaseline = 'middle';
        ctx.fillText(opts.description, -4, opts.distance / 2);
      }
    } else {
      if (opts.name) {
        ctx.textAlign = 'right';
        ctx.textBaseline = 'bottom';
        ctx.fillText(opts.name, -10, -10);
      }
      if (opts.description) {
        ctx.textAlign = 'center';
        ctx.textBaseline = 'top';
        ctx.fillText(opts.description, opts.distance / 2, 4);
      }
    }
    // ç”»è¿žçº¿
    ctx.save();
    if (opts.isOn) {
      ctx.rotate(-6 * Math.PI / 180);
    } else {
      ctx.rotate(-30 * Math.PI / 180);
    }
    ctx.lineWidth = this.lineWidth;
    ctx.strokeStyle = color;
    ctx.globalCompositeOperation = 'destination-over';
    ctx.beginPath();
    if ('ver' == opts.direction) {
      ctx.moveTo(0, r);
      ctx.lineTo(0, opts.distance);
    } else {
      ctx.moveTo(r, 0);
      ctx.lineTo(opts.distance, 0);
    }
    ctx.stroke();
    ctx.closePath();
    if (opts.clickAble) {
      ctx.beginPath();
      ctx.fillStyle = this.strokeStyle;
      if ('ver' == opts.direction) {
        ctx.arc(0, opts.distance - opts.r, opts.r, - Math.PI / 2, Math.PI / 2);
      } else {
        ctx.arc(opts.distance - opts.r, 0, opts.r, - Math.PI, 0);
      }
      ctx.fill();
      ctx.closePath();
    }
    ctx.restore();
    ctx.restore();
  }
  // åˆ¤æ–­é¼ æ ‡ç‚¹å‡»çš„位置有没有无素 ç”¨æœ‰æ²¡æœ‰é¢œè‰²å€¼æ¥åˆ¤æ–­
  mousePointInObj (mousePoint, obj) {
    let offscreenCanvas;
    if (!obj) {
      offscreenCanvas = this.getOffscreenCanvas(true, undefined);
    } else {
      offscreenCanvas = this.getOffscreenCanvas(false, obj);
      // that.drawMonitor(offscreenCanvas);
    }
    let offscreenCanvasContext = offscreenCanvas.getContext('2d');
    let ratio = this.ratio;
    // console.log('ratio', ratio);
    // å–九个点 å®¹å·®
    // console.log(mousePoint);
    let res = offscreenCanvasContext.getImageData(mousePoint[0] / ratio - 1, mousePoint[1] / ratio - 1, 3, 3);
    // console.log(res, 'getImageData');
    let transparentCount = 0;
    for (let i = 0, j = res.data.length; i < j; i += 4) {
      // let r = res.data[i];
      // let g = res.data[i + 1];
      // let b = res.data[i + 2];
      let a = res.data[i + 3];
      if (!a) {
        // console.log('这个像素没有内容');
        transparentCount++;
      }
    }
    // console.log(transparentCount, 'transparentCount');
    return transparentCount < 3 * 3;
  }
  // é¼ æ ‡ç‚¹å‡»å¤„在不在线段上
  _pointInLine (mousePoint, pointS, pointE) {
    let offscreenCanvas = document.createElement('canvas');
    let offscreenCanvasContext = offscreenCanvas.getContext('2d');
    offscreenCanvas.width = this.width;
    offscreenCanvas.height = this.height;
    offscreenCanvasContext.save();
    offscreenCanvasContext.lineWidth = this.lineWidth;
    offscreenCanvasContext.strokeStyle = this.strokeStyle;
    offscreenCanvasContext.globalCompositeOperation = "destination-over";
    offscreenCanvasContext.beginPath();
    offscreenCanvasContext.moveTo(pointS[0], pointS[1]);
    offscreenCanvasContext.lineTo(pointE[0], pointE[1]);
    offscreenCanvasContext.stroke();
    offscreenCanvasContext.closePath();
    offscreenCanvasContext.restore();
    let ratio = this.ratio;
    let res = offscreenCanvasContext.getImageData(mousePoint[0] / ratio - 1, mousePoint[1] / ratio - 1, 3, 3);
    let transparentCount = 0;
    for (let i = 0, j = res.data.length; i < j; i += 4) {
      // let r = res.data[i];
      // let g = res.data[i + 1];
      // let b = res.data[i + 2];
      let a = res.data[i + 3];
      if (!a) {
        // console.log('这个像素没有内容');
        transparentCount++;
      }
    }
    // console.log(transparentCount, 'transparentCount');
    return transparentCount < 3 * 3;
  }
  // åˆ¤æ–­é¼ æ ‡æ˜¯å¦ç‚¹å‡»çš„线段
  mousePointInLine (mousePoint, id) {
    let offscreenCanvas = this.getLineOffscreenCanvas(id);
    let offscreenCanvasContext = offscreenCanvas.getContext('2d');
    let ratio = this.ratio;
    // å–九个点 å®¹å·®
    // console.log(mousePoint);
    let res = offscreenCanvasContext.getImageData(mousePoint[0] / ratio - 1, mousePoint[1] / ratio - 1, 3, 3);
    // console.log(res, 'getImageData');
    let transparentCount = 0;
    for (let i = 0, j = res.data.length; i < j; i += 4) {
      let r = res.data[i];
      let g = res.data[i + 1];
      let b = res.data[i + 2];
      let a = res.data[i + 3];
      if ((!r && !g && !b) || !a) {
        // console.log('这个像素没有内容');
        transparentCount++;
      }
    }
    // console.log(transparentCount, 'transparentCount');
    return transparentCount < 3 * 3;
  }
  /**
 * ç”»è™šçº¿
 * @param  {[type]} ctx        ç”»å¸ƒä¸Šä¸‹æ–‡
 * @return {[type]}            [description]
 */
  drawDashLine (ctx, opts) {
    ctx.save();
    ctx.lineWidth = opts.lineWidth;
    ctx.strokeStyle = opts.color;
    ctx.globalCompositeOperation = "destination-over";
    // è®¾ç½®è™šçº¿
    ctx.setLineDash([2, 4]);
    ctx.beginPath();
    for (let i = 0, j = opts.points.length; i < j; i++) {
      if (0 == i) {
        ctx.moveTo(opts.points[0][0], opts.points[0][1]);
      } else {
        ctx.lineTo(opts.points[i][0], opts.points[i][1]);
      }
    }
    ctx.stroke();
    ctx.closePath();
    ctx.restore();
  }
  // å–除了当前移动的元素之外的元素 ç»˜åˆ¶ç¦»å±canvas
  getOffscreenCanvas (drawAll, objId) {
    let offscreenCanvas = document.createElement('canvas');
    let offscreenCanvasContext = offscreenCanvas.getContext('2d');
    offscreenCanvas.width = this.width;
    offscreenCanvas.height = this.height;
    // console.log(objId, 'objId');
    // console.trace('getOffscreenCanvas');
    // ä¸ç”»å…¨éƒ¨
    if (!drawAll) {
      // æŒ‡å®šobjId åˆ™åªç”»æŒ‡å®šå¯¹è±¡
      if (objId) {
        this.drawObj(offscreenCanvasContext, objId);
      }
    // ç”»å…¨éƒ¨
    } else {
      // drawAll, no objId åˆ™ç”»å…¨éƒ¨  æœ‰objId åˆ™ç”»é™¤äº†objId的全部
      // console.log(objId, 'draw snapshoot', this.selected_obj_id, this[objIdArr]);
      this.drawSubjoin(offscreenCanvasContext);
      // drawGrid(offscreenCanvasContext, that);
      // drawSeparateLine(offscreenCanvasContext, that);
      this[objIdArr].forEach((v) => {
        if (objId && v == this.selected_obj_id) {
          return false;
        }
        // console.log('draw all and grid');
        this.drawObj(offscreenCanvasContext, v);
      });
    }
    return offscreenCanvas;
  }
/**
 * ç§»åŠ¨çš„å°çƒ è¡¨ç¤ºæµå‘çš„
 */
  moveBall (opts, count, ballNum) {
    ballNum = ballNum || 1;
    // console.log(opts, count, ballNum);
    let points = opts.points;
    let step = 0;
    let delta = 0;
    opts.fillStyle = opts.fillStyle || '#fff';
    let point0, point1, point2, point3;
    let pointMax, pointMin;
    // åˆ†æ®µåŽ å–一段的长度
    let pointLen;
    switch (opts.direction) {
      // å‘上
      case 'top':
        point3 = points[3] > points[1] ? points[3] : points[1];
        point1 = points[3] > points[1] ? points[1] : points[3];
        pointLen = Math.round((point3 - point1) / ballNum);
        for (let i = 0; i < ballNum; i++) {
          pointMax = point3 - pointLen * i;
          pointMin = point3 - pointLen * (i + 1);
          if (i == ballNum - 1) {
            pointMin = point1;
          }
          step = (pointMax - pointMin) / this.COUNT;
          delta = pointMax;
          delta -= step * count;
          if (delta < pointMin) {
            delta = pointMax;
          }
          this.drawPoint(this.context, {
            x: points[2],
            y: delta,
            fillStyle: opts.fillStyle,
            r: 6
          });
        }
        // this.draw
        break;
      // å‘下
      case 'bottom':
      // debugger;
        point3 = points[3] > points[1] ? points[3] : points[1];
        point1 = points[3] > points[1] ? points[1] : points[3];
        pointLen = Math.round((point3 - point1) / ballNum);
        for (let i = 0; i < ballNum; i++) {
          pointMax = point3 - pointLen * i;
          pointMin = point3 - pointLen * (i + 1);
          if (i == ballNum - 1) {
            pointMin = point1;
          }
          step = (pointMax - pointMin) / this.COUNT;
          delta = pointMin;
          delta += step * count;
          if (delta > pointMax) {
            delta = pointMin;
          }
          this.drawPoint(this.context, {
            x: points[2],
            y: delta,
            fillStyle: opts.fillStyle,
            r: 6
          });
        }
        break;
      // å‘å·¦
      case 'left':
        point2 = points[2] > points[0] ? points[2] : points[0];
        point0 = points[2] > points[0] ? points[0] : points[2];
        pointLen = Math.round((point2 - point0) / ballNum);
        for (let i = 0; i < ballNum; i++) {
          pointMax = point2 - pointLen * i;
          pointMin = point2 - pointLen * (i + 1);
          if (i == ballNum - 1) {
            pointMin = point0;
          }
          step = (pointMax - pointMin) / this.COUNT;
          delta = pointMax;
          delta -= step * count;
          if (delta < pointMin) {
            delta = pointMax;
          }
          this.drawPoint(this.context, {
            x: delta,
            y: points[1],
            fillStyle: opts.fillStyle,
            r: 6
          });
        }
        // step = (point2 - point0) / this.COUNT;
        // delta = point2;
        // delta -= step * count;
        // if (delta < point0) {
        //   delta = point2;
        // }
        // this.drawPoint(this.context, {
        //   x: delta,
        //   y: points[1],
        //   fillStyle: opts.fillStyle,
        //   r: 6
        // });
        break;
      // å‘右
      case 'right':
        point2 = points[2] > points[0] ? points[2] : points[0];
        point0 = points[2] > points[0] ? points[0] : points[2];
        pointLen = Math.round((point2 - point0) / ballNum);
        for (let i = 0; i < ballNum; i++) {
          pointMax = point2 - pointLen * i;
          pointMin = point2 - pointLen * (i + 1);
          if (i == ballNum - 1) {
            pointMin = point0;
          }
          step = (pointMax - pointMin) / this.COUNT;
          delta = pointMin;
          delta += step * count;
          if (delta > pointMax) {
            delta = pointMin;
          }
          this.drawPoint(this.context, {
            x: delta,
            y: points[1],
            fillStyle: opts.fillStyle,
            r: 6
          });
        }
        break;
    }
  }
  // ç”»äºŒæžç®¡
  drawDiode (ctx, opts) {
    let color = '#b370fe';
    let height = 20;
    ctx.save();
    ctx.fillStyle = color;
    ctx.lineWidth = 2;
    ctx.strokeStyle = color;
    ctx.translate(opts.x, opts.y);
    ctx.textAlign = 'right';
    ctx.textBaseline = 'bottom';
    ctx.font = '20px Arial'
    if (opts.name) {
      ctx.fillText(opts.name, 0, 0);
    }
    // æ°´å¹³æ–¹å‘的还是竖直方向的
    if (!opts.isHor) {
      ctx.rotate(-Math.PI / 2);
    }
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(0, height);
    ctx.lineTo(height / 2, height / 2);
    ctx.closePath();
    ctx.fill();
    ctx.beginPath();
    ctx.moveTo(height / 2, 0);
    ctx.lineTo(height / 2, height);
    ctx.stroke();
    ctx.closePath();
    ctx.restore();
  }
  drawRect (ctx, opts) {
    ctx.save();
    ctx.translate(opts.x, opts.y);
    ctx.strokeStyle = opts.strokeStyle || 'transparent';
    ctx.lineWidth = opts.lineWidth || this.lineWidth;
    ctx.beginPath();
    ctx.rect(0, 0, opts.width, opts.height);
    ctx.closePath();
    ctx.stroke();
    ctx.restore();
  }
  // ç”»ç”µé˜»
  drawResistance (ctx, opts) {
    let width = 60;
    let height = 10;
    ctx.save();
    ctx.textAlign = 'start';
    ctx.strokeStyle = opts.color || this.strokeStyle;
    ctx.fillStyle = '#fff';
    ctx.font = '16px Arial';
    ctx.translate(opts.x, opts.y);
    ctx.beginPath();
    if (opts.isHor) {
      ctx.rect(0, 0, width, height);
      if (opts.name) {
        ctx.textBaseline = 'bottom';
        ctx.fillText(opts.name, 0, - 8);
      }
    } else {
      ctx.rect(0, 0, height, width);
      if (opts.name) {
        ctx.textBaseline = 'top';
        ctx.fillText(opts.name, height + 8, 0);
      }
    }
    ctx.closePath();
    ctx.stroke();
    ctx.restore();
  }
  // ç”»ç”µæ„Ÿ
  drawInductance (ctx, opts) {
    let r = 6;
    ctx.save();
    ctx.fillStyle = '#fff';
    ctx.strokeStyle = opts.color;
    ctx.translate(opts.x, opts.y);
    for (let i = 0, j = 4; i < j; i++) {
      let x = r * 2 * i + r;
      ctx.beginPath();
      ctx.arc(x, 0, r, Math.PI, 2 * Math.PI);
      ctx.stroke();
      ctx.closePath();
    }
    ctx.beginPath();
    ctx.moveTo(0, - r - 4);
    ctx.lineTo(8 * r, - r - 4);
    ctx.moveTo(0, - r - 10);
    ctx.lineTo(8 * r, - r - 10);
    ctx.stroke();
    ctx.closePath();
    if (opts.name) {
      ctx.textAlign = 'start';
      ctx.textBaseline = 'bottom';
      ctx.font = '16px Arial';
      ctx.fillText(opts.name, 0, -r -16);
    }
    ctx.restore();
  }
  // ç”»æ•´æµå™¨
  drawRectifier (ctx, opts) {
    this.drawDevImg(ctx, opts);
    ctx.save();
    ctx.translate(opts.x, opts.y);
    // ctx.fillText(opts.name, 0, 0);
    ctx.font = '16px Arial';
    ctx.textAlign = 'start';
    ctx.fillStyle = '#fff';
    let arr = opts.name.split('');
    // ä¸­å¿ƒåœ¨Y轴上基数
    let center = (arr.length - 1) / 2;
    arr.forEach((v, i) => {
      ctx.fillText(v, opts.width + 6, opts.height / 2 + (i - center) * 20 + 6);
    });
    ctx.restore();
  }
  // ç”»ç”µæ± ç»„
  drawBatts (ctx, opts) {
    this.drawDevImg(ctx, opts);
    ctx.save();
    ctx.translate(0, opts.height + opts.distance);
    this.drawDevImg(ctx, opts);
    ctx.restore();
    ctx.save();
    ctx.translate(opts.x, opts.y);
    ctx.font = '16px Arial';
    ctx.textAlign = 'start';
    ctx.fillStyle = '#fff';
    let arr = opts.name.split('');
    // ä¸­å¿ƒåœ¨Y轴上基数
    let center = (arr.length - 1) / 2;
    arr.forEach((v, i) => {
      ctx.fillText(v, opts.width + 6, opts.height + opts.distance / 2 + (i - center) * 20 + 6);
    });
    this.drawDashLine(ctx, {
      color: '#00f7f9'
      ,lineWidth: 4
      ,points: [[opts.width / 2, opts.height], [opts.width / 2, opts.height + opts.distance]]
    });
    ctx.restore();
  }
  // ç”»è´Ÿè½½
  drawLoad (ctx, opts) {
    this.drawDevImg(ctx, opts);
    ctx.save();
    ctx.translate(opts.x, opts.y);
    ctx.font = '16px Arial';
    ctx.textAlign = 'start';
    ctx.fillStyle = '#fff';
    let arr = opts.name.split('');
    // ä¸­å¿ƒåœ¨Y轴上基数
    let center = (arr.length - 1) / 2;
    arr.forEach((v, i) => {
      ctx.fillText(v, opts.width + 6, opts.height / 2 + (i - center) * 20 + 6);
    });
    ctx.restore();
  }
  // ç»˜åˆ¶å…¨éƒ¨å¯¹è±¡
  drawAll () {
    let offscreenCanvas = document.createElement('canvas');
    let offscreenCanvasContext = offscreenCanvas.getContext('2d');
    offscreenCanvas.width = this.width;
    offscreenCanvas.height = this.height;
    this.drawSubjoin(offscreenCanvasContext);
    this[objIdArr].forEach((v) => {
      this.drawObj(offscreenCanvasContext, v);
    });
    let can = this.canvas;
    let context = this.context;
    context.clearRect(0, 0, can.width, can.height);
    // æ“é™¤ç”»å¸ƒ ä»Žç¼“存中取离屏canvas é‡ç»˜
    context.drawImage(offscreenCanvas, 0, 0, can.width, can.height);
  }
  // ç»˜åˆ¶é™„加元素
  drawSubjoin (ctx) {
    // if (this.drawGrid) {
    //   this.drawGrid(ctx);
    // }
    // if (this.drawSeparateLine) {
    //   this.drawSeparateLine(ctx);
    // }
  }
  drawGrid (ctx) {
    // å¯ä»¥ç”¨ç¦»å±canvas优化
    let canvasW = this.width;
    let canvasH = this.height;
    let width = this.gridWidth;
    ctx.save();
    ctx.lineWidth = 1;
    ctx.strokeStyle = '#999';
    // ç”»æ¨ªçº¿
    for (let i = 0, j = canvasH; i <= j; i += width) {
      ctx.beginPath();
      ctx.moveTo(0, i);
      ctx.lineTo(canvasW, i);
      ctx.stroke();
      ctx.closePath();
    }
    // ç”»ç«–线
    for (let i = 0, j = canvasW; i <= j; i += width) {
      ctx.beginPath();
      ctx.moveTo(i, 0);
      ctx.lineTo(i, canvasH);
      ctx.stroke();
      ctx.closePath();
    }
    ctx.restore();
  }
  // ç”»è®¾å¤‡å›¾ç‰‡
  draw_Dev (opts, whetherAdd) {
    whetherAdd = whetherAdd === undefined || !!whetherAdd;
    let {
      context
      ,img
      ,type
      ,x
      ,y
      ,width
      ,height
    } = opts;
    let ratio = this.ratio;
    x = Math.round(x / ratio);
    y = Math.round(y / ratio);
    // img.crossOrigin = '';
    // console.log(obj, '-=-=');
    if (img.complete) {
      context.drawImage(img, x, y, width, height);
    } else {
      img.addEventListener('load', () => {
        context.drawImage(img, x, y, width, height);
      });
    }
    let periphery = this.getPeripheryPoints(img, width, height);
    let options = {
      type: type
      ,src: img.src
      ,points: []
      ,width: width
      ,height: height
      ,x: x
      ,y: y
      ,center: [x + width / 2, y + height / 2]
      ,periphery
      ,method: 'drawDevImg'
    };
    whetherAdd && this[addToObj](type, options);
  }
  // èŽ·å–panel定位数据
  getPanelPos (subName, count) {
    let res = [];
    let list = this[objList];
    let name_pre = 'rect_' + subName + '_';
    for (let i = 0; i < count; i++) {
      let name = name_pre + i;
      console.log(list, name);
      res.push(list[name]);
    }
    return res;
  }
  drawSwitch1 (ctx, opts) {
    // this.resetPosition(opts);
    ctx.save();
    ctx.lineWidth = this.lineWidth;
    ctx.strokeStyle = this.strokeStyle;
    ctx.fillStyle = this.fillStyle;
    ctx.fillStyle = '#fff';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.font = '14px Arial';
    ctx.translate(opts.x, opts.y);
    ctx.beginPath();
    ctx.arc(0, 0, opts.r, 0, Math.PI * 2);
    ctx.fill();
    ctx.closePath();
    ctx.beginPath();
    ctx.arc(opts.distance, 0, opts.r, 0, Math.PI * 2);
    ctx.fill();
    ctx.closePath();
    ctx.save();
    if (opts.isOn) {
      ctx.rotate(-3 * Math.PI / 180);
    } else {
      ctx.rotate(-30 * Math.PI / 180);
    }
    ctx.lineWidth = this.lineWidth;
    ctx.strokeStyle = this.strokeStyle;
    ctx.globalCompositeOperation = 'destination-over';
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(opts.distance, 0);
    ctx.stroke();
    ctx.closePath();
    ctx.restore();
    // æ–‡å­—
    ctx.fillText(opts.txt, opts.distance / 2, - Math.tan(36 * Math.PI / 180) * opts.distance);
    ctx.globalCompositeOperation = 'destination-over';
    if (opts.block) {
      if (opts.blockLeft) {
        ctx.moveTo(0, 0);
        ctx.lineTo(- 20 - opts.blockWidth, 0);
        ctx.rect(- 20 - opts.blockWidth, - opts.blockHeight / 2, opts.blockWidth, opts.blockHeight);
      } else {
        ctx.moveTo(opts.distance, 0);
        ctx.lineTo(opts.distance + 20 + opts.blockWidth, 0);
        ctx.rect(opts.distance + 20, - opts.blockHeight / 2, opts.blockWidth, opts.blockHeight);
      }
      ctx.stroke();
      ctx.closePath();
    }
    ctx.restore();
  }
  // ç”»å¼€å…³
  draw_Switch_1 (opts, whetherAdd) {
    whetherAdd = whetherAdd == undefined || !!whetherAdd;
    let type = 'switch1';
    let {
      context
      ,x
      ,y
      ,txt
      ,isOn
      // æ˜¯å¦å¸¦å°æ–¹å—
      ,block
      ,blockLeft
    } = opts;
    let r = 3;
    let distance = 20;
    let blockWidth = 10;
    let blockHeight = 8;
    context.save();
    context.fillStyle = '#fff';
    context.textAlign = 'center';
    context.textBaseline = 'middle';
    context.font = '14px Arial';
    context.translate(x, y);
    context.beginPath();
    context.arc(0, 0, r, 0, Math.PI * 2);
    context.fill();
    context.closePath();
    context.beginPath();
    context.arc(distance, 0, r, 0, Math.PI * 2);
    context.fill();
    context.closePath();
    context.save();
    if (isOn) {
      context.rotate(-3 * Math.PI / 180);
    } else {
      context.rotate(-30 * Math.PI / 180);
    }
    context.lineWidth = this.lineWidth;
    context.strokeStyle = this.strokeStyle;
    context.globalCompositeOperation = 'destination-over';
    context.beginPath();
    context.moveTo(0, 0);
    context.lineTo(distance, 0);
    context.stroke();
    context.closePath();
    context.restore();
    // æ–‡å­—
    context.fillText(txt, distance / 2, - Math.tan(36 * Math.PI / 180) * distance);
    context.globalCompositeOperation = 'destination-over';
    if (block) {
      if (blockLeft) {
        context.moveTo(0, 0);
        context.lineTo(- 20 - blockWidth, 0);
        context.rect(- 20 - blockWidth, - blockHeight / 2, blockWidth, blockHeight);
      } else {
        context.moveTo(distance, 0);
        context.lineTo(distance + 20 + blockWidth, 0);
        context.rect(distance + 20, - blockHeight / 2, blockWidth, blockHeight);
      }
      context.stroke();
      context.closePath();
    }
    context.restore();
    let periphery = {
      point_left: [0, 0]
      ,point_right: [distance, 0]
      // è¿™ä¸ªæ±½å‘只有左右连接 ä¸Šä¸‹çš„点可以不用
      ,point_top: [-1, -1]
      ,point_bottom: [-1, -1]
    }
    let options = {
      type: type
      ,x: x
      ,y: y
      ,r
      ,txt
      ,isOn
      // æ˜¯å¦å¸¦å°æ–¹å—
      ,block
      ,blockLeft
      ,distance
      ,blockWidth
      ,blockHeight
      // ,name: name
      ,center: [x + distance / 2, y]
      ,periphery
      ,method: 'drawSwitch1'
    };
    whetherAdd && this[addToObj](type, options);
  }
  draw_switch (opts, whetherAdd) {
    whetherAdd = whetherAdd == undefined || !!whetherAdd;
    let type = 'switch';
    let context = this.context;
    this.drawSwitch(context, opts);
    let options = Object.assign({}, opts, {
      type
      ,method: 'drawSwitch'
    });
    whetherAdd && this[addToObj](type, options);
  }
  drawTitle (ctx, opts) {
    ctx.save();
    ctx.beginPath();
    ctx.translate(this.width / 2, 6);
    ctx.textAlign = 'center';
    ctx.textBaseline = 'top';
    ctx.font = '24px Arial';
    ctx.fillStyle = opts.color || '#fff';
    ctx.fillText(opts.title, 0, 0);
    ctx.closePath();
    ctx.restore();
  }
  // ç”»çŸ©å½¢å ä½æ¡†
  drawRect1 (opts, whetherAdd) {
    whetherAdd = whetherAdd == undefined || !!whetherAdd;
    let type = 'rect';
    let {
      x
      ,y
      ,width
      ,height
      ,subName
      ,color
    } = opts;
    if (subName) {
      type += '_' + subName;
    }
    let context = this.context;
    context.save();
    context.translate(x, y);
    context.beginPath();
    context.lineWidth = 1;
    context.strokeStyle = color || this.strokeStyle;
    context.strokeRect(0, 0, width, height);
    context.closePath();
    context.restore();
    let options = {
      method: 'drawRect'
      ,x
      ,y
      ,strokeStyle: color
      ,lineWidth: opts.lineWidth
      ,tlPoint: {
        x: x
        ,y: y
      }
      ,trPoint: {
        x: x + width
        ,y: y
      }
      ,brPoint: {
        x: x + width
        ,y: y + height
      }
      ,blPoint: {
        x: x
        ,y: y + height
      }
      ,top: y
      ,left: x
      ,right: x + width
      ,bottom: y + height
      ,width: width
      ,height: height
    }
    whetherAdd && this[addToObj](type, options);
  }
}
src/components/diagram/js/json.js
New file
@@ -0,0 +1 @@
export default {"width":1050,"height":800,"data":{"power_0":{"type":"power","src":"http://localhost:9090/dragdemo/img/cgj.6b79ac54.png","points":[],"width":100,"height":90,"x":50,"y":105,"center":[100,150],"periphery":{"point_left":[5,45],"point_top":[50,8],"point_right":[99,45],"point_bottom":[50,83]},"method":"drawDevImg","id":"power_0"},"power_1":{"type":"power","src":"http://localhost:9090/dragdemo/img/clx.f73c4e0d.png","points":[],"width":88,"height":90,"x":156,"y":305,"center":[200,350],"periphery":{"point_left":[1,45],"point_top":[44,0],"point_right":[87,45],"point_bottom":[44,89]},"method":"drawDevImg","id":"power_1"},"power_2":{"type":"power","src":"http://localhost:9090/dragdemo/img/czt.65e41f78.png","points":[],"width":60,"height":90,"x":20,"y":555,"center":[50,600],"periphery":{"point_left":[0,45],"point_top":[30,0],"point_right":[59,45],"point_bottom":[30,89]},"method":"drawDevImg","id":"power_2"},"load_0":{"type":"load","src":"http://localhost:9090/dragdemo/img/tbdj.812f40c1.png","points":[],"width":114,"height":90,"x":793,"y":155,"center":[850,200],"periphery":{"point_left":[6,45],"point_top":[57,15],"point_right":[113,45],"point_bottom":[57,85]},"method":"drawDevImg","id":"load_0"},"load_1":{"type":"load","src":"http://localhost:9090/dragdemo/img/gsz.3b4dfa80.png","points":[],"width":80,"height":90,"x":960,"y":355,"center":[1000,400],"periphery":{"point_left":[0,45],"point_top":[40,0],"point_right":[79,45],"point_bottom":[40,89]},"method":"drawDevImg","id":"load_1"},"load_2":{"type":"load","src":"http://localhost:9090/dragdemo/img/zdcsxt.7692b31e.png","points":[],"width":60,"height":90,"x":820,"y":605,"center":[850,650],"periphery":{"point_left":[2,45],"point_top":[30,0],"point_right":[58,45],"point_bottom":[30,89]},"method":"drawDevImg","id":"load_2"},"line1_0":{"type":"line","points":[[149,150],[350,150]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_0"},"line1_1":{"type":"line","points":[[193,350],[350,350]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_1"},"line1_2":{"type":"line","points":[[79,600],[350,600]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_2"},"line1_3":{"type":"line","points":[[700,200],[799,200]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_3"},"line1_4":{"type":"line","points":[[700,400],[960,400]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_4"},"line1_5":{"type":"line","points":[[700,650],[822,650]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_5"},"switch_0":{"type":"switch","height":80,"isOn":false,"method":"drawSwitch","r":6,"x":350,"y":464,"id":"switch_0"},"switch_1":{"type":"switch","height":80,"isOn":false,"clickAble":true,"method":"drawSwitch","r":6,"x":700,"y":492,"id":"switch_1"},"test_0":{"type":"test","width":90,"height":60,"x":505,"y":220,"name":"参试设备","center":[550,250],"method":"drawTest","periphery":{"point_left":[0,30],"point_right":[90,30],"point_top":[45,0],"point_bottom":[45,60]},"id":"test_0"},"test_1":{"type":"test","width":90,"height":60,"x":505,"y":620,"name":"参试设备","center":[550,650],"method":"drawTest","periphery":{"point_left":[0,30],"point_right":[90,30],"point_top":[45,0],"point_bottom":[45,60]},"id":"test_1"},"line2_0":{"type":"line","points":[[550,280],[550,620]],"center":[550,"*"],"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line2_0"},"line1_6":{"type":"line","points":[[350,250],[505,250]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_6"},"line1_7":{"type":"line","points":[[350,650],[505,650]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_7"},"line1_8":{"type":"line","points":[[595,250],[700,250]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_8"},"line1_9":{"type":"line","points":[[595,650],[700,650]],"center":null,"method":"drawLine","dragLinePoints":[],"dragLineDirection":null,"dragLinePosition":null,"id":"line1_9"}}}
src/pages/dataTest/components/activateDialogContent.vue
@@ -69,14 +69,14 @@
                                    <el-input v-model.number="params.CharSotpCurr"></el-input>
                                </el-form-item>
                            </div>
                            <div class="table-cell pr16">
                            <!-- <div class="table-cell pr16">
                                <el-form-item label="充电容量(AH)" prop="CharCap">
                                    <el-input v-model.number="params.CharCap"></el-input>
                                </el-form-item>
                            </div>
                            </div> -->
                            <div class="table-cell pr16">
                                <el-form-item label="单体上限(V)" prop="MonVolHightLimit">
                                    <el-input v-model.number="params.MonVolHightLimit"></el-input>
                                    <el-input v-model="params.MonVolHightLimit"></el-input>
                                </el-form-item>
                            </div>
                            <div class="table-cell">
@@ -99,6 +99,52 @@
                            <div class="table-cell pr16">
                                <el-form-item label="浮充时长(分钟)" prop="FloatCharTimeLong">
                                    <el-input v-model.number="params.FloatCharTimeLong"></el-input>
                                </el-form-item>
                            </div>
                        </div>
                        <div class="table-row">
                            <div class="table-cell pr16">
                                <el-form-item label="恒流总阶段数" prop="FlowOver_Count">
                                    <el-select v-model="params.FlowOver_Count" placeholder="请选择">
                                        <el-option
                                            v-for="item in flowOverCount" :key="item"
                                            :label="item"
                                            :value="item"></el-option>
                                    </el-select>
                                </el-form-item>
                            </div>
                            <div class="table-cell pr16">
                                <el-form-item label="恒流1阶段充电电流" prop="FlowOver_CharCurr_1">
                                    <el-input v-model.number="params.FlowOver_CharCurr_1"></el-input>
                                </el-form-item>
                            </div>
                            <div class="table-cell pr16">
                                <el-form-item label="恒流2阶段充电电流" prop="FlowOver_CharCurr_2">
                                    <el-input v-model.number="params.FlowOver_CharCurr_2"></el-input>
                                </el-form-item>
                            </div>
                            <div class="table-cell">
                                <el-form-item label="恒流3阶段充电电流" prop="FlowOver_CharCurr_3">
                                    <el-input v-model.number="params.FlowOver_CharCurr_3"></el-input>
                                </el-form-item>
                            </div>
                        </div>
                        <div class="table-row">
                            <div class="table-cell pr16">
                            </div>
                            <div class="table-cell pr16">
                                <el-form-item label="恒流1阶段充电时长" prop="FlowOver_CharTime_1">
                                    <el-input v-model.number="params.FlowOver_CharTime_1"></el-input>
                                </el-form-item>
                            </div>
                            <div class="table-cell pr16">
                                <el-form-item label="恒流2阶段充电时长" prop="FlowOver_CharTime_2">
                                    <el-input v-model.number="params.FlowOver_CharTime_2"></el-input>
                                </el-form-item>
                            </div>
                            <div class="table-cell">
                                <el-form-item label="恒流3阶段充电时长" prop="FlowOver_CharTime_3">
                                    <el-input v-model.number="params.FlowOver_CharTime_3"></el-input>
                                </el-form-item>
                            </div>
                        </div>
@@ -146,12 +192,12 @@
                        <div class="table-row">
                            <div class="table-cell pr16">
                                <el-form-item label="放电阻值(mΩ)" prop="DisPreRes">
                                    <el-input v-model.number="params.DisPreRes"></el-input>
                                    <el-input v-model="params.DisPreRes"></el-input>
                                </el-form-item>
                            </div>
                            <div class="table-cell pr16">
                                <el-form-item label="预放功率(KW)" prop="DisPower">
                                    <el-input v-model.number="params.DisPower"></el-input>
                                    <el-input v-model="params.DisPower"></el-input>
                                </el-form-item>
                            </div>
                            <div class="table-cell pr16">
@@ -278,6 +324,7 @@
        return {
            setFaceShow: false,
            startFaceShow: false,
            flowOverCount: const_aio.flowOverCount,
            cmd: cmd,               // æ“ä½œå‘½ä»¤
            startTestFlag: false,   // å¯åŠ¨æµ‹è¯•çš„çŠ¶æ€
            setTestFlag: false,     // è®¾ç½®å‚数的状态
@@ -288,7 +335,7 @@
            params: {
                AutoTestStartVol: 0,    //浮充电压(V)
                BattGroupNum: 0,        //电池组编号
                CharCap: 0,             //充电容量(AH)
                CharCap: 0,             //充电容量(AH)(不显示)
                CharHighTmp: 0,         //充电过温
                CharSotpCurr: 0,        //截止电流
                CharTimeLong: 0,        //充电时长
@@ -314,6 +361,13 @@
                OffLineYHOnceCycle: 1,  //活化起点
                OffLineYHTimes: 1,      //活化次数
                OffLineYH_Cycle: 0,     //电池组标称容量
                FlowOver_Count: 1,      //恒流总阶段数
                FlowOver_CharCurr_1: 0,//恒流1阶段充电电流
                FlowOver_CharCurr_2: 0,//恒流2阶段充电电流
                FlowOver_CharCurr_3: 0,//恒流3阶段充电电流
                FlowOver_CharTime_1: 0,    //恒流3阶段充电时长
                FlowOver_CharTime_2: 0,    //恒流3阶段充电时长
                FlowOver_CharTime_3: 0,    //恒流3阶段充电时长
                OffLineYHstarttime: "2000-01-01 00:00:00",//养护开始时间
                OnLineVol_Low: 0,       //充电电压
                OnlineLowAction: 0,     //测试类型 0:恒电流,1:恒功率,2:恒电阻
@@ -343,12 +397,12 @@
                    },
                    trigger: 'change'
                }],
                CharCap: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.CharCap)
                    },
                    trigger: 'change'
                }],
                // CharCap: [{
                //     validator(rule, value, callback) {
                //         testVal(rule, value, callback, rules.CharCap)
                //     },
                //     trigger: 'change'
                // }],
                CharHighTmp: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.CharHighTmp)
@@ -415,12 +469,12 @@
                    },
                    trigger: 'change'
                }],
                FloatCharTimeLong: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.FloatCharTimeLong)
                    },
                    trigger: 'change'
                }],
                // FloatCharTimeLong: [{
                //     validator(rule, value, callback) {
                //         testVal(rule, value, callback, rules.FloatCharTimeLong)
                //     },
                //     trigger: 'change'
                // }],
                GroupVol_Low: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.GroupVol_Low)
@@ -504,6 +558,13 @@
                OffLineYHOnceCycle: 1,  //活化起点
                OffLineYHTimes: 1,      //活化次数
                OffLineYH_Cycle: 0,     //电池组标称容量
                FlowOver_Count: 1,      //恒流总阶段数
                FlowOver_CharCurr_1: 0,//恒流1阶段充电电流
                FlowOver_CharCurr_2: 0,//恒流2阶段充电电流
                FlowOver_CharCurr_3: 0,//恒流3阶段充电电流
                FlowOver_CharTime_1: 0,    //恒流3阶段充电时长
                FlowOver_CharTime_2: 0,    //恒流3阶段充电时长
                FlowOver_CharTime_3: 0,    //恒流3阶段充电时长
                OffLineYHstarttime: "2000-01-01 00:00:00",//养护开始时间
                OnLineVol_Low: 0,       //充电电压
                OnlineLowAction: 0,     //测试类型 0:恒电流,1:恒功率,2:恒电阻
@@ -545,11 +606,11 @@
            // æŸ¥è¯¢åŽå°
            this.$apis.aio.realtime.getParams({
                dev_id: '618500001' || this.batt.FBSDeviceId
                dev_id: this.batt.FBSDeviceId
                ,op_cmd: const_aio.cmd.getParams
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                console.log(rs, '-------=====');
                console.log('00000', rs, '-------=====');
                // debugger;
                if(rs.code == 1) {
                    let fsparam = rs.data[0];
@@ -608,7 +669,7 @@
        setParams() {
            // ç­‰å¾…框
            let loading = this.$layer.loading(1);
            this.params.dev_id = 618500001;
            // this.params.dev_id = 618500001;
            // è¯·æ±‚后台
            this.$apis.aio.realtime.setParams(this.params).then(res => {
                let rs = JSON.parse(res.data.result);
src/pages/dataTest/components/chargeDialogContent.vue
New file
@@ -0,0 +1,452 @@
<template>
    <div class="params-container">
        <el-form
            ref="ruleForm"
            size="mini"
            label-position="top"
            :model="params"
            :rules="rules"
            class="params-dialog">
            <el-form-item label="电池组名称">
                <el-input v-model="otherParams.groupName" readonly></el-input>
            </el-form-item>
            <div class="table-layout">
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="设备ID">
                            <el-input v-model="otherParams.FBSDeviceId" readonly></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell">
                        <el-form-item label="电池组信息">
                            <el-input v-model="otherParams.groupInfo" readonly></el-input>
                        </el-form-item>
                    </div>
                </div>
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="电池组编号">
                            <el-input v-model="otherParams.GroupIndexInFBSDevice" readonly></el-input>
                        </el-form-item>
                    </div>
                </div>
            </div>
            <div class="table-layout">
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="充电电压(V)" prop="DisCurr">
                            <el-input v-model="params.DisCurr"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell pr16">
                        <el-form-item label="充电电流(A)">
                            <el-input v-model="params.HourRate"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell">
                        <el-form-item label="浮充电压(V)" prop="DisCap">
                            <el-input v-model="params.DisCap"></el-input>
                        </el-form-item>
                    </div>
                </div>
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="浮充电流(A)" prop="DisCap">
                            <el-input v-model="params.DisCap"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell pr16">
                        <el-form-item label="充电容量(AH)" prop="DisTime">
                            <el-input v-model="params.DisTime"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell">
                        <el-form-item label="单体上限(V)" prop="MonomerVol_Low">
                            <el-input v-model="params.MonomerVol_Low"></el-input>
                        </el-form-item>
                    </div>
                </div>
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="上限个数(个)" prop="GroupVol_Low">
                            <el-input v-model="params.GroupVol_Low"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell pr16">
                        <el-form-item label="均充时长(分钟)" prop="MonomerLowCount">
                            <el-input v-model="params.MonomerLowCount"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell">
                        <el-form-item label="浮充时长(分钟)">
                            <el-input v-model="params.DCVolHighLimit"></el-input>
                        </el-form-item>
                    </div>
                </div>
            </div>
            <div class="form-footer">
                <!-- <three-btn>清除告警</three-btn> -->
                <three-btn :disabled="!startTestFlag" @click="startTestCheck">启动充电</three-btn>
                <three-btn @click="getParams(true)">读取</three-btn>
                <three-btn :disabled="!setTestFlag" @click="submitFrom">设定</three-btn>
            </div>
        </el-form>
    </div>
</template>
<script>
import {
    testVal
} from "@/assets/js/tools";
import {
    const_aio
} from "@/assets/js/const"
import config from "@/assets/js/config";
// import checkFace from "@/components/checkFace";
export default {
    name: "dischargeParams",
    components: {
        // checkFace
    },
    props: {
        batt: {
            type: Object,
            default() {
                return {}
            }
        }
    },
    data() {
        let cmd = const_aio.cmd;
        let testType = const_aio.testType;
        let rules = const_aio.dischargeRules;
        let batt = this.batt;
        // ä¿®æ”¹ç»„端下限的取值范围
        rules.GroupVol_Low.min = (batt.MonCount*batt.MonVolStd*0.875).toHold(1);
        rules.GroupVol_Low.max = (batt.MonCount*batt.MonVolStd*1.125).toHold(1);
        rules.GroupVol_Low.msg = "取值范围"+rules.GroupVol_Low.min+"~"+rules.GroupVol_Low.max+"(保留一位小数)";
        // ä¿®æ”¹ç”µæ± å•体下限的取值范围
        rules.MonomerVol_Low.min = (batt.MonVolStd*0.9).toHold(1);
        rules.MonomerVol_Low.max = (batt.MonVolStd*1.2).toHold(1);
        rules.MonomerVol_Low.msg = "取值范围"+rules.MonomerVol_Low.min+"~"+rules.MonomerVol_Low.max+"(保留一位小数)";
        return {
            setFaceShow: false,
            startFaceShow: false,
            cmd: cmd,               // æ“ä½œå‘½ä»¤
            startTestFlag: false,   // å¯åŠ¨æµ‹è¯•çš„çŠ¶æ€
            setTestFlag: false,     // è®¾ç½®å‚数的状态
            testType: testType,     // æµ‹è¯•类型
            params: {
                num: 0,             //命令
                dev_id: 0,          //设备id
                BattGroupNum: 0,    //电池组编号
                DisCurr: 0,         //放电电流
                DisCap: 0,          //放电容量
                DisTime: 0,         //放电时长
                GroupVol_Low: 0,    //组端下限阀值
                HourRate: 0,        //放电小时率
                MonomerLowCount: 0, //单体下限数量
                MonomerVol_Low: 0,  //单体下限阀值
                OnlineLowAction: 0, //在线电压低处理
                TestCmd: 37,         //测试类型
                ChargeCurrSet: 0,   //充电电流
                DCVolHighLimit: 0,  //升压上限
                MonomerTmp_High: 0  //温度上限
            },
            ranges: {
                GroupVol_Low: {
                    name: '组端电压下限',
                    unit: 'V',
                    min: rules.GroupVol_Low.min,
                    max: rules.GroupVol_Low.max
                },
                MonomerVol_Low: {
                    name: '单体电压下限',
                    unit: 'V',
                    min: rules.MonomerVol_Low.min,
                    max: rules.MonomerVol_Low.max
                }
            },
            rules: {
                DisCurr: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.DisCurr)
                    },
                    trigger: 'change'
                }],
                DisCap: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.DisCap)
                    },
                    trigger: 'change'
                }],
                DisTime: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.DisTime)
                    },
                    trigger: 'change'
                }],
                MonomerVol_Low: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.MonomerVol_Low)
                    },
                    trigger: 'change'
                }],
                GroupVol_Low: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.GroupVol_Low)
                    },
                    trigger: 'change'
                }],
            },
        }
    },
    methods: {
        initParams() {
            // åˆå§‹åŒ–参数
            this.params = {
                num: 0,             //命令
                dev_id: 0,          //设备id
                BattGroupNum: 0,    //电池组编号
                DisCurr: 0,         //放电电流
                DisCap: 0,          //放电容量
                DisTime: 0,         //放电时长
                GroupVol_Low: 0,    //组端下限阀值
                HourRate: 0,        //放电小时率
                MonomerLowCount: 0, //单体下限数量
                MonomerVol_Low: 0,  //单体下限阀值
                OnlineLowAction: 0, //在线电压低处理
                TestCmd: 37,         //测试类型
                ChargeCurrSet: 0,   //充电电流
                DCVolHighLimit: 0,  //升压上限
                MonomerTmp_High: 0  //温度上限
            };
        },
        // èŽ·å–å‚æ•°
        getParams(showLoad) {
            // å®šä¹‰ç­‰å¾…框
            let loading;
            if (showLoad) {
                loading = this.$layer.loading(1);
            }
            // å¯åŠ¨æŒ‰é’®ä¸å¯ç‚¹å‡»
            this.startTestFlag = false;
            // æŸ¥è¯¢åŽå°
            this.$apis.dischargeTest.bts.getParams({
                num: this.cmd.get,
                dev_id: this.batt.FBSDeviceId
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                if(rs.code == 1) {
                    let testType = this.testType;
                    let fsparam = rs.data[0].fsparam;
                    let isIn = this.checkValIsInObjects(fsparam.TestCmd, testType);
                    // éåŽ†å‚æ•°å±žæ€§å¹¶èµ‹å€¼
                    for (let key in this.params) {
                        if (key === "TestCmd" && !isIn) {
                            this.params.TestCmd = 37;
                        } else {
                            this.params[key] = fsparam[key];
                        }
                    }
                    // è®¾ç½®çš„命令和dev_id
                    this.params.num = this.cmd.set;
                    this.params.dev_id = this.batt.FBSDeviceId;
                    this.params.BattGroupNum = this.otherParams.GroupIndexInFBSDevice;
                    this.$layer.msg('读取成功!');
                    // è®¾ç½®æŒ‰é’®å¯ç‚¹å‡»
                    this.setTestFlag = true;
                }else {
                    // åˆå§‹åŒ–参数
                    this.initParams();
                    // è®¾ç½®æŒ‰é’®ä¸å¯ç‚¹å‡»
                    this.setTestFlag = false;
                    this.$layer.msg('读取失败!');
                }
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
            }).catch(error=>{
                console.log(error);
                // åˆå§‹åŒ–参数
                this.initParams();
                // è®¾ç½®æŒ‰é’®ä¸å¯ç‚¹å‡»
                this.setTestFlag = false;
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
                this.$layer.msg('读取失败,读取请求异常!');
            });
        },
        // æäº¤è¡¨å•设置参数
        submitFrom() {
            this.$refs.ruleForm.validate((valid) => {
                // æ ¡éªŒé€šè¿‡
                if (valid) {
                    // è®¾ç½®å‚æ•°
                    this.setParamsCheck();
                } else {
                    this.$layer.msg('存在校验未通过的数据!');
                    return false;
                }
            });
        },
        setParamsCheck() {
            if(config.dischargeByFace.value) {
                this.setFaceShow = true;
            }else {
                this.setParams(true);
            }
        },
        // è®¾ç½®å‚æ•°
        setParams() {
            // ç­‰å¾…框
            let loading = this.$layer.loading(1);
            // è¯·æ±‚后台
            this.$apis.dischargeTest.bts.setParams(this.params).then(res => {
                let rs = JSON.parse(res.data.result);
                if (rs.code == 1) {
                    // å¯åŠ¨æŒ‰é’®å¯ç‚¹å‡»
                    this.startTestFlag = true;
                    // æç¤ºä¿¡æ¯
                    this.$layer.msg('设置成功');
                } else {
                    // å¯åŠ¨æŒ‰é’®ä¸å¯ç‚¹å‡»
                    this.startTestFlag = false;
                    // æç¤ºä¿¡æ¯
                    this.$layer.msg('设置失败!');
                }
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
            }).catch(error => {
                console.log(error);
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
                // å¯åŠ¨æŒ‰é’®ä¸å¯ç‚¹å‡»
                this.startTestFlag = false;
                // æç¤ºä¿¡æ¯
                this.$layer.msg('设置失败,设置请求异常!');
            });
        },
        startTestCheck() {
            if(config.dischargeByFace.value) {
                this.startFaceShow = true;
            }else {
                this.confirmStartTest();
            }
        },
        // ç¡®è®¤æ¡†
        confirmStartTest() {
            this.$layer.prompt({title: '输入启动口令,并确认', formType: 2, area: ['300px', '180px']}, (pass, index) => {
                // è¯·æ±‚后台校验密码
                this.$apis.login.checkUserPwd(pass).then(res=>{
                    let rs = JSON.parse(res.data.result);
                    if(rs.code == 1) {
                        // å…³é—­å¼¹å‡ºæ¡†
                        this.$layer.close(index);
                        this.$layer.msg("密码检测通过,启动测试");
                        // å¯åŠ¨æµ‹è¯•
                        this.startTest();
                    }else {
                        this.$layer.msg("启动口令错误!");
                    }
                }).catch(error=>{
                    console.log(error);
                    this.$layer.msg("网络请求异常");
                });
            });
        },
        // å¯åЍ
        startTest() {
            // ç­‰å¾…框
            let loading = this.$layer.loading(1);
            // è¯·æ±‚后台
            this.$apis.dischargeTest.bts.start({
                num: this.cmd.start,
                dev_id: this.batt.FBSDeviceId,
                BattGroupNum: this.batt.GroupIndexInFBSDevice+1,
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                if (rs.code == 1) {
                    // æç¤ºä¿¡æ¯
                    this.$layer.msg('启动测试成功');
                } else {
                    // æç¤ºä¿¡æ¯
                    this.$layer.msg('启动测试失败!');
                }
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
            }).catch(error => {
                console.log(error);
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
                // æç¤ºä¿¡æ¯
                this.$layer.msg('启动测试失败,启动测试请求异常!');
            });
        },
        checkValIsInObjects(val, objects) {
            let rs = false;
            for(let i=0; i<objects.length; i++) {
                let obj = objects[i];
                if(obj.value === val) {
                    rs = true;
                    break;
                }
            }
            return false;
        },
        setFaceSuccess() {
            this.setFaceShow = false;
            this.setParams();
        },
        startFaceSuccess() {
            this.startFaceShow = false;
            this.startTest();
        },
    },
    computed: {
        otherParams() {
            let batt = this.batt;
            let groupInfo = '单体数量:' + this.batt.MonCount + ";电压(V):"
                + this.batt.MonVolStd + ";容量(AH):" + this.batt.MonCapStd;
            return {
                groupName: batt.StationName + "-" + batt.BattGroupName,
                FBSDeviceId: batt.FBSDeviceId,
                groupInfo: groupInfo,
                GroupIndexInFBSDevice: this.batt.GroupIndexInFBSDevice + 1,
            }
        },
        rangeLabel() {
            let ranges = this.ranges;
            let result = {};
            for(let key in ranges) {
                let item = ranges[key];
                result[key] = item.name+"("+item.min+"~"+item.max+item.unit+")";
            }
            return result;
        },
    },
    mounted() {
        // èŽ·å–æ•°æ®
        this.getParams(true);
    }
}
</script>
<style scoped>
.form-footer {
    margin-top: 16px;
    margin-bottom: 16px;
    text-align: right;
}
.form-footer .three-btn {
    margin-left: 12px;
}
.params-container {
    padding: 0.4rem;
    background-color: #ececec;
}
</style>
src/pages/dataTest/components/dischargeDialogContent.vue
New file
@@ -0,0 +1,476 @@
<template>
    <div class="params-container">
        <el-form
            ref="ruleForm"
            size="mini"
            label-position="top"
            :model="params"
            :rules="rules"
            class="params-dialog">
            <el-form-item label="电池组名称">
                <el-input v-model="otherParams.groupName" readonly></el-input>
            </el-form-item>
            <div class="table-layout">
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="设备ID">
                            <el-input v-model="otherParams.FBSDeviceId" readonly></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell">
                        <el-form-item label="电池组信息">
                            <el-input v-model="otherParams.groupInfo" readonly></el-input>
                        </el-form-item>
                    </div>
                </div>
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="电池组编号">
                            <el-input v-model="otherParams.GroupIndexInFBSDevice" readonly></el-input>
                        </el-form-item>
                    </div>
                </div>
            </div>
            <div class="table-layout">
                <div class="table-row">
                    <div class="table-cell">
                        <el-form-item label="放电模式">
                            <!-- æ’电流 åŠŸçŽ‡ ç”µé˜» -->
                            <el-select v-model="params.TestCmd" placeholder="请选择">
                                <el-option
                                    v-for="item in testType" :key="item.value"
                                    :label="item.label"
                                    :value="item.value"></el-option>
                            </el-select>
                        </el-form-item>
                    </div>
                    <div class="table-cell pr16">
                        <el-form-item label="预设电流(A)" prop="DisCurr">
                            <el-input v-model="params.DisCurr"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell pr16">
                        <el-form-item label="预设容量(AH)">
                            <el-input v-model="params.HourRate"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell">
                        <el-form-item label="放电阻值(mΩ)" prop="DisCap">
                            <el-input v-model="params.DisCap"></el-input>
                        </el-form-item>
                    </div>
                </div>
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="预放功率(KW)" prop="DisTime">
                            <el-input v-model="params.DisTime"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell pr16">
                        <el-form-item label="预放时间(分钟)" prop="MonomerVol_Low">
                            <el-input v-model="params.MonomerVol_Low"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell">
                        <el-form-item label="组端下限(V)" prop="GroupVol_Low">
                            <el-input v-model="params.GroupVol_Low"></el-input>
                        </el-form-item>
                    </div>
                </div>
                <div class="table-row">
                    <div class="table-cell pr16">
                        <el-form-item label="单体下限(V)" prop="GroupVol_Low">
                            <el-input v-model="params.GroupVol_Low"></el-input>
                        </el-form-item>
                    </div>
                    <div class="table-cell pr16">
                        <el-form-item label="单体下限数量(个)" prop="MonomerLowCount">
                            <el-input v-model="params.MonomerLowCount"></el-input>
                        </el-form-item>
                    </div>
                </div>
            </div>
            <div class="form-footer">
                <!-- <three-btn>清除告警</three-btn> -->
                <three-btn :disabled="!startTestFlag" @click="startTestCheck">启动放电</three-btn>
                <three-btn @click="getParams(true)">读取</three-btn>
                <three-btn :disabled="!setTestFlag" @click="submitFrom">设定</three-btn>
            </div>
            <!-- <el-dialog
                title="人脸校验" width="480px"
                :visible.sync="setFaceShow"
                :close-on-click-modal="false" top="0"
                :modal="false"
                class="dialog-center"
                :modal-append-to-body="false" :destroy-on-close="true">
                <check-face v-if="setFaceShow" @checkSuccess="setFaceSuccess"></check-face>
            </el-dialog>
            <el-dialog
                title="人脸校验" width="480px"
                :visible.sync="startFaceShow"
                :close-on-click-modal="false" top="0"
                :modal="false"
                class="dialog-center"
                :modal-append-to-body="false" :destroy-on-close="true">
                <check-face v-if="startFaceShow" @checkSuccess="startFaceSuccess"></check-face>
            </el-dialog> -->
        </el-form>
    </div>
</template>
<script>
import {
    testVal
} from "@/assets/js/tools";
import {
    const_aio
} from "@/assets/js/const"
import config from "@/assets/js/config";
// import checkFace from "@/components/checkFace";
export default {
    name: "dischargeParams",
    components: {
        // checkFace
    },
    props: {
        batt: {
            type: Object,
            default() {
                return {}
            }
        }
    },
    data() {
        let cmd = const_aio.cmd;
        let testType = const_aio.testType;
        let rules = const_aio.dischargeRules;
        let batt = this.batt;
        // ä¿®æ”¹ç»„端下限的取值范围
        rules.GroupVol_Low.min = (batt.MonCount*batt.MonVolStd*0.875).toHold(1);
        rules.GroupVol_Low.max = (batt.MonCount*batt.MonVolStd*1.125).toHold(1);
        rules.GroupVol_Low.msg = "取值范围"+rules.GroupVol_Low.min+"~"+rules.GroupVol_Low.max+"(保留一位小数)";
        // ä¿®æ”¹ç”µæ± å•体下限的取值范围
        rules.MonomerVol_Low.min = (batt.MonVolStd*0.9).toHold(1);
        rules.MonomerVol_Low.max = (batt.MonVolStd*1.2).toHold(1);
        rules.MonomerVol_Low.msg = "取值范围"+rules.MonomerVol_Low.min+"~"+rules.MonomerVol_Low.max+"(保留一位小数)";
        return {
            setFaceShow: false,
            startFaceShow: false,
            cmd: cmd,               // æ“ä½œå‘½ä»¤
            startTestFlag: false,   // å¯åŠ¨æµ‹è¯•çš„çŠ¶æ€
            setTestFlag: false,     // è®¾ç½®å‚数的状态
            testType: testType,     // æµ‹è¯•类型
            params: {
                num: 0,             //命令
                dev_id: 0,          //设备id
                BattGroupNum: 0,    //电池组编号
                DisCurr: 0,         //放电电流
                DisCap: 0,          //放电容量
                DisTime: 0,         //放电时长
                GroupVol_Low: 0,    //组端下限阀值
                HourRate: 0,        //放电小时率
                MonomerLowCount: 0, //单体下限数量
                MonomerVol_Low: 0,  //单体下限阀值
                OnlineLowAction: 0, //在线电压低处理
                TestCmd: 37,         //测试类型
                ChargeCurrSet: 0,   //充电电流
                DCVolHighLimit: 0,  //升压上限
                MonomerTmp_High: 0  //温度上限
            },
            ranges: {
                GroupVol_Low: {
                    name: '组端电压下限',
                    unit: 'V',
                    min: rules.GroupVol_Low.min,
                    max: rules.GroupVol_Low.max
                },
                MonomerVol_Low: {
                    name: '单体电压下限',
                    unit: 'V',
                    min: rules.MonomerVol_Low.min,
                    max: rules.MonomerVol_Low.max
                }
            },
            rules: {
                DisCurr: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.DisCurr)
                    },
                    trigger: 'change'
                }],
                DisCap: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.DisCap)
                    },
                    trigger: 'change'
                }],
                DisTime: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.DisTime)
                    },
                    trigger: 'change'
                }],
                MonomerVol_Low: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.MonomerVol_Low)
                    },
                    trigger: 'change'
                }],
                GroupVol_Low: [{
                    validator(rule, value, callback) {
                        testVal(rule, value, callback, rules.GroupVol_Low)
                    },
                    trigger: 'change'
                }],
            },
        }
    },
    methods: {
        initParams() {
            // åˆå§‹åŒ–参数
            this.params = {
                num: 0,             //命令
                dev_id: 0,          //设备id
                BattGroupNum: 0,    //电池组编号
                DisCurr: 0,         //放电电流
                DisCap: 0,          //放电容量
                DisTime: 0,         //放电时长
                GroupVol_Low: 0,    //组端下限阀值
                HourRate: 0,        //放电小时率
                MonomerLowCount: 0, //单体下限数量
                MonomerVol_Low: 0,  //单体下限阀值
                OnlineLowAction: 0, //在线电压低处理
                TestCmd: 37,         //测试类型
                ChargeCurrSet: 0,   //充电电流
                DCVolHighLimit: 0,  //升压上限
                MonomerTmp_High: 0  //温度上限
            };
        },
        // èŽ·å–å‚æ•°
        getParams(showLoad) {
            // å®šä¹‰ç­‰å¾…框
            let loading;
            if (showLoad) {
                loading = this.$layer.loading(1);
            }
            // å¯åŠ¨æŒ‰é’®ä¸å¯ç‚¹å‡»
            this.startTestFlag = false;
            // æŸ¥è¯¢åŽå°
            this.$apis.dischargeTest.bts.getParams({
                num: this.cmd.get,
                dev_id: this.batt.FBSDeviceId
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                if(rs.code == 1) {
                    let testType = this.testType;
                    let fsparam = rs.data[0].fsparam;
                    let isIn = this.checkValIsInObjects(fsparam.TestCmd, testType);
                    // éåŽ†å‚æ•°å±žæ€§å¹¶èµ‹å€¼
                    for (let key in this.params) {
                        if (key === "TestCmd" && !isIn) {
                            this.params.TestCmd = 37;
                        } else {
                            this.params[key] = fsparam[key];
                        }
                    }
                    // è®¾ç½®çš„命令和dev_id
                    this.params.num = this.cmd.set;
                    this.params.dev_id = this.batt.FBSDeviceId;
                    this.params.BattGroupNum = this.otherParams.GroupIndexInFBSDevice;
                    this.$layer.msg('读取成功!');
                    // è®¾ç½®æŒ‰é’®å¯ç‚¹å‡»
                    this.setTestFlag = true;
                }else {
                    // åˆå§‹åŒ–参数
                    this.initParams();
                    // è®¾ç½®æŒ‰é’®ä¸å¯ç‚¹å‡»
                    this.setTestFlag = false;
                    this.$layer.msg('读取失败!');
                }
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
            }).catch(error=>{
                console.log(error);
                // åˆå§‹åŒ–参数
                this.initParams();
                // è®¾ç½®æŒ‰é’®ä¸å¯ç‚¹å‡»
                this.setTestFlag = false;
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
                this.$layer.msg('读取失败,读取请求异常!');
            });
        },
        // æäº¤è¡¨å•设置参数
        submitFrom() {
            this.$refs.ruleForm.validate((valid) => {
                // æ ¡éªŒé€šè¿‡
                if (valid) {
                    // è®¾ç½®å‚æ•°
                    this.setParamsCheck();
                } else {
                    this.$layer.msg('存在校验未通过的数据!');
                    return false;
                }
            });
        },
        setParamsCheck() {
            if(config.dischargeByFace.value) {
                this.setFaceShow = true;
            }else {
                this.setParams(true);
            }
        },
        // è®¾ç½®å‚æ•°
        setParams() {
            // ç­‰å¾…框
            let loading = this.$layer.loading(1);
            // è¯·æ±‚后台
            this.$apis.dischargeTest.bts.setParams(this.params).then(res => {
                let rs = JSON.parse(res.data.result);
                if (rs.code == 1) {
                    // å¯åŠ¨æŒ‰é’®å¯ç‚¹å‡»
                    this.startTestFlag = true;
                    // æç¤ºä¿¡æ¯
                    this.$layer.msg('设置成功');
                } else {
                    // å¯åŠ¨æŒ‰é’®ä¸å¯ç‚¹å‡»
                    this.startTestFlag = false;
                    // æç¤ºä¿¡æ¯
                    this.$layer.msg('设置失败!');
                }
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
            }).catch(error => {
                console.log(error);
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
                // å¯åŠ¨æŒ‰é’®ä¸å¯ç‚¹å‡»
                this.startTestFlag = false;
                // æç¤ºä¿¡æ¯
                this.$layer.msg('设置失败,设置请求异常!');
            });
        },
        startTestCheck() {
            if(config.dischargeByFace.value) {
                this.startFaceShow = true;
            }else {
                this.confirmStartTest();
            }
        },
        // ç¡®è®¤æ¡†
        confirmStartTest() {
            this.$layer.prompt({title: '输入启动口令,并确认', formType: 2, area: ['300px', '180px']}, (pass, index) => {
                // è¯·æ±‚后台校验密码
                this.$apis.login.checkUserPwd(pass).then(res=>{
                    let rs = JSON.parse(res.data.result);
                    if(rs.code == 1) {
                        // å…³é—­å¼¹å‡ºæ¡†
                        this.$layer.close(index);
                        this.$layer.msg("密码检测通过,启动测试");
                        // å¯åŠ¨æµ‹è¯•
                        this.startTest();
                    }else {
                        this.$layer.msg("启动口令错误!");
                    }
                }).catch(error=>{
                    console.log(error);
                    this.$layer.msg("网络请求异常");
                });
            });
        },
        // å¯åЍ
        startTest() {
            // ç­‰å¾…框
            let loading = this.$layer.loading(1);
            // è¯·æ±‚后台
            this.$apis.dischargeTest.bts.start({
                num: this.cmd.start,
                dev_id: this.batt.FBSDeviceId,
                BattGroupNum: this.batt.GroupIndexInFBSDevice+1,
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                if (rs.code == 1) {
                    // æç¤ºä¿¡æ¯
                    this.$layer.msg('启动测试成功');
                } else {
                    // æç¤ºä¿¡æ¯
                    this.$layer.msg('启动测试失败!');
                }
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
            }).catch(error => {
                console.log(error);
                // å…³é—­ç­‰å¾…框
                this.$layer.close(loading);
                // æç¤ºä¿¡æ¯
                this.$layer.msg('启动测试失败,启动测试请求异常!');
            });
        },
        checkValIsInObjects(val, objects) {
            let rs = false;
            for(let i=0; i<objects.length; i++) {
                let obj = objects[i];
                if(obj.value === val) {
                    rs = true;
                    break;
                }
            }
            return false;
        },
        setFaceSuccess() {
            this.setFaceShow = false;
            this.setParams();
        },
        startFaceSuccess() {
            this.startFaceShow = false;
            this.startTest();
        },
    },
    computed: {
        otherParams() {
            let batt = this.batt;
            let groupInfo = '单体数量:' + this.batt.MonCount + ";电压(V):"
                + this.batt.MonVolStd + ";容量(AH):" + this.batt.MonCapStd;
            return {
                groupName: batt.StationName + "-" + batt.BattGroupName,
                FBSDeviceId: batt.FBSDeviceId,
                groupInfo: groupInfo,
                GroupIndexInFBSDevice: this.batt.GroupIndexInFBSDevice + 1,
            }
        },
        rangeLabel() {
            let ranges = this.ranges;
            let result = {};
            for(let key in ranges) {
                let item = ranges[key];
                result[key] = item.name+"("+item.min+"~"+item.max+item.unit+")";
            }
            return result;
        },
    },
    mounted() {
        // èŽ·å–æ•°æ®
        this.getParams(true);
    }
}
</script>
<style scoped>
.form-footer {
    margin-top: 16px;
    margin-bottom: 16px;
    text-align: right;
}
.form-footer .three-btn {
    margin-left: 12px;
}
.params-container {
    padding: 0.4rem;
    background-color: #ececec;
}
</style>
src/pages/dataTest/js/draw_diagram.js
New file
@@ -0,0 +1,486 @@
import {
    Timeout
} from '@/assets/js/tools';
import screenImage from '@/assets/js/diagram/images/screen.png';
import loadImage from '@/assets/js/diagram/images/load.png';
import battImage from '@/assets/js/diagram/images/elegroup.png';
let Img_screen = new Image();
let Img_load = new Image();
let Img_batt = new Image();
Img_screen.src = screenImage;
Img_load.src = loadImage;
Img_batt.src = battImage;
// console.log(Date.now(), 'init')
// if (Img_batt.complete) {
//     console.log(Date.now(), 'batt');
// } else {
//     Img_batt.addEventListener('load', () => {
//         console.log(Date.now(), 'batt load');
//     });
// }
// let Img_screen = 'url(' + screenImage + ')';
// let Img_load = 'url(' + loadImage + ')';
// let Img_batt = 'url(' + battImage + ')';
// function getDataUrl (img) {
//     let can = document.createElement('canvas');
//     let offCtx = can.getContext('2d');
//     let width = img.width;
//     let height = img.height;
//     can.width = width;
//     can.height = height;
//     console.dir(img);
//     if (img.complete) {
//         offCtx.drawImage(img, 0, 0, width, height);
//     } else {
//         img.addEventListener('load', () => {
//             offCtx.drawImage(img, 0, 0, width, height);
//         });
//     }
//     return can;
// }
// console.log(getDataUrl(Img_batt));
let timer = new Timeout();
const BALLCOLOR = '#00f7f9';
let list = {
    // äºŒæžç®¡
    'diode_0': {
        x: 720
        ,y: 50
        ,method: 'drawDiode'
        ,isHor: true
        ,name: 'D1'
    }
    // äºŒæžç®¡
    ,'diode_1': {
        x: 628
        ,y: 254
        ,method: 'drawDiode'
    }
    ,'diode_2': {
        x: 628
        ,y: 552
        ,method: 'drawDiode'
    }
    // è™šçº¿æ¡†
    ,'dashline_0': {
        points: [[106, 82], [870, 82], [870, 730], [106, 730], [106, 82]]
        ,method: 'drawDashLine'
        ,color: '#00f7f9'
        ,lineWidth: 4
    }
    // ç”µé˜»
    ,'resistance_0': {
        x: 800
        ,y: 216
        ,name: 'R1'
        ,method: 'drawResistance'
    }
    // ,'switch_0': {
    //     x: 300
    //     ,y: 120
    //     ,distance: 60
    //     ,method: 'drawSwitch'
    //     ,isOn: false
    //     ,name: 'K1'
    //     ,description: '80A'
    // }
    // ,'switch_1': {
    //     x: 300
    //     ,y: 330
    //     ,distance: 60
    //     ,method: 'drawSwitch'
    //     ,isOn: false
    //     ,name: 'K2'
    //     ,description: '80A'
    // }
    // ,'switch_2': {
    //     x: 300
    //     ,y: 420
    //     ,distance: 60
    //     ,method: 'drawSwitch'
    //     ,isOn: false
    //     ,name: 'K3'
    //     ,description: '80A'
    // }
    // ,'switch_3': {
    //     x: 820
    //     ,y: 60
    //     ,distance: 60
    //     ,method: 'drawSwitch'
    //     ,isOn: false
    //     ,name: 'K4'
    //     // ,description: '80A'
    // }
    // ,'switch_4': {
    //     x: 660
    //     ,y: 420
    //     ,distance: 60
    //     ,method: 'drawSwitch'
    //     ,isOn: false
    //     ,name: 'K5'
    //     ,description: '80A'
    // }
    // ,'switch_5': {
    //     x: 580
    //     ,y: 220
    //     ,distance: 60
    //     ,method: 'drawSwitch'
    //     ,isOn: false
    //     ,direction: 'ver'
    // }
    // ,'switch_6': {
    //     x: 580
    //     ,y: 520
    //     ,distance: 60
    //     ,method: 'drawSwitch'
    //     ,isOn: false
    //     ,direction: 'ver'
    // }
    ,'inductance_0': {
        x: 404
        ,y: 420
        ,method: 'drawInductance'
        ,name: 'L1'
        ,color: '#00f7f9'
    }
    ,'rectifier_0': {
        x: 120
        ,y: 160
        ,name: '整流器'
        ,method: 'drawRectifier'
        ,width: 68
        ,height: 100
        ,img: Img_screen
    }
    ,'rectifier_1': {
        x: 950
        ,y: 320
        ,name: '整流器'
        ,method: 'drawRectifier'
        ,width: 80
        ,height: 120
        ,img: Img_screen
    }
    ,'load_0': {
        x: 1180
        ,y: 320
        ,method: 'drawLoad'
        ,name: '用户负载'
        ,width: 80
        ,height: 140
        ,img: Img_load
    }
    ,'batts_0': {
        x: 30
        ,y: 480
        ,method: 'drawBatts'
        ,name: '电池组'
        ,width: 36
        ,height: 60
        ,distance: 24
        ,img: Img_batt
    }
    ,'line_0': {
        points: [[47, 480], [47, 60], [720, 60]]
        ,method: 'drawLine'
    }
    ,'line_1': {
        points: [[730, 60], [816, 60]]
        ,method: 'drawLine'
    }
    ,'line_2': {
        points: [[884, 60], [1222, 60], [1222, 323]]
        ,method: 'drawLine'
    }
    ,'line_3': {
        points: [[1222, 458], [1222, 700], [47, 700], [47, 624]]
        ,method: 'drawLine'
    }
    ,'line_4': {
        points: [[154, 162], [154, 120], [296, 120]]
        ,method: 'drawLine'
    }
    ,'line_5': {
        points: [[364, 120], [805, 120], [805, 216]]
        ,method: 'drawLine'
    }
    ,'line_6': {
        points: [[805, 276], [805, 420], [724, 420]]
        ,method: 'drawLine'
    }
    ,'line_7': {
        points: [[452, 420], [656, 420]]
        ,method: 'drawLine'
    }
    ,'line_8': {
        points: [[364, 420], [404, 420]]
        ,method: 'drawLine'
    }
    ,'line_9': {
        points: [[47, 420], [296, 420]]
        ,method: 'drawLine'
    }
    ,'line_10': {
        points: [[154, 260], [154, 330], [296, 330]]
        ,method: 'drawLine'
    }
    ,'line_11': {
        points: [[364, 330], [384, 330], [384, 420]]
        ,method: 'drawLine'
    }
    ,'line_12': {
        points: [[580, 120], [580, 216]]
        ,method: 'drawLine'
    }
    ,'line_13': {
        points: [[580, 284], [580, 516]]
        ,method: 'drawLine'
    }
    ,'line_14': {
        points: [[580, 584], [580, 700]]
        ,method: 'drawLine'
    }
    ,'line_15': {
        points: [[580, 196], [638, 196], [638, 244]]
        ,method: 'drawLine'
    }
    ,'line_16': {
        points: [[638, 254], [638, 304], [580, 304]]
        ,method: 'drawLine'
    }
    ,'line_17': {
        points: [[580, 496], [638, 496], [638, 542]]
        ,method: 'drawLine'
    }
    ,'line_18': {
        points: [[638, 552], [638, 604], [580, 604]]
        ,method: 'drawLine'
    }
    ,'line_19': {
        points: [[990, 60], [990, 322]]
        ,method: 'drawLine'
    }
    ,'line_20': {
        points: [[990, 440], [990, 700]]
        ,method: 'drawLine'
    }
};
// ç”»é¢æ¿
// const drawPanel = (can) => {
//     can.drawRect1({
//         x: 400
//         ,y: 10
//         ,width: 260
//         ,height: 40
//         ,subName: 'title'
//         // ,color: '#f00'
//     }, true);
// }
// é¢æ¿ä½ç½®ä¿¡æ¯
const panelPos = {
    // title
    title: {
        left: 400
        ,top: 10
        ,width: 260
        ,height: 40
    }
}
let firstTime = true;
const resetFirstTime = function () {
    firstTime = true;
}
// let ballList = [];
const updateBalls = (can, ballList) => {
    let count = 0;
    return function (ballList) {
        can.updateCanvas();
        // console.log(ballList, '--------');
        for (let i = 0, j = ballList.length; i < j; i++) {
            can.moveBall({
                points: ballList[i].points
                ,direction: ballList[i].direction
                ,fillStyle: ballList[i].fillStyle
            }, count, ballList[i].ballNum);
        }
        count++;
        count %= can.COUNT;
    }
}
const update = function (callback, stateL, status, ballList) {
    if (!timer.callback) {
        timer.init(function () {
            callback(ballList);
            timer.open();
        }, 1000 / 30);
    }
    // console.log(status, 'status');
    let ctx = stateL.context;
    stateL.clearCanvas();
    // stateL.drawLine(ctx, {
    //     points: [[500, 100], [500, 500], [800, 500]],
    //     color: status.Q1 ? '#00f7f9' : '#ccc'
    // });
    // stateL.drawLine(ctx, {
    //     points: [[480, 200], [480, 600], [780, 600]],
    //     color: status.Q2 ? '#00f7f9' : '#ccc'
    // });
    // æ”¾ç”µç”µæµ
    // list1与list3公共的第一部分
    const list0 = [
        {points: [47, 480, 47, 420], direction: status.state == 2 ? 'top' : 'bottom', fillStyle: BALLCOLOR, ballNum: 1}
    ];
    const list1 = [
        {points: [47, 480, 47, 420], direction: status.state == 2 ? 'top' : 'bottom', fillStyle: BALLCOLOR, ballNum: 1}
        ,{points: [47, 420, 580, 420], direction: status.state == 2 ? 'right' : 'left', fillStyle: BALLCOLOR, ballNum: 4}
        ,{points: [580, 420, 580, 700], direction: status.state == 2 ? 'bottom' : 'top', fillStyle: BALLCOLOR, ballNum: 3}
    ];
    const list2 = [
        {points: [580, 420, 580, 120], direction: 'top', fillStyle: BALLCOLOR, ballNum: 3}
        ,{points: [580, 120, 805, 120], direction: 'right', fillStyle: BALLCOLOR, ballNum: 2}
        ,{points: [805, 120, 805, 216], direction: 'bottom', fillStyle: BALLCOLOR, ballNum: 1}
        ,{points: [805, 276, 805, 420], direction: 'bottom', fillStyle: BALLCOLOR, ballNum: 1}
        ,{points: [580, 420, 805, 420], direction: 'left', fillStyle: BALLCOLOR, ballNum: 2}
    ];
    const list3 = [
        {points: [47, 420, 47, 60], direction: 'top', fillStyle: BALLCOLOR, ballNum: 4}
        ,{points: [47, 60, 1222, 60], direction: 'right', fillStyle: BALLCOLOR, ballNum: 10}
        ,{points: [1222, 323, 1222, 60], direction: 'bottom', fillStyle: BALLCOLOR, ballNum: 3}
        ,{points: [1222, 458, 1222, 700], direction: 'bottom', fillStyle: BALLCOLOR, ballNum: 3}
        ,{points: [580, 700, 1222, 700], direction: 'left', fillStyle: BALLCOLOR, ballNum: 5}
    ];
    // list1与list3公共第二部分
    const list30 = [
        {points: [47, 700, 580, 700], direction: status.state == 2 ? 'left' : 'right', fillStyle: BALLCOLOR, ballNum: 4}
        ,{points: [47, 624, 47, 700], direction: status.state == 2 ? 'top' : 'bottom', fillStyle: BALLCOLOR, ballNum: 1}
    ];
    const list4 = [
        {points: [154, 162, 154, 120], direction: 'top', fillStyle: BALLCOLOR, ballNum: 1}
        ,{points: [154, 120, 580, 120], direction: 'right', fillStyle: BALLCOLOR, ballNum: 4}
        ,{points: [580, 420, 580, 120], direction: 'bottom', fillStyle: BALLCOLOR, ballNum: 3}
        ,{points: [580, 420, 384, 420], direction: 'left', fillStyle: BALLCOLOR, ballNum: 2}
        ,{points: [384, 330, 384, 420], direction: 'top', fillStyle: BALLCOLOR, ballNum: 1}
        ,{points: [154, 330, 384, 330], direction: 'left', fillStyle: BALLCOLOR, ballNum: 2}
        ,{points: [154, 330, 154, 260], direction: 'top', fillStyle: BALLCOLOR, ballNum: 1}
    ];
    // console.log('q3, q4, q5', status.Q3, status.Q4, status.Q5);
    // æ¸…空数组 ä¸æ”¹å˜åœ°å€;
    ballList.length = 0;
    let Q1 = status.state == 2 && firstTime;
    let Q2 = status.state == 2 && !firstTime;
    let Q3 = status.main;
    let Q4 = status.state == 4 && firstTime;
    let Q5 = status.state == 4 && !firstTime;
    stateL.draw_switch({
        x: 300
        ,y: 420
        ,distance: 60
        ,method: 'drawSwitch'
        ,isOn: Q1 || Q5
        ,name: 'K3'
        ,description: '80A'
    });
    stateL.draw_switch({
        x: 580
        ,y: 520
        ,distance: 60
        ,method: 'drawSwitch'
        ,isOn: Q1 || Q5
        ,direction: 'ver'
    });
    stateL.draw_switch({
        x: 660
        ,y: 420
        ,distance: 60
        ,method: 'drawSwitch'
        ,isOn: Q2
        ,name: 'K5'
        ,description: '80A'
    });
    stateL.draw_switch({
        x: 580
        ,y: 220
        ,distance: 60
        ,method: 'drawSwitch'
        ,isOn: Q2 || Q4
        ,direction: 'ver'
    });
    stateL.draw_switch({
        x: 300
        ,y: 120
        ,distance: 60
        ,method: 'drawSwitch'
        ,isOn: Q4
        ,name: 'K1'
        ,description: '80A'
    });
    stateL.draw_switch({
        x: 300
        ,y: 330
        ,distance: 60
        ,method: 'drawSwitch'
        ,isOn: Q4
        ,name: 'K2'
        ,description: '80A'
    });
    stateL.draw_switch({
        x: 820
        ,y: 60
        ,distance: 60
        ,method: 'drawSwitch'
        ,isOn: Q3
        ,name: 'K4'
    })
    if (Q1 || Q5) {
        ballList.push(...list1, ...list0, ...list30);
        // console.log('q3', ballList);
    }
    if (Q2) {
        ballList.push(...list2);
        // console.log('q4', ballList);
    }
    if (Q3) {
        ballList.push(...list3, ...list0, ...list30);
    }
    if (Q4) {
        ballList.push(...list4);
    }
    timer.open();
    firstTime = !firstTime;
};
export {
    list
    ,panelPos
    ,resetFirstTime
    // ,drawPanel
    ,update
    ,updateBalls
}
src/pages/dataTest/realTimeAio.vue
@@ -2,12 +2,12 @@
    <flex-layout direction="row" class="page-real-time" :no-bg="true">
        <!-- å……放电一体机 -->
        <content-box style="margin-left: 4px; margin-right: 4px;" :title="battFullName">
            <!-- <div slot="box-tools" class="box-tools">
            <div slot="box-tools" class="box-tools">
                <el-tooltip class="item" effect="dark" content="历史数据" placement="bottom">
                    <i class="iconfont el-icon-jinru" @click="syncPage"></i>
                </el-tooltip>
            </div>
            <div slot="box-tools" class="box-tools" style="right: 40px;">
            <!-- <div slot="box-tools" class="box-tools" style="right: 40px;">
                <el-tooltip class="item" effect="dark" content="历史实时数据" placement="bottom">
                    <i class="el-iconfont el-icon-s-marketing" @click="historyRealTimeDataDialog.show=true"></i>
                </el-tooltip>
@@ -79,9 +79,9 @@
                                    <li class="hdw-menu-item" v-if="control.data.clearAlerm.show">
                                        <a @click="clearAlerm" href="javascript:void(0);">清除告警</a>
                                    </li>
                                    <li class="hdw-menu-item" v-if="control.data.pause.show">
                                    <!-- <li class="hdw-menu-item" v-if="control.data.pause.show">
                                        <a @click="pause(type)" href="javascript:void(0);">暂停{{typeStr}}}</a>
                                    </li>
                                    </li> -->
                                </ul>
                            </div>
                            <button class="hdw-btn transparentBtn" slot="reference">
@@ -216,46 +216,37 @@
                                    </div>
                                </div>
                            </science-box> -->
                            <!-- <circuit-diagram
                            <circuit-diagram
                                ref="circuitDiagram"
                                :width="diagramOpt.width"
                                :height="diagramOpt.height"
                                wrap-class="wrap"
                                :debug="true"
                                :levelArr="['staticL', 'stateL', 'flushL']"
                                @ratioChanged="ratioChanged"
                                @debugClick="debugClick"
                                >
                                <canvas
                                    :width="$options.width"
                                    :height="$options.height"
                                    ref="staticL"></canvas>
                                <canvas
                                    :width="$options.width"
                                    :height="$options.height"
                                    ref="stateL"></canvas>
                                <canvas
                                    :width="$options.width"
                                    :height="$options.height"
                                    ref="flushL"></canvas>
                            </circuit-diagram> -->
                                <div class="info-panel" :style="getStyle('title', 1)">{{diagram.desc}}</div>
                            </circuit-diagram>
                        </el-tab-pane>
                        <el-tab-pane label="电压" name="vol">
                            <bar-chart ref="vol" id="vol" unit="V" right-menu></bar-chart>
                        </el-tab-pane>
                        <el-tab-pane label="内阻" name="res">
                        <!-- <el-tab-pane label="内阻" name="res">
                            <bar-chart ref="res" id="res" unit="mΩ" max-color="red" min-color="green" right-menu></bar-chart>
                        </el-tab-pane>
                        </el-tab-pane> -->
                        <el-tab-pane label="温度" name="temp">
                            <bar-chart ref="temp" id="temp" unit="℃" max-color="red" min-color="green" right-menu></bar-chart>
                        </el-tab-pane>
                        <el-tab-pane label="电导" name="conduct">
                        <!-- <el-tab-pane label="电导" name="conduct">
                            <bar-chart ref="conduct" id="conduct" right-menu></bar-chart>
                        </el-tab-pane>
                        <el-tab-pane label="均衡电流" name="curr">
                        </el-tab-pane> -->
                        <!-- <el-tab-pane label="均衡电流" name="curr">
                            <bar-chart ref="curr" id="curr" unit="A" right-menu></bar-chart>
                        </el-tab-pane>
                        <el-tab-pane label="漏液电压" name="leakVol">
                            <bar-chart ref="leakVol" id="leakVol" unit="V" right-menu></bar-chart>
                        </el-tab-pane>
                        </el-tab-pane> -->
                        <el-tab-pane label="数据表格" name="tblData" class="el-table-wrapper">
                            <el-table
@@ -297,32 +288,48 @@
<script>
import ContentBox from "@/components/ContentBox";
import BarChart from "@/components/chart/BarChart";
// import ChargeDialogContent from './components/chargeDialogContent';
// import DischargeDialogContent from './components/dischargeDialogContent';
import ActivateDialogContent from './components/activateDialogContent';
import {
    realTimeSearch,
    realTimeGroup,
    realTimePowerOff,
    realTimeAlarm
} from '@/assets/js/realTime';
import {
    Timeout,
    getBarNum,
    sethoubeiTime,
    regEquipType,
    formatSeconds,
    isHasPermit
} from '@/assets/js/tools';
import {
    list
    ,panelPos
    ,resetFirstTime
    ,update
    ,updateBalls
} from './js/draw_diagram';
import battGroupMager from '@/assets/js/apis/dataMager/battGroupMager';
import getMarkLineData from "@/components/chart/js/getMarkLineData";
// import CircuitDiagram from '@/components/diagram/diagram';
import CircuitDiagram from '@/components/diagram/diagram';
import Diagram from '@/components/diagram/js/diagram';
import common from '@/components/diagram/js/common';
let interval = common.interval;
import {
    const_aio
} from '@/assets/js/const';
let vol, resChart, temp, conduct, currChart, leakVol;
let staticL, stateL, flushL;
let tblData = [];
let ballList = [];
export default {
    name: "realTimeAio",
    components: {
@@ -331,7 +338,7 @@
        // ChargeDialogContent,
        // DischargeDialogContent,
        ActivateDialogContent,
        // CircuitDiagram
        CircuitDiagram
    },
    watch: {
        "$route.params.BattGroupId"(BattGroupId) {
@@ -352,10 +359,13 @@
        let isCanTest = isHasPermit('batt_test_op_permit', permits);
        // let stateList = const_61850.stateList;
        return {
            acTabs: "vol",
            isCanTest: !0 || isCanTest,
            acTabs: "eleLine",
            isCanTest: isCanTest,
            dialogTitle: '充电参数设置',
            type: '',       // å½“前状态 charge discharge activate
            moveBall: null,
            // k4状态
            main: false,
            /* ç”µæ± çŠ¶æ€ æ¨¡å— ç»„端展示 */
            inputs: {
                group_vol: 0 /* ç«¯ç”µåŽ‹-组端电压 */ ,
@@ -368,7 +378,7 @@
                batt_state: 0 /* ç”µæ± çŠ¶æ€ */
            },
            control: {
                show: !0 || false,
                show: true,
                data: {
                    startCharge: { // å¯åŠ¨å……ç”µ
                        show: true,
@@ -404,11 +414,6 @@
                        show: true,
                        typeshow: false,
                        id: 17
                    },
                    pause: {
                        show: false,
                        typeshow: false,
                        id: 18
                    }
                }
            },
@@ -416,7 +421,8 @@
                show: false,
                type: ''
            },
            timer: new Timeout('movingRingSystemRealTime'),
            timer: new Timeout('movingRingSysteRrealTime'),
            timer2: new Timeout(),
            table: {
                headers: [
                    {
@@ -430,30 +436,10 @@
                        width: ""
                    },
                    {
                        prop: "res1",
                        label: "内阻(mΩ)",
                        width: ""
                    },
                    {
                        prop: "temp1",
                        label: "温度(℃)",
                        width: ""
                    },
                    {
                        prop: "conduct1",
                        label: "电导",
                        width: ""
                    },
                    {
                        prop: "curr1",
                        label: "均衡电流(A)",
                        width: ""
                    },
                    {
                        prop: "leakVol1",
                        label: "漏液电压(V)",
                        width: ""
                    }
                ],
                datas: []
            },
@@ -465,6 +451,25 @@
                powerCut: 1,
                temp: 0 // è®¾å¤‡æ¸©åº¦
            },
            diagramOpt: {
                width: 1300,
                height: 760,
            }
            ,stateList: const_aio.stateList
            ,sta: {
                Q1: false
                ,Q2: false
                ,Q3: false
                ,Q4: false
                ,Q5: false
            }
        }
    },
    watch: {
        'diagram.type' (n) {
            if (n == 2 || n ==4) {
                resetFirstTime();
            }
        }
    },
    computed: {
@@ -535,9 +540,20 @@
        tabClick(tab) {
            // æ ¹æ®tab更新电路图
            if(this.acTabs === "eleLine") {
                this.diagram.update = true;
            }else {
                this.diagram.update = false;
                // this.diagram.update = true;
                // console.log(this.timer2, 'timer2', this.timer2.callback, stateL);
                this.$refs.circuitDiagram.resizeHandle();
                // debugger;
                this.timer2.restart();
                // this.$nextTick(() => {
                //     this.timer2.restart();
                // });
                // this.init();
                // this.drawStatic();
                // this.loop();
            } else {
                // this.diagram.update = false;
                this.timer2.stop();
            }
            // æ›´æ–°å›¾è¡¨
            this.setChart();
@@ -672,28 +688,28 @@
                case 'vol':
                    this.$refs.vol.setOption(vol);
                    break;
                case 'res':
                    this.$refs.res.setOption(resChart);
                    break;
                // case 'res':
                //     this.$refs.res.setOption(resChart);
                //     break;
                case 'temp':
                    this.$refs.temp.setOption(temp);
                    break;
                case 'conduct':
                    this.$refs.conduct.setOption(conduct);
                    break;
                case 'curr':
                    this.$refs.curr.setOption(currChart);
                    break;
                case 'leakVol':
                    this.$refs.leakVol.setOption(leakVol);
                    break;
                // case 'conduct':
                //     this.$refs.conduct.setOption(conduct);
                //     break;
                // case 'curr':
                //     this.$refs.curr.setOption(currChart);
                //     break;
                // case 'leakVol':
                //     this.$refs.leakVol.setOption(leakVol);
                //     break;
            }
        },
        getBattGroupInfo(BattGroupId) {
            console.log(BattGroupId, 'battGroupId');
            // console.log(BattGroupId, 'battGroupId');
            this.$apis.dataMager.battGroupMager.getBattGroupInfo(BattGroupId).then(res=>{
                let rs = JSON.parse(res.data.result);
                console.log(rs, 'rs');
                // console.log(rs, 'rs');
                if(rs.code == 1) {
                    this.leafClick(rs.data[0]);
                }else {
@@ -723,9 +739,9 @@
                // å•体温度
                this.setChartMarkLine(temp, "Temperature", "Batt_Alarm_Type_MonTmp", list);
                // å•体内阻
                this.setChartMarkLine(resChart, "Resistance", "Batt_Alarm_Type_MonRes", list);
                // this.setChartMarkLine(resChart, "Resistance", "Batt_Alarm_Type_MonRes", list);
                // å•体电导
                this.setChartMarkLine(conduct, "Conductance", "Batt_Alarm_Type_MonRes", list);
                // this.setChartMarkLine(conduct, "Conductance", "Batt_Alarm_Type_MonRes", list);
              }
            });
        },
@@ -750,16 +766,16 @@
                  high = parseFloat(std_mon_tmp*item.alm_high_coe).toHold(1);
                  low = parseFloat(std_mon_tmp*item.alm_low_coe).toHold(1);
                  break;
                case "Resistance":
                  let std_mon_res = (1*(batt.MonVolStd/2))/(batt.MonCapStd/100);
                  high = parseFloat(std_mon_res*item.alm_high_coe).toHold(3);
                  low = parseFloat(std_mon_res*item.alm_low_coe).toHold(3);
                  break;
                case "Conductance":
                  let std_mon_ser = batt.MonSerStd;
                  high = parseFloat(std_mon_ser*item.alm_high_coe).toHold(0);
                  low = parseFloat(std_mon_ser*item.alm_low_coe).toHold(0);
                  break;
                // case "Resistance":
                //   let std_mon_res = (1*(batt.MonVolStd/2))/(batt.MonCapStd/100);
                //   high = parseFloat(std_mon_res*item.alm_high_coe).toHold(3);
                //   low = parseFloat(std_mon_res*item.alm_low_coe).toHold(3);
                //   break;
                // case "Conductance":
                //   let std_mon_ser = batt.MonSerStd;
                //   high = parseFloat(std_mon_ser*item.alm_high_coe).toHold(0);
                //   low = parseFloat(std_mon_ser*item.alm_low_coe).toHold(0);
                //   break;
              }
              // ä½Žå‘Šè­¦
              chartData.series[0].markLine.data[0].yAxis = low;
@@ -776,7 +792,7 @@
                BattGroupId: batt.BattGroupId
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                console.log(rs, 'rs');
                // console.log(rs, 'rs===========');
                let data = [];
                if (rs.code == 1) {
                    data = rs.data.map(item => {
@@ -798,7 +814,6 @@
                    tblData = data;
                }
                // ç”µåދ值
                let volTempVol = [];
                if (rs.code == 1) {
@@ -810,18 +825,6 @@
                vol.title.text = "最大值=" + volBarNum.max.toFixed(2) + "V;最小值=" + volBarNum.min.toFixed(2) + "V;平均值=" + volBarNum.avg
                    .toFixed(2) + "V";
                vol.series[0].data = volTempVol;
                // å†…阻
                let volTempres = [];
                if (rs.code == 1) {
                    volTempres = rs.data.map(item => {
                        return ["#" + item.mon_num, item.mon_res];
                    });
                }
                let resBarNum = getBarNum(volTempres);
                resChart.title.text = "最大值=" + resBarNum.max.toFixed(2) + "mΩ;最小值=" + resBarNum.min.toFixed(2) + "mΩ;平均值=" +
                    resBarNum.avg.toFixed(2) + "mΩ";
                resChart.series[0].data = volTempres;
                // æ¸©åº¦
                let volTempte = [];
@@ -835,52 +838,134 @@
                    tempBarNum.avg.toFixed(1) + "℃";
                temp.series[0].data = volTempte;
                // ç”µå¯¼
                let conductTemp = [];
                if (rs.code == 1) {
                    conductTemp = rs.data.map(item => {
                        return ["#" + item.mon_num, item.mon_res ? (1 / item.mon_res * 1000).toFixed(0) : 0];
                    });
                }
                let conductBarNum = getBarNum(conductTemp);
                conduct.title.text = "最大值=" + conductBarNum.max.toFixed(0) + ";最小值=" + conductBarNum.min.toFixed(0) + ";平均值=" +
                    conductBarNum.avg.toFixed(0);
                conduct.series[0].data = conductTemp;
                // å‡è¡¡ç”µæµ
                let currTemp = [];
                if (rs.code == 1) {
                    currTemp = rs.data.map(item => {
                        return ["#" + item.mon_num, item.mon_JH_curr];
                    });
                }
                let currBarNum = getBarNum(currTemp);
                currChart.title.text = "最大值=" + currBarNum.max.toFixed(1) + "mA;最小值=" + currBarNum.min.toFixed(1) + "mA;平均值=" +
                    currBarNum.avg.toFixed(1) + "mA";
                currChart.series[0].data = currTemp;
                // æ¼æ¶²ç”µåŽ‹
                let leakVolTemp = [];
                if(rs.code == 1){
                    leakVolTemp = rs.data.map(item => {
                        return ["#" + item.mon_num, item.mon_LY_vol];
                    });
                }
                let leakVolNum = getBarNum(leakVolTemp);
                leakVol.title.text = "最大值=" + leakVolNum.max.toFixed(1) + "V;最小值=" + leakVolNum.min.toFixed(1) + "V;平均值=" +
                    leakVolNum.avg.toFixed(1) + 'V';
                leakVol.series[0].data = leakVolTemp;
                // æ›´æ–°ç”µåŽ‹å›¾è¡¨
                this.setChart();
            });
        },
        // å‘父级发送同步页面的指令
        syncPage() {
            let batt = this.batt;
            let search =
                "?province=" +
                batt.StationName1 +
                "&city=" +
                batt.StationName2 +
                "&county=" +
                batt.StationName5 +
                "&home=" +
                batt.StationName3 +
                "&batt=" +
                batt.BattGroupId;
            window.parent.postMessage({
                    cmd: "syncPage",
                    params: {
                        pageInfo: {
                            label: "历史数据",
                            name: "history",
                            src: "#/history" + search,
                            closable: true
                        }
                    }
                },
                "*"
            );
        },
        // è®¾ç½®stateList的值
        setStateList(name, value, type) {
            let stateList = this.stateList;
            for (let i = 0; i < stateList.length; i++) {
                let state = stateList[i];
                if (state.name == name) {
                    state.value = value;
                    state.type = type ? type : "";
                }
            }
        },
        /* å®žæ—¶ç»„端信息 */
        realTimeGroupss() {
            var batt = this.batt;
            realTimeGroup(batt.BattGroupId).then(res => {
                let rsa = JSON.parse(res.data.result);
                // console.log(rsa, '??', rsa.data[0]);
                if (rsa.code == 1) {
                    this.inputs = rsa.data[0];
                    console.log(this.inputs.rec_datetime, '更新时间');
                }
            });
        },
        /* æŸ¥è¯¢ç”µè·¯å›¾å¼€å…³çŠ¶æ€å’Œä¿¡æ¯ */
        realTimePowerOffs() {
            let batt = this.batt;
            // è®¾å¤‡ä¸º61850显示右侧的面板
            // if (regEquipType(batt.FBSDeviceId, "equip61850")) {
            //     this.stateListShow = true;
            // } else {
            //     this.stateListShow = false;
            // }
            // æŸ¥è¯¢åŽå°æ•°æ®
            realTimePowerOff({
                dev_id: batt.FBSDeviceId
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                // console.log('状态:', rs);
                let outTime = 2 * 60; //设备超时时间(2分钟)
                let isOutTime = true; //通讯中断        åˆ¤æ–­è®¾å¤‡æ˜¯å¦é€šè®¯ä¸­æ–­    true:中断    false:正常
                if (rs.code == 1) {
                    let data = rs.data[0];
                    // åŸºç¡€ä¿¡æ¯
                    this.setEquipBase(data);
                    // åˆ¤æ–­æ˜¯å¦è¶…æ—¶
                    var nowTime = new Date(data.note).getTime(); //当前时间
                    var record = new Date(data.record_datetime).getTime();
                    if (Math.abs(nowTime - record) / 1000 > outTime) {
                        this.disconnect();
                    } else {
                        // æœªè¶…时执行逻辑
                        let dev_id = batt.FBSDeviceId;
                        this.diagram.powerCut = 0;
                        //
                        this.diagram.type = data.dev_workstate;
                        this.diagram.desc = const_aio.workstates[data.dev_workstate];
                    }
                } else {
                    // è®¾å¤‡å¤„于未连接
                    this.disconnect();
                }
            });
        },
        disconnect() {
            // è®¾å¤‡æœªè¿žæŽ¥
            this.diagram.type = -1;
            this.setStateList("workState", "未连接");
            this.diagram.temp = 0;
            // é€šè®¯çŠ¶æ€
            // this.setStateList("connect", "异常", "table-row-error");
            // æ¸©åº¦
            // this.setStateList("devTemp", "未知", "table-row-warn");
            // å¹²æŽ¥ç‚¹
            // this.setStateList("contact", "未知", "table-row-warn");
            // æ ¸å®¹ç»ˆæ­¢åŽŸå› 
            // this.setStateList("stopReason", "未知");
            // æ“ä½œå¤±è´¥åŽŸå› 
            // this.setStateList("failReason", "未知");
        },
        // åŸºç¡€ä¿¡æ¯
        setEquipBase(data) {
            // è®¾å¤‡çš„æ¸©åº¦
            this.diagram.temp = data.dev_temp;
        },
        startTimer() {
            this.timer.start(() => {
                this.$axios
                    .all([
                        this.realTimeSearch(),
                        // this.realTimeGroupss(),
                        // this.realTimePowerOffs(),
                        this.realTimeGroupss(),
                        this.realTimePowerOffs(),
                        // this.realTimeStateList(),
                        //this.inversionInfo()
                        // this.inversionInfo()
                    ])
                    .then(() => {
                        this.timer.open();
@@ -893,6 +978,7 @@
        monitorPage() {
            // èŽ·å–ç¼“å­˜çš„session
            let name = sessionStorage.getItem('acTabs');
            // console.log(name, 'session acTabs');
            if(name === "movingRingSystemRealTime" && this.acTabs === "eleLine") {
                this.diagram.update = true;
            }else {
@@ -1002,9 +1088,9 @@
            this.dialog.show = true;
        }
        // æš‚停
        ,pause (type) {
            console.log('暂停', type)
        }
        // ,pause (type) {
        //     console.log('暂停', type)
        // }
        ,clearAlerm () {
            console.log('clearAlerm');
            // æ¸…除告警
@@ -1040,9 +1126,76 @@
                }
            );
        }
        ,ratioChanged (ratio) {
            // console.log(ratio);
            staticL && staticL.setRatio(ratio);
            flushL && flushL.setRatio(ratio);
            stateL && stateL.setRatio(ratio);
        }
        ,init () {
            // console.log(this.$refs.circuitDiagram);
            let circuitDiagram = this.$refs.circuitDiagram;
            // console.log(circuitDiagram.$refs.staticL[0]);
            // debugger;
            staticL = new Diagram(circuitDiagram.$refs.staticL[0]);
            stateL = new Diagram(circuitDiagram.$refs.stateL[0]);
            flushL = new Diagram(circuitDiagram.$refs.flushL[0]);
            this.moveBall = updateBalls(flushL, ballList);
        }
        ,drawStatic () {
            staticL.importObjList(list);
            // drawPanel(staticL);
            staticL.drawAll();
        }
        ,drawFlush () {
        }
        // è°ƒè¯•时的点击
        ,debugClick (o) {
            let point = {
                x: o.offsetX
                ,y: o.offsetY
            };
            let inObj = staticL.mousePointInObj([point.x, point.y], undefined);
            let canvas_obj_id_arr = staticL.getObjIdArr();
            let canvas_obj = staticL.getObjList();
            if (inObj) {
                for (let i = 0, j = canvas_obj_id_arr.length; i < j; i++) {
                let id = canvas_obj_id_arr[i];
                let _inObj = staticL.mousePointInObj([point.x, point.y], id);
                if (_inObj) {
                    let _obj = canvas_obj[id];
                    console.log('----obj', _obj, id);
                    break;
                }
                }
            }
        }
        ,loop () {
            this.timer2.init(() => {
                // console.log('loop');
                update(this.moveBall, stateL, {state: this.diagram.type, main: this.main}, ballList);
                this.timer2.open();
            }, 1000);
        }
        ,getStyle (type) {
            if (!staticL) {
                return {};
            }
           let pos = panelPos[type];
           let ratio = staticL.ratio;
           return {
               top: pos.top * ratio + 'px'
               ,left: pos.left * ratio + 'px'
               ,width: pos.width * ratio + 'px'
               ,height: pos.height * ratio + 'px'
           }
        }
    },
    mounted() {
        console.log(this.$route.params, 'mounted');
        // console.log(this.$route.params, 'mounted');
        let BattGroupId = this.$route.params.BattGroupId;
        this.getBattGroupInfo(BattGroupId);
        this.initChart();
@@ -1053,9 +1206,15 @@
        window.addEventListener('resize', this.resize);
        // ç›‘控是否已经切换到当前页面
        this.monitorPage();
        this.init();
        interval(this.drawStatic, 100, 50);
        // this.drawStatic();
        this.loop();
        this.timer2.open();
    },
    beforeDestroy () {
        this.timer.stop();
        this.timer2.stop();
    }
}
</script>
@@ -1137,4 +1296,11 @@
.hdw-menu-item a:active {
    background-color: rgb(34, 100, 167);
}
.info-panel {
    position: absolute;
    /* background: #999; */
}
>>> .wrap {
    /* background: rgba(66, 66, 66, 1); */
}
</style>
ÏîÄ¿ÐèÇó.md
@@ -61,3 +61,51 @@
解决方案:在后台返回,命令执行失败时,在向设备发送停止启动测试的命令
```
#充放电一体机
####2021-07-29
```
quint16 test_mode;              //放电类型
quint16 acstop_op;              //停电处理
quint16 nominal_cap;  ////标称容量 èŒƒå›´0-9999AH
quint16 hourly_rate;  //小时率     èŒƒå›´1-10,20
quint16 preset_cur;  //放电电流, èŒƒå›´1-150A
quint16 preset_cap;  //放电容量 èŒƒå›´0-9999AH
quint16 preset_time;  //预放时间 åˆ†é’Ÿå•位,没用限定范围
quint16 mon_lower;  //单体下限 åˆ†è¾¨çއ0.01,范围0-20V
quint16 group_lower;  //组端下限 åˆ†è¾¨çއ0.1,范围1-285V
quint16 mon_number;  //单体数量 1-300
quint16 group_number;  //组数 ä¸å¯è®¾å€¼ï¼Œç›®å‰ä¸º1
quint16 lower_number;  //下限个数 èŒƒå›´1至单体总数
quint16 mon_vol;  //只取值1.2, 2.0,6.0,12.0,3.2,3.7
quint16 dischg_mode;  //放电模式:0恒流放电   1恒功率放电
quint16 pre_power;  //预放功率   åˆ†è¾¨çއ0.1 èŒƒå›´0-7.5kw
quint16 pre_res;  //放电阻值 åˆ†è¾¨çއ0.01 èŒƒå›´0.05——655
quint16 chrg_curr;  //充电电流//范围1-100A
quint16 chrg_vol;  //充电电压//范围1-285V
quint16 chrg_vol_2;  //浮充电压//范围小于充电电压
quint16 chrg_cap;  //充电容量  (不显示)
quint16 chrg_time;  //充电时长  èŒƒå›´æ²¡æœ‰é™åˆ¶
quint16 chrg_time_2;  //浮充时长  èŒƒå›´æ²¡æœ‰é™åˆ¶
quint16 chrg_stopcurr;  //截止电流  å°äºŽå……电电流
quint16 grp_uppervol;  //组端上限 ä¸å¯è®¾ç½®ï¼Œæ¯”充电电压大5V
quint16 mon_uppervol;  //单体上限 åˆ†è¾¨çއ0.01,范围0-16V
quint16 mon_uppernum;  //单体上限数量  èŒƒå›´å¤§äºŽ0,小于单体总数
quint16 chrg_temp;  //充电过温
quint16 dischrg_temp;  //放电过温
quint16 cycle_start;  //活化起点 0放电 ï¼Œ1充电
quint16 cycle_times;  //活化次数 1-50次
quint16 waitdis_time;  //充完静置 0-500分钟
quint16 waitchr_time;  //放完静置 0-500分钟
quint8 chargeC_num; //恒流总阶段数 1-3
quint8 C_Curr_Num;  //当前设置阶段index Â Â 0-2
quint16 C_charge[3];//恒流阶段充电电流 èŒƒå›´1-100A
quint16 C_time[3];  //恒流阶段充电时间
```