Browse Source

refactor: 更换echarts;删除多余文件

master
wally 4 years ago
parent
commit
b39bd9dce7
  1. 6844
      package-lock.json
  2. 1
      package.json
  3. 109
      src/components/chart/data-report.vue
  4. 0
      src/components/commands/search-commands.vue
  5. 2
      src/components/config/function-config-pending.vue
  6. 2
      src/components/config/network-config-pending.vue
  7. 0
      src/components/config/refresh.vue
  8. 65
      src/components/data-search-bar.vue
  9. 0
      src/components/device/device-edit.vue
  10. 152
      src/components/function-config-applied.vue
  11. 51
      src/components/integral-electric.vue
  12. 53
      src/components/moist-time.vue
  13. 99
      src/components/network-config-applied.vue
  14. 81
      src/components/overview/chart-device-count.vue
  15. 2
      src/components/overview/device-table.vue
  16. 125
      src/components/realtime-data.vue
  17. 0
      src/components/realtime/search-bar.vue
  18. 66
      src/components/statistical/data-report.vue
  19. 4
      src/components/statistical/search-bar.vue
  20. 52
      src/components/total-corrosion.vue
  21. 27
      src/routers/index.js
  22. 62
      src/utils/overview.js
  23. 221
      src/utils/statistical.js
  24. 68
      src/views/access-log.vue
  25. 2
      src/views/commands.vue
  26. 5
      src/views/communication-log.vue
  27. 10
      src/views/data-realtime.vue
  28. 41
      src/views/device-list.vue
  29. 28
      src/views/function-config.vue
  30. 73
      src/views/month-data.vue
  31. 28
      src/views/network-config.vue
  32. 69
      src/views/statistical-realtime.vue
  33. 16
      src/views/statistical-report.vue

6844
package-lock.json

File diff suppressed because it is too large

1
package.json

@ -14,7 +14,6 @@
"prepare": "husky install"
},
"dependencies": {
"@antv/g2plot": "^2.3.39",
"@vitejs/plugin-vue": "^1.9.3",
"axios": "^0.23.0",
"dayjs": "^1.10.7",

109
src/components/chart/data-report.vue

@ -1,109 +0,0 @@
<template>
<el-card class="box-card">
<el-empty v-if="noData" description="暂无数据"></el-empty>
<div id="realtimeContainer"></div>
</el-card>
</template>
<script setup>
import { defineExpose, onMounted, ref } from 'vue';
import { Line } from '@antv/g2plot';
import { formatChartTime } from 'utils/time';
const show = ref(false);
const noData = ref(true);
let bar = null;
//
onMounted(() => {
show.value = true;
});
//
const setDate = data => {
if (bar) {
bar.destroy();
}
bar = new Line('realtimeContainer', {
data,
padding: 'auto',
xField: 'time',
yField: 'value',
seriesField: 'category',
slider: {
start: 0.5,
end: 1,
},
height: 700,
// smooth: true,
point: {
size: 2,
shape: 'circular',
style: {
fill: 'white',
lineWidth: 2,
},
},
});
bar.render();
};
//
const changeDate = value => {
if (!value || !value.length) {
noData.value = true;
return;
}
noData.value = false;
const arr = [];
value.forEach(element => {
const item = { ...element };
const so2Item = { category: 'SO2(ppb)' };
const saltItem = { category: '盐分阻抗(Ω)' };
const environmentTemperatureItem = { category: '环温(℃)' };
const environmentHumidityItem = { category: '环湿(RH%)' };
const corrosion1Item = { category: '锌腐蚀电流(nA)' };
const corrosion2Item = { category: '铜腐蚀电流(nA)' };
const corrosion3Item = { category: '铝腐蚀电流(nA)' };
const corrosion4Item = { category: '钢腐蚀电流(nA)' };
so2Item.time = formatChartTime(item.time);
so2Item.value = item.so2;
arr.push(so2Item);
saltItem.time = formatChartTime(item.time);
saltItem.value = item.salt;
arr.push(saltItem);
environmentTemperatureItem.time = formatChartTime(item.time);
environmentTemperatureItem.value = item.environmentTemperature;
arr.push(environmentTemperatureItem);
environmentHumidityItem.time = formatChartTime(item.time);
environmentHumidityItem.value = item.environmentHumidity;
arr.push(environmentHumidityItem);
corrosion1Item.time = formatChartTime(item.time);
corrosion1Item.value = item.corrosion1;
arr.push(corrosion1Item);
corrosion2Item.time = formatChartTime(item.time);
corrosion2Item.value = item.corrosion2;
arr.push(corrosion2Item);
corrosion3Item.time = formatChartTime(item.time);
corrosion3Item.value = item.corrosion3;
arr.push(corrosion3Item);
corrosion4Item.time = formatChartTime(item.time);
corrosion4Item.value = item.corrosion4;
arr.push(corrosion4Item);
});
setDate(arr);
};
defineExpose({ changeDate });
</script>

0
src/components/search-commands.vue → src/components/commands/search-commands.vue

2
src/components/config/function-config-pending.vue

@ -162,7 +162,7 @@ import { ElMessage } from 'element-plus';
import cloneDeep from 'lodash/cloneDeep';
import isDate from 'lodash/isDate';
import { createConfigFunction, getConfigAppliedFunction } from 'apis';
import Refresh from 'components/refresh.vue';
import Refresh from 'components/config/refresh.vue';
import { corrosiveTypes, functionConfig } from '@/config/config';
const data = ref(functionConfig);

2
src/components/config/network-config-pending.vue

@ -80,7 +80,7 @@ import { computed, defineEmits, defineProps, ref, watch } from 'vue';
import { useStore } from 'vuex';
import { ElMessage } from 'element-plus';
import { createConfigNetwork, getConfigAppliedNetwork } from 'apis';
import Refresh from 'components/refresh.vue';
import Refresh from 'components/config/refresh.vue';
import { networkConfig } from '@/config/config';
const data = ref(networkConfig);

0
src/components/refresh.vue → src/components/config/refresh.vue

65
src/components/data-search-bar.vue

@ -1,65 +0,0 @@
<template>
<el-form :inline="true" :model="searchDevice" ref="searchDeviceForm">
<el-form-item label="选择站点">
<el-select v-model="searchDevice.deviceId" placeholder="请选择站点" @change="change">
<el-option label="全部" value=""></el-option>
<el-option :label="item.address" :value="item.deviceId" v-for="item in devices" :key="item.deviceId"></el-option>
</el-select>
</el-form-item>
<el-form-item label="选择日期">
<el-date-picker
v-model="searchDevice.date"
type="monthrange"
range-separator="~"
start-placeholder="开始月份"
end-placeholder="结束月份"
>
</el-date-picker>
</el-form-item>
<el-form-item class="ml-6">
<el-button type="primary" @click="onSubmit"><i class="el-icon-search mr-2"></i> 查询</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive, ref, computed, defineEmits, watch } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
const emit = defineEmits(['search']);
const searchDevice = reactive({ deviceId: '', date: '' });
const searchDeviceForm = ref(null); // form
const store = useStore();
const devices = computed(() => store.state.device.devices);
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // id
// currentDeviceId
watch(
() => currentDeviceId.value,
newValue => {
if (newValue && searchDevice.deviceId !== newValue) {
searchDevice.deviceId = newValue;
}
},
{ immediate: true },
);
const change = e => {
store.commit('device/setCurrentDeviceId', e);
};
const onSubmit = () => {
searchDeviceForm.value.validate(() => {
const { deviceId, date } = { ...searchDevice };
if (date) {
const start = dayjs(date[0]).valueOf();
const end = dayjs(date[1]).valueOf();
const daterange = [start, end];
emit('search', { deviceId, date: daterange });
} else {
emit('search', { deviceId, date });
}
});
};
</script>

