forked from TALL/tall3-pc-keti
69 changed files with 14689 additions and 8593 deletions
@ -0,0 +1 @@ |
|||||
|
regisrty https://registry.npm.taobao.org |
File diff suppressed because it is too large
@ -1,85 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="searchDeviceForm" :inline="true" :model="searchDevice"> |
|
||||
<el-form-item label="选择站点"> |
|
||||
<el-select v-model="searchDevice.deviceId" placeholder="请选择站点" @change="change"> |
|
||||
<el-option label="全部" value></el-option> |
|
||||
<el-option |
|
||||
v-for="item in devices" |
|
||||
:key="item.deviceId" |
|
||||
:label="`${item.address}-${item.deviceId}`" |
|
||||
:value="item.deviceId" |
|
||||
></el-option> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<!-- <el-form-item label="类型">--> |
|
||||
<!-- <el-select v-model="searchDevice.type" placeholder="选择查询类型">--> |
|
||||
<!-- <el-option label="全部" value=""></el-option>--> |
|
||||
<!-- <el-option label="事件上报" value="EVENT"></el-option>--> |
|
||||
<!-- <el-option label="业务上报" value="DATA"></el-option>--> |
|
||||
<!-- </el-select>--> |
|
||||
<!-- </el-form-item>--> |
|
||||
|
|
||||
<!-- <el-form-item label="状态">--> |
|
||||
<!-- <el-select v-model="searchDevice.status" placeholder="选择查询类型">--> |
|
||||
<!-- <el-option label="全部" value=""></el-option>--> |
|
||||
<!-- <el-option label="PENDING" value="PENDING"></el-option>--> |
|
||||
<!-- <el-option label="SUCCESS" value="SUCCESS"></el-option>--> |
|
||||
<!-- </el-select>--> |
|
||||
<!-- </el-form-item>--> |
|
||||
|
|
||||
<el-form-item> |
|
||||
<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 { computed, defineEmits, reactive, ref, watch } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
|
|
||||
const emit = defineEmits(['search']); |
|
||||
const searchDevice = reactive({ |
|
||||
deviceId: '', |
|
||||
paging: true, |
|
||||
page: 1, |
|
||||
size: 50, |
|
||||
sort: [ |
|
||||
{ |
|
||||
col: 'createdAt', |
|
||||
order: 'DESC', |
|
||||
}, |
|
||||
], |
|
||||
type: '', |
|
||||
status: '', |
|
||||
}); |
|
||||
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(() => { |
|
||||
emit('search', { ...searchDevice }); |
|
||||
}); |
|
||||
}; |
|
||||
</script> |
|
@ -1,92 +0,0 @@ |
|||||
<template> |
|
||||
<template v-if="data"> |
|
||||
<el-table :data="data" :max-height="contentHeight" border stripe style="width: 100%"> |
|
||||
<el-table-column type="expand"> |
|
||||
<template #default="props"> |
|
||||
<div class="mx-4"> |
|
||||
<FunctionConfigApplied v-if="props.row" :data="props.row" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="设备ID" min-min-width="100" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="上次配置时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.settingTime)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="状态" min-width="100"> |
|
||||
<template #default="scope"> |
|
||||
<StatusTagPending :type="scope.row.settingStatus" /> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
|
|
||||
<!-- <el-pagination--> |
|
||||
<!-- :current-page="devicesAll.page.page"--> |
|
||||
<!-- :default-page-size="50"--> |
|
||||
<!-- :page-count="devicesAll.page.count"--> |
|
||||
<!-- :page-size="devicesAll.page.size"--> |
|
||||
<!-- :page-sizes="[1, 10, 20, 50, 100]"--> |
|
||||
<!-- :total="devicesAll.page.total"--> |
|
||||
<!-- background--> |
|
||||
<!-- class="my-3 float-right"--> |
|
||||
<!-- layout="total, sizes, prev, pager, next, jumper"--> |
|
||||
<!-- @size-change="onSizeChange"--> |
|
||||
<!-- @current-change="onCurrentPageChange"--> |
|
||||
<!-- ></el-pagination>--> |
|
||||
</template> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, onMounted, ref, watchEffect } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { getConfigFunction } from 'apis'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import StatusTagPending from 'components/config/status-tag-pending.vue'; |
|
||||
import FunctionConfigApplied from 'components/config/function-config-applied.vue'; |
|
||||
|
|
||||
const store = useStore(); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); |
|
||||
const contentHeight = ref(600); |
|
||||
const data = ref(null); |
|
||||
|
|
||||
// 设置表格高度 |
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 250; |
|
||||
}); |
|
||||
|
|
||||
watchEffect(() => { |
|
||||
const deviceId = currentDeviceId.value; |
|
||||
onSearch(deviceId); |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 删除 |
|
||||
* @param {number} page 页码 |
|
||||
* @param {number} size 每页条数 |
|
||||
*/ |
|
||||
async function onSearch(deviceId = currentDeviceId.value) { |
|
||||
const params = { deviceId }; |
|
||||
try { |
|
||||
const resData = await getConfigFunction(params); |
|
||||
data.value = resData; |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error.message); |
|
||||
console.error(error); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
currentDeviceId.value && onSearch(currentDeviceId.value); |
|
||||
|
|
||||
// 当前页码变化 |
|
||||
// const onCurrentPageChange = page => { |
|
||||
// onSearch(page, devicesAll.value.page.size || 50); |
|
||||
// }; |
|
||||
|
|
||||
// 每页条数变化 |
|
||||
// const onSizeChange = size => { |
|
||||
// onSearch(1, size); |
|
||||
// }; |
|
||||
</script> |
|
@ -1,93 +0,0 @@ |
|||||
<template> |
|
||||
<template v-if="data"> |
|
||||
<el-table :data="data" :max-height="contentHeight" border stripe style="width: 100%"> |
|
||||
<el-table-column type="expand"> |
|
||||
<template #default="props"> |
|
||||
<div class="mx-4"> |
|
||||
<NetworkConfigApplied v-if="props.row" :data="props.row" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="设备ID" min-min-width="100" prop="deviceId" /> |
|
||||
|
|
||||
<el-table-column align="center" label="上次配置时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.settingTime)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="状态" min-width="100"> |
|
||||
<template #default="scope"> |
|
||||
<StatusTagPending :type="scope.row.settingStatus" /> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
|
|
||||
<!-- <el-pagination--> |
|
||||
<!-- :current-page="devicesAll.page.page"--> |
|
||||
<!-- :default-page-size="50"--> |
|
||||
<!-- :page-count="devicesAll.page.count"--> |
|
||||
<!-- :page-size="devicesAll.page.size"--> |
|
||||
<!-- :page-sizes="[1, 10, 20, 50, 100]"--> |
|
||||
<!-- :total="devicesAll.page.total"--> |
|
||||
<!-- background--> |
|
||||
<!-- class="my-3 float-right"--> |
|
||||
<!-- layout="total, sizes, prev, pager, next, jumper"--> |
|
||||
<!-- @size-change="onSizeChange"--> |
|
||||
<!-- @current-change="onCurrentPageChange"--> |
|
||||
<!-- ></el-pagination>--> |
|
||||
</template> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, onMounted, ref, watchEffect } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import StatusTagPending from 'components/config/status-tag-pending.vue'; |
|
||||
import NetworkConfigApplied from 'components/config/network-config-applied.vue'; |
|
||||
import { getConfigNetwork } from 'apis'; |
|
||||
|
|
||||
const store = useStore(); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); |
|
||||
const contentHeight = ref(600); |
|
||||
const data = ref(null); |
|
||||
|
|
||||
// 设置表格高度 |
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 250; |
|
||||
}); |
|
||||
|
|
||||
watchEffect(() => { |
|
||||
const deviceId = currentDeviceId.value; |
|
||||
onSearch(deviceId); |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 删除 |
|
||||
* @param {number} page 页码 |
|
||||
* @param {number} size 每页条数 |
|
||||
*/ |
|
||||
async function onSearch(deviceId = currentDeviceId.value) { |
|
||||
const params = { deviceId }; |
|
||||
try { |
|
||||
const resData = await getConfigNetwork(params); |
|
||||
data.value = resData; |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error.message); |
|
||||
console.error(error); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
currentDeviceId.value && onSearch(currentDeviceId.value); |
|
||||
|
|
||||
// 当前页码变化 |
|
||||
// const onCurrentPageChange = page => { |
|
||||
// onSearch(page, devicesAll.value.page.size || 50); |
|
||||
// }; |
|
||||
|
|
||||
// 每页条数变化 |
|
||||
// const onSizeChange = size => { |
|
||||
// onSearch(1, size); |
|
||||
// }; |
|
||||
</script> |
|
@ -1,42 +0,0 @@ |
|||||
<script setup> |
|
||||
import { computed, ref, watch } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
|
|
||||
const store = useStore(); |
|
||||
const devices = computed(() => store.state.device.devices); // 设备/站点列表 |
|
||||
const deviceId = ref(''); // 选中的设备id |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // 正在操作的设备的id |
|
||||
|
|
||||
// 监听currentDeviceId |
|
||||
watch( |
|
||||
() => currentDeviceId.value, |
|
||||
newValue => { |
|
||||
if (newValue && deviceId.value !== newValue) { |
|
||||
deviceId.value = newValue; |
|
||||
} |
|
||||
}, |
|
||||
{ immediate: true }, |
|
||||
); |
|
||||
|
|
||||
/** |
|
||||
* 设备id修改 |
|
||||
* 更新store里的deviceId |
|
||||
*/ |
|
||||
function onChange(event) { |
|
||||
store.commit('device/setCurrentDeviceId', event); |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<template> |
|
||||
<div class="mb-3"> |
|
||||
<span class="text-sm text-gray-500">选择站点:</span> |
|
||||
<el-select v-model="deviceId" placeholder="选择站点" @change="onChange"> |
|
||||
<el-option |
|
||||
v-for="item in devices" |
|
||||
:key="item.deviceId" |
|
||||
:label="`${item.address}-${item.deviceId}`" |
|
||||
:value="item.deviceId" |
|
||||
></el-option> |
|
||||
</el-select> |
|
||||
</div> |
|
||||
</template> |
|
@ -1,77 +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>电池电压低阈值(V):</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>电池电压高阈值(V):</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>太阳能板电压高阈值(V):</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>湿度高阈值(RH%):</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>金属腐蚀采集个数:</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>{{ SER[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">{{ REPORT_TYPE[data.report.type] }}</span> |
|
||||
|
|
||||
<span v-if="data.report.type === 'POINT'"> |
|
||||
<span v-for="item in data.report.timePoints" :key="item" class="mr-3">{{ item }}</span> |
|
||||
</span> |
|
||||
<span v-else>{{ data.report.cycle }}分钟</span> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<!-- 刷新下发按钮 --> |
|
||||
<!-- <Refresh @refresh="onSearch(currentDeviceI, 1)" /> --> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { defineProps } from 'vue'; |
|
||||
import { SER } from '@/config/log'; |
|
||||
import { REPORT_TYPE } from '@/config/config'; |
|
||||
|
|
||||
defineProps({ data: Object }); |
|
||||
</script> |
|
@ -1,287 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="functionForm" :model="data" label-position="top"> |
|
||||
<StatusAndLastTime v-if="data.settingStatus" :setting-status="data.settingStatus" :setting-time="+data.settingTime" /> |
|
||||
|
|
||||
<el-row :gutter="20"> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="金属腐蚀采样频率(分钟)" prop="frequency.metal"> |
|
||||
<el-input-number v-model="data.frequency.metal" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="温湿度采样频率(分钟)" prop="frequency.th"> |
|
||||
<el-input-number v-model="data.frequency.th" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="SO2采样频率(分钟)" prop="frequency.so2"> |
|
||||
<el-input-number v-model="data.frequency.so2" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="盐分采样频率(分钟)" prop="frequency.salt"> |
|
||||
<el-input-number v-model="data.frequency.salt" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="电池电压低阈值(V)" prop="batteryLow"> |
|
||||
<el-input-number v-model="data.batteryLow" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="电池电压高阈值(V)" prop="batteryHigh"> |
|
||||
<el-input-number v-model="data.batteryHigh" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="太阳能板电压高阈值(V)" prop="sunHigh"> |
|
||||
<el-input-number v-model="data.sunHigh" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="湿度高阈值(RH%)" prop="humidityHigh"> |
|
||||
<el-input-number v-model="data.humidityHigh" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="温度低阈值(℃)" prop="temperatureLow"> |
|
||||
<el-input-number v-model="data.temperatureLow" :min="-30" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="温度高阈值(℃)" prop="temperatureHigh"> |
|
||||
<el-input-number v-model="data.temperatureHigh" :min="0" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="金属腐蚀采集个数" prop="count"> |
|
||||
<el-input v-model="data.count" :min="0" disabled style="width: 180px" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="安全模式" prop="securityMode"> |
|
||||
<!-- <el-input v-model="data.securityMode"></el-input> --> |
|
||||
<el-radio v-model="data.securityMode" label="OPEN">不加密</el-radio> |
|
||||
<el-radio v-model="data.securityMode" label="ENCRYPTION">加密</el-radio> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<el-row :gutter="20"> |
|
||||
<el-col :span="12"> |
|
||||
<el-form-item label="上报时间" prop="report.type" style="margin-bottom: 0 !important"> |
|
||||
<el-radio-group v-model="data.report.type"> |
|
||||
<el-radio label="POINT">定时上报</el-radio> |
|
||||
<el-radio label="CYCLE">周期上报(分钟)</el-radio> |
|
||||
</el-radio-group> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<!-- 定时上报输入--> |
|
||||
<el-row v-if="data.report.type === 'POINT'" :gutter="20"> |
|
||||
<el-col v-for="(item, index) in data.report.timePoints" :key="index" :lg="6" :md="12" :sm="24" :xl="4"> |
|
||||
<el-form-item prop="report.timePoints" style="margin-bottom: 10px !important"> |
|
||||
<el-time-picker v-model="data.report.timePoints[index]" :placeholder="`上报时间点${index + 1}`" format="HH:mm"></el-time-picker> |
|
||||
<el-button circle type="text" @click="removeTimePoint(index)"> |
|
||||
<i class="el-icon-circle-close text-lg text-red-600"></i> |
|
||||
</el-button> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col v-if="!data.report.timePoints || data.report.timePoints.length < 6" :lg="6" :md="8" :sm="12" :xl="4"> |
|
||||
<el-button plain @click="addTimePoints"> |
|
||||
<i class="el-icon-plus px-6"></i> |
|
||||
</el-button> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
<!--周期上报输入--> |
|
||||
<el-row v-else :gutter="20"> |
|
||||
<el-col :span="12"> |
|
||||
<el-form-item prop="report.cycle"> |
|
||||
<el-input-number v-model="data.report.cycle" :max="1440" :min="10" step="10" /> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<el-row :gutter="20" class="mt-5 pl-2"> |
|
||||
<el-form-item> |
|
||||
<el-button type="primary" @click="onSubmit">提交</el-button> |
|
||||
<el-button @click="onReset">重置</el-button> |
|
||||
</el-form-item> |
|
||||
</el-row> |
|
||||
</el-form> |
|
||||
|
|
||||
<!-- 刷新下发按钮 --> |
|
||||
<Refresh @refresh="onSearch(currentDeviceId, 1)" /> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, defineEmits, defineProps, ref, watch } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import cloneDeep from 'lodash/cloneDeep'; |
|
||||
import isDate from 'lodash/isDate'; |
|
||||
import { createConfigFunction, getConfigAppliedFunction } from 'apis'; |
|
||||
import Refresh from 'components/config/refresh.vue'; |
|
||||
import StatusAndLastTime from 'components/config/status-and-last-time.vue'; |
|
||||
import { functionConfig } from '@/config/config'; |
|
||||
|
|
||||
const data = ref(functionConfig); |
|
||||
|
|
||||
const functionForm = ref(null); // form |
|
||||
const store = useStore(); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); |
|
||||
const emit = defineEmits(['status']); |
|
||||
const props = defineProps({ activeName: String }); |
|
||||
|
|
||||
/** |
|
||||
* 格式化时间 |
|
||||
*/ |
|
||||
const formatTime = date => { |
|
||||
if (!isDate(date)) return ''; |
|
||||
const hour = date.getHours(); |
|
||||
const minute = date.getMinutes(); |
|
||||
return `${hour}:${minute}`; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询网络参数配置 |
|
||||
* @param {string} deviceId 设备id |
|
||||
* @param {number} type 0数据库查询 1刷新查询 |
|
||||
*/ |
|
||||
async function onSearch(deviceId, type = 0) { |
|
||||
const params = { |
|
||||
deviceId, |
|
||||
type, |
|
||||
}; |
|
||||
const resData = await getConfigAppliedFunction(params); |
|
||||
if (resData && resData.time) { |
|
||||
// 格式化ms为日期格式 |
|
||||
resData.time = new Date(+resData.time); |
|
||||
} |
|
||||
if (resData && resData.status) { |
|
||||
// 设置 设置状态 |
|
||||
emit('status', resData.status); |
|
||||
} else { |
|
||||
emit('status', ''); |
|
||||
} |
|
||||
|
|
||||
if (resData && resData.report.type === 'POINT') { |
|
||||
const { timePoints } = resData.report; |
|
||||
// 如果是按照时间点上传的 |
|
||||
if (timePoints && timePoints.length) { |
|
||||
for (let i = 0; i < timePoints.length; i++) { |
|
||||
const date = new Date().toLocaleDateString(); |
|
||||
const item = resData.report.timePoints[i]; |
|
||||
const reg = /^\d{1,2}:\d{1,2}$/; |
|
||||
if (item && reg.test(item)) { |
|
||||
resData.report.timePoints[i] = new Date(`${date} ${item}`); |
|
||||
} else { |
|
||||
resData.report.timePoints[i] = ''; |
|
||||
} |
|
||||
} |
|
||||
} else { |
|
||||
resData.report = ['']; |
|
||||
} |
|
||||
} |
|
||||
data.value = resData || functionConfig; |
|
||||
} |
|
||||
|
|
||||
watch( |
|
||||
currentDeviceId, |
|
||||
newDeviceId => { |
|
||||
newDeviceId && props.activeName === 'function' && onSearch(newDeviceId); |
|
||||
}, |
|
||||
{ immediate: true }, |
|
||||
); |
|
||||
|
|
||||
// 提交表单 |
|
||||
const onSubmit = () => { |
|
||||
functionForm.value.validate(async () => { |
|
||||
try { |
|
||||
if (!currentDeviceId.value) { |
|
||||
return ElMessage.error('请选择站点'); |
|
||||
} |
|
||||
const param = cloneDeep({ |
|
||||
...data.value, |
|
||||
deviceId: currentDeviceId.value, |
|
||||
}); |
|
||||
param.time = new Date(param.time).getTime(); |
|
||||
if (param.report.type === 'POINT') { |
|
||||
// 按时间点上报 格式化时间格式 |
|
||||
const points = [...param.report.timePoints]; |
|
||||
|
|
||||
for (let i = 0; i < points.length; i++) { |
|
||||
if (points[i]) { |
|
||||
points[i] = formatTime(points[i]); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const validated = validateTimePoints(points); |
|
||||
if (!validated) { |
|
||||
ElMessage.error('上报时间点不能重复'); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
param.report.timePoints = points; |
|
||||
} |
|
||||
await createConfigFunction(param); |
|
||||
ElMessage.success('提交成功'); |
|
||||
} catch (error) { |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
// 重置表单 |
|
||||
const onReset = () => { |
|
||||
functionForm.value.resetFields(); |
|
||||
}; |
|
||||
|
|
||||
// currentDeviceId && onSearch(currentDeviceId.value); |
|
||||
// 添加时间上报时间点输入框 |
|
||||
function addTimePoints() { |
|
||||
const { timePoints } = data.value.report; |
|
||||
console.log(data.value.report); |
|
||||
if (!timePoints || !timePoints.length) { |
|
||||
data.value.report.timePoints = ['']; |
|
||||
} else { |
|
||||
if (timePoints.length >= 6) return; |
|
||||
data.value.report.timePoints.push(''); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 验证上报时间点是否重复 |
|
||||
* @param {array|null} points ["时:分"] |
|
||||
* @returns {boolean} |
|
||||
*/ |
|
||||
function validateTimePoints(points) { |
|
||||
if (!points || !points.length) return true; |
|
||||
const obj = {}; |
|
||||
points.forEach(item => { |
|
||||
if (obj[item]) { |
|
||||
obj[item] += 1; |
|
||||
} else { |
|
||||
obj[item] = 1; |
|
||||
} |
|
||||
}); |
|
||||
// eslint-disable-next-line no-restricted-syntax |
|
||||
for (const key in obj) { |
|
||||
if (obj[key] > 1) return false; |
|
||||
} |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 移除上报时间点 |
|
||||
* @param {number} index 索引 |
|
||||
*/ |
|
||||
function removeTimePoint(index) { |
|
||||
data.value.report.timePoints.splice(index, 1); |
|
||||
} |
|
||||
</script> |
|
@ -1,65 +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>上报IP地址1:</span> |
|
||||
<span>{{ data.ip1 }}</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>{{ data.port1 }}</span> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3"> |
|
||||
<span>上报IP地址2:</span> |
|
||||
<span>{{ data.ip2 }}</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>{{ data.port2 }}</span> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3"> |
|
||||
<span>上报IP地址3:</span> |
|
||||
<span>{{ data.ip3 }}</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>{{ data.port3 }}</span> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3"> |
|
||||
<span>上报IP地址4:</span> |
|
||||
<span>{{ data.ip4 }}</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>{{ data.port4 }}</span> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3"> |
|
||||
<span>备用ip地址:</span> |
|
||||
<span>{{ data.ipBackup }}</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.portBackup }}</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.account }}</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.password }}</span> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :xl="6" :xs="24" class="text-sm text-gray-500 py-3"> |
|
||||
<span>APN:</span> |
|
||||
<span>{{ data.apn }}</span> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<!-- 刷新下发按钮 --> |
|
||||
<!-- <Refresh @refresh="onSearch(currentDeviceI, 1)" /> --> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { defineProps } from 'vue'; |
|
||||
|
|
||||
defineProps({ data: Object }); |
|
||||
</script> |
|
@ -1,150 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="networkForm" :model="data" label-position="top"> |
|
||||
<StatusAndLastTime v-if="data.settingStatus" :setting-status="data.settingStatus" :setting-time="+data.settingTime" /> |
|
||||
|
|
||||
<el-row :gutter="20"> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="上报IP1地址" prop="ip1"> |
|
||||
<el-input v-model="data.ip1"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="上报端口号1" prop="port1"> |
|
||||
<el-input v-model="data.port1"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="上报IP2地址" prop="ip2"> |
|
||||
<el-input v-model="data.ip2"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="上报端口号2" prop="port2"> |
|
||||
<el-input v-model="data.port2"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="上报IP3地址" prop="ip3"> |
|
||||
<el-input v-model="data.ip3"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="上报端口号3" prop="port3"> |
|
||||
<el-input v-model="data.port3"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="备用ip地址" prop="ipBackup"> |
|
||||
<el-input v-model="data.ipBackup"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="备用端口号" prop="portBackup"> |
|
||||
<el-input v-model="data.portBackup"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="用户名" prop="account"> |
|
||||
<el-input v-model="data.account"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="密码" prop="password"> |
|
||||
<el-input v-model="data.password"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="APN" prop="apn"> |
|
||||
<el-input v-model="data.apn"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<el-row :gutter="20" class="mt-5 pl-2"> |
|
||||
<el-form-item> |
|
||||
<el-button type="primary" @click="onSubmit">提交</el-button> |
|
||||
<el-button @click="onReset">重置</el-button> |
|
||||
</el-form-item> |
|
||||
</el-row> |
|
||||
</el-form> |
|
||||
|
|
||||
<!-- 刷新下发按钮 --> |
|
||||
<Refresh @refresh="onSearch(currentDeviceId, 1)" /> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
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/config/refresh.vue'; |
|
||||
import StatusAndLastTime from 'components/config/status-and-last-time.vue'; |
|
||||
import { networkConfig } from '@/config/config'; |
|
||||
|
|
||||
const data = ref(networkConfig); |
|
||||
const networkForm = ref(null); // form |
|
||||
const store = useStore(); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); |
|
||||
const emit = defineEmits(['status']); |
|
||||
const props = defineProps({ activeName: String }); |
|
||||
|
|
||||
/** |
|
||||
* 查询网络参数配置 |
|
||||
* @param {string} deviceId 设备id |
|
||||
* @param {number} type 0数据库查询 1刷新查询 |
|
||||
*/ |
|
||||
async function onSearch(deviceId, type = 0) { |
|
||||
try { |
|
||||
const params = { |
|
||||
deviceId, |
|
||||
type, |
|
||||
}; |
|
||||
const resData = await getConfigAppliedNetwork(params); |
|
||||
data.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 === 'network' && onSearch(newDeviceId); |
|
||||
}, |
|
||||
{ immediate: true }, |
|
||||
); |
|
||||
|
|
||||
// 提交表单 |
|
||||
const onSubmit = () => { |
|
||||
networkForm.value.validate(async () => { |
|
||||
const param = { |
|
||||
...data.value, |
|
||||
deviceId: currentDeviceId.value, |
|
||||
}; |
|
||||
try { |
|
||||
await createConfigNetwork(param); |
|
||||
ElMessage.success('提交成功'); |
|
||||
} catch (error) { |
|
||||
console.error('error: ', error); |
|
||||
ElMessage.error('提交失败, 请稍后重试'); |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
// 重置表单 |
|
||||
const onReset = () => { |
|
||||
networkForm.value.resetFields(); |
|
||||
}; |
|
||||
|
|
||||
// currentDeviceId && onSearch(currentDeviceId.value); |
|
||||
</script> |
|
@ -1,19 +0,0 @@ |
|||||
<script setup> |
|
||||
import { defineEmits } from 'vue'; |
|
||||
|
|
||||
defineEmits(['refresh']); |
|
||||
</script> |
|
||||
|
|
||||
<template> |
|
||||
<el-tooltip class="refresh-btn shadow-md" effect="dark" content="刷新" placement="top-start"> |
|
||||
<el-button type="primary" icon="el-icon-refresh" circle @click="$emit('refresh')"></el-button> |
|
||||
</el-tooltip> |
|
||||
</template> |
|
||||
|
|
||||
<style scoped> |
|
||||
.refresh-btn { |
|
||||
position: fixed; |
|
||||
right: 20px; |
|
||||
bottom: 20px; |
|
||||
} |
|
||||
</style> |
|
@ -1,19 +0,0 @@ |
|||||
<template> |
|
||||
<el-row class="text-gray-500 text-sm my-2 flex items-center"> |
|
||||
<span class="mr-10"> |
|
||||
配置状态:<el-tag :type="PEND_TYPE[settingStatus].type">{{ PEND_TYPE[settingStatus].text }}</el-tag> |
|
||||
</span> |
|
||||
<span>最后配置时间:{{ dayjs(settingTime).format('YYYY-MM-DD HH:mm:ss') }}</span> |
|
||||
</el-row> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { defineProps } from 'vue'; |
|
||||
import { PEND_TYPE } from '@/config/config'; |
|
||||
|
|
||||
defineProps({ |
|
||||
settingStatus: String, |
|
||||
settingTime: Number, |
|
||||
}); |
|
||||
</script> |
|
@ -1,12 +0,0 @@ |
|||||
<template> |
|
||||
<el-tag :type="PEND_TYPE[type].type"> |
|
||||
{{ PEND_TYPE[type].text }} |
|
||||
</el-tag> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { defineProps } from 'vue'; |
|
||||
import { PEND_TYPE } from '@/config/config'; |
|
||||
|
|
||||
defineProps({ type: String }); |
|
||||
</script> |
|
@ -1,193 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="deviceCreate" :model="data" :rules="deviceRules" label-position="top"> |
|
||||
<el-row :gutter="20"> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="设备ID(6位)" prop="deviceId"> |
|
||||
<el-input v-model="data.deviceId"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="站点名称" prop="address"> |
|
||||
<el-input v-model="data.address"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="产品类型" prop="type"> |
|
||||
<!-- <el-input v-model="data.securityMode"></el-input> --> |
|
||||
<el-radio v-model="data.type" label="IACD">大气腐蚀</el-radio> |
|
||||
<el-radio v-model="data.type" label="OTHER">其他</el-radio> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="设备完整ID" prop="deviceFullId"> |
|
||||
<el-input v-model="data.deviceFullId"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="地区" prop="area"> |
|
||||
<el-input v-model="data.area"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="联系人" prop="contact"> |
|
||||
<el-input v-model="data.contact"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="电话" prop="phone"> |
|
||||
<el-input v-model="data.phone"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="经度" prop="lon"> |
|
||||
<el-input v-model="data.lon"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="纬度" prop="lat"> |
|
||||
<el-input v-model="data.lat"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="负责人" prop="head"> |
|
||||
<el-input v-model="data.head"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="安装位置" prop="installLocation"> |
|
||||
<el-input v-model="data.installLocation"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="安装时间" prop="installTime"> |
|
||||
<el-date-picker v-model="data.installTime" placeholder="安装时间" style="width: 100%" type="datetime"></el-date-picker> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="正式运行时间" prop="runTime"> |
|
||||
<el-date-picker v-model="data.runTime" placeholder="正式运行时间" style="width: 100%" type="datetime"></el-date-picker> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="链路地址" prop="linkAddress"> |
|
||||
<el-input v-model="data.linkAddress"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="探头编号" prop="probNo"> |
|
||||
<el-input v-model="data.probNo"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="试样" prop="simple"> |
|
||||
<el-input v-model="data.simple"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="sim卡1" prop="sim1"> |
|
||||
<el-input v-model="data.sim1"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="设备朝向" prop="deviceDirection"> |
|
||||
<el-input v-model="data.deviceDirection"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="协议版本" prop="protocolVersion"> |
|
||||
<el-input v-model="data.protocolVersion"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="与主站后台联调情况" prop="joint"> |
|
||||
<el-input v-model="data.joint" type="textarea"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="备注" prop="remark"> |
|
||||
<el-input v-model="data.remark" type="textarea"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<el-row> |
|
||||
<el-col :span="24"> |
|
||||
<el-form-item label="维修记录" prop="operationRecord"> |
|
||||
<el-input v-model="data.operationRecord" type="textarea"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<el-row :gutter="20" class="mt-5 pl-2"> |
|
||||
<el-form-item> |
|
||||
<el-button type="primary" @click="onSubmit">提交</el-button> |
|
||||
<el-button @click="onReset">重置</el-button> |
|
||||
</el-form-item> |
|
||||
</el-row> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { defineEmits, reactive, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'; |
|
||||
import { createDevice } from 'apis'; |
|
||||
import { deviceData, deviceRules } from '@/config/config'; |
|
||||
|
|
||||
const data = reactive(deviceData); |
|
||||
const deviceCreate = ref(null); // form |
|
||||
const store = useStore(); |
|
||||
const emit = defineEmits(['hide']); |
|
||||
|
|
||||
// 重置表单 |
|
||||
const onReset = () => { |
|
||||
deviceCreate.value.resetFields(); |
|
||||
}; |
|
||||
|
|
||||
// 提交表单 |
|
||||
const onSubmit = () => { |
|
||||
deviceCreate.value.validate(async valid => { |
|
||||
if (!valid) return; |
|
||||
if (data.installTime) { |
|
||||
data.installTime = new Date(data.installTime).getTime(); |
|
||||
} |
|
||||
if (data.runTime) { |
|
||||
data.runTime = new Date(data.runTime).getTime(); |
|
||||
} |
|
||||
try { |
|
||||
await createDevice({ ...data }); |
|
||||
store.commit('device/unshiftDevice', { ...data }); |
|
||||
ElMessageBox.confirm('添加成功,是否继续添加', '提示', { |
|
||||
confirmButtonText: '继续添加', |
|
||||
cancelButtonText: '关闭', |
|
||||
type: 'success', |
|
||||
}) |
|
||||
.then(() => { |
|
||||
// 确认继续添加 |
|
||||
onReset(); |
|
||||
}) |
|
||||
.catch(() => { |
|
||||
onReset(); |
|
||||
emit('on-hide'); |
|
||||
}); |
|
||||
await store.dispatch('device/getDevices'); // 更新站点列表 |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error); |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
</script> |
|
@ -1,13 +0,0 @@ |
|||||
<template> |
|
||||
<el-dialog v-model="show" title="编辑设备信息" fullscreen="true" @close="$emit('toggle-mdoal')"> |
|
||||
<DeviceEdit v-if="show" :edit="true" @cancel="$emit('toggle-mdoal')" /> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { defineProps, defineEmits } from 'vue'; |
|
||||
import DeviceEdit from 'views/device-edit.vue'; |
|
||||
|
|
||||
defineProps({ show: Boolean }); |
|
||||
defineEmits(['toggle-mdoal']); |
|
||||
</script> |
|
@ -1,233 +0,0 @@ |
|||||
<template> |
|
||||
<SearchBar :loading-search="loadingSearch" :show-command="true" :show-export="true" :show-pass-setting="true" @search="onSearch" /> |
|
||||
|
|
||||
<template v-if="data"> |
|
||||
<el-table :data="data" :max-height="contentHeight" border stripe style="width: 100%"> |
|
||||
<el-table-column align="center" fixed label="设备ID" min-width="80" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="采集时间" min-width="170"> |
|
||||
<template #default="scope"> |
|
||||
{{ formatTime(+scope.row.time) }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="后台接收时间" min-width="170"> |
|
||||
<template #default="scope"> |
|
||||
{{ formatTime(+scope.row.createdAt) }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<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-column align="center" label="环境温度(℃)" min-width="110" prop="environmentTemperature" /> |
|
||||
<el-table-column align="center" label="环境湿度(RH%)" min-width="130" prop="environmentHumidity" /> |
|
||||
<el-table-column align="center" label="SO2(ppb)" min-width="90" prop="so2" /> |
|
||||
<el-table-column align="center" label="盐分温度(℃)" min-width="110" prop="saltT" /> |
|
||||
<el-table-column align="center" label="盐分阻抗(Ω)" min-width="110" prop="saltR" /> |
|
||||
<el-table-column align="center" label="机箱温度(℃)" min-width="110" prop="deviceTemperature" /> |
|
||||
<el-table-column align="center" label="机箱湿度(RH%)" min-width="130" prop="deviceHumidity" /> |
|
||||
<el-table-column align="center" label="太阳能板电压(V)" min-width="140" prop="solarVoltage" /> |
|
||||
<el-table-column align="center" label="蓄电池电压(V)" min-width="120" prop="batteryVoltage" /> |
|
||||
<el-table-column align="center" label="电压百分比" min-width="94" prop="batteryVoltagePercentage" /> |
|
||||
<el-table-column align="center" label="剩余电量(mAH)" min-width="140" prop="batteryVoltageRemain" /> |
|
||||
<el-table-column align="center" label="消耗电量(mAH)" min-width="140" prop="batteryLoss" /> |
|
||||
<el-table-column align="center" label="ICCID" min-width="190" prop="iccid" /> |
|
||||
<el-table-column align="center" label="IMEI" min-width="150" prop="imei" /> |
|
||||
<el-table-column align="center" label="信号强度" min-width="80" prop="signal" /> |
|
||||
<el-table-column align="center" label="基站编号" min-width="130" prop="stationNo" /> |
|
||||
<el-table-column align="center" label="硬件版本" min-width="80" prop="hardwareVersion" /> |
|
||||
<el-table-column align="center" label="软件版本" min-width="80" prop="softwareVersion" /> |
|
||||
</el-table> |
|
||||
|
|
||||
<el-pagination |
|
||||
:current-page="page.page" |
|
||||
:default-page-size="50" |
|
||||
:page-count="page.count" |
|
||||
:page-size="page.size" |
|
||||
:page-sizes="[1, 10, 20, 50, 100]" |
|
||||
:total="page.total" |
|
||||
background |
|
||||
class="my-3 float-right" |
|
||||
layout="total, sizes, prev, pager, next, jumper" |
|
||||
@current-change="onCurrentPageChange" |
|
||||
@size-change="onSizeChange" |
|
||||
@prev-click="onPrev" |
|
||||
@next-click="onNext" |
|
||||
></el-pagination> |
|
||||
</template> |
|
||||
|
|
||||
<el-badge v-if="missingData && missingData.length" :max="99" :value="missingData.length" class="pass-button animate-bounce"> |
|
||||
<div circle class="shadow-xl btn" type="primary" @click="showMissing = true"> |
|
||||
<i class="el-icon-upload"></i> |
|
||||
</div> |
|
||||
</el-badge> |
|
||||
|
|
||||
<el-dialog v-model="showMissing" custom-class="device-dialog" title="待补传列表" top="30px" width="80%"> |
|
||||
<MissingData :data="missingData" @on-success="onPassSuccess" /> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, onMounted, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { getDatas } from 'apis'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import SearchBar from 'components/history/search-bar-data.vue'; |
|
||||
import MissingData from 'components/history/missing-data.vue'; |
|
||||
|
|
||||
const search = ref({}); |
|
||||
const page = ref({ |
|
||||
page: 1, |
|
||||
size: 50, |
|
||||
}); |
|
||||
let timer = null; |
|
||||
const store = useStore(); |
|
||||
const token = computed(() => store.getters['user/token']); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // 正在操作的设备的id |
|
||||
const contentHeight = ref(600); |
|
||||
const loadingSearch = ref(false); |
|
||||
const data = ref(null); |
|
||||
const showMissing = ref(false); |
|
||||
const missingData = ref([]); |
|
||||
|
|
||||
// 获取设备完整信息列表 |
|
||||
const getData = async () => { |
|
||||
try { |
|
||||
if (token && token.value) { |
|
||||
if (!currentDeviceId.value) { |
|
||||
return ElMessage.error('请选择站点'); |
|
||||
} |
|
||||
|
|
||||
const { date, missingIntervalInMs } = search.value; |
|
||||
if (!date || date.length !== 2) { |
|
||||
return ElMessage.error('请选择时间 '); |
|
||||
} |
|
||||
const params = { |
|
||||
deviceId: currentDeviceId.value, |
|
||||
gatheredDateRange: date, |
|
||||
paging: true, |
|
||||
missingIntervalInMs, |
|
||||
page: page.value.page, |
|
||||
size: page.value.size, |
|
||||
sort: [ |
|
||||
{ |
|
||||
col: 'time', |
|
||||
order: 'DESC', |
|
||||
}, |
|
||||
], |
|
||||
}; |
|
||||
|
|
||||
loadingSearch.value = true; |
|
||||
const resData = await getDatas(params); |
|
||||
loadingSearch.value = false; |
|
||||
|
|
||||
data.value = resData.data; |
|
||||
page.value = resData.page; |
|
||||
timer && clearTimeout(timer); |
|
||||
timer = null; |
|
||||
|
|
||||
if (resData.missingData) { |
|
||||
missingData.value = [...resData.missingData]; |
|
||||
missingData.value.forEach(item => { |
|
||||
item.uuid = `${item.deviceId}-${item.startTime}-${item.endTime}`; |
|
||||
}); |
|
||||
} |
|
||||
} else { |
|
||||
timer = setTimeout(() => { |
|
||||
getData(); |
|
||||
}, 20); |
|
||||
} |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error.message || '获取数据失败'); |
|
||||
console.log('error: ', error); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
// getData(); |
|
||||
|
|
||||
// 设置表格高度 |
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 260; |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 监听sear h信息 |
|
||||
* @param {object} payload search组件emi 的数据 |
|
||||
*/ |
|
||||
const onSearch = payload => { |
|
||||
search.value = { ...payload }; |
|
||||
getData(); |
|
||||
}; |
|
||||
/** |
|
||||
* 当前 码变化 |
|
||||
* 更新page 重新 取数据 |
|
||||
* @param {number} e 的页码 |
|
||||
*/ |
|
||||
const onCurrentPageChange = e => { |
|
||||
page.value.page = e; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
const onSizeChange = e => { |
|
||||
page.value.size = e; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
// 下一页 |
|
||||
const onNext = e => { |
|
||||
page.value.page = e + 1; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
// 上一页 |
|
||||
const onPrev = e => { |
|
||||
page.value.page = e - 1; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 格式化时间 |
|
||||
* @param {number} time 时间戳 |
|
||||
* @returns {string} |
|
||||
*/ |
|
||||
function formatTime(time) { |
|
||||
return dayjs(new Date(time)).format('YYYY-MM-DD HH:mm:ss'); |
|
||||
} |
|
||||
|
|
||||
// 补传成功 标记当前记录 |
|
||||
function onPassSuccess(uuid) { |
|
||||
// eslint-disable-next-line no-restricted-syntax |
|
||||
for (const item of missingData.value) { |
|
||||
if (item.uuid === uuid) { |
|
||||
item.disabled = true; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.device-dialog :deep(.el-dialog__body) { |
|
||||
padding-top: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.pass-button { |
|
||||
z-index: 999; |
|
||||
position: fixed; |
|
||||
right: 30px; |
|
||||
bottom: 40px; |
|
||||
} |
|
||||
|
|
||||
.pass-button .btn { |
|
||||
width: 56px; |
|
||||
height: 56px; |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
background-color: #409eff; |
|
||||
border-radius: 50%; |
|
||||
color: #fff; |
|
||||
font-size: 26px; |
|
||||
cursor: pointer; |
|
||||
} |
|
||||
</style> |
|
@ -1,42 +0,0 @@ |
|||||
<template> |
|
||||
<template v-if="data"> |
|
||||
<el-table :data="data" :max-height="contentHeight" border class="mt-6" stripe style="width: 100%"> |
|
||||
<el-table-column align="center" label="设备ID" min-min-width="100" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="开始时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.startTime)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="截止时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.endTime)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" header-align="center" label="下发状态" min-width="150"> |
|
||||
<template #default="scope"> |
|
||||
<StatusTagPending :type="scope.row.status" /> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" header-align="center" label="类型" min-width="150"> |
|
||||
<template #default="scope"> |
|
||||
<span v-if="scope.row && scope.row.type && PENDING_TYPE[scope.row.type]">{{ PENDING_TYPE[scope.row.type].text }}</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
</template> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { defineProps, onMounted, ref } from 'vue'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { PENDING_TYPE } from '@/config/config'; |
|
||||
|
|
||||
defineProps({ data: Object }); |
|
||||
|
|
||||
const contentHeight = ref(600); |
|
||||
|
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 150; |
|
||||
}); |
|
||||
</script> |
|
@ -1,35 +0,0 @@ |
|||||
<template> |
|
||||
<SearchHistoryLog @search="getData" /> |
|
||||
|
|
||||
<TableHistoryLog :data="data" /> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { getSendHistory } from 'apis'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import SearchHistoryLog from 'components/history/search-history-log.vue'; |
|
||||
import TableHistoryLog from 'components/history/history-log-table.vue'; |
|
||||
|
|
||||
const store = useStore(); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // 正在操作的设备的id |
|
||||
const data = ref([]); |
|
||||
|
|
||||
async function getData( |
|
||||
params = { |
|
||||
deviceId: currentDeviceId.value, |
|
||||
status: '', |
|
||||
type: '', |
|
||||
}, |
|
||||
) { |
|
||||
try { |
|
||||
const resData = await getSendHistory(params); |
|
||||
data.value = resData ? [...resData] : []; |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error.message || '查询失败'); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
getData(); |
|
||||
</script> |
|
@ -1,162 +0,0 @@ |
|||||
<template> |
|
||||
<SearchBar :show-export="true" :show-type-select="true" @search="onSearch" /> |
|
||||
|
|
||||
<template v-if="data"> |
|
||||
<el-table :data="data" :max-height="contentHeight" border stripe style="width: 100%"> |
|
||||
<el-table-column align="center" fixed label="设备ID" min-width="80" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="采集时间" min-width="170"> |
|
||||
<template #default="scope"> |
|
||||
{{ formatTime(+scope.row.time) }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="后台接收时间" min-width="170"> |
|
||||
<template #default="scope"> |
|
||||
{{ formatTime(+scope.row.createdAt) }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<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-column align="center" label="环境温度(℃)" min-width="110" prop="environmentTemperature" /> |
|
||||
<el-table-column align="center" label="环境湿度(RH%)" min-width="130" prop="environmentHumidity" /> |
|
||||
<el-table-column align="center" label="SO2(ppb)" min-width="90" prop="so2" /> |
|
||||
<el-table-column align="center" label="盐分温度(℃)" min-width="110" prop="saltT" /> |
|
||||
<el-table-column align="center" label="盐分阻抗(Ω)" min-width="110" prop="saltR" /> |
|
||||
<el-table-column align="center" label="太阳能板电压(V)" min-width="140" prop="solarVoltage" /> |
|
||||
<el-table-column align="center" label="蓄电池电压(V)" min-width="120" prop="batteryVoltage" /> |
|
||||
<el-table-column align="center" label="机箱温度(℃)" min-width="110" prop="deviceTemperature" /> |
|
||||
<el-table-column align="center" label="机箱湿度(RH%)" min-width="130" prop="deviceHumidity" /> |
|
||||
</el-table> |
|
||||
|
|
||||
<el-pagination |
|
||||
:current-page="page.page" |
|
||||
:default-page-size="50" |
|
||||
:page-count="page.count" |
|
||||
:page-size="page.size" |
|
||||
:page-sizes="[1, 10, 20, 50, 100]" |
|
||||
:total="page.total" |
|
||||
background |
|
||||
class="my-3 float-right" |
|
||||
layout="total, sizes, prev, pager, next, jumper" |
|
||||
@current-change="onCurrentPageChange" |
|
||||
@size-change="onSizeChange" |
|
||||
@prev-click="onPrev" |
|
||||
@next-click="onNext" |
|
||||
></el-pagination> |
|
||||
</template> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { getDatas } from 'apis'; |
|
||||
import SearchBar from 'components/history/search-bar-data.vue'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import { computed, onMounted, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
|
|
||||
const search = ref({}); |
|
||||
const page = ref({ |
|
||||
page: 1, |
|
||||
size: 50, |
|
||||
}); |
|
||||
let timer = null; |
|
||||
const store = useStore(); |
|
||||
const token = computed(() => store.getters['user/token']); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // 正在操作的设备的id |
|
||||
const contentHeight = ref(600); |
|
||||
const data = ref(null); |
|
||||
|
|
||||
// 获取设备完整信息列表 |
|
||||
const getData = async () => { |
|
||||
try { |
|
||||
if (token && token.value) { |
|
||||
if (!currentDeviceId.value) { |
|
||||
return ElMessage.error('请选择站点'); |
|
||||
} |
|
||||
|
|
||||
const options = { ...search.value }; |
|
||||
const date = options && options.date ? options.date : []; |
|
||||
console.log(date); |
|
||||
if (!date || date.length !== 2) { |
|
||||
return ElMessage.error('请选择时间 '); |
|
||||
} |
|
||||
const params = { |
|
||||
deviceId: currentDeviceId.value, |
|
||||
gatheredDateRange: date, |
|
||||
paging: true, |
|
||||
page: page.value.page, |
|
||||
size: page.value.size, |
|
||||
sort: [ |
|
||||
{ |
|
||||
col: 'time', |
|
||||
order: 'DESC', |
|
||||
}, |
|
||||
], |
|
||||
}; |
|
||||
const resData = await getDatas(params); |
|
||||
data.value = resData.data; |
|
||||
page.value = resData.page; |
|
||||
timer && clearTimeout(timer); |
|
||||
timer = null; |
|
||||
} else { |
|
||||
timer = setTimeout(() => { |
|
||||
getData(); |
|
||||
}, 20); |
|
||||
} |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error.message || '获取数据失败'); |
|
||||
console.log('error: ', error); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
// 设置表格高度 |
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 250; |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 监听sear h信息 |
|
||||
* @param {object} payload search组件emi 的数据 |
|
||||
*/ |
|
||||
const onSearch = payload => { |
|
||||
search.value = { ...payload }; |
|
||||
getData(); |
|
||||
}; |
|
||||
/** |
|
||||
* 当前 码变化 |
|
||||
* 更新page 重新 取数据 |
|
||||
* @param {number} e 的页码 |
|
||||
*/ |
|
||||
const onCurrentPageChange = e => { |
|
||||
page.value.page = e; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
const onSizeChange = e => { |
|
||||
page.value.size = e; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
// 下一页 |
|
||||
const onNext = e => { |
|
||||
page.value.page = e + 1; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
// 上一页 |
|
||||
const onPrev = e => { |
|
||||
page.value.page = e - 1; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 格式化时间 |
|
||||
* @param {number} time 时间戳 |
|
||||
* @returns {string} |
|
||||
*/ |
|
||||
function formatTime(time) { |
|
||||
return dayjs(new Date(time)).format('YYYY-MM-DD HH:mm:ss'); |
|
||||
} |
|
||||
</script> |
|
@ -1,48 +0,0 @@ |
|||||
<template> |
|
||||
<el-table :data="data" :max-height="contentHeight" border class="mt-6" stripe style="width: 100%; margin-top: 0"> |
|
||||
<el-table-column align="center" label="设备ID" min-width="100" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="起始时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.startTime)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="截止时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.endTime)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
|
|
||||
<el-table-column align="center" header-align="center" label="操作" min-width="100"> |
|
||||
<template #default="scope"> |
|
||||
<el-button :disabled="scope.row.disabled" plain size="small" type="success" @click="handlePass(scope.row)">补传 </el-button> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { defineProps, defineEmits, ref } from 'vue'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { sendCommand } from 'apis'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
|
|
||||
defineProps({ data: Object }); |
|
||||
const emit = defineEmits(['on-success']); |
|
||||
|
|
||||
const contentHeight = ref(600); |
|
||||
|
|
||||
/** |
|
||||
* 发送补传指令 |
|
||||
* @param { Object } item |
|
||||
* @returns {Promise<void>} |
|
||||
*/ |
|
||||
async function handlePass(item) { |
|
||||
try { |
|
||||
await sendCommand({ ...item }); |
|
||||
ElMessage.success('发送成功'); |
|
||||
emit('on-success', item.uuid); |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error.message || '发送补传指令失败'); |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
@ -1,148 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="searchDeviceForm" :inline="true" :model="searchDevice"> |
|
||||
<el-form-item label="选择站点:"> |
|
||||
<el-select v-model="searchDevice.deviceId" placeholder="请选择站点" @change="change"> |
|
||||
<!-- <el-option label="全部" value></el-option> --> |
|
||||
<el-option |
|
||||
v-for="item in devices" |
|
||||
:key="item.deviceId" |
|
||||
:label="`${item.address}-${item.deviceId}`" |
|
||||
:value="item.deviceId" |
|
||||
></el-option> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item label="起始时间:"> |
|
||||
<el-date-picker |
|
||||
v-model="searchDevice.date[0]" |
|
||||
format="YYYY-MM-DD HH:mm" |
|
||||
placeholder="起始时间" |
|
||||
style="width: 180px" |
|
||||
type="datetime" |
|
||||
></el-date-picker> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item label="截止时间:"> |
|
||||
<el-date-picker |
|
||||
v-model="searchDevice.date[1]" |
|
||||
format="YYYY-MM-DD HH:mm" |
|
||||
placeholder="截止时间" |
|
||||
style="width: 180px" |
|
||||
type="datetime" |
|
||||
></el-date-picker> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item v-if="showPassSetting" label="补传间隔(h):"> |
|
||||
<el-input-number v-model="searchDevice.missingIntervalInMs" :min="0" controls-position="right" style="width: 100px" /> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item> |
|
||||
<template v-if="showCommand"> |
|
||||
<el-button type="primary" @click="onSubmit">查询历史数据</el-button> |
|
||||
<!-- <el-button type="warning" @click="onSend('EVENT')">查询历史事件</el-button>--> |
|
||||
</template> |
|
||||
<el-button v-else :loading="loadingSearch" type="primary" @click="onSubmit"> |
|
||||
<i class="el-icon-search mr-2"></i> |
|
||||
查询 |
|
||||
</el-button> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item v-if="showExport"> |
|
||||
<el-button :loading="loadingExport" type="success" @click="onExport"> |
|
||||
<i class="el-icon-download mr-2"></i> |
|
||||
导出 |
|
||||
</el-button> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { exportHistory } from 'apis'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { computed, defineEmits, defineProps, reactive, ref, watch } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
|
|
||||
const emit = defineEmits(['search']); |
|
||||
const searchDevice = reactive({ |
|
||||
deviceId: '', |
|
||||
date: [dayjs().subtract(7, 'day').startOf('day'), new Date()], |
|
||||
missingIntervalInMs: 1, |
|
||||
}); |
|
||||
const searchDeviceForm = ref(null); // form |
|
||||
const store = useStore(); |
|
||||
const devices = computed(() => store.state.device.devices); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // 正在操作的设备的id |
|
||||
const loadingExport = ref(false); |
|
||||
|
|
||||
defineProps({ |
|
||||
showExport: Boolean, |
|
||||
loadingSearch: Boolean, |
|
||||
showCommand: Boolean, |
|
||||
showPassSetting: Boolean, |
|
||||
}); |
|
||||
|
|
||||
// 监听currentDeviceId |
|
||||
watch( |
|
||||
[searchDeviceForm, currentDeviceId], |
|
||||
([newForm, newDeviceId]) => { |
|
||||
if (newDeviceId && newForm) { |
|
||||
searchDevice.deviceId !== newDeviceId && (searchDevice.deviceId = newDeviceId); |
|
||||
onSubmit(); |
|
||||
} |
|
||||
}, |
|
||||
{ immediate: true }, |
|
||||
); |
|
||||
|
|
||||
const change = e => { |
|
||||
store.commit('device/setCurrentDeviceId', e); |
|
||||
}; |
|
||||
|
|
||||
// 生成查询参数 |
|
||||
function generateParams() { |
|
||||
const { deviceId, date, missingIntervalInMs } = searchDevice; |
|
||||
const params = { |
|
||||
deviceId, |
|
||||
missingIntervalInMs: missingIntervalInMs * 60 * 60 * 1000, |
|
||||
}; |
|
||||
|
|
||||
if (date) { |
|
||||
const start = +dayjs(date[0]).format('x'); |
|
||||
const end = +dayjs(date[1]).format('x'); |
|
||||
params.date = [start, end]; |
|
||||
} |
|
||||
|
|
||||
return params; |
|
||||
} |
|
||||
|
|
||||
// 提交 |
|
||||
function onSubmit() { |
|
||||
searchDeviceForm.value.validate(valid => { |
|
||||
if (valid) { |
|
||||
const params = generateParams(); |
|
||||
emit('search', params); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
// 导出 |
|
||||
async function onExport() { |
|
||||
try { |
|
||||
loadingExport.value = true; |
|
||||
const params = generateParams(); |
|
||||
params.sort = [ |
|
||||
{ |
|
||||
col: 'time', |
|
||||
order: 'DESC', |
|
||||
}, |
|
||||
]; |
|
||||
params.paging = false; |
|
||||
params.gatheredDateRange = params.date; |
|
||||
const resData = await exportHistory(params); |
|
||||
loadingExport.value = false; |
|
||||
resData && (window.location.href = resData); |
|
||||
} catch (error) { |
|
||||
loadingExport.value = false; |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
@ -1,77 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="searchHistoryLogForm" :inline="true" :model="searchDevice"> |
|
||||
<el-form-item label="选择站点"> |
|
||||
<el-select v-model="searchDevice.deviceId" placeholder="请选择站点" @change="change"> |
|
||||
<el-option label="全部" value></el-option> |
|
||||
<el-option |
|
||||
v-for="item in devices" |
|
||||
:key="item.deviceId" |
|
||||
:label="`${item.address}-${item.deviceId}`" |
|
||||
:value="item.deviceId" |
|
||||
></el-option> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item label="类型"> |
|
||||
<el-select v-model="searchDevice.type" placeholder="选择查询类型"> |
|
||||
<el-option label="全部" value=""></el-option> |
|
||||
<el-option label="事件上报" value="EVENT"></el-option> |
|
||||
<el-option label="业务上报" value="DATA"></el-option> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item label="状态"> |
|
||||
<el-select v-model="searchDevice.status" placeholder="选择查询类型"> |
|
||||
<el-option label="全部" value=""></el-option> |
|
||||
<el-option label="待下发" value="PENDING"></el-option> |
|
||||
<el-option label="下发成功" value="SUCCESS"></el-option> |
|
||||
<el-option label="下发失败" value="FAIL"></el-option> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item> |
|
||||
<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 { computed, defineEmits, reactive, ref, watch } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
|
|
||||
const emit = defineEmits(['search']); |
|
||||
const searchDevice = reactive({ |
|
||||
deviceId: '', |
|
||||
type: '', |
|
||||
status: '', |
|
||||
}); |
|
||||
const searchHistoryLogForm = 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 = () => { |
|
||||
searchHistoryLogForm.value.validate(() => { |
|
||||
emit('search', { ...searchDevice }); |
|
||||
}); |
|
||||
}; |
|
||||
</script> |
|
@ -1,23 +0,0 @@ |
|||||
<script setup> |
|
||||
import { computed } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
|
|
||||
const store = useStore(); |
|
||||
const toggleCollapse = () => { |
|
||||
console.log('Toggle Collapse'); |
|
||||
store.commit('toggleCollapse'); |
|
||||
}; |
|
||||
const menu = computed(() => store.state.menu); |
|
||||
</script> |
|
||||
|
|
||||
<template> |
|
||||
<h1 class="text-lg font-medium py-3 px-6 shadow"> |
|
||||
<i |
|
||||
class="el-icon-guide mr-2" |
|
||||
:class="{ 'text-gray-800': !menu.collapse, 'text-gray-400': menu.collapse }" |
|
||||
@click="toggleCollapse" |
|
||||
v-if="menu.show" |
|
||||
></i> |
|
||||
{{ $route.meta.title || '智能大气腐蚀监测平台' }} |
|
||||
</h1> |
|
||||
</template> |
|
@ -1,49 +0,0 @@ |
|||||
<template> |
|
||||
<div id="device-overview-container" style="height: 354px"></div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, onMounted, ref, watchEffect } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import isEmpty from 'lodash/isEmpty'; |
|
||||
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 myChart = null; |
|
||||
|
|
||||
watchEffect(() => { |
|
||||
if (isEmpty(count.value) || !isMounted.value) return; |
|
||||
if (!myChart) { |
|
||||
initChart(); |
|
||||
render(count.value); |
|
||||
} else { |
|
||||
render(count.value); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
// 初始化chart |
|
||||
function initChart() { |
|
||||
const chartDom = document.getElementById('device-overview-container'); |
|
||||
myChart = echarts.init(chartDom); |
|
||||
} |
|
||||
|
|
||||
// 渲染chart |
|
||||
function render(rawCount) { |
|
||||
const option = generateChartOption(rawCount); |
|
||||
option && myChart.setOption(option); |
|
||||
} |
|
||||
|
|
||||
onMounted(() => { |
|
||||
initChart(); |
|
||||
isMounted.value = true; |
|
||||
}); |
|
||||
</script> |
|
@ -1,93 +0,0 @@ |
|||||
<template> |
|
||||
<el-card class="pb-4" shadow="hover"> |
|
||||
<el-row :gutter="20"> |
|
||||
<el-col :span="12"> |
|
||||
<div class="text-sm text-gray-400">设备总数</div> |
|
||||
<div class="text-gray-500 text-4xl mt-1 mb-3">{{ count.total }}</div> |
|
||||
<div class="line-wrap bg-blue-50"> |
|
||||
<div :style="{ width: `${countPercent.total}` }" class="line bg-blue-300"></div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :span="12"> |
|
||||
<div class="text-sm text-gray-400">正常数量</div> |
|
||||
<div class="text-gray-500 text-4xl mt-1 mb-3">{{ count.normal }}</div> |
|
||||
<div class="line-wrap bg-lime-50"> |
|
||||
<div :style="{ width: `${countPercent.normal}` }" class="line bg-lime-300"></div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :span="12" class="mt-10"> |
|
||||
<div class="text-sm text-gray-400">离线数量</div> |
|
||||
<div class="text-gray-500 text-4xl mt-1 mb-3">{{ count.offline }}</div> |
|
||||
<div class="line-wrap bg-gray-50"> |
|
||||
<div :style="{ width: `${countPercent.offline}` }" class="line bg-gray-300"></div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :span="12" class="mt-10"> |
|
||||
<div class="text-sm text-gray-400">报警数量</div> |
|
||||
<div class="text-gray-500 text-4xl mt-1 mb-3">{{ count.warning }}</div> |
|
||||
<div class="line-wrap bg-yellow-50"> |
|
||||
<div :style="{ width: `${countPercent.warning}` }" class="line bg-yellow-300"></div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :span="12" class="mt-10"> |
|
||||
<div class="text-sm text-gray-400">在线数量</div> |
|
||||
<div class="text-gray-500 text-4xl mt-1 mb-3">{{ count.online }}</div> |
|
||||
<div class="line-wrap bg-green-50"> |
|
||||
<div :style="{ width: `${countPercent.online}` }" class="line bg-green-300"></div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :span="12" class="mt-10"> |
|
||||
<div class="text-sm text-gray-400">故障数量</div> |
|
||||
<div class="text-gray-500 text-4xl mt-1 mb-3">{{ count.fault }}</div> |
|
||||
<div class="line-wrap bg-red-50"> |
|
||||
<div :style="{ width: `${countPercent.fault}` }" class="line bg-red-300"></div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
</el-card> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
|
|
||||
const store = useStore(); |
|
||||
const count = computed(() => store.state.device.count); |
|
||||
const countPercent = computed(() => { |
|
||||
return { |
|
||||
online: computeWidth(count.value.online), |
|
||||
offline: computeWidth(count.value.offline), |
|
||||
warning: computeWidth(count.value.warning), |
|
||||
fault: computeWidth(count.value.fault), |
|
||||
total: computeWidth(count.value.total), |
|
||||
normal: computeWidth(count.value.normal), |
|
||||
}; |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 计算宽度百分比 |
|
||||
* @param {number} itemCount |
|
||||
* @returns {string} |
|
||||
*/ |
|
||||
function computeWidth(itemCount) { |
|
||||
const percent = (itemCount * 100) / count.value.total; |
|
||||
return `${percent}%`; |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.line-wrap { |
|
||||
position: relative; |
|
||||
width: 60%; |
|
||||
height: 10px; |
|
||||
border-radius: 5px; |
|
||||
overflow: hidden; |
|
||||
} |
|
||||
|
|
||||
.line { |
|
||||
position: absolute; |
|
||||
left: 0; |
|
||||
top: 0; |
|
||||
height: 100%; |
|
||||
} |
|
||||
</style> |
|
@ -1,112 +0,0 @@ |
|||||
<template> |
|
||||
<template v-if="devicesAll && devicesAll.data"> |
|
||||
<el-table :data="devicesAll.data" :max-height="contentHeight" border class="mt-6" stripe style="width: 100%"> |
|
||||
<el-table-column align="center" label="站点名称" min-width="150" prop="address" /> |
|
||||
<el-table-column align="center" label="设备ID" min-width="100" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="注册时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.signupTime)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="最近上传时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.lastUploadTime)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" header-align="center" label="设备状态" min-width="150"> |
|
||||
<template #default="scope"> |
|
||||
<el-tag v-if="scope.row.status" :color="STATUS_COLOR[scope.row.status].color" style="color: #fff"> |
|
||||
{{ STATUS_COLOR[scope.row.status].text }} |
|
||||
</el-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" header-align="center" label="产品类型" min-width="150"> |
|
||||
<template #default="scope"> |
|
||||
<span v-if="scope.row.type && ASDU_TYPE[scope.row.type]">{{ ASDU_TYPE[scope.row.type].text }}</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" header-align="center" label="协议版本" min-width="150" prop="protocolVersion" /> |
|
||||
</el-table> |
|
||||
|
|
||||
<el-pagination |
|
||||
:current-page="devicesAll.page.page" |
|
||||
:default-page-size="50" |
|
||||
:page-count="devicesAll.page.count" |
|
||||
:page-size="devicesAll.page.size" |
|
||||
:page-sizes="[1, 10, 20, 50, 100]" |
|
||||
:total="devicesAll.page.total" |
|
||||
background |
|
||||
class="my-3 float-right" |
|
||||
layout="total, sizes, prev, pager, next, jumper" |
|
||||
@size-change="onSizeChange" |
|
||||
@current-change="onCurrentPageChange" |
|
||||
></el-pagination> |
|
||||
</template> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, onMounted, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { STATUS_COLOR } from '@/config/config'; |
|
||||
import { ASDU_TYPE } from '@/config/log'; |
|
||||
|
|
||||
let timer = null; |
|
||||
const store = useStore(); |
|
||||
const token = computed(() => store.getters['user/token']); |
|
||||
const devicesAll = computed(() => { |
|
||||
return store.state.device.devicesAll; |
|
||||
}); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); |
|
||||
const contentHeight = ref(600); |
|
||||
|
|
||||
// 获取设备完整信息列表 |
|
||||
const getDevicesAllData = () => { |
|
||||
try { |
|
||||
if (token && token.value) { |
|
||||
store.dispatch('device/getDevicesAll'); |
|
||||
timer && clearTimeout(timer); |
|
||||
timer = null; |
|
||||
} else { |
|
||||
timer = setTimeout(() => { |
|
||||
getDevicesAllData(); |
|
||||
}); |
|
||||
} |
|
||||
} catch (error) { |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
getDevicesAllData(); |
|
||||
|
|
||||
// 设置表格高度 |
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 250; |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 删除 |
|
||||
* @param {number} page 页码 |
|
||||
* @param {number} size 每页条数 |
|
||||
*/ |
|
||||
function onSearch(page, size = 50) { |
|
||||
const deviceId = currentDeviceId.value; |
|
||||
const params = { |
|
||||
deviceId, |
|
||||
page, |
|
||||
size, |
|
||||
}; |
|
||||
store.dispatch('device/getDevicesAll', params); |
|
||||
} |
|
||||
|
|
||||
// 当前页码变化 |
|
||||
const onCurrentPageChange = page => { |
|
||||
onSearch(page, devicesAll.value.page.size || 50); |
|
||||
}; |
|
||||
|
|
||||
// 每页条数变化 |
|
||||
const onSizeChange = size => { |
|
||||
onSearch(1, size); |
|
||||
}; |
|
||||
</script> |
|
@ -1,66 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="searchDeviceForm" :inline="true" :model="searchDevice"> |
|
||||
<el-form-item label="选择站点"> |
|
||||
<el-select v-model="searchDevice.deviceId" placeholder="请选择站点" @change="change"> |
|
||||
<el-option v-if="showAll" label="全部" value></el-option> |
|
||||
<el-option |
|
||||
v-for="item in devices" |
|
||||
:key="item.deviceId" |
|
||||
:label="`${item.address}-${item.deviceId}`" |
|
||||
:value="item.deviceId" |
|
||||
></el-option> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
<el-form-item> |
|
||||
<el-button type="primary" @click="onSubmit"> |
|
||||
<i class="el-icon-search mr-2"></i> |
|
||||
查询 |
|
||||
</el-button> |
|
||||
</el-form-item> |
|
||||
<el-form-item v-if="showRefresh"> |
|
||||
<el-button type="primary" @click="$emit('refresh')"> |
|
||||
<i class="el-icon-refresh mr-2"></i> |
|
||||
刷新 |
|
||||
</el-button> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, defineEmits, defineProps, reactive, ref, watch } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { useRouter } from 'vue-router'; |
|
||||
|
|
||||
defineProps({ showRefresh: Boolean }); |
|
||||
const emit = defineEmits(['getDate', 'refresh']); |
|
||||
const router = useRouter(); |
|
||||
const searchDevice = reactive({ deviceId: '' }); |
|
||||
|
|
||||
const searchDeviceForm = ref(null); // form |
|
||||
|
|
||||
const store = useStore(); |
|
||||
const devices = computed(() => store.state.device.devices); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // 正在操作的设备的id |
|
||||
const showAll = computed(() => router.currentRoute.value.name === 'devices'); // 是否显示全部 |
|
||||
|
|
||||
// 监听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(() => { |
|
||||
emit('search'); |
|
||||
}); |
|
||||
}; |
|
||||
</script> |
|
@ -1,131 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="searchDeviceForm" :inline="true" :model="searchDevice"> |
|
||||
<el-form-item label="选择站点:"> |
|
||||
<el-select v-model="searchDevice.deviceId" placeholder="请选择站点" @change="change"> |
|
||||
<!-- <el-option label="全部" value></el-option> --> |
|
||||
<el-option |
|
||||
v-for="item in devices" |
|
||||
:key="item.deviceId" |
|
||||
:label="`${item.address}-${item.deviceId}`" |
|
||||
:value="item.deviceId" |
|
||||
></el-option> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
<el-form-item v-if="showTypeSelect" label="类型:"> |
|
||||
<el-select v-model="searchDevice.dataType" placeholder="选择查询类型"> |
|
||||
<el-option label="全部" value=""></el-option> |
|
||||
<el-option label="事件上报" value="ReportHistoryEvent"></el-option> |
|
||||
<el-option label="业务上报" value="ReportHistoryData"></el-option> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item label="起始时间:"> |
|
||||
<el-date-picker v-model="searchDevice.date[0]" format="YYYY-MM-DD HH:mm" placeholder="起始时间" type="datetime"></el-date-picker> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item label="截止时间:"> |
|
||||
<el-date-picker v-model="searchDevice.date[1]" format="YYYY-MM-DD HH:mm" placeholder="截止时间" type="datetime"></el-date-picker> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item> |
|
||||
<el-button :loading="loadingSearch" type="primary" @click="onSubmit"> |
|
||||
<i class="el-icon-search mr-2"></i> |
|
||||
查询 |
|
||||
</el-button> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<el-form-item v-if="showExport"> |
|
||||
<el-button :loading="loadingExport" type="success" @click="onExport"> |
|
||||
<i class="el-icon-download mr-2"></i> |
|
||||
导出 |
|
||||
</el-button> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, defineEmits, defineProps, reactive, ref, watch } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { exportHistory } from 'apis'; |
|
||||
|
|
||||
const emit = defineEmits(['search']); |
|
||||
const searchDevice = reactive({ |
|
||||
deviceId: '', |
|
||||
date: [dayjs().subtract(7, 'day').startOf('day'), new Date()], |
|
||||
dataType: 'ReportHistoryData', |
|
||||
}); |
|
||||
const searchDeviceForm = ref(null); // form |
|
||||
const store = useStore(); |
|
||||
const devices = computed(() => store.state.device.devices); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // 正在操作的设备的id |
|
||||
const loadingExport = ref(false); |
|
||||
|
|
||||
defineProps({ |
|
||||
showExport: Boolean, |
|
||||
showTypeSelect: Boolean, |
|
||||
loadingSearch: Boolean, |
|
||||
}); |
|
||||
|
|
||||
// 监听currentDeviceId |
|
||||
watch( |
|
||||
() => currentDeviceId.value, |
|
||||
newValue => { |
|
||||
if (newValue) { |
|
||||
searchDevice.deviceId !== newValue && (searchDevice.deviceId = newValue); |
|
||||
} |
|
||||
}, |
|
||||
{ immediate: true }, |
|
||||
); |
|
||||
|
|
||||
const change = e => { |
|
||||
store.commit('device/setCurrentDeviceId', e); |
|
||||
}; |
|
||||
|
|
||||
// 生成查询参数 |
|
||||
function generateParams() { |
|
||||
const { deviceId, date, dataType } = searchDevice; |
|
||||
let params = { |
|
||||
deviceId, |
|
||||
date, |
|
||||
dataType, |
|
||||
}; |
|
||||
|
|
||||
if (date) { |
|
||||
const start = +dayjs(date[0]).format('x'); |
|
||||
const end = +dayjs(date[1]).format('x'); |
|
||||
const daterange = [start, end]; |
|
||||
params = { |
|
||||
deviceId, |
|
||||
date: daterange, |
|
||||
dataType, |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
return params; |
|
||||
} |
|
||||
|
|
||||
// 提交 |
|
||||
const onSubmit = () => { |
|
||||
searchDeviceForm.value.validate(valid => { |
|
||||
if (valid) { |
|
||||
const params = generateParams(); |
|
||||
emit('search', params); |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
// 导出 |
|
||||
async function onExport() { |
|
||||
try { |
|
||||
loadingExport.value = true; |
|
||||
const params = generateParams(); |
|
||||
const resData = await exportHistory(params); |
|
||||
loadingExport.value = false; |
|
||||
resData && (window.location.href = resData); |
|
||||
} catch (error) { |
|
||||
loadingExport.value = false; |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
@ -1,82 +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 { computed, defineExpose, defineProps, onMounted, ref, watchEffect } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
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'; |
|
||||
import { generateChartOption } from 'utils/statistical'; |
|
||||
|
|
||||
echarts.use([ |
|
||||
ToolboxComponent, |
|
||||
TooltipComponent, |
|
||||
GridComponent, |
|
||||
LegendComponent, |
|
||||
LineChart, |
|
||||
CanvasRenderer, |
|
||||
UniversalTransition, |
|
||||
DataZoomComponent, |
|
||||
]); |
|
||||
|
|
||||
const store = useStore(); |
|
||||
const props = defineProps({ searchHeight: Number }); |
|
||||
const realtimeData = computed(() => store.state.statistics.realtimeData); |
|
||||
const isMounted = ref(false); |
|
||||
const noData = ref(true); |
|
||||
let myChart = null; |
|
||||
|
|
||||
// 设置图表 |
|
||||
onMounted(() => { |
|
||||
isMounted.value = true; |
|
||||
window.addEventListener('resize', () => { |
|
||||
if (!myChart) return; |
|
||||
myChart.resize(); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
watchEffect(() => { |
|
||||
if (!realtimeData.value) return; |
|
||||
const { data } = realtimeData.value; |
|
||||
if (!data || !data.length || !isMounted.value) return; |
|
||||
initChart(data); |
|
||||
}); |
|
||||
|
|
||||
// 初始化chart |
|
||||
function initChart(data) { |
|
||||
const chartDom = document.getElementById('realtimeContainer'); |
|
||||
const canvasHeight = document.documentElement.clientHeight - props.searchHeight - 150; |
|
||||
chartDom.style.height = `${canvasHeight}px`; |
|
||||
myChart && myChart.dispose(); |
|
||||
myChart = echarts.init(chartDom); |
|
||||
render(data); |
|
||||
|
|
||||
myChart.on('legendselectchanged', event => { |
|
||||
render(data, event.selected); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
function render(data, selected) { |
|
||||
// myChart && myChart.clear(); |
|
||||
if (!data || !data.length) { |
|
||||
noData.value = true; |
|
||||
return; |
|
||||
} |
|
||||
noData.value = false; |
|
||||
|
|
||||
if (!myChart) { |
|
||||
initChart(data); |
|
||||
} |
|
||||
const option = generateChartOption(data, selected); |
|
||||
option && myChart.setOption(option); |
|
||||
} |
|
||||
|
|
||||
defineExpose({ render }); |
|
||||
</script> |
|
@ -0,0 +1,82 @@ |
|||||
|
<template> |
||||
|
<a-calendar v-model="date" :fullscreen="false" @panelChange="onPanelChange" @select="onSelectDate"> |
||||
|
<template #headerRender="{ value: current, onChange }"> |
||||
|
<div style="padding: 10px"> |
||||
|
<a-row type="flex" justify="space-between"> |
||||
|
<a-col> |
||||
|
<a-select |
||||
|
size="small" |
||||
|
:dropdown-match-select-width="false" |
||||
|
class="my-year-select" |
||||
|
:value="String(current.year())" |
||||
|
@change=" |
||||
|
newYear => { |
||||
|
onChange(current.year(newYear)); |
||||
|
} |
||||
|
" |
||||
|
> |
||||
|
<a-select-option v-for="val in getYears(current)" :key="String(val)" class="year-item"> |
||||
|
{{ val }} |
||||
|
</a-select-option> |
||||
|
</a-select> |
||||
|
</a-col> |
||||
|
<a-col> |
||||
|
<a-select |
||||
|
size="small" |
||||
|
:dropdown-match-select-width="false" |
||||
|
:value="String(current.month())" |
||||
|
@change=" |
||||
|
selectedMonth => { |
||||
|
onChange(current.month(parseInt(selectedMonth, 10))); |
||||
|
} |
||||
|
" |
||||
|
> |
||||
|
<a-select-option v-for="(val, index) in getMonths(current)" :key="String(index)" class="month-item"> |
||||
|
{{ val }} |
||||
|
</a-select-option> |
||||
|
</a-select> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
</div> |
||||
|
</template> |
||||
|
</a-calendar> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref } from 'vue'; |
||||
|
|
||||
|
const date = ref(); |
||||
|
const onPanelChange = (value, mode) => { |
||||
|
console.log(value, mode); |
||||
|
}; |
||||
|
|
||||
|
const getMonths = value => { |
||||
|
const localeData = value.localeData(); |
||||
|
const months = []; |
||||
|
|
||||
|
for (let i = 0; i < 12; i++) { |
||||
|
months.push(localeData.monthsShort(value.month(i))); |
||||
|
} |
||||
|
|
||||
|
return months; |
||||
|
}; |
||||
|
|
||||
|
const getYears = value => { |
||||
|
const year = value.year(); |
||||
|
const years = []; |
||||
|
|
||||
|
for (let i = year - 10; i < year + 10; i += 1) { |
||||
|
years.push(i); |
||||
|
} |
||||
|
|
||||
|
return years; |
||||
|
}; |
||||
|
|
||||
|
function onSelectDate(event) { |
||||
|
console.log(event); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<script> |
||||
|
export default { name: 'LeftCanlendar' }; |
||||
|
</script> |
@ -0,0 +1,13 @@ |
|||||
|
<template> |
||||
|
<Calendar /> |
||||
|
<Projects /> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import Calendar from './Calendar.vue'; |
||||
|
import Projects from './Projects.vue'; |
||||
|
</script> |
||||
|
|
||||
|
<script> |
||||
|
export default { name: 'LeftIndex' }; |
||||
|
</script> |
@ -0,0 +1,5 @@ |
|||||
|
<template>项目列表</template> |
||||
|
|
||||
|
<script setup></script> |
||||
|
|
||||
|
<style scoped></style> |
@ -0,0 +1,20 @@ |
|||||
|
<template> |
||||
|
<menu-unfold-outlined v-if="collapsed" @click="toggleCollapse" /> |
||||
|
<menu-fold-outlined v-else class="trigger" @click="toggleCollapse" /> |
||||
|
<h1>课题数据库</h1> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { computed } from 'vue'; |
||||
|
import { useStore } from 'vuex'; |
||||
|
// eslint-disable-next-line import/no-extraneous-dependencies |
||||
|
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue'; |
||||
|
|
||||
|
const store = useStore(); |
||||
|
const collapsed = computed(() => store.state.layout.display.left); // 是否显示左栏 |
||||
|
|
||||
|
// toggle left window display |
||||
|
function toggleCollapse() { |
||||
|
store.commit('layout/setDisplay', { prop: 'left', show: !collapsed.value }); |
||||
|
} |
||||
|
</script> |
@ -1,157 +0,0 @@ |
|||||
/* eslint-disable max-len */ |
|
||||
export const colors = ['#5470C6', '#91CC75', '#EE6666', '#5470C6', '#91CC75', '#EE6666', '#5470C6', '#91CC75', '#5470C6']; |
|
||||
|
|
||||
export const legendData = [ |
|
||||
'SO2(ppb)', |
|
||||
'盐分阻抗(Ω)', |
|
||||
'盐分温度(℃)', |
|
||||
'环境温度(℃)', |
|
||||
'环境湿度(RH%)', |
|
||||
'锌腐蚀电流(nA)', |
|
||||
'铜腐蚀电流(nA)', |
|
||||
'铝腐蚀电流(nA)', |
|
||||
'钢腐蚀电流(nA)', |
|
||||
]; |
|
||||
|
|
||||
// 默认legend select
|
|
||||
export const defaultSelectedLegend = { |
|
||||
'钢腐蚀电流(nA)': true, |
|
||||
'铜腐蚀电流(nA)': true, |
|
||||
'铝腐蚀电流(nA)': true, |
|
||||
'锌腐蚀电流(nA)': true, |
|
||||
'SO2(ppb)': false, |
|
||||
'盐分阻抗(Ω)': false, |
|
||||
'盐分温度(℃)': false, |
|
||||
'环境温度(℃)': false, |
|
||||
'环境湿度(RH%)': false, |
|
||||
}; |
|
||||
|
|
||||
// y轴定义
|
|
||||
export const yAxisData = [ |
|
||||
{ |
|
||||
type: 'value', |
|
||||
name: '腐蚀电流(nA)', |
|
||||
offset: 0, |
|
||||
position: 'left', |
|
||||
axisLine: { |
|
||||
show: true, |
|
||||
lineStyle: { color: colors[0] }, |
|
||||
}, |
|
||||
axisLabel: { formatter: '{value}' }, |
|
||||
axisPointer: { show: false }, |
|
||||
}, |
|
||||
{ |
|
||||
type: 'value', |
|
||||
name: '温度(℃)', |
|
||||
offset: 0, |
|
||||
position: 'right', |
|
||||
axisLine: { |
|
||||
show: true, |
|
||||
lineStyle: { color: colors[1] }, |
|
||||
}, |
|
||||
axisLabel: { formatter: '{value}' }, |
|
||||
axisPointer: { show: false }, |
|
||||
}, |
|
||||
{ |
|
||||
type: 'value', |
|
||||
name: '湿度(RH%)', |
|
||||
offset: 70, |
|
||||
position: 'right', |
|
||||
axisLine: { |
|
||||
show: true, |
|
||||
lineStyle: { color: colors[2] }, |
|
||||
}, |
|
||||
axisLabel: { formatter: '{value}' }, |
|
||||
axisPointer: { show: false }, |
|
||||
}, |
|
||||
{ |
|
||||
type: 'value', |
|
||||
name: 'SO2(ppb)', |
|
||||
position: 'right', |
|
||||
show: false, |
|
||||
offset: 150, |
|
||||
axisLine: { |
|
||||
show: true, |
|
||||
lineStyle: { color: colors[3] }, |
|
||||
}, |
|
||||
axisLabel: { formatter: '{value}' }, |
|
||||
axisPointer: { show: false }, |
|
||||
}, |
|
||||
{ |
|
||||
type: 'value', |
|
||||
name: '盐分阻抗(Ω)', |
|
||||
show: false, |
|
||||
position: 'right', |
|
||||
offset: 220, |
|
||||
axisLine: { |
|
||||
show: true, |
|
||||
lineStyle: { color: colors[4] }, |
|
||||
}, |
|
||||
axisLabel: { formatter: '{value}' }, |
|
||||
axisPointer: { show: false }, |
|
||||
}, |
|
||||
]; |
|
||||
|
|
||||
/** |
|
||||
* 生成默认数据 |
|
||||
* @param {Object} data |
|
||||
* @returns {[{data: (number|[]|string|*), name: string, type: string},{data: (number|[]|BufferSource|string|*), name: string, type: string, yAxisIndex: number},{data: ([]|string|*), name: string, type: string, yAxisIndex: number},{data: ([]|string|*), name: string, type: string, yAxisIndex: number},{data: [], name: string, type: string, yAxisIndex: number},null,null,null]} |
|
||||
*/ |
|
||||
export function generateDefaultSeries(data) { |
|
||||
return [ |
|
||||
{ |
|
||||
name: '锌腐蚀电流(nA)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 0, |
|
||||
data: data.corrosionXIN, |
|
||||
}, |
|
||||
{ |
|
||||
name: '铜腐蚀电流(nA)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 0, |
|
||||
data: data.corrosionTONG, |
|
||||
}, |
|
||||
{ |
|
||||
name: '铝腐蚀电流(nA)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 0, |
|
||||
data: data.corrosionLV, |
|
||||
}, |
|
||||
{ |
|
||||
name: '钢腐蚀电流(nA)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 0, |
|
||||
data: data.corrosionGANG, |
|
||||
}, |
|
||||
{ |
|
||||
name: '环境温度(℃)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 1, |
|
||||
data: data.environmentTemperature, |
|
||||
}, |
|
||||
{ |
|
||||
name: '盐分温度(℃)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 1, |
|
||||
data: data.saltT, |
|
||||
}, |
|
||||
{ |
|
||||
name: '环境湿度(RH%)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 2, |
|
||||
data: data.environmentHumidity, |
|
||||
}, |
|
||||
{ |
|
||||
name: 'SO2(ppb)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 3, |
|
||||
data: data.so2, |
|
||||
}, |
|
||||
{ |
|
||||
name: '盐分阻抗(Ω)', |
|
||||
type: 'line', |
|
||||
yAxisIndex: 4, |
|
||||
data: data.saltR, |
|
||||
}, |
|
||||
]; |
|
||||
} |
|
@ -1,164 +0,0 @@ |
|||||
// 网络参数设置
|
|
||||
export const networkConfig = { |
|
||||
ip1: '', |
|
||||
port1: '', |
|
||||
ip2: '', |
|
||||
port2: '', |
|
||||
ip3: '', |
|
||||
port3: '', |
|
||||
ipBackup: '', |
|
||||
portBackup: '', |
|
||||
account: '', |
|
||||
password: '', |
|
||||
apn: '', |
|
||||
status: '', |
|
||||
}; |
|
||||
|
|
||||
// 功能参数设置
|
|
||||
export const functionConfig = { |
|
||||
frequency: { |
|
||||
so2: 0, // SO2采样频率
|
|
||||
metal: 0, // 金属腐蚀采样频率
|
|
||||
th: 0, // 温湿度 采样频率
|
|
||||
salt: 0, // 盐雾 采样频率
|
|
||||
}, // 采样频率
|
|
||||
count: 0, // 采集个数
|
|
||||
time: Date.now(), // 设置时间
|
|
||||
batteryLow: 0, // 电池电压低阈值
|
|
||||
batteryHigh: 0, // 电池电压高阈值
|
|
||||
sunHigh: 0, // 太阳能电压高阈值
|
|
||||
humidityHigh: 0, // 湿度高阈值
|
|
||||
temperatureLow: 0, // 温度低阈值
|
|
||||
temperatureHigh: 0, // 温度高阈值
|
|
||||
securityMode: 'OPEN', // 安全模式 OPEN->不加密 ENCRYPTION->加密
|
|
||||
report: { |
|
||||
type: 'CYCLE', // 上报周期类型 0->时间点 1->周期
|
|
||||
timePoints: [''], // 设置时间点
|
|
||||
cycle: 240, // 上报周期分钟数
|
|
||||
}, |
|
||||
status: '', |
|
||||
}; |
|
||||
|
|
||||
// 金属腐蚀类型
|
|
||||
export const corrosiveTypes = [ |
|
||||
{ |
|
||||
value: 'XIN', |
|
||||
type: '锌', |
|
||||
}, |
|
||||
{ |
|
||||
value: 'LV', |
|
||||
type: '铝', |
|
||||
}, |
|
||||
{ |
|
||||
value: 'TONG', |
|
||||
type: '铜', |
|
||||
}, |
|
||||
{ |
|
||||
value: 'GANG', |
|
||||
type: '钢', |
|
||||
}, |
|
||||
]; |
|
||||
|
|
||||
// 添加设备
|
|
||||
export const deviceData = { |
|
||||
deviceId: '', // 设备id
|
|
||||
deviceFullId: '', // 设备完整id
|
|
||||
deviceDirection: '', // 设备朝向
|
|
||||
area: '', // 地区
|
|
||||
address: '', // 站点名称
|
|
||||
contact: '', // 联系人
|
|
||||
phone: '', // 联系人电话
|
|
||||
lon: '', // 经度
|
|
||||
lat: '', // 纬度
|
|
||||
head: '', // 负责人
|
|
||||
installLocation: '', // 安装位置
|
|
||||
installTime: '', // 安装时间
|
|
||||
runTime: '', // 正式运行时间
|
|
||||
linkAddress: '', // 链路地址
|
|
||||
probNo: '', // 探头编号
|
|
||||
simple: '', // 试样
|
|
||||
sim1: '', // sim卡1
|
|
||||
protocolVersion: '', // 协议版本
|
|
||||
joint: '', // 主站后台联调情况
|
|
||||
operationRecord: '', // 维修记录
|
|
||||
remark: '', // 备注
|
|
||||
type: 'IACD', // 产品类型
|
|
||||
}; |
|
||||
|
|
||||
// 设备添加编辑 规则
|
|
||||
export const deviceRules = { |
|
||||
deviceId: [ |
|
||||
{ |
|
||||
required: true, |
|
||||
message: '请输入设备ID号', |
|
||||
trigger: 'blur', |
|
||||
}, |
|
||||
{ |
|
||||
len: 6, |
|
||||
message: '请输入6位设备ID号', |
|
||||
trigger: 'blur', |
|
||||
}, |
|
||||
], |
|
||||
address: [ |
|
||||
{ |
|
||||
required: true, |
|
||||
message: '请输入站点名称', |
|
||||
trigger: 'blur', |
|
||||
}, |
|
||||
], |
|
||||
}; |
|
||||
|
|
||||
// 下发类型
|
|
||||
export const PEND_TYPE = { |
|
||||
PENDING: { |
|
||||
type: 'primary', |
|
||||
text: '待下发', |
|
||||
}, |
|
||||
FAIL: { |
|
||||
type: 'danger', |
|
||||
text: '配置失败', |
|
||||
}, |
|
||||
SUCCESS: { |
|
||||
type: 'success', |
|
||||
text: '配置成功', |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
// 上报类型
|
|
||||
export const REPORT_TYPE = { |
|
||||
CYCLE: '周期上报', |
|
||||
POINT: '定时上报', |
|
||||
}; |
|
||||
|
|
||||
// 下发类型
|
|
||||
export const PENDING_TYPE = { |
|
||||
DATA: { text: '业务上报' }, |
|
||||
EVENT: { text: '事件上报' }, |
|
||||
}; |
|
||||
|
|
||||
// 实时查询数据的轮询时间 1分钟
|
|
||||
export const REALTIME_DATA_INTERVAL = 60000 * 5; |
|
||||
|
|
||||
// 设备状态 情景
|
|
||||
export const STATUS_COLOR = { |
|
||||
FAULT: { |
|
||||
text: '故障', |
|
||||
color: '#FCA5A5', |
|
||||
}, |
|
||||
WARNING: { |
|
||||
text: '报警', |
|
||||
color: '#FCD34D', |
|
||||
}, |
|
||||
NORMAL: { |
|
||||
text: '正常', |
|
||||
color: '#BEF264', |
|
||||
}, |
|
||||
OFFLINE: { |
|
||||
text: '离线', |
|
||||
color: '#CBD5E1', |
|
||||
}, |
|
||||
ONLINE: { |
|
||||
text: '在线', |
|
||||
color: '#6EE7B7', |
|
||||
}, |
|
||||
}; |
|
@ -1,110 +0,0 @@ |
|||||
// 功能码
|
|
||||
export const CODE = { |
|
||||
BUSINESS_REPORT: { |
|
||||
text: '业务上报', |
|
||||
code: 0, |
|
||||
}, |
|
||||
EVENT_REPORT: { |
|
||||
text: '事件上报', |
|
||||
code: 1, |
|
||||
}, |
|
||||
NET_PARAM_SETTING_OR_READING: { |
|
||||
code: 2, |
|
||||
text: '联网参数设置或读取', |
|
||||
}, |
|
||||
FUNC_PARAM_SETTING_OR_READING: { |
|
||||
code: 3, |
|
||||
text: '功能参数设置或读取', |
|
||||
}, |
|
||||
READ_HISTORY_DATA: { |
|
||||
code: 4, |
|
||||
text: '读取历史日志记录', |
|
||||
}, |
|
||||
READ_HISTORY_EVENT: { |
|
||||
code: 5, |
|
||||
text: '读取历史事件记录', |
|
||||
}, |
|
||||
UPGRADE: { |
|
||||
code: 6, |
|
||||
text: '升级启动、传输、结束', |
|
||||
}, |
|
||||
ACK: { |
|
||||
code: 7, |
|
||||
text: '应答帧(固定帧)', |
|
||||
}, |
|
||||
OVER: { |
|
||||
code: 8, |
|
||||
text: '结束帧', |
|
||||
}, |
|
||||
RESERVED: { |
|
||||
code: 9, |
|
||||
text: '保留', |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
// 传输方向
|
|
||||
export const DIRECTION = { |
|
||||
IACD2SERVER: '上行', |
|
||||
SERVER2IACD: '下行', |
|
||||
}; |
|
||||
|
|
||||
// 传输启动
|
|
||||
export const PRM = { |
|
||||
ACK: '传输结束', |
|
||||
REQ: '传输启动', |
|
||||
}; |
|
||||
|
|
||||
// 流控
|
|
||||
export const DFC = { |
|
||||
CONTINUE: '有后续包', |
|
||||
OVER: '无后续包', |
|
||||
}; |
|
||||
|
|
||||
// 安全方式
|
|
||||
export const SER = { |
|
||||
OPEN: '不加密', |
|
||||
ENCRYPTION: '加密', |
|
||||
}; |
|
||||
|
|
||||
// 类型标识
|
|
||||
export const ASDU_TYPE = { |
|
||||
IACD: { |
|
||||
code: 1, |
|
||||
text: '大气腐蚀', |
|
||||
}, |
|
||||
OTHER: { |
|
||||
code: 2, |
|
||||
text: '其他', |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
// 信息体序
|
|
||||
export const INFO_ORDER = { |
|
||||
NoOrder: '无序', |
|
||||
HasOrder: '有序', |
|
||||
None: '无', |
|
||||
}; |
|
||||
|
|
||||
// 传输原因
|
|
||||
export const REASON = { |
|
||||
None: { |
|
||||
code: 0, |
|
||||
text: '无', |
|
||||
}, |
|
||||
ReportData: { |
|
||||
code: 1, |
|
||||
text: '业务主动上报', |
|
||||
}, |
|
||||
ReportEvent: { |
|
||||
code: 2, |
|
||||
text: '事件主动上报', |
|
||||
}, |
|
||||
History: { |
|
||||
code: 3, |
|
||||
text: '历史数据记录或程序数据', |
|
||||
}, |
|
||||
HumanOperator: { |
|
||||
code: 4, |
|
||||
text: '人工上报', |
|
||||
}, |
|
||||
}; |
|
@ -1,19 +0,0 @@ |
|||||
import { ref } from 'vue'; |
|
||||
|
|
||||
export default function useDeviceCreate() { |
|
||||
const display = ref(false); |
|
||||
|
|
||||
function hide() { |
|
||||
display.value = false; |
|
||||
} |
|
||||
|
|
||||
function show() { |
|
||||
display.value = true; |
|
||||
} |
|
||||
|
|
||||
return { |
|
||||
display, |
|
||||
hide, |
|
||||
show, |
|
||||
}; |
|
||||
} |
|
@ -1,163 +0,0 @@ |
|||||
import { getDevices, getDevicesAll, getDevicesCount } from 'apis'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
|
|
||||
const user = { |
|
||||
namespaced: true, |
|
||||
|
|
||||
state: { |
|
||||
devices: [], // 站点列表 设备列表简版
|
|
||||
devicesAll: { page: {}, data: [] }, // 设备列表完整版
|
|
||||
currentDeviceId: '', // 当前正在编辑的设备deviceId
|
|
||||
count: { |
|
||||
total: 0, // 总设备数量
|
|
||||
online: 0, // 在线
|
|
||||
offline: 0, // 离线
|
|
||||
warning: 0, // 警告
|
|
||||
fault: 0, // 故障
|
|
||||
}, |
|
||||
}, |
|
||||
|
|
||||
getters: { |
|
||||
// 当前正在编辑的设备的完整信息
|
|
||||
current({ devicesAll, currentDeviceId }) { |
|
||||
try { |
|
||||
return devicesAll.data.find(device => device.deviceId === currentDeviceId); |
|
||||
} catch (error) { |
|
||||
return null; |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
|
|
||||
mutations: { |
|
||||
/** |
|
||||
* 设置devices数据 |
|
||||
* @param {*} state |
|
||||
* @param {array} devices |
|
||||
*/ |
|
||||
setDevices(state, devices) { |
|
||||
if (devices && devices.length) { |
|
||||
state.devices = devices; |
|
||||
user.mutations.setCurrentDeviceId(state, devices[0].deviceId); |
|
||||
} else { |
|
||||
state.devices = []; |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 设置设备统计数据信息 |
|
||||
* @param {object} state |
|
||||
* @param {object} count // 服务端返回的对象
|
|
||||
* @param {number} count.total // 总设备数量
|
|
||||
* @param {number} count.online // 在线
|
|
||||
* @param {number} count.offline // 离线
|
|
||||
* @param {number} count.warning // 报警
|
|
||||
* @param {number} count.fault // 故障
|
|
||||
*/ |
|
||||
setDevicesCount(state, count) { |
|
||||
state.count = count; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 设置devicesAll的数据 |
|
||||
* @param {*} state |
|
||||
* @param {object} devices {page, data} |
|
||||
*/ |
|
||||
setDevicesAll(state, devices) { |
|
||||
if (devices && devices.data) { |
|
||||
for (let i = 0; i < devices.data.length; i++) { |
|
||||
const device = devices.data[i]; |
|
||||
if (device.installTime) { |
|
||||
devices.data[i].installTime = dayjs(new Date(+device.installTime)).format('YYYY-MM-DD HH:mm:ss'); |
|
||||
} |
|
||||
if (device.runTime) { |
|
||||
devices.data[i].runTime = dayjs(new Date(+device.runTime)).format('YYYY-MM-DD HH:mm:ss'); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
state.devicesAll = devices; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 设置正则编辑的设备deviceId |
|
||||
* @param {*} state |
|
||||
* @param {string} deviceId |
|
||||
*/ |
|
||||
setCurrentDeviceId(state, deviceId) { |
|
||||
state.currentDeviceId = deviceId; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 更新某个设备的信息 |
|
||||
* @param {*} param0 |
|
||||
* @param {object} newData 设备更新后的信息 |
|
||||
*/ |
|
||||
updateDevice({ devicesAll }, newData) { |
|
||||
for (let i = 0; i < devicesAll.data.length; i++) { |
|
||||
const item = devicesAll.data[i]; |
|
||||
if (item && item.deviceId === newData.deviceId) { |
|
||||
newData.installTime = dayjs(new Date(+item.installTime)).format('YYYY-MM-DD HH:mm:ss'); |
|
||||
newData.runTime = dayjs(new Date(+item.runTime)).format('YYYY-MM-DD HH:mm:ss'); |
|
||||
devicesAll.data[i] = newData; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 删除设备 |
|
||||
* @param {*} param0 |
|
||||
* @param {string} deviceId 设备id |
|
||||
*/ |
|
||||
deleteDevice({ devicesAll }, deviceId) { |
|
||||
if (!devicesAll || !devicesAll.data || !devicesAll.data.length) return; |
|
||||
devicesAll.data = devicesAll.data.filter(item => item.deviceId !== deviceId); |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 新增设备后将设备数据追加到最前边 |
|
||||
* @param {array} devicesAll |
|
||||
* @param {object} device 后台返回的新增设备信息 |
|
||||
*/ |
|
||||
unshiftDevice({ devicesAll }, device) { |
|
||||
devicesAll.data.unshift(device); |
|
||||
}, |
|
||||
}, |
|
||||
|
|
||||
actions: { |
|
||||
// 获取设备列表(站点列表)
|
|
||||
async getDevices({ commit }) { |
|
||||
try { |
|
||||
const data = await getDevices(); |
|
||||
commit('setDevices', data || []); |
|
||||
return data; |
|
||||
} catch (error) { |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 查询设备数量信息
|
|
||||
async getDevicesCount({ commit }) { |
|
||||
try { |
|
||||
const data = await getDevicesCount(); |
|
||||
commit('setDevicesCount', data); |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error.message || '获取设备统计信息失败'); |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 获取设备列表(站点列表) 完整信息
|
|
||||
async getDevicesAll({ commit }, params) { |
|
||||
try { |
|
||||
const data = await getDevicesAll(params); |
|
||||
commit('setDevicesAll', data || null); |
|
||||
return data; |
|
||||
} catch (error) { |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
export default user; |
|
@ -1,16 +1,5 @@ |
|||||
import { createStore } from 'vuex'; |
import { createStore } from 'vuex'; |
||||
import device from './device'; |
import user from './tall/user'; |
||||
import statistics from './statistics'; |
import layout from './tall/layout'; |
||||
import user from './user'; |
|
||||
|
|
||||
export default createStore({ |
export default createStore({ modules: { user, layout } }); |
||||
modules: { user, device, statistics }, |
|
||||
state: { menu: { show: true, collapse: false } }, |
|
||||
getters: {}, |
|
||||
mutations: { |
|
||||
toggleCollapse(state) { |
|
||||
state.menu.collapse = !state.menu.collapse; |
|
||||
}, |
|
||||
}, |
|
||||
actions: {}, |
|
||||
}); |
|
||||
|
@ -1,78 +0,0 @@ |
|||||
import { getDatas, getMonthsDate } from 'apis/index'; |
|
||||
|
|
||||
export default { |
|
||||
namespaced: true, |
|
||||
|
|
||||
state: { |
|
||||
electricData: null, |
|
||||
corrosionData: null, |
|
||||
moistTimeData: null, |
|
||||
realtimeData: null, |
|
||||
}, |
|
||||
|
|
||||
getters: {}, |
|
||||
|
|
||||
mutations: { |
|
||||
/** |
|
||||
* 设置积分电量数据 |
|
||||
* @param {*} state |
|
||||
* @param {array} data |
|
||||
*/ |
|
||||
setElectricData(state, data) { |
|
||||
state.electricData = data; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 设置月累计腐蚀的数据 |
|
||||
* @param {*} state |
|
||||
* @param {*} data |
|
||||
*/ |
|
||||
setCorrosionData(state, data) { |
|
||||
state.corrosionData = data; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 设置月累计湿润时间图的数据 |
|
||||
* @param {*} state |
|
||||
* @param {*} data |
|
||||
*/ |
|
||||
setMoistTimeData(state, data) { |
|
||||
state.moistTimeData = data; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 设置实时数据统计的数据 |
|
||||
* @param {*} state |
|
||||
* @param {*} data |
|
||||
*/ |
|
||||
setRealtimeData(state, data) { |
|
||||
state.realtimeData = data; |
|
||||
}, |
|
||||
}, |
|
||||
|
|
||||
actions: { |
|
||||
// 获取积分电量数据
|
|
||||
async getMonthsDate({ commit }, params) { |
|
||||
try { |
|
||||
const data = await getMonthsDate(params); |
|
||||
commit('setElectricData', data.powers || null); |
|
||||
commit('setCorrosionData', data.corrosions || null); |
|
||||
commit('setMoistTimeData', data.humids || null); |
|
||||
return data; |
|
||||
} catch (error) { |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 获取实时数据统计数据
|
|
||||
async getRealtimeData({ commit }, params) { |
|
||||
try { |
|
||||
const data = await getDatas(params); |
|
||||
commit('setRealtimeData', data || null); |
|
||||
return data; |
|
||||
} catch (error) { |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
@ -0,0 +1,8 @@ |
|||||
|
import state from './state'; |
||||
|
import mutations from './mutations'; |
||||
|
|
||||
|
export default { |
||||
|
namespaced: true, |
||||
|
state, |
||||
|
mutations, |
||||
|
}; |
@ -0,0 +1,13 @@ |
|||||
|
const mutations = { |
||||
|
/** |
||||
|
* 设置显隐 |
||||
|
* @param { Object} state |
||||
|
* @param {String} prop 要设置的字段/属性名 |
||||
|
* @param {Boolean} show true->显示,false->隐藏 |
||||
|
*/ |
||||
|
setDisplay(state, { prop, show }) { |
||||
|
state.display[prop] = show; |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
export default mutations; |
@ -0,0 +1,8 @@ |
|||||
|
/* eslint-disable object-curly-newline */ |
||||
|
const state = { |
||||
|
display: { |
||||
|
left: true, // 是否显示左栏
|
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
export default state; |
@ -1,4 +1,4 @@ |
|||||
import { getToken } from 'apis/index'; |
import { getToken } from 'apis'; |
||||
|
|
||||
export default { |
export default { |
||||
namespaced: true, |
namespaced: true, |
@ -0,0 +1,6 @@ |
|||||
|
import dayjs from 'dayjs'; |
||||
|
import 'dayjs/locale/zh-cn'; |
||||
|
|
||||
|
dayjs.locale('zh-cn'); |
||||
|
|
||||
|
export default dayjs; |
@ -1,128 +0,0 @@ |
|||||
import { STATUS_COLOR } from '@/config/config'; |
|
||||
|
|
||||
/** |
|
||||
* 生成设备概览 数量数据 |
|
||||
* @param {object} count |
|
||||
* @param {number} count.online 在线数量 |
|
||||
* @param {number} count.offline 离线数量 |
|
||||
* @param {number} count.fault 故障数量 |
|
||||
* @param {number} count.warning 报警数量 |
|
||||
* @param {number} count.total 总设备数 |
|
||||
* @returns {object} {} |
|
||||
*/ |
|
||||
// eslint-disable-next-line import/prefer-default-export
|
|
||||
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: [ |
|
||||
{ |
|
||||
name: '设备统计', |
|
||||
type: 'pie', |
|
||||
radius: ['70%', '95%'], |
|
||||
avoidLabelOverlap: false, |
|
||||
itemStyle: { |
|
||||
borderRadius: 10, |
|
||||
borderColor: '#fff', |
|
||||
borderWidth: 2, |
|
||||
}, |
|
||||
label: { |
|
||||
show: true, |
|
||||
position: 'inside', |
|
||||
fontSize: 17, |
|
||||
color: '#323232', |
|
||||
// formatter: '{b}\n{c}',
|
|
||||
lineHeight: 40, |
|
||||
}, |
|
||||
emphasis: { |
|
||||
label: { |
|
||||
show: true, |
|
||||
fontSize: 19, |
|
||||
fontWeight: 'bold', |
|
||||
}, |
|
||||
}, |
|
||||
labelLine: { show: false }, |
|
||||
data: [ |
|
||||
{ |
|
||||
value: count.online, |
|
||||
name: STATUS_COLOR.ONLINE.text, |
|
||||
itemStyle: { color: STATUS_COLOR.ONLINE.color }, |
|
||||
label: { show: count.online }, |
|
||||
}, |
|
||||
{ |
|
||||
value: count.offline, |
|
||||
name: STATUS_COLOR.OFFLINE.text, |
|
||||
itemStyle: { color: STATUS_COLOR.OFFLINE.color }, |
|
||||
label: { show: count.offline }, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
{ |
|
||||
name: '设备统计', |
|
||||
type: 'pie', |
|
||||
radius: ['35%', '60%'], |
|
||||
avoidLabelOverlap: false, |
|
||||
itemStyle: { |
|
||||
borderRadius: 10, |
|
||||
borderColor: '#fff', |
|
||||
borderWidth: 2, |
|
||||
}, |
|
||||
label: { |
|
||||
show: true, |
|
||||
position: 'inside', |
|
||||
fontSize: 14, |
|
||||
color: '#323232', |
|
||||
// formatter: '{b}\n{c}',
|
|
||||
lineHeight: 40, |
|
||||
}, |
|
||||
emphasis: { |
|
||||
label: { |
|
||||
show: true, |
|
||||
fontSize: 16, |
|
||||
fontWeight: 'bold', |
|
||||
}, |
|
||||
}, |
|
||||
labelLine: { show: false }, |
|
||||
data: [ |
|
||||
{ |
|
||||
value: count.fault, |
|
||||
name: STATUS_COLOR.FAULT.text, |
|
||||
itemStyle: { color: STATUS_COLOR.FAULT.color }, |
|
||||
label: { show: count.fault }, |
|
||||
}, |
|
||||
{ |
|
||||
value: count.warning, |
|
||||
name: STATUS_COLOR.WARNING.text, |
|
||||
itemStyle: { color: STATUS_COLOR.WARNING.color }, |
|
||||
label: { show: count.warning }, |
|
||||
}, |
|
||||
{ |
|
||||
value: count.normal, |
|
||||
name: STATUS_COLOR.NORMAL.text, |
|
||||
itemStyle: { color: STATUS_COLOR.NORMAL.color }, |
|
||||
label: { show: count.normal }, |
|
||||
}, |
|
||||
{ |
|
||||
value: count.offline, |
|
||||
name: STATUS_COLOR.OFFLINE.text, |
|
||||
itemStyle: { |
|
||||
color: STATUS_COLOR.OFFLINE.color, |
|
||||
opacity: 0, |
|
||||
}, |
|
||||
label: { show: count.offline }, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
], |
|
||||
}; |
|
||||
} |
|
@ -1,176 +0,0 @@ |
|||||
/* eslint-disable max-len,object-curly-newline */ |
|
||||
import dayjs from 'dayjs'; |
|
||||
import max from 'lodash/max'; |
|
||||
import { colors, defaultSelectedLegend, generateDefaultSeries, legendData, yAxisData } from '@/config/chart'; |
|
||||
|
|
||||
/** |
|
||||
* 生成chart所需参数 |
|
||||
* @param {Object[]} data 服务端返回数据 |
|
||||
* @param {string} data[].time 时间 ms |
|
||||
* @param {string} data[].so2 SO2 |
|
||||
* @param {string} data[].saltR 盐阻 |
|
||||
* @param {string} data[].saltT 盐温 |
|
||||
* @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: *[], corrosionTONG: *[], so2: *[], corrosionLV: *[], time: *[], saltT: *[], saltR: *[], environmentHumidity: *[]}} |
|
||||
*/ |
|
||||
function generateParams(data) { |
|
||||
const result = { |
|
||||
time: [], |
|
||||
so2: [], |
|
||||
saltR: [], |
|
||||
saltT: [], |
|
||||
environmentTemperature: [], |
|
||||
environmentHumidity: [], |
|
||||
corrosionXIN: [], |
|
||||
corrosionTONG: [], |
|
||||
corrosionLV: [], |
|
||||
corrosionGANG: [], |
|
||||
}; |
|
||||
data.forEach(item => { |
|
||||
result.time.push(dayjs(new Date(+item.time)).format('YY/MM/DD HH:mm')); |
|
||||
result.so2.push(+item.so2); |
|
||||
result.saltR.push(+item.saltR); |
|
||||
result.saltT.push(+item.saltT); |
|
||||
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; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 计算Y轴的显示 |
|
||||
* @param {string} yName Y轴的name |
|
||||
* @param {Object} selectedLegend legends |
|
||||
* @returns {boolean} |
|
||||
*/ |
|
||||
export function computeYAxisShow(yName, selectedLegend) { |
|
||||
// eslint-disable-next-line guard-for-in,no-restricted-syntax
|
|
||||
for (const key in selectedLegend) { |
|
||||
if (key.includes(yName) && selectedLegend[key]) { |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 生产y轴内容 |
|
||||
* @param {Object} selectedLegend |
|
||||
* @returns {({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}, offset: number, 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})[]} |
|
||||
*/ |
|
||||
export function generateYAxis(selectedLegend) { |
|
||||
let leftIndex = 0; |
|
||||
let rightIndex = 0; |
|
||||
yAxisData.forEach(item => { |
|
||||
item.show = computeYAxisShow(item.name, selectedLegend); |
|
||||
if (item.show) { |
|
||||
if (item.position === 'left') { |
|
||||
item.offset = 100 * leftIndex; |
|
||||
leftIndex += 1; |
|
||||
} else { |
|
||||
item.offset = 80 * rightIndex; |
|
||||
rightIndex += 1; |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
return yAxisData; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 生成series数据 |
|
||||
* @param {Object} data |
|
||||
* @param {Object[]} yAxis |
|
||||
* @returns {({data: ([]|number|string|*), name: string, type: string}|{data: ([]|number|BufferSource|string|*), name: string, type: string, yAxisIndex: number}|{data: ([]|string|*), name: string, type: string, yAxisIndex: number}|{data: ([]|string|*), name: string, type: string, yAxisIndex: number}|{data: [], name: string, type: string, yAxisIndex: number})[]|*[]} |
|
||||
*/ |
|
||||
function generateSeries(data, yAxis) { |
|
||||
const seriesArr = generateDefaultSeries(data); |
|
||||
const showArr = seriesArr.filter(item => yAxis.find(y => y.name === item.name)); |
|
||||
const hideArr = seriesArr.filter(item => !yAxis.find(y => y.name === item.name)); |
|
||||
const result = [...showArr, ...hideArr]; |
|
||||
result.forEach(item => { |
|
||||
if (item.name.includes('电流')) { |
|
||||
item.yAxisIndex = 0; |
|
||||
} else if (item.name.includes('温度')) { |
|
||||
item.yAxisIndex = 1; |
|
||||
} else if (item.name.includes('湿度')) { |
|
||||
item.yAxisIndex = 2; |
|
||||
} else if (item.name.includes('SO2')) { |
|
||||
item.yAxisIndex = 3; |
|
||||
} else if (item.name.includes('阻抗')) { |
|
||||
item.yAxisIndex = 4; |
|
||||
} |
|
||||
}); |
|
||||
return result || []; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 计算图表grid left right值 |
|
||||
* @param {Object[]} yAxis |
|
||||
* @returns {{left: number, right: number}} |
|
||||
*/ |
|
||||
function generateGrid(yAxis) { |
|
||||
const left = []; |
|
||||
const right = []; |
|
||||
yAxis.forEach(item => { |
|
||||
if (item.show) { |
|
||||
if (item.position === 'left') { |
|
||||
left.push(item.offset || 0); |
|
||||
} else { |
|
||||
right.push(item.offset || 0); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
return { |
|
||||
left: max(left) + 100, |
|
||||
right: max(right) + 80, |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 生成chart参数 |
|
||||
* @param {Object[]} rawData 返回段返回的data数据 |
|
||||
* @param {Object[]} yAxis |
|
||||
* @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, selected = defaultSelectedLegend) { |
|
||||
const data = generateParams(rawData); |
|
||||
const yAxis = generateYAxis(selected); |
|
||||
const series = generateSeries(data, yAxis); |
|
||||
const grid = generateGrid(yAxis); |
|
||||
const option = { |
|
||||
color: colors, |
|
||||
tooltip: { |
|
||||
trigger: 'axis', |
|
||||
axisPointer: { |
|
||||
type: 'cross', |
|
||||
snap: true, |
|
||||
}, |
|
||||
}, |
|
||||
grid, |
|
||||
legend: { |
|
||||
selected, |
|
||||
data: legendData, |
|
||||
}, |
|
||||
dataZoom: [{ type: 'inside' }, { type: 'slider' }], |
|
||||
xAxis: [ |
|
||||
{ |
|
||||
type: 'category', |
|
||||
axisTick: { alignWithLabel: true }, |
|
||||
data: data.time, |
|
||||
}, |
|
||||
], |
|
||||
yAxis, |
|
||||
series, |
|
||||
}; |
|
||||
return option; |
|
||||
} |
|
@ -1,16 +0,0 @@ |
|||||
import dayjs from 'dayjs'; |
|
||||
|
|
||||
/** |
|
||||
* 格式化时间 |
|
||||
* @param {string | number} time 时间戳字符串或数字 |
|
||||
* @param {string} formatStyle |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function formatMsTime(time, formatStyle = 'YYYY-MM-DD HH:mm:ss') { |
|
||||
return dayjs(new Date(+time)).format(formatStyle); |
|
||||
} |
|
||||
|
|
||||
// 图表时间轴的时间格式化
|
|
||||
export function formatChartTime(time) { |
|
||||
return formatMsTime(time, 'MM/DD HH:mm'); |
|
||||
} |
|
@ -1,182 +0,0 @@ |
|||||
<template> |
|
||||
<SearchCommands @search="onSearch" /> |
|
||||
<template v-if="data"> |
|
||||
<el-table :data="data" :max-height="contentHeight" border stripe style="width: 100%"> |
|
||||
<el-table-column align="center" fixed label="设备ID" min-width="100" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="时间" min-width="200"> |
|
||||
<template #default="scope"> |
|
||||
{{ dayjs(new Date(+scope.row.createdAt)).format('YYYY-MM-DD HH:mm:ss') }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="传输方向" min-width="80"> |
|
||||
<template #default="scope"> |
|
||||
{{ log.DIRECTION[scope.row.dir] }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="传输启动" min-width="80"> |
|
||||
<template #default="scope"> |
|
||||
{{ log.PRM[scope.row.prm] }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="安全模式" min-width="80"> |
|
||||
<template #default="scope"> |
|
||||
{{ log.SER[scope.row.ser] }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="流控" min-width="80"> |
|
||||
<template #default="scope"> |
|
||||
{{ log.DFC[scope.row.dfc] }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
|
|
||||
<el-table-column align="center" label="功能码" min-width="180"> |
|
||||
<template #default="scope"> |
|
||||
{{ log.CODE[scope.row.code].text }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
|
|
||||
<el-table-column align="center" label="包序号" min-width="80" prop="serialNo" /> |
|
||||
|
|
||||
<el-table-column align="center" label="类型标识" min-width="80"> |
|
||||
<template #default="scope"> |
|
||||
<span v-if="scope.row.asduType && log.ASDU_TYPE[scope.row.asduType]"> |
|
||||
{{ log.ASDU_TYPE[scope.row.asduType].text }} |
|
||||
</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="信息体顺序" min-width="100"> |
|
||||
<template #default="scope"> |
|
||||
{{ log.INFO_ORDER[scope.row.infoOrder] }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="信息体个数" min-width="100" prop="infoNum" /> |
|
||||
|
|
||||
<el-table-column align="center" label="传输原因" min-width="180"> |
|
||||
<template #default="scope"> |
|
||||
{{ log.REASON[scope.row.reason].text }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="协议内容" min-width="80"> |
|
||||
<template #default="scope"> |
|
||||
<el-button type="text" @click="openContent(scope.row.content)">查看</el-button> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<el-pagination |
|
||||
:current-page="page.page" |
|
||||
:default-page-size="50" |
|
||||
:page-count="page.count" |
|
||||
:page-size="page.size" |
|
||||
:page-sizes="[1, 10, 20, 50, 100]" |
|
||||
:total="page.total" |
|
||||
background |
|
||||
class="my-3 float-right" |
|
||||
layout="total, sizes, prev, pager, next, jumper" |
|
||||
@size-change="onSizeChange" |
|
||||
@current-change="onCurrentPageChange" |
|
||||
></el-pagination> |
|
||||
</template> |
|
||||
|
|
||||
<!-- 弹出框--> |
|
||||
<el-dialog v-model="showContent" title="协议内容"> |
|
||||
<code class="font-mono">{{ contents }}</code> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { getLog } from 'apis'; |
|
||||
import SearchCommands from 'components/commands/search-commands.vue'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import { computed, onMounted, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import * as log from '@/config/log'; |
|
||||
|
|
||||
const data = ref([]); |
|
||||
const page = ref({ |
|
||||
page: 1, |
|
||||
size: 50, |
|
||||
count: 0, |
|
||||
total: 0, |
|
||||
}); |
|
||||
const showContent = ref(false); // 是否显示协议内容弹出框 |
|
||||
const contents = ref(''); // 弹出的协议内容 |
|
||||
const contentHeight = ref(700); |
|
||||
const store = useStore(); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); |
|
||||
|
|
||||
// 设置表格高度 |
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 250; |
|
||||
onSearch(); |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 查询 |
|
||||
* @param {object} options |
|
||||
* @returns {Promise<void>} |
|
||||
*/ |
|
||||
async function onSearch( |
|
||||
options = { |
|
||||
...page.value, |
|
||||
sort: [ |
|
||||
{ |
|
||||
col: 'createdAt', |
|
||||
order: 'DESC', |
|
||||
}, |
|
||||
], |
|
||||
deviceId: currentDeviceId.value, |
|
||||
}, |
|
||||
) { |
|
||||
try { |
|
||||
const resData = await getLog(options); |
|
||||
page.value = resData.page; |
|
||||
data.value = resData.data; |
|
||||
} catch (error) { |
|
||||
ElMessage.error('查询失败'); |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 打开协议内容的弹出框 并记录值 |
|
||||
* @param {string} content 协议内容 |
|
||||
*/ |
|
||||
function openContent(content) { |
|
||||
showContent.value = true; |
|
||||
contents.value = content; |
|
||||
} |
|
||||
|
|
||||
// 当前页码变化 |
|
||||
const onCurrentPageChange = pageEvent => { |
|
||||
const options = { |
|
||||
page: pageEvent, |
|
||||
size: page.value.size || 50, |
|
||||
sort: [ |
|
||||
{ |
|
||||
col: 'createdAt', |
|
||||
order: 'DESC', |
|
||||
}, |
|
||||
], |
|
||||
deviceId: currentDeviceId.value, |
|
||||
}; |
|
||||
onSearch(options); |
|
||||
}; |
|
||||
|
|
||||
// 每页条数变化 |
|
||||
const onSizeChange = size => { |
|
||||
const options = { |
|
||||
page: 1, |
|
||||
size, |
|
||||
sort: [ |
|
||||
{ |
|
||||
col: 'createdAt', |
|
||||
order: 'DESC', |
|
||||
}, |
|
||||
], |
|
||||
deviceId: currentDeviceId.value, |
|
||||
}; |
|
||||
onSearch(options); |
|
||||
}; |
|
||||
</script> |
|
@ -1,32 +0,0 @@ |
|||||
<template> |
|
||||
<!-- 设置站点选择 和 设备下发状态 --> |
|
||||
<DeviceSelectAndStatus :status="status" /> |
|
||||
|
|
||||
<el-tabs v-model="activeName"> |
|
||||
<el-tab-pane :lazy="true" label="远动参数" name="function"> |
|
||||
<FunctionConfigPending v-if="activeName === 'function'" :active-name="activeName" /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane :lazy="true" label="网络参数" name="network"> |
|
||||
<NetworkConfigPending v-if="activeName === 'network'" :active-name="activeName" /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane :lazy="true" label="远动参数配置记录" name="function-log"> |
|
||||
<ConfigLogFunction v-if="activeName === 'function-log'" :active-name="activeName" /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane :lazy="true" label="网络参数配置记录" name="network-log"> |
|
||||
<ConfigLogNetwork v-if="activeName === 'network-log'" :active-name="activeName" /> |
|
||||
</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 NetworkConfigPending from 'components/config/network-config-pending.vue'; |
|
||||
import ConfigLogFunction from 'components/config/config-log-function.vue'; |
|
||||
import ConfigLogNetwork from 'components/config/config-log-network.vue'; |
|
||||
|
|
||||
const status = ref(''); |
|
||||
|
|
||||
const activeName = ref('function'); |
|
||||
</script> |
|
@ -1,185 +0,0 @@ |
|||||
<template> |
|
||||
<SearchBar :show-refresh="true" @refresh="onRefresh" @search="getData" /> |
|
||||
|
|
||||
<template v-if="data"> |
|
||||
<el-table :data="data" :max-height="contentHeight" border stripe style="width: 100%"> |
|
||||
<el-table-column align="center" fixed label="设备ID" min-width="80" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="采集时间" min-width="170"> |
|
||||
<template #default="scope"> |
|
||||
{{ formatTime(+scope.row.time) }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="后台接收时间" min-width="170"> |
|
||||
<template #default="scope"> |
|
||||
{{ formatTime(+scope.row.createdAt) }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<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-column align="center" label="环境温度(℃)" min-width="110" prop="environmentTemperature" /> |
|
||||
<el-table-column align="center" label="环境湿度(RH%)" min-width="130" prop="environmentHumidity" /> |
|
||||
<el-table-column align="center" label="SO2(ppb)" min-width="90" prop="so2" /> |
|
||||
<!-- TODO:--> |
|
||||
<el-table-column align="center" label="盐分温度(℃)" min-width="110" prop="saltT" /> |
|
||||
<el-table-column align="center" label="盐分阻抗(Ω)" min-width="110" prop="saltR" /> |
|
||||
<el-table-column align="center" label="机箱温度(℃)" min-width="110" prop="deviceTemperature" /> |
|
||||
<el-table-column align="center" label="机箱湿度(RH%)" min-width="130" prop="deviceHumidity" /> |
|
||||
<el-table-column align="center" label="太阳能板电压(V)" min-width="140" prop="solarVoltage" /> |
|
||||
<el-table-column align="center" label="蓄电池电压(V)" min-width="120" prop="batteryVoltage" /> |
|
||||
<el-table-column align="center" label="电压百分比" min-width="94" prop="batteryVoltagePercentage" /> |
|
||||
<el-table-column align="center" label="剩余电量(mAH)" min-width="140" prop="batteryVoltageRemain" /> |
|
||||
<el-table-column align="center" label="消耗电量(mAH)" min-width="140" prop="batteryLoss" /> |
|
||||
<el-table-column align="center" label="ICCID" min-width="190" prop="iccid" /> |
|
||||
<el-table-column align="center" label="IMEI" min-width="150" prop="imei" /> |
|
||||
<el-table-column align="center" label="信号强度" min-width="80" prop="signal" /> |
|
||||
<el-table-column align="center" label="基站编号" min-width="130" prop="stationNo" /> |
|
||||
<el-table-column align="center" label="硬件版本" min-width="80" prop="hardwareVersion" /> |
|
||||
<el-table-column align="center" label="软件版本" min-width="80" prop="softwareVersion" /> |
|
||||
</el-table> |
|
||||
|
|
||||
<el-pagination |
|
||||
:current-page="page.page" |
|
||||
:default-page-size="50" |
|
||||
:page-count="page.count" |
|
||||
:page-size="page.size" |
|
||||
:page-sizes="[1, 10, 20, 50, 100]" |
|
||||
:total="page.total" |
|
||||
background |
|
||||
class="my-3 float-right" |
|
||||
layout="total, sizes, prev, pager, next, jumper" |
|
||||
@current-change="onCurrentPageChange" |
|
||||
@size-change="onSizeChange" |
|
||||
@prev-click="onPrev" |
|
||||
@next-click="onNext" |
|
||||
></el-pagination> |
|
||||
</template> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import SearchBar from 'components/realtime/search-bar.vue'; |
|
||||
import { getDatas } from 'apis'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
import { REALTIME_DATA_INTERVAL } from '@/config/config'; |
|
||||
|
|
||||
const page = ref({ |
|
||||
page: 1, |
|
||||
size: 50, |
|
||||
}); |
|
||||
let timer = null; |
|
||||
let apiTimer = null; |
|
||||
const store = useStore(); |
|
||||
const token = computed(() => store.getters['user/token']); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); // 正在操作的设备的id |
|
||||
const contentHeight = ref(600); |
|
||||
const loadingSearch = ref(false); |
|
||||
const data = ref(null); |
|
||||
|
|
||||
// 获取设备完整信息列表 |
|
||||
const getData = async () => { |
|
||||
try { |
|
||||
if (token && token.value) { |
|
||||
if (!currentDeviceId.value) { |
|
||||
return ElMessage.error('请选择站点'); |
|
||||
} |
|
||||
|
|
||||
const date = [dayjs().startOf('day').format('x'), dayjs().endOf('day').format('x')]; |
|
||||
const params = { |
|
||||
deviceId: currentDeviceId.value, |
|
||||
dateRange: date, |
|
||||
paging: true, |
|
||||
page: page.value.page, |
|
||||
size: page.value.size, |
|
||||
sort: [ |
|
||||
{ |
|
||||
col: 'createdAt', |
|
||||
order: 'DESC', |
|
||||
}, |
|
||||
], |
|
||||
}; |
|
||||
|
|
||||
loadingSearch.value = true; |
|
||||
const resData = await getDatas(params); |
|
||||
loadingSearch.value = false; |
|
||||
|
|
||||
data.value = resData.data; |
|
||||
page.value = resData.page; |
|
||||
timer && clearTimeout(timer); |
|
||||
timer = null; |
|
||||
|
|
||||
// 定时轮询请求新数据 |
|
||||
if (!apiTimer) { |
|
||||
apiTimer = setInterval(() => { |
|
||||
getData(); |
|
||||
}, REALTIME_DATA_INTERVAL); |
|
||||
} |
|
||||
} else { |
|
||||
timer = setTimeout(() => { |
|
||||
getData(); |
|
||||
}, 20); |
|
||||
} |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error.message || '获取数据失败'); |
|
||||
console.log('error: ', error); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
// 设置表格高度 |
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 170; |
|
||||
currentDeviceId.value && getData(); |
|
||||
}); |
|
||||
|
|
||||
onUnmounted(() => { |
|
||||
apiTimer && clearInterval(apiTimer); |
|
||||
apiTimer = null; |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 当前 码变化 |
|
||||
* 更新page 重新 取数据 |
|
||||
* @param {number} e 的页码 |
|
||||
*/ |
|
||||
const onCurrentPageChange = e => { |
|
||||
page.value.page = e; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
const onSizeChange = e => { |
|
||||
page.value.size = e; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
// 下一页 |
|
||||
const onNext = e => { |
|
||||
page.value.page = e + 1; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
// 上一页 |
|
||||
const onPrev = e => { |
|
||||
page.value.page = e - 1; |
|
||||
getData(); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 格式化时间 |
|
||||
* @param {number} time 时间戳 |
|
||||
* @returns {string} |
|
||||
*/ |
|
||||
function formatTime(time) { |
|
||||
return dayjs(new Date(time)).format('YYYY-MM-DD HH:mm:ss'); |
|
||||
} |
|
||||
|
|
||||
// 手动刷新 清除定时器 重新获取数据 |
|
||||
function onRefresh() { |
|
||||
apiTimer && clearInterval(apiTimer); |
|
||||
apiTimer = null; |
|
||||
getData(); |
|
||||
} |
|
||||
</script> |
|
@ -0,0 +1,3 @@ |
|||||
|
<template>测试</template> |
||||
|
|
||||
|
<script setup></script> |
@ -1,192 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="deviceEdit" :model="data" :rules="deviceRules" label-position="top"> |
|
||||
<el-row :gutter="20"> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="设备ID" prop="deviceId"> |
|
||||
<el-input v-model="data.deviceId" disabled></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="站点名称" prop="address"> |
|
||||
<el-input v-model="data.address"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="产品类型" prop="type"> |
|
||||
<!-- <el-input v-model="data.securityMode"></el-input> --> |
|
||||
<el-radio v-model="data.type" label="IACD">大气腐蚀</el-radio> |
|
||||
<el-radio v-model="data.type" label="OTHER">其他</el-radio> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="设备完整ID" prop="deviceFullId"> |
|
||||
<el-input v-model="data.deviceFullId"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="地区" prop="area"> |
|
||||
<el-input v-model="data.area"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="联系人" prop="contact"> |
|
||||
<el-input v-model="data.contact"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="电话" prop="phone"> |
|
||||
<el-input v-model="data.phone"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="经度" prop="lon"> |
|
||||
<el-input v-model="data.lon"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="纬度" prop="lat"> |
|
||||
<el-input v-model="data.lat"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="负责人" prop="head"> |
|
||||
<el-input v-model="data.head"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="安装位置" prop="installLocation"> |
|
||||
<el-input v-model="data.installLocation"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="安装时间" prop="installTime"> |
|
||||
<el-date-picker v-model="data.installTime" placeholder="安装时间" style="width: 100%" type="datetime"></el-date-picker> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="正式运行时间" prop="runTime"> |
|
||||
<el-date-picker v-model="data.runTime" placeholder="正式运行时间" style="width: 100%" type="datetime"></el-date-picker> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="链路地址" prop="linkAddress"> |
|
||||
<el-input v-model="data.linkAddress"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="探头编号" prop="probNo"> |
|
||||
<el-input v-model="data.probNo"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="试样" prop="simple"> |
|
||||
<el-input v-model="data.simple"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="sim卡1" prop="sim1"> |
|
||||
<el-input v-model="data.sim1"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="设备朝向" prop="deviceDirection"> |
|
||||
<el-input v-model="data.deviceDirection"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="协议版本" prop="protocolVersion"> |
|
||||
<el-input v-model="data.protocolVersion"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="与主站后台联调情况" prop="joint"> |
|
||||
<el-input v-model="data.joint" type="textarea"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
|
|
||||
<el-col :lg="8" :md="12" :span="12" :xl="6" :xs="24"> |
|
||||
<el-form-item label="备注" prop="remark"> |
|
||||
<el-input v-model="data.remark" type="textarea"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<el-row> |
|
||||
<el-col :span="24"> |
|
||||
<el-form-item label="维修记录" prop="operationRecord"> |
|
||||
<el-input v-model="data.operationRecord" type="textarea"></el-input> |
|
||||
</el-form-item> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
|
|
||||
<el-row :gutter="20" class="mt-5 pl-2"> |
|
||||
<el-form-item> |
|
||||
<el-button type="primary" @click="onSubmit">提交</el-button> |
|
||||
<el-button @click="$emit('cancel')">取消</el-button> |
|
||||
</el-form-item> |
|
||||
</el-row> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, defineEmits, reactive, ref, watch } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { updateDevice } from 'apis'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import { deviceData, deviceRules } from '@/config/config'; |
|
||||
|
|
||||
let data = reactive(deviceData); |
|
||||
|
|
||||
const deviceEdit = ref(null); // form |
|
||||
const store = useStore(); |
|
||||
const device = computed(() => store.getters['device/current']); |
|
||||
const currentDeviceId = computed(() => store.state.device.currentDeviceId); |
|
||||
const emit = defineEmits(['cancel']); |
|
||||
|
|
||||
watch( |
|
||||
() => device.value, |
|
||||
newValue => { |
|
||||
data = newValue; |
|
||||
}, |
|
||||
{ |
|
||||
immediate: true, |
|
||||
deep: true, |
|
||||
}, |
|
||||
); |
|
||||
|
|
||||
// 提交表单 |
|
||||
const onSubmit = () => { |
|
||||
deviceEdit.value.validate(async valid => { |
|
||||
if (valid) { |
|
||||
if (data.installTime) { |
|
||||
data.installTime = new Date(data.installTime).getTime(); |
|
||||
} |
|
||||
if (data.runTime) { |
|
||||
data.runTime = new Date(data.runTime).getTime(); |
|
||||
} |
|
||||
try { |
|
||||
await updateDevice(currentDeviceId.value, data); |
|
||||
ElMessage.success('更新成功'); |
|
||||
emit('cancel'); |
|
||||
store.commit('device/updateDevice', data); |
|
||||
await store.dispatch('device/getDevices'); // 更新站点列表 |
|
||||
} catch (error) { |
|
||||
ElMessage.error('更新失败, 请稍后重试'); |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
</script> |
|
@ -1,216 +0,0 @@ |
|||||
<template> |
|
||||
<SearchBar @search="onSearch" /> |
|
||||
|
|
||||
<div class="my-3"> |
|
||||
<el-button type="primary" @click="deviceCreate.show()"> |
|
||||
<i class="el-icon-plus mr-2"></i> |
|
||||
添加设备 |
|
||||
</el-button> |
|
||||
</div> |
|
||||
|
|
||||
<template v-if="devicesAll && devicesAll.data"> |
|
||||
<el-table :data="devicesAll.data" :max-height="contentHeight" border stripe style="width: 100%"> |
|
||||
<el-table-column type="expand"> |
|
||||
<template #default="props"> |
|
||||
<el-row :gutter="20" class="px-6 text-gray-400"> |
|
||||
<el-col :span="9">链路地址:{{ props.row.linkAddress }}</el-col> |
|
||||
<el-col :span="9">探头编号:{{ props.row.probNo }}</el-col> |
|
||||
<el-col :span="9">设备朝向:{{ props.row.deviceDirection }}</el-col> |
|
||||
<el-col :span="9">试样:{{ props.row.simple }}</el-col> |
|
||||
<el-col :span="9">安装位置:{{ props.row.installLocation }}</el-col> |
|
||||
<el-col :span="9">sim1:{{ props.row.sim1 }}</el-col> |
|
||||
<el-col :span="9">协议版本:{{ props.row.protocolVersion }}</el-col> |
|
||||
<el-col :span="9"> |
|
||||
产品类型: |
|
||||
<span v-if="ASDU_TYPE[props.row.type]">{{ ASDU_TYPE[props.row.type].text }}</span> |
|
||||
</el-col> |
|
||||
<el-col :span="9">与主站后台联调情况:{{ props.row.joint }}</el-col> |
|
||||
<el-col :span="9">备注:{{ props.row.remark }}</el-col> |
|
||||
<el-col :span="9">维修记录:{{ props.row.operationRecord }}</el-col> |
|
||||
</el-row> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="设备ID" min-width="100" prop="deviceId" /> |
|
||||
<el-table-column align="center" label="设备完整ID" min-width="150" prop="deviceFullId" /> |
|
||||
<el-table-column align="left" header-align="center" label="站点" min-width="150" prop="address" /> |
|
||||
<el-table-column align="left" header-align="center" label="地区" min-width="120" prop="area" /> |
|
||||
<el-table-column align="center" label="状态" min-width="70"> |
|
||||
<template #default="scope"> |
|
||||
<el-tag v-if="scope.row.status" :color="STATUS_COLOR[scope.row.status].color" style="color: #fff"> |
|
||||
{{ STATUS_COLOR[scope.row.status].text }} |
|
||||
</el-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="联系人" min-width="100" prop="contact" /> |
|
||||
<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="180"> |
|
||||
<template #default="props"> |
|
||||
<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-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-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-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> |
|
||||
<!-- <el-button type="text" plain size="mini" icon="el-icon-delete"></el-button> --> |
|
||||
</template> |
|
||||
</el-popconfirm> |
|
||||
|
|
||||
<el-tooltip class="item" content="编辑设备信息" effect="dark" placement="top"> |
|
||||
<i class="el-icon-edit text-base text-blue-600 mx-1" @click="handleEdit(props.row)"></i> |
|
||||
</el-tooltip> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
|
|
||||
<el-pagination |
|
||||
:current-page="devicesAll.page.page" |
|
||||
:default-page-size="50" |
|
||||
:page-count="devicesAll.page.count" |
|
||||
:page-size="devicesAll.page.size" |
|
||||
:page-sizes="[1, 10, 20, 50, 100]" |
|
||||
:total="devicesAll.page.total" |
|
||||
background |
|
||||
class="my-3 float-right" |
|
||||
layout="total, sizes, prev, pager, next, jumper" |
|
||||
@size-change="onSizeChange" |
|
||||
@current-change="onCurrentPageChange" |
|
||||
></el-pagination> |
|
||||
</template> |
|
||||
|
|
||||
<!-- 编辑设备信息 --> |
|
||||
<DeviceEdit :show="editing" @toggle-mdoal="editing = false" /> |
|
||||
|
|
||||
<el-dialog v-model="deviceCreate.display" title="添加设备" top="30px" width="80%"> |
|
||||
<DeviceCreate @on-hide="deviceCreate.hide()" /> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { computed, onMounted, reactive, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { useRoute, useRouter } from 'vue-router'; |
|
||||
import { deleteDevice } from 'apis'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
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'; |
|
||||
import { STATUS_COLOR } from '@/config/config'; |
|
||||
import { ASDU_TYPE } from '@/config/log'; |
|
||||
|
|
||||
let timer = null; |
|
||||
const store = useStore(); |
|
||||
const router = useRouter(); |
|
||||
const route = useRoute(); |
|
||||
const token = computed(() => store.getters['user/token']); |
|
||||
const devicesAll = computed(() => { |
|
||||
return store.state.device.devicesAll; |
|
||||
}); |
|
||||
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 getDevicesAllData = () => { |
|
||||
try { |
|
||||
if (token && token.value) { |
|
||||
store.dispatch('device/getDevicesAll'); |
|
||||
timer && clearTimeout(timer); |
|
||||
timer = null; |
|
||||
} else { |
|
||||
timer = setTimeout(() => { |
|
||||
getDevicesAllData(); |
|
||||
}); |
|
||||
} |
|
||||
} catch (error) { |
|
||||
ElMessage.error(error); |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
getDevicesAllData(); |
|
||||
|
|
||||
// 设置表格高度 |
|
||||
onMounted(() => { |
|
||||
const winHeight = document.documentElement.clientHeight; |
|
||||
contentHeight.value = winHeight - 250; |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 删除 |
|
||||
* @param {number} page 页码 |
|
||||
* @param {number} size 每页条数 |
|
||||
*/ |
|
||||
function onSearch(page, size = 50) { |
|
||||
const deviceId = currentDeviceId.value; |
|
||||
const params = { |
|
||||
deviceId, |
|
||||
page, |
|
||||
size, |
|
||||
}; |
|
||||
store.dispatch('device/getDevicesAll', params); |
|
||||
} |
|
||||
|
|
||||
// 当前页码变化 |
|
||||
const onCurrentPageChange = page => { |
|
||||
onSearch(page, devicesAll.value.page.size || 50); |
|
||||
}; |
|
||||
|
|
||||
// 每页条数变化 |
|
||||
const onSizeChange = size => { |
|
||||
onSearch(1, size); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 删除某设备 |
|
||||
* @param {string} deviceId 设备id |
|
||||
*/ |
|
||||
const handleDelete = async deviceId => { |
|
||||
try { |
|
||||
await deleteDevice(deviceId); |
|
||||
store.commit('device/deleteDevice', deviceId); |
|
||||
ElMessage.success('删除成功'); |
|
||||
store.dispatch('device/getDevices'); // 更新站点列表 |
|
||||
} catch (error) { |
|
||||
ElMessage.error('删除失败, 请稍后重试'); |
|
||||
throw new Error(error); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
// 编辑设备信息 |
|
||||
const handleEdit = item => { |
|
||||
store.commit('device/setCurrentDeviceId', item.deviceId); |
|
||||
editing.value = true; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 打开页面 |
|
||||
* @param {object} item 设备对象 |
|
||||
* @param {string} pageName 页面name |
|
||||
*/ |
|
||||
const openPage = (item, pageName) => { |
|
||||
item && store.commit('device/setCurrentDeviceId', item.deviceId); |
|
||||
router.push({ |
|
||||
path: `/corrosion/${pageName}`, |
|
||||
query: route.query, |
|
||||
}); |
|
||||
}; |
|
||||
</script> |
|
@ -1,22 +0,0 @@ |
|||||
<template> |
|
||||
<el-tabs v-model="activeName"> |
|
||||
<el-tab-pane :lazy="true" label="本地数据" name="local"> |
|
||||
<Local v-if="activeName === 'local'" :active-name="activeName" /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane :lazy="true" label="设备数据" name="device"> |
|
||||
<Device v-if="activeName === 'device'" :active-name="activeName" /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane :lazy="true" label="补传记录" name="log"> |
|
||||
<HistoryLog v-if="activeName === 'log'" :active-name="activeName" /> |
|
||||
</el-tab-pane> |
|
||||
</el-tabs> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { ref } from 'vue'; |
|
||||
import Local from 'components/history/local.vue'; |
|
||||
import Device from 'components/history/device.vue'; |
|
||||
import HistoryLog from 'components/history/history-log.vue'; |
|
||||
|
|
||||
const activeName = ref('local'); |
|
||||
</script> |
|
@ -0,0 +1,12 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div>左边 时间轴</div> |
||||
|
<div> |
||||
|
<router-view></router-view> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup></script> |
||||
|
|
||||
|
<style scoped></style> |
@ -1,23 +0,0 @@ |
|||||
<template> |
|
||||
<el-row :gutter="20"> |
|
||||
<el-col :span="8"> |
|
||||
<el-card shadow="hover"> |
|
||||
<ChartDeviceCount /> |
|
||||
</el-card> |
|
||||
</el-col> |
|
||||
<el-col :span="16"> |
|
||||
<ChartDeviceDetail /> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
<DeviceTable /> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import ChartDeviceCount from 'components/overview/chart-device-count.vue'; |
|
||||
import ChartDeviceDetail from 'components/overview/chart-device-detail.vue'; |
|
||||
import DeviceTable from 'components/overview/device-table.vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
|
|
||||
const store = useStore(); |
|
||||
store.dispatch('device/getDevicesCount'); // 获取设备数量信息 |
|
||||
</script> |
|
@ -1,80 +0,0 @@ |
|||||
<template> |
|
||||
<SearchBar ref="searchBar" :loading-search="loadingSearch" @search="onSearch" /> |
|
||||
<HistoryData :search-height="searchHeight" class="mt-4" /> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import SearchBar from 'components/statistical/search-bar.vue'; |
|
||||
import HistoryData from 'components/statistical/stastistical-chart.vue'; |
|
||||
import { computed, onMounted, ref } from 'vue'; |
|
||||
import { useStore } from 'vuex'; |
|
||||
import { ElMessage } from 'element-plus'; |
|
||||
import dayjs from 'dayjs'; |
|
||||
|
|
||||
const searchBar = ref(null); |
|
||||
let timer = null; |
|
||||
const store = useStore(); |
|
||||
const token = computed(() => store.getters['user/token']); |
|
||||
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; |
|
||||
}); |
|
||||
|
|
||||
/** |
|
||||
* 历史数据统计 |
|
||||
* @param {*} deviceId // 站点 设备id |
|
||||
* @param {*} date // 年月时间段 |
|
||||
* @param {*} sort // 1 -> 按时间正序 -1->按时间倒序 |
|
||||
* @param {*} page // 第几页 |
|
||||
* @param {*} size // 每页多少条 |
|
||||
* @param {*} type // 0查全部 |
|
||||
*/ |
|
||||
const getData = async () => { |
|
||||
try { |
|
||||
if (token && token.value) { |
|
||||
if (!currentDeviceId.value) return; |
|
||||
loadingSearch.value = true; |
|
||||
const options = { ...search.value }; |
|
||||
const date = options && options.date ? options.date : [+dayjs().subtract(7, 'day').startOf('day').format('x'), +dayjs().format('x')]; |
|
||||
const params = { |
|
||||
deviceId: currentDeviceId.value, |
|
||||
gatheredDateRange: date, |
|
||||
paging: false, |
|
||||
sort: [ |
|
||||
{ |
|
||||
col: 'time', |
|
||||
order: 'ASC', |
|
||||
}, |
|
||||
], |
|
||||
}; |
|
||||
await store.dispatch('statistics/getRealtimeData', params); |
|
||||
timer && clearTimeout(timer); |
|
||||
timer = null; |
|
||||
loadingSearch.value = false; |
|
||||
} else { |
|
||||
loadingSearch.value = false; |
|
||||
timer = setTimeout(() => { |
|
||||
getData(); |
|
||||
}); |
|
||||
} |
|
||||
} catch (error) { |
|
||||
loadingSearch.value = false; |
|
||||
ElMessage.error(error.message || '查询失败'); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
getData(); |
|
||||
|
|
||||
/** |
|
||||
* 监听search信息 |
|
||||
* @param {object} payload search组件emit的数据 |
|
||||
*/ |
|
||||
const onSearch = payload => { |
|
||||
search.value = { ...payload }; |
|
||||
getData(); |
|
||||
}; |
|
||||
</script> |
|
@ -0,0 +1,3 @@ |
|||||
|
<template>登录</template> |
||||
|
|
||||
|
<script setup></script> |
File diff suppressed because it is too large
Loading…
Reference in new issue