499 lines
15 KiB
Vue
499 lines
15 KiB
Vue
<!-- eslint-disable vue/v-on-event-hyphenation -->
|
||
<template>
|
||
<div class="parent-container">
|
||
<div class="ns-tree-title">
|
||
<ns-icon name="deviceType" size="11" style="margin-top: 10px" />
|
||
<div class="title">设备列表</div>
|
||
</div>
|
||
<a-tree-select
|
||
ref="select"
|
||
placeholder="请选择设备类型"
|
||
v-model:value="value"
|
||
style="width: 100%"
|
||
:treeDefaultExpandedKeys="firstKey"
|
||
:tree-line="treeLine && { showLeafIcon }"
|
||
:tree-data="treeData1"
|
||
@change="changeDeviceType" />
|
||
|
||
<!-- <a-spin :spinning="treeLoading"> -->
|
||
<a-tree
|
||
v-model:expandedKeys="expandedKeys"
|
||
v-model:selectedKeys="selectedKeys"
|
||
v-model:checkedKeys="checkedKeys"
|
||
:show-line="{ showLeafIcon: false }"
|
||
checkable
|
||
:height="560"
|
||
style="width: 100%; overflow-y: auto; margin-bottom: 10px; margin-top: 10px"
|
||
:tree-data="treeData2" />
|
||
<!-- </a-spin> -->
|
||
|
||
<!-- <div class="fixed-bottom"> -->
|
||
<div>
|
||
<!-- <a-divider /> -->
|
||
<a-select
|
||
v-model:value="selectedValue"
|
||
placeholder="请选择点位"
|
||
:style="{
|
||
top: '50px',
|
||
left: `${divWidth + 55}px`,
|
||
zIndex: 4,
|
||
position: 'absolute',
|
||
width: `${divWidth}px`,
|
||
}"
|
||
:options="options1" />
|
||
<a-select
|
||
v-model:value="frequencyValue"
|
||
placeholder="请选择频率"
|
||
:style="{
|
||
top: '50px',
|
||
left: `${divWidth * 2 + 65}px`,
|
||
zIndex: 4,
|
||
position: 'absolute',
|
||
width: `${divWidth}px`,
|
||
}"
|
||
:options="options2" />
|
||
<a-range-picker
|
||
:value="hackValue || dateRange"
|
||
:disabled-date="disabledDate"
|
||
@change="onChange"
|
||
@openChange="onOpenChange"
|
||
@calendarChange="onCalendarChange"
|
||
:style="{
|
||
top: '50px',
|
||
left: `${divWidth * 3 + 75}px`,
|
||
zIndex: 4,
|
||
position: 'absolute',
|
||
width: `${divWidth}px`,
|
||
}"
|
||
:placeholder="['请选择日期', '请选择日期']" />
|
||
<a-button
|
||
type="primary"
|
||
:style="{
|
||
top: '50px',
|
||
left: `${divWidth * 4 + 85}px`,
|
||
zIndex: 4,
|
||
position: 'absolute',
|
||
}"
|
||
@click="getSelect"
|
||
v-if="divWidth != 0">
|
||
查询
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts">
|
||
import { message } from 'ant-design-vue';
|
||
import type { TreeSelectProps, SelectProps } from 'ant-design-vue';
|
||
import { defineComponent, ref, onMounted, onUnmounted, watch } from 'vue';
|
||
import dayjs, { Dayjs } from 'dayjs';
|
||
import { inject } from 'vue';
|
||
import { http } from '/nerv-lib/util';
|
||
import { device } from '/@/api/deviceManage';
|
||
import { deviceMonitor } from '/@/api/monitor';
|
||
import { Item } from 'ant-design-vue/lib/menu';
|
||
import { dict, getEnum } from '/@/api';
|
||
// 全局变量
|
||
import { items } from '/@/store/item';
|
||
|
||
export default defineComponent({
|
||
// eslint-disable-next-line vue/multi-word-component-names
|
||
name: 'Tree',
|
||
setup() {
|
||
const select = ref<HTMLElement | null>(null);
|
||
const divWidth = ref(0); // 用于存储 div 的宽度
|
||
|
||
// 全局变量
|
||
const state = items();
|
||
// 获取 div 的宽度
|
||
// const getDivWidth = () => {
|
||
// if (select.value) {
|
||
// divWidth.value = select.value.$el.offsetWidth;
|
||
// }
|
||
// };
|
||
// 使用 ResizeObserver 监听宽度变化
|
||
const getDivWidth = new ResizeObserver(() => {
|
||
if (select.value?.$el) {
|
||
divWidth.value = select.value.$el.offsetWidth;
|
||
console.log('宽度变化:', divWidth.value);
|
||
}
|
||
});
|
||
|
||
const treeLoading = ref(false);
|
||
const treeLine = ref(true);
|
||
const showLeafIcon = ref(false);
|
||
const value = ref<string>();
|
||
|
||
const orgId = ref('');
|
||
const result = JSON.parse(sessionStorage.getItem('ORGID')!);
|
||
orgId.value = result;
|
||
|
||
const treeData1 = ref<TreeSelectProps['treeData']>([]);
|
||
const firstKey = ref<String[]>([]);
|
||
|
||
http.post(device.queryDeviceTree, { orgId: orgId.value }).then((res) => {
|
||
treeData1.value = formatTreeData(res.data);
|
||
if (treeData1.value && treeData1.value.length > 0) {
|
||
firstKey.value = [treeData1.value[0].value];
|
||
}
|
||
// if (treeData1.value && treeData1.value.length > 0) {
|
||
// if (treeData1.value[0].children) {
|
||
// value.value = treeData1.value[0].children[0].value;
|
||
// changeDeviceType(treeData1.value[0].children[0].value, [
|
||
// treeData1.value[0].children[0].title,
|
||
// ]);
|
||
// } else {
|
||
// value.value = treeData1.value[0].value;
|
||
// changeDeviceType(treeData1.value[0].value, [treeData1.value[0].title]);
|
||
// }
|
||
// }
|
||
});
|
||
|
||
const formatTreeData = (data: any) => {
|
||
return data.map((item: any) => ({
|
||
title: item.code + '.' + item.deviceType,
|
||
value: item.code,
|
||
disabled: item.children.length != 0 ? true : false,
|
||
children: item.children ? formatTreeData(item.children) : [],
|
||
}));
|
||
};
|
||
|
||
const treeData2 = ref<TreeSelectProps['treeData']>([]);
|
||
|
||
const changeDeviceType = (val: any, label: any) => {
|
||
options1.value = [];
|
||
selectedValue.value = '';
|
||
treeLoading.value = true;
|
||
http
|
||
.post(device.queryDevicePage, {
|
||
deviceCode: val,
|
||
orgId: orgId.value,
|
||
pageNum: 1,
|
||
pageSize: 1000,
|
||
})
|
||
.then((res) => {
|
||
if (!val) {
|
||
val = '999999999';
|
||
}
|
||
if (!label || label.length == 0) {
|
||
label = ['所有设备'];
|
||
}
|
||
let records = res.data.records;
|
||
records.forEach((item: any) => {
|
||
(item.title = item.snCode + '(' + item.deviceName + ')'),
|
||
(item.key = item.deviceInfoCode);
|
||
});
|
||
let a: TreeSelectProps['treeData'] = [{ title: label[0], key: val, children: records }];
|
||
treeData2.value = a;
|
||
expandedKeys.value = [val];
|
||
if (records && records.length > 2) {
|
||
checkedKeys.value = [records[0].deviceInfoCode, records[1].deviceInfoCode];
|
||
}
|
||
})
|
||
.finally(() => {
|
||
treeLoading.value = false;
|
||
});
|
||
};
|
||
|
||
const expandedKeys = ref<string[]>([]);
|
||
const selectedKeys = ref<string[]>([]);
|
||
const checkedKeys = ref<string[]>([]);
|
||
|
||
const options1 = ref<SelectProps['options']>([]);
|
||
const options2 = ref<SelectProps['options']>([
|
||
// {
|
||
// value: '1',
|
||
// label: '5分钟',
|
||
// },
|
||
// {
|
||
// value: '2',
|
||
// label: '10分钟',
|
||
// },
|
||
// {
|
||
// value: '3',
|
||
// label: '30分钟',
|
||
// },
|
||
// {
|
||
// value: '4',
|
||
// label: '1小时',
|
||
// },
|
||
]);
|
||
const selectedValue = ref<string | undefined>();
|
||
const frequencyValue = ref<string | undefined>();
|
||
const dateRange = ref<[Dayjs, Dayjs] | undefined>([dayjs(), dayjs()]);
|
||
|
||
interface PageData {
|
||
tableList: any[];
|
||
tableColumns: any[];
|
||
graphList: any[];
|
||
XData: any[];
|
||
}
|
||
const pageData = inject<PageData>('pageData');
|
||
if (!pageData) {
|
||
throw new Error('pageData is not provided');
|
||
}
|
||
const getDianWeiList = () => {
|
||
options1.value = [];
|
||
selectedValue.value = '';
|
||
let deviceIds: any[] = [];
|
||
if (checkedKeys.value && checkedKeys.value.length > 0) {
|
||
checkedKeys.value.forEach((element) => {
|
||
if (value.value != element && value.value != '999999999') {
|
||
deviceIds.push(element);
|
||
}
|
||
});
|
||
if (deviceIds.length == 0) {
|
||
return;
|
||
}
|
||
http
|
||
.post(deviceMonitor.getDevicePointToMonitor, {
|
||
deviceIds: deviceIds,
|
||
orgId: orgId.value,
|
||
type: 0,
|
||
})
|
||
.then((res) => {
|
||
if (res.retcode == 0) {
|
||
options1.value = [];
|
||
res.data.forEach((item: any) => {
|
||
options1.value?.push({ value: item.code, label: item.name });
|
||
});
|
||
selectedValue.value = options1.value[0].value;
|
||
if (
|
||
pageData.tableList.length == 0 ||
|
||
pageData.tableColumns.length == 0 ||
|
||
pageData.graphList.length == 0 ||
|
||
pageData.XData.length == 0
|
||
) {
|
||
getSelect();
|
||
}
|
||
}
|
||
|
||
// options1.value = res.data;
|
||
});
|
||
} else {
|
||
options1.value = [];
|
||
}
|
||
// options1.value = [
|
||
// { value: '1', label: 'A 项电压' },
|
||
// { value: '2', label: 'B 项电压' },
|
||
// { value: '3', label: 'C 项电压' },
|
||
// { value: '4', label: 'AB 线电压' },
|
||
// { value: '5', label: 'BC 线电压' },
|
||
// { value: '6', label: 'A 项电流' },
|
||
// { value: '7', label: 'B 项电流' },
|
||
// ];
|
||
};
|
||
|
||
// 查询数据后放入pageData
|
||
const getSelect = () => {
|
||
state.setLoading(true);
|
||
pageData.tableList = [];
|
||
pageData.tableColumns = [];
|
||
|
||
pageData.graphList = [];
|
||
pageData.XData = [];
|
||
if (!startDate.value || !endDate.value) {
|
||
// 获取当天的时间
|
||
const today = new Date();
|
||
const year = today.getFullYear();
|
||
const month = String(today.getMonth() + 1).padStart(2, '0'); // getMonth() 返回的月份是0-11
|
||
const day = String(today.getDate()).padStart(2, '0');
|
||
|
||
startDate.value = year + '-' + month + '-' + day;
|
||
endDate.value = year + '-' + month + '-' + day;
|
||
}
|
||
let deviceIds: any[] = [];
|
||
if (checkedKeys.value && checkedKeys.value.length > 0) {
|
||
checkedKeys.value.forEach((element) => {
|
||
if (value.value != element && value.value != '999999999') {
|
||
deviceIds.push(element);
|
||
}
|
||
});
|
||
}
|
||
if (deviceIds.length == 0) {
|
||
message.warning('请先选择设备!');
|
||
return;
|
||
}
|
||
http
|
||
.post(deviceMonitor.getDeviceGraph, {
|
||
deviceIds: deviceIds,
|
||
devicePointCode: selectedValue.value,
|
||
|
||
endDate: endDate.value,
|
||
startDate: startDate.value,
|
||
timeRate: frequencyValue.value,
|
||
})
|
||
.then((res) => {
|
||
pageData.tableList = res.data.tableList;
|
||
pageData.tableColumns = res.data.tableHeaderList;
|
||
|
||
pageData.graphList = res.data.graphData;
|
||
pageData.XData = res.data.XData;
|
||
})
|
||
.finally(() => {
|
||
state.setLoading(false);
|
||
});
|
||
};
|
||
|
||
type RangeValue = [Dayjs, Dayjs];
|
||
const dates = ref<RangeValue>();
|
||
const hackValue = ref<RangeValue>();
|
||
const startDate = ref<String>();
|
||
const endDate = ref<String>();
|
||
|
||
const onChange = (val: RangeValue, dateStrings: any) => {
|
||
dateRange.value = val;
|
||
if (dateStrings && dateStrings.length === 2) {
|
||
startDate.value = dateStrings[0];
|
||
endDate.value = dateStrings[1];
|
||
}
|
||
};
|
||
const onOpenChange = (open: boolean) => {
|
||
if (open) {
|
||
dates.value = [] as any;
|
||
hackValue.value = [] as any;
|
||
} else {
|
||
hackValue.value = undefined;
|
||
}
|
||
};
|
||
const disabledDate = (current: Dayjs) => {
|
||
if (!dates.value || (dates.value as any).length === 0) {
|
||
return false;
|
||
}
|
||
const tooLate = dates.value[0] && current.diff(dates.value[0], 'days') > 2;
|
||
const tooEarly = dates.value[1] && dates.value[1].diff(current, 'days') > 2;
|
||
return tooEarly || tooLate;
|
||
};
|
||
const onCalendarChange = (val: RangeValue) => {
|
||
dates.value = val;
|
||
};
|
||
|
||
onMounted(async () => {
|
||
if (select.value?.$el) {
|
||
divWidth.value = select.value.$el.offsetWidth;
|
||
getDivWidth.observe(select.value.$el);
|
||
}
|
||
// getDivWidth();
|
||
// window.addEventListener('resize', getDivWidth); // 监听窗口大小变化
|
||
|
||
let frequency = await getEnum({ params: { enumType: 'TimeFrequencyEnum' } });
|
||
options2.value = frequency.data;
|
||
if (options2.value && options2.value.length > 0) {
|
||
frequencyValue.value = options2.value[options2.value.length - 1].value;
|
||
}
|
||
// changeDeviceType(null, null);
|
||
// getSelect();
|
||
});
|
||
// 在组件卸载时移除监听器
|
||
// onUpdated(() => {
|
||
// window.removeEventListener('resize', getDivWidth);
|
||
// });
|
||
// 在组件卸载时停止监听
|
||
onUnmounted(() => {
|
||
if (select.value?.$el) {
|
||
getDivWidth.unobserve(select.value.$el);
|
||
}
|
||
getDivWidth.disconnect();
|
||
});
|
||
// 监听 pageData 的变化
|
||
watch(
|
||
() => checkedKeys,
|
||
(_newValue, _oldValue) => {
|
||
getDianWeiList();
|
||
},
|
||
{ deep: true },
|
||
);
|
||
|
||
return {
|
||
treeLine,
|
||
showLeafIcon,
|
||
value,
|
||
treeData1,
|
||
treeData2,
|
||
expandedKeys,
|
||
selectedKeys,
|
||
checkedKeys,
|
||
options1,
|
||
options2,
|
||
selectedValue,
|
||
frequencyValue,
|
||
dateRange,
|
||
getDianWeiList,
|
||
getSelect,
|
||
disabledDate,
|
||
onCalendarChange,
|
||
onOpenChange,
|
||
onChange,
|
||
hackValue,
|
||
pageData,
|
||
changeDeviceType,
|
||
treeLoading,
|
||
select,
|
||
divWidth,
|
||
firstKey,
|
||
};
|
||
},
|
||
});
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.ns-tree-title {
|
||
display: flex;
|
||
user-select: text;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 10px;
|
||
padding-top: 10px;
|
||
border-bottom: 1px solid #e9e9e9;
|
||
> span {
|
||
padding-left: 10px;
|
||
line-height: 20px;
|
||
}
|
||
}
|
||
.parent-container {
|
||
// position: relative;
|
||
border-radius: 10px;
|
||
background: #ffffff;
|
||
padding-left: 10px;
|
||
padding-right: 10px;
|
||
height: 100%;
|
||
}
|
||
|
||
// .fixed-bottom {
|
||
// // display: flex;
|
||
// // top: 50px;
|
||
// // left: 340px;
|
||
// // z-index: 9;
|
||
|
||
// // position: absolute;
|
||
// // bottom: 0;
|
||
// width: 100%;
|
||
// // margin-bottom: 10px;
|
||
// }
|
||
|
||
.title {
|
||
text-align: left;
|
||
height: 32px;
|
||
line-height: 32px;
|
||
font-weight: bold;
|
||
user-select: text;
|
||
position: relative;
|
||
padding-left: 9px;
|
||
}
|
||
// .title::before {
|
||
// content: '';
|
||
// position: absolute;
|
||
// left: 10px;
|
||
// top: 50%;
|
||
// transform: translateY(-50%);
|
||
// height: 13px;
|
||
// width: 3px;
|
||
// border-radius: 1px;
|
||
// background-color: #2778ff;
|
||
// }
|
||
|
||
::v-deep .ant-tree-list-scrollbar-thumb {
|
||
width: 75% !important;
|
||
background: rgba(0, 0, 0, 0.25) !important;
|
||
}
|
||
</style>
|