WholeProcessPlatform/frontend/src/modules/yanchengshuiwenChangeMod/index.vue
2026-06-12 16:59:35 +08:00

534 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="沿程水温变化" :prompt="prompts" :moreSelect="select" :datetimePicker="datetimePicker"
@update-values="handlePanelChange1">
<a-spin :spinning="loading" tip="加载中...">
<div v-show="showemit && !loading" ref="chartRef" class="chart-container"></div>
<div v-show="!showemit && !loading" class="chart-container"> <a-empty /></div>
</a-spin>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, watch, computed } from "vue";
import * as echarts from "echarts";
import type { ECharts } from "echarts";
import SidePanelItem from "@/components/SidePanelItem/index.vue";
import { getKendoListCust, wbsbGetKendoList } from "@/api/sw";
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import { da } from "element-plus/es/locale/index.mjs";
import { f } from "vue-router/dist/router-CWoNjPRp.mjs";
import { useModelStore } from "@/store/modules/model";
const modelStore = useModelStore();
// 定义组件名(便于调试和递归)
defineOptions({
name: "yanchengshuiwenChangeMod",
});
// 改为动态获取当前时间
const getCurrentHourTime = () => {
const now = new Date();
// 减去一小时
now.setHours(now.getHours() - 1);
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hour = String(now.getHours()).padStart(2, '0');
return `${year}-${month}-${day} ${hour}`;
};
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid: any = ref(null);
const paramsOne = {
rvcd: '',
tm: []
}
const dataOne = ref('')
// 使用 computed 使 prompts 响应 dataOne.value 的变化
const prompts = computed(() => ({
show: true,
value: `注:最新数据时间为${dataOne.value || getCurrentHourTime()}`,
}));
const showemit = ref(false)
const loading = ref(false)
// const selectOptions: any = ref([])
const optionsFmt = (options: any) =>
options.map((item: any) => ({
label: item.wbsName,
value: item.wbsCode
}))
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: ECharts | null = null;
// 静态数据 - 站点名称
const stationNames = ref([]);
// 静态数据 - 水温值 (°C),班多无数据设为 null使用对象格式携带stcd信息
const waterTemperatures = ref<{ value: number | null; stcd: string; stnm: string }[]>([]);
// 使用 computed 使 currentTime 响应 dataOne.value 的变化
const currentTime = computed(() => dataOne.value || getCurrentHourTime());
// 选择器配置
const select = ref({
show: true,
value: '',
options: [],
picker: undefined,
format: undefined,
});
// 日期选择器配置
const datetimePicker = ref({
show: true,
value: computed(() => getCurrentHourTime()),
format: "YYYY-MM-DD HH",
picker: "date" as const,
options: [],
});
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
chartInstance = echarts.init(chartRef.value);
const option = {
title: {
text: "水温(°C)",
left: 5,
top: 0,
textStyle: {
color: "#000000",
fontSize: 12,
fontWeight: "normal",
},
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
zoomOnMouseWheel: true,
moveOnMouseMove: true,
filterMode: 'filter'
}
],
tooltip: {
trigger: "axis",
formatter: (params: any) => {
if (params && params.length > 0) {
const data = params[0];
// 根据项目规范:空值统一显示为短横线 `-`
if (data.value != null) {
return `${currentTime.value}<br/>${data.name}${data.value}°C`;
} else {
return `${currentTime.value}<br/>${data.name}-`;
}
}
return "";
},
},
grid: {
left: "3%",
right: "4%",
bottom: "3%",
top: "15%",
containLabel: true,
},
xAxis: {
type: "category",
data: stationNames.value,
boundaryGap: true,
axisLine: {
show: true,
lineStyle: {
color: "#8f8f8f",
},
},
axisTick: {
show: false,
},
axisLabel: {
color: "#333",
fontSize: 12,
margin: 8,
interval: 0,
formatter: (value: string, index: number) => {
// 偶数索引0, 2, 4, 6的标签在上方
// 奇数索引1, 3, 5的标签在下方
// 通过添加空行实现上下错位
if (index % 2 === 0) {
return `${value}\n `; // 上方标签:文字 + 换行 + 空格占位
} else {
return ` \n${value}`; // 下方标签:空格占位 + 换行 + 文字
}
},
},
splitLine: {
show: true,
lineStyle: {
color: "#e0e0e0",
type: "solid",
},
},
},
yAxis: {
type: "value",
min: 0,
// max: 10,
interval: 2,
axisLine: {
show: true,
lineStyle: {
color: "#8f8f8f",
},
},
axisTick: {
show: true,
length: 3,
lineStyle: {
color: "#8f8f8f",
},
},
axisLabel: {
color: "#333",
fontSize: 12,
},
splitLine: {
show: true,
lineStyle: {
color: "#e0e0e0",
type: "solid",
},
},
},
series: [
{
name: "水温",
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 6,
connectNulls: true, // 连接空值两侧的线段,避免折线断开
lineStyle: {
color: "#6ca4f7",
width: 2,
},
itemStyle: {
color: "#6ca4f7",
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "rgba(108, 164, 247, 0.3)",
},
{
offset: 1,
color: "rgba(108, 164, 247, 0.05)",
},
]),
},
data: waterTemperatures.value,
},
],
};
chartInstance.setOption(option);
// 添加点击事件监听器
chartInstance.on('click', (params: any) => {
if (params.componentType === 'series') {
console.log('点击数据点:', params);
console.log('stcd:', params.data.stcd);
console.log('stnm:', params.data.stnm);
console.log('temperature:', params.data.value);
modelStore.modalVisible = true;
modelStore.params.sttp = "WT";
modelStore.title = params.data.stnm;
modelStore.params.stcd = params.data.stcd;
modelStore.params.date = paramsOne.tm;
}
});
};
// 处理窗口大小变化
const handleResize = () => {
chartInstance?.resize();
};
const init = async () => {
if (loading.value) return; // 防止重复请求
loading.value = true;
try {
const params = {
filter: {
logic: "and",
filters: [
{ field: "rvcd", operator: "eq", dataType: "string", value: paramsOne.rvcd },
{ field: "tm", operator: "gte", dataType: "date", value: paramsOne.tm[1] },
{ field: "tm", operator: "lte", dataType: "date", value: paramsOne.tm[0] },
],
},
sort: [{ field: "sort", dir: "asc" }],
};
let res = await getKendoListCust(params);
let data = res.data.data || res.data
if (data.length > 0) {
showemit.value = true
} else {
showemit.value = false
}
stationNames.value = data
.filter((item: any) => item.sttp == "1")
.map((item: any) => item.stnm);
console.log(stationNames.value);
// 修改为对象格式携带stcd和stnm信息
waterTemperatures.value = data
.filter((item: any) => item.sttp == "2")
.map((item: any) => ({
value: item.temperature,
stcd: item.stcd,
stnm: item.stnm
}));
console.log(waterTemperatures.value);
// 数据获取完成后,初始化或更新图表
setTimeout(() => {
if (!chartInstance) {
initChart();
} else {
// 如果图表已存在,只更新数据
chartInstance.setOption({
xAxis: {
data: stationNames.value,
},
series: [
{
data: waterTemperatures.value,
},
],
});
}
// 强制重绘,确保尺寸正确
setTimeout(() => {
chartInstance?.resize();
}, 100);
}, 50);
} catch (error) {
console.error('数据加载失败:', error);
showemit.value = false;
} finally {
loading.value = false;
}
};
//获取选择器配置参数
const getSelectConfig = async () => {
loading.value = true;
try {
let obj: any = {}
if (baseid.value === 'all') {
obj = { rstcdStepSort: 'asc', siteStepSort: 'asc' }
} else {
obj = { siteStepSort: 'asc' }
}
const filters = [
{
field: 'wbsType',
operator: 'eq',
value: 'PSB_RVCD'
}
]
if (baseid.value && baseid.value !== 'all') {
filters.push({
field: 'objId',
operator: 'eq', // contains
value: baseid.value
})
}
let data: any = {
filter: {
logic: 'and',
filters
}
// select: ['WBS_CODE', 'WBS_NAME']
}
if (obj) {
data.sort = [obj]
} else {
data = {
...data,
group: [
{ dir: 'asc', field: 'orderIndex' },
{ dir: 'asc', field: 'wbsCode' },
{ dir: 'asc', field: 'wbsName' },
{ dir: 'asc', field: 'objid' },
],
groupResultFlat: true
}
}
let res = await wbsbGetKendoList(data)
let dataOne = res?.data?.data || res?.data
if (dataOne.length > 0) {
let dataMapNameMap: any = {}
let jiDiListMap: any = {}
JidiSelectEventStore.jidiData.forEach((item: any) => {
jiDiListMap[item.wbsCode] = item.wbsName
})
dataOne.map((item: any, index: number) => {
const { stcd, stnm, objId } = item
if (dataMapNameMap[objId]) {
dataMapNameMap[objId].push({ ...item, baseName: jiDiListMap[objId], baseId: objId })
} else {
dataMapNameMap[objId] = [{ ...item, baseName: jiDiListMap[objId], baseId: objId }]
}
return { label: item.wbsName, value: item.wbsCode, baseId: objId, baseName: jiDiListMap[objId] }
})
let dataMapNameArr: any = []
Object.keys(dataMapNameMap).forEach((item: any) => {
dataMapNameArr.push({
title: dataMapNameMap[item]?.[0]?.baseName,
value: item,
selectable: false,
// baseId:dataMapNameMap[item]?.[0]?.baseId,
children: dataMapNameMap[item].map((item2: any) => {
return {
title: item2.wbsName,
value: item2.wbsCode
}
})
})
})
dataMapNameArr = dataMapNameArr.sort((a: any, b: any) => {
const indexA = JidiSelectEventStore.jidiData.findIndex(item => item.wbsCode === a.value);
const indexB = JidiSelectEventStore.jidiData.findIndex(item => item.wbsCode === b.value);
return indexA - indexB;
})
select.value.options = filterSelectOptions(dataMapNameArr)
if (baseid.value === 'all') {
select.value.value = 'SJLY1U'
} else if (filterSelectOptions(dataMapNameArr)[0]?.children) {
select.value.value = filterSelectOptions(dataMapNameArr)[0]?.children[0]?.value
} else if (filterSelectOptions(dataMapNameArr)[0]?.value) {
select.value.value = filterSelectOptions(dataMapNameArr)[0]?.value
} else {
select.value.value = ''
}
}
} catch (error) {
console.error('选择器配置加载失败:', error);
} finally {
loading.value = false;
}
}
const filterSelectOptions = (selectOptions: any) => {
if (selectOptions?.length === 1 && selectOptions?.[0]?.children?.length === 1) {
return [{ ...selectOptions?.[0]?.children?.[0], isLeaf: true }]
} else if (selectOptions.length) {
return selectOptions.map((e) => {
if (e?.children?.length > 1) {
return { ...e, isLeaf: false, selectable: true, children: e.children.map((item) => ({ ...item, isLeaf: true })) }
} else {
return { ...e.children[0], isLeaf: true }
}
})
}
return []
}
//监听子组件的数据变化
const handlePanelChange1 = (data) => {
console.log('当前所有控件状态:', data);
if (data.moreSelect) {
paramsOne.rvcd = data.moreSelect
}
if (data.datetime) {
dataOne.value = data.datetime
const datetime = data.datetime;
// 解析日期和时间
const [datePart, hourPart] = datetime.split(' ');
const [year, month, day] = datePart.split('-').map(Number);
// 创建当前时间的 Date 对象
const currentDate = new Date(year, month - 1, day, parseInt(hourPart), 0, 0);
// 创建一个月前的 Date 对象
const previousDate = new Date(year, month - 2, day, 0, 0, 0);
// 格式化函数:将 Date 对象转为 "YYYY-MM-DD HH:mm:ss" 格式
function formatDate(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
const h = String(date.getHours()).padStart(2, '0');
const min = String(date.getMinutes()).padStart(2, '0');
const s = String(date.getSeconds()).padStart(2, '0');
return `${y}-${m}-${d} ${h}:${min}:${s}`;
}
// 生成结果数组
const result = [
formatDate(currentDate), // "2026-05-15 15:00:00"
formatDate(previousDate) // "2026-04-15 00:00:00"
];
paramsOne.tm = result
console.log(paramsOne.tm, 'paramsOne.tm')
}
if (paramsOne.rvcd || paramsOne.tm.length > 0) {
init();
}
}
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
baseid.value = newVal.wbsCode;
getSelectConfig()
},
{ deep: true, immediate: true }
);
// 页面加载时执行的逻辑
onMounted(() => {
// 延迟初始化,确保 DOM 渲染完成
init();
window.addEventListener("resize", handleResize);
});
// 组件卸载前清理
onBeforeUnmount(() => {
window.removeEventListener("resize", handleResize);
chartInstance?.dispose();
});
</script>
<style lang="scss" scoped>
.chart-container {
width: 100%;
height: 252px;
display: flex;
justify-content: center;
align-items: center;
}
:deep(.ant-spin-nested-loading) {
height: 252px !important;
}
</style>