whyczyk
2021-09-28 f48b2102886e3191c757befb15af840a6ba20844
实时告警首页提交
9个文件已修改
1个文件已删除
15个文件已添加
3067 ■■■■ 已修改文件
package-lock.json 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/api.js 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/const_aio.js 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/Timeout.js 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/formatSeconds.js 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/getBarNum.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/index.js 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/BarChart.vue 362 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/js/getMarkLineData.js 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/js/getYMax.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/js/getYMin.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/theme/EleResize.js 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/theme/transparent.js 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/global/ChartManage.js 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/global/common.js 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/global/index.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/alarm-details.vue 131 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/alarm-list.vue 295 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 295 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login.vue 304 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/menu.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/real-monitoring.vue 702 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes.js 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -1703,6 +1703,16 @@
          "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=",
          "dev": true
        },
        "ansi-styles": {
          "version": "4.3.0",
          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-convert": "^2.0.1"
          }
        },
        "cacache": {
          "version": "13.0.1",
          "resolved": "https://registry.npm.taobao.org/cacache/download/cacache-13.0.1.tgz?cache=0&sync_timestamp=1594429684526&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcacache%2Fdownload%2Fcacache-13.0.1.tgz",
@@ -1729,6 +1739,53 @@
            "unique-filename": "^1.1.1"
          }
        },
        "chalk": {
          "version": "4.1.2",
          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
          "dev": true,
          "optional": true,
          "requires": {
            "ansi-styles": "^4.1.0",
            "supports-color": "^7.1.0"
          }
        },
        "color-convert": {
          "version": "2.0.1",
          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-name": "~1.1.4"
          }
        },
        "color-name": {
          "version": "1.1.4",
          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
          "dev": true,
          "optional": true
        },
        "has-flag": {
          "version": "4.0.0",
          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
          "dev": true,
          "optional": true
        },
        "loader-utils": {
          "version": "2.0.0",
          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
          "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "big.js": "^5.2.2",
            "emojis-list": "^3.0.0",
            "json5": "^2.1.2"
          }
        },
        "source-map": {
          "version": "0.6.1",
          "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
@@ -1743,6 +1800,16 @@
          "requires": {
            "figgy-pudding": "^3.5.1",
            "minipass": "^3.1.1"
          }
        },
        "supports-color": {
          "version": "7.2.0",
          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
          "dev": true,
          "optional": true,
          "requires": {
            "has-flag": "^4.0.0"
          }
        },
        "terser-webpack-plugin": {
@@ -1760,6 +1827,18 @@
            "source-map": "^0.6.1",
            "terser": "^4.6.12",
            "webpack-sources": "^1.4.3"
          }
        },
        "vue-loader-v16": {
          "version": "npm:vue-loader@16.8.1",
          "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.1.tgz",
          "integrity": "sha512-V53TJbHmzjBhCG5OYI2JWy/aYDspz4oVHKxS43Iy212GjGIG1T3EsB3+GWXFm/1z5VwjdjLmdZUFYM70y77vtQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "chalk": "^4.1.0",
            "hash-sum": "^2.0.0",
            "loader-utils": "^2.0.0"
          }
        }
      }
@@ -4410,19 +4489,11 @@
      }
    },
    "echarts": {
      "version": "5.1.1",
      "resolved": "https://registry.nlark.com/echarts/download/echarts-5.1.1.tgz",
      "integrity": "sha1-sYbxYvAXxVXP1nsS7eZ2K9w939o=",
      "version": "4.9.0",
      "resolved": "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz",
      "integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==",
      "requires": {
        "tslib": "2.0.3",
        "zrender": "5.1.0"
      },
      "dependencies": {
        "tslib": {
          "version": "2.0.3",
          "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-2.0.3.tgz",
          "integrity": "sha1-jgdBrEX8DCJuWKF7/D5kubxsphw="
        }
        "zrender": "4.3.2"
      }
    },
    "ee-first": {
@@ -10332,87 +10403,6 @@
        }
      }
    },
    "vue-loader-v16": {
      "version": "npm:vue-loader@16.5.0",
      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.5.0.tgz",
      "integrity": "sha512-WXh+7AgFxGTgb5QAkQtFeUcHNIEq3PGVQ8WskY5ZiFbWBkOwcCPRs4w/2tVyTbh2q6TVRlO3xfvIukUtjsu62A==",
      "dev": true,
      "optional": true,
      "requires": {
        "chalk": "^4.1.0",
        "hash-sum": "^2.0.0",
        "loader-utils": "^2.0.0"
      },
      "dependencies": {
        "ansi-styles": {
          "version": "4.3.0",
          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-convert": "^2.0.1"
          }
        },
        "chalk": {
          "version": "4.1.2",
          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
          "dev": true,
          "optional": true,
          "requires": {
            "ansi-styles": "^4.1.0",
            "supports-color": "^7.1.0"
          }
        },
        "color-convert": {
          "version": "2.0.1",
          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-name": "~1.1.4"
          }
        },
        "color-name": {
          "version": "1.1.4",
          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
          "dev": true,
          "optional": true
        },
        "has-flag": {
          "version": "4.0.0",
          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
          "dev": true,
          "optional": true
        },
        "loader-utils": {
          "version": "2.0.0",
          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
          "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "big.js": "^5.2.2",
            "emojis-list": "^3.0.0",
            "json5": "^2.1.2"
          }
        },
        "supports-color": {
          "version": "7.2.0",
          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
          "dev": true,
          "optional": true,
          "requires": {
            "has-flag": "^4.0.0"
          }
        }
      }
    },
    "vue-router": {
      "version": "3.4.9",
      "resolved": "https://registry.npm.taobao.org/vue-router/download/vue-router-3.4.9.tgz?cache=0&sync_timestamp=1607347284428&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-router%2Fdownload%2Fvue-router-3.4.9.tgz",
@@ -11269,19 +11259,9 @@
      }
    },
    "zrender": {
      "version": "5.1.0",
      "resolved": "https://registry.npm.taobao.org/zrender/download/zrender-5.1.0.tgz?cache=0&sync_timestamp=1618215769844&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fzrender%2Fdownload%2Fzrender-5.1.0.tgz",
      "integrity": "sha1-tqhMOqfMxmQu4FGZAcpMCDXE2F4=",
      "requires": {
        "tslib": "2.0.3"
      },
      "dependencies": {
        "tslib": {
          "version": "2.0.3",
          "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-2.0.3.tgz",
          "integrity": "sha1-jgdBrEX8DCJuWKF7/D5kubxsphw="
        }
      }
      "version": "4.3.2",
      "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.2.tgz",
      "integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g=="
    }
  }
}
package.json
@@ -9,7 +9,7 @@
  "dependencies": {
    "axios": "^0.19.2",
    "core-js": "^3.6.5",
    "echarts": "^5.1.1",
    "echarts": "^4.8.0",
    "js-md5": "^0.7.3",
    "vant": "^2.8.1",
    "vue": "^2.6.11",
src/assets/js/api.js
@@ -124,4 +124,77 @@
        url: `WorkAlarmAction!dispatchTask`,
        data: 'json=' + JSON.stringify(data)
    })
}
/**
 * 查询机房信息
 * 参数:json = {"StationName1":"北京市","StationName2":"市辖区","StationName5":"海淀区"}
 */
export const searchStation = (params) => {
    return axios({
        method: "post",
        url: "BattInfAction!serchAllStationName",
        data: "json=" + JSON.stringify(params)
    })
}
/**
 * 查询电池组信息
 * 参数:json = {"StationName1":"北京市","StationName2":"市辖区","StationName5":"海淀区","StationName3":"紫晶科技机房"}
 */
export const searchBattInfo = (params) => {
    return axios({
        method: "post",
        url: "BattInfAction!serchAllBattinf",
        data: "json=" + JSON.stringify(params)
    })
}
/**
 * 根据电池组ID查询电池组信息
 * @param data
 * @returns {AxiosPromise}
 */
export const getBattGroupInfo = (params) => {
    return axios({
        method: 'post',
        url: 'BattInfAction!findByBattGroupId',
        data: 'bif.BattGroupId=' + params,
    })
}
/**
 * 查询电池告警参数
 * 参数:json={"dev_id":910000022}
 */
export const realTimeAlarm = (params) => {
    return axios({
        method: "post",
        url: "Dev_paramAction!serchParamById",
        data: "json=" + JSON.stringify(params)
    })
}
/**
 * 根据电池组id查询该电池组中所有电池信息  (图表数据)
 * json={"BattGroupId":1005074}
 */
export const realTimeSearch = (params) => {
    return axios({
        method: "post",
        url: "Batt_rtdataAction_serchByCondition",
        data: "json=" + JSON.stringify(params)
    })
}
/**
 * 根据电池组id查询电池组实时组端信息
 * 参数:rtstate.battGroupId=1005074
 */
