whychdw
2020-07-29 f0d443cb6997a1979eb6c256f1ca3624aab1b45b
内容提交
13个文件已修改
7个文件已添加
1829 ■■■■■ 已修改文件
src/api/services/batt/index.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/common.css 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/checkIsLink.js 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/common.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/isInArray.js 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/isSetOption.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ContentBox.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/ChartConfigs.vue 182 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/ChartConfigsPlus.vue 198 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/LineChart.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/LineChartPlus.vue 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/chartConfigsComponent/ChartConfigsDefault.vue 194 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chart/chartConfigsComponent/ChartConfigsGroup.vue 366 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tree/TreeItem.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/batt-list/history-page-plus.vue 423 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/batt-list/history-page.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/batt-list/index.vue 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/batt-list/real-time-page.vue 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/file/index.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/services/batt/index.js
@@ -60,5 +60,18 @@
            url: 'Devdata_historyAction!serchByInfo',
            data: 'json='+JSON.stringify(data),
        });
    },
    /**
     * 检测机房的连接状态
     * 无参
     * 根据record_time和record_time1做对比
     */
    checkHomeState() {
        return axios({
            method: 'post',
            url: 'Devdata_rtAction!searchAll',
            data: null,
        });
    }
}
src/assets/css/common.css
@@ -95,7 +95,7 @@
    /* 滚动条里面小方块 */
    border-radius: 0.1rem;
    -webkit-box-shadow: inset 0 0 0.05rem rgba(0,0,0,0.2);
    background: #00f0ff;
    background: #f9fafa;
}
div::-webkit-scrollbar-track {
    /* 滚动条里面轨道 */
src/assets/js/checkIsLink.js
New file
@@ -0,0 +1,21 @@
/**
 * [checkIsLink description]
 *
 * @param   {[String]}  old  历史时间
 * @param   {[String]}  now  当前时间
 * @param   {[String]}  long 时长(分钟)
 *
 * @return  {[Boolean]}       返回是否通讯正常(true:连接正常, false:连接中断)
 */
function checkIsLink(old, now, long) {
    let oldTime = new Date(old).getTime();
    let nowTime = new Date(now).getTime();
    let differ = (nowTime-oldTime)/(1000*60);    // 转化为分钟
    if(!long) {
        long = 10;  // 默认10分钟
    }
    return differ>=long?false:true;
}
export default checkIsLink;
src/assets/js/common.js
@@ -4,8 +4,10 @@
import getBattstate from './getBattstate'   // 电池状态
import getMaxFromArr from './getMaxFromArr' // 最大值
import hex_md5 from './hex_md5'
import isSetOption from './isSetOption'
import isSetOption from './isSetOption'     // 检测配置项
import ChartManage from './ChartManage'
import checkIsLink from './checkIsLink'     // 检测是否连接
import isInArray from './isInArray'
export {
    Timeout,
@@ -16,4 +18,6 @@
    hex_md5,
    isSetOption,
    ChartManage,
    checkIsLink,
    isInArray,
}
src/assets/js/isInArray.js
New file
@@ -0,0 +1,14 @@
/**
 * 检测数据是否在数组中
 */
function isInArray(arr, val) {
    let result = false;
    arr.forEach(item=>{
        if(item == val) {
            result = true;
        }
    });
    return result;
}
export default isInArray;
src/assets/js/isSetOption.js
@@ -7,6 +7,11 @@
 *
 * @return  {Boolean}           返回匹配结果
 */
const delStrings = [
    '1号定子腔体压力报警信号',
    '2号定子腔体压力报警信号',
];
function isSetOption(str, pattern, type) {
    let result = true;
    switch(type) {
@@ -17,6 +22,14 @@
            result = !pattern.test(str);
        break;
    }
    // 遍历delString
    delStrings.forEach(item=>{
        if(item == str) {
            result = false;
        }
    });
    return result;
}
src/components/ContentBox.vue
@@ -1,10 +1,13 @@
<template>
    <div class="content-box" :class="{'no-border': noborder}">
    <div class="content-box" :class="{'no-border': noborder, 'footer': footer}">
        <div class="content-box-title" :class="getTitlePos">
            <slot name="title">{{title}}</slot>
        </div>
        <div class="content-box-content">
            <slot></slot>
        </div>
        <div class="content-box-footer" v-if="footer">
            <slot name="footer"></slot>
        </div>
    </div>
</template>
@@ -25,6 +28,10 @@
            type: Boolean,
            default: false
        },
        footer: {
            type: Boolean,
            default: false,
        }
    },
    computed: {
        getTitlePos: function() {
@@ -72,6 +79,22 @@
    bottom: 0;
    overflow-y: auto;
}
.footer .content-box-content {
    bottom: 0.32rem;
}
.content-box-footer {
    position: absolute;
    bottom: 0;
    left: 0.04rem;
    right: 0.04rem;
    padding-left: 0.1rem;
    border-radius: 0.06rem;
    font-size: 0.14rem;
    text-align: center;
    line-height: 0.32rem;
    font-weight: bold;
    z-index: 1;
}
</style>
src/components/chart/ChartConfigs.vue
@@ -1,61 +1,28 @@
<template>
    <flex-layout height="100vh">
        <div slot="header" class="drawer-title-content">
            <div class="drawer-title">
                <img src="../../assets/images/card-title.png">
                图表配置<div style="float: right;">已选中:{{list.length}}/{{getOptionsLength}}</div>
            </div>
            <div class="drawer-title-search">
                <el-input
                placeholder="请输入搜索内容"
                prefix-icon="el-icon-search"
                size="small"
                v-model.trim="search"
                @input="matchingSearch"
                clearable>
                </el-input>
            </div>
        </div>
        <div class="drawer-content" v-if="search.length == 0">
            <div class="no-data" v-if="getOptionsLength == 0">
                暂无图表配置项
            </div>
            <el-checkbox v-else :indeterminate="indeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
            <el-checkbox-group
            v-model="list"
            @change="handleCheckedChange">
                <el-col class="el-col-padding-top-bottom-6" :span="24" v-for="(option, key) in options" :key="option.title+key">
                    <el-checkbox :label="option.title">{{option.title}}</el-checkbox>
                </el-col>
            </el-checkbox-group>
        </div>
        <div class="drawer-content" v-else>
            <div class="no-data" v-if="matchingNum == 0">
                未匹配到图表配置项
            </div>
            <el-checkbox-group
            v-model="list"
            @change="handleCheckedChange">
                <el-col class="el-col-padding-top-bottom-6" :span="24" v-for="(option, key) in matchingData" :key="option.title+key">
                    <el-checkbox :label="option.title">{{option.title}}</el-checkbox>
                </el-col>
            </el-checkbox-group>
        </div>
        <div slot="footer" class="drawer-footer">
            <el-button type="primary" size="mini"
            @click="ok">确定</el-button>
            <el-button type="default" size="mini"
            @click="cancel">取消</el-button>
        </div>
    </flex-layout>
    <div class="chart-configs">
        <chart-configs-default
        v-if="optionsLength<300"
        :selecteds="selecteds"
        :options="options"
        @ok="ok"
        @cancel="cancel"></chart-configs-default>
        <chart-configs-group
        v-else
        :selecteds="selecteds"
        :options="options"
        @ok="ok"
        @cancel="cancel"></chart-configs-group>
    </div>
</template>
<script>
import FlexLayout from '@/components/FlexLayout'
import ChartConfigsDefault from './chartConfigsComponent/ChartConfigsDefault'
import ChartConfigsGroup from './chartConfigsComponent/ChartConfigsGroup'
export default {
    components: {
        FlexLayout,
        ChartConfigsDefault,
        ChartConfigsGroup,
    },
    props: {
        selecteds: {
@@ -69,128 +36,27 @@
            default() {
                return {}
            }
        }
        },
    },
    data() {
        let slecteds = this.selecteds;
        let list = [];
        slecteds.forEach(function(value) {
            list.push(value);
        });
        let optionsLength = Object.keys(this.options).length;
        return {
            checkAll: false,
            indeterminate: true,
            list: list,
            search: '',
            matchingData: {},
            matchingNum: 0,
            optionsLength: optionsLength,
        }
    },
    methods: {
        ok() {
            this.$emit('ok', this.list);
        ok(list) {
            this.$emit('ok', list);
        },
        cancel() {
            this.$emit('cancel');
        },
        clearMatchingData() {
            // 遍历删除
            for(let key in this.matchingData){
                delete this.matchingData[key];
            }
            this.matchingNum = 0;
        },
        matchingSearch() {
            // 清理属性
            this.clearMatchingData();
            // 构造查询规则
            let search = this.search;
            let matching = new RegExp(search,['i']);
            let options = this.options;
            // 遍历options的值获取添加匹配的内容
            for(let key in options) {
                let option = options[key];
                if(matching.test(option.title)) {
                    this.$set(this.matchingData, key, options[key]);
                }
            }
            this.matchingNum = Object.keys(this.matchingData).length;
        },
        handleCheckAllChange(val) {
            let list = [];
            for(let i=0; i<this.allList.length; i++) {
                list.push(this.allList[i]);
            }
            this.list = val?list:[];
            this.indeterminate = false;
        },
        handleCheckedChange(value) {
            let checkedCount = value.length;
            this.checkAll = checkedCount === this.allList.length;
            this.indeterminate = checkedCount > 0 && checkedCount < this.allList.length;
        },
    },
    computed: {
        getOptionsLength() {
            return Object.keys(this.options).length;
        },
        allList() {
            let allList = [];
            let options = this.options;
            for(let key in options) {
                allList.push(options[key].title)
            }
            return allList;
        }
    },
    mounted(){
       this.handleCheckedChange(this.list);
    }
}
</script>
<style scoped>
.drawer-title {
    padding: 0.14rem 0.14rem 0.14rem 0.14rem;
    background-color: #004364;
    background-image: linear-gradient(#02a7fa, #0486c7, #0270a7, #024d72);
}
.drawer-title img {
    vertical-align: middle;
    margin-right: 0.08rem;
}
.drawer-title-search {
    padding-left: 0.18rem;
    padding-right: 0.19rem;
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
}
.drawer-content {
    padding-left: 0.2rem;
    padding-right: 0.2rem;
}
.drawer-content-title {
    position: absolute;
    top: 0.04rem;
    left: 0.18rem;
    right: 0.18rem;
}
.el-col-padding-top-bottom-6 {
    padding-top: 0.06rem;
    padding-bottom: 0.06rem;
}
.drawer-footer {
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
    padding-left: 0.08rem;
    padding-right: 0.08rem;
    text-align: right;
    background-color: #004364;
}
.no-data {
    text-align: center;
}
</style>
src/components/chart/ChartConfigsPlus.vue
New file
@@ -0,0 +1,198 @@
<template>
    <flex-layout height="100vh">
        <div slot="header" class="drawer-title-content">
            <div class="drawer-title">
                <img src="../../assets/images/card-title.png">
                图表配置<div style="float: right;">已选中:{{list.length}}/{{all.length}}</div>
            </div>
            <div class="drawer-title-search">
                <el-input
                placeholder="请输入搜索内容"
                prefix-icon="el-icon-search"
                size="small"
                v-model.trim="search"
                @input="matchingSearch"
                clearable>
                </el-input>
            </div>
        </div>
        <div class="drawer-content" v-if="search.length == 0">
            <div class="no-data" v-if="all.length == 0">
                暂无图表配置项
            </div>
            <el-checkbox v-else :indeterminate="indeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
            <el-checkbox-group
            v-model="list"
            @change="handleCheckedChange">
                <el-col class="el-col-padding-top-bottom-6" :span="24" v-for="(item, key) in all" :key="item.name+key">
                    <el-checkbox :label="item.name">{{item.name}}</el-checkbox>
                </el-col>
            </el-checkbox-group>
        </div>
        <div class="drawer-content" v-else>
            <div class="no-data" v-if="matchingNum == 0">
                未匹配到图表配置项
            </div>
            <el-checkbox-group
            v-model="list"
            @change="handleCheckedChange">
                <el-col class="el-col-padding-top-bottom-6" :span="24" v-for="(item, key) in matchingData" :key="item.name+key">
                    <el-checkbox :label="item.name">{{item.name}}</el-checkbox>
                </el-col>
            </el-checkbox-group>
        </div>
        <div slot="footer" class="drawer-footer">
            <el-button type="primary" size="mini"
            @click="ok">确定</el-button>
            <el-button type="default" size="mini"
            @click="cancel">取消</el-button>
        </div>
    </flex-layout>
</template>
<script>
import FlexLayout from '@/components/FlexLayout'
export default {
    components: {
        FlexLayout,
    },
    props: {
        selecteds: {
            type: Array,
            default() {
                return []
            }
        },
        all: {
            type: Array,
            default() {
                return []
            }
        }
    },
    data() {
        let slecteds = this.selecteds;
        let list = slecteds.map(item=>{
            return item.name;
        });
        return {
            checkAll: false,
            indeterminate: true,
            list: list,
            search: '',
            matchingData: [],
            matchingNum: 0,
        }
    },
    methods: {
        ok() {
            let all = this.all;
            let list = this.list;
            let result = [];
            // 遍历list
            list.forEach(item=>{
                for(let key in all) {
                    if(all[key].name == item) {
                        result.push(all[key]);
                    }
                }
            });
            this.$emit('ok', result);
        },
        cancel() {
            this.$emit('cancel');
        },
        clearMatchingData() {
            // 遍历删除
            this.matchingData = [];
            this.matchingNum = 0;
        },
        matchingSearch() {
            // 清空匹配内容
            this.clearMatchingData();
            // 构造查询规则
            let search = this.search;
            let matching = new RegExp(search,['i']);
            let all = this.all;
            // 遍历options的值获取添加匹配的内容
            all.forEach((item)=> {
                if(matching.test(item.name)) {
                    this.matchingData.push(item);
                }
            });
            // 设置匹配的个数
            this.matchingNum = this.matchingData.length;
        },
        handleCheckAllChange(val) {
            let list = [];
            for(let i=0; i<this.allList.length; i++) {
                list.push(this.allList[i]);
            }
            this.list = val?list:[];
            this.indeterminate = false;
        },
        handleCheckedChange(value) {
            let checkedCount = value.length;
            this.checkAll = checkedCount === this.allList.length;
            this.indeterminate = checkedCount > 0 && checkedCount < this.allList.length;
        },
    },
    computed: {
        allList() {
            let all = this.all;
            return all.map(item=>{
                return item.name;
            });
        }
    },
    mounted(){
       this.handleCheckedChange(this.list);
    }
}
</script>
<style scoped>
.drawer-title {
    padding: 0.14rem 0.14rem 0.14rem 0.14rem;
    background-color: #004364;
    background-image: linear-gradient(#02a7fa, #0486c7, #0270a7, #024d72);
}
.drawer-title img {
    vertical-align: middle;
    margin-right: 0.08rem;
}
.drawer-title-search {
    padding-left: 0.18rem;
    padding-right: 0.19rem;
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
}
.drawer-content {
    padding-left: 0.2rem;
    padding-right: 0.2rem;
}
.drawer-content-title {
    position: absolute;
    top: 0.04rem;
    left: 0.18rem;
    right: 0.18rem;
}
.el-col-padding-top-bottom-6 {
    padding-top: 0.06rem;
    padding-bottom: 0.06rem;
}
.drawer-footer {
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
    padding-left: 0.08rem;
    padding-right: 0.08rem;
    text-align: right;
    background-color: #004364;
}
.no-data {
    text-align: center;
}
</style>
src/components/chart/LineChart.vue
@@ -117,7 +117,7 @@
                },
                grid: {
                    left: '0',
                    right: '0',
                    right: '12px',
                    bottom: '1',
                    top: dataZoom.show?'40px': '0',
                    containLabel: true 
@@ -129,6 +129,7 @@
                    trigger: 'axis',
                    triggerOn: tooltip.triggerOn,
                    hideDelay: this.delayTime,
                    confine: true,      // 避免被格挡
                    formatter: function(params) {
                        var res = params[0].name;
                        var cols = Math.ceil(params.length/5);
@@ -146,6 +147,7 @@
                xAxis: {
                    show: false,
                    type: 'category',
                    boundaryGap: false,
                    data: []
                },
                yAxis: {
@@ -214,9 +216,9 @@
            let dataIndex = this.dataIndex == -1?option.xAxis.data.length:this.dataIndex;
            
            option.title.subtext = '历史数据:'+history.time+" "+history.value+unit+'\n'
            +'当前数据:'+option.xAxis.data[dataIndex-1]+" "+option.series[0].data[dataIndex-1]+unit;
            +'当前数据:'+option.xAxis.data[dataIndex]+" "+option.series[0].data[dataIndex]+unit;
            if(!this.subtext || option.xAxis.data[dataIndex-1] == undefined) {
            if(!this.subtext || option.xAxis.data[dataIndex] == undefined) {
                option.title.subtext="";
            }
            
src/components/chart/LineChartPlus.vue
New file
@@ -0,0 +1,245 @@
<template>
    <div class="chart-container" :id="id+'container'">
        <div class="chart-content-container">
            <div class="chart-content"
            :id="id" :style="{'height': height.chart+'px'}"></div>
        </div>
    </div>
</template>
<script>
// 引入 ECharts 主模块
import ECharts from "echarts/lib/echarts";
//引入折线图
import "echarts/lib/chart/line";
//引入提示框
import "echarts/lib/component/tooltip";
//引入标题
import "echarts/lib/component/title";
//引入图例标志
import "echarts/lib/component/legend";
//区域缩放
import "echarts/lib/component/dataZoom";
// 引入自定义主题
import "./theme/transparent"
import { setTimeout } from 'timers';
export default {
    data() {
        return {
            id: 'chart',
            height: {
                container: 200,
                chart: 200,
                item: 200,
            },
            num: 1,     // 图表个数
        }
    },
    methods: {
        /**
         * list 为对象集合
         * 对象必须属性name, step, unit, data
         */
        setOption(list, config) {
            // 清空图表
            if(config && config.clear) {
                this.clear();
            }
            // 设置高度
            this.setHeight(list.length);
            // 获取单位列表
            let units = this.getUnits(list);
            // 配置项
            let option = {
                animation: false,
                tooltip: {
                    trigger: 'axis',
                    confine: true,      // 避免被格挡
                    axisPointer: {
                        animation: false
                    },
                    formatter: function(params) {
                        var res = params[0].name;
                        var cols = Math.ceil(params.length/20);
                        params.forEach((item, index)=>{
                            if(index%cols == 0) {
                                res += '<br>';
                            }
                            res += item.marker+item.seriesName
                            +': '+item.value[1]+units[item.axisIndex]+
                            "<span style='display: inline-block;margin-right: 8px'></span>";
                        });
                        return res;
                    }
                },
                axisPointer: {
                    link: {xAxisIndex: 'all'}
                },
                visualMap: [],
                title: [],
                grid: [],
                xAxis: [],
                yAxis: [],
                series: [],
            };
            // 遍历list的值
            list.forEach((item, index)=> {
                // 设置visualMap
                //option.visualMap.push(this.getVisualMap(index));
                // 设置title
                option.title.push(this.getTitle(item, index));
                // 设置title
                option.grid.push(this.getGrid(index));
                // 设置xAxis
                option.xAxis.push(this.getXAxis(index));
                // 设置xAxis
                option.yAxis.push(this.getYAxis(index));
                // 设置series
                option.series.push(this.getSeries(item, index));
            });
            this.$nextTick(()=>{
                this.$G.chartManage.get(this.id).setOption(option);
            });
        },
        appendData(list) {
            let chart = this.$G.chartManage.get(this.id);
            list.forEach((item, index)=>{
                chart.appendData({
                    seriesIndex: index,
                    data: item,
                });
            });
            // 延时执行重置大小
            setTimeout(()=>{
                this.resize();
            }, 0)
        },
        setHeight(num) {
            let container = this.height.container;
            this.num = num;     // chart的个数
            let minChartHt = 200;   // 最小高度
            this.height.item = Math.floor(container/num)<minChartHt?minChartHt:container/num;
            this.height.chart = this.height.item*num;
            // 重置大小
            this.resize();
        },
        getUnits(list) {
            return list.map(item=> {
                return item.unit;
            });
        },
        getVisualMap(index) {
            return {
                    show: false,
                    type: 'continuous',
                    seriesIndex: index,
                };
        },
        getTitle(item, index) {     // 获取echarts的title
            let top = this.height.item*index;
            return {
                text: item.name,
                x: 'left',
                top: top+'px',
                textStyle: {
                    fontSize: 12
                },
            };
        },
        getGrid(index) {
            let ht = this.height.item;
            return {
                left: '8px',
                right: '8px',
                top: index*ht+'px',
                height: ht-8+'px',
            }
        },
        getXAxis(index) {
            return {
                show: false,
                type: 'category',
                boundaryGap: false,
                gridIndex: index,
            }
        },
        getYAxis(index) {
            return {
                type: 'value',
                show: false,
                gridIndex: index,
                max: function(data) {
                    return data.max*2;
                }
            };
        },
        getSeries(item, index) {      // 获取echarts的series
            return {
                name: item.name,
                type: 'line',
                smooth: item.step?false: true,
                symbolSize: 0,
                sampling: 'average',
                step: item.step,
                data: item.data,
                itemStyle: {
                    color: '#15E3F3',
                },
                xAxisIndex: index,
                yAxisIndex: index,
            };
        },
        clear() {       // 清空echarts
            this.$G.chartManage.get(this.id).clear();
        },
        resize() {      // 重置echarts
            let container = document.getElementById(this.id+'container');     // 获取到容器
            this.height.container = container.offsetHeight;       // 获取容器的高度
            this.$nextTick(()=>{
                this.$G.chartManage.get(this.id).resize();
            });
        },
    },
    mounted() {
        let ele = document.getElementById(this.id);     // 获取到echarts的容器
        let container = document.getElementById(this.id+'container');     // 获取到容器
        this.height.container = container.offsetHeight;       // 获取容器的高度
        let chart = ECharts.init(ele, 'transparent');
        // 将图表添加到图表管理
        this.$G.chartManage.set(this.id, chart);
    },
    destroyed() {
        // 销毁echarts
        this.$G.chartManage.del(this.id);
    }
}
</script>
<style scoped>
.chart-container,
.chart-container .chart-content-container,
.chart-content-container .chart-content{
    height: 100%;
}
.chart-container {
    box-sizing: border-box;
    overflow-y: auto;
    overflow-x: hidden;
}
</style>
src/components/chart/chartConfigsComponent/ChartConfigsDefault.vue
New file
@@ -0,0 +1,194 @@
<template>
    <flex-layout height="100vh">
        <div slot="header" class="drawer-title-content">
            <div class="drawer-title">
                <img src="@/assets/images/card-title.png">
                图表配置<div style="float: right;">已选中:{{list.length}}/{{getOptionsLength}}</div>
            </div>
            <div class="drawer-title-search">
                <el-input
                placeholder="请输入搜索内容"
                prefix-icon="el-icon-search"
                size="small"
                v-model.trim="search"
                @input="matchingSearch"
                clearable>
                </el-input>
            </div>
        </div>
        <div class="drawer-content" v-if="search.length == 0">
            <div class="no-data" v-if="getOptionsLength == 0">
                暂无图表配置项
            </div>
            <el-checkbox v-else :indeterminate="indeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
            <el-checkbox-group
            v-model="list"
            @change="handleCheckedChange">
                <el-col class="el-col-padding-top-bottom-6" :span="24" v-for="(option, key) in options" :key="option.title+key">
                    <el-checkbox :label="option.title">{{option.title}}</el-checkbox>
                </el-col>
            </el-checkbox-group>
        </div>
        <div class="drawer-content" v-else>
            <div class="no-data" v-if="matchingNum == 0">
                未匹配到图表配置项
            </div>
            <el-checkbox-group
            v-model="list"
            @change="handleCheckedChange">
                <el-col class="el-col-padding-top-bottom-6" :span="24" v-for="(option, key) in matchingData" :key="option.title+key">
                    <el-checkbox :label="option.title">{{option.title}}</el-checkbox>
                </el-col>
            </el-checkbox-group>
        </div>
        <div slot="footer" class="drawer-footer">
            <el-button type="primary" size="mini"
            @click="ok">确定</el-button>
            <el-button type="default" size="mini"
            @click="cancel">取消</el-button>
        </div>
    </flex-layout>
</template>
<script>
import FlexLayout from '@/components/FlexLayout'
export default {
    components: {
        FlexLayout,
    },
    props: {
        selecteds: {
            type: Array,
            default() {
                return []
            }
        },
        options: {
            type: Object,
            default() {
                return {}
            }
        }
    },
    data() {
        let slecteds = this.selecteds;
        let list = [];
        slecteds.forEach(function(value) {
            list.push(value);
        });
        return {
            checkAll: false,
            indeterminate: true,
            list: list,
            search: '',
            matchingData: {},
            matchingNum: 0,
        }
    },
    methods: {
        ok() {
            this.$emit('ok', this.list);
        },
        cancel() {
            this.$emit('cancel');
        },
        clearMatchingData() {
            // 遍历删除
            for(let key in this.matchingData){
                delete this.matchingData[key];
            }
            this.matchingNum = 0;
        },
        matchingSearch() {
            // 清理属性
            this.clearMatchingData();
            // 构造查询规则
            let search = this.search;
            let matching = new RegExp(search,['i']);
            let options = this.options;
            // 遍历options的值获取添加匹配的内容
            for(let key in options) {
                let option = options[key];
                if(matching.test(option.title)) {
                    this.$set(this.matchingData, key, options[key]);
                }
            }
            this.matchingNum = Object.keys(this.matchingData).length;
        },
        handleCheckAllChange(val) {
            let list = [];
            for(let i=0; i<this.allList.length; i++) {
                list.push(this.allList[i]);
            }
            this.list = val?list:[];
            this.indeterminate = false;
        },
        handleCheckedChange(value) {
            let checkedCount = value.length;
            this.checkAll = checkedCount === this.allList.length;
            this.indeterminate = checkedCount > 0 && checkedCount < this.allList.length;
        },
    },
    computed: {
        getOptionsLength() {
            return Object.keys(this.options).length;
        },
        allList() {
            let allList = [];
            let options = this.options;
            for(let key in options) {
                allList.push(options[key].title)
            }
            return allList;
        }
    },
    mounted(){
       this.handleCheckedChange(this.list);
    }
}
</script>
<style scoped>
.drawer-title {
    padding: 0.14rem 0.14rem 0.14rem 0.14rem;
    background-color: #004364;
    background-image: linear-gradient(#02a7fa, #0486c7, #0270a7, #024d72);
}
.drawer-title img {
    vertical-align: middle;
    margin-right: 0.08rem;
}
.drawer-title-search {
    padding-left: 0.18rem;
    padding-right: 0.19rem;
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
}
.drawer-content {
    padding-left: 0.2rem;
    padding-right: 0.2rem;
}
.drawer-content-title {
    position: absolute;
    top: 0.04rem;
    left: 0.18rem;
    right: 0.18rem;
}
.el-col-padding-top-bottom-6 {
    padding-top: 0.06rem;
    padding-bottom: 0.06rem;
}
.drawer-footer {
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
    padding-left: 0.08rem;
    padding-right: 0.08rem;
    text-align: right;
    background-color: #004364;
}
.no-data {
    text-align: center;
}
</style>
src/components/chart/chartConfigsComponent/ChartConfigsGroup.vue
New file
@@ -0,0 +1,366 @@
<template>
    <flex-layout height="100vh">
        <div slot="header" class="drawer-title-content">
            <div class="drawer-title">
                <img src="@/assets/images/card-title.png">
                图表配置<div style="float: right;">已选中:{{getCheckedList.length}}/{{getOptionsLength}}</div>
            </div>
        </div>
        <div class="drawer-content" ref="content">
            <div class="hdw-collapse">
                <div class="hdw-collapse-item"
                v-for="(group, key) in groups" :key="key"
                :class="{'hdw-collapsed': activeName==key}">
                    <div class="hdw-collapse-title">
                        <div class="hdw-collapse-title-content">
                            <el-checkbox
                            :indeterminate="group.isIndeterminate"
                            v-model="group.checkAll"
                            @change="handleCheckAllChange(key)">
                            </el-checkbox>
                            <span
                            class="checkbox-label"
                            @click="toggleCollapsed(key)">全选 ({{50*key+1}}~{{50*key+group.list.length}})</span>
                            <i class="el-icon-remove-outline" title="反选"
                            @click="backChecked(key)"></i>
                        </div>
                        <div class="hdw-collapse-icon" @click="toggleCollapsed(key)">
                            <i class="el-icon-d-arrow-right"></i>
                        </div>
                    </div>
                    <div class="hdw-collapse-content" v-if="activeName == key">
                        <el-checkbox-group
                        v-model="group.checkedList"
                        @change="handleCheckedCitiesChange(key)">
                            <el-col class="el-col-padding-top-bottom-6" :span="24" v-for="item in group.list" :key="item">
                                <el-checkbox :label="item">{{item}}</el-checkbox>
                            </el-col>
                        </el-checkbox-group>
                    </div>
                </div>
                <div class="hdw-collapse-item">
                    <div class="hdw-collapse-title" style="border:none; padding: 0.08rem;">
                        <div class="hdw-collapse-title-content"></div>
                        <div class="hdw-collapse-icon"></div>
                    </div>
                </div>
            </div>
        </div>
        <div slot="footer" class="drawer-footer">
            <el-button type="primary" size="mini"
            @click="ok">确定</el-button>
            <el-button type="default" size="mini"
            @click="cancel">取消</el-button>
        </div>
    </flex-layout>
</template>
<script>
import FlexLayout from '@/components/FlexLayout'
import {
    isInArray
} from '@/assets/js/common'
import { setTimeout } from 'timers';
export default {
    components: {
        FlexLayout
    },
    props: {
        selecteds: {
            type: Array,
            default() {
                return []
            }
        },
        options: {
            type: Object,
            default() {
                return {}
            }
        }
    },
    data() {
        let slecteds = this.selecteds;
        let list = [];
        slecteds.forEach(function(value) {
            list.push(value);
        });
        let optionsLength =  Object.keys(this.options).length;
        return {
            checkAll: false,
            indeterminate: true,
            list: list,
            search: '',
            matchingData: {},
            matchingNum: 0,
            radio: '',
            activeName: -1,
            optionsLength: optionsLength,
            num: 50,
            groups: []
        }
    },
    watch:{
        activeName() {
            setTimeout(()=>{
                this.$nextTick(()=>{
                    this.$refs.content.scrollTop = this.activeName*35;
                });
            },100);
        }
    },
    methods: {
        ok() {
            let list = this.getCheckedList;
            if(list.length > 50) {
                this.$message({
                    type: 'warning',
                    message: '选择不能超过50个!!!'
                });
                return;
            }
            this.$emit('ok', list);
        },
        cancel() {
            this.$emit('cancel');
        },
        matchingSearch() {
            // 清理属性
            this.clearMatchingData();
            // 构造查询规则
            let search = this.search;
            let matching = new RegExp(search,['i']);
            let options = this.options;
            // 遍历options的值获取添加匹配的内容
            for(let key in options) {
                let option = options[key];
                if(matching.test(option.title)) {
                    this.$set(this.matchingData, key, options[key]);
                }
            }
            this.matchingNum = Object.keys(this.matchingData).length;
        },
        toggleCollapsed(name) {
            if(this.activeName == name) {
                this.activeName = -1;
            }else {
                this.activeName = name;
            }
        },
        setList(num) {
            let group = this.groups[num];
            for(let key in group) {
                this.list.push(group[key].title);
            }
            this.activeName = num;
            this.$nextTick(()=> {
                this.$refs.content.scrollTop = 0;
            });
        },
        setGroups() {
            let groups = this.groups;
            let num = this.num;
            let list = this.list;
            Object.keys(this.options).forEach((key, index) =>{
                let option = this.options[key];
                // 新建group
                if(index%num == 0) {
                    // 新建组
                    groups.push({
                        checkAll: false,
                        checkedList: [],
                        list: [],
                        isIndeterminate: true,
                    });
                }
                // 获取的新建的组
                let temp = groups[groups.length-1];
                // 添加整体list
                temp.list.push(option.title);
                // 判断当前数据是否在list中
                if(isInArray(list, option.title)) {
                    temp.checkedList.push(option.title);
                }
            });
            // 遍历groups的值设置状态
            groups.forEach(group=> {
                let checkedCount = group.checkedList.length;
                group.checkAll = checkedCount === group.list.length;
                group.isIndeterminate = checkedCount > 0 && checkedCount < group.list.length;
            });
        },
        handleCheckAllChange(key) {
            let group = this.groups[key];
            let list = group.list.map(item=>{
                return item;
            });
            group.checkedList = group.checkAll ? list : [];
            group.isIndeterminate = false;
            // 展开
            this.activeName = key;
        },
        handleCheckedCitiesChange(key) {
            let group = this.groups[key];
            let checkedCount = group.checkedList.length;
            group.checkAll = checkedCount === group.list.length;
            group.isIndeterminate = checkedCount > 0 && checkedCount < group.list.length;
            // 展开
            this.activeName = key;
        },
        backChecked(key) {
            let group = this.groups[key];
            let checkedList = group.checkedList;
            let list = group.list;
            let result = [];
            list.forEach(item=> {
                if(!isInArray(checkedList, item)) {
                    result.push(item);
                }
            });
            // 设置选中的值
            group.checkedList = result;
            // 修改全选的状态
            this.handleCheckedCitiesChange(key);
        }
    },
    computed: {
        getOptionsLength() {
            return Object.keys(this.options).length;
        },
        allList() {
            let allList = [];
            let options = this.options;
            for(let key in options) {
                allList.push(options[key].title)
            }
            return allList;
        },
        getCheckedList() {
            let result = [];
            let groups = this.groups;
            groups.forEach(group=> {
                group.checkedList.forEach(item=> {
                    result.push(item);
                });
            });
            return result;
        }
    },
    mounted(){
        this.setGroups();
    }
}
</script>
<style scoped>
.drawer-title {
    padding: 0.14rem 0.14rem 0.14rem 0.14rem;
    background-color: #004364;
    background-image: linear-gradient(#02a7fa, #0486c7, #0270a7, #024d72);
}
.drawer-title img {
    vertical-align: middle;
    margin-right: 0.08rem;
}
.drawer-title-search {
    padding-left: 0.18rem;
    padding-right: 0.19rem;
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
}
.drawer-content {
    height: 100%;
    box-sizing: border-box;
    overflow-y: auto;
    padding-left: 0.08rem;
    padding-right: 0.08rem;
}
.el-col-padding-top-bottom-6 {
    padding-top: 0.06rem;
    padding-bottom: 0.06rem;
}
.hdw-collapse-title {
    display: flex;
    flex-direction: row;
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
    padding-left: 0.08rem;
    padding-right: 0.08rem;
}
.hdw-collapse-title:hover {
    background-color: rgb(2, 167, 250, 0.4);
}
.hdw-collapse-item:first-child .hdw-collapse-title {
    border-top: none;
}
.hdw-collapse-item.hdw-collapsed .hdw-collaspe-title {
    border-bottom: none;
}
.hdw-collapse-title .hdw-collapse-icon {
    flex: 1;
    text-align: right;
}
.hdw-collapse-item .hdw-collapse-title .el-icon-d-arrow-right {
    animation: closed .25s;
    animation-fill-mode:forwards;
}
.hdw-collapse-item.hdw-collapsed .hdw-collapse-title .el-icon-d-arrow-right{
    animation: collapsed .25s;
    animation-fill-mode:forwards;
}
.hdw-collapse-item .hdw-collapse-content {
    display: none;
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
    padding-left: 0.26rem;
    padding-right: 0.08rem;
}
.hdw-collapse-item.hdw-collapsed .hdw-collapse-content {
    display: block;
}
.drawer-footer {
    padding-top: 0.08rem;
    padding-bottom: 0.08rem;
    padding-left: 0.08rem;
    padding-right: 0.08rem;
    text-align: right;
    background-color: #004364;
}
.hdw-collapse-title-content .el-icon-remove-outline:hover {
    cursor: pointer;
    color: #d4d1d1;
}
.hdw-collapse-title-content .el-icon-remove-outline:active {
    color: #FF0000;
}
.checkbox-label {
    cursor: pointer;
    margin-left: 0.06rem;
    font-size: 0.14rem;
}
@keyframes collapsed {
    0%   {transform: rotate(90deg);}
    25%  {transform: rotate(45deg);}
    50%  {transform: rotate(0deg);}
    75%  {transform: rotate(-45deg);}
    100% {transform: rotate(-90deg);}
}
@keyframes closed {
    0%   {transform: rotate(-90deg);}
    25%  {transform: rotate(-45deg);}
    50%  {transform: rotate(0deg);}
    75%  {transform: rotate(45deg);}
    100% {transform: rotate(90deg);}
}
</style>
src/components/tree/TreeItem.vue
@@ -2,7 +2,7 @@
    <div class="tree-item">
        <div class="tree-title" :class="{'active': treeData.active}" :style="getPadding" @click="treeClick">
            <span class="iconfont iconfont-flag" v-if="getChildren" :class="getOpen"></span>
            <!-- <span class="iconfont icon-lingxing home-state" :class="getHomeState"></span> -->
            <span class="iconfont icon-lingxing home-state" v-if="!treeData.hideState" :class="getHomeState"></span>
            <span class="tree-title-txt">{{treeData.txt}}</span>
        </div>
        <div class="tree-child" v-if="getChildren" :class="isShow">
@@ -112,7 +112,7 @@
    margin-right: 0.06rem;
}
.active {
    background-color: #15E3F3;
    background-color: #499ca1;
}
</style>
src/pages/batt-list/history-page-plus.vue
New file
@@ -0,0 +1,423 @@
<template>
    <flex-layout>
        <div class="page-header" slot="header">
            <flex-layout direction="row">
                <el-form label-width="100px" inline>
                    <el-form-item label="起始时间" class="el-green">
                        <el-date-picker
                        v-model="record_time"
                        type="datetime"
                        placeholder="起始时间"
                        size="mini"
                        @change="recordTimeChange">
                        </el-date-picker>
                    </el-form-item>
                    <el-form-item label="结束时间" class="el-green">
                        <el-date-picker
                        v-model="record_time1"
                        type="datetime"
                        placeholder="结束时间"
                        size="mini">
                        </el-date-picker>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" size="mini"
                        icon="el-icon-search"
                        :loading="loading"
                        @click="searchHistoryData">查询</el-button>
                    </el-form-item>
                </el-form>
                <div class="page-tools" slot="footer">
                    <el-tooltip
                    class="item"
                    effect="dark"
                    content="导出数据"
                    placement="top">
                        <i class="iconfont icon-daochu"></i>
                    </el-tooltip>
                    <el-tooltip
                    class="item"
                    effect="dark"
                    content="图表配置"
                    placement="top">
                        <i class="iconfont icon-peizhiguanli" @click="drawer=true"></i>
                    </el-tooltip>
                </div>
            </flex-layout>
        </div>
        <line-chart-plus v-if="show" ref="lineChartPlus"></line-chart-plus>
        <el-drawer
        class="el-drawer-science"
        title="我是标题"
        size="4rem"
        :with-header="false"
        :visible.sync="drawer">
            <chart-configs-plus
            v-if="drawer"
            :selecteds="chart.show"
            :all="chart.all"
            @ok="ensureSelects"
            @cancel="drawer=false"></chart-configs-plus>
        </el-drawer>
    </flex-layout>
</template>
<script>
import FlexLayout from '@/components/FlexLayout'
import LineChartPlus from '@/components/chart/LineChartPlus'
import ChartConfigsPlus from '@/components/chart/ChartConfigsPlus'
import {
    isSetOption,
} from '@/assets/js/common'
let optionList = [];
export default {
    components: {
        FlexLayout,
        LineChartPlus,
        ChartConfigsPlus,
    },
    data() {
        let record_time = new Date().format('yyyy-MM-dd hh:mm:ss');
        let record_time1 = new Date().format('yyyy-MM-dd hh:mm:ss');
        return {
            show: true,
            drawer: false,
            loading: false,
            layerLoad: '',
            pickerRange: {
                start: '2019-01-01 00:00:00',
                end: new Date().format('yyyy-MM-dd hh:mm:ss'),
            },
            record_time: new Date(record_time),
            record_time1: new Date(record_time1),
            searchTime: {
                record_time: '',
                record_time1: '',
            },
            chart: {
                id: 'lineChartPlus',
                all: [],
                show: []
            }
        }
    },
    watch: {
        '$store.state.batt': function() {
            this.changeChart();
        },
    },
    methods: {
        // 初始化chart的信息
        initChart() {
            optionList = [];
            this.chart.all = [];
            this.chart.show = [];
        },
        changeChart() {
            let self = this;
            let configs  = this.$store.state.batt.configs;
            let pattern = this.$store.state.batt.pattern;
            let match_type = this.$store.state.batt.match_type;
            this.dev_name = this.$store.state.batt.dev_name;
            // 初始化chart的信息
            this.initChart();
            // 标识位
            let num = 0;
            // 遍历batt根据batt的config设置配置项
            configs.forEach(function(config, index) {
                if(isSetOption(config.title, pattern, match_type)) {
                    // 设置全部图表的信息
                    let all = {
                        name: config.title,
                        state: 'state'+(index+1),
                        step: config.type == 1?'':'end',
                        unit: config.unit,
                    };
                    self.chart.all.push(all);
                    // 设置显示的图表
                    if(num<5) {
                        let show = {
                            name: config.title,
                            state: 'state'+(index+1),
                            step: config.type == 1?'':'end',
                            unit: config.unit,
                        }
                        self.chart.show.push(show);
                    }
                    // 加1
                    num++;
                }
            });
            // 设置配置项的值
            this.setOptionList(this.chart.show);
            // 查询开始和结束日期
            this.searchHistoryTimeRange();
        },
        setOptionList(list) {
            // 设置配置项的值
            optionList = list.map(item=> {
                return {
                    name: item.name,
                    step: item.step,
                    unit: item.unit,
                    data: []
                }
            });
            // 设置配置项
            this.$refs.lineChartPlus.setOption(optionList, {
                clear: true,
            });
        },
        searchHistoryTimeRange() {
            let batt  = this.$store.state.batt;
            if(batt.dev_id == "") {
                return;
            }
            // 构造查询条件
            let searchParams = {
                dev_id: batt.dev_id,
            };
            let self = this;
            this.$api.batt.searchHistoryTimeRange(searchParams)
            .then(function(res) {
                res = JSON.parse(res.data.result);
                self.pickerRange.start = '2019-01-01 00:00:00';
                self.pickerRange.end = new Date().format('yyyy-MM-dd hh:mm:ss');
                if(res.code == 1) {
                    self.pickerRange.start = res.data[0]+' 00:00:00';
                    self.pickerRange.end = res.data[1]+' 23:59:59';
                }
            });
        },
        searchHistoryData() {
            let checkFormResult = this.checkFromData();
            // 设置配置项的值
            this.setOptionList(this.chart.show);
            // 数据检测成功
            if(checkFormResult.code == 1) {
                this.layerLoad = this.$layer.loading(1);
                let searchParams = checkFormResult.data;
                let timeRanges = this.getTimeRanges();
                searchParams.record_time = timeRanges[0].record_time;
                searchParams.record_time1 = timeRanges[0].record_time1;
                // 查询历史数据
                this.$api.batt.searchHistoryData(searchParams)
                .then(res=>{
                    res = JSON.parse(res.data.result);
                    let data = [];
                    if(res.code == 1) {
                        data = res.data;
                    }
                    // 格式化查询结果并添加到图表中
                    this.formatData(data);
                    // 循环执行余下的数据
                    this.loopSearchHistoryData(timeRanges, 1, searchParams);
                }).catch(function(error) {
                    console.log(error);
                    // 关闭等待框
                    this.$layer.close(self.layerLoad);
                    // 提示信息
                    this.$layer.msg('获取数据失败!');
                });
            }else if(checkFormResult.code == -1){
                //alert(checkFormResult.msg);
                let content = checkFormResult.msg.join('<br><br>');
                this.$layer.confirm(content,index => {
                    this.$layer.close(index);
                    if(checkFormResult.flag == 0) {
                        this.record_time = checkFormResult.data;
                        this.record_time1 = new Date(checkFormResult.data.getTime() + 8.64e7 - 1000);
                    }else {
                        this.record_time = new Date(checkFormResult.data.getTime() - 8.64e7 + 1000);
                        this.record_time1 = checkFormResult.data;
                    }
                });
            }else {
                // 提示信息
                this.$layer.msg(checkFormResult.msg);
            }
        },
        getTimeRanges() {
            let record_time = this.record_time.getTime();       // 开始时间
            let record_time1 = this.record_time1.getTime();     // 结束时间
            let step = 3600*1000;       // 一小时
            let nowTime = record_time + step;
            let timeRanges = [];
            while(nowTime<=(record_time1+step)) {
                let endTime = nowTime>record_time1?record_time1:nowTime;
                let tmp = {
                    record_time: new Date(record_time).format('yyyy-MM-dd hh:mm:ss'),
                    record_time1: new Date(endTime).format('yyyy-MM-dd hh:mm:ss'),
                };
                record_time = nowTime + 1000;
                nowTime = record_time + step;
                timeRanges.push(tmp);
            }
            return timeRanges;
        },
        checkFromData() {
            var result = {
                code: 1,
                msg: '条件符合',
                data: []
            };
            var batt  = this.$store.state.batt;
            // 没有dev_id不进行提示
            if(batt.dev_id == '') {
                result.code = 0;
                result.msg =  '请选择站点';
                return result;
            }
            // 测试类型
            let list = [];
            if(this.chart.show.length == 0) {
                result.code = 0;
                result.msg =  '请选择测试类型';
                return result;
            }else {
                list = this.chart.show.map(item=>{
                    return item.state;
                });
            }
            // 校验起始和结束日期
            let pickerRange = this.pickerRange;
            let record_time = this.record_time;
            let record_time1 = this.record_time1;
            // 校验起始时间
            if(record_time.getTime()<new Date(pickerRange.start).getTime()) {
                result.code = -1;
                result.msg = [
                    '数据开始日期:'+pickerRange.start,
                    '当前选择时间:'+record_time.format('yyyy-MM-dd hh:mm:ss'),
                    '建议选择时间:'+pickerRange.start
                ];
                result.flag = 0;
                result.data = new Date(pickerRange.start);
                return result;
            }
            // 校验结束时间
            if(record_time1.getTime()>new Date(pickerRange.end).getTime()) {
                result.code = -1;
                result.msg = [
                    '数据结束日期:'+pickerRange.end,
                    '当前选择时间:'+record_time1.format('yyyy-MM-dd hh:mm:ss'),
                    '建议选择时间:'+pickerRange.end
                ];
                result.flag = 1;
                result.data = new Date(pickerRange.end);
                return result;
            }
            // 测试类型
            if(this.record_time.getTime() > this.record_time1.getTime()) {
                result.code = 0;
                result.msg =  '开始时间大于结束时间';
                return result;
            }
            // 开始日期和结束日期不能超过一天验证
            if(this.record_time1.getTime() - this.record_time.getTime()> 86400196) {
                result.code = 0;
                result.msg =  '时间间隔不能超出一天';
                return result;
            }
            result.data = {
                dev_id: batt.dev_id,
                dev_name: batt.full_name,
                record_time: this.record_time.format("yyyy-MM-dd hh:mm:ss"),
                record_time1: this.record_time1.format("yyyy-MM-dd hh:mm:ss"),
                list: list
            };
            // 存储查询时间
            this.searchTime.record_time = this.record_time.format("yyyy-MM-dd hh:mm:ss");
            this.searchTime.record_time1 = this.record_time1.format("yyyy-MM-dd hh:mm:ss");
            return result;
        },
        loopSearchHistoryData(timeRanges, num, searchParams) {
            let self = this;
            let timeRange = timeRanges[num];
            // 无法获取到timeRange返回
            if(!timeRange) {
                // 关闭等待框
                this.$layer.close(this.layerLoad);
                this.$layer.msg('数据加载完成');
                return;
            }
            // 更新循环量(重要)
            num++;
            // 设置开始和结束日期
            searchParams.record_time = timeRange.record_time;
            searchParams.record_time1 = timeRange.record_time1;
            // 查询历史数据
            this.$api.batt.searchHistoryData(searchParams)
            .then(res=>{
                res = JSON.parse(res.data.result);
                let data = [];
                if(res.code == 1) {
                    data = res.data;
                }
                // 格式化查询结果并添加到图表中
                this.formatData(data);
                // 回到函数
                this.loopSearchHistoryData(timeRanges, num, searchParams);
            }).catch(function(error) {
                console.log(error);
                // 关闭等待框
                this.$layer.close(self.layerLoad);
                // 提示信息
                this.$layer.msg('获取数据失败!');
            });
        },
        formatData(data) {
            // 长度为0
            if(data.length == 0) {
                return;
            }
            // 构着list
            let list = [];
            // 遍历list
            for(let key in this.chart.show) {
                let item = data.map(item=> {
                    return [item.record_time, item.list[key]];
                });
                list.push(item);
            }
            // 设置配置项
            this.$refs.lineChartPlus.appendData(list);
        },
        ensureSelects(list) {
            this.chart.show = list;
            // 关闭弹出框
            this.drawer = false;
            // 生成图表
            this.setOptionList(this.chart.show);
        },
        recordTimeChange() {
        },
    },
    mounted() {
        // 修改echart的配置项
        this.changeChart();
    }
}
</script>
<style scoped>
</style>
src/pages/batt-list/history-page.vue
@@ -224,7 +224,7 @@
                                series: [{
                                    name: config.title,
                                    type: 'line',
                                    smooth: true,
                                    smooth: config.type==1?true:false,
                                    symbolSize: 0,
                                    sampling: 'average',
                                    step: config.type == 1?'':'end',
@@ -365,7 +365,7 @@
                this.resizeCharts();
                // 关闭等待框
                this.$layer.close(this.layerLoad);
                this.$layer.msg('数据加载完成');
                this.$layer.msg('数据加载完成,共'+allData.length+"记录!");
                return;
            }
            // 更新循环量(重要)
@@ -487,7 +487,7 @@
                this.options[key].option.series = [{
                    name: option.title,
                    type: 'line',
                    smooth: true,
                    smooth: option.type==1?true:false,
                    symbolSize: 0,
                    sampling: 'average',
                    step: option.type==1?'':'end',
src/pages/batt-list/index.vue
@@ -2,10 +2,15 @@
    <div class="page-content-container">
        <div class="page-content-left">
            <content-box
            title="站点管理">
            title="站点管理"
            :footer="true">
                <my-tree
                :tree-data="treeData"
                @tree-click="treeClick"></my-tree>
                <div slot="footer">
                    <span class="iconfont icon-lingxing home-status home-state-normal"></span>通信正常
                    <span class="iconfont icon-lingxing home-status home-state-danger"></span>通信中断
                </div>
            </content-box>
        </div>
        <div class="page-content-right">
@@ -22,6 +27,10 @@
<script>
import ContentBox from '@/components/ContentBox'
import MyTree from '@/components/tree/Index'
import {
    Timeout,
    checkIsLink,
} from "@/assets/js/common"
export default {
    components: {
@@ -30,7 +39,8 @@
    },
    data() {
        return {
            treeData: []
            treeData: [],
            timer: new Timeout(),
        }
    },
    methods: {
@@ -46,6 +56,8 @@
                }
                // 格式化数据
                self.formatTreeData(data);
                // 查询机房的连接状态并设置状态
                self.startCheckTreeState();
            });
        },
        formatTreeData(data) {
@@ -128,7 +140,48 @@
            }
            regStr = ''+regStr+'';
            return new RegExp(regStr);
        }
        },
        startCheckTreeState() {
            this.timer.start(()=>{
                this.checkTreeState();
            }, 1000);
        },
        checkTreeState() {
            this.$api.batt.checkHomeState().then(res=>{
                res = JSON.parse(res.data.result);
                if(res.code) {
                    let treeData = this.treeData;
                    let data = res.data;
                    // 遍历data的值
                    data.forEach(item=>{
                        let dev_id = item.dev_id;
                        let isLink = checkIsLink(item.record_time, item.record_time1);
                        let state = isLink?'normal':'danger';
                        // 遍历树第一层
                        treeData.forEach(parent=>{
                            parent.children.forEach(item=>{
                                if(item.dev_id == dev_id) {
                                    this.$set(item, 'state', state);
                                }
                            });
                            let parentState = 'normal';
                            parent.children.forEach(item=>{
                                if(item.state == 'danger') {
                                    parentState= 'danger';
                                }
                            });
                            this.$set(parent, 'state', parentState);
                        });
                    });
                }
                // 开启计时器
                this.timer.open();
            }).catch(error=>{
                // 开启计时器
                this.timer.open();
                console.log(error, '机房连接状态catch');
            });
        }
    },
    mounted() {
        // 查询树状列表数据
@@ -148,6 +201,9 @@
            switch_count: 0,
            configs: []
        });
        // 关闭计时器
        this.timer.stop();
    }
}
</script>
src/pages/batt-list/real-time-page.vue
@@ -145,7 +145,7 @@
                                series: [{
                                    name: config.title,
                                    type: 'line',
                                    smooth: true,
                                    smooth: config.type==1?true:false,
                                    symbolSize: 0,
                                    step: config.type==1?'':'end',
                                    sampling: 'average',
@@ -184,7 +184,7 @@
            });
        },
        searchHistory100() {
            var batt  = this.$store.state.batt;
            var batt = this.$store.state.batt;
            // 没有dev_id不进行查询
            if(batt.dev_id == '') {
                return;
@@ -205,6 +205,30 @@
                if(res.code == 1) {
                    data = res.data;
                }
                // 检测数据是否够100笔
                if(data.length<100) {
                    let differ = 100 - data.length;
                    let listLength = batt.configs.length;
                    let nowTime = new Date().format('yyyy-MM-dd hh:mm:ss');
                    if(data[0]) {
                        nowTime = data[0].record_time;
                    }
                    // 补0
                    for(let i=0; i<differ; i++) {
                        let list = [];
                        for(let k=0;k<listLength;k++) {
                            list.push(0);
                        }
                        let record_time = new Date(new Date(nowTime).getTime()-1000*(i+1)).format('yyyy-MM-dd hh:mm:ss');
                        let tmp = {
                            list: list,
                            record_time: record_time
                        };
                        data.unshift(tmp);
                    }
                }
                // 格式化数据并设置到配置项中
                self.formatHistoryData(data);
            });
@@ -253,7 +277,7 @@
                this.options[key].option.series = [{
                    name: option.title,
                    type: 'line',
                    smooth: true,
                    smooth: option.type==1?true:false,
                    symbolSize: 0,
                    sampling: 'average',
                    step: option.type==1?'': 'end',
@@ -317,6 +341,7 @@
            if(data.length == 0) {
                return;
            }
            let options = this.options;
            // 遍历options的属性
            Object.keys(options).forEach(function(key) {
@@ -355,7 +380,6 @@
                }
                this.tbl.tbData.unshift(realTimeData);
            }
            // 设置图表
            if(this.type=='chart') {
                this.setOptions();
src/pages/file/index.vue
@@ -395,7 +395,8 @@
                        active: false,
                        open: false,
                        end: true,
                        cfg: v.cfg
                        cfg: v.cfg,
                        hideState: true,
                    }
                });
@@ -418,7 +419,8 @@
                                active: false,
                                open: false,
                                end: true,
                                cfg: obj[v][val].cfg
                                cfg: obj[v][val].cfg,
                                hideState: true,
                            });
                            idx = val;
                        });
@@ -428,6 +430,7 @@
                            active: false,
                            open: false,
                            end: false,
                            hideState: true,
                            children
                        });
                    }
src/router/routes.js
@@ -33,6 +33,14 @@
                        },
                        component: (resolve)=>require(['@/pages/batt-list/history-page.vue'], resolve)
                    },
                    {
                        path: 'history-plus',
                        name: 'PagesHistory',
                        meta: {
                            crumb: '历史数据'
                        },
                        component: (resolve)=>require(['@/pages/batt-list/history-page-plus.vue'], resolve)
                    },
                ]
            },
            {