0
src/components/device-edit.vue → src/components/device/device-edit.vue

152
src/components/function-config-applied.vue

@ -1,152 +0,0 @@
<template>
<el-row :gutter="10">
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置金属腐蚀采样频率(分钟)</span>
<span>{{ data.frequency.metal }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置温湿度采样频率(分钟)</span>
<span>{{ data.frequency.th }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置SO2采样频率(分钟)</span>
<span>{{ data.frequency.so2 }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置盐雾采样频率(分钟)</span>
<span>{{ data.frequency.salt }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置时间</span>
<span>{{ formatMsTime(data.time) }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置金属腐蚀采集个数</span>
<span>{{ data.count }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置电池电压低阈值</span>
<span>{{ data.batteryLow }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置电池电压高阈值</span>
<span>{{ data.batteryHigh }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置太阳能电压高阈值</span>
<span>{{ data.sunHigh }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置湿度高阈值</span>
<span>{{ data.humidityHigh }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置温度低阈值</span>
<span>{{ data.temperatureLow }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>设置温度高阈值</span>
<span>{{ data.temperatureHigh }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>选择金属通道1类型</span>
<span>{{ formatCorrosiveType(data.corrosiveType1) }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>选择金属通道2类型</span>
<span>{{ formatCorrosiveType(data.corrosiveType2) }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>选择金属通道3类型</span>
<span>{{ formatCorrosiveType(data.corrosiveType3) }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>选择金属通道4类型</span>
<span>{{ formatCorrosiveType(data.corrosiveType4) }}</span>
</el-col>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>安全模式</span>
<span>{{ formatMode(data.securityMode) }}</span>
</el-col>
</el-row>
<el-row>
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3">
<span>上报类型</span>
<span class="mr-8">{{ formatReportType(data.report.type) }}</span>
<span v-if="data.report.type === 'POINT'">{{ data.report.reportTimePoints }}</span>
<span v-else>{{ data.report.cycle }}分钟</span>
</el-col>
</el-row>
<!-- 刷新下发按钮 -->
<!-- <Refresh @refresh="onSearch(currentDeviceI, 1)" /> -->
</template>
<script setup>
import { computed, defineEmits, defineProps, ref, watch } from 'vue';
import { useStore } from 'vuex';
import { getConfigAppliedFunction } from 'apis';
import { formatMsTime } from 'utils/time';
import { corrosiveTypes, functionConfig } from '@/config/config';
const store = useStore();
const currentDeviceId = computed(() => store.state.device.currentDeviceId);
const data = ref(functionConfig); //
const emit = defineEmits(['status']);
const props = defineProps({ activeName: String });
/**
* 查询网络参数配置 设备真实参数
* @param {string} deviceId 设备id
*/
const onSearch = async deviceId => {
try {
const params = { deviceId };
const resData = await getConfigAppliedFunction(params);
data.value = resData || functionConfig;
if (resData && resData.status) {
emit('status', resData.status);
} else {
emit('status', '');
}
} catch (error) {
throw new Error(error);
}
};
watch(
currentDeviceId,
newDeviceId => {
newDeviceId && props.activeName === 'applied' && onSearch(newDeviceId);
},
{ immediate: true },
);
/**
* 转化安全模式
* @param {string} mode OPEN->加密
*/
function formatMode(mode) {
return mode === 'OPEN' ? '不加密' : '加密';
}
/**
* 转化上报类型显示
* @param {string} reportType 上报类型
*/
function formatReportType(reportType) {
return reportType === 'POINT' ? '按时间点上报' : '按周期上报';
}
/**
* 格式化金属腐蚀类型
* @param {string} type 服务端返回的类型
* @return {string} type 对应的文字名称
*/
function formatCorrosiveType(type) {
const target = corrosiveTypes.find(item => item.value === type);
return target && target.type ? target.type : '';
}
</script>

51
src/components/integral-electric.vue

@ -1,51 +0,0 @@
<template>
<el-card class="box-card">
<div class="text-sm">积分电量(C)</div>
<el-empty description="暂无数据" v-if="noData"></el-empty>
<div id="container"></div>
</el-card>
</template>
<script setup>
import { onMounted, ref, defineExpose } from 'vue';
import { Column } from '@antv/g2plot';
const show = ref(false);
const noData = ref(true);
let bar = null;
//
onMounted(() => {
show.value = true;
});
const setDate = data => {
noData.value = false;
if (bar) {
bar.destroy();
}
bar = new Column('container', {
data,
layout: 'vertical',
xField: 'time',
yField: 'value',
padding: [30, 16, 60, 50],
columnWidthRatio: 0.6, //
yAxis: {
title: {
text: '积分电量',
spacing: 20,
},
},
slider: {
start: 0.1,
end: 0.5,
},
meta: { value: { alias: '积分电量(C)' } },
});
bar.render();
};
defineExpose({ setDate });
</script>

53
src/components/moist-time.vue

@ -1,53 +0,0 @@
<template>
<el-card class="box-card">
<div class="text-sm">月累计湿润时间h</div>
<el-empty description="暂无数据" v-if="noData"></el-empty>
<div id="moistTimeDataContainer"></div>
</el-card>
</template>
<script setup>
import { onMounted, ref, defineExpose } from 'vue';
import { Column } from '@antv/g2plot';
const show = ref(false);
const noData = ref(true);
let bar = null;
//
onMounted(() => {
show.value = true;
});
const setDate = data => {
noData.value = false;
if (bar) {
bar.destroy();
}
bar = new Column('moistTimeDataContainer', {
data,
layout: 'vertical',
xField: 'time',
yField: 'value',
// height: 200,
padding: [30, 16, 60, 50],
color: '#C280FF',
columnWidthRatio: 0.6, //
yAxis: {
title: {
text: '月累计湿润时间',
spacing: 20,
},
},
slider: {
start: 0.1,
end: 0.5,
},
meta: { value: { alias: '月累计湿润时间(h)' } },
});
bar.render();
};
defineExpose({ setDate });
</script>

99
src/components/network-config-applied.vue

@ -1,99 +0,0 @@
<template>
<el-row :gutter="10">
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>上报IP地址1</span>
<span>{{ appliedData.ip1 }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>上报端口号1</span>
<span>{{ appliedData.port1 }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>上报IP地址2</span>
<span>{{ appliedData.ip2 }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>上报端口号2</span>
<span>{{ appliedData.port2 }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>上报IP地址3</span>
<span>{{ appliedData.ip3 }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>上报端口号3</span>
<span>{{ appliedData.port3 }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>上报IP地址4</span>
<span>{{ appliedData.ip4 }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>上报端口号4</span>
<span>{{ appliedData.port4 }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>备用ip地址</span>
<span>{{ appliedData.ipBackup }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>备用端口号</span>
<span>{{ appliedData.portBackup }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>用户名</span>
<span>{{ appliedData.account }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>密码</span>
<span>{{ appliedData.password }}</span>
</el-col>
<el-col :xs="24" :md="12" :lg="8" :xl="6" class="text-sm text-gray-500 py-3">
<span>APN</span>
<span>{{ appliedData.apn }}</span>
</el-col>
</el-row>
<!-- 刷新下发按钮 -->
<!-- <Refresh @refresh="onSearch(currentDeviceI, 1)" /> -->
</template>
<script setup>
import { computed, ref, watch, defineEmits, defineProps } from 'vue';
import { useStore } from 'vuex';
import { getConfigAppliedNetwork } from 'apis/index';
import { networkConfig } from '@/config/config';
const store = useStore();
const currentDeviceId = computed(() => store.state.device.currentDeviceId);
const appliedData = ref(networkConfig); //
const emit = defineEmits(['status']);
const props = defineProps({ activeName: String });
/**
* 查询网络参数配置 设备真实参数
* @param {string} deviceId 设备id
*/
const onSearch = async deviceId => {
try {
const params = { deviceId };
const resData = await getConfigAppliedNetwork(params);
appliedData.value = resData || networkConfig;
if (resData && resData.status) {
emit('status', resData.status);
} else {
emit('status', '');
}
} catch (error) {
throw new Error(error);
}
};
watch(
currentDeviceId,
newDeviceId => {
newDeviceId && props.activeName === 'applied' && onSearch(newDeviceId);
},
{ immediate: true },
);
</script>

81
src/components/overview/chart-device-count.vue

@ -5,84 +5,45 @@
<script setup>
import { computed, onMounted, ref, watchEffect } from 'vue';
import { useStore } from 'vuex';
import { Pie } from '@antv/g2plot';
import isEmpty from 'lodash/isEmpty';
import { generateChartData } from 'utils/overview';
import { generateChartOption } from 'utils/overview';
import * as echarts from 'echarts/core';
import { TitleComponent, TooltipComponent } from 'echarts/components';
import { PieChart } from 'echarts/charts';
import { LabelLayout } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([TitleComponent, TooltipComponent, PieChart, CanvasRenderer, LabelLayout]);
const store = useStore();
const count = computed(() => store.state.device.count);
const isMounted = ref(false);
let piePlot = null;
let myChart = null;
watchEffect(() => {
if (isEmpty(count.value) || !isMounted.value) return;
if (!piePlot) {
if (!myChart) {
initChart();
render(count.value);
} else {
// TODO:
piePlot.destroy();
render(count.value);
}
});
// chart
function initChart() {
const chartDom = document.getElementById('device-overview-container');
myChart = echarts.init(chartDom);
}
// chart
function render(rawCount) {
const data = generateChartData(rawCount);
piePlot = new Pie('device-overview-container', {
legend: false,
appendPadding: 10,
data,
angleField: 'value',
colorField: 'type',
radius: 1,
innerRadius: 0.64,
label: {
type: 'inner',
offset: '-50%',
autoRotate: false,
style: { textAlign: 'center' },
},
statistic: {
title: {
offsetY: -12,
content: '设备总数',
},
content: { offsetY: 0 },
},
//
interactions: [
{ type: 'element-selected' },
{ type: 'element-active' },
{
type: 'pie-statistic-active',
cfg: {
start: [
{
trigger: 'element:mouseenter',
action: 'pie-statistic:change',
},
{
trigger: 'legend-item:mouseenter',
action: 'pie-statistic:change',
},
],
end: [
{
trigger: 'element:mouseleave',
action: 'pie-statistic:reset',
},
{
trigger: 'legend-item:mouseleave',
action: 'pie-statistic:reset',
},
],
},
},
],
});
piePlot.render();
const option = generateChartOption(rawCount);
option && myChart.setOption(option);
}
onMounted(() => {
initChart();
isMounted.value = true;
});
</script>

2
src/components/overview/device-table.vue

@ -40,7 +40,7 @@
<script setup>
import { computed, onMounted, ref } from 'vue';
import { useStore } from 'vuex';
import DeviceEdit from 'components/device-edit.vue';
import DeviceEdit from 'components/device/device-edit.vue';
let timer = null;
const store = useStore();

125
src/components/realtime-data.vue

@ -1,125 +0,0 @@
<template>
<el-card class="box-card">
<el-empty v-if="noData" description="暂无数据"></el-empty>
<div v-show="!noData" id="realtimeContainer"></div>
</el-card>
</template>
<script setup>
import { defineExpose, onMounted, ref } from 'vue';
import { Line } from '@antv/g2plot';
import { formatChartTime } from 'utils/time';
const show = ref(false);
const noData = ref(true);
let bar = null;
//
onMounted(() => {
show.value = true;
});
//
const setDate = data => {
if (bar) {
bar.changeData(data);
return;
}
bar = new Line('realtimeContainer', {
data,
padding: 'auto',
xField: 'time',
yField: 'value',
seriesField: 'category',
slider: {
start: 0.5,
end: 1,
},
height: 700,
// smooth: true,
point: {
size: 2,
shape: 'circular',
style: {
fill: 'white',
lineWidth: 2,
},
},
});
// bar.on('slider:drag', function (event) {
// console.log('event: ', event);
// });
bar.render();
};
//
const changeDate = value => {
if (!value || !value.length) {
noData.value = true;
return;
}
noData.value = false;
const arr = [];
value.forEach(element => {
const item = { ...element };
const so2Item = { category: 'SO2' };
const saltItem = { category: '盐分' };
const environmentTemperatureItem = { category: '环温' };
const environmentHumidityItem = { category: '环湿' };
const deviceTemperatureItem = { category: '机温' };
const deviceHumidityItem = { category: '机湿' };
const corrosion1Item = { category: '腐流1' };
const corrosion2Item = { category: '腐流2' };
const corrosion3Item = { category: '腐流3' };
const corrosion4Item = { category: '腐流4' };
so2Item.time = formatChartTime(item.time);
so2Item.value = item.so2;
arr.push(so2Item);
saltItem.time = formatChartTime(item.time);
saltItem.value = item.salt;
arr.push(saltItem);
environmentTemperatureItem.time = formatChartTime(item.time);
environmentTemperatureItem.value = item.environmentTemperature;
arr.push(environmentTemperatureItem);
environmentHumidityItem.time = formatChartTime(item.time);
environmentHumidityItem.value = item.environmentHumidity;
arr.push(environmentHumidityItem);
deviceTemperatureItem.time = formatChartTime(item.time);
deviceTemperatureItem.value = item.deviceTemperature;
arr.push(deviceTemperatureItem);
deviceHumidityItem.time = formatChartTime(item.time);
deviceHumidityItem.value = item.deviceHumidity;
arr.push(deviceHumidityItem);
corrosion1Item.time = formatChartTime(item.time);
corrosion1Item.value = item.corrosion1;
arr.push(corrosion1Item);
corrosion2Item.time = formatChartTime(item.time);
corrosion2Item.value = item.corrosion2;
arr.push(corrosion2Item);
corrosion3Item.time = formatChartTime(item.time);
corrosion3Item.value = item.corrosion3;
arr.push(corrosion3Item);
corrosion4Item.time = formatChartTime(item.time);
corrosion4Item.value = item.corrosion4;
arr.push(corrosion4Item);
});
setDate(arr);
};
defineExpose({ changeDate });
</script>

0
src/components/search-bar.vue → src/components/realtime/search-bar.vue

66
src/components/statistical/data-report.vue

@ -0,0 +1,66 @@
<template>
<el-card class="box-card">
<el-empty v-if="noData" description="暂无数据"></el-empty>
<div id="realtimeContainer"></div>
</el-card>
</template>
<script setup>
import { defineExpose, defineProps, onMounted, ref } from 'vue';
import { generateChartOption } from 'utils/statistical';
import * as echarts from 'echarts/core';
import { DataZoomComponent, GridComponent, LegendComponent, ToolboxComponent, TooltipComponent } from 'echarts/components';
import { LineChart } from 'echarts/charts';
import { UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
ToolboxComponent,
TooltipComponent,
GridComponent,
LegendComponent,
LineChart,
CanvasRenderer,
UniversalTransition,
DataZoomComponent,
]);
const props = defineProps({ searchHeight: Number });
const show = ref(false);
const noData = ref(true);
let myChart = null;
//
onMounted(() => {
show.value = true;
initChart();
});
// chart
function initChart() {
const chartDom = document.getElementById('realtimeContainer');
const canvasHeight = document.documentElement.clientHeight - props.searchHeight - 150;
console.log(canvasHeight, document.documentElement.clientHeight, props.searchHeight);
chartDom.style.height = `${canvasHeight}px`;
myChart && myChart.dispose();
myChart = echarts.init(chartDom);
}
function render(data) {
myChart && myChart.clear();
if (!data || !data.length) {
noData.value = true;
return;
}
noData.value = false;
if (!myChart) {
initChart();
}
const option = generateChartOption(data);
option && myChart.setOption(option);
}
defineExpose({ render });
</script>

4
src/components/statistical/search-bar.vue

@ -38,12 +38,16 @@
</el-form>
</template>
<script></script>
<script setup>
import { computed, defineEmits, defineProps, reactive, ref, watch } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import { exportHistory } from 'apis';
export default { name: 'StatisticsSearch' };
const emit = defineEmits(['search']);
const searchDevice = reactive({
deviceId: '',

52
src/components/total-corrosion.vue

@ -1,52 +0,0 @@
<template>
<el-card class="box-card">
<div class="text-sm">月累计腐蚀g/m²</div>
<el-empty description="暂无数据" v-if="noData"></el-empty>
<div id="corrosionContainer"></div>
</el-card>
</template>
<script setup>
import { onMounted, ref, defineExpose } from 'vue';
import { Column } from '@antv/g2plot';
const show = ref(false);
const noData = ref(true);
let bar = null;
//
onMounted(() => {
show.value = true;
});
const setDate = data => {
noData.value = false;
if (bar) {
bar.destroy();
}
bar = new Column('corrosionContainer', {
data,
layout: 'vertical',
xField: 'time',
yField: 'value',
padding: [30, 16, 60, 50],
color: '#70B603',
columnWidthRatio: 0.6, //
yAxis: {
title: {
text: '月累计腐蚀',
spacing: 20,
},
},
slider: {
start: 0.1,
end: 0.5,
},
meta: { value: { alias: '月累计腐蚀(g/m²)' } },
});
bar.render();
};
defineExpose({ setDate });
</script>

27
src/routers/index.js

@ -65,33 +65,6 @@ export const routes = [
},
component: () => import('@/views/commands.vue'),
},
// {
// path: '/corrosion/statistical-history',
// name: 'statistical-history',
// meta: {
// title: '历史数据统计',
// icon: 'el-icon-data-line',
// },
// component: () => import('@/views/statistical-history.vue'),
// },
// {
// path: '/corrosion/months',
// name: 'months',
// meta: { title: '月累计数据分析', icon: 'el-icon-data-analysis' },
// component: () => import('@/views/month-data.vue'),
// },
// {
// path: '/corrosion/communication-log',
// name: 'communication-log',
// meta: { title: '通讯日志', icon: 'el-icon-phone-outline' },
// component: () => import('@/views/communication-log.vue'),
// },
// {
// path: '/corrosion/access-log',
// name: 'access-log',
// meta: { title: '访问日志', icon: 'el-icon-message' },
// component: () => import('@/views/access-log.vue'),
// },
];
const router = createRouter({

62
src/utils/overview.js

@ -5,26 +5,58 @@
* @param {number} count.offline 离线数量
* @param {number} count.fault 故障数量
* @param {number} count.warning 报警数量
* @returns {[{type: string, value: number},{type: string, value: number},{type: string, value: number},{type: string, value: number}]}
* @param {number} count.total 总设备数
* @returns {object} {}
*/
// eslint-disable-next-line import/prefer-default-export
export function generateChartData(count) {
return [
{
type: '在线',
value: count.online || 0,
export function generateChartOption(count) {
return {
tooltip: { trigger: 'item' },
title: {
text: '设备总数',
top: '45%',
left: '50%',
textAlign: 'center',
textVerticalAlign: 'middle',
textStyle: { fontSize: 22 },
subtext: count.total,
subtextStyle: { fontSize: 18 },
},
series: [
{
type: '故障',
value: count.fault || 0,
name: '设备统计',
type: 'pie',
radius: ['50%', '98%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2,
},
{
type: '离线',
value: count.offline || 0,
label: {
show: true,
position: 'inside',
fontSize: 18,
color: '#FFF',
// formatter: '{b}\n{c}',
lineHeight: 40,
},
{
type: '报警',
value: count.warning || 0,
emphasis: {
label: {
show: true,
fontSize: 20,
fontWeight: 'bold',
},
},
labelLine: { show: false },
data: [
{ value: count.online, name: '在线' },
{ value: count.offline, name: '离线' },
{ value: count.fault, name: '故障' },
{ value: count.warning, name: '报警' },
],
},
];
],
};
}

221
src/utils/statistical.js

@ -0,0 +1,221 @@
/* eslint-disable max-len,object-curly-newline */
import dayjs from 'dayjs';
const colors = ['#5470C6', '#91CC75', '#EE6666', '#5470C6', '#91CC75', '#EE6666', '#5470C6', '#91CC75'];
/**
* 生成chart所需参数
* @param {Object[]} data 服务端返回数据
* @param {string} data[].time 时间 ms
* @param {string} data[].so2 SO2
* @param {string} data[].salt 盐阻
* @param {string} data[].environmentTemperature 环温
* @param {string} data[].environmentHumidity 环湿
* @param {string} data[].corrosion1
* @param {string} data[].corrosion2
* @param {string} data[].corrosion3
* @param {string} data[].corrosion4
* @returns {{environmentTemperature: *[], corrosionXIN: *[], corrosionGANG: *[], salt: *[], corrosionTONG: *[], so2: *[], corrosionLV: *[], time: *[], environmentHumidity: *[]}}
*/
function generateParams(data) {
const result = {
time: [],
so2: [],
salt: [],
environmentTemperature: [],
environmentHumidity: [],
corrosionXIN: [],
corrosionTONG: [],
corrosionLV: [],
corrosionGANG: [],
};
data.forEach(item => {
result.time.push(dayjs(+item.time).format('YY/MM/MM HH:mm'));
result.so2.push(+item.so2);
result.salt.push(+item.salt);
result.environmentTemperature.push(+item.environmentTemperature);
result.environmentHumidity.push(+item.environmentHumidity);
result.corrosionXIN.push(+item.corrosion1);
result.corrosionTONG.push(+item.corrosion2);
result.corrosionLV.push(+item.corrosion3);
result.corrosionGANG.push(+item.corrosion4);
});
return result;
}
/**
* 生成chart参数
* @param {Object[]} rawData 返回段返回的data数据
* @returns {{yAxis: [{axisLabel: {formatter: string}, axisLine: {lineStyle: {color: string}, show: boolean}, name: string, position: string, type: string},{axisLabel: {formatter: string}, offset: number, axisLine: {lineStyle: {color: string}, show: boolean}, name: string, position: string, type: string},{axisLabel: {formatter: string}, axisLine: {lineStyle: {color: string}, show: boolean}, name: string, position: string, type: string},{axisLabel: {formatter: string}, axisLine: {lineStyle: {color: string}, show: boolean}, name: string, position: string, type: string},{axisLabel: {formatter: string}, axisLine: {lineStyle: {color: string}, show: boolean}, name: string, position: string, type: string},null,null,null], xAxis: [{data: *[], axisTick: {alignWithLabel: boolean}, type: string}], color: string[], grid: {right: string}, legend: {data: string[]}, series: [{data: *[], name: string, type: string},{data: *[], name: string, type: string, yAxisIndex: number},{data: *[], name: string, type: string, yAxisIndex: number},{data: *[], name: string, type: string, yAxisIndex: number},{data: *[], name: string, type: string, yAxisIndex: number},null,null,null], tooltip: {axisPointer: {type: string}, trigger: string}, toolbox: {feature: {saveAsImage: {show: boolean}, restore: {show: boolean}, dataView: {show: boolean, readOnly: boolean}}}}}
*/
// eslint-disable-next-line import/prefer-default-export
export function generateChartOption(rawData) {
const data = generateParams(rawData);
const option = {
color: colors,
tooltip: {
trigger: 'axis',
axisPointer: { type: 'cross' },
},
grid: {
right: '30%',
left: '20%',
},
legend: {
data: ['SO2(ppb)', '盐分阻抗(Ω)', '环温(℃)', '环湿(RH%)', '锌腐蚀电流(nA)', '铜腐蚀电流(nA)', '铝腐蚀电流(nA)', '钢腐蚀电流(nA)'],
},
dataZoom: [{ type: 'inside' }, { type: 'slider' }],
xAxis: [
{
type: 'category',
axisTick: { alignWithLabel: true },
data: data.time,
},
],
yAxis: [
{
type: 'value',
name: 'SO2(ppb)',
position: 'left',
axisLine: {
show: true,
lineStyle: { color: colors[0] },
},
axisLabel: { formatter: '{value}ppb' },
},
{
type: 'value',
name: '盐分阻抗(Ω)',
// min: 0,
// max: 250,
position: 'left',
offset: 70,
axisLine: {
show: true,
lineStyle: { color: colors[1] },
},
axisLabel: { formatter: '{value}Ω' },
},
{
type: 'value',
name: '环温(℃)',
// min: 0,
// max: 25,
position: 'left',
offset: 135,
axisLine: {
show: true,
lineStyle: { color: colors[2] },
},
axisLabel: { formatter: '{value}°C' },
},
{
type: 'value',
name: '环湿(RH%)',
// min: 0,
// max: 25,
position: 'left',
offset: 200,
axisLine: {
show: true,
lineStyle: { color: colors[3] },
},
axisLabel: { formatter: '{value}RH%' },
},
{
type: 'value',
name: '锌腐蚀电流(nA)',
position: 'right',
axisLine: {
show: true,
lineStyle: { color: colors[4] },
},
axisLabel: { formatter: '{value}' },
},
{
type: 'value',
name: '铜腐蚀电流(nA)',
offset: 100,
position: 'right',
axisLine: {
show: true,
lineStyle: { color: colors[5] },
},
axisLabel: { formatter: '{value}' },
},
{
type: 'value',
name: '铝腐蚀电流(nA)',
offset: 200,
position: 'right',
axisLine: {
show: true,
lineStyle: { color: colors[6] },
},
axisLabel: { formatter: '{value}' },
},
{
type: 'value',
name: '钢腐蚀电流(nA)',
offset: 300,
position: 'right',
axisLine: {
show: true,
lineStyle: { color: colors[7] },
},
axisLabel: { formatter: '{value}' },
},
],
series: [
{
name: 'SO2(ppb)',
type: 'line',
data: data.so2,
},
{
name: '盐分阻抗(Ω)',
type: 'line',
yAxisIndex: 1,
data: data.salt,
},
{
name: '环温(℃)',
type: 'line',
yAxisIndex: 2,
data: data.environmentTemperature,
},
{
name: '环湿(RH%)',
type: 'line',
yAxisIndex: 3,
data: data.environmentHumidity,
},
{
name: '锌腐蚀电流(nA)',
type: 'line',
yAxisIndex: 4,
data: data.corrosionXIN,
},
{
name: '铜腐蚀电流(nA)',
type: 'line',
yAxisIndex: 5,
data: data.corrosionTONG,
},
{
name: '铝腐蚀电流(nA)',
type: 'line',
yAxisIndex: 6,
data: data.corrosionLV,
},
{
name: '钢腐蚀电流(nA)',
type: 'line',
yAxisIndex: 7,
data: data.corrosionGANG,
},
],
};
return option;
}

68
src/views/access-log.vue

@ -1,68 +0,0 @@
<template>
<el-row :gutter="24" class="flex flex-column">
<el-col :xs="24" :md="12" v-for="(list, index) in lists" :key="index">
<el-card class="box-card mb-3">
<div class="flex flex-column">
<el-avatar icon="el-icon-user-solid" :size="46" :src="circleUrl"></el-avatar>
<div class="ml-4 flex-1 flex-col">
<span class="font-bold">
{{ list.name }}
</span>
<div class="flex flex-col mt-5 text-sm text-gray-400">
<span class="mb-1">{{ list.operation }}</span>
<span>{{ list.time }}</span>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</template>
<script setup>
import { ref } from 'vue';
const circleUrl = 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png';
const lists = ref([
{
name: '管理员01',
operation: '管理员01',
time: '2021年10月19日',
},
{
name: '管理员01',
operation: '管理员01',
time: '2021年10月19日',
},
{
name: '管理员01',
operation: '管理员01',
time: '2021年10月19日',
},
{
name: '管理员01',
operation: '管理员01',
time: '2021年10月19日',
},
{
name: '管理员01',
operation: '管理员01',
time: '2021年10月19日',
},
{
name: '管理员01',
operation: '管理员01',
time: '2021年10月19日',
},
{
name: '管理员01',
operation: '管理员01',
time: '2021年10月19日',
},
{
name: '管理员01',
operation: '管理员01',
time: '2021年10月19日',
},
]);
</script>

2
src/views/commands.vue

@ -28,7 +28,7 @@
</template>
<script setup>
import SearchCommands from 'components/search-commands.vue';
import SearchCommands from 'components/commands/search-commands.vue';
import { getCommansStatus } from 'apis';
import { onMounted, ref } from 'vue';
import { ElMessage } from 'element-plus';

5
src/views/communication-log.vue

@ -1,5 +0,0 @@
<template>
<div>通讯日志</div>
</template>
<script setup></script>

10
src/views/data-realtime.vue

@ -32,10 +32,10 @@
<el-table-column align="center" label="SO2(ppb)" min-width="90" prop="so2" />
<el-table-column align="center" label="盐温(℃)" min-width="80" prop="salt" />
<el-table-column align="center" label="盐阻(Ω)" min-width="80" prop="salt" />
<el-table-column align="center" label="锌(nA)" min-width="80" prop="corrosion1" />
<el-table-column align="center" label="铜(nA)" min-width="80" prop="corrosion2" />
<el-table-column align="center" label="铝(nA)" min-width="80" prop="corrosion3" />
<el-table-column align="center" label="钢(nA)" min-width="80" prop="corrosion4" />
<el-table-column align="center" label="锌腐蚀电流(nA)" min-width="130" prop="corrosion1" />
<el-table-column align="center" label="铜腐蚀电流(nA)" min-width="130" prop="corrosion2" />
<el-table-column align="center" label="铝腐蚀电流(nA)" min-width="130" prop="corrosion3" />
<el-table-column align="center" label="钢腐蚀电流(nA)" min-width="130" prop="corrosion4" />
</el-table>
<el-pagination
@ -59,7 +59,7 @@
<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useStore } from 'vuex';
import SearchBar from 'components/search-bar.vue';
import SearchBar from 'components/realtime/search-bar.vue';
import { getDatas } from 'apis';
import { ElMessage } from 'element-plus';
import dayjs from 'dayjs';

41
src/views/device-list.vue

@ -33,32 +33,21 @@
<el-table-column align="center" label="联系电话" min-width="150" prop="phone" />
<el-table-column align="center" label="安装时间" min-width="200" prop="installTime" />
<el-table-column align="center" label="正式运行时间" min-width="200" prop="runTime" />
<el-table-column align="center" fixed="right" label="操作" min-width="270">
<el-table-column align="center" fixed="right" label="操作" min-width="180">
<template #default="props">
<el-tooltip class="item" content="网络参数配置" effect="dark" placement="top">
<i class="el-icon-setting text-base text-yellow-600 mx-1" @click="openPage(props.row, 'network-config')"></i>
<el-tooltip class="item" content="参数配置" effect="dark" placement="top">
<i class="el-icon-set-up text-base text-yellow-600 mx-1" @click="openPage(props.row, 'config')"></i>
</el-tooltip>
<el-tooltip class="item" content="功能参数配置" effect="dark" placement="top">
<i class="el-icon-set-up text-base text-yellow-600 mx-1" @click="openPage(props.row, 'function-config')"></i>
</el-tooltip>
<el-tooltip class="item" content="实时数据查看" effect="dark" placement="top">
<el-tooltip class="item" content="实时数据" effect="dark" placement="top">
<i class="el-icon-odometer text-base text-green-600 mx-1" @click="openPage(props.row, 'data-realtime')"></i>
</el-tooltip>
<el-tooltip class="item" content="实时数据统计" effect="dark" placement="top">
<i class="el-icon-data-analysis text-base text-green-600 mx-1" @click="openPage(props.row, 'statistical-realtime')"></i>
</el-tooltip>
<el-tooltip class="item" content="上报数据查看" effect="dark" placement="top">
<i class="el-icon-stopwatch text-base text-green-600 mx-1" @click="openPage(props.row, 'data-report')"></i>
</el-tooltip>
<el-tooltip class="item" content="上报数据统计" effect="dark" placement="top">
<i class="el-icon-data-line text-base text-green-600 mx-1" @click="openPage(props.row, 'statistical-report')"></i>
<el-tooltip class="item" content="历史数据" effect="dark" placement="top">
<i class="el-icon-document-copy text-base text-green-600 mx-1" @click="openPage(props.row, 'history')"></i>
</el-tooltip>
<el-tooltip class="item" content="历史数据查看" effect="dark" placement="top">
<i class="el-icon-document-copy text-base text-green-600 mx-1" @click="openPage(props.row, 'data-history')"></i>
</el-tooltip>
<el-tooltip class="item" content="历史数据下发状态指令" effect="dark" placement="top">
<i class="el-icon-moon-night text-base text-green-600 mx-1" @click="openPage(props.row, 'commands')"></i>
<el-tooltip class="item" content="数据统计" effect="dark" placement="top">
<i class="el-icon-data-line text-base text-green-600 mx-1" @click="openPage(props.row, 'statistical')"></i>
</el-tooltip>
<el-popconfirm title="确定要删除此设备吗?" @confirm="handleDelete(props.row.deviceId)">
<template #reference>
<i class="el-icon-delete text-base text-red-600 mx-1"></i>
@ -91,7 +80,7 @@
<!-- 编辑设备信息 -->
<DeviceEdit :show="editing" @toggle-mdoal="editing = false" />
<el-dialog v-model="deviceCreate.display" title="添加设备" width="80%" top="30px">
<el-dialog v-model="deviceCreate.display" title="添加设备" top="30px" width="80%">
<DeviceCreate @on-hide="deviceCreate.hide()" />
</el-dialog>
</template>
@ -102,8 +91,8 @@ import { useStore } from 'vuex';
import { useRoute, useRouter } from 'vue-router';
import { deleteDevice } from 'apis';
import { ElMessage } from 'element-plus';
import SearchBar from 'components/search-bar.vue';
import DeviceEdit from 'components/device-edit.vue';
import SearchBar from 'components/realtime/search-bar.vue';
import DeviceEdit from 'components/device/device-edit.vue';
import DeviceCreate from 'components/device/device-create.vue';
import useDeviceCreate from '@/hooks/useDeviceCreate';
@ -119,7 +108,11 @@ const currentDeviceId = computed(() => store.state.device.currentDeviceId);
const contentHeight = ref(600);
const editing = ref(false);
const { show, display, hide } = useDeviceCreate();
const deviceCreate = reactive({ show, display, hide }); // hook
const deviceCreate = reactive({
show,
display,
hide,
}); // hook
//
const getDevicesAllData = () => {

28
src/views/function-config.vue

@ -1,28 +0,0 @@
<template>
<!-- 设置站点选择 设备下发状态 -->
<DeviceSelectAndStatus :status="status" />
<el-tabs v-model="activeName">
<el-tab-pane :lazy="true" label="下发参数" name="pending">
<FunctionConfigPending v-if="activeName === 'pending'" :active-name="activeName" @status="setStatus" />
</el-tab-pane>
<el-tab-pane :lazy="true" label="设备参数" name="applied">
<FunctionConfigApplied v-if="activeName === 'applied'" :active-name="activeName" @status="setStatus" />
</el-tab-pane>
</el-tabs>
</template>
<script setup>
import { ref } from 'vue';
import DeviceSelectAndStatus from 'components/config/device-select-and-status.vue';
import FunctionConfigPending from 'components/config/function-config-pending.vue';
import FunctionConfigApplied from 'components/function-config-applied.vue';
const activeName = ref('pending');
const status = ref('PENDING');
//
function setStatus(event) {
status.value = event;
}
</script>

73
src/views/month-data.vue

@ -1,73 +0,0 @@
<template>
<DataSearchBar @search="onSearch" />
<IntegralElectric ref="child1" class="mt-4" />
<TotalCorrosion ref="child2" class="mt-4" />
<MoistTime ref="child3" class="mt-4" />
</template>
<script setup>
import DataSearchBar from 'components/data-search-bar.vue';
import IntegralElectric from 'components/integral-electric.vue';
import TotalCorrosion from 'components/total-corrosion.vue';
import MoistTime from 'components/moist-time.vue';
import { computed, ref } from 'vue';
import { useStore } from 'vuex';
const child1 = ref(null);
const child2 = ref(null);
const child3 = ref(null);
const search = ref({});
const page = ref({ page: 2, size: 10 });
let timer = null;
const store = useStore();
const token = computed(() => store.getters['user/token']);
const electricData = computed(() => store.state.statistics.electricData);
const corrosionData = computed(() => store.state.statistics.corrosionData);
const moistTimeData = computed(() => store.state.statistics.moistTimeData);
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // id
/**
* 获取月累计数据
* @param {*} deviceId // id
* @param {*} date //
* @param {*} sort // 1 -> -1->
*/
const getDate = async () => {
try {
if (token && token.value) {
const options = { ...search.value };
const date = options && options.date ? options.date : [];
const params = {
search: { deviceId: currentDeviceId.value, date },
page: { page: page.value.page, size: page.value.size },
};
await store.dispatch('statistics/getMonthsDate', params);
timer && clearTimeout(timer);
timer = null;
//
child1.value.setDate(electricData.value);
child2.value.setDate(corrosionData.value);
child3.value.setDate(moistTimeData.value);
} else {
timer = setTimeout(() => {
getDate();
});
}
} catch (error) {
console.log('error: ', error);
}
};
getDate();
/**
* 监听search信息
* @param {object} payload search组件emit的数据
*/
const onSearch = payload => {
search.value = { ...payload };
getDate();
};
</script>

28
src/views/network-config.vue

@ -1,28 +0,0 @@
<template>
<!-- 设置站点选择 设备下发状态 -->
<DeviceSelectAndStatus :status="status" />
<el-tabs v-model="activeName">
<el-tab-pane :lazy="true" label="下发参数" name="pending">
<NetworkConfigPending v-if="activeName === 'pending'" :active-name="activeName" @status="setStatus" />
</el-tab-pane>
<el-tab-pane :lazy="true" label="设备参数" name="applied">
<NetworkConfigApplied v-if="activeName === 'applied'" :active-name="activeName" @status="setStatus" />
</el-tab-pane>
</el-tabs>
</template>
<script setup>
import { ref } from 'vue';
import DeviceSelectAndStatus from 'components/config/device-select-and-status.vue';
import NetworkConfigPending from 'components/config/network-config-pending.vue';
import NetworkConfigApplied from 'components/network-config-applied.vue';
const activeName = ref('pending');
const status = ref('');
//
function setStatus(event) {
status.value = event;
}
</script>

69
src/views/statistical-realtime.vue

@ -1,69 +0,0 @@
<template>
<SearchBar @search="getData" @refresh="onRefresh" :show-refresh="true" />
<RealtimeData ref="childRef" class="mt-4" />
</template>
<script setup>
import SearchBar from 'components/search-bar.vue';
import RealtimeData from 'components/realtime-data.vue';
import { computed, ref, onUnmounted } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import { REALTIME_DATA_INTERVAL } from '@/config/config';
const childRef = ref(null);
let timer = null;
let apiTimer = null;
const store = useStore();
const token = computed(() => store.getters['user/token']);
const realtimeData = computed(() => store.state.statistics.realtimeData);
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // id
/**
* 实时数据统计
*/
const getData = async () => {
try {
if (token && token.value) {
const start = +dayjs().startOf('day').format('x');
const end = +dayjs().format('x');
const params = {
deviceId: currentDeviceId.value,
date: [start, end],
type: 0,
};
await store.dispatch('statistics/getRealtimeData', params);
timer && clearTimeout(timer);
timer = null;
childRef.value.changeDate(realtimeData.value.data);
//
if (!apiTimer) {
apiTimer = setInterval(() => {
getData();
}, REALTIME_DATA_INTERVAL);
}
} else {
timer = setTimeout(() => {
getData();
}, 20);
}
} catch (error) {
console.log('error: ', error);
}
};
getData();
onUnmounted(() => {
apiTimer && clearInterval(apiTimer);
apiTimer = null;
});
//
function onRefresh() {
apiTimer && clearInterval(apiTimer);
apiTimer = null;
getData();
}
</script>

16
src/views/statistical-report.vue

@ -1,15 +1,16 @@
<template>
<SearchBar :loading-search="loadingSearch" @search="onSearch" />
<HistoryData ref="childRef" class="mt-4" />
<SearchBar ref="searchBar" :loading-search="loadingSearch" @search="onSearch" />
<HistoryData ref="childRef" class="mt-4" :search-height="searchHeight" />
</template>
<script setup>
import SearchBar from 'components/statistical/search-bar.vue';
import HistoryData from 'components/chart/data-report.vue';
import { computed, ref } from 'vue';
import HistoryData from 'components/statistical/data-report.vue';
import { computed, onMounted, ref } from 'vue';
import { useStore } from 'vuex';
const childRef = ref(null);
const searchBar = ref(null);
let timer = null;
const store = useStore();
@ -18,6 +19,11 @@ const realtimeData = computed(() => store.state.statistics.realtimeData);
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // id
const search = ref({});
const loadingSearch = ref(false);
const searchHeight = ref(50);
onMounted(() => {
searchHeight.value = searchBar.value.$el.clientHeight;
});
/**
* 历史数据统计
@ -42,7 +48,7 @@ const getData = async () => {
await store.dispatch('statistics/getRealtimeData', params);
timer && clearTimeout(timer);
timer = null;
childRef.value.changeDate(realtimeData.value.data);
childRef.value.render(realtimeData.value.data);
loadingSearch.value = false;
} else {
loadingSearch.value = false;

Loading…
Cancel
Save