export const realTimeGroup = (params) => {
    return axios({
        method: "post",
        url: "Batt_rtstateAction_serchByCondition",
        data: "rtstate.battGroupId=" + params
    })
}
src/assets/js/const_aio.js
@@ -1,14 +1,14 @@
export default {
    // workstates: ["在线浮充","预充电","核容测试","停电放电","内阻测试","K1/D1测试", '离线养护测试', '未知'],
    // alarmstates: ["继电器K1告警","通讯告警","设备过温告警","二极管D1告警"],
    // stopreasons: {
    // workstates: ["在线浮充","预充电","核容测试","停电放电","内阻测试","K1/D1测试", '离线养护测试', '未知'],
    // alarmstates: ["继电器K1告警","通讯告警","设备过温告警","二极管D1告警"],
    // stopreasons: {
    //     0:'设备掉电',1:'手动终止',2:'放电时间到',3:'放电容量到',4:'单体电压下限到',5:'单体温度上限到',6:'组端电压下限到',
    //     7:'市电中断',8:'单体模块通信异常',9:'存储数据满',10:'机内温度异常',11:'放电电流异常',12:'后台通信中断',13:'内部程序异常',
    //     14:'电源电压高',15:'协议转通信异常',16:'其他',27:'其他设备在工作',28:'其他设备故障停止',29:'电压过高或过低',30:'干接点故障',
    //     31:'单体异常',32:'电压输入过高或过低',33: '电池电流异常', 34:'未知'
    // },
    // failreasons: {
    //     0:'无', 1:'暂停',2:'正在放电测试',3:'正在等待放电',4:'正在限流充电',5:'正在直连充电',6:'正在等待充电',7:'放电时间到停止',
    // },
    // failreasons: {
    //     0:'无', 1:'暂停',2:'正在放电测试',3:'正在等待放电',4:'正在限流充电',5:'正在直连充电',6:'正在等待充电',7:'放电时间到停止',
    //     8:'放电容量到停止',9:'单体电压下限到停止',10:'组端电压下限到停止',11:'市电中断停止',12:'存储数据满停止',13:'机内温度异常停止',
    //     14:'放电电流过流停止',15:'后台通信中断停止',16:'负载模块通信中断停止',17:'选择模块通信中断停止',18:'负载模块放电过功率停止',
    //     19:'内部程序异常停止',20:'市电恢复停止升压放电',21:'充电过程中市电中断',22:'组端电压下限',23:'单体温度上限到停止',24:'在线电压异常高停止',
@@ -98,7 +98,7 @@
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        },
        //截止电流
        CharSotpCurr: {
            pattern: /^[0-9]{1,3}$/,
@@ -359,14 +359,14 @@
    //     }
    // ],
    // getItemByName(name, list) {
    //     let result = false;
    //     for(let i=0; i<list.length; i++) {
    //         let item = list[i];
    //         if(item.name == name) {
    //             result = item;
    //             break;
    //     let result = false;
    //     for(let i=0; i<list.length; i++) {
    //         let item = list[i];
    //         if(item.name == name) {
    //             result = item;
    //             break;
    //         }
    //     }
    //     return result;
    //     return result;
    // }
};
src/assets/units/function/Timeout.js
New file
@@ -0,0 +1,67 @@
// 延时计时器
function Timeout(name) {
    this.timer = null;
    this.time = '';
    this.callback = '';
    this.workState = false;
    this.name = name?name:-33;
}
// 开启计时器并添加
Timeout.prototype.start = function(callback, time, exe) {
    // 配置执行函数
    if(typeof callback == 'function' && typeof time == 'number') {
        this.callback = callback;
        this.time = time;
        // 获取缓存的session
        let name = sessionStorage.getItem('acTabs');
        if(exe != 'exe') {
            this.workState = true;
            callback();
        }else {
            // 已经停止了
            if(!this.workState) {
                return;
            }
            // 清除计时器
            clearTimeout(this.timer);
            if(this.name == -33 || this.name == name) {
                this.timer = setTimeout(callback, time);
            }else {
                setTimeout(()=>{
                    this.open();
                }, 300);
            }
        }
    }else {
        console.warn('未完整配置参数!');
    }
};
// 开启计时器
Timeout.prototype.open = function() {
    var callback = this.callback;
    var time = this.time;
    this.start(callback, time, 'exe');
};
// 关闭计时器
Timeout.prototype.stop = function() {
    clearTimeout(this.timer);
    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/assets/units/function/formatSeconds.js
New file
@@ -0,0 +1,35 @@
/**
 * 将秒转化成时:分:秒
 *
 * @param   {[Number]}  value  秒数
 *
 * @return  {[String]}         00:00:00
 */
function formatSeconds(value) {
    if(value<=0){
        value = 0;
    }
    var theTime = parseInt(value);// 秒
    var theTime1 = 0;// 分
    var theTime2 = 0;// 小时
    // alert(theTime);
    if(theTime >= 60) {
        theTime1 = parseInt(theTime/60);
        theTime = parseInt(theTime%60);
        //alert(theTime1+"-"+theTime);
        if(theTime1 >= 60) {
            theTime2 = parseInt(theTime1/60);
            theTime1 = parseInt(theTime1%60);
        }
    }
    var result = (theTime<10?"0":"")+parseInt(theTime);
    if(theTime1 >= 0) {
        result =(theTime1<10?"0":"")+parseInt(theTime1)+":"+result;
    }
    if(theTime2 >= 0) {
        result =(theTime2<10?"0":"")+parseInt(theTime2)+":"+result;
    }
    return result;
}
export default formatSeconds;
src/assets/units/function/getBarNum.js
New file
@@ -0,0 +1,28 @@
/**
 * 获取柱状图的重要的数据
 *
 * @param   {[type]}  data  柱状图数据
 *
 * @return  {[type]}        [return description]
 */
function getBarNum(data) {
    let result = {};
    let arr = [];
    let sum = 0;
    data.forEach(item=> {
        let val = Number(item[1]);
        arr.push(val);
        sum += val;
    });
    // 获取平均值
    let avg = data.length>0?sum/data.length:0;
    return {
        min: arr.length>0?Math.min.apply(null, arr):0,
        max: arr.length>0?Math.max.apply(null, arr):0,
        sum: sum,
        avg: avg,
    }
}
export default getBarNum;
src/assets/units/index.js
@@ -37,6 +37,15 @@
//替换上传文件地址头部
import getStationSrc from './function/getStationSrc'
//将秒转化成时:分:秒
import formatSeconds from './function/formatSeconds'
//计时器定时查询
import Timeout from './function/Timeout'
//获取柱状图的重要的数据
import getBarNum from './function/getBarNum'
export default {
    deepClone,
    deepMerge,
@@ -50,5 +59,8 @@
    toThousands,
    pageTotal,
    convertToPinyin,
    getStationSrc
    getStationSrc,
    formatSeconds,
    Timeout,
    getBarNum,
}
src/components/chart/BarChart.vue
New file
@@ -0,0 +1,362 @@
<template>
    <div class="e-chart-root" @dblclick="fullScreen" :class="{'full-screen': fullScreenState}">
        <div class="e-chart-container">
            <div class="e-chart" :id="id" :ref="id"></div>
            <div class="e-chart-tools" v-if="showTools">
                <i class="iconfont el-icon-yanjingkejian" :class="eleClass" @click="changeEyeState"></i>
            </div>
        </div>
    </div>
</template>
<script>
// 引入 ECharts 主模块
import ECharts from "echarts/lib/echarts";
//引入折线图
import "echarts/lib/chart/bar";
//引入提示框
import "echarts/lib/component/tooltip";
//引入标题
import "echarts/lib/component/title";
//引入图例标志
import "echarts/lib/component/legend";
//区域缩放
import "echarts/lib/component/dataZoom";
//markeline
import "echarts/lib/component/markLine"
// 引入自定义主题
import "./theme/transparent"
export default {
    props: {
        id: {
            type: String,
            required: true,
        },
        unit: {
            type: String,
            default: '',
        },
        showTools: {
            type: Boolean,
            default: false,
        },
        showLabel: {
            type: Boolean,
            default: true,
        },
        maxColor: {
            type: String,
            default: 'green',
        },
        minColor: {
            type: String,
            default: 'red',
        },
        rightMenu: {
            type: Boolean,
            default: false,
        }
    },
    data() {
        return {
            fullScreenState: false,
            eye: true,
        }
    },
    methods: {
        getOption(opt) {
            let unit = this.unit;
            let alarmVol = this.getAlarmVal(opt);
            // 整体配置项
            let option = {
                animation: false,
                color: this.getColor(opt),
                title: this.getTitle(opt),
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {            // 坐标轴指示器,坐标轴触发有效
                        type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
                    },
                    formatter(params) {
                        var res = params[0].name + '<br/>';
                        params.forEach(item => {
                            res += item.marker;
                            res += item.seriesName;
                            res += ' : ' + item.data[1] + unit + '</br>';
                        });
                        return res;
                    }
                },
                grid: {
                    left: '1%',
                    right: '1%',
                    bottom: '2%',
                    containLabel: true
                },
                xAxis: [
                    {
                        type: 'category',
                        axisLine: {
                            show: true,
                            lineStyle: {
                                color: '#b3b3b3',
                            }
                        },
                        axisLabel: {
                            color: '#737474',
                            textStyle: {
                                fontSize: 10
                            },
                        },
                    }
                ],
                yAxis: [
                    {
                        type: 'value',
                        axisLine: {
                            show: true,
                            lineStyle: {
                                color: '#b3b3b3',
                            }
                        },
                        axisLabel: {
                            color: '#737474',
                            textStyle: {
                                fontSize: 10
                            },
                        },
                        splitLine: {
                            show: true,
                            lineStyle: {
                                color: '#e8eff8',
                            }
                        },
                        min: function (data) {
                            let min = data.min;
                            if (min == Infinity) {
                                return 0;
                            }
                            min = alarmVol.low == false ? min : alarmVol.low < min ? alarmVol.low : min;
                            return Number((min - min * 0.2).toFixed(2));
                        },
                        max: function (data) {
                            let max = data.max;
                            if (max == -Infinity) {
                                max = 1;
                            }
                            max = alarmVol.high == false ? max : alarmVol.high > max ? alarmVol.high : max;
                            return Number((max + max * 0.2).toFixed(2));
                        }
                    }
                ],
                series: this.getSeries(opt),
            };
            return option;
        },
        setOption(opt) {
            let option = this.getOption(opt);
            // 清理画布
            this.$G.chartManage.get(this.id).clear();
            // 设置配置项
            this.$G.chartManage.get(this.id).setOption(option);
        },
        getAlarmVal(opt) {
            let result = {
                low: false,
                high: false
            };
            if (opt && opt.series && opt.series.length != 0) {
                let markLine = opt.series[0].markLine;
                if (opt.series && markLine && markLine.data) {
                    result.low = markLine.data[0].yAxis;
                    result.high = markLine.data[1].yAxis;
                }
            }
            return result;
        },
        getColor(opt) {     // 配置自定义颜色
            // 未配置自定义颜色
            if (!opt || !opt.color) {
                return []
            }
            // 返回颜色
            return opt.color;
        },
        getTitle(opt) {     // 配置标题
            // 未配置标题
            if (!opt || !opt.title) {
                return {
                    show: false,
                };
            }
            // 返回标题
            return opt.title;
        },
        getSeries(opt) {    // 设置series
            // 未配置series
            if (!opt || !opt.series) {
                return [];
            }
            let minColor = this.minColor;
            let maxColor = this.maxColor;
            // 设置配置项
            let series = opt.series.map(item => {
                let max = this.getMax(item.data);
                let min = this.getMin(item.data);
                item.type = "bar";
                // 显示数据
                item.label = {
                    // show: this.showChartLabel,
                    show: false,
                    position: 'top',
                    color: '#737474',
                };
                // 设置颜色
                if (item.hColor) {
                    // 设置背景
                    item.itemStyle = {
                        color: item.hColor,
                    };
                } else {
                    // 设置背景
                    item.itemStyle = {
                        color: function (value) {
                            let val = value.value[1];
                            if (val == max) {
                                return maxColor;
                            } else if (val == min) {
                                return minColor;
                            }
                        }
                    };
                }
                return item;
            });
            // 返回
            return series;
        },
        getMax(list) {
            let arr = list.map(item => {
                return item[1];
            });
            return Math.max.apply(null, arr);
        },
        getMin(list) {
            let arr = list.map(item => {
                return item[1];
            });
            return Math.min.apply(null, arr);
        },
        fullScreen() {
            this.fullScreenState = this.fullScreenState ? false : true;
            this.$nextTick(() => {
                // 重置大小
                this.$G.chartManage.get(this.id).resize();
            });
        },
        resize() {
            // 重置大小
            this.$G.chartManage.get(this.id).resize();
        },
        changeEyeState() {
            this.eye = this.eye ? false : true;
            let option = this.$G.chartManage.get(this.id).getOption();
            this.setOption(option);
        }
    },
    computed: {
        eleClass() {
            return this.eye ? "el-icon-yanjingkejian" : "el-icon-yanjing-bukejian";
        },
        showChartLabel() {
            return this.showLabel && this.eye ? true : false;
        }
    },
    mounted() {
        let self = this;
        this.$refs[this.id].oncontextmenu = function () {
            return false;
        }
        // 基于准备好的dom,初始化echarts实例
        let chart = ECharts.init(this.$refs[this.id], 'transparent');
        // 将图表添加到图表管理
        this.$G.chartManage.set(this.id, chart);
        // 设置配置项
        this.setOption();
        // 点击事件
        chart.getZr().on('mousedown', function (params) {
            if (params.which == 3) {
                let pointInPixel = [params.offsetX, params.offsetY];
                if (chart.containPixel('grid', pointInPixel)) {
                    /*单击图标X轴数据,打开详情*/
                    let xIndex = chart.convertFromPixel({ seriesIndex: 0 }, pointInPixel)[0];
                    self.$emit('right-click', {
                        x: params.event.clientX + 16,
                        y: params.event.clientY + 16,
                        xIndex: xIndex
                    });
                }
            }
        });
        // 根据功能屏蔽右键菜单
        if (this.rightMenu) {
            document.getElementById(this.id).oncontextmenu = function () {
                return false;
            };
        }
    }
}
</script>
<style scoped>
.e-chart-root,
.e-chart-container,
.e-chart {
    height: 100%;
    box-sizing: border-box;
}
.e-chart-root.full-screen .e-chart-container {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-size: 100% 100%;
    z-index: 9999;
}
.e-chart-tools {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 9;
}
.e-chart-tools .iconfont {
    margin-left: 8px;
    font-size: 24px;
    cursor: pointer;
    color: #00fefe;
}
.e-chart-tools .iconfont:hover {
    color: #04b1b1;
}
.e-chart-tools .iconfont:active {
    color: #ff0000;
}
</style>
src/components/chart/js/getMarkLineData.js
New file
@@ -0,0 +1,48 @@
function getMarkLineData() {
    return [
        {
            name: '低告警',
            yAxis: 0,
            lineStyle: {
                width: 2,
                color: "#f9b253",
            },
            label: {
                color: "#000",
                fontSize: 16,
                formatter:"{b}:{c}",
                position: 'middle',
                padding: [6, 4, 2, 4],
                backgroundColor: "#f9b253",
                borderWidth: 2,
                borderColor: "#ffffff",
            },
            emphasis: {
                type: "dashed",
            },
        },
        {
            name: '高告警',
            yAxis: 0,
            lineStyle: {
                width: 2,
                color: "#f83030",
            },
            label: {
                color: "#ffffff",
                fontSize: 16,
                formatter:"{b}:{c}",
                position: 'middle',
                padding: [6, 4, 2, 4],
                backgroundColor: "#f83030",
                borderWidth: 2,
                borderColor: "#ffffff",
            },
            emphasis: {
                type: "dashed",
            },
        },
    ]
}
export default getMarkLineData;
src/components/chart/js/getYMax.js
New file
@@ -0,0 +1,13 @@
function getYMax(data) {
    let max = data.max;
    if (max == -Infinity) {
        return 1;
    }
    if (max > 0) {
        Math.ceil(max * 1.01);
    } else {
        return Math.floor(max * 0.9);
    }
}
export default getYMax;
src/components/chart/js/getYMin.js
New file
@@ -0,0 +1,13 @@
function getYMin(data) {
    let min = data.min;
    if (min == Infinity) {
        return 0;
    }
    if (min > 0) {
        return Math.floor(min * 0.9);
    } else {
        return Math.floor(min * 1.01);
    }
}
export default getYMin;
src/components/chart/theme/EleResize.js
New file
@@ -0,0 +1,107 @@
const EleResize = {
  _handleResize: function(e) {
    var ele = e.target || e.srcElement
    var trigger = ele.__resizeTrigger__
    if (trigger) {
      var handlers = trigger.__z_resizeListeners
      if (handlers) {
        var size = handlers.length
        for (var i = 0; i < size; i++) {
          var h = handlers[i]
          var handler = h.handler
          var context = h.context
          handler.apply(context, [e])
        }
      }
    }
  },
  _removeHandler: function(ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (handlers) {
      var size = handlers.length
      for (var i = 0; i < size; i++) {
        var h = handlers[i]
        if (h.handler === handler && h.context === context) {
          handlers.splice(i, 1)
          return
        }
      }
    }
  },
  _createResizeTrigger: function(ele) {
    var obj = document.createElement('object')
    obj.setAttribute('style',
      'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -1;'
    )
    obj.onload = EleResize._handleObjectLoad
    obj.type = 'text/html'
    ele.appendChild(obj)
    obj.data = 'about:blank'
    return obj
  },
  _handleObjectLoad: function(evt) {
    this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__
    this.contentDocument.defaultView.addEventListener('resize', EleResize._handleResize)
  }
}
if (document.attachEvent) { // ie9-10
  EleResize.on = function(ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (!handlers) {
      handlers = []
      ele.__z_resizeListeners = handlers
      ele.__resizeTrigger__ = ele
      ele.attachEvent('onresize', EleResize._handleResize)
    }
    handlers.push({
      handler: handler,
      context: context
    })
  }
  EleResize.off = function(ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (handlers) {
      EleResize._removeHandler(ele, handler, context)
      if (handlers.length === 0) {
        ele.detachEvent('onresize', EleResize._handleResize)
        delete ele.__z_resizeListeners
      }
    }
  }
} else {
  EleResize.on = function(ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (!handlers) {
      handlers = []
      ele.__z_resizeListeners = handlers
      if (getComputedStyle(ele, null).position === 'static') {
        ele.style.position = 'relative'
      }
      var obj = EleResize._createResizeTrigger(ele)
      ele.__resizeTrigger__ = obj
      obj.__resizeElement__ = ele
    }
    handlers.push({
      handler: handler,
      context: context
    })
  }
  EleResize.off = function(ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (handlers) {
      EleResize._removeHandler(ele, handler, context)
      if (handlers.length === 0) {
        var trigger = ele.__resizeTrigger__
        if (trigger) {
          trigger.contentDocument.defaultView.removeEventListener('resize', EleResize._handleResize)
          ele.removeChild(trigger)
          delete ele.__resizeTrigger__
        }
        delete ele.__z_resizeListeners
      }
    }
  }
}
export default EleResize
src/components/chart/theme/transparent.js
New file
@@ -0,0 +1,178 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
// 引入 ECharts 主模块
import ECharts from "echarts/lib/echarts";
var contrastColor = '#00feff';
var axisCommon = function () {
  return {
    axisLine: {
      lineStyle: {
        color: contrastColor
      }
    },
    axisTick: {
      show: false,
      lineStyle: {
        color: contrastColor
      }
    },
    axisLabel: {
      show: true,
      textStyle: {
        color: contrastColor
      }
    },
    splitLine: {
      show: false,
      lineStyle: {
        type: 'solid',
        color: '#0b388a'
      }
    },
    splitArea: {
      areaStyle: {
        color: contrastColor
      }
    }
  };
};
var colorPalette = ['#15E3F3', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53', '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'];
var theme = {
  color: colorPalette,
  backgroundColor: '',
  tooltip: {
    axisPointer: {
      lineStyle: {
        color: contrastColor
      },
      crossStyle: {
        color: contrastColor
      },
      label: {
        color: '#000'
      }
    }
  },
  legend: {
    textStyle: {
      color: contrastColor
    }
  },
  textStyle: {
    color: contrastColor
  },
  title: {
    textStyle: {
      color: contrastColor
    }
  },
  toolbox: {
    show: false,
    iconStyle: {
      normal: {
        borderColor: contrastColor
      }
    }
  },
  dataZoom: {
    textStyle: {
      color: contrastColor
    }
  },
  visualMap: {
    textStyle: {
      color: contrastColor
    }
  },
  timeline: {
    lineStyle: {
      color: contrastColor
    },
    itemStyle: {
      normal: {
        color: colorPalette[1]
      }
    },
    label: {
      normal: {
        textStyle: {
          color: contrastColor
        }
      }
    },
    controlStyle: {
      normal: {
        color: contrastColor,
        borderColor: contrastColor
      }
    }
  },
  timeAxis: axisCommon(),
  logAxis: axisCommon(),
  valueAxis: axisCommon(),
  categoryAxis: axisCommon(),
  line: {
    symbol: 'circle'
  },
  graph: {
    color: colorPalette
  },
  gauge: {
    title: {
      textStyle: {
        color: contrastColor
      }
    }
  },
  candlestick: {
    itemStyle: {
      normal: {
        color: '#FD1050',
        color0: '#0CF49B',
        borderColor: '#FD1050',
        borderColor0: '#0CF49B'
      }
    }
  }
};
ECharts.registerTheme('transparent', theme);
src/global/ChartManage.js
New file
@@ -0,0 +1,79 @@
// 引入 ECharts 主模块
import ECharts from "echarts/lib/echarts"
function ChartManage() {
    this.charts = {};
    this.group = '';
}
/**
 * [setChart description]
 *
 * @param   {String}  id     chart对象的id
 * @param   {Echarts}  chart  echarts对象
 */
ChartManage.prototype.set = function(id, chart) {
    // 将id和chart绑定
    this.charts[id] = chart;
};
ChartManage.prototype.get = function(id) {
    return this.charts[id]?this.charts[id]:-1;
};
ChartManage.prototype.del = function(id) {
    let chart = this.get(id);
    if(chart != -1) {
        // 销毁echarts
        chart.dispose();
        delete this.charts[id];
    }
};
ChartManage.prototype.resize = function(id) {
    let chart = this.get(id);
    if(chart != -1) {
        chart.resize();
    }
};
ChartManage.prototype.connect = function(ids) {
    let self = this;
    let groups = ids.map(function(id) {
        let chart = self.get(id);
        if(chart != -1) {
            return chart;
        }
    });
    // 清空分组
    this.disconnect();
    this.group = ECharts.connect(groups);
}
ChartManage.prototype.disconnect = function() {
    ECharts.disconnect(this.group);
    // 清除分组信息
    Object.keys(this.charts).forEach(id=>{
        delete this.charts[id].group;
    });
}
ChartManage.prototype.changeDataZoom = function(id, range) {
    let chart = this.get(id);
    if(chart != -1) {
        chart.dispatchAction({
            type: 'dataZoom',
            batch: [
                {
                    // 第一个 dataZoom 组件
                    start: range[0],
                    end: range[1],
                }
            ]
        });
    }
}
export default new ChartManage();
src/global/common.js
New file
@@ -0,0 +1,43 @@
import store from "@/store";
//格式化时间
Date.prototype.format = function (format) {
    var o = {
        "M+": this.getMonth() + 1, //month
        "d+": this.getDate(), //day
        "h+": this.getHours(), //hour
        "m+": this.getMinutes(), //minute
        "s+": this.getSeconds(), //second
        "q+": Math.floor((this.getMonth() + 3) / 3), //quarter
        "S": this.getMilliseconds() //millisecond
    };
    if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
        (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
        if (new RegExp("(" + k + ")").test(format))
            format = format.replace(RegExp.$1,
                RegExp.$1.length == 1 ? o[k] :
                    ("00" + o[k]).substr(("" + o[k]).length));
    return format;
};
// 对toFixed数字保留位数二次封装(ps:toFixed返回的是字符串)
Number.prototype.toHold = function (value) {
    var hold = this.toFixed(value);
    hold = Number(hold);
    return hold;
};
/* eslint-disable */
; (function (doc, win) {
    let docEl = doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        recalc = function () {
            let clientWidth = docEl.clientWidth;
            if (!clientWidth) return;
            let fontSize = 20 * (clientWidth / 1920);
            docEl.style.fontSize = fontSize + 'px';
        };
    if (!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
src/global/index.js
New file
@@ -0,0 +1,5 @@
import chartManage from './ChartManage'
export default {
    chartManage
};
src/main.js
@@ -40,7 +40,8 @@
  ImagePreview,
  IndexBar,
  IndexAnchor,
  SwipeCell
  SwipeCell,
  Cascader,
} from 'vant';
import App from './App.vue'
@@ -48,12 +49,14 @@
import store from './store'
import 'vant/lib/index.css'; // 全局引入样式
import units from './assets/units'
import G from './global'
import "./global/common"
Vue.config.productionTip = false
Vue.use(Toast).use(Notify).use(Picker).use(Form).use(Image).use(Dialog).use(Tabbar).use(TabbarItem).use(CellGroup).use(Cell).use(Icon).use(Button).use(NavBar).use(Grid).use(GridItem).use(Row).use(Col).use(Collapse).use(CollapseItem).use(Steps).use(Step).use(Divider).use(Switch).use(Tag).use(Search).use(Field).use(Uploader).use(Popup).use(CheckboxGroup).use(Checkbox).use(PullRefresh).use(ActionSheet).use(List).use(Tab).use(Tabs).use(Empty).use(ImagePreview).use(IndexBar).use(IndexAnchor).use(SwipeCell).use(Cascader);
Vue.use(Toast).use(Notify).use(Picker).use(Form).use(Image).use(Dialog).use(Tabbar).use(TabbarItem).use(CellGroup).use(Cell).use(Icon).use(Button).use(NavBar).use(Grid).use(GridItem).use(Row).use(Col).use(Collapse).use(CollapseItem).use(Steps).use(Step).use(Divider).use(Switch).use(Tag).use(Search).use(Field).use(Uploader).use(Popup).use(CheckboxGroup).use(Checkbox).use(PullRefresh).use(ActionSheet).use(List).use(Tab).use(Tabs).use(Empty).use(ImagePreview).use(IndexBar).use(IndexAnchor).use(SwipeCell);
Vue.prototype.$G = G;
Vue.prototype.$notify = Notify;
Vue.prototype.$dialog = Dialog;
Vue.prototype.$toast = Toast;
src/pages/alarm-details.vue
@@ -1,13 +1,6 @@
<template>
    <div class="alarm-details">
        <van-nav-bar
            title="告警详情"
            @click-left="$router.back()"
            left-arrow
            fixed
            safe-area-inset-top
            placeholder
        >
        <van-nav-bar title="告警详情" @click-left="$router.back()" left-arrow fixed safe-area-inset-top placeholder>
        </van-nav-bar>
        <div class="detailsCon">
            <div class="card">
@@ -59,39 +52,19 @@
                </div>
                <div class="commonTitle">
                    <div class="label">订单状态:</div>
                    <div
                        class="text"
                        v-if="alarmInfo.status == 2 && stepsActive == 0"
                        style="color: #eac406"
                    >
                    <div class="text" v-if="alarmInfo.status == 2 && stepsActive == 0" style="color: #eac406">
                        处理中
                    </div>
                    <div
                        class="text"
                        v-else-if="alarmInfo.status == 2 && stepsActive == 1"
                        style="color: #eac406"
                    >
                    <div class="text" v-else-if="alarmInfo.status == 2 && stepsActive == 1" style="color: #eac406">
                        待审核
                    </div>
                    <div
                        class="text"
                        v-else-if="alarmInfo.status == 3"
                        style="color: #07c160"
                    >
                    <div class="text" v-else-if="alarmInfo.status == 3" style="color: #07c160">
                        已完成
                    </div>
                    <div
                        class="text"
                        v-else-if="alarmInfo.status == 0"
                        style="color: #4b88f9"
                    >
                    <div class="text" v-else-if="alarmInfo.status == 0" style="color: #4b88f9">
                        待派发
                    </div>
                    <div
                        class="text"
                        v-else-if="alarmInfo.status == 1 && userPower == 0"
                        style="color: #4b88f9"
                    >
                    <div class="text" v-else-if="alarmInfo.status == 1 && userPower == 0" style="color: #4b88f9">
                        已派发
                    </div>
                    <div class="text" v-else style="color: #4b88f9">待处理</div>
@@ -107,14 +80,11 @@
                </van-steps>
            </div>
            <!-- 如果是进入审核状态 -->
            <div
                class="card"
                v-if="
            <div class="card" v-if="
                    (alarmInfo.status == 2 && stepsActive == 1) ||
                    (alarmInfo.status == 2 && stepsActive == 2) ||
                    alarmInfo.status == 3
                "
            >
                ">
                <div class="commonTitle cardTitle">告警处理:</div>
                <div class="commonTitle">
                    <div class="label">问题描述:</div>
@@ -125,25 +95,13 @@
                <div class="commonTitle">
                    <div class="label">处理前照片:</div>
                    <div class="text">
                        <div
                            class="van-uploader__wrapper"
                            v-if="
                        <div class="van-uploader__wrapper" v-if="
                                handleInfo.imageBefore &&
                                handleInfo.imageBefore.split(',').length > 0
                            "
                        >
                            <div
                                class="van-uploader__preview"
                                v-for="(item, i) in handleInfo.imageBefore.split(',')"
                                :key="i"
                                @click="toShowImgpreview(handleInfo.imageBefore.split(','))"
                            >
                            ">
                            <div class="van-uploader__preview" v-for="(item, i) in handleInfo.imageBefore.split(',')" :key="i" @click="toShowImgpreview(handleInfo.imageBefore.split(','))">
                                <div class="van-image van-uploader__preview-image">
                                    <img
                                        :src="$units.getStationSrc(item)"
                                        class="van-image__img"
                                        style="object-fit: cover"
                                    />
                                    <img :src="$units.getStationSrc(item)" class="van-image__img" style="object-fit: cover" />
                                </div>
                            </div>
                        </div>
@@ -158,25 +116,13 @@
                <div class="commonTitle">
                    <div class="label">处理后照片:</div>
                    <div class="text">
                        <div
                            class="van-uploader__wrapper"
                            v-if="
                        <div class="van-uploader__wrapper" v-if="
                                handleInfo.imageAfter &&
                                handleInfo.imageAfter.split(',').length > 0
                            "
                        >
                            <div
                                class="van-uploader__preview"
                                v-for="(item, i) in handleInfo.imageAfter.split(',')"
                                :key="i"
                                @click="toShowImgpreview(handleInfo.imageAfter.split(','))"
                            >
                            ">
                            <div class="van-uploader__preview" v-for="(item, i) in handleInfo.imageAfter.split(',')" :key="i" @click="toShowImgpreview(handleInfo.imageAfter.split(','))">
                                <div class="van-image van-uploader__preview-image">
                                    <img
                                        :src="$units.getStationSrc(item)"
                                        class="van-image__img"
                                        style="object-fit: cover"
                                    />
                                    <img :src="$units.getStationSrc(item)" class="van-image__img" style="object-fit: cover" />
                                </div>
                            </div>
                        </div>
@@ -194,53 +140,33 @@
                <div class="subBtn" @click="startHandle" v-if="alarmInfo.status == 1">
                    开始处理
                </div>
                <div
                    class="subBtn"
                    @click="toPage('edit')"
                    v-if="alarmInfo.status == 2 && stepsActive == 0"
                >
                <div class="subBtn" @click="toPage('edit')" v-if="alarmInfo.status == 2 && stepsActive == 0">
                    继续处理
                </div>
            </div>
            <!-- 如果是维护员并且实时告警已自动消除 -->
            <div
                class="subBtn"
                @click="completeAlarm"
                v-else-if="userPower != 0 && isNoAlarm"
            >
            <div class="subBtn" @click="completeAlarm" v-else-if="userPower != 0 && isNoAlarm">
                确认告警自动消除
            </div>
            <!-- 如果是管理员未派发 -->
            <div v-if="userPower == 0 && alarmInfo.status == 0">
                <div class="card">
                    <div class="commonTitle cardTitle">指派人员:</div>
                    <van-cell
                        :title="assignUser.UName"
                        is-link
                        @click="
                    <van-cell :title="assignUser.UName" is-link @click="
                            $router.push({
                                path: '/userList',
                                query: {
                                    stationId: alarmInfo.stationId,
                                },
                            })
                        "
                    />
                        " />
                </div>
                <div class="subBtn" @click="toAssign">确认指派</div>
            </div>
            <!-- 如果是管理员待审核 -->
            <div v-if="userPower == 0 && alarmInfo.status == 2 && stepsActive == 1">
                <div class="card">
                    <van-field
                        v-model="handleInfo.note"
                        rows="2"
                        autosize
                        label="审核意见"
                        type="textarea"
                        placeholder="请输入审核意见…"
                        show-word-limit
                    />
                    <van-field v-model="handleInfo.note" rows="2" autosize label="审核意见" type="textarea" placeholder="请输入审核意见…" show-word-limit />
                </div>
                <div class="btnCon">
                    <div class="subBtn" @click="suggest(3)">通过</div>
@@ -311,7 +237,6 @@
        if (assignUser) {
            this.assignUser = JSON.parse(assignUser)
        }
        console.log(this.alarmInfo)
        this.loadStatus()
    },
    destroyed() {
@@ -331,12 +256,11 @@
        },
        //确认指派
        toAssign() {
            this.$dialog
                .confirm({
            if (this.assignUser.UId) {
                this.$dialog.confirm({
                    title: "提示",
                    message: `是否确认把该告警指派给${this.assignUser.UName}?`,
                })
                .then(() => {
                }).then(() => {
                    let postData = [
                        {
                            id: this.alarmInfo.id,
@@ -355,10 +279,13 @@
                        .catch((err) => {
                            console.log(err)
                        })
                })
                .catch(() => {
                }).catch(() => {
                    // on cancel
                })
            } else {
                this.$toast('请选择指派人员!')
            }
        },
        //确认自动完成告警
        completeAlarm() {
src/pages/alarm-list.vue
New file
@@ -0,0 +1,295 @@
<template>
    <div class="indexWarp">
        <van-nav-bar title="告警列表" @click-left="$router.back()" left-arrow fixed safe-area-inset-top placeholder></van-nav-bar>
        <van-tabs v-model="active" color="#4B88F9" animated swipeable background="#ffffff">
            <van-tab :title="tab.title" v-for="(tab,i) in tabs" :key="i">
                <van-pull-refresh v-model="tab.refreshing" @refresh="onRefresh(tab)">
                    <van-list v-model="tab.loading" :finished="tab.finished" finished-text="没有更多了" @load="loadData(tab)">
                        <div class="pd-24">
                            <div class="listWarp">
                                <van-cell center is-link v-for="(item,i) in tab.listData" :key="i" @click="toPage(item)">
                                    <template #title>
                                        <div class="alarmTitle">
                                            <van-tag class="tag" v-if="item.alarmLevel==1">一级</van-tag>
                                            <van-tag class="tag" v-else-if="item.alarmLevel==2">二级</van-tag>
                                            <van-tag class="tag" v-else-if="item.alarmLevel==3">三级</van-tag>
                                            {{item.alarmName}}
                                        </div>
                                        <div class="time">{{item.alarmTime}}</div>
                                    </template>
                                </van-cell>
                            </div>
                        </div>
                    </van-list>
                </van-pull-refresh>
            </van-tab>
        </van-tabs>
    </div>
</template>
<script>
import {
    searchAllByUserIdAndStatus,
    getTaskListWithFlag
} from '@/assets/js/api'
import {
    mapState,
} from 'vuex';
export default {
    components: {},
    data() {
        return {
            active: 0,
            tabs: [],
            tabs1: [{
                title: '全部',
                listData: [],
                loading: false,
                finished: false,
                refreshing: false,
                page: {
                    pageSize: 12,
                    pageCurr: 0
                }
            }, {
                title: '待处理',
                listData: [],
                loading: false,
                finished: false,
                refreshing: false,
                page: {
                    pageSize: 12,
                    pageCurr: 0
                }
            }, {
                title: '处理中',
                listData: [],
                loading: false,
                finished: false,
                refreshing: false,
                page: {
                    pageSize: 12,
                    pageCurr: 0
                }
            }, {
                title: '已完成',
                listData: [],
                loading: false,
                finished: false,
                refreshing: false,
                page: {
                    pageSize: 12,
                    pageCurr: 0
                }
            }],
            tabs2: [{
                title: '待派发',
                listData: [],
                loading: false,
                finished: false,
                refreshing: false,
                page: {
                    pageSize: 12,
                    pageCurr: 0
                }
            }, {
                title: '已派发',
                listData: [],
                loading: false,
                finished: false,
                refreshing: false,
                page: {
                    pageSize: 12,
                    pageCurr: 0
                }
            }, {
                title: '待审核',
                listData: [],
                loading: false,
                finished: false,
                refreshing: false,
                page: {
                    pageSize: 12,
                    pageCurr: 0
                }
            }, {
                title: '已完成',
                listData: [],
                loading: false,
                finished: false,
                refreshing: false,
                page: {
                    pageSize: 12,
                    pageCurr: 0
                }
            }],
        }
    },
    computed: {
        ...mapState(['userPower']),
    },
    mounted() {
        this.loadData()
    },
    methods: {
        //请求数据总触发
        loadData(tab) {
            if (this.userPower == 0) {
                this.tabs = this.tabs2
                if (tab) {
                    this.managelLoadData(tab)
                } else {
                    this.managelLoadData(this.tabs[0])
                }
            } else {
                //请求维护员数据
                this.tabs = this.tabs1
                if (tab) {
                    this.maintainlLoadData(tab)
                } else {
                    this.maintainlLoadData(this.tabs[0])
                }
            }
        },
        //区管理员请求数据
        managelLoadData(tab) {
            // 将 loading 设置为 true,表示处于加载状态
            tab.loading = true;
            tab.page.pageCurr++
            let status = null
            status = this.active + 1
            let postData = {
                note: status,
                pageNum: tab.page.pageCurr,
                pageSize: tab.page.pageSize,
            }
            getTaskListWithFlag(postData).then((res) => {
                let resData = JSON.parse(res.data.result).data
                tab.loading = false;
                if (resData && resData.obj && resData.obj.length > 0) {
                    tab.listData.push(...resData.obj)
                }
                if (resData.pageNum >= resData.totalPage) {
                    tab.finished = true;
                } else {
                    tab.finished = false;
                }
            }).catch((err) => {
                tab.loading = false;
                tab.finished = true;
                console.log(err)
            });
        },
        //维护员请求数据
        maintainlLoadData(tab) {
            // 将 loading 设置为 true,表示处于加载状态
            tab.loading = true;
            tab.page.pageCurr++
            let status = null
            status = this.active + 1
            let postData = {
                note: status,
                pageNum: tab.page.pageCurr,
                pageSize: tab.page.pageSize,
            }
            searchAllByUserIdAndStatus(postData).then((res) => {
                let resData = JSON.parse(res.data.result).data
                tab.loading = false;
                if (resData && resData.obj && resData.obj.length > 0) {
                    tab.listData.push(...resData.obj)
                }
                if (resData.pageNum >= resData.totalPage) {
                    tab.finished = true;
                } else {
                    tab.finished = false;
                }
            }).catch((err) => {
                tab.loading = false;
                tab.finished = true;
                console.log(err)
            });
        },
        onRefresh(tab) {
            // 清空列表数据
            tab.finished = false;
            tab.listData = [];
            tab.refreshing = false;
            tab.page = {
                pageSize: 12,
                pageCurr: 0
            }
            // 重新加载数据
            this.loadData(tab);
        },
        toPage(item) {
            this.$router.push({
                path: '/alarmDetails',
                query: {
                    alarmData: JSON.stringify(item)
                }
            })
        },
    }
}
</script>
<style scoped>
.indexWarp {
    width: 100%;
    height: 100%;
    background: #f5f5f5;
}
.van-tabs {
    height: calc(100% - 92px);
    padding-top: 92px;
}
.van-tabs /deep/ .van-tabs__content {
    min-height: 100%;
    background: #f5f5f5;
}
.van-tabs /deep/ .van-tabs__wrap {
    position: fixed;
    left: 0;
    width: 100%;
    top: 92px;
    z-index: 9;
    border-bottom: 1px solid #ededed;
}
.pd-24 {
    padding: 24px;
}
.listWarp {
    background: #ffffff;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0px 4px 20px 0px rgba(75, 136, 249, 0.2);
}
.van-tabs /deep/ .van-cell__title {
    width: 90%;
}
.alarmTitle {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #323233;
    font-size: 24px;
}
.alarmTitle .tag {
    font-size: 20px;
    margin-right: 8px;
    background-color: #4b88f9;
}
.time {
    color: #969799;
    font-size: 20px;
}
</style>
src/pages/index.vue
File was deleted
src/pages/login.vue
@@ -1,171 +1,171 @@
<template>
  <div class="loginDiv">
    <div class="logo-bg"></div>
    <div class="login-con">
      <div class="appName">成都石化告警APP</div>
      <div class="login-title">登录</div>
      <div class="lineInput">
        <img src="../assets/img/login-ico1.png" class="ico1">
        <van-field v-model="userName" placeholder="请输入账号" />
      </div>
      <div class="lineInput">
        <img src="../assets/img/login-ico2.png" class="ico2">
        <van-field v-model="password" placeholder="请输入密码" type="password" />
      </div>
      <div class="subBtn" @click="submit">登录</div>
    </div>
    <div class="loginDiv">
        <div class="logo-bg"></div>
        <div class="login-con">
            <div class="appName">成都石化告警APP</div>
            <div class="login-title">登录</div>
            <div class="lineInput">
                <img src="../assets/img/login-ico1.png" class="ico1">
                <van-field v-model="userName" placeholder="请输入账号" />
            </div>
            <div class="lineInput">
                <img src="../assets/img/login-ico2.png" class="ico2">
                <van-field v-model="password" placeholder="请输入密码" type="password" />
            </div>
            <div class="subBtn" @click="submit">登录</div>
        </div>
  </div>
    </div>
</template>
<script>
  import {
    login
  } from "@/assets/js/api";
  import {
    mapMutations,
  } from 'vuex';
  export default {
    data() {
      return {
        userName: '',
        password: ''
      }
    },
    mounted() {
import {
    login
} from "@/assets/js/api";
import {
    mapMutations,
} from 'vuex';
export default {
    data() {
        return {
            userName: '',
            password: ''
        }
    },
    mounted() {
    },
    methods: {
      ...mapMutations(['setUserPower']),
      // 登录
      submit() {
        let self = this;
        if (self.userName == '') {
          self.$toast('请输入账号!')
          return
        }
        if (self.password == '') {
          self.$toast('请输入密码!')
          return
        }
        // 开启等待框
        this.$toast.loading({
          message: '登录中...',
          duration: 0
        })
        login(self.userName, self.password).then(res => {
          // 对结果进行处理
          self.handleLogin(res)
        }).catch(error => {
          // 关闭等待
          // console.log(error);
          self.$toast("网络异常");
        });
      },
      // 登录验证
      handleLogin(res) {
        let self = this;
        // 关闭等待
        // this.loading = false;
        let rs = JSON.parse(res.data.result);
        if (rs.code == 1) {
          self.$toast("登录成功!");
          sessionStorage.setItem('username', self.username);
          sessionStorage.setItem('userId', rs.data);
          self.setUserPower(rs.data2);
          self.$router.push({
            path: '/index'
          })
        } else {
          self.$toast(rs.msg);
        }
      },
    }
  }
    },
    methods: {
        ...mapMutations(['setUserPower']),
        // 登录
        submit() {
            let self = this;
            if (self.userName == '') {
                self.$toast('请输入账号!')
                return
            }
            if (self.password == '') {
                self.$toast('请输入密码!')
                return
            }
            // 开启等待框
            this.$toast.loading({
                message: '登录中...',
                duration: 0
            })
            login(self.userName, self.password).then(res => {
                // 对结果进行处理
                self.handleLogin(res)
            }).catch(error => {
                // 关闭等待
                // console.log(error);
                self.$toast("网络异常");
            });
        },
        // 登录验证
        handleLogin(res) {
            let self = this;
            // 关闭等待
            // this.loading = false;
            let rs = JSON.parse(res.data.result);
            if (rs.code == 1) {
                self.$toast("登录成功!");
                sessionStorage.setItem('username', self.username);
                sessionStorage.setItem('userId', rs.data);
                self.setUserPower(rs.data2);
                self.$router.push({
                    path: '/menu'
                })
            } else {
                self.$toast(rs.msg);
            }
        },
    }
}
</script>
<style scoped="scoped">
  .loginDiv {
    width: 100%;
    height: 100%;
    background: #ffffff;
    padding-top: 160px;
  }
.loginDiv {
    width: 100%;
    height: 100%;
    background: #ffffff;
    padding-top: 160px;
}
  .logo-bg {
    width: 100%;
    height: 100%;
    background: url('../assets/img/logo-bg.png') 0 0 no-repeat;
    background-size: 100% 100%;
    position: absolute;
    left: 0;
    top: 0;
  }
.logo-bg {
    width: 100%;
    height: 100%;
    background: url("../assets/img/logo-bg.png") 0 0 no-repeat;
    background-size: 100% 100%;
    position: absolute;
    left: 0;
    top: 0;
}
  .login-con {
    width: 100%;
    padding: 0 70px;
    position: relative;
  }
.login-con {
    width: 100%;
    padding: 0 70px;
    position: relative;
}
  .appName {
    color: #ffffff;
    font-size: 48px;
    font-weight: bold;
    margin-bottom: 240px;
    width: 100%;
    text-align: center;
  }
.appName {
    color: #ffffff;
    font-size: 48px;
    font-weight: bold;
    margin-bottom: 240px;
    width: 100%;
    text-align: center;
}
  .login-title {
    width: 110px;
    height: 76px;
    line-height: 76px;
    font-size: 50px;
    font-weight: bold;
    color: #333;
    border-bottom: 8px solid #4B88F9;
    text-align: center;
    margin-bottom: 68px;
  }
.login-title {
    width: 110px;
    height: 76px;
    line-height: 76px;
    font-size: 50px;
    font-weight: bold;
    color: #333;
    border-bottom: 8px solid #4b88f9;
    text-align: center;
    margin-bottom: 68px;
}
  .lineInput {
    width: 100%;
    height: 88px;
    background-color: #f5f5f5;
    border-radius: 44px;
    margin-bottom: 40px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 40px;
  }
.lineInput {
    width: 100%;
    height: 88px;
    background-color: #f5f5f5;
    border-radius: 44px;
    margin-bottom: 40px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 40px;
}
  .lineInput .ico1 {
    width: 25px;
    height: 31px;
  }
.lineInput .ico1 {
    width: 25px;
    height: 31px;
}
  .lineInput .ico2 {
    width: 26px;
    height: 31px;
  }
.lineInput .ico2 {
    width: 26px;
    height: 31px;
}
  .lineInput /deep/ .van-cell {
    background-color: transparent;
  }
.lineInput /deep/ .van-cell {
    background-color: transparent;
}
  .subBtn {
    width: 100%;
    height: 88px;
    border-radius: 44px;
    background-image: linear-gradient(to right, #08aeec, #4B88F9);
    box-shadow: 0 10px 20px rgb(85 149 246 / 50%);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    font-size: 32px;
    margin-top: 50px;
  }
.subBtn {
    width: 100%;
    height: 88px;
    border-radius: 44px;
    background-image: linear-gradient(to right, #08aeec, #4b88f9);
    box-shadow: 0 10px 20px rgb(85 149 246 / 50%);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    font-size: 32px;
    margin-top: 50px;
}
</style>
src/pages/menu.vue
New file
@@ -0,0 +1,30 @@
<template>
    <div class="menuWarp">
        <van-nav-bar title="功能菜单" fixed safe-area-inset-top placeholder></van-nav-bar>
        <van-grid clickable :column-num="2">
            <van-grid-item icon="browsing-history" text="实时监控" to="/realMonitoring" />
            <van-grid-item icon="todo-list" text="告警列表" to="/alarmList" />
        </van-grid>
    </div>
</template>
<script>
export default {
    data() {
        return {
        }
    },
}
</script>
<style scoped>
.menuWarp {
    width: 100%;
    height: 100%;
    background: #f5f5f5;
}
.van-grid-item {
    color: #4b88f9;
}
</style>
src/pages/real-monitoring.vue
New file
@@ -0,0 +1,702 @@
<template>
    <div class="realMonitoring">
        <van-nav-bar title="实时监控" @click-left="$router.back()" left-arrow fixed safe-area-inset-top placeholder>
        </van-nav-bar>
        <div class="detailsCon">
            <div class="card">
                <div class="commonTitle cardTitle">
                    <van-field v-model="fieldValue" is-link readonly label="" placeholder="请选择具体站点" @click="showPopup = true" />
                </div>
                <div class="commonTitle">
                    <div class="label">电池状态:</div>
                    <div class="text">
                        {{backInputs.batt_state}}
                    </div>
                </div>
                <div class="commonTitle">
                    <div class="label">端电压:</div>
                    <div class="text">
                        {{backInputs.group_online_vol}}
                    </div>
                </div>
                <div class="commonTitle">
                    <div class="label">电池电流:</div>
                    <div class="text">
                        {{backInputs.group_curr}}
                    </div>
                </div>
                <div class="commonTitle">
                    <div class="label">更新日期:</div>
                    <div class="text">
                        {{backInputs.rec_datetime}}
                    </div>
                </div>
                <div class="commonTitle">
                    <div class="label">测试时长:</div>
                    <div class="text">
                        {{backInputs.batt_test_tlong}}
                    </div>
                </div>
                <div class="commonTitle">
                    <div class="label">测试容量:</div>
                    <div class="text">
                        {{backInputs.batt_test_cap}}
                    </div>
                </div>
                <div class="commonTitle">
                    <div class="label">剩余容量:</div>
                    <div class="text">
                        {{backInputs.batt_syrl_cap}}
                    </div>
                </div>
                <div class="commonTitle">
                    <div class="label">续航时长:</div>
                    <div class="text">
                        {{backInputs.sysc}}
                    </div>
                </div>
            </div>
            <div class="card">
                <div class="commonTitle cardTitle">电压</div>
                <div class="chartWarp">
                    <bar-chart ref="vol" id="vol" unit="V" right-menu></bar-chart>
                </div>
            </div>
            <div class="card">
                <div class="commonTitle cardTitle">内阻</div>
                <div class="chartWarp">
                    <bar-chart ref="res" id="res" unit="mΩ" max-color="red" min-color="green" right-menu></bar-chart>
                </div>
            </div>
            <div class="card">
                <div class="commonTitle cardTitle">温度</div>
                <div class="chartWarp">
                    <bar-chart ref="temp" id="temp" unit="℃" max-color="red" min-color="green" right-menu></bar-chart>
                </div>
            </div>
            <div class="card">
                <div class="commonTitle cardTitle">电导</div>
                <div class="chartWarp">
                    <bar-chart ref="conduct" id="conduct" right-menu></bar-chart>
                </div>
            </div>
            <div class="card">
                <div class="commonTitle cardTitle">均衡电流</div>
                <div class="chartWarp">
                    <bar-chart ref="curr" id="curr" unit="A" right-menu></bar-chart>
                </div>
            </div>
            <div class="card">
                <div class="commonTitle cardTitle">漏液电压</div>
                <div class="chartWarp">
                    <bar-chart ref="leakVol" id="leakVol" unit="V" right-menu></bar-chart>
                </div>
            </div>
        </div>
        <van-popup v-model="showPopup" round position="bottom">
            <van-cascader v-model="cascaderValue" title="请选择站点电池组" :options="options" active-color="#4b88f9" @change="onChange" @close="showPopup = false" @finish="onFinish" />
        </van-popup>
    </div>
</template>
<script>
import {
    searchStation,
    searchBattInfo,
    getBattGroupInfo,
    realTimeAlarm,
    realTimeSearch,
    realTimeGroup,
} from "@/assets/js/api"
import BarChart from "@/components/chart/BarChart";
import getMarkLineData from "@/components/chart/js/getMarkLineData";
let vol, resChart, temp, conduct, currChart, leakVol;
let tblData = [];
export default {
    data() {
        return {
            showPopup: false,
            cascaderValue: '',
            fieldValue: '请选择站点',
            // 选项列表,children 代表子选项,支持多级嵌套
            options: [],
            /* 电池状态 模块 组端展示 */
            inputs: {
                group_vol: 0 /* 端电压-组端电压 */,
                online_vol: 0 /* 端电压-在线电压 */,
                group_curr: 0 /* 电池电流 */,
                batt_test_tlong: "0:00:00" /* 测试时长 */,
                rec_datetime: "1982-01-01 00:00:00" /* 更新日期 */,
                batt_test_cap: 0 /* 测试容量 */,
                batt_rest_cap: 0, // 剩余容量
                batt_state: 0 /* 电池状态 */
            },
            batt: {},
            timer: new this.$units.Timeout('movingRingSystemRealTime'),
        }
    },
    components: {
        BarChart,
    },
    computed: {
        backInputs() {
            let obj = {
                0: "未知",
                1: "浮充",
                2: "充电",
                3: "放电",
                4: "均充",
            };
            let list = {
                batt_state: "未知",
                group_online_vol: "在线:0.00V;组端:0.00V",
                group_curr: "0.00A",
                rec_datetime: "1982-01-01 00:00:00",
                batt_test_tlong: this.$units.formatSeconds(0),
                batt_test_cap: "0Ah",
                batt_syrl_cap: "---",
                sysc: "------"
            };
            list.batt_state = obj[this.inputs.batt_state];
            list.group_online_vol =
                `在线:${this.inputs.online_vol.toFixed(
                    2
                )}V;组端:${this.inputs.group_vol.toFixed(2)}V`;
            list.group_curr = this.inputs.group_curr.toFixed(2) + "A";
            list.rec_datetime = this.inputs.rec_datetime;
            list.batt_test_tlong = this.$units.formatSeconds(this.inputs.batt_test_tlong);
            list.batt_test_cap = this.inputs.batt_test_cap.toFixed(1) + "AH";
            if (this.inputs.batt_state === 2) {
                list.batt_syrl_cap = "---";
            } else {
                list.batt_syrl_cap = this.inputs.batt_rest_cap.toFixed(1) + "AH";
            }
            if (this.inputs.batt_state === 3) {
                list.sysc = sethoubeiTime(
                    parseFloat(this.inputs.batt_rest_cap) /
                    parseFloat(this.inputs.group_curr)
                );
            } else {
                list.sysc = "------";
            }
            return list;
        },
    },
    methods: {
        //查询电池组信息
        getBattGroupInfo(BattGroupId) {
            getBattGroupInfo(BattGroupId).then(res => {
                let rs = JSON.parse(res.data.result);
                if (rs.code == 1) {
                    this.leafClick(rs.data[0]);
                } else {
                    this.$toast('未获取到电池组的信息');
                }
            }).catch(error => {
                console.log(error);
            });
        },
        leafClick(data) {
            this.batt = data;
            this.realTimeAlarmss();
            // 开启循环请求
            this.startTimer();
        },
        /* 查询电池告警参数 */
        realTimeAlarmss() {
            var batt = this.batt;
            realTimeAlarm({
                dev_id: batt.FBSDeviceId
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                if (rs.code == 1) {
                    let list = rs.data;
                    // 单体电压
                    this.setChartMarkLine(vol, "Voltage", "Batt_Alarm_Type_MonVol", list);
                    // 单体温度
                    this.setChartMarkLine(temp, "Temperature", "Batt_Alarm_Type_MonTmp", list);
                    // 单体内阻
                    this.setChartMarkLine(resChart, "Resistance", "Batt_Alarm_Type_MonRes", list);
                    // 单体电导
                    this.setChartMarkLine(conduct, "Conductance", "Batt_Alarm_Type_MonRes", list);
                }
            });
        },
        setChartMarkLine(chartData, name, alm_name, list) {
            let batt = this.batt;
            // 遍历list
            for (let i = 0; i < list.length; i++) {
                let item = list[i];
                if (item.alm_name == alm_name) {
                    let high = 0;
                    let low = 0;
                    switch (name) {
                        case "Voltage":      // 电压告警
                            //单体电压
                            let std_mon_vol = batt.MonVolStd;
                            high = parseFloat(std_mon_vol * item.alm_high_coe).toHold(3);
                            low = parseFloat(std_mon_vol * item.alm_low_coe).toHold(3);
                            break;
                        case "Temperature":
                            //单体温度
                            let std_mon_tmp = 25;
                            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;
                    }
                    // 低告警
                    chartData.series[0].markLine.data[0].yAxis = low;
                    // 高告警
                    chartData.series[0].markLine.data[1].yAxis = high;
                    break;
                }
            }
        },
        startTimer() {
            this.timer.start(() => {
                this.$axios
                    .all([
                        this.realTimeSearch(),
                        this.realTimeGroupss(),
                    ])
                    .then(() => {
                        this.timer.open();
                    })
                    .catch(() => {
                        this.timer.open();
                    });
            }, 3000);
        },
        /* echars图表 */
        realTimeSearch() {
            var batt = this.batt;
            realTimeSearch({
                BattGroupId: batt.BattGroupId
            }).then(res => {
                let rs = JSON.parse(res.data.result);
                let data = [];
                if (rs.code == 1) {
                    data = rs.data.map(item => {
                        return {
                            num1: "#" + item.mon_num,
                            vol1: item.mon_vol,
                            res1: item.mon_res,
                            temp1: item.mon_tmp,
                            conduct1: item.mon_res ? (1 / item.mon_res * 1000).toFixed(0) : 0,
                            curr1: item.mon_JH_curr,
                            leakVol1: item.mon_LY_vol
                        };
                    });
                }
                // 更新表格
                if (this.acTabs == 'tblData') {
                    this.table.datas = data;
                } else {
                    tblData = data;
                }
                // 电压值
                let volTempVol = [];
                if (rs.code == 1) {
                    volTempVol = rs.data.map(item => {
                        return ["#" + item.mon_num, item.mon_vol];
                    });
                }
                let volBarNum = this.$units.getBarNum(volTempVol);
                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 = this.$units.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 = [];
                if (rs.code == 1) {
                    volTempte = rs.data.map(item => {
                        return ["#" + item.mon_num, item.mon_tmp];
                    });
                }
                let tempBarNum = this.$units.getBarNum(volTempte);
                temp.title.text = "最大值=" + tempBarNum.max.toFixed(1) + "℃;最小值=" + tempBarNum.min.toFixed(1) + "℃;平均值=" +
                    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 = this.$units.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 = this.$units.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 = this.$units.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();
            });
        },
        initChart() {
            // 电压
            vol = {
                title: {
                    show: true,
                    text: "最大值=0V;最小值=0V;平均值=0V",
                    x: "center",
                    textStyle: {
                        fontSize: "14",
                        color: '#323233'
                    }
                },
                series: [{
                    name: "电压",
                    type: "bar",
                    data: [],
                    markLine: {
                        data: getMarkLineData(),
                    },
                }]
            };
            // 漏液电压
            leakVol = {
                title: {
                    show: true,
                    text: "最大值=0V;最小值=0V;平均值=0V",
                    x: "center",
                    textStyle: {
                        fontSize: "14",
                        color: '#323233'
                    }
                },
                series: [{
                    name: "漏液电压",
                    type: "bar",
                    data: [],
                }]
            };
            // 内阻
            resChart = {
                title: {
                    show: true,
                    text: "最大值=0mΩ;最小值=mΩ;平均值=0mΩ",
                    x: "center",
                    textStyle: {
                        fontSize: "14",
                        color: '#323233'
                    }
                },
                series: [{
                    name: "内阻",
                    type: "bar",
                    data: [],
                    markLine: {
                        data: getMarkLineData(),
                    },
                }]
            };
            // 温度
            temp = {
                title: {
                    show: true,
                    text: "最大值=0℃;最小值=0℃;平均值=0℃",
                    x: "center",
                    textStyle: {
                        fontSize: "14",
                        color: '#323233'
                    }
                },
                series: [{
                    name: "温度",
                    type: "bar",
                    data: [],
                    markLine: {
                        data: getMarkLineData(),
                    },
                }]
            };
            // 电导
            conduct = {
                title: {
                    show: true,
                    text: "最大值=0;最小值=0;平均值=0",
                    x: "center",
                    textStyle: {
                        fontSize: "14",
                        color: '#323233'
                    }
                },
                series: [{
                    name: "电导",
                    type: "bar",
                    data: [],
                    markLine: {
                        data: getMarkLineData(),
                    },
                }]
            };
            // 均衡电流
            currChart = {
                title: {
                    show: true,
                    text: "最大值=0mA;最小值=0mA;平均值=0mA",
                    x: "center",
                    textStyle: {
                        fontSize: "14",
                        color: '#323233'
                    }
                },
                series: [{
                    name: "均衡电流",
                    type: "bar",
                    data: []
                }]
            };
            // 设置配置项
            this.setChart();
        },
        setChart() {
            this.$refs.vol.setOption(vol);
            this.$refs.res.setOption(resChart);
            this.$refs.temp.setOption(temp);
            this.$refs.conduct.setOption(conduct);
            this.$refs.curr.setOption(currChart);
            this.$refs.leakVol.setOption(leakVol);
        },
        /* 实时组端信息 */
        realTimeGroupss() {
            var batt = this.batt;
            realTimeGroup(batt.BattGroupId).then(res => {
                let rsa = JSON.parse(res.data.result);
                if (rsa.code == 1) {
                    this.inputs = rsa.data[0];
                    console.log(this.inputs)
                }
            }).catch(err => {
                console.log(err)
            });
        },
        // 全部选项选择完毕后,会触发 finish 事件
        onFinish({ selectedOptions }) {
            this.showPopup = false;
            this.fieldValue = selectedOptions.map((option) => option.text).join('-');
            this.getBattGroupInfo(this.cascaderValue)
        },
        //选择站点时触发查询站点下电池组
        onChange(select) {
            if (select.tabIndex == 3) {
                let objs = select.selectedOptions[select.selectedOptions.length - 1];
                searchBattInfo({
                    StationName1: objs.data.StationName1,
                    StationName2: objs.data.StationName2,
                    StationName5: objs.data.StationName5,
                    StationName3: objs.data.StationName3
                }).then((res) => {
                    let rs = JSON.parse(res.data.result);
                    if (rs.code == 1) {
                        let data = rs.data;
                        data.map(item => {
                            item.text = item.StationName4 + '-' + item.BattGroupName
                            item.value = item.BattGroupId
                        })
                        this.options.map(item => {
                            item?.children.map(jtem => {
                                jtem?.children.map(etem => {
                                    etem?.children.map(gtem => {
                                        if (gtem.value == select.value) {
                                            gtem.children = data
                                        }
                                    })
                                })
                            })
                        })
                    }
                }).catch((err) => {
                    console.log(err)
                });
            }
        },
        //查询站点信息
        searchStation() {
            searchStation({
                StationName1: "",
                StationName2: "",
                StationName5: "",
            }).then((res) => {
                let rs = JSON.parse(res.data.result);
                let data = [];
                if (rs.code == 1) {
                    data = rs.data;
                }
                // 格式化数据
                this.formatData(data);
            }).catch(err => {
                console.log(err)
            });
        },
        //整理数据格式
        formatData(data) {
            let result = [];
            // 遍历数据构造树状
            data.forEach(item => {
                // 省
                let provice = this.addData(result, item.StationName1);
                // 市
                let city = this.addData(provice.children, item.StationName2, provice);
                // 区县
                let county = this.addData(city.children, item.StationName5, city);
                // 机房
                let home = this.addData(county.children, item.StationName3, county, item);
            });
            // 设置树状列表
            this.options = result;
        },
        addData(list, val, parent, data, leaf) {
            let item;
            let index = this.checkValIsIn(val, list);
            let parentId = parent ? parent.text + '-' : "";
            if (index == -1) {
                if (leaf) {
                    item = {
                        value: parentId + val + Math.random(),
                        text: val,
                        data: data,
                    };
                } else {
                    item = {
                        value: parentId + val + Math.random(),
                        text: val,
                        children: [],
                        data: data,
                    };
                }
                list.push(item);
            } else {
                item = list[index];
            }
            return item;
        },
        checkValIsIn(val, arr) {
            for (let i = 0; i < arr.length; i++) {
                if (arr[i].text == val) {
                    return i;
                }
            }
            return -1;
        },
    },
    mounted() {
        this.searchStation();
        // 初始化图表
        this.initChart();
    },
    destroyed() {
        this.timer.stop();
    }
}
</script>
<style scoped>
.realMonitoring {
    width: 100%;
    min-height: 100%;
    background: #f5f5f5;
}
.detailsCon {
    padding: 24px;
}
.card {
    background-color: #ffffff;
    border-radius: 16px;
    margin: 0 auto 24px;
    width: 702px;
    padding: 24px;
    box-shadow: 0px 4px 20px 0px rgba(75, 136, 249, 0.2);
}
.commonTitle {
    font-size: 28px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #333333;
    line-height: 40px;
    padding-bottom: 24px;
    border-bottom: 1px solid #eeeeee;
    margin-bottom: 22px;
    display: flex;
}
.cardTitle {
    font-weight: bold;
}
.cardTitle .van-cell {
    padding: 0;
}
.commonTitle .label {
    line-height: 40px;
    display: inline-block;
    width: 170px;
}
.commonTitle .text {
    flex: 1;
}
.chartWarp {
    width: 100%;
    height: 500px;
}
</style>
src/router/routes.js
@@ -6,9 +6,13 @@
    meta: {},
    component: (resolve) => require(['@/pages/login.vue'], resolve)
}, {
    path: '/index',
    path: '/menu',
    meta: {},
    component: (resolve) => require(['@/pages/index.vue'], resolve)
    component: (resolve) => require(['@/pages/menu.vue'], resolve)
}, {
    path: '/alarmList',
    meta: {},
    component: (resolve) => require(['@/pages/alarm-list.vue'], resolve)
}, {
    path: '/alarmDetails',
    meta: {},
@@ -21,4 +25,8 @@
    path: '/userList',
    meta: {},
    component: (resolve) => require(['@/pages/user-list.vue'], resolve)
}, ];
}, {
    path: '/realMonitoring',
    meta: {},
    component: (resolve) => require(['@/pages/real-monitoring.vue'], resolve)
},];