水温接口-线上和弹框
This commit is contained in:
commit
a43b35b5a8
@ -9,7 +9,7 @@ VITE_APP_BASE_API = '/dev-api'
|
|||||||
# 本地环境
|
# 本地环境
|
||||||
# VITE_APP_BASE_URL = 'http://localhost:8093'
|
# VITE_APP_BASE_URL = 'http://localhost:8093'
|
||||||
# 测试环境
|
# 测试环境
|
||||||
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
|
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
|
||||||
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
|
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
|
||||||
# 汤伟
|
# 汤伟
|
||||||
VITE_APP_BASE_URL = 'http://10.84.121.21:8093'
|
VITE_APP_BASE_URL = 'http://10.84.121.21:8093'
|
||||||
|
|||||||
8
frontend/src/api/mapModal/index.ts
Normal file
8
frontend/src/api/mapModal/index.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
export function getStcdDetail(url: string, stcd: string) {
|
||||||
|
return request({
|
||||||
|
url: url,
|
||||||
|
method: 'get',
|
||||||
|
params: { stcd }
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -64,3 +64,91 @@ export function baseEvnmAutoMonitorGetKendoListCust(data: any) {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
////水温监测工作开展情况弹框
|
||||||
|
export function vmsstbprptGetKendoList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//出入库水温打开弹框api/wmp-env-server/sw/inOutOne/details
|
||||||
|
export function inOutOneDetails(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/wmp-env-server/sw/inOutOne/details',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//鱼类适宜性分析 - select
|
||||||
|
export function infoGetKendoListCust(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/wmp-env-server/sw/wtrv/fish/info/GetKendoListCust',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//鱼类适宜性分析-图表和table
|
||||||
|
export function fishGetKendoListCust(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/wmp-env-server/sw/wtrv/fish/GetKendoListCust',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//月平均水温历史对比
|
||||||
|
export function avgMonGetKendoListCust(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/wmp-env-server/sw/monthList/avgMon/GetKendoListCust',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//水温年内分布
|
||||||
|
export function yearListGetKendoListCust(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/wmp-env-server/sw/yearList/GetKendoListCust',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//设施类型介绍
|
||||||
|
export function sttpbGetKendoList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/dec-lygk-base-server/base/sttpb/GetKendoList',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//设施类型及接入情况
|
||||||
|
export function dwInfoGetKendoListCust(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/dec-lygk-base-server/base/dwInfo/GetKendoListCust',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//月均水温对比,图表,表格 /api/wmp-env-server/sw/monthDetail/Det/GetKendoListCust
|
||||||
|
export function DetGetKendoListCust(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/wmp-env-server/sw/monthDetail/Det/GetKendoListCust',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//水温年内分布
|
||||||
|
export function yearDetailGetKendoListCust(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/wmp-env-server/sw/yearDetail/GetKendoListCust',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//获取建设状态
|
||||||
|
export function dictgetRemoteDictValue(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/api/dec-modules-usm-springcloud-starter/usm/v1/dict/getRemoteDictValue',
|
||||||
|
method: 'get',
|
||||||
|
params: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -82,7 +82,7 @@ const scrollConfig = computed(() => {
|
|||||||
else if (tableScrollY.value > 0) {
|
else if (tableScrollY.value > 0) {
|
||||||
config.y = tableScrollY.value;
|
config.y = tableScrollY.value;
|
||||||
}
|
}
|
||||||
console.log(tableScrollY.value);
|
console.log(config);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2072,7 +2072,7 @@ const DwPointColumns: Array<any> = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '站址',
|
name: '站址',
|
||||||
filed: 'stlc',
|
filed: 'addvcdName',
|
||||||
visible: true,
|
visible: true,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
url: '',
|
url: '',
|
||||||
@ -2608,7 +2608,7 @@ const DwOnePointColumns: Array<any> = [
|
|||||||
url: '',
|
url: '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '多层式进水口',
|
name: '夹岩双层取水',
|
||||||
visible: false,
|
visible: false,
|
||||||
ruleTips: '',
|
ruleTips: '',
|
||||||
type: '',
|
type: '',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
监测数据
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@ -0,0 +1,653 @@
|
|||||||
|
<template>
|
||||||
|
<div class="body_one">
|
||||||
|
<div class="search_one">
|
||||||
|
<div class="search_left">
|
||||||
|
<div>鱼类选择:</div>
|
||||||
|
<a-select v-model:value="selectValue" mode="multiple" style="width: 260px;" placeholder=" "
|
||||||
|
:options="selectOption" @change="handleChange"></a-select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a-range-picker v-model:value="rangePicker" format="YYYY-MM-DD" :disabled-date="disabledDate"
|
||||||
|
:allow-clear="false" @change="handleDateChange">
|
||||||
|
<template #renderExtraFooter>
|
||||||
|
<div class="quick-date-options">
|
||||||
|
<a-button size="small" @click="setQuickRange(7)">最近七天</a-button>
|
||||||
|
<a-button size="small" @click="setQuickRange(30)">最近一个月</a-button>
|
||||||
|
<a-button size="small" @click="setQuickRange(90)">最近三个月</a-button>
|
||||||
|
<a-button size="small" @click="setQuickRange(180)">最近六个月</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-range-picker>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="body_body">
|
||||||
|
<div class="echarts" ref="chartRef"></div>
|
||||||
|
<div class="table">
|
||||||
|
<BasicTable ref="tableRef" :scrollY="460" :columns="columns" :list-url="fishGetKendoListCust"
|
||||||
|
:search-params="{}" :transform-data="customTransform" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch, onMounted, onUnmounted, computed } from "vue";
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
|
import { useModelStore } from "@/store/modules/model";
|
||||||
|
import { infoGetKendoListCust, fishGetKendoListCust } from "@/api/sw";
|
||||||
|
import BasicTable from "@/components/BasicTable/index.vue";
|
||||||
|
const modelStore = useModelStore();
|
||||||
|
const selectOption = ref([])
|
||||||
|
const selectValue = ref([])
|
||||||
|
const tableRef = ref<any>(null);
|
||||||
|
const chartRef = ref<HTMLDivElement | null>(null);
|
||||||
|
let chartInstance: echarts.ECharts | null = null;
|
||||||
|
const chartData = ref<any[]>([]);
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '时间',
|
||||||
|
dataIndex: 'dt',
|
||||||
|
width: 180,
|
||||||
|
customRender: ({ text }: any) => text ? dayjs(text).format('YYYY-MM-DD') : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '水温°C',
|
||||||
|
dataIndex: 'wt',
|
||||||
|
customRender: ({ text }: any) => text !== undefined && text !== null ? text : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '上一年水温',
|
||||||
|
dataIndex: 'beforeWt',
|
||||||
|
customRender: ({ text }: any) => text !== undefined && text !== null ? text : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '同期对比',
|
||||||
|
dataIndex: 'contrast',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ record }: any) => {
|
||||||
|
if (record.wt && record.beforeWt) {
|
||||||
|
const diff = (record.wt - record.beforeWt).toFixed(2);
|
||||||
|
const diffNum = record.wt - record.beforeWt;
|
||||||
|
return (diffNum > 0) ? `+${diff}` : diff;
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '适宜产卵鱼',
|
||||||
|
dataIndex: 'spawnFish',
|
||||||
|
width: 200,
|
||||||
|
customRender: ({ record }: any) => {
|
||||||
|
if (record.fishList && Array.isArray(record.fishList) && record.fishList.length > 0) {
|
||||||
|
return record.fishList.map(fish => fish.name).join('、');
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 初始化日期范围:7天前到当天
|
||||||
|
const initDateRange = () => {
|
||||||
|
const endDate = dayjs();
|
||||||
|
const startDate = dayjs().subtract(7, 'day');
|
||||||
|
return [startDate, endDate] as [Dayjs, Dayjs];
|
||||||
|
};
|
||||||
|
|
||||||
|
const rangePicker = ref<[Dayjs, Dayjs] | undefined>(initDateRange());
|
||||||
|
// 禁用超过当前日期的选项
|
||||||
|
const disabledDate = (current: Dayjs) => {
|
||||||
|
// 不能选择今天之后的日期
|
||||||
|
return current && current.isAfter(dayjs(), 'day');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置快捷日期范围
|
||||||
|
const setQuickRange = (days: number) => {
|
||||||
|
const endDate = dayjs();
|
||||||
|
const startDate = dayjs().subtract(days, 'day');
|
||||||
|
rangePicker.value = [startDate, endDate];
|
||||||
|
// 手动触发变更事件
|
||||||
|
handleDateChange(rangePicker.value, [
|
||||||
|
startDate.format('YYYY-MM-DD'),
|
||||||
|
endDate.format('YYYY-MM-DD')
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 日期改变时的处理方法(内容待定)
|
||||||
|
const handleDateChange = (dates: any, dateStrings: string[]) => {
|
||||||
|
console.log('日期改变:', dates, dateStrings);
|
||||||
|
getEchartsData()
|
||||||
|
gerTableData()
|
||||||
|
// TODO: 在此处添加日期改变后的业务逻辑
|
||||||
|
};
|
||||||
|
// 下拉框数据
|
||||||
|
const getSelectOption = async () => {
|
||||||
|
//
|
||||||
|
// modelStore.params.date
|
||||||
|
let params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "stcd",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": modelStore.params.stcd
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let res = await infoGetKendoListCust(params)
|
||||||
|
let data = res?.data?.data || res?.data
|
||||||
|
console.log(res)
|
||||||
|
selectOption.value = data.map(item => {
|
||||||
|
return {
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
pretemp: item.pretemp,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
selectValue.value = data.map(item => item.id)
|
||||||
|
}
|
||||||
|
//echarts 数据获取
|
||||||
|
const getEchartsData = async () => {
|
||||||
|
const params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "stcd",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": modelStore.params.stcd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "startTime",
|
||||||
|
"operator": "gte",
|
||||||
|
"dataType": "date",
|
||||||
|
"value": rangePicker.value[0].format('YYYY-MM-DD') + " 00:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "endTime",
|
||||||
|
"operator": "lte",
|
||||||
|
"dataType": "date",
|
||||||
|
"value": rangePicker.value[1].format('YYYY-MM-DD') + " 23:59:59"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sort": [
|
||||||
|
{
|
||||||
|
"field": "dt",
|
||||||
|
"dir": "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
let res = await fishGetKendoListCust(params)
|
||||||
|
console.log('ECharts原始数据:', res)
|
||||||
|
|
||||||
|
// 存储原始数据到响应式变量
|
||||||
|
const rawData = res?.data?.data || res?.data?.records || []
|
||||||
|
chartData.value = rawData
|
||||||
|
|
||||||
|
// 延迟更新图表,确保DOM已渲染
|
||||||
|
setTimeout(() => {
|
||||||
|
updateChart()
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
//table 数据获取
|
||||||
|
const gerTableData = async () => {
|
||||||
|
const filter = {
|
||||||
|
logic: 'and',
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "stcd",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": modelStore.params.stcd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "startTime",
|
||||||
|
"operator": "gte",
|
||||||
|
"dataType": "date",
|
||||||
|
"value": rangePicker.value[0].format('YYYY-MM-DD') + " 00:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "endTime",
|
||||||
|
"operator": "lte",
|
||||||
|
"dataType": "date",
|
||||||
|
"value": rangePicker.value[1].format('YYYY-MM-DD') + " 23:59:59"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
tableRef.value?.getList(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = (value: any) => {
|
||||||
|
console.log(value)
|
||||||
|
getEchartsData()
|
||||||
|
// gerTableData()
|
||||||
|
}
|
||||||
|
const customTransform = (res: any) => {
|
||||||
|
console.log('表格数据:', res);
|
||||||
|
return {
|
||||||
|
records: res?.data?.data || [],
|
||||||
|
total: res?.data?.total || 0
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 过滤和处理图表数据
|
||||||
|
const processChartData = (rawData: any[]) => {
|
||||||
|
if (!rawData || !Array.isArray(rawData)) return [];
|
||||||
|
|
||||||
|
// 过滤掉 wt 或 beforeWt 为 null 的记录
|
||||||
|
const filtered = rawData.filter(item =>
|
||||||
|
item.wt !== null && item.wt !== undefined &&
|
||||||
|
item.beforeWt !== null && item.beforeWt !== undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
// 按 dt 升序排序
|
||||||
|
return filtered.sort((a, b) =>
|
||||||
|
new Date(a.dt).getTime() - new Date(b.dt).getTime()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 计算 Y 轴最大值(向上取整到个位)
|
||||||
|
const calculateYAxisMax = (data: any[]) => {
|
||||||
|
if (!data || data.length === 0) return 10;
|
||||||
|
|
||||||
|
const allValues = [
|
||||||
|
...data.map(item => item.wt),
|
||||||
|
...data.map(item => item.beforeWt)
|
||||||
|
].filter(v => v !== null && v !== undefined);
|
||||||
|
|
||||||
|
const max = Math.max(...allValues);
|
||||||
|
return Math.ceil(max);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成随机颜色(HSL转HEX)
|
||||||
|
const generateRandomColor = () => {
|
||||||
|
const hue = Math.random() * 360; // 色相:0-360°
|
||||||
|
const saturation = 40 + Math.random() * 30; // 饱和度:40%-70%
|
||||||
|
const lightness = 45 + Math.random() * 20; // 亮度:45%-65%
|
||||||
|
|
||||||
|
// HSL转RGB
|
||||||
|
const c = (1 - Math.abs(2 * lightness / 100 - 1)) * saturation / 100;
|
||||||
|
const x = c * (1 - Math.abs((hue / 60) % 2 - 1));
|
||||||
|
const m = lightness / 100 - c / 2;
|
||||||
|
|
||||||
|
let r = 0, g = 0, b = 0;
|
||||||
|
|
||||||
|
if (hue < 60) { r = c; g = x; b = 0; }
|
||||||
|
else if (hue < 120) { r = x; g = c; b = 0; }
|
||||||
|
else if (hue < 180) { r = 0; g = c; b = x; }
|
||||||
|
else if (hue < 240) { r = 0; g = x; b = c; }
|
||||||
|
else if (hue < 300) { r = x; g = 0; b = c; }
|
||||||
|
else { r = c; g = 0; b = x; }
|
||||||
|
|
||||||
|
// RGB转HEX
|
||||||
|
const toHex = (value: number) => {
|
||||||
|
const hex = Math.round((value + m) * 255).toString(16);
|
||||||
|
return hex.length === 1 ? '0' + hex : hex;
|
||||||
|
};
|
||||||
|
|
||||||
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 计算选中鱼类的温度范围数组
|
||||||
|
const calculateTempRanges = () => {
|
||||||
|
if (!selectValue.value || selectValue.value.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 selectOption 中找到选中的鱼类
|
||||||
|
const selectedFish = selectOption.value.filter(fish =>
|
||||||
|
selectValue.value.includes(fish.value)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectedFish.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为每个鱼类生成温度范围和随机颜色
|
||||||
|
return selectedFish
|
||||||
|
.map(fish => {
|
||||||
|
if (!fish.pretemp || !Array.isArray(fish.pretemp) || fish.pretemp.length !== 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const min = parseFloat(fish.pretemp[0]);
|
||||||
|
const max = parseFloat(fish.pretemp[1]);
|
||||||
|
|
||||||
|
if (isNaN(min) || isNaN(max)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: fish.label,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
color: generateRandomColor()
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(item => item !== null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成 ECharts 配置
|
||||||
|
const getChartOption = computed(() => {
|
||||||
|
const data = processChartData(chartData.value);
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// const yAxisMax = calculateYAxisMax(data);
|
||||||
|
const tempRanges = calculateTempRanges();
|
||||||
|
const dataMax = calculateYAxisMax(data);
|
||||||
|
const tempMax = tempRanges.length > 0
|
||||||
|
? Math.max(...tempRanges.map(r => r.max))
|
||||||
|
: 0;
|
||||||
|
const yAxisMax = Math.max(dataMax, tempMax);
|
||||||
|
// 提取时间轴和数据
|
||||||
|
const xAxisData = data.map(item => dayjs(item.dt).format('YYYY-MM-DD'));
|
||||||
|
const wtData = data.map(item => item.wt);
|
||||||
|
const beforeWtData = data.map(item => item.beforeWt);
|
||||||
|
|
||||||
|
// 构建 markArea 配置(为每个鱼类生成独立的背景区域)
|
||||||
|
const markAreaConfig = tempRanges.length > 0 ? {
|
||||||
|
silent: true,
|
||||||
|
data: tempRanges.map(range => [
|
||||||
|
{
|
||||||
|
yAxis: range.min,
|
||||||
|
name: `${range.name}: ${range.min}-${range.max}°C`,
|
||||||
|
itemStyle: { color: `${range.color}26` }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
yAxis: range.max
|
||||||
|
}
|
||||||
|
])
|
||||||
|
} : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(50, 50, 50, 0.9)',
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
formatter: (params: any) => {
|
||||||
|
if (!params || params.length === 0) return '';
|
||||||
|
|
||||||
|
const date = params[0].axisValue;
|
||||||
|
let html = `<div style="font-weight:bold;margin-bottom:8px;">${date}</div>`;
|
||||||
|
|
||||||
|
params.forEach((param: any) => {
|
||||||
|
const dataIndex = param.dataIndex;
|
||||||
|
const record = data[dataIndex];
|
||||||
|
|
||||||
|
html += `
|
||||||
|
<div style="display:flex;align-items:center;margin:4px 0;">
|
||||||
|
<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:${param.color};margin-right:8px;"></span>
|
||||||
|
<span>${param.seriesName}: ${param.value}°C</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
top: 10,
|
||||||
|
left: 'center',
|
||||||
|
data: ['现在水温', '上一年同期水温'],
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 13
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 60,
|
||||||
|
right: 40,
|
||||||
|
top: 60,
|
||||||
|
bottom: 50
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: xAxisData,
|
||||||
|
boundaryGap: false,
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#000000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
interval: Math.ceil(xAxisData.length / 7),
|
||||||
|
fontSize: 12,
|
||||||
|
rotate: 0,
|
||||||
|
margin: 10
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#bfbfbf',
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '水温(°C)',
|
||||||
|
min: 0,
|
||||||
|
max: yAxisMax,
|
||||||
|
scale: false,
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#000000',
|
||||||
|
width: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: true,
|
||||||
|
length: 4
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
fontSize: 12,
|
||||||
|
formatter: '{value}'
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#bfbfbf',
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '现在水温',
|
||||||
|
type: 'line',
|
||||||
|
data: wtData,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 6,
|
||||||
|
lineStyle: { color: '#009dff', width: 2 },
|
||||||
|
itemStyle: { color: '#009dff' },
|
||||||
|
connectNulls: false,
|
||||||
|
// 移除 markArea
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '上一年同期水温',
|
||||||
|
type: 'line',
|
||||||
|
data: beforeWtData,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 6,
|
||||||
|
lineStyle: { color: '#fee588', width: 2 },
|
||||||
|
itemStyle: { color: '#fee588' },
|
||||||
|
connectNulls: false
|
||||||
|
},
|
||||||
|
// 新增辅助系列,专门承载 markArea
|
||||||
|
{
|
||||||
|
name: '温度区间背景', // 名字不会被放入 legend,所以不显示
|
||||||
|
type: 'line',
|
||||||
|
data: new Array(xAxisData.length).fill(0), // 假数据,保证坐标匹配
|
||||||
|
showSymbol: false,
|
||||||
|
symbol: 'none',
|
||||||
|
lineStyle: { opacity: 0 },
|
||||||
|
itemStyle: { opacity: 0 },
|
||||||
|
legendHoverLink: false, // 图例悬停时不联动
|
||||||
|
silent: true, // 不响应鼠标事件
|
||||||
|
markArea: markAreaConfig // 温度区间背景绑定于此
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: 'inside',
|
||||||
|
xAxisIndex: [0],
|
||||||
|
throttle: 50,
|
||||||
|
start: 0,
|
||||||
|
end: 100
|
||||||
|
}
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
saveAsImage: {
|
||||||
|
title: '导出图片',
|
||||||
|
type: 'png',
|
||||||
|
pixelRatio: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
right: 20,
|
||||||
|
top: 10
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化图表
|
||||||
|
const initChart = () => {
|
||||||
|
if (!chartRef.value) return;
|
||||||
|
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
chartInstance = echarts.init(chartRef.value);
|
||||||
|
updateChart();
|
||||||
|
|
||||||
|
// 监听窗口resize
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新图表
|
||||||
|
const updateChart = () => {
|
||||||
|
if (!chartInstance) return;
|
||||||
|
|
||||||
|
const option = getChartOption.value;
|
||||||
|
if (Object.keys(option).length > 0) {
|
||||||
|
chartInstance.setOption(option, true);
|
||||||
|
} else {
|
||||||
|
// 如果没有数据,清空图表或显示空状态
|
||||||
|
chartInstance.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理窗口resize
|
||||||
|
const handleResize = () => {
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.resize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 销毁图表
|
||||||
|
const destroyChart = () => {
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.dispose();
|
||||||
|
chartInstance = null;
|
||||||
|
}
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getSelectOption()
|
||||||
|
getEchartsData()
|
||||||
|
gerTableData()
|
||||||
|
// 初始化图表
|
||||||
|
setTimeout(() => {
|
||||||
|
initChart()
|
||||||
|
}, 200)
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
destroyChart()
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.body_one {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 600px;
|
||||||
|
|
||||||
|
.search_one {
|
||||||
|
width: 100%;
|
||||||
|
height: 32px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.search_left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.body_body {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
height: 540px;
|
||||||
|
|
||||||
|
.echarts {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-date-options {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 0;
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
border-color: #1890ff !important;
|
||||||
|
color: #1890ff !important;
|
||||||
|
background-color: #e6f7ff !important;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: #40a9ff !important;
|
||||||
|
color: #40a9ff !important;
|
||||||
|
background-color: #bae7ff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,19 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal :open="visible" :title="title" width="80vw" :footer="null" :closable="true" @cancel="handleClose"
|
||||||
:open="visible"
|
:destroyOnClose="true" class="map-modal">
|
||||||
:title="title"
|
|
||||||
width="80vw"
|
|
||||||
:footer="null"
|
|
||||||
:closable="true"
|
|
||||||
@cancel="handleClose"
|
|
||||||
:destroyOnClose="true"
|
|
||||||
class="map-modal"
|
|
||||||
>
|
|
||||||
<a-tabs :active-key="currentActiveKey" @change="onTabChange">
|
<a-tabs :active-key="currentActiveKey" @change="onTabChange">
|
||||||
<a-tab-pane v-for="tab in tabsConfig" :key="tab.key" :tab="tab.name">
|
<a-tab-pane v-for="tab in tabsConfig" :key="tab.key" :tab="tab.name">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<!-- 基本信息组件 -->
|
<!-- 基本信息组件 -->
|
||||||
<BasicInfo v-if="currentActiveKey === 'basicInfo'" :url="tab.url" />
|
<BasicInfo v-if="currentActiveKey === 'basicInfo'" :url="tab.url" />
|
||||||
|
<!-- 水温-监测数据 -->
|
||||||
|
<WaterTemperature v-if="currentActiveKey === 'WaterTemperature'" />
|
||||||
|
<!-- 水温-鱼类繁殖适宜性分析 -->
|
||||||
|
<WaterTemperatureContrast v-if="currentActiveKey === 'WaterTemperatureRep'" />
|
||||||
<!-- 地图组件 -->
|
<!-- 地图组件 -->
|
||||||
<!-- <MapView v-else-if="currentActiveKey === 'mapView'" :data="modalData" /> -->
|
<!-- <MapView v-else-if="currentActiveKey === 'mapView'" :data="modalData" /> -->
|
||||||
<!-- 周边配套组件 -->
|
<!-- 周边配套组件 -->
|
||||||
@ -28,8 +24,7 @@
|
|||||||
<a-button type="primary" :disabled="isEngConfig">
|
<a-button type="primary" :disabled="isEngConfig">
|
||||||
<i class="icon iconfont icon-topic mr-[5px]"></i>
|
<i class="icon iconfont icon-topic mr-[5px]"></i>
|
||||||
电站专题
|
电站专题
|
||||||
</a-button></a-tooltip
|
</a-button></a-tooltip>
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
@ -39,6 +34,8 @@
|
|||||||
import { ref, watch } from "vue";
|
import { ref, watch } from "vue";
|
||||||
// 导入预定义的 Tab 内容组件
|
// 导入预定义的 Tab 内容组件
|
||||||
import BasicInfo from "./components/BasicInfo.vue";
|
import BasicInfo from "./components/BasicInfo.vue";
|
||||||
|
import WaterTemperature from "./components/WaterTemperature.vue";
|
||||||
|
import WaterTemperatureContrast from "./components/WaterTemperatureContrast.vue";
|
||||||
import { useModelStore } from "@/store/modules/model";
|
import { useModelStore } from "@/store/modules/model";
|
||||||
import { handleTabs } from "./setting.config";
|
import { handleTabs } from "./setting.config";
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ const ENGTabs: Array<any> = [
|
|||||||
name: '基础信息',
|
name: '基础信息',
|
||||||
key: 'basicInfo',
|
key: 'basicInfo',
|
||||||
type: 'basic',
|
type: 'basic',
|
||||||
url: '/bbi/siteBipc/getSiteBasicInfo',
|
url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo',
|
||||||
default: true // 默认显示
|
default: true // 默认显示
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -724,7 +724,7 @@ const WTTabs: Array<any> = [
|
|||||||
name: '基础信息',
|
name: '基础信息',
|
||||||
key: 'basicInfo',
|
key: 'basicInfo',
|
||||||
type: 'basic',
|
type: 'basic',
|
||||||
url: '/bbi/siteBipc/getSiteBasicInfo'
|
url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '监测数据',
|
name: '监测数据',
|
||||||
@ -767,23 +767,24 @@ const DWTabs: Array<any> = [
|
|||||||
key: 'basicInfo',
|
key: 'basicInfo',
|
||||||
type: 'basic',
|
type: 'basic',
|
||||||
default: true, // 默认显示
|
default: true, // 默认显示
|
||||||
|
url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo'
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: '实时视频',
|
// name: '实时视频',
|
||||||
key: 'videoInfo',
|
// key: 'videoInfo',
|
||||||
type: 'video',
|
// type: 'video',
|
||||||
url: '/video/dataStcdFrame/getVideoMonitorList'
|
// url: '/video/dataStcdFrame/getVideoMonitorList'
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: '监测数据',
|
// name: '监测数据',
|
||||||
key: 'VerticalWaterTemperature',
|
// key: 'VerticalWaterTemperature',
|
||||||
type: 'VerticalWaterTemperature',
|
// type: 'VerticalWaterTemperature',
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: '叠梁门运行AI识别',
|
// name: '叠梁门运行AI识别',
|
||||||
key: 'AIYXSB',
|
// key: 'AIYXSB',
|
||||||
type: 'AIYXSB',
|
// type: 'AIYXSB',
|
||||||
}
|
// }
|
||||||
]
|
]
|
||||||
// //低温水减缓设施这是旧的
|
// //低温水减缓设施这是旧的
|
||||||
// const DWTabs2: Array<any> = [
|
// const DWTabs2: Array<any> = [
|
||||||
@ -887,7 +888,7 @@ const DEVICETABS: Array<any> = [
|
|||||||
name: '基础信息',
|
name: '基础信息',
|
||||||
key: 'basicInfo',
|
key: 'basicInfo',
|
||||||
type: 'basic',
|
type: 'basic',
|
||||||
url: '/bbi/siteBipc/getSiteBasicInfo',
|
url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo',
|
||||||
default: true, // 默认显示
|
default: true, // 默认显示
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@ -16,8 +16,7 @@
|
|||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="iconmap.show" class="title_icon">
|
<span v-if="iconmap.show" class="title_icon">
|
||||||
<a-tooltip placement="top" :title="iconmap.value"
|
<a-tooltip placement="top" :title="iconmap.value" :get-popup-container="getPopupContainer">
|
||||||
:get-popup-container="getPopupContainer">
|
|
||||||
<span :class="iconmap.icon"></span>
|
<span :class="iconmap.icon"></span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
</span>
|
||||||
@ -26,52 +25,38 @@
|
|||||||
<div v-if="select.show">
|
<div v-if="select.show">
|
||||||
<a-select v-model:value="selectValue" show-search placeholder="请选择" :size="'small'"
|
<a-select v-model:value="selectValue" show-search placeholder="请选择" :size="'small'"
|
||||||
style="width: 120px" :options="select.options" :filter-option="filterOption"
|
style="width: 120px" :options="select.options" :filter-option="filterOption"
|
||||||
@focus="handleFocus" @blur="handleBlur" @change="handleChange" ></a-select>
|
@focus="handleFocus" @blur="handleBlur" @change="handleChange"></a-select>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="shrink" class="title_shrink" @click="isExpand = !isExpand">
|
<div v-if="shrink" class="title_shrink" @click="isExpand = !isExpand">
|
||||||
<img v-if="isExpand" src="@/assets/components/arrow-up.png" alt="">
|
<img v-if="isExpand" src="@/assets/components/arrow-up.png" alt="">
|
||||||
<img v-else src="@/assets/components/arrow-down.png" alt="">
|
<img v-else src="@/assets/components/arrow-down.png" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div v-if="moreSelect.show">
|
<div v-if="moreSelect.show">
|
||||||
<a-tree-select v-model:value="moreSelectValue" show-search :size="'small'" style="width: 110px"
|
<a-tree-select v-model:value="moreSelectValue" v-model:tree-expanded-keys="treeExpandedKeys"
|
||||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto',minWidth: '180px' }" placeholder=" "
|
show-search :size="'small'" style="width: 110px"
|
||||||
:tree-data="processedMoreSelectOptions"
|
:dropdown-style="{ maxHeight: '400px', overflow: 'auto', minWidth: '180px' }" placeholder=" "
|
||||||
|
:tree-data="processedMoreSelectOptions"
|
||||||
:field-names="{ label: 'title', value: 'value', children: 'children' }"
|
:field-names="{ label: 'title', value: 'value', children: 'children' }"
|
||||||
tree-node-filter-prop="label"
|
tree-node-filter-prop="label" popup-class-name="no-wrap-tree-select" @select="handleTreeSelect"
|
||||||
:expanded-keys="expandedKeys"
|
@expand="handleTreeExpand">
|
||||||
popup-class-name="no-wrap-tree-select"
|
|
||||||
@select="handleTreeSelect"
|
|
||||||
@expand="handleTreeExpand"
|
|
||||||
@dropdownVisibleChange="handleDropdownVisibleChange">
|
|
||||||
</a-tree-select>
|
</a-tree-select>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="datetimePicker.show">
|
<div v-if="datetimePicker.show">
|
||||||
<!-- 添加 locale 属性来设置语言 -->
|
<!-- 添加 locale 属性来设置语言 -->
|
||||||
<a-date-picker
|
<a-date-picker v-model:value="datetimeValue" show-time
|
||||||
v-model:value="datetimeValue"
|
:style="{ width: datetimePicker.picker === 'year' ? '80px' : datetimePicker.picker === 'month' ? '90px' : '130px' }"
|
||||||
show-time
|
|
||||||
:style="{ width: datetimePicker.picker === 'year' ? '80px' : '130px' }"
|
|
||||||
:format="datetimePicker.format !== null ? datetimePicker.format : undefined"
|
:format="datetimePicker.format !== null ? datetimePicker.format : undefined"
|
||||||
:picker="datetimePicker.picker"
|
:picker="datetimePicker.picker" :allowClear="false" placeholder=" "
|
||||||
:allowClear="false"
|
@change="handleDateTimeChange" :size="'small'"
|
||||||
placeholder=" "
|
|
||||||
@change="handleDateTimeChange"
|
|
||||||
:size="'small'"
|
|
||||||
:disabledDate="createDisabledDateFn(datetimePicker.picker)"
|
:disabledDate="createDisabledDateFn(datetimePicker.picker)"
|
||||||
:disabledTime="disabledTimeForSinglePicker" />
|
:disabledTime="disabledTimeForSinglePicker" />
|
||||||
<!-- 修改为 locale 变量 -->
|
<!-- 修改为 locale 变量 -->
|
||||||
</div>
|
</div>
|
||||||
<div v-if="scopeDate.show" class="title_scopeDate">
|
<div v-if="scopeDate.show" class="title_scopeDate">
|
||||||
<a-range-picker
|
<a-range-picker v-model:value="scopeDateValue" :picker="scopeDate.picker" :allowClear="false"
|
||||||
v-model:value="scopeDateValue"
|
|
||||||
:picker="scopeDate.picker"
|
|
||||||
:allowClear="false"
|
|
||||||
:style="{ width: scopeDate.picker === 'year' ? '80px' : (scopeDate.picker === 'month' ? '180px' : '') }"
|
:style="{ width: scopeDate.picker === 'year' ? '80px' : (scopeDate.picker === 'month' ? '180px' : '') }"
|
||||||
:format="scopeDate.format"
|
:format="scopeDate.format" :range-separator="' 至 '" :size="'small'"
|
||||||
:range-separator="' 至 '"
|
:presets="computedScopeDatePresets" :disabledDate="createDisabledDateFn(scopeDate.picker)" />
|
||||||
:size="'small'"
|
|
||||||
:presets="computedScopeDatePresets"
|
|
||||||
:disabledDate="createDisabledDateFn(scopeDate.picker)" />
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="tabs.show" class="typeOne">
|
<div v-if="tabs.show" class="typeOne">
|
||||||
<div @click="handleTabClick('one')" :class="tabsValue == 'one' ? 'typezhong' : ''">图片</div>
|
<div @click="handleTabClick('one')" :class="tabsValue == 'one' ? 'typezhong' : ''">图片</div>
|
||||||
@ -86,7 +71,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted, watch, computed } from 'vue';
|
import { ref, onMounted, watch, computed, nextTick } from 'vue';
|
||||||
import {
|
import {
|
||||||
QuestionCircleOutlined,
|
QuestionCircleOutlined,
|
||||||
InfoCircleOutlined
|
InfoCircleOutlined
|
||||||
@ -144,7 +129,7 @@ const props = defineProps({
|
|||||||
default: () => ({
|
default: () => ({
|
||||||
show: false,
|
show: false,
|
||||||
value: '',
|
value: '',
|
||||||
icon:'iconfont icon-time',
|
icon: 'iconfont icon-time',
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
select: { // 选择框
|
select: { // 选择框
|
||||||
@ -201,8 +186,9 @@ const scopeDateValue = ref<[Dayjs, Dayjs] | undefined>(
|
|||||||
);
|
);
|
||||||
const tabsValue = ref(props.tabs.value)
|
const tabsValue = ref(props.tabs.value)
|
||||||
|
|
||||||
// 树选择器展开状态管理
|
// 树形选择器展开状态管理
|
||||||
const expandedKeys = ref<string[]>([]);
|
const treeExpandedKeys = ref<string[]>([])
|
||||||
|
const nodeMap = new Map<string, { node: any; parentKey: string | null }>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建针对不同 picker 类型的日期禁用函数
|
* 创建针对不同 picker 类型的日期禁用函数
|
||||||
@ -210,34 +196,34 @@ const expandedKeys = ref<string[]>([]);
|
|||||||
* @returns disabledDate 回调函数
|
* @returns disabledDate 回调函数
|
||||||
*/
|
*/
|
||||||
const createDisabledDateFn = (pickerType: string) => {
|
const createDisabledDateFn = (pickerType: string) => {
|
||||||
return (current: Dayjs) => {
|
return (current: Dayjs) => {
|
||||||
if (!current) return false
|
if (!current) return false
|
||||||
|
|
||||||
const now = dayjs()
|
const now = dayjs()
|
||||||
|
|
||||||
switch (pickerType) {
|
switch (pickerType) {
|
||||||
case 'year':
|
case 'year':
|
||||||
// 年份选择器:禁用 > 当前年份
|
// 年份选择器:禁用 > 当前年份
|
||||||
return current.year() > now.year()
|
return current.year() > now.year()
|
||||||
|
|
||||||
case 'month':
|
case 'month':
|
||||||
// 月份选择器:禁用 > 当前年月
|
// 月份选择器:禁用 > 当前年月
|
||||||
return current.isAfter(now, 'month')
|
return current.isAfter(now, 'month')
|
||||||
|
|
||||||
case 'quarter':
|
case 'quarter':
|
||||||
// 季度选择器:禁用 > 当前季度
|
// 季度选择器:禁用 > 当前季度
|
||||||
return current.isAfter(now, 'quarter')
|
return current.isAfter(now, 'quarter')
|
||||||
|
|
||||||
case 'week':
|
case 'week':
|
||||||
// 周选择器:禁用 > 当前周
|
// 周选择器:禁用 > 当前周
|
||||||
return current.isAfter(now, 'week')
|
return current.isAfter(now, 'week')
|
||||||
|
|
||||||
case 'date':
|
case 'date':
|
||||||
default:
|
default:
|
||||||
// 日期选择器:禁用 > 当前日期
|
// 日期选择器:禁用 > 当前日期
|
||||||
return current.isAfter(now, 'day')
|
return current.isAfter(now, 'day')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,50 +231,50 @@ const createDisabledDateFn = (pickerType: string) => {
|
|||||||
* 精确限制到当前时刻的时分秒
|
* 精确限制到当前时刻的时分秒
|
||||||
*/
|
*/
|
||||||
const disabledTimeForSinglePicker = () => {
|
const disabledTimeForSinglePicker = () => {
|
||||||
// 只在 datetimePicker 显示且为 date 类型时生效
|
// 只在 datetimePicker 显示且为 date 类型时生效
|
||||||
if (!props.datetimePicker.show || props.datetimePicker.picker !== 'date') {
|
if (!props.datetimePicker.show || props.datetimePicker.picker !== 'date') {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
|
||||||
|
|
||||||
const now = dayjs()
|
|
||||||
const selectedDate = datetimeValue.value
|
|
||||||
|
|
||||||
// 如果未选择日期,或选择的不是今天,则不限制时间
|
|
||||||
if (!selectedDate || !selectedDate.isSame(now, 'day')) {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 辅助函数:生成从 start 到 end-1 的数组
|
|
||||||
const range = (start: number, end: number) => {
|
|
||||||
const result: number[] = []
|
|
||||||
for (let i = start; i < end; i++) {
|
|
||||||
result.push(i)
|
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
const now = dayjs()
|
||||||
// 禁用当前小时之后的所有小时
|
const selectedDate = datetimeValue.value
|
||||||
disabledHours: () => {
|
|
||||||
return range(now.hour() + 1, 24)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 禁用当前分钟之后的所有分钟(仅在当前小时)
|
// 如果未选择日期,或选择的不是今天,则不限制时间
|
||||||
disabledMinutes: (selectedHour: number) => {
|
if (!selectedDate || !selectedDate.isSame(now, 'day')) {
|
||||||
if (selectedHour === now.hour()) {
|
return {}
|
||||||
return range(now.minute() + 1, 60)
|
}
|
||||||
}
|
|
||||||
return []
|
// 辅助函数:生成从 start 到 end-1 的数组
|
||||||
},
|
const range = (start: number, end: number) => {
|
||||||
|
const result: number[] = []
|
||||||
// 禁用当前秒数之后的所有秒数(仅在当前小时和分钟)
|
for (let i = start; i < end; i++) {
|
||||||
disabledSeconds: (selectedHour: number, selectedMinute: number) => {
|
result.push(i)
|
||||||
if (selectedHour === now.hour() && selectedMinute === now.minute()) {
|
}
|
||||||
return range(now.second() + 1, 60)
|
return result
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
|
return {
|
||||||
|
// 禁用当前小时之后的所有小时
|
||||||
|
disabledHours: () => {
|
||||||
|
return range(now.hour() + 1, 24)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 禁用当前分钟之后的所有分钟(仅在当前小时)
|
||||||
|
disabledMinutes: (selectedHour: number) => {
|
||||||
|
if (selectedHour === now.hour()) {
|
||||||
|
return range(now.minute() + 1, 60)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
|
||||||
|
// 禁用当前秒数之后的所有秒数(仅在当前小时和分钟)
|
||||||
|
disabledSeconds: (selectedHour: number, selectedMinute: number) => {
|
||||||
|
if (selectedHour === now.hour() && selectedMinute === now.minute()) {
|
||||||
|
return range(now.second() + 1, 60)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 定义 locale 变量
|
// // 定义 locale 变量
|
||||||
@ -326,6 +312,54 @@ const processedMoreSelectOptions = computed(() => {
|
|||||||
return processTreeData(props.moreSelect.options || []);
|
return processTreeData(props.moreSelect.options || []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建树节点映射(建立父子关系)
|
||||||
|
* @param treeData 树形数据
|
||||||
|
* @param parentKey 父节点key
|
||||||
|
*/
|
||||||
|
const buildNodeMap = (treeData: any[], parentKey: string | null = null) => {
|
||||||
|
if (!treeData || !Array.isArray(treeData)) return
|
||||||
|
|
||||||
|
treeData.forEach(node => {
|
||||||
|
// 存储当前节点及其父节点信息
|
||||||
|
nodeMap.set(node.value, {
|
||||||
|
node,
|
||||||
|
parentKey
|
||||||
|
})
|
||||||
|
|
||||||
|
// 递归处理子节点
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
buildNodeMap(node.children, node.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取目标节点的所有父节点keys
|
||||||
|
* @param targetValue 目标节点value
|
||||||
|
* @returns 父节点keys数组(从根到直接父节点)
|
||||||
|
*/
|
||||||
|
const getParentKeys = (targetValue: string): string[] => {
|
||||||
|
const parentKeys: string[] = []
|
||||||
|
let currentKey: string | null = targetValue
|
||||||
|
|
||||||
|
// 向上追溯所有父节点
|
||||||
|
while (currentKey !== null && currentKey !== undefined) {
|
||||||
|
const nodeInfo = nodeMap.get(currentKey)
|
||||||
|
|
||||||
|
// 如果节点不存在或已到达根节点,停止追溯
|
||||||
|
if (!nodeInfo || nodeInfo.parentKey === null || nodeInfo.parentKey === undefined) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将父节点插入到数组开头(保持从根到叶的顺序)
|
||||||
|
parentKeys.unshift(nodeInfo.parentKey)
|
||||||
|
currentKey = nodeInfo.parentKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return parentKeys
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算属性:根据 picker 类型动态生成快捷日期选项
|
* 计算属性:根据 picker 类型动态生成快捷日期选项
|
||||||
*/
|
*/
|
||||||
@ -469,56 +503,7 @@ const handleTreeSelect = (selectedKeys: string | string[], info: any) => {
|
|||||||
* @param keys 展开的节点键值数组
|
* @param keys 展开的节点键值数组
|
||||||
*/
|
*/
|
||||||
const handleTreeExpand = (keys: string[]) => {
|
const handleTreeExpand = (keys: string[]) => {
|
||||||
expandedKeys.value = keys;
|
// 保留事件处理函数以维持组件接口完整性
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找节点的父节点路径
|
|
||||||
* @param treeData 树数据
|
|
||||||
* @param targetValue 目标节点的值
|
|
||||||
* @returns 父节点值的数组(从根到直接父节点)
|
|
||||||
*/
|
|
||||||
const findParentKeys = (treeData: any[], targetValue: string): string[] => {
|
|
||||||
const parentKeys: string[] = [];
|
|
||||||
|
|
||||||
const search = (nodes: any[], target: string, parents: string[]): boolean => {
|
|
||||||
for (const node of nodes) {
|
|
||||||
if (node.value === target) {
|
|
||||||
// 找到目标节点,记录所有父节点
|
|
||||||
parentKeys.push(...parents);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.children && node.children.length > 0) {
|
|
||||||
// 递归搜索子节点,将当前节点加入父节点列表
|
|
||||||
if (search(node.children, target, [...parents, node.value])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
search(treeData, targetValue, []);
|
|
||||||
return parentKeys;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理下拉框显示/隐藏变化事件
|
|
||||||
* 当下拉框打开且有选中值时,自动展开该节点的所有父节点
|
|
||||||
* @param visible 下拉框是否可见
|
|
||||||
*/
|
|
||||||
const handleDropdownVisibleChange = (visible: boolean) => {
|
|
||||||
if (visible && moreSelectValue.value && processedMoreSelectOptions.value.length > 0) {
|
|
||||||
// 查找选中节点的所有父节点
|
|
||||||
const parentKeys = findParentKeys(processedMoreSelectOptions.value, moreSelectValue.value);
|
|
||||||
|
|
||||||
if (parentKeys.length > 0) {
|
|
||||||
// 合并现有的展开节点和父节点,去重
|
|
||||||
const mergedKeys = Array.from(new Set([...expandedKeys.value, ...parentKeys]));
|
|
||||||
expandedKeys.value = mergedKeys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 下拉选择框事件处理
|
// 下拉选择框事件处理
|
||||||
@ -619,19 +604,12 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 监听 moreSelectValue 的变化,移除了自动展开逻辑
|
||||||
watch(
|
watch(
|
||||||
() => props.moreSelect.value,
|
() => props.moreSelect.value,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal !== moreSelectValue.value) {
|
if (newVal !== moreSelectValue.value) {
|
||||||
moreSelectValue.value = newVal;
|
moreSelectValue.value = newVal;
|
||||||
|
|
||||||
// 如果有新值且树数据已加载,自动展开其父节点
|
|
||||||
if (newVal && processedMoreSelectOptions.value.length > 0) {
|
|
||||||
const parentKeys = findParentKeys(processedMoreSelectOptions.value, newVal);
|
|
||||||
if (parentKeys.length > 0) {
|
|
||||||
expandedKeys.value = Array.from(new Set([...expandedKeys.value, ...parentKeys]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -676,18 +654,45 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 监听 moreSelectValue 变化(包括默认值和用户选择)
|
||||||
|
watch(() => moreSelectValue.value, (newValue) => {
|
||||||
|
console.log('moreSelectValue 变化:', newValue)
|
||||||
|
|
||||||
|
if (newValue && nodeMap.size > 0) {
|
||||||
|
// 只有当 nodeMap 已构建时才执行
|
||||||
|
const parentKeys = getParentKeys(newValue as string)
|
||||||
|
treeExpandedKeys.value = parentKeys
|
||||||
|
console.log('自动展开父节点:', parentKeys)
|
||||||
|
} else {
|
||||||
|
treeExpandedKeys.value = []
|
||||||
|
}
|
||||||
|
}, { immediate: true }) // immediate: true 确保默认值也能触发
|
||||||
|
|
||||||
|
// 监听树数据变化,重新构建映射
|
||||||
|
watch(() => processedMoreSelectOptions.value, (newData) => {
|
||||||
|
console.log('树数据变化,重新构建映射')
|
||||||
|
|
||||||
|
if (newData && newData.length > 0) {
|
||||||
|
// 清空旧映射
|
||||||
|
nodeMap.clear()
|
||||||
|
// 重新构建映射
|
||||||
|
buildNodeMap(newData)
|
||||||
|
|
||||||
|
// 数据加载完成后,如果已有默认值,重新触发一次
|
||||||
|
if (moreSelectValue.value) {
|
||||||
|
nextTick(() => {
|
||||||
|
const parentKeys = getParentKeys(moreSelectValue.value as string)
|
||||||
|
treeExpandedKeys.value = parentKeys
|
||||||
|
console.log('数据加载后自动展开父节点:', parentKeys)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
// 页面加载时执行的逻辑
|
// 页面加载时执行的逻辑
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 初始化时发送一次默认值
|
// 初始化时发送一次默认值
|
||||||
emitAllValues();
|
emitAllValues();
|
||||||
|
|
||||||
// 如果 tree-select 有默认值,预先展开其父节点
|
|
||||||
if (moreSelectValue.value && processedMoreSelectOptions.value.length > 0) {
|
|
||||||
const parentKeys = findParentKeys(processedMoreSelectOptions.value, moreSelectValue.value);
|
|
||||||
if (parentKeys.length > 0) {
|
|
||||||
expandedKeys.value = parentKeys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
270
frontend/src/components/carouselIntroduce/ArtsDetail.vue
Normal file
270
frontend/src/components/carouselIntroduce/ArtsDetail.vue
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
<!-- ArtsDetail.vue -->
|
||||||
|
<template>
|
||||||
|
<div class="arts-detail">
|
||||||
|
<div class="card-container">
|
||||||
|
<div class="card_left">
|
||||||
|
<div class="card_img">
|
||||||
|
<div class="carousel-wrapper">
|
||||||
|
<div class="carousel-inner">
|
||||||
|
<div class="carousel-track" :style="trackStyle">
|
||||||
|
<div v-for="(item, index) in originalMediaData" :key="index" class="carousel-item">
|
||||||
|
<img :src="item.image" :alt="item.title" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card_right">
|
||||||
|
<div class="card_text_title"></div>
|
||||||
|
<div class="card_text_content">
|
||||||
|
{{ currentDescription }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="width: 100%;display: flex;justify-content: center;">
|
||||||
|
<div class="card_button">
|
||||||
|
<LeftOutlined @click="prevSlide" />
|
||||||
|
<div class="pagination-dots">
|
||||||
|
<span v-for="(item, index) in originalMediaData" :key="index" class="dot-item"
|
||||||
|
:class="{ 'active': currentIndex === index }" @click="jumpToSlide(index)" />
|
||||||
|
</div>
|
||||||
|
<RightOutlined @click="nextSlide" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed, onMounted, watch } from 'vue';
|
||||||
|
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'ArtsDetail'
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
dataSource: Array<{
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
image: string;
|
||||||
|
}>;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
interface MediaItem {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
image: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalMediaData = ref<MediaItem[]>([]);
|
||||||
|
const currentIndex = ref(0);
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
const initOriginalData = () => {
|
||||||
|
if (props.dataSource && props.dataSource.length > 0) {
|
||||||
|
originalMediaData.value = props.dataSource.map(item => ({
|
||||||
|
title: item.title,
|
||||||
|
description: item.description,
|
||||||
|
image: item.image
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 计算轨道样式 - 完全按照 React 版本的逻辑
|
||||||
|
const trackStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
transform: `translateX(calc((68.8px - 48vw) * ${currentIndex.value}))`
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 切换到下一张
|
||||||
|
const nextSlide = () => {
|
||||||
|
if (currentIndex.value < originalMediaData.value.length - 1) {
|
||||||
|
currentIndex.value++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换到上一张
|
||||||
|
const prevSlide = () => {
|
||||||
|
if (currentIndex.value > 0) {
|
||||||
|
currentIndex.value--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 跳转到指定页面
|
||||||
|
const jumpToSlide = (targetIndex: number) => {
|
||||||
|
currentIndex.value = targetIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 计算当前显示的描述文字
|
||||||
|
const currentDescription = computed(() => {
|
||||||
|
return originalMediaData.value[currentIndex.value]?.description || '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面加载时执行
|
||||||
|
onMounted(() => {
|
||||||
|
initOriginalData();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听 dataSource 变化
|
||||||
|
watch(
|
||||||
|
() => props.dataSource,
|
||||||
|
(newData) => {
|
||||||
|
if (newData && newData.length > 0) {
|
||||||
|
currentIndex.value = 0;
|
||||||
|
initOriginalData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.arts-detail {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.card-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_left {
|
||||||
|
// flex: 6;
|
||||||
|
width: 60%;
|
||||||
|
height: 630px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.card_img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.carousel-inner {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-track {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
|
||||||
|
.carousel-item {
|
||||||
|
width: calc(48vw - 80.8px);
|
||||||
|
flex: 0 0 calc(48vw - 80.8px);
|
||||||
|
height: 100%;
|
||||||
|
margin-right: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
border: none;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_right {
|
||||||
|
// flex: 4;
|
||||||
|
width: 40%;
|
||||||
|
height: 630px;
|
||||||
|
padding-left: 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.card_text_title {
|
||||||
|
width: 6px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: rgb(108, 164, 247);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_text_content {
|
||||||
|
width: 100%;
|
||||||
|
height: 96%;
|
||||||
|
padding: 0px 16px 16px 0px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
line-height: 1.5;
|
||||||
|
overflow: auto;
|
||||||
|
font-size: 20px;
|
||||||
|
text-indent: 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_button {
|
||||||
|
display: flex;
|
||||||
|
// justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.pagination-dots {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.dot-item {
|
||||||
|
display: inline-block;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #adaaaa;
|
||||||
|
margin: 0 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #8a8a8a;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #5E9BFE;
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.anticon) {
|
||||||
|
font-size: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #6c8cf7;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover:not([disabled]) {
|
||||||
|
color: #4a6fd4;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
color: #d9d9d9;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -21,7 +21,9 @@ import type { ECharts } from 'echarts';
|
|||||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||||
import { getChuiXiangShuiWenTreeStcd, getCxswList } from "@/api/sw";
|
import { getChuiXiangShuiWenTreeStcd, getCxswList } from "@/api/sw";
|
||||||
|
import { useModelStore } from "@/store/modules/model";
|
||||||
|
|
||||||
|
const modelStore = useModelStore();
|
||||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||||
const baseid = ref('');
|
const baseid = ref('');
|
||||||
|
|
||||||
@ -109,11 +111,26 @@ function arrMin(arr: number[]): number {
|
|||||||
/**
|
/**
|
||||||
* 将 API 返回的 aggregates 数据转换为图表数据格式
|
* 将 API 返回的 aggregates 数据转换为图表数据格式
|
||||||
*/
|
*/
|
||||||
function transformAggregatesToChartData(aggregates: Record<string, any[]>): Array<{
|
function transformAggregatesToChartData(
|
||||||
|
aggregates: Record<string, any[]>,
|
||||||
|
stcd: string,
|
||||||
|
stnm: string
|
||||||
|
): Array<{
|
||||||
name: string;
|
name: string;
|
||||||
dataXy: Array<[number, number]>;
|
dataXy: Array<{
|
||||||
|
value: [number, number];
|
||||||
|
stcd: string;
|
||||||
|
stnm: string;
|
||||||
|
}>;
|
||||||
}> {
|
}> {
|
||||||
const result: Array<{ name: string; dataXy: Array<[number, number]> }> = [];
|
const result: Array<{
|
||||||
|
name: string;
|
||||||
|
dataXy: Array<{
|
||||||
|
value: [number, number];
|
||||||
|
stcd: string;
|
||||||
|
stnm: string;
|
||||||
|
}>;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
for (let month = 1; month <= 12; month++) {
|
for (let month = 1; month <= 12; month++) {
|
||||||
const key = month.toString();
|
const key = month.toString();
|
||||||
@ -128,11 +145,19 @@ function transformAggregatesToChartData(aggregates: Record<string, any[]>): Arra
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 转换数据格式:{ wthg, vwt } → [vwt, wthg]
|
// ✅ 转换数据格式:将数据点包装为对象,包含元信息
|
||||||
const dataXy: Array<[number, number]> = monthData.map((item: any) => [
|
const dataXy: Array<{
|
||||||
parseFloat(item.vwt), // 温度
|
value: [number, number];
|
||||||
parseInt(item.wthg) // 深度/高程
|
stcd: string;
|
||||||
]);
|
stnm: string;
|
||||||
|
}> = monthData.map((item: any) => ({
|
||||||
|
value: [
|
||||||
|
parseFloat(item.vwt), // 温度
|
||||||
|
parseInt(item.wthg) // 深度/高程
|
||||||
|
] as [number, number], // ✅ 显式声明为元组类型
|
||||||
|
stcd: stcd, // 站点编码
|
||||||
|
stnm: stnm // 站点名称
|
||||||
|
}));
|
||||||
|
|
||||||
result.push({
|
result.push({
|
||||||
name: `${month}月`,
|
name: `${month}月`,
|
||||||
@ -336,8 +361,15 @@ const selectOptions = async () => {
|
|||||||
const chartRef = ref<HTMLElement | null>(null);
|
const chartRef = ref<HTMLElement | null>(null);
|
||||||
let chartInstance: ECharts | null = null;
|
let chartInstance: ECharts | null = null;
|
||||||
|
|
||||||
// 图表数据
|
// 图表数据(对象型格式,包含站点元信息)
|
||||||
const chartData = ref<Array<{ name: string; dataXy: Array<[number, number]> }>>([]);
|
const chartData = ref<Array<{
|
||||||
|
name: string;
|
||||||
|
dataXy: Array<{
|
||||||
|
value: [number, number];
|
||||||
|
stcd: string;
|
||||||
|
stnm: string;
|
||||||
|
}>;
|
||||||
|
}>>([]);
|
||||||
|
|
||||||
// Y轴类型(1=水深,2=高程)
|
// Y轴类型(1=水深,2=高程)
|
||||||
const type = ref(1);
|
const type = ref(1);
|
||||||
@ -386,8 +418,18 @@ const fetchChartData = async (stcd: string, year: string | number) => {
|
|||||||
const aggregates = res?.data?.aggregates;
|
const aggregates = res?.data?.aggregates;
|
||||||
|
|
||||||
if (aggregates) {
|
if (aggregates) {
|
||||||
// 转换数据
|
// ✅ 获取当前选中的站点名称
|
||||||
chartData.value = transformAggregatesToChartData(aggregates);
|
let currentStnm = '';
|
||||||
|
select.value.options.forEach((station: any) => {
|
||||||
|
station.children?.forEach((child: any) => {
|
||||||
|
if (child.value === stcd) {
|
||||||
|
currentStnm = child.title;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ✅ 转换数据,传递 stcd 和 stnm
|
||||||
|
chartData.value = transformAggregatesToChartData(aggregates, stcd, currentStnm);
|
||||||
|
|
||||||
// ✅ 修改:传入固定值 12,而非 chartData.value.length
|
// ✅ 修改:传入固定值 12,而非 chartData.value.length
|
||||||
const { colors: newColors, selected: newSelected } = generateColorsAndVisibility(
|
const { colors: newColors, selected: newSelected } = generateColorsAndVisibility(
|
||||||
@ -433,6 +475,30 @@ const initChart = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
chartInstance = echarts.init(chartRef.value);
|
chartInstance = echarts.init(chartRef.value);
|
||||||
|
|
||||||
|
// 绑定点击事件(具体处理逻辑由用户自行实现)
|
||||||
|
chartInstance.on('click', (params: any) => {
|
||||||
|
console.log('图表数据点被点击:', params);
|
||||||
|
|
||||||
|
// ✅ 直接从 params.data 中获取 stcd 和 stnm
|
||||||
|
const stcd = params.data?.stcd;
|
||||||
|
const stnm = params.data?.stnm;
|
||||||
|
const temperature = params.data?.value?.[0];
|
||||||
|
const depth = params.data?.value?.[1];
|
||||||
|
|
||||||
|
console.log('站点编码:', stcd);
|
||||||
|
console.log('站点名称:', stnm);
|
||||||
|
console.log('水温:', temperature);
|
||||||
|
console.log('深度:', depth);
|
||||||
|
modelStore.modalVisible = true;
|
||||||
|
modelStore.params.sttp = "wt_point";
|
||||||
|
modelStore.title = stnm + "详情信息";
|
||||||
|
// modelStore.isBasicEdit = true;
|
||||||
|
modelStore.params.stcd = stcd;
|
||||||
|
|
||||||
|
// TODO: 在此处添加您的业务逻辑
|
||||||
|
});
|
||||||
|
|
||||||
updateChart();
|
updateChart();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -446,14 +512,15 @@ const updateChart = () => {
|
|||||||
|
|
||||||
chartData.value.forEach((item) => {
|
chartData.value.forEach((item) => {
|
||||||
if (item.dataXy.length > 0) {
|
if (item.dataXy.length > 0) {
|
||||||
xData.push(item.dataXy[0][0]);
|
// ✅ 从对象中提取 value[0](温度值)
|
||||||
|
xData.push(item.dataXy[0].value[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
legend.push(item.name);
|
legend.push(item.name);
|
||||||
|
|
||||||
yData.push({
|
yData.push({
|
||||||
name: item.name,
|
name: item.name,
|
||||||
data: item.dataXy,
|
data: item.dataXy, // ✅ 直接使用对象数组
|
||||||
type: 'line',
|
type: 'line',
|
||||||
smooth: true,
|
smooth: true,
|
||||||
connectNulls: true,
|
connectNulls: true,
|
||||||
@ -483,8 +550,9 @@ const updateChart = () => {
|
|||||||
formatter: (params: any) => {
|
formatter: (params: any) => {
|
||||||
if (!params || !params.seriesName) return '';
|
if (!params || !params.seriesName) return '';
|
||||||
|
|
||||||
const temperature = params.data[0];
|
// ✅ 从对象格式中获取数据
|
||||||
const depth = params.data[1];
|
const temperature = params.data?.value?.[0];
|
||||||
|
const depth = params.data?.value?.[1];
|
||||||
|
|
||||||
return `<span>${params.seriesName}</span><br />
|
return `<span>${params.seriesName}</span><br />
|
||||||
<span>水温(℃):${temperature}</span><br />
|
<span>水温(℃):${temperature}</span><br />
|
||||||
@ -649,7 +717,7 @@ const handlePanelChange1 = (data: any) => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 252px !important;
|
min-height: 252px !important;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|||||||
378
frontend/src/modules/churukushuiwenMod/churukushuiwen.vue
Normal file
378
frontend/src/modules/churukushuiwenMod/churukushuiwen.vue
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
<template>
|
||||||
|
<div class="body_fu">
|
||||||
|
<!-- 左侧 ECharts 图表 -->
|
||||||
|
<a-spin :spinning="loading" tip="加载中...">
|
||||||
|
<div class="echarts">
|
||||||
|
<div ref="chartRef" class="echarts"></div>
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
|
||||||
|
<!-- 右侧 BasicTable 表格 -->
|
||||||
|
<BasicTable ref="tableRef" :scrollY="460" :columns="columns" :list-url="inOutOneDetails" :search-params="{ sort: sort }"
|
||||||
|
:transform-data="customTransform" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { inOutOneDetails } from '@/api/sw';
|
||||||
|
import BasicTable from '@/components/BasicTable/index.vue';
|
||||||
|
|
||||||
|
// ==================== Props 定义 ====================
|
||||||
|
const props = defineProps<{
|
||||||
|
tm: [string, string]; // 时间范围 [startDate, endDate]
|
||||||
|
stcd: string; // 站点编码
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// ==================== DOM 引用与状态 ====================
|
||||||
|
const chartRef = ref<HTMLDivElement>();
|
||||||
|
let chartInstance: echarts.ECharts | null = null;
|
||||||
|
const tableRef = ref<any>(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
let sort = [
|
||||||
|
{
|
||||||
|
field: "tm",
|
||||||
|
dir: "asc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// ==================== 表格配置 ===================
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '监测时间点',
|
||||||
|
dataIndex: 'dt',
|
||||||
|
width: 180,
|
||||||
|
customRender: ({ text }: any) => text ? dayjs(text).format('YYYY-MM-DD HH:mm:ss') : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '入库水温(℃)',
|
||||||
|
dataIndex: 'iwtValue',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ text }: any) => {
|
||||||
|
const val = Number(text);
|
||||||
|
return isNaN(val) ? '-' : val.toFixed(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '出库水温(℃)',
|
||||||
|
dataIndex: 'dwtValue',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ text }: any) => {
|
||||||
|
const val = Number(text);
|
||||||
|
return isNaN(val) ? '-' : val.toFixed(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const customTransform = (res: any) => {
|
||||||
|
console.log('图表数据:', res);
|
||||||
|
return {
|
||||||
|
records: res?.data?.data || [],
|
||||||
|
total: res?.data?.total || 0
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== 辅助函数 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算Y轴显示范围
|
||||||
|
* 基于数据最小值和最大值,上下各扩展0.2的缓冲空间
|
||||||
|
* @param data - 水温数据数组(可能包含null值)
|
||||||
|
* @returns Y轴的最小值和最大值对象
|
||||||
|
*/
|
||||||
|
function calculateYAxisRange(data: (number | null)[]) {
|
||||||
|
// 过滤出有效数值
|
||||||
|
const validValues = data.filter(v => v !== null) as number[]
|
||||||
|
if (validValues.length === 0) return { min: 0, max: 10 } // 无数据时返回默认范围
|
||||||
|
|
||||||
|
const min = Math.min(...validValues)
|
||||||
|
const max = Math.max(...validValues)
|
||||||
|
|
||||||
|
// 上下各扩展0.2,避免曲线贴边
|
||||||
|
return {
|
||||||
|
min: Number((min - 0.1).toFixed(1)), // 最小值减0.2
|
||||||
|
max: Number((max + 0.1).toFixed(1)) // 最大值加0.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算X轴刻度间隔
|
||||||
|
* 确保最多显示4个刻度标签,避免标签重叠
|
||||||
|
* @param dateCount - 日期总数
|
||||||
|
* @returns X轴刻度间隔值(interval属性)
|
||||||
|
*/
|
||||||
|
function calculateXAxisInterval(dateCount: number): number {
|
||||||
|
if (dateCount <= 4) return 0 // 数据点≤4时,显示所有刻度
|
||||||
|
return Math.ceil(dateCount / 4) - 1 // 动态计算间隔,保证最多4个刻度
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 图表初始化与更新 ====================
|
||||||
|
const initChart = () => {
|
||||||
|
if (!chartRef.value) return;
|
||||||
|
|
||||||
|
const rect = chartRef.value.getBoundingClientRect();
|
||||||
|
if (rect.width === 0 || rect.height === 0) {
|
||||||
|
setTimeout(() => initChart(), 50);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chartInstance = echarts.init(chartRef.value);
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateChart = (data: any[]) => {
|
||||||
|
if (!chartInstance) return;
|
||||||
|
|
||||||
|
const xData: string[] = [];
|
||||||
|
const inData: (number | null)[] = [];
|
||||||
|
const outData: (number | null)[] = [];
|
||||||
|
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
xData.push(item.dt);
|
||||||
|
inData.push(item.iwtValue !== null && item.iwtValue !== undefined ? Number(item.iwtValue) : null);
|
||||||
|
outData.push(item.dwtValue !== null && item.dwtValue !== undefined ? Number(item.dwtValue) : null);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 动态计算坐标轴范围
|
||||||
|
const xAxisInterval = calculateXAxisInterval(xData.length);
|
||||||
|
const { min: yAxisMin, max: yAxisMaxValue } = calculateYAxisRange([...inData, ...outData]);
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
// 提示框配置
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(50, 50, 50, 0.9)',
|
||||||
|
borderColor: 'transparent',
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line',
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(91, 143, 249, 0.15)',
|
||||||
|
width: 30,
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
formatter: function (params: any) {
|
||||||
|
if (!params || params.length === 0) return '';
|
||||||
|
const date = params[0].name;
|
||||||
|
let result = `<div style="font-weight: bold; margin-bottom: 8px; font-size: 14px;">${date}</div>`;
|
||||||
|
params.forEach((item: any) => {
|
||||||
|
const value = item.value !== null && item.value !== undefined ? `${item.value}°C` : '-';
|
||||||
|
result += `<div style="display: flex; align-items: center; gap: 6px; margin: 4px 0; font-size: 14px;">
|
||||||
|
<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${item.color};"></span>
|
||||||
|
<span>${item.seriesName}</span>
|
||||||
|
<span style="font-weight: bold; margin-left: auto;">${value}</span>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// // 标题配置
|
||||||
|
// title: {
|
||||||
|
// text: '水温(°C)',
|
||||||
|
// left: 17,
|
||||||
|
// top: 13,
|
||||||
|
// textStyle: {
|
||||||
|
// fontSize: 13,
|
||||||
|
// color: '#000000',
|
||||||
|
// fontWeight: 'normal'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
legend: {
|
||||||
|
data: ['入库水温', '出库水温'],
|
||||||
|
top: 0
|
||||||
|
},
|
||||||
|
|
||||||
|
grid: {
|
||||||
|
left: '7%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: true,
|
||||||
|
data: xData,
|
||||||
|
interval: xAxisInterval,
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#000000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#000000',
|
||||||
|
fontSize: 10,
|
||||||
|
margin: 5
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#bfbfbf',
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 数据缩放配置
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: 'inside',
|
||||||
|
start: 0,
|
||||||
|
end: 100,
|
||||||
|
minValueSpan: 2,
|
||||||
|
zoomOnMouseWheel: true,
|
||||||
|
moveOnMouseMove: true,
|
||||||
|
moveOnMouseWheel: false,
|
||||||
|
zoomLock: false,
|
||||||
|
throttle: 50
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '水温(℃)',
|
||||||
|
min: yAxisMin,
|
||||||
|
max: yAxisMaxValue,
|
||||||
|
scale: true,
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#000000',
|
||||||
|
width: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#000000',
|
||||||
|
width: 1
|
||||||
|
},
|
||||||
|
length: 4
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#000000',
|
||||||
|
fontSize: 10,
|
||||||
|
formatter: '{value}'
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#bfbfbf',
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '入库水温',
|
||||||
|
data: inData,
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
connectNulls: true,
|
||||||
|
color: '#5470c6'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '出库水温',
|
||||||
|
data: outData,
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
connectNulls: true,
|
||||||
|
color: '#91cc75'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
chartInstance.setOption(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
chartInstance?.resize();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== 数据获取逻辑 ====================
|
||||||
|
const fetchData = async () => {
|
||||||
|
if (!props.stcd || !props.tm || !props.tm[0]) return;
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
// 构建过滤条件
|
||||||
|
console.log('图表点击事件:', props.tm);
|
||||||
|
const startTime = dayjs(props.tm[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
const endTime = dayjs(props.tm[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
logic: 'and',
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
logic: "or",
|
||||||
|
filters: [
|
||||||
|
{ field: "engDwtCode", operator: "eq", value: props.stcd },
|
||||||
|
{ field: "engIwtCode", operator: "eq", value: props.stcd }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ field: "tm", operator: 'gte', dataType: "date", value: startTime },
|
||||||
|
{ field: "tm", operator: 'lte', dataType: "date", value: endTime }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
tableRef.value?.getList(filter);
|
||||||
|
// 调用接口获取图表数据
|
||||||
|
const res = await inOutOneDetails({ filter, sort: [{ field: "tm", dir: "asc" }] });
|
||||||
|
let dataOne = res?.data?.data || res?.data;
|
||||||
|
if (dataOne) {
|
||||||
|
updateChart(dataOne);
|
||||||
|
// 刷新表格数据
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取出入库水温数据失败:', error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== 生命周期与监听 ====================
|
||||||
|
onMounted(() => {
|
||||||
|
initChart();
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
chartInstance?.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听 props 变化,重新获取数据
|
||||||
|
watch(() => [props.tm, props.stcd], () => {
|
||||||
|
fetchData();
|
||||||
|
}, { deep: true });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.body_fu {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
height: 570px;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.echarts {
|
||||||
|
min-width: 541px;
|
||||||
|
height: 500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -14,6 +14,15 @@
|
|||||||
<a-empty />
|
<a-empty />
|
||||||
</div>
|
</div>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
|
|
||||||
|
<!-- 数据点详情弹框 -->
|
||||||
|
<a-modal v-model:open="modalVisible" :title="`${stationName}出入库水温`" :width="1536" :footer="null"
|
||||||
|
@cancel="handleModalClose">
|
||||||
|
<!-- 弹框内容区域 - 待完善 -->
|
||||||
|
<div class="modal-content">
|
||||||
|
<churukushuiwen v-if="clickDataInfo" :tm="[clickDataInfo.date, clickDataInfo.date]" :stcd="paramsOne.value" />
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
</SidePanelItem>
|
</SidePanelItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -24,7 +33,7 @@ import dayjs from 'dayjs';
|
|||||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
import { getVmsstbprpt, inOutOneGetKendoListCust } from '@/api/sw';
|
import { getVmsstbprpt, inOutOneGetKendoListCust } from '@/api/sw';
|
||||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||||
|
import churukushuiwen from './churukushuiwen.vue'
|
||||||
// ==================== 组件基础配置 ====================
|
// ==================== 组件基础配置 ====================
|
||||||
// 定义组件名(便于调试和递归)
|
// 定义组件名(便于调试和递归)
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@ -64,6 +73,9 @@ const scopeDate = ref({
|
|||||||
|
|
||||||
// ==================== 业务变量 ====================
|
// ==================== 业务变量 ====================
|
||||||
const baseid = ref(''); // 当前选中的基地ID
|
const baseid = ref(''); // 当前选中的基地ID
|
||||||
|
const modalVisible = ref(false); // 弹框显示状态
|
||||||
|
const clickDataInfo = ref<any>(null); // 点击的数据点信息
|
||||||
|
const stationName = ref(''); // 站点名称
|
||||||
|
|
||||||
// ==================== 基地列表数据(硬编码) ====================
|
// ==================== 基地列表数据(硬编码) ====================
|
||||||
const jiDiList: any = ref([
|
const jiDiList: any = ref([
|
||||||
@ -201,7 +213,7 @@ function calculateYAxisRange(data: (number | null)[]) {
|
|||||||
// 上下各扩展0.2,避免曲线贴边
|
// 上下各扩展0.2,避免曲线贴边
|
||||||
return {
|
return {
|
||||||
min: Number((min - 0.2).toFixed(1)), // 最小值减0.2
|
min: Number((min - 0.2).toFixed(1)), // 最小值减0.2
|
||||||
max: Number((max + 0.2).toFixed(1)) // 最大值加0.2
|
max: Number((max + 0.1).toFixed(1)) // 最大值加0.2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +227,7 @@ function calculateXAxisInterval(dateCount: number): number {
|
|||||||
if (dateCount <= 4) return 0 // 数据点≤4时,显示所有刻度
|
if (dateCount <= 4) return 0 // 数据点≤4时,显示所有刻度
|
||||||
return Math.ceil(dateCount / 4) - 1 // 动态计算间隔,保证最多4个刻度
|
return Math.ceil(dateCount / 4) - 1 // 动态计算间隔,保证最多4个刻度
|
||||||
}
|
}
|
||||||
const paramsOne = ref({
|
const paramsOne:any = ref({
|
||||||
value: '',
|
value: '',
|
||||||
tm: [currentMonth, currentMonth]
|
tm: [currentMonth, currentMonth]
|
||||||
})
|
})
|
||||||
@ -528,6 +540,11 @@ function updateChart(dates: string[], iwtData: (number | null)[], dwtData: (numb
|
|||||||
|
|
||||||
// 应用配置到图表实例
|
// 应用配置到图表实例
|
||||||
chartInstance.setOption(option, true); // true表示完全替换配置
|
chartInstance.setOption(option, true); // true表示完全替换配置
|
||||||
|
|
||||||
|
// 绑定点击事件监听器
|
||||||
|
chartInstance.off('click'); // 先移除旧的事件监听
|
||||||
|
chartInstance.on('click', handleChartClick);
|
||||||
|
|
||||||
console.log('图表更新成功')
|
console.log('图表更新成功')
|
||||||
|
|
||||||
// 强制重绘,确保图表尺寸正确适配容器
|
// 强制重绘,确保图表尺寸正确适配容器
|
||||||
@ -582,6 +599,45 @@ const handleResize = () => {
|
|||||||
|
|
||||||
// ==================== 事件处理函数 ====================
|
// ==================== 事件处理函数 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图表数据点点击事件处理
|
||||||
|
* @param params - ECharts点击事件参数
|
||||||
|
*/
|
||||||
|
const handleChartClick = (params: any) => {
|
||||||
|
console.log('图表点击事件:', params);
|
||||||
|
|
||||||
|
// 只处理数据系列的点击
|
||||||
|
if (params.componentType === 'series') {
|
||||||
|
const { seriesName, name, value, dataIndex } = params;
|
||||||
|
|
||||||
|
// 保存点击数据信息
|
||||||
|
clickDataInfo.value = {
|
||||||
|
date: name, // 日期
|
||||||
|
temperature: value, // 水温值
|
||||||
|
type: seriesName, // 类型:入库水温/出库水温
|
||||||
|
dataIndex: dataIndex // 数据索引
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取站点名称(从下拉选项中查找)
|
||||||
|
// console.log('站点名称:', select.value.options, paramsOne.value.value);
|
||||||
|
const selectedStation = select.value.options
|
||||||
|
.flatMap((base: any) => base.children || [])
|
||||||
|
.find((station: any) => station.stcd === paramsOne.value.value);
|
||||||
|
stationName.value = selectedStation?.title || '未知站点';
|
||||||
|
|
||||||
|
// 打开弹框
|
||||||
|
modalVisible.value = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹框关闭处理
|
||||||
|
*/
|
||||||
|
const handleModalClose = () => {
|
||||||
|
modalVisible.value = false;
|
||||||
|
clickDataInfo.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SidePanelItem面板变化回调
|
* SidePanelItem面板变化回调
|
||||||
* 处理下拉框和日期选择器的值变化
|
* 处理下拉框和日期选择器的值变化
|
||||||
@ -725,12 +781,19 @@ watch(
|
|||||||
.chart-container {
|
.chart-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 252px;
|
height: 252px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
/* 固定高度252px */
|
/* 固定高度252px */
|
||||||
}
|
}
|
||||||
:deep(.ant-spin-nested-loading ){
|
|
||||||
height: 252px !important;
|
:deep(.ant-spin-nested-loading) {
|
||||||
|
height: 252px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 弹框内容样式 */
|
||||||
|
.modal-content {
|
||||||
|
min-height: 100px;
|
||||||
|
padding: 16px 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -0,0 +1,525 @@
|
|||||||
|
<template>
|
||||||
|
<div class="facility-detail-container">
|
||||||
|
<!-- 搜索区域 -->
|
||||||
|
<a-form ref="formRef" :model="formState" layout="inline" class="search-form">
|
||||||
|
<a-form-item label="所属基地" name="dataDimensionVal">
|
||||||
|
<a-select v-model:value="formState.dataDimensionVal" placeholder="请选择" style="width: 200px"
|
||||||
|
@change="handleBaseChange">
|
||||||
|
<a-select-option v-for="item in baseList" :key="item.baseid" :value="item.baseid">
|
||||||
|
{{ item.basename }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="接入状态" name="hydrodtin">
|
||||||
|
<a-select v-model:value="formState.hydrodtin" placeholder="请选择" style="width: 200px">
|
||||||
|
<a-select-option value="">全部</a-select-option>
|
||||||
|
<a-select-option value="0">未接入</a-select-option>
|
||||||
|
<a-select-option value="1">已接入</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="建设状态" name="bldstt">
|
||||||
|
<a-select v-model:value="formState.bldstt" placeholder="请选择" style="width: 200px"
|
||||||
|
:loading="buildStateLoading">
|
||||||
|
<a-select-option v-for="item in buildStateList" :key="item.value" :value="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="设施名称" name="stnm">
|
||||||
|
<a-input v-model:value="formState.stnm" placeholder="请输入设施名称" style="width: 200px" allow-clear />
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="handleSearch">查询</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
|
||||||
|
<!-- Tab标签页 -->
|
||||||
|
<a-tabs v-model:activeKey="activeTab" class="facility-tabs" @change="handleTabChange">
|
||||||
|
<a-tab-pane v-for="item in facilityStats" :key="item.key" :tab="`${item.name}(${item.count})`">
|
||||||
|
<!-- 表格区域 -->
|
||||||
|
<BasicTable style="overflow: visible;" v-show="activeTab === item.key"
|
||||||
|
:ref="(el) => setTableRef(el, item.key)" :scrollY="360" :columns="columns"
|
||||||
|
:list-url="vmsstbprptGetKendoList" :search-params="{ sort: sort }"
|
||||||
|
:transform-data="customTransform">
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<!-- 名称列 - 可点击 -->
|
||||||
|
<template v-if="column.key === 'stnm'">
|
||||||
|
<a @click="handleViewDetail(record, 'DW')" class="text-link">
|
||||||
|
{{ record.stnm }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<!-- 关联电站列 - 可点击 -->
|
||||||
|
<template v-if="column.key === 'ennm'">
|
||||||
|
<a @click="handleViewDetail(record, 'ENG')" class="text-link">
|
||||||
|
{{ record.ennm || '-' }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</BasicTable>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import BasicTable from '@/components/BasicTable/index.vue'
|
||||||
|
// import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'
|
||||||
|
import { dictgetRemoteDictValue, dwInfoGetKendoListCust, vmsstbprptGetKendoList } from '@/api/sw'
|
||||||
|
import { useModelStore } from "@/store/modules/model";
|
||||||
|
|
||||||
|
const modelStore = useModelStore();
|
||||||
|
// Props
|
||||||
|
const props = defineProps<{
|
||||||
|
datas?: Array<{ baseid: string; basename: string }> // 基地列表
|
||||||
|
BID?: string // 基地ID
|
||||||
|
data?: { name: string } // 设施类型名称
|
||||||
|
res?: { bldstt: string; hydrodtin: string } // 初始筛选条件
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// Store (预留位置,根据需要取消注释)
|
||||||
|
// const jidiStore = useJidiSelectEventStore()
|
||||||
|
|
||||||
|
// Refs
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
|
// 管理多个表格实例的ref
|
||||||
|
const tableRefs = ref<Record<string, any>>({})
|
||||||
|
|
||||||
|
// 动态设置表格ref的函数
|
||||||
|
const setTableRef = (el: any, key: string) => {
|
||||||
|
if (el) {
|
||||||
|
tableRefs.value[key] = el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前激活tab的表格实例
|
||||||
|
const getCurrentTable = () => {
|
||||||
|
return tableRefs.value[activeTab.value]
|
||||||
|
}
|
||||||
|
|
||||||
|
// State
|
||||||
|
const formState = reactive({
|
||||||
|
dataDimensionVal: props.BID || '',
|
||||||
|
hydrodtin: props.res?.hydrodtin || '',
|
||||||
|
bldstt: props.res?.bldstt || '',
|
||||||
|
stnm: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 根据设施类型名称映射dwtp值
|
||||||
|
const dwtpMap: Record<string, string> = {
|
||||||
|
'叠梁门': '2',
|
||||||
|
'前置挡墙': '5',
|
||||||
|
'隔水幕墙': '6'
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentDwtp = computed(() => {
|
||||||
|
return dwtpMap[props.data?.name || ''] || '9'
|
||||||
|
})
|
||||||
|
|
||||||
|
// 初始化activeTab为当前设施类型对应的key
|
||||||
|
const activeTab = ref(currentDwtp.value)
|
||||||
|
|
||||||
|
const facilityStats = ref<Array<{ name: string; key: string; count: number }>>([])
|
||||||
|
const buildStateList = ref<Array<{ label: string; value: string }>>([])
|
||||||
|
const buildStateLoading = ref(false)
|
||||||
|
|
||||||
|
// 弹窗相关
|
||||||
|
|
||||||
|
|
||||||
|
// 排序配置 - 根据baseId动态配置,与React版本保持一致
|
||||||
|
const sort = computed(() => {
|
||||||
|
return formState.dataDimensionVal === 'all'
|
||||||
|
? [{ field: 'baseStepSort', dir: 'asc' }, { field: 'rvcdStepSort', dir: 'asc' }, { field: 'rstcdStepSort', dir: 'asc' }]
|
||||||
|
: [{ field: 'rvcdStepSort', dir: 'asc' }, { field: 'rstcdStepSort', dir: 'asc' }]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 基地列表(从props或store获取)
|
||||||
|
const baseList = computed(() => {
|
||||||
|
return props.datas || []
|
||||||
|
// 或者从store获取: return jidiStore.jidiData || []
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表格列定义
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'stnm',
|
||||||
|
key: 'stnm',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '接入状态',
|
||||||
|
dataIndex: 'dtinName',
|
||||||
|
key: 'dtinName',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '接入日期',
|
||||||
|
dataIndex: 'dtinTm',
|
||||||
|
key: 'dtinTm',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '建设状态',
|
||||||
|
dataIndex: 'bldsttCcodeName',
|
||||||
|
key: 'bldsttCcodeName',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '开工日期',
|
||||||
|
dataIndex: 'ststdt',
|
||||||
|
key: 'ststdt',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '建成日期',
|
||||||
|
dataIndex: 'jcdt',
|
||||||
|
key: 'jcdt',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '所在河段',
|
||||||
|
dataIndex: 'hbrvcdName',
|
||||||
|
key: 'hbrvcdName',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '关联电站',
|
||||||
|
dataIndex: 'ennm',
|
||||||
|
key: 'ennm',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '关联基地',
|
||||||
|
dataIndex: 'baseName',
|
||||||
|
key: 'baseName',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// API调用函数 - 获取统计数据(预留位置)
|
||||||
|
const fetchFacilityStats = async () => {
|
||||||
|
try {
|
||||||
|
let params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
formState.dataDimensionVal != 'all' ? {
|
||||||
|
"field": "baseId",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": formState.dataDimensionVal
|
||||||
|
} : null,
|
||||||
|
formState.hydrodtin ? {
|
||||||
|
"field": "dtin",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": formState.hydrodtin
|
||||||
|
} : null,
|
||||||
|
formState.bldstt ? {
|
||||||
|
"field": "bldsttCcode",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "2"
|
||||||
|
} : null,
|
||||||
|
formState.stnm ? {
|
||||||
|
"field": "stnm",
|
||||||
|
"operator": "contains",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": formState.stnm
|
||||||
|
} : null,
|
||||||
|
].filter(Boolean),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await dwInfoGetKendoListCust(params)
|
||||||
|
let mockData = res.data.data
|
||||||
|
// 转换数据格式
|
||||||
|
facilityStats.value = mockData.map((item: any) => ({
|
||||||
|
name: item.name,
|
||||||
|
count: item.totalNum,
|
||||||
|
key: item.dwtp === '1' ? '2' : item.dwtp === '2' ? '5' : item.dwtp === '3' ? '6' : '9'
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 如果当前激活的tab不在返回的数据中,则设置为第一个tab
|
||||||
|
if (facilityStats.value.length > 0) {
|
||||||
|
const hasCurrentTab = facilityStats.value.some(item => item.key === activeTab.value)
|
||||||
|
if (!hasCurrentTab) {
|
||||||
|
activeTab.value = facilityStats.value[0].key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取设施统计数据失败:', error)
|
||||||
|
message.error('获取设施统计数据失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API调用函数 - 获取表格数据(预留位置)
|
||||||
|
|
||||||
|
|
||||||
|
// 自定义数据转换
|
||||||
|
const customTransform = (res: any) => {
|
||||||
|
return {
|
||||||
|
records: res?.data?.data || [],
|
||||||
|
total: res?.data?.total || 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取建设状态列表(预留位置)
|
||||||
|
const fetchBuildStateList = async () => {
|
||||||
|
try {
|
||||||
|
buildStateLoading.value = true
|
||||||
|
// TODO: 调用API获取建设状态字典数据
|
||||||
|
const res = await dictgetRemoteDictValue({ dictCode: 'BLDSTT3T' })
|
||||||
|
buildStateList.value = res.data.map((item: any) => ({
|
||||||
|
label: item.dictMeaning,
|
||||||
|
value: item.dictValue
|
||||||
|
}))
|
||||||
|
buildStateList.value.push({ label: '全部', value: '' })
|
||||||
|
// 临时模拟数据(实际使用时删除)
|
||||||
|
// buildStateList.value = [
|
||||||
|
// { label: '全部', value: '' },
|
||||||
|
// { label: '未建', value: '0' },
|
||||||
|
// { label: '在建', value: '1' },
|
||||||
|
// { label: '已建', value: '2' }
|
||||||
|
// ]
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取建设状态列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
buildStateLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基地变化处理
|
||||||
|
const handleBaseChange = async () => {
|
||||||
|
formState.stnm = ''
|
||||||
|
await fetchFacilityStats()
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tab切换处理
|
||||||
|
const handleTabChange = (key: string) => {
|
||||||
|
activeTab.value = key
|
||||||
|
// 刷新表格数据
|
||||||
|
nextTick(() => {
|
||||||
|
handleSearch()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
|
||||||
|
const filters: any[] = [
|
||||||
|
activeTab.value != '9' ? {
|
||||||
|
"field": "sttpCode",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": 'DW_' + activeTab.value
|
||||||
|
} : null,
|
||||||
|
{
|
||||||
|
"field": "sttpFullPath",
|
||||||
|
"operator": "contains",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "ENV,ENVP,DW,DW_"
|
||||||
|
},
|
||||||
|
formState.dataDimensionVal != 'all' ? {
|
||||||
|
"field": "baseId",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "01"
|
||||||
|
} : null,
|
||||||
|
formState.hydrodtin ? {
|
||||||
|
"field": "dtin",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": formState.hydrodtin
|
||||||
|
} : null,
|
||||||
|
formState.bldstt ? {
|
||||||
|
"field": "bldsttCcode",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "2"
|
||||||
|
} : null,
|
||||||
|
formState.stnm ? {
|
||||||
|
"field": "stnm",
|
||||||
|
"operator": "contains",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": formState.stnm
|
||||||
|
} : null,
|
||||||
|
].filter(Boolean)
|
||||||
|
const filList = [
|
||||||
|
{
|
||||||
|
"field": "sttpCode",
|
||||||
|
"operator": "neq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "DW_2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "sttpCode",
|
||||||
|
"operator": "neq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "DW_5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "sttpCode",
|
||||||
|
"operator": "neq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "DW_6"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
if (activeTab.value == '9') {
|
||||||
|
filList.forEach((item) => {
|
||||||
|
filters.push(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
logic: 'and',
|
||||||
|
filters
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新表格
|
||||||
|
getCurrentTable()?.getList(filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
const typefenbian = (type: string) => {
|
||||||
|
if (type == '2') {
|
||||||
|
return 'dw_point'
|
||||||
|
} else if (type == '5') {
|
||||||
|
return 'DW_5'
|
||||||
|
} else if (type == '6') {
|
||||||
|
return 'DW_6'
|
||||||
|
} else {
|
||||||
|
return 'DW_1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 查看详情
|
||||||
|
const handleViewDetail = (record: any, type: string) => {
|
||||||
|
|
||||||
|
if (type === 'DW') {
|
||||||
|
modelStore.modalVisible = true;
|
||||||
|
modelStore.params.sttp = typefenbian(activeTab.value);
|
||||||
|
modelStore.title = record.stnm;
|
||||||
|
modelStore.params.stcd = record.stcd;
|
||||||
|
} else if (type === 'ENG') {
|
||||||
|
modelStore.modalVisible = true;
|
||||||
|
modelStore.params.sttp = "ENG";
|
||||||
|
modelStore.title = record.stnm + " 详情信息";
|
||||||
|
modelStore.params.stcd = record.rstcd;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 监听表单变化,自动查询
|
||||||
|
watch(
|
||||||
|
() => [formState.dataDimensionVal, formState.hydrodtin, formState.bldstt],
|
||||||
|
async () => {
|
||||||
|
await fetchFacilityStats()
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 监听props.data变化,重新计算默认激活的tab
|
||||||
|
watch(
|
||||||
|
() => props.data?.name,
|
||||||
|
async (newNameString) => {
|
||||||
|
const newDwtp = dwtpMap[newNameString || ''] || '9'
|
||||||
|
// 只有当新的dwtp与当前activeTab不同时才更新
|
||||||
|
if (newDwtp !== activeTab.value) {
|
||||||
|
activeTab.value = newDwtp
|
||||||
|
await fetchFacilityStats()
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: false } // 不立即执行,因为初始化时已经设置过了
|
||||||
|
)
|
||||||
|
|
||||||
|
// 监听props.BID变化,更新基地选择
|
||||||
|
watch(
|
||||||
|
() => props.BID,
|
||||||
|
(newBid) => {
|
||||||
|
// 只有当新的BID与当前formState.dataDimensionVal不同时才更新
|
||||||
|
if (newBid !== formState.dataDimensionVal) {
|
||||||
|
formState.dataDimensionVal = newBid || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: false } // 不立即执行,因为初始化时已经在reactive中设置过了
|
||||||
|
)
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
onMounted(async () => {
|
||||||
|
await fetchBuildStateList()
|
||||||
|
await fetchFacilityStats()
|
||||||
|
handleSearch()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
handleSearch
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.facility-detail-container {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.search-form {
|
||||||
|
// padding: 16px;
|
||||||
|
background: #fff;
|
||||||
|
// margin-bottom: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
:deep(.ant-form-item) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.facility-tabs {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
:deep(.ant-tabs-content) {
|
||||||
|
height: calc(100% - 46px);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs-tabpane) {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-link {
|
||||||
|
color: #2f6b98;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #40a9ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs-content-holder) {
|
||||||
|
height: 450px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,49 +1,42 @@
|
|||||||
<!-- SidePanelItem.vue -->
|
<!-- SidePanelItem.vue -->
|
||||||
<template>
|
<template>
|
||||||
<SidePanelItem title="设施类型及接入情况">
|
<SidePanelItem title="设施类型及接入情况">
|
||||||
<div class="card-container">
|
<a-spin :spinning="loading">
|
||||||
<div v-for="(item) in dataJson" class="facility-card">
|
<div v-if="dataJson.length > 0" class="card-container">
|
||||||
<div class="img_icon">
|
<div v-for="(item) in dataJson" class="facility-card" @click="imgclick(item)">
|
||||||
<i class="icon iconfont" :class="item?.icon" />
|
<div class="img_icon">
|
||||||
</div>
|
<i class="icon iconfont" :class="item?.icon" />
|
||||||
<div class="img_text">
|
</div>
|
||||||
<div>{{ item.nameString }}</div>
|
<div class="img_text">
|
||||||
<div class="text_num">{{ item.total + item.zj }}</div>
|
<div>{{ item.name }}</div>
|
||||||
|
<div class="text_num">{{ item.totalNum }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <a-card v-for="(item, index) in dataJson" :key="index" class="facility-card" type="inner" size="small"
|
<div v-else style="width: 100%;height: 158px;display: flex; align-items: center; justify-content: center;">
|
||||||
@click="handleCardClick(item)">
|
<a-empty description="暂无数据" />
|
||||||
<template #title>
|
</div>
|
||||||
<i class="icon iconfont" :class="item?.icon" style="
|
</a-spin>
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 40px;
|
|
||||||
background-color: #5389B5;
|
|
||||||
line-height: 40px;
|
|
||||||
color: #FFFFFF;
|
|
||||||
" />
|
|
||||||
</template>
|
|
||||||
<a-tooltip>
|
|
||||||
<div style="font-size: 14px; color: #333">{{ item.nameString }}</div>
|
|
||||||
<div style="padding: 4px 0" class="showNum">
|
|
||||||
<span>{{ item.total + item.zj }}</span>
|
|
||||||
</div>
|
|
||||||
</a-tooltip>
|
|
||||||
</a-card> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- <div v-else>
|
|
||||||
<a-empty />
|
|
||||||
</div> -->
|
|
||||||
</SidePanelItem>
|
</SidePanelItem>
|
||||||
|
|
||||||
|
<!-- 自定义弹框 -->
|
||||||
|
<a-modal v-model:open="modalVisible" title="设施类型及接入情况" width="1536px" :footer="null">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<DiwenshuijianhuansheshileixingzuchengjijieruqingkuangTwoLayers :datas="jiDiList" :BID="baseid"
|
||||||
|
:data="selectedItem" :res="res">
|
||||||
|
</DiwenshuijianhuansheshileixingzuchengjijieruqingkuangTwoLayers>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted, watch } from 'vue';
|
||||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
|
import { dwInfoGetKendoListCust } from "@/api/sw";
|
||||||
|
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||||
|
import DiwenshuijianhuansheshileixingzuchengjijieruqingkuangTwoLayers from "./TwoLayers/diwenshuijianhuansheshileixingzuchengjijieruqingkuangTwoLayers.vue"
|
||||||
|
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||||
// 定义组件名(便于调试和递归)
|
// 定义组件名(便于调试和递归)
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'diwenshuijianhuansheshileixingzuchengjijieruqingkuang'
|
name: 'diwenshuijianhuansheshileixingzuchengjijieruqingkuang'
|
||||||
@ -52,45 +45,156 @@ defineOptions({
|
|||||||
// 数据类型定义
|
// 数据类型定义
|
||||||
interface DataString {
|
interface DataString {
|
||||||
icon?: string;
|
icon?: string;
|
||||||
nameString: string;
|
name: string;
|
||||||
num?: number;
|
totalNum?: number;
|
||||||
total: number;
|
|
||||||
zj: number;
|
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 响应式数据
|
// 图标映射配置(根据dwtp值对应icon)
|
||||||
const dataJson = ref<DataString[]>([
|
const iconMap: Record<string, string> = {
|
||||||
|
'1': 'icon-dwsjhDieliangmen',
|
||||||
|
'2': 'icon-dwsjhQianzhidangqiang',
|
||||||
|
'3': 'icon-dwsjhGeshuimuqiang',
|
||||||
|
'4': 'icon-dwsjhQita'
|
||||||
|
};
|
||||||
|
|
||||||
|
const jiDiList: any = ref([
|
||||||
{
|
{
|
||||||
icon: 'icon-dwsjhDieliangmen',
|
"baseid": "all",
|
||||||
nameString: '叠梁门',
|
"basename": "当前全部",
|
||||||
num: 18,
|
"id": "9BFEC848-83EA-AD22-6DE2-10E969476693"
|
||||||
total: 18,
|
|
||||||
zj: 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'icon-dwsjhQianzhidangqiang',
|
"baseid": "01",
|
||||||
nameString: '前置挡墙',
|
"basename": "金沙江干流",
|
||||||
num: 4,
|
"id": "A33040B7-8977-D9F1-5E02-D7F0241AB8AA"
|
||||||
total: 4,
|
|
||||||
zj: 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'icon-dwsjhGeshuimuqiang',
|
"baseid": "02",
|
||||||
nameString: '隔水幕墙',
|
"basename": "雅砻江干流",
|
||||||
num: 1,
|
"id": "C63D6020-995D-FE97-2F4A-F619A7142C79"
|
||||||
total: 1,
|
|
||||||
zj: 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'icon-dwsjhQita',
|
"baseid": "03",
|
||||||
nameString: '其他',
|
"basename": "大渡河干流",
|
||||||
num: 1,
|
"id": "CCB0766B-F1D4-7DD6-650F-5C556B7231B3"
|
||||||
total: 1,
|
},
|
||||||
zj: 0
|
{
|
||||||
|
"baseid": "04",
|
||||||
|
"basename": "乌江干流",
|
||||||
|
"id": "E8A66641-B4F4-CC85-0815-38C5B2F93DBD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "05",
|
||||||
|
"basename": "长江上游干流",
|
||||||
|
"id": "E02C11E9-CEA5-A030-202F-3BFE84465D03"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "10",
|
||||||
|
"basename": "湘西",
|
||||||
|
"id": "B1D1D52D-CEEF-6DC4-27DF-9990EB572F8D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "08",
|
||||||
|
"basename": "黄河上游干流",
|
||||||
|
"id": "BC6AF135-263D-09A9-D5CA-C99B2598FE6E"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "09",
|
||||||
|
"basename": "黄河中游干流",
|
||||||
|
"id": "60EEEC28-128F-A2A8-44F3-6EAAC8FD8BB6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "06",
|
||||||
|
"basename": "南盘江-红水河",
|
||||||
|
"id": "7BB9A8F4-34B5-42B4-A7FC-CE910AD7F203"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "12",
|
||||||
|
"basename": "东北",
|
||||||
|
"id": "47F8EF06-924E-E161-FCAF-62A66BBF252D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "07",
|
||||||
|
"basename": "澜沧江干流",
|
||||||
|
"id": "A966A4C9-278C-B0DA-2B97-2D10B7A6E96A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "13",
|
||||||
|
"basename": "怒江干流",
|
||||||
|
"id": "FA89E8CB-67A8-76DA-DC1E-23AE4C54F9E4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "11",
|
||||||
|
"basename": "闽浙赣",
|
||||||
|
"id": "CD98F995-EEB2-1021-D807-DA1B1AD9E49A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "other",
|
||||||
|
"basename": "其他",
|
||||||
|
"id": "AFBDFC67-B955-4EFD-959A-014CFB59EBFC"
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
const res = ref({
|
||||||
|
hydrodtin: '',
|
||||||
|
bldstt: ''
|
||||||
|
})
|
||||||
|
// 响应式数据
|
||||||
|
const dataJson = ref<DataString[]>([]);
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(false);
|
||||||
|
const baseid = ref('')
|
||||||
|
|
||||||
|
// 弹框相关
|
||||||
|
const modalVisible = ref(false);
|
||||||
|
const selectedItem: any = ref<DataString | null>(null);
|
||||||
|
|
||||||
|
|
||||||
|
const getListData = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
baseid.value == 'all' ? null : {
|
||||||
|
"field": "baseId",
|
||||||
|
"operator": "contains",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": baseid.value
|
||||||
|
}
|
||||||
|
].filter(Boolean),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await dwInfoGetKendoListCust(params)
|
||||||
|
let data = res?.data?.data || res?.data || []
|
||||||
|
|
||||||
|
// 合并接口数据和icon配置
|
||||||
|
if (Array.isArray(data) && data.length > 0) {
|
||||||
|
dataJson.value = data.map((item: any) => ({
|
||||||
|
...item,
|
||||||
|
icon: iconMap[item.dwtp] || 'icon-dwsjhQita' // 根据dwtp匹配icon,默认使用"其他"图标
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
dataJson.value = [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取设施类型数据失败:', error);
|
||||||
|
dataJson.value = [];
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
watch(
|
||||||
|
() => JidiSelectEventStore.selectedItem,
|
||||||
|
(newVal) => {
|
||||||
|
baseid.value = newVal.wbsCode;
|
||||||
|
getListData()
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
// 卡片点击事件处理
|
// 卡片点击事件处理
|
||||||
// const handleCardClick = (item: DataString) => {
|
// const handleCardClick = (item: DataString) => {
|
||||||
// clickList.value = item;
|
// clickList.value = item;
|
||||||
@ -100,11 +204,17 @@ const dataJson = ref<DataString[]>([
|
|||||||
// hydrodtin: ''
|
// hydrodtin: ''
|
||||||
// };
|
// };
|
||||||
// };
|
// };
|
||||||
|
const imgclick = (item: DataString) => {
|
||||||
|
// 点击图片处理逻辑
|
||||||
|
console.log(item)
|
||||||
|
selectedItem.value = item;
|
||||||
|
modalVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
// 页面加载时执行的逻辑
|
// 页面加载时执行的逻辑
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 可以在这里加载实际的图片数据
|
// 可以在这里加载实际的图片数据
|
||||||
// loadData();
|
// getListData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -143,15 +253,24 @@ onMounted(() => {
|
|||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #333;
|
color: #333;
|
||||||
.text_num{
|
|
||||||
|
.text_num {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
// font-size: 16px;
|
// font-size: 16px;
|
||||||
color: #2f6b98;
|
color: #2f6b98;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.ant-spin-nested-loading) {
|
||||||
|
height: 158px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -1,51 +1,429 @@
|
|||||||
<!-- NEW_FILE_CODE -->
|
<!-- NEW_FILE_CODE -->
|
||||||
<template>
|
<template>
|
||||||
<SidePanelItem title="月平均水温历史对比">
|
<SidePanelItem title="月平均水温历史对比" :moreSelect="select" :datetimePicker="datetimePicker"
|
||||||
<div>
|
@update-values="handlePanelChange1">
|
||||||
<div class="water-temp-compare-chart" ref="chartRef"></div>
|
<a-spin :spinning="loading" tip="加载中...">
|
||||||
</div>
|
<div v-show="!loading && showemit" class="water-temp-compare-chart" ref="chartRef"></div>
|
||||||
<!-- <div v-else>
|
<div v-show="!loading && !showemit" class="water-temp-compare-chart">
|
||||||
<a-empty />
|
<a-empty description="暂无数据" />
|
||||||
</div> -->
|
</div>
|
||||||
|
</a-spin>
|
||||||
</SidePanelItem>
|
</SidePanelItem>
|
||||||
|
|
||||||
|
<!-- 数据点详情弹框 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:open="modalVisible"
|
||||||
|
:title="'月均水温对比'"
|
||||||
|
width="1536px"
|
||||||
|
:footer="null"
|
||||||
|
@cancel="handleModalClose"
|
||||||
|
>
|
||||||
|
|
||||||
|
<div v-if="modalData" class="modal-content">
|
||||||
|
<MonthlyAverage
|
||||||
|
:tm="modalData.date ? moment(modalData.date).format('YYYY-MM') + '-01 00:00:00' : moment().format('YYYY-MM') + '-01 23:59:59'"
|
||||||
|
:dataDimensionVal="modalData.baseid"
|
||||||
|
:rvcd='modalData.rvcd'
|
||||||
|
:stcd="modalData.stcd"
|
||||||
|
:jdList="jiDiList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
|
import { wbsbGetKendoList, avgMonGetKendoListCust } from "@/api/sw";
|
||||||
|
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||||
|
import MonthlyAverage from './monthlyAverage.vue'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'monthlyAvgWaterTemCompareHistory'
|
name: 'monthlyAvgWaterTemCompareHistory'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||||
const chartRef = ref<HTMLElement | null>(null)
|
const chartRef = ref<HTMLElement | null>(null)
|
||||||
let chartInstance: echarts.ECharts | null = null
|
let chartInstance: echarts.ECharts | null = null
|
||||||
|
|
||||||
const unit = '°C'
|
const unit = '°C'
|
||||||
|
const baseid: any = ref(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
const showemit = ref(true);
|
||||||
|
|
||||||
const initChart = () => {
|
// 弹框相关状态
|
||||||
|
const modalVisible = ref(false);
|
||||||
|
const modalData = ref<any>(null);
|
||||||
|
const stationName = ref('');
|
||||||
|
|
||||||
|
// 基地列表
|
||||||
|
const jiDiList: any = ref([
|
||||||
|
{
|
||||||
|
"baseid": "all",
|
||||||
|
"basename": "当前全部",
|
||||||
|
"id": "9BFEC848-83EA-AD22-6DE2-10E969476693"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "01",
|
||||||
|
"basename": "金沙江干流",
|
||||||
|
"id": "A33040B7-8977-D9F1-5E02-D7F0241AB8AA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "02",
|
||||||
|
"basename": "雅砻江干流",
|
||||||
|
"id": "C63D6020-995D-FE97-2F4A-F619A7142C79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "03",
|
||||||
|
"basename": "大渡河干流",
|
||||||
|
"id": "CCB0766B-F1D4-7DD6-650F-5C556B7231B3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "04",
|
||||||
|
"basename": "乌江干流",
|
||||||
|
"id": "E8A66641-B4F4-CC85-0815-38C5B2F93DBD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "05",
|
||||||
|
"basename": "长江上游干流",
|
||||||
|
"id": "E02C11E9-CEA5-A030-202F-3BFE84465D03"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "10",
|
||||||
|
"basename": "湘西",
|
||||||
|
"id": "B1D1D52D-CEEF-6DC4-27DF-9990EB572F8D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "08",
|
||||||
|
"basename": "黄河上游干流",
|
||||||
|
"id": "BC6AF135-263D-09A9-D5CA-C99B2598FE6E"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "09",
|
||||||
|
"basename": "黄河中游干流",
|
||||||
|
"id": "60EEEC28-128F-A2A8-44F3-6EAAC8FD8BB6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "06",
|
||||||
|
"basename": "南盘江-红水河",
|
||||||
|
"id": "7BB9A8F4-34B5-42B4-A7FC-CE910AD7F203"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "12",
|
||||||
|
"basename": "东北",
|
||||||
|
"id": "47F8EF06-924E-E161-FCAF-62A66BBF252D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "07",
|
||||||
|
"basename": "澜沧江干流",
|
||||||
|
"id": "A966A4C9-278C-B0DA-2B97-2D10B7A6E96A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "13",
|
||||||
|
"basename": "怒江干流",
|
||||||
|
"id": "FA89E8CB-67A8-76DA-DC1E-23AE4C54F9E4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "11",
|
||||||
|
"basename": "闽浙赣",
|
||||||
|
"id": "CD98F995-EEB2-1021-D807-DA1B1AD9E49A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "other",
|
||||||
|
"basename": "其他",
|
||||||
|
"id": "AFBDFC67-B955-4EFD-959A-014CFB59EBFC"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 选择器配置
|
||||||
|
const select = ref({
|
||||||
|
show: true,
|
||||||
|
value: '',
|
||||||
|
options: [],
|
||||||
|
picker: undefined,
|
||||||
|
format: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 日期选择器配置
|
||||||
|
const datetimePicker = ref({
|
||||||
|
show: true,
|
||||||
|
value: (() => {
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.getFullYear();
|
||||||
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||||
|
return `${year}-${month}`;
|
||||||
|
})(),
|
||||||
|
format: "YYYY-MM",
|
||||||
|
picker: "month" as const,
|
||||||
|
options: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
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 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',
|
||||||
|
value: baseid.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let data: any = {
|
||||||
|
filter: {
|
||||||
|
logic: 'and',
|
||||||
|
filters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = {}
|
||||||
|
jiDiList.value.forEach((item: any) => {
|
||||||
|
jiDiListMap[item.baseid] = item.basename
|
||||||
|
})
|
||||||
|
|
||||||
|
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,
|
||||||
|
children: dataMapNameMap[item].map((item2: any) => {
|
||||||
|
return {
|
||||||
|
title: item2.wbsName,
|
||||||
|
value: item2.wbsCode
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
dataMapNameArr = dataMapNameArr.sort((a: any, b: any) => {
|
||||||
|
const indexA = jiDiList.value.findIndex(item => item.baseid === a.value);
|
||||||
|
const indexB = jiDiList.value.findIndex(item => item.baseid === b.value);
|
||||||
|
return indexA - indexB;
|
||||||
|
})
|
||||||
|
select.value.options = filterSelectOptions(dataMapNameArr)
|
||||||
|
if (baseid.value === 'all') {
|
||||||
|
select.value.value = 'SJLY176'
|
||||||
|
} 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 = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getEchartsData()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('选择器配置加载失败:', error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//获取图表配置
|
||||||
|
const getEchartsData = async () => {
|
||||||
|
if (loading.value) return; // 防止重复请求
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 根据 datetimePicker.value.value 解析年月
|
||||||
|
const dateValue = datetimePicker.value.value || '';
|
||||||
|
const [yearStr, monthStr] = dateValue.split('-');
|
||||||
|
const year = parseInt(yearStr);
|
||||||
|
const month = parseInt(monthStr);
|
||||||
|
|
||||||
|
// 计算该月的第一天和最后一天
|
||||||
|
const firstDay = `${dateValue}-01 00:00:00`;
|
||||||
|
// 创建下个月1号,然后减去1天得到本月最后一天
|
||||||
|
const nextMonth = month === 12 ? 1 : month + 1;
|
||||||
|
const nextYear = month === 12 ? year + 1 : year;
|
||||||
|
const lastDate = new Date(nextYear, nextMonth - 1, 1);
|
||||||
|
lastDate.setDate(lastDate.getDate() - 1);
|
||||||
|
const lastDay = `${year}-${String(month).padStart(2, '0')}-${String(lastDate.getDate()).padStart(2, '0')} 23:59:59`;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "rvcd",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": select.value.value
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "tm",
|
||||||
|
"operator": "gte",
|
||||||
|
"dataType": "date",
|
||||||
|
"value": firstDay
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "tm",
|
||||||
|
"operator": "lte",
|
||||||
|
"dataType": "date",
|
||||||
|
"value": lastDay
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "year",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": year
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "month",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": month
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await avgMonGetKendoListCust(params)
|
||||||
|
console.log('接口返回数据:', res)
|
||||||
|
let data = res?.data?.data || res?.data || []
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
showemit.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showemit.value = true
|
||||||
|
|
||||||
|
// 筛选 sttp === "1" 的数据作为 X 轴站点名称
|
||||||
|
const stationData = data.filter((item: any) => item.sttp === "1")
|
||||||
|
const xData = stationData.map((item: any) => ({
|
||||||
|
value: item.stnm,
|
||||||
|
stnm: item.stnm,
|
||||||
|
stcd: item.stcd // 保留站点编码用于点击事件
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 筛选 sttp === "2" 的数据作为图表系列数据
|
||||||
|
const tempData = data.filter((item: any) => item.sttp === "2")
|
||||||
|
|
||||||
|
// 按照站点顺序提取三个系列的数据,包装为对象格式以保留元信息
|
||||||
|
const actualData = tempData.map((item: any) => ({
|
||||||
|
value: item.actualTemp,
|
||||||
|
stcd: item.stcd,
|
||||||
|
stnm: item.stnm
|
||||||
|
}))
|
||||||
|
const lastData = tempData.map((item: any) => ({
|
||||||
|
value: item.lastTemp,
|
||||||
|
stcd: item.stcd,
|
||||||
|
stnm: item.stnm
|
||||||
|
}))
|
||||||
|
const naturalData = stationData.map((item: any) => ({
|
||||||
|
value: item.naturalTemp,
|
||||||
|
stcd: item.stcd,
|
||||||
|
stnm: item.stnm
|
||||||
|
}))
|
||||||
|
|
||||||
|
console.log('X轴数据:', xData)
|
||||||
|
console.log('实测值:', actualData)
|
||||||
|
console.log('去年同期:', lastData)
|
||||||
|
console.log('天然值:', naturalData)
|
||||||
|
|
||||||
|
// 初始化或更新图表
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!chartInstance) {
|
||||||
|
initChart(xData, actualData, lastData, naturalData)
|
||||||
|
} else {
|
||||||
|
// 如果图表已存在,只更新数据
|
||||||
|
chartInstance.setOption({
|
||||||
|
xAxis: {
|
||||||
|
data: xData
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{ data: actualData },
|
||||||
|
{ data: lastData },
|
||||||
|
{ data: naturalData }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 强制重绘,确保尺寸正确
|
||||||
|
setTimeout(() => {
|
||||||
|
chartInstance?.resize()
|
||||||
|
}, 100)
|
||||||
|
}, 50)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('图表数据加载失败:', error)
|
||||||
|
showemit.value = false
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initChart = (xData: any[], actualData: any[], lastData: any[], naturalData: any[]) => {
|
||||||
if (!chartRef.value) return
|
if (!chartRef.value) return
|
||||||
|
|
||||||
chartInstance = echarts.init(chartRef.value)
|
chartInstance = echarts.init(chartRef.value)
|
||||||
|
|
||||||
const legendData = ['实测值', '去年同期', '天然']
|
const legendData = ['实测值', '去年同期', '天然']
|
||||||
|
|
||||||
// x轴数据 - 保持与原始配置一致的结构 { value, stnm }
|
|
||||||
const xData = [
|
|
||||||
{ value: '两河口', stnm: '两河口' },
|
|
||||||
{ value: '锦屏一级', stnm: '锦屏一级' },
|
|
||||||
{ value: '桐子林', stnm: '桐子林' }
|
|
||||||
]
|
|
||||||
|
|
||||||
// 根据图片数据提取的静态数据
|
|
||||||
const actualData = [9, 11.5, 14] // 实测值(蓝色线)
|
|
||||||
const lastData = [8.8, 10.5, 13.2] // 去年同期(紫色线)
|
|
||||||
const naturalData = [9.2, 12, 15.5] // 天然(绿色线)
|
|
||||||
|
|
||||||
// 计算Y轴范围:最小值向下取整,最大值向上取整
|
// 计算Y轴范围:最小值向下取整,最大值向上取整
|
||||||
const allData = [...actualData, ...lastData, ...naturalData].filter(val => val !== null && val !== undefined)
|
const allData = [...actualData, ...lastData, ...naturalData].map(item => item.value).filter(val => val !== null && val !== undefined)
|
||||||
const dataMin = Math.min(...allData)
|
const dataMin = allData.length > 0 ? Math.min(...allData) : 0
|
||||||
const dataMax = Math.max(...allData)
|
const dataMax = allData.length > 0 ? Math.max(...allData) : 10
|
||||||
const yAxisMin = Math.floor(dataMin)
|
const yAxisMin = Math.floor(dataMin)
|
||||||
const yAxisMax = Math.ceil(dataMax)
|
const yAxisMax = Math.ceil(dataMax)
|
||||||
|
|
||||||
@ -72,11 +450,12 @@ const initChart = () => {
|
|||||||
const label = xData.filter((item: any) => item.value === params[0].axisValueLabel)?.[0]?.stnm
|
const label = xData.filter((item: any) => item.value === params[0].axisValueLabel)?.[0]?.stnm
|
||||||
let elm = ``
|
let elm = ``
|
||||||
for (const item of params) {
|
for (const item of params) {
|
||||||
|
const value = item.data?.value ?? item.value;
|
||||||
elm += `
|
elm += `
|
||||||
<div>
|
<div>
|
||||||
${item.marker}
|
${item.marker}
|
||||||
<span>${item.seriesName}:</span>
|
<span>${item.seriesName}:</span>
|
||||||
<span>${item.value === null || item.value === undefined ? '-' : item.value}${unit}</span>
|
<span>${value === null || value === undefined ? '-' : value}${unit}</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
@ -93,7 +472,7 @@ const initChart = () => {
|
|||||||
left: 30
|
left: 30
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
type: 'shadow',
|
type: 'shadow',
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#007aff1a',
|
color: '#007aff1a',
|
||||||
@ -204,15 +583,63 @@ const initChart = () => {
|
|||||||
options.color = ['#5470c6', '#9b59b6', '#91cc75']
|
options.color = ['#5470c6', '#9b59b6', '#91cc75']
|
||||||
|
|
||||||
chartInstance.setOption(options)
|
chartInstance.setOption(options)
|
||||||
|
|
||||||
|
// 绑定点击事件
|
||||||
|
chartInstance.on('click', (params: any) => {
|
||||||
|
console.log('图表数据点被点击:', params);
|
||||||
|
|
||||||
|
// 获取点击的数据点信息
|
||||||
|
const dataPoint = params.data;
|
||||||
|
const stcd = dataPoint?.stcd || '';
|
||||||
|
const stnm = dataPoint?.stnm || '';
|
||||||
|
|
||||||
|
// 设置弹框数据
|
||||||
|
stationName.value = stnm;
|
||||||
|
modalData.value = {
|
||||||
|
baseid: baseid.value,
|
||||||
|
rvcd: select.value.value,
|
||||||
|
date: datetimePicker.value.value,
|
||||||
|
stcd: stcd,
|
||||||
|
stnm: stnm
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开弹框
|
||||||
|
modalVisible.value = true;
|
||||||
|
|
||||||
|
// TODO: 在此处添加您的点击事件处理逻辑
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 关闭弹框
|
||||||
|
const handleModalClose = () => {
|
||||||
|
modalVisible.value = false;
|
||||||
|
modalData.value = null;
|
||||||
|
stationName.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
//监听子组件的数据变化
|
||||||
|
const handlePanelChange1 = (data) => {
|
||||||
|
console.log('当前所有控件状态:', data);
|
||||||
|
|
||||||
|
// 当选择器或日期变化时,重新加载图表数据
|
||||||
|
if (data.moreSelect || data.datetime) {
|
||||||
|
getEchartsData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => JidiSelectEventStore.selectedItem,
|
||||||
|
(newVal) => {
|
||||||
|
baseid.value = newVal.wbsCode;
|
||||||
|
getSelectConfig()
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 延迟初始化,确保容器尺寸已就绪
|
// 延迟初始化,确保容器尺寸已就绪
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
initChart()
|
getEchartsData()
|
||||||
// 初始化完成后再次调用 resize 确保尺寸正确
|
|
||||||
chartInstance?.resize()
|
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
@ -231,7 +658,17 @@ onBeforeUnmount(() => {
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.water-temp-compare-chart {
|
.water-temp-compare-chart {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
|
||||||
height: 260px;
|
height: 260px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-spin-nested-loading) {
|
||||||
|
height: 260px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
padding: 16px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -0,0 +1,835 @@
|
|||||||
|
<template>
|
||||||
|
<div class="monthly-average-container">
|
||||||
|
<!-- 搜索表单 -->
|
||||||
|
<a-form ref="formRef" :model="formValue" layout="inline" class="search-form">
|
||||||
|
<a-form-item label="基地名称" name="dataDimensionVal">
|
||||||
|
<a-select v-model:value="formValue.dataDimensionVal" placeholder="请选择" style="width: 200px"
|
||||||
|
@change="handleBaseChange">
|
||||||
|
<a-select-option v-for="item in jdList" :key="item.baseid" :value="item.baseid">
|
||||||
|
{{ item.basename }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="所在流域" name="rvcd">
|
||||||
|
<a-select v-model:value="formValue.rvcd" placeholder="请选择" style="width: 200px"
|
||||||
|
:disabled="!formValue.dataDimensionVal" @change="handleRvcdChange">
|
||||||
|
<a-select-option v-for="item in lyList" :key="item.value" :value="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="断面名称" name="stcd">
|
||||||
|
<a-select v-model:value="formValue.stcd" placeholder="请选择" style="width: 200px"
|
||||||
|
:disabled="!formValue.rvcd">
|
||||||
|
<a-select-option v-for="item in dmList" :key="item.value" :value="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="月份" name="tm">
|
||||||
|
<a-date-picker v-model:value="formValue.tm" picker="month" :disabled-date="disabledDate"
|
||||||
|
format="YYYY-MM" value-format="YYYY-MM-DD HH:mm:ss" :allow-clear="false" />
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="handleSearch">
|
||||||
|
查询
|
||||||
|
</a-button>
|
||||||
|
<a-button :loading="exportLoading" @click="handleExport">
|
||||||
|
导出
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<div style="width: 100%;display: flex;">
|
||||||
|
<!-- 图表容器:始终存在,不再使用 v-if -->
|
||||||
|
<div class="chart-wrapper" ref="chartRef"></div>
|
||||||
|
<BasicTable ref="tableRef" :scrollY="460" :columns="columns" :list-url="DetGetKendoListCust"
|
||||||
|
:search-params="{ sort: sort }" :transform-data="customTransform">
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a @click="handleViewDetail(record)" class="text_hocer">查看详情</a>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</BasicTable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, watch, onMounted, onBeforeUnmount } from 'vue'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import dayjs, { Dayjs } from 'dayjs'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import type { EChartsOption } from 'echarts'
|
||||||
|
import moment from 'moment'
|
||||||
|
import { omit } from 'lodash-es'
|
||||||
|
import { wbsbGetKendoList, getVmsstbprpt, DetGetKendoListCust } from "@/api/sw";
|
||||||
|
import BasicTable from '@/components/BasicTable/index.vue';
|
||||||
|
import { useModelStore } from "@/store/modules/model";
|
||||||
|
|
||||||
|
const modelStore = useModelStore();
|
||||||
|
|
||||||
|
// ==================== Props 定义 ====================
|
||||||
|
interface Props {
|
||||||
|
tm?: string
|
||||||
|
dataDimensionVal?: string
|
||||||
|
rvcd?: string
|
||||||
|
stcd?: string
|
||||||
|
jdList?: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
tm: '',
|
||||||
|
dataDimensionVal: '',
|
||||||
|
rvcd: '',
|
||||||
|
stcd: '',
|
||||||
|
jdList: () => []
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== 类型定义 ====================
|
||||||
|
interface DefautState {
|
||||||
|
dataDimensionType: string
|
||||||
|
dataDimensionVal: any
|
||||||
|
tm: string | Dayjs
|
||||||
|
startDt: string
|
||||||
|
endDt: string
|
||||||
|
stcd: string
|
||||||
|
rvcd: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OptionItem {
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 响应式状态 ====================
|
||||||
|
const formRef = ref()
|
||||||
|
const chartRef = ref<HTMLElement | null>(null)
|
||||||
|
let chartInstance: echarts.ECharts | null = null
|
||||||
|
|
||||||
|
const chartLoading = ref(false)
|
||||||
|
const tableLoading = ref(false)
|
||||||
|
const exportLoading = ref(false)
|
||||||
|
const tableRef = ref<any>(null);
|
||||||
|
|
||||||
|
const sort = [
|
||||||
|
{
|
||||||
|
"field": "dt",
|
||||||
|
"dir": "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// 下拉列表
|
||||||
|
const lyList = ref<OptionItem[]>([])
|
||||||
|
const dmList = ref<OptionItem[]>([])
|
||||||
|
|
||||||
|
// 表单值
|
||||||
|
const formValue = reactive<DefautState>({
|
||||||
|
dataDimensionType: 'hyBase',
|
||||||
|
dataDimensionVal: props.dataDimensionVal || 'all',
|
||||||
|
tm: props.tm ? dayjs(props.tm) : dayjs(),
|
||||||
|
startDt: '',
|
||||||
|
endDt: '',
|
||||||
|
stcd: props.stcd || '',
|
||||||
|
rvcd: props.rvcd || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表格数据
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
const pagination = reactive({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
total: 0,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showTotal: (total: number) => `共 ${total} 条`
|
||||||
|
})
|
||||||
|
|
||||||
|
// 图表数据
|
||||||
|
const optionData = ref<any[]>([])
|
||||||
|
|
||||||
|
// ==================== 工具函数 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单位转换
|
||||||
|
*/
|
||||||
|
const transUnit = (value: any, code: string, type: string): string => {
|
||||||
|
if (value === null || value === undefined) return '-'
|
||||||
|
const numValue = Number(value)
|
||||||
|
if (isNaN(numValue)) return '-'
|
||||||
|
return numValue.toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单位配置
|
||||||
|
*/
|
||||||
|
const getUnitConfigByCode = (code: string, type: string): { unit: string } => {
|
||||||
|
return { unit: '℃' }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取颜色配置
|
||||||
|
*/
|
||||||
|
const getColorByCodeAndType = (code: string[], typeKey: string[]): string[] => {
|
||||||
|
// 实测值(蓝)、去年同期(紫)、天然(绿)
|
||||||
|
return ['#5470c6', '#9b59b6', '#91cc75']
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式化
|
||||||
|
*/
|
||||||
|
const tmFmt = (d: string) => moment(d).format('YYYY-MM-DD')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化数值:保留一位小数,四舍五入,空值显示 -
|
||||||
|
*/
|
||||||
|
const formatNumber = (value: any): string => {
|
||||||
|
if (value === null || value === undefined || value === '') return '-'
|
||||||
|
const numValue = Number(value)
|
||||||
|
if (isNaN(numValue)) return '-'
|
||||||
|
return numValue.toFixed(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期为 YYYY-MM-DD 格式
|
||||||
|
*/
|
||||||
|
const formatDate = (dateStr: string): string => {
|
||||||
|
if (!dateStr) return '-'
|
||||||
|
try {
|
||||||
|
return dayjs(dateStr).format('YYYY-MM-DD')
|
||||||
|
} catch (error) {
|
||||||
|
return dateStr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算变化趋势:实测值 - 去年同期值
|
||||||
|
*/
|
||||||
|
const calculateComparison = (record: any): string => {
|
||||||
|
const wt = record.wt
|
||||||
|
const beforeWt = record.beforeWt
|
||||||
|
|
||||||
|
if (wt === null || wt === undefined || wt === '' ||
|
||||||
|
beforeWt === null || beforeWt === undefined || beforeWt === '') {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
const wtNum = Number(wt)
|
||||||
|
const beforeWtNum = Number(beforeWt)
|
||||||
|
|
||||||
|
if (isNaN(wtNum) || isNaN(beforeWtNum)) return '-'
|
||||||
|
|
||||||
|
const diff = wtNum - beforeWtNum
|
||||||
|
return diff.toFixed(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用未来日期
|
||||||
|
*/
|
||||||
|
const disabledDate = (current: Dayjs) => {
|
||||||
|
return current && current > dayjs().endOf('day')
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== API 调用 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流域下拉列表
|
||||||
|
*/
|
||||||
|
const fetchLyData = async () => {
|
||||||
|
try {
|
||||||
|
console.log('获取流域列表,baseid:', formValue.dataDimensionVal)
|
||||||
|
let params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "wbsType",
|
||||||
|
"operator": "eq",
|
||||||
|
"value": "PSB_RVCD"
|
||||||
|
},
|
||||||
|
formValue.dataDimensionVal != 'all' ? {
|
||||||
|
"field": "fullPath",
|
||||||
|
"operator": "startswith",
|
||||||
|
"value": formValue.dataDimensionVal
|
||||||
|
} : null
|
||||||
|
].filter(Boolean)
|
||||||
|
},
|
||||||
|
"group": [
|
||||||
|
{ "dir": "asc", "field": "orderIndex" },
|
||||||
|
{ "dir": "asc", "field": "wbsCode" },
|
||||||
|
{ "dir": "asc", "field": "wbsName" },
|
||||||
|
{ "dir": "asc", "field": "objid" }
|
||||||
|
],
|
||||||
|
"groupResultFlat": true
|
||||||
|
}
|
||||||
|
const res = await wbsbGetKendoList(params)
|
||||||
|
let data = res?.data?.data || res?.data || []
|
||||||
|
if (data.length > 0) {
|
||||||
|
const options = data.map((item: any) => ({
|
||||||
|
label: item.wbsName,
|
||||||
|
value: item.wbsCode
|
||||||
|
}))
|
||||||
|
lyList.value = options
|
||||||
|
const rvcd = options.find((i: any) => i.value === props.rvcd)?.value || options[0]?.value
|
||||||
|
formValue.rvcd = rvcd
|
||||||
|
await fetchDmData()
|
||||||
|
} else {
|
||||||
|
lyList.value = []
|
||||||
|
formValue.rvcd = ''
|
||||||
|
await fetchDmData()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 忽略错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取断面下拉列表
|
||||||
|
*/
|
||||||
|
const fetchDmData = async () => {
|
||||||
|
try {
|
||||||
|
console.log('获取断面列表,baseid:', formValue.dataDimensionVal, 'rvcd:', formValue.rvcd)
|
||||||
|
let params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{ "field": "sttpCode", "operator": "eq", "value": "WTRV" },
|
||||||
|
{ "field": "mway", "operator": "eq", "value": 2 },
|
||||||
|
formValue.dataDimensionVal == 'all' ? {
|
||||||
|
"field": "rvcd",
|
||||||
|
"operator": "contains",
|
||||||
|
"value": formValue.rvcd
|
||||||
|
} : {
|
||||||
|
"field": "baseId",
|
||||||
|
"operator": "contains",
|
||||||
|
"value": formValue.dataDimensionVal
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"select": [ "stcd", "stnm", "lgtd", "lttd", "rstcdStepSort" ],
|
||||||
|
"sort": [ { "field": "rstcdStepSort", "dir": "desc" } ]
|
||||||
|
}
|
||||||
|
const res = await getVmsstbprpt(params)
|
||||||
|
let resData = res?.data?.data || res?.data || []
|
||||||
|
const options = resData.map((item: any) => ({
|
||||||
|
label: item.stnm,
|
||||||
|
value: item.stcd
|
||||||
|
}))
|
||||||
|
dmList.value = options
|
||||||
|
const stcd = options.find((i: any) => i.value === props.stcd)?.value || options[0]?.value
|
||||||
|
formValue.stcd = stcd || ''
|
||||||
|
handleSearch()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取断面列表失败:', error)
|
||||||
|
message.error('获取断面列表失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取图表数据
|
||||||
|
*/
|
||||||
|
const getChartData = async (value: any) => {
|
||||||
|
// 显示 loading
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.showLoading('default', {
|
||||||
|
text: '加载中...',
|
||||||
|
color: '#5470c6',
|
||||||
|
textColor: '#000',
|
||||||
|
maskColor: 'rgba(255, 255, 255, 0.8)',
|
||||||
|
zlevel: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
chartLoading.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tmValue = dayjs.isDayjs(value.tm) ? value.tm : dayjs(value.tm)
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "stcd",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": value.stcd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "startTime",
|
||||||
|
"operator": "gte",
|
||||||
|
"dataType": "date",
|
||||||
|
value: tmValue.startOf('month').format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "endTime",
|
||||||
|
"operator": "lte",
|
||||||
|
"dataType": "date",
|
||||||
|
value: tmValue.endOf('month').format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const res = await DetGetKendoListCust(params)
|
||||||
|
let data = res?.data?.data || res?.data || []
|
||||||
|
|
||||||
|
if (data.length > 0) {
|
||||||
|
optionData.value = data
|
||||||
|
updateChart() // 正常绘制图表
|
||||||
|
} else {
|
||||||
|
optionData.value = []
|
||||||
|
// 数据为空:清除图表并显示“暂无数据”
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.clear();
|
||||||
|
chartInstance.setOption({
|
||||||
|
title: {
|
||||||
|
show: true,
|
||||||
|
text: '暂无数据',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center',
|
||||||
|
textStyle: {
|
||||||
|
color: '#999',
|
||||||
|
fontSize: 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取图表数据失败:', error)
|
||||||
|
message.error('获取图表数据失败')
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.clear();
|
||||||
|
chartInstance.setOption({
|
||||||
|
title: {
|
||||||
|
show: true,
|
||||||
|
text: '数据加载失败',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center',
|
||||||
|
textStyle: { color: '#f00' }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
chartLoading.value = false
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取表格数据
|
||||||
|
*/
|
||||||
|
const getTableData = async (value: any) => {
|
||||||
|
try {
|
||||||
|
const tmValue = dayjs.isDayjs(value.tm) ? value.tm : dayjs(value.tm)
|
||||||
|
const filter = {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "stcd",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": value.stcd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "startTime",
|
||||||
|
"operator": "gte",
|
||||||
|
"dataType": "date",
|
||||||
|
value: tmValue.startOf('month').format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "endTime",
|
||||||
|
"operator": "lte",
|
||||||
|
"dataType": "date",
|
||||||
|
value: tmValue.endOf('month').format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
tableRef.value?.getList(filter);
|
||||||
|
} catch (error) {
|
||||||
|
// 忽略错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 图表相关 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化图表
|
||||||
|
*/
|
||||||
|
const initChart = () => {
|
||||||
|
if (!chartRef.value) return
|
||||||
|
chartInstance = echarts.init(chartRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新图表(有数据时调用)
|
||||||
|
*/
|
||||||
|
const updateChart = () => {
|
||||||
|
if (!chartInstance) return
|
||||||
|
|
||||||
|
// 清除可能残留的“暂无数据”title
|
||||||
|
chartInstance.setOption({ title: { show: false } }, false);
|
||||||
|
|
||||||
|
const { unit } = getUnitConfigByCode('Other', 'ACTUALTEMP')
|
||||||
|
const legendData = ['实测值', '去年同期', '天然']
|
||||||
|
|
||||||
|
const xData: any[] = []
|
||||||
|
const actualData: (number | null)[] = []
|
||||||
|
const lastData: (number | null)[] = []
|
||||||
|
const naturalData: (number | null)[] = []
|
||||||
|
|
||||||
|
optionData.value.forEach((item: any) => {
|
||||||
|
actualData.push(item.wt === null ? null : Number(transUnit(item.wt, 'Other', 'ACTUALTEMP')))
|
||||||
|
lastData.push(item.beforeWt === null ? null : Number(transUnit(item.beforeWt, 'Other', 'LASTTEMP')))
|
||||||
|
naturalData.push(item.actualTemp === null ? null : Number(transUnit(item.actualTemp, 'Other', 'NATURALTEMP')))
|
||||||
|
xData.push({ value: item.dt })
|
||||||
|
})
|
||||||
|
|
||||||
|
const code = ['Other']
|
||||||
|
const typeKey = ['ACTUALTEMP', 'LASTTEMP', 'NATURALTEMP']
|
||||||
|
const colors = getColorByCodeAndType(code, typeKey)
|
||||||
|
|
||||||
|
const option: EChartsOption = {
|
||||||
|
color: colors,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: (params: any) => {
|
||||||
|
const a = params
|
||||||
|
.map((item: any) => {
|
||||||
|
const value = item.value !== null && item.value !== undefined ? item.value : '-'
|
||||||
|
return `<div>${item.marker}${item.seriesName}: <span style="float:right">${value} ${unit}</span></div>`
|
||||||
|
})
|
||||||
|
.join('')
|
||||||
|
return `<h3 style="color:#FFF">${tmFmt(params[0].name)}</h3>${a}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: legendData
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
axisTick: { show: true },
|
||||||
|
data: xData,
|
||||||
|
axisLabel: {
|
||||||
|
formatter: (value: string) => tmFmt(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: `水温(${unit})`,
|
||||||
|
scale: true,
|
||||||
|
axisLine: { show: true }
|
||||||
|
},
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: 'inside',
|
||||||
|
show: false,
|
||||||
|
xAxisIndex: [0],
|
||||||
|
yAxisIndex: [], // 不控制 Y 轴缩放
|
||||||
|
zoomOnMouseWheel: true,
|
||||||
|
moveOnMouseMove: true
|
||||||
|
},
|
||||||
|
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: legendData[0],
|
||||||
|
data: actualData,
|
||||||
|
type: 'line',
|
||||||
|
connectNulls: true,
|
||||||
|
smooth: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: legendData[1],
|
||||||
|
data: lastData,
|
||||||
|
type: 'line',
|
||||||
|
connectNulls: true,
|
||||||
|
smooth: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: legendData[2],
|
||||||
|
data: naturalData,
|
||||||
|
type: 'line',
|
||||||
|
connectNulls: true,
|
||||||
|
smooth: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chartInstance.setOption(option, true) // notMerge = true 确保完全替换
|
||||||
|
} catch (error) {
|
||||||
|
console.error('图表更新失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 事件处理 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基地变化
|
||||||
|
*/
|
||||||
|
const handleBaseChange = async (value: string) => {
|
||||||
|
formValue.dataDimensionVal = value
|
||||||
|
formValue.rvcd = ''
|
||||||
|
formValue.stcd = ''
|
||||||
|
lyList.value = []
|
||||||
|
dmList.value = []
|
||||||
|
await fetchLyData()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流域变化
|
||||||
|
*/
|
||||||
|
const handleRvcdChange = async (value: string) => {
|
||||||
|
formValue.rvcd = value
|
||||||
|
formValue.stcd = ''
|
||||||
|
dmList.value = []
|
||||||
|
await fetchDmData()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
*/
|
||||||
|
const handleSearch = async () => {
|
||||||
|
// if (!formValue.stcd) {
|
||||||
|
// message.error('请选择断面名称')
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
const tmValue = dayjs.isDayjs(formValue.tm)
|
||||||
|
? formValue.tm.format('YYYY-MM-DD 00:00:00')
|
||||||
|
: moment(formValue.tm).format('YYYY-MM-DD 00:00:00')
|
||||||
|
|
||||||
|
const values = {
|
||||||
|
...formValue,
|
||||||
|
tm: tmValue
|
||||||
|
}
|
||||||
|
|
||||||
|
await getChartData(values)
|
||||||
|
await getTableData(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出
|
||||||
|
*/
|
||||||
|
const handleExport = async () => {
|
||||||
|
exportLoading.value = true
|
||||||
|
try {
|
||||||
|
const tmValue = dayjs.isDayjs(formValue.tm)
|
||||||
|
? formValue.tm.format('YYYY-MM-DD 00:00:00')
|
||||||
|
: moment(formValue.tm).format('YYYY-MM-DD 00:00:00')
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
...buildFilterParams({ ...formValue, tm: tmValue }),
|
||||||
|
exportType: 'excel',
|
||||||
|
exportFileName: `月平均水温历史对比 ${moment().format('YYYY-MM-DD HH-mm-ss')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
message.success('导出功能待实现')
|
||||||
|
console.log('导出参数:', params)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('导出失败:', error)
|
||||||
|
message.error('导出失败')
|
||||||
|
} finally {
|
||||||
|
exportLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格分页变化
|
||||||
|
*/
|
||||||
|
const handleTableChange = (pag: any) => {
|
||||||
|
pagination.current = pag.current
|
||||||
|
pagination.pageSize = pag.pageSize
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建表格过滤参数
|
||||||
|
*/
|
||||||
|
const buildFilterParams = (values: any) => {
|
||||||
|
let _p: any = { ...values, stcd: values?.stcd || props?.stcd }
|
||||||
|
|
||||||
|
if (_p.tm) {
|
||||||
|
const tmValue = dayjs.isDayjs(_p.tm) ? _p.tm : dayjs(_p.tm)
|
||||||
|
_p.startDt = [{
|
||||||
|
field: 'startTime',
|
||||||
|
operator: 'gte',
|
||||||
|
dataType: 'date',
|
||||||
|
value: tmValue.startOf('month').format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}]
|
||||||
|
_p.endDt = [{
|
||||||
|
field: 'endTime',
|
||||||
|
operator: 'lte',
|
||||||
|
dataType: 'date',
|
||||||
|
value: tmValue.endOf('month').format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_p?.stcd) {
|
||||||
|
_p.stcd = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return omit(_p, ['dataDimensionType', 'dataDimensionVal', 'tm', 'rvcd'])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 表格列配置 ====================
|
||||||
|
|
||||||
|
const { unit } = getUnitConfigByCode('Other', 'ACTUALTEMP')
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '日期',
|
||||||
|
dataIndex: 'dt',
|
||||||
|
key: 'dt',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ record }: any) => formatDate(record.dt)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日均水温(℃)实测值',
|
||||||
|
dataIndex: 'wt',
|
||||||
|
key: 'wt',
|
||||||
|
width: 150,
|
||||||
|
customRender: ({ record }: any) => formatNumber(record.wt)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日均水温(℃)去年同期',
|
||||||
|
dataIndex: 'beforeWt',
|
||||||
|
key: 'beforeWt',
|
||||||
|
width: 150,
|
||||||
|
customRender: ({ record }: any) => formatNumber(record.beforeWt)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '天然值',
|
||||||
|
dataIndex: 'actualTemp',
|
||||||
|
key: 'actualTemp',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ record }: any) => formatNumber(record.actualTemp)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `变化趋势(${unit})`,
|
||||||
|
key: 'comparison',
|
||||||
|
width: 150,
|
||||||
|
customRender: ({ record }: any) => calculateComparison(record)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 100,
|
||||||
|
align: 'center' as const,
|
||||||
|
fixed: 'right' as const
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// ==================== 监听器 ====================
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [props.tm, props.dataDimensionVal, props.rvcd, props.stcd],
|
||||||
|
() => {
|
||||||
|
if (props.tm) formValue.tm = dayjs(props.tm)
|
||||||
|
if (props.dataDimensionVal) formValue.dataDimensionVal = props.dataDimensionVal
|
||||||
|
if (props.rvcd) formValue.rvcd = props.rvcd
|
||||||
|
if (props.stcd) formValue.stcd = props.stcd
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// ==================== 生命周期 ====================
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
initChart()
|
||||||
|
}, 100)
|
||||||
|
|
||||||
|
fetchLyData()
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('resize', handleResize)
|
||||||
|
chartInstance?.dispose()
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== 工具方法 ====================
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
chartInstance?.resize()
|
||||||
|
}
|
||||||
|
|
||||||
|
const customTransform = (res: any) => {
|
||||||
|
console.log('表格数据:', res);
|
||||||
|
return {
|
||||||
|
records: res?.data?.data || [],
|
||||||
|
total: res?.data?.total || 0
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleViewDetail = (record: any) => {
|
||||||
|
let stnm = record.stnm;
|
||||||
|
dmList.value.forEach((element: any) => {
|
||||||
|
if (element.value == formValue.stcd) {
|
||||||
|
stnm = element.label;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
modelStore.modalVisible = true;
|
||||||
|
modelStore.params.sttp = "wt_point";
|
||||||
|
modelStore.title = stnm + "详情信息";
|
||||||
|
modelStore.params.stcd = formValue.stcd;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
handleSearch,
|
||||||
|
getChartData,
|
||||||
|
getTableData
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.monthly-average-container {
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.search-form {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-wrapper {
|
||||||
|
width: 40%;
|
||||||
|
height: 600px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-wrapper {
|
||||||
|
flex: 7;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text_hocer {
|
||||||
|
color: #2f6b98;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #40a9ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-spin-nested-loading) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,31 +1,46 @@
|
|||||||
<!-- SidePanelItem.vue -->
|
<!-- SidePanelItem.vue -->
|
||||||
<template>
|
<template>
|
||||||
<SidePanelItem title="设施类型介绍">
|
<SidePanelItem title="设施类型介绍">
|
||||||
<div v-if="carouselData.length > 0" class="carousel-wrapper">
|
<a-spin :spinning="loading">
|
||||||
<a-carousel v-model:current="currentIndex" autoplay class="tech-carousel" :dot-style="{ bottom: '0px' }">
|
<div v-if="carouselData.length > 0" class="carousel-wrapper">
|
||||||
<!-- -->
|
<a-carousel v-model:current="currentIndex" autoplay class="tech-carousel" :dot-style="{ bottom: '0px' }">
|
||||||
<div v-for="(item, index) in carouselData" :key="index" class="carousel-item">
|
<!-- -->
|
||||||
<div class="image-container">
|
<div v-for="(item, index) in carouselData" :key="index" class="carousel-item">
|
||||||
<img :src="item.image" :alt="item.title" class="carousel-image" />
|
<div class="image-container" @click="handleItemClick(carouselData)">
|
||||||
|
<img :src="item.image" :alt="item.title" class="carousel-image" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</a-carousel>
|
||||||
|
<!-- 文字描述区域 -->
|
||||||
|
<div v-if="carouselData[currentIndex]" class="description-container" @click="handleItemClick(carouselData)">
|
||||||
|
<p class="item-description">{{ carouselData[currentIndex].description }}</p>
|
||||||
</div>
|
</div>
|
||||||
</a-carousel>
|
|
||||||
|
|
||||||
<!-- 文字描述区域 -->
|
|
||||||
<div v-if="carouselData[currentIndex]" class="description-container">
|
|
||||||
<p class="item-description">{{ carouselData[currentIndex].description }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-else style="width: 100%;height: 300px;display: flex; align-items: center; justify-content: center;">
|
||||||
<div v-else>
|
<a-empty description="暂无数据" />
|
||||||
<a-empty />
|
</div>
|
||||||
</div>
|
</a-spin>
|
||||||
</SidePanelItem>
|
</SidePanelItem>
|
||||||
|
|
||||||
|
<!-- 设施详情弹框 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:open="modalVisible"
|
||||||
|
:title="'设施类型介绍'"
|
||||||
|
width="1536px"
|
||||||
|
:footer="null"
|
||||||
|
>
|
||||||
|
<!-- 你在这里编写弹框内容 -->
|
||||||
|
<div v-if="currentItem">
|
||||||
|
<ArtsDetail :dataSource='currentItem' />
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
|
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
|
||||||
|
import { sttpbGetKendoList } from "@/api/sw";
|
||||||
// 定义组件名(便于调试和递归)
|
// 定义组件名(便于调试和递归)
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'diwenshuijianhuansheshileixingzuchengjijieruqingkuang'
|
name: 'diwenshuijianhuansheshileixingzuchengjijieruqingkuang'
|
||||||
@ -34,39 +49,78 @@ defineOptions({
|
|||||||
// 当前轮播索引
|
// 当前轮播索引
|
||||||
const currentIndex = ref(0);
|
const currentIndex = ref(0);
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
// 轮播图数据
|
// 轮播图数据
|
||||||
const carouselData = ref([
|
const carouselData = ref<any[]>([]);
|
||||||
{
|
|
||||||
title: '叠梁门',
|
// 弹框控制
|
||||||
description: '叠梁门是一种用于调节水库流量和控制水位的设施。在低温季节,可以通过控制叠梁门的开闭程度来调节流量,减少低温水体的进...',
|
const modalVisible = ref(false);
|
||||||
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png' // 替换为实际图片路径
|
const currentItem = ref<any>(null);
|
||||||
},
|
|
||||||
{
|
const getListData = async () => {
|
||||||
title: '环保设施',
|
loading.value = true;
|
||||||
description: '现代化环保设施,采用先进技术,有效处理工业废水废气,实现达标排放,保护生态环境...',
|
try {
|
||||||
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png'
|
const params = {
|
||||||
},
|
"filter": {
|
||||||
{
|
"logic": "and",
|
||||||
title: '智能监控',
|
"filters": [
|
||||||
description: '24 小时智能监控系统,实时监测设备运行状态,确保设施安全稳定运行...',
|
{
|
||||||
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png'
|
"field": "fullPath",
|
||||||
},
|
"operator": "contains",
|
||||||
{
|
"dataType": "string",
|
||||||
title: '水处理系统',
|
"value": "DW,DW"
|
||||||
description: '高效水处理系统,通过多级过滤和生物处理,实现水资源循环利用...',
|
},
|
||||||
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png'
|
{
|
||||||
|
"field": "logo",
|
||||||
|
"operator": "isnotnull",
|
||||||
|
"dataType": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "introduce",
|
||||||
|
"operator": "isnotnull",
|
||||||
|
"dataType": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let res = await sttpbGetKendoList(params);
|
||||||
|
let data = res?.data?.data || res?.data || [];
|
||||||
|
|
||||||
|
// 将接口返回的数据转换为轮播图格式
|
||||||
|
const baseUrl = import.meta.env.VITE_APP_PREVIEW_URL;
|
||||||
|
carouselData.value = data.map((item: any) => ({
|
||||||
|
title: item.sttpName,
|
||||||
|
description: item.introduce,
|
||||||
|
image: item.logo ? `${baseUrl}/?${item.logo}` : ''
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取设施类型数据失败:', error);
|
||||||
|
carouselData.value = [];
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
]);
|
};
|
||||||
|
|
||||||
|
// 处理项目点击事件
|
||||||
|
const handleItemClick = (item: any) => {
|
||||||
|
console.log('轮播图项目被点击:', item);
|
||||||
|
currentItem.value = item;
|
||||||
|
modalVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
// 页面加载时执行的逻辑
|
// 页面加载时执行的逻辑
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 可以在这里加载实际的图片数据
|
// 可以在这里加载实际的图片数据
|
||||||
|
getListData()
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.carousel-wrapper {
|
.carousel-wrapper {
|
||||||
width: 414px;
|
width: 414px;
|
||||||
|
|
||||||
:deep(.slick-slide) {
|
:deep(.slick-slide) {
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -77,6 +131,20 @@ onMounted(() => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.image-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 250px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
:deep() {
|
:deep() {
|
||||||
.ant-carousel .slick-dots li {
|
.ant-carousel .slick-dots li {
|
||||||
width: 5px !important;
|
width: 5px !important;
|
||||||
@ -85,27 +153,32 @@ onMounted(() => {
|
|||||||
background-color: #888e95;
|
background-color: #888e95;
|
||||||
|
|
||||||
}
|
}
|
||||||
.ant-carousel .slick-dots li button{
|
|
||||||
width: 5px !important;
|
.ant-carousel .slick-dots li button {
|
||||||
|
width: 5px !important;
|
||||||
height: 5px !important;
|
height: 5px !important;
|
||||||
border-radius: 50% !important;
|
border-radius: 50% !important;
|
||||||
background-color: #888e95;
|
background-color: #888e95;
|
||||||
}
|
}
|
||||||
.ant-carousel .slick-dots li.slick-active{
|
|
||||||
|
.ant-carousel .slick-dots li.slick-active {
|
||||||
background-color: #005293 !important;
|
background-color: #005293 !important;
|
||||||
}
|
}
|
||||||
.ant-carousel .slick-dots li.slick-active button{
|
|
||||||
|
.ant-carousel .slick-dots li.slick-active button {
|
||||||
background-color: #005293 !important;
|
background-color: #005293 !important;
|
||||||
}
|
}
|
||||||
.ant-carousel .slick-dots li :hover {
|
|
||||||
|
.ant-carousel .slick-dots li :hover {
|
||||||
width: 5px !important;
|
width: 5px !important;
|
||||||
height: 5px !important;
|
height: 5px !important;
|
||||||
border-radius: 50% !important;
|
border-radius: 50% !important;
|
||||||
background-color: #ffffffcc;
|
background-color: #ffffffcc;
|
||||||
|
|
||||||
}
|
}
|
||||||
.ant-carousel .slick-dots li button :hover{
|
|
||||||
width: 5px !important;
|
.ant-carousel .slick-dots li button :hover {
|
||||||
|
width: 5px !important;
|
||||||
height: 5px !important;
|
height: 5px !important;
|
||||||
border-radius: 50% !important;
|
border-radius: 50% !important;
|
||||||
background-color: #ffffffcc;
|
background-color: #ffffffcc;
|
||||||
@ -124,7 +197,11 @@ onMounted(() => {
|
|||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 2;
|
||||||
text-indent: 0em;
|
text-indent: 0em;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
:deep(.ant-spin-nested-loading) {
|
||||||
|
height: 300px !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -0,0 +1,379 @@
|
|||||||
|
<template>
|
||||||
|
<div class="year-average-container">
|
||||||
|
<!-- 搜索区域 -->
|
||||||
|
<a-form ref="formRef" :model="formState" layout="inline" class="search-form">
|
||||||
|
<a-form-item label="基地名称" name="dataDimensionVal">
|
||||||
|
<a-select v-model:value="formState.dataDimensionVal" placeholder="请选择" style="width: 200px"
|
||||||
|
@change="handleJdChange">
|
||||||
|
<a-select-option v-for="item in jdList" :key="item.wbsCode" :value="item.wbsCode">
|
||||||
|
{{ item.wbsName }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="断面名称" name="stcd">
|
||||||
|
<a-select v-model:value="formState.stcd" placeholder="请选择" style="width: 200px"
|
||||||
|
:loading="selectLoading">
|
||||||
|
<a-select-option v-for="item in dmList" :key="item.value" :value="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="月份" name="tm">
|
||||||
|
<a-date-picker v-model:value="formState.tm" picker="month" placeholder="请选择月份" style="width: 200px"
|
||||||
|
format="YYYY-MM" value-format="YYYY-MM-DD HH:mm:ss" />
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="handleSearch">查询</a-button>
|
||||||
|
<a-button :loading="exportLoading" @click="handleExport">
|
||||||
|
导出
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<BasicTable ref="tableRef" :scrollY="460" :columns="columns" :list-url="yearDetailGetKendoListCust"
|
||||||
|
:search-params="{ sort: sort }" :transform-data="customTransform">
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a @click="handleViewDetail(record)" class="text_hocer">查看详情</a>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</BasicTable>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed, onMounted, watch } from 'vue'
|
||||||
|
import dayjs, { Dayjs } from 'dayjs'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import { getVmsstbprpt, yearDetailGetKendoListCust } from '@/api/sw'
|
||||||
|
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'
|
||||||
|
import BasicTable from '@/components/BasicTable/index.vue';
|
||||||
|
import { useModelStore } from "@/store/modules/model";
|
||||||
|
|
||||||
|
const modelStore = useModelStore();
|
||||||
|
// 类型定义
|
||||||
|
interface FormState {
|
||||||
|
dataDimensionVal: string | number | null
|
||||||
|
tm: string | Dayjs | null
|
||||||
|
stcd: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableFilter {
|
||||||
|
startDt: string
|
||||||
|
endDt: string
|
||||||
|
stcd: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Props
|
||||||
|
const props = defineProps<{
|
||||||
|
tm?: string
|
||||||
|
dataDimensionVal?: string | number
|
||||||
|
stcd?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// Store
|
||||||
|
const jidiStore = useJidiSelectEventStore()
|
||||||
|
|
||||||
|
// Refs
|
||||||
|
const tableRef = ref()
|
||||||
|
const timeRef = ref(props.tm || '')
|
||||||
|
|
||||||
|
// State
|
||||||
|
const formState = reactive<FormState>({
|
||||||
|
dataDimensionVal: props.dataDimensionVal || '',
|
||||||
|
tm: props.tm ? dayjs(props.tm) : null,
|
||||||
|
stcd: props.stcd || ''
|
||||||
|
})
|
||||||
|
const sort = [
|
||||||
|
{
|
||||||
|
"field": "tm",
|
||||||
|
"dir": "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const selectLoading = ref(false)
|
||||||
|
const exportLoading = ref(false)
|
||||||
|
const mapModalVisible = ref(false)
|
||||||
|
const modalData = ref<any>({})
|
||||||
|
const dmList = ref<Array<{ label: string; value: string }>>([])
|
||||||
|
const isFirstLoad = ref(true)
|
||||||
|
|
||||||
|
// 基地列表(从 store 获取)
|
||||||
|
const jdList = computed(() => {
|
||||||
|
return jidiStore.jidiData || []
|
||||||
|
})
|
||||||
|
// 表格列定义
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '日期',
|
||||||
|
dataIndex: 'dt',
|
||||||
|
key: 'dt',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ text }: any) => text ? dayjs(text).format('YYYY-MM-DD') : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日均水温(℃)实测值',
|
||||||
|
dataIndex: 'wt',
|
||||||
|
key: 'wt',
|
||||||
|
width: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日均水温(℃)去年同期',
|
||||||
|
dataIndex: 'beforeWt',
|
||||||
|
key: 'beforeWt',
|
||||||
|
width: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '天然值',
|
||||||
|
dataIndex: 'naturalTemp',
|
||||||
|
key: 'naturalTemp',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ text }: any) => text ? Number(text).toFixed(1) : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 100,
|
||||||
|
align: 'center' as const,
|
||||||
|
fixed: 'right' as const
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// API 调用函数
|
||||||
|
const getTableDataApi = async (params: any) => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
// const res = await yearListGetKendoListCust(requestParams)
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取断面列表
|
||||||
|
const fetchDmData = async () => {
|
||||||
|
if (!formState.dataDimensionVal) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
selectLoading.value = true
|
||||||
|
const res = await getVmsstbprpt({
|
||||||
|
filter: {
|
||||||
|
logic: 'and',
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
"field": "sttpFullPath",
|
||||||
|
"operator": "contains",
|
||||||
|
"value": "ENV,ENVM,WT,"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "sttpCode",
|
||||||
|
"operator": "eq",
|
||||||
|
"value": "WTRV"
|
||||||
|
},
|
||||||
|
formState.dataDimensionVal != 'all' ? {
|
||||||
|
"field": "baseId",
|
||||||
|
"operator": "contains",
|
||||||
|
"value": formState.dataDimensionVal
|
||||||
|
} : null
|
||||||
|
].filter(Boolean)
|
||||||
|
},
|
||||||
|
select: [
|
||||||
|
"stcd",
|
||||||
|
"stnm",
|
||||||
|
"lgtd",
|
||||||
|
"lttd",
|
||||||
|
"baseId",
|
||||||
|
"baseName",
|
||||||
|
"siteStepSort"
|
||||||
|
],
|
||||||
|
// sort: [{ field: 'rstcdStepSort', dir: 'desc' }]
|
||||||
|
})
|
||||||
|
|
||||||
|
const resData = res?.data?.data || res?.data || []
|
||||||
|
|
||||||
|
if (resData.length > 0) {
|
||||||
|
dmList.value = resData.map((item: any) => ({
|
||||||
|
label: item.stnm,
|
||||||
|
value: item.stcd
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 如果是首次加载且有传入的 stcd,设置默认值
|
||||||
|
if (props.stcd) {
|
||||||
|
formState.stcd = props.stcd
|
||||||
|
isFirstLoad.value = false
|
||||||
|
} else {
|
||||||
|
// 非首次加载时,自动选择第一个
|
||||||
|
formState.stcd = dmList.value[0].value
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
dmList.value = []
|
||||||
|
formState.stcd = ''
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取断面列表失败:', error)
|
||||||
|
message.error('获取断面列表失败')
|
||||||
|
} finally {
|
||||||
|
selectLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基地变化处理
|
||||||
|
const handleJdChange = (value: string) => {
|
||||||
|
formState.stcd = ''
|
||||||
|
dmList.value = []
|
||||||
|
fetchDmData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = async () => {
|
||||||
|
const tmValue = dayjs.isDayjs(formState.tm) ? formState.tm : dayjs(formState.tm)
|
||||||
|
const filter = {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "stcd",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": formState.stcd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "dt",
|
||||||
|
"operator": "gte",
|
||||||
|
"dataType": "date",
|
||||||
|
value: tmValue.startOf('month').format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "dt",
|
||||||
|
"operator": "lte",
|
||||||
|
"dataType": "date",
|
||||||
|
value: tmValue.endOf('month').format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新表格
|
||||||
|
tableRef.value?.getList(filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 导出处理
|
||||||
|
const handleExport = async () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
const handleViewDetail = (record: any) => {
|
||||||
|
modelStore.modalVisible = true;
|
||||||
|
modelStore.params.sttp = "wt_point";
|
||||||
|
modelStore.title = record.stnm + "详情信息";
|
||||||
|
modelStore.params.stcd = record.stcd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const handleModalClose = () => {
|
||||||
|
mapModalVisible.value = false
|
||||||
|
modalData.value = {}
|
||||||
|
}
|
||||||
|
const customTransform = (res: any) => {
|
||||||
|
console.log('表格数据:', res);
|
||||||
|
return {
|
||||||
|
records: res?.data?.data || [],
|
||||||
|
total: res?.data?.total || 0
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听props变化
|
||||||
|
watch(
|
||||||
|
() => [props.tm, props.dataDimensionVal, props.stcd],
|
||||||
|
async ([newTm, newDataDimensionVal, newStcd], [oldTm, oldDataDimensionVal, oldStcd]) => {
|
||||||
|
// 只有当值真正发生变化时才处理
|
||||||
|
if (newTm !== oldTm || newDataDimensionVal !== oldDataDimensionVal || newStcd !== oldStcd) {
|
||||||
|
// 更新formState
|
||||||
|
formState.tm = newTm ? dayjs(newTm) : null
|
||||||
|
formState.dataDimensionVal = newDataDimensionVal || ''
|
||||||
|
formState.stcd = String(newStcd || '')
|
||||||
|
|
||||||
|
// 如果基地发生变化,需要重新获取断面列表
|
||||||
|
if (newDataDimensionVal !== oldDataDimensionVal && newDataDimensionVal) {
|
||||||
|
await fetchDmData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求数据
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// 监听基地变化
|
||||||
|
watch(
|
||||||
|
() => formState.dataDimensionVal,
|
||||||
|
async (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
await fetchDmData()
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
onMounted(async () => {
|
||||||
|
if (formState.dataDimensionVal) {
|
||||||
|
await fetchDmData()
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
handleSearch,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.year-average-container {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 600px;
|
||||||
|
|
||||||
|
.search-form {
|
||||||
|
// padding: 16px;
|
||||||
|
background: #fff;
|
||||||
|
// margin-bottom: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
:deep(.ant-form-item) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-hocer {
|
||||||
|
color: #2f6b98;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #40a9ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.text_hocer{
|
||||||
|
color: #2f6b98;
|
||||||
|
}
|
||||||
|
.text_hocer:hover{
|
||||||
|
color: #40a9ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,28 +1,140 @@
|
|||||||
<template>
|
<template>
|
||||||
<SidePanelItem title="水温年内分布">
|
<SidePanelItem title="水温年内分布" :moreSelect="select" :datetimePicker="datetimePicker"
|
||||||
<div class="water-temp-chart-container">
|
@update-values="handlePanelChange1">
|
||||||
<div ref="chartRef" class="chart-wrapper"></div>
|
<a-spin :spinning="loading" tip="加载中...">
|
||||||
</div>
|
<div v-show="!loading && showemit" class="water-temp-chart-container">
|
||||||
<!-- <div v-else>
|
<div ref="chartRef" class="chart-wrapper"></div>
|
||||||
<a-empty />
|
</div>
|
||||||
</div> -->
|
<div v-show="!loading && !showemit" class="water-temp-chart-container">
|
||||||
|
<a-empty description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
</SidePanelItem>
|
</SidePanelItem>
|
||||||
|
|
||||||
|
<!-- 数据点详情弹框 -->
|
||||||
|
<a-modal v-model:open="modalVisible" title="水温数据详情" :footer="null" width="1536px" @cancel="handleModalClose">
|
||||||
|
<YaerAverage :tm="`${datetimePicker.value}-${String(currentData.monthInt).padStart(2, '0')}-01 00:00:00`"
|
||||||
|
:dataDimensionVal="baseid" :stcd="select.value" />
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
const data = [
|
import { getVmsstbprpt, yearListGetKendoListCust } from "@/api/sw";
|
||||||
{ monthInt: 1, actualTemp: 0.9, naturalTemp: 0 },
|
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||||
{ monthInt: 2, actualTemp: 0.9, naturalTemp: 0.1 },
|
import YaerAverage from "./TwoLayers/yaerAverage.vue"
|
||||||
{ monthInt: 3, actualTemp: 1.0, naturalTemp: 2.0 }
|
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||||
]
|
// 水温年内分布数据(响应式)
|
||||||
|
const waterTempData = ref<any[]>([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const showemit = ref(true)
|
||||||
|
// 弹框相关状态
|
||||||
|
const modalVisible = ref(false)
|
||||||
|
const currentData = ref<any>({})
|
||||||
|
const jiDiList: any = ref([
|
||||||
|
{
|
||||||
|
"baseid": "all",
|
||||||
|
"basename": "当前全部",
|
||||||
|
"id": "9BFEC848-83EA-AD22-6DE2-10E969476693"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "01",
|
||||||
|
"basename": "金沙江干流",
|
||||||
|
"id": "A33040B7-8977-D9F1-5E02-D7F0241AB8AA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "02",
|
||||||
|
"basename": "雅砻江干流",
|
||||||
|
"id": "C63D6020-995D-FE97-2F4A-F619A7142C79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "03",
|
||||||
|
"basename": "大渡河干流",
|
||||||
|
"id": "CCB0766B-F1D4-7DD6-650F-5C556B7231B3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "04",
|
||||||
|
"basename": "乌江干流",
|
||||||
|
"id": "E8A66641-B4F4-CC85-0815-38C5B2F93DBD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "05",
|
||||||
|
"basename": "长江上游干流",
|
||||||
|
"id": "E02C11E9-CEA5-A030-202F-3BFE84465D03"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "10",
|
||||||
|
"basename": "湘西",
|
||||||
|
"id": "B1D1D52D-CEEF-6DC4-27DF-9990EB572F8D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "08",
|
||||||
|
"basename": "黄河上游干流",
|
||||||
|
"id": "BC6AF135-263D-09A9-D5CA-C99B2598FE6E"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "09",
|
||||||
|
"basename": "黄河中游干流",
|
||||||
|
"id": "60EEEC28-128F-A2A8-44F3-6EAAC8FD8BB6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "06",
|
||||||
|
"basename": "南盘江-红水河",
|
||||||
|
"id": "7BB9A8F4-34B5-42B4-A7FC-CE910AD7F203"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "12",
|
||||||
|
"basename": "东北",
|
||||||
|
"id": "47F8EF06-924E-E161-FCAF-62A66BBF252D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "07",
|
||||||
|
"basename": "澜沧江干流",
|
||||||
|
"id": "A966A4C9-278C-B0DA-2B97-2D10B7A6E96A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "13",
|
||||||
|
"basename": "怒江干流",
|
||||||
|
"id": "FA89E8CB-67A8-76DA-DC1E-23AE4C54F9E4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "11",
|
||||||
|
"basename": "闽浙赣",
|
||||||
|
"id": "CD98F995-EEB2-1021-D807-DA1B1AD9E49A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"baseid": "other",
|
||||||
|
"basename": "其他",
|
||||||
|
"id": "AFBDFC67-B955-4EFD-959A-014CFB59EBFC"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
const chartRef = ref<HTMLElement | null>(null)
|
const chartRef = ref<HTMLElement | null>(null)
|
||||||
let chartInstance: echarts.ECharts | null = null
|
let chartInstance: echarts.ECharts | null = null
|
||||||
|
// 选择器配置
|
||||||
|
const select = ref({
|
||||||
|
show: true,
|
||||||
|
value: '',
|
||||||
|
options: [],
|
||||||
|
picker: undefined,
|
||||||
|
format: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 日期选择器配置
|
||||||
|
const datetimePicker = ref({
|
||||||
|
show: true,
|
||||||
|
value: (() => {
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.getFullYear();
|
||||||
|
return `${year}`;
|
||||||
|
})(),
|
||||||
|
format: "YYYY",
|
||||||
|
picker: "year" as const,
|
||||||
|
options: [],
|
||||||
|
});
|
||||||
const transUnit = (value: number | null) => {
|
const transUnit = (value: number | null) => {
|
||||||
if (value === null) return null
|
if (value === null) return null
|
||||||
return value
|
return value
|
||||||
@ -38,6 +150,209 @@ const getColorByCodeAndType = (_code: string[], _typeKey: string[]) => {
|
|||||||
return ['#4b79ab', '#78c300']
|
return ['#4b79ab', '#78c300']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理图表数据点点击事件
|
||||||
|
const handleChartClick = (params: any) => {
|
||||||
|
if (!params || !params.dataIndex) return
|
||||||
|
|
||||||
|
// 获取点击的数据点索引
|
||||||
|
const dataIndex = params.dataIndex
|
||||||
|
const dataItem = waterTempData.value[dataIndex]
|
||||||
|
|
||||||
|
if (dataItem) {
|
||||||
|
currentData.value = {
|
||||||
|
...dataItem,
|
||||||
|
stnm: select.value.options.find((opt: any) =>
|
||||||
|
opt.children?.some((child: any) => child.value === select.value.value)
|
||||||
|
)?.children?.find((child: any) => child.value === select.value.value)?.title || '未知站点'
|
||||||
|
}
|
||||||
|
modalVisible.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹框
|
||||||
|
const handleModalClose = () => {
|
||||||
|
modalVisible.value = false
|
||||||
|
currentData.value = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下拉框数据选择
|
||||||
|
const getselectData = async () => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
filter: {
|
||||||
|
logic: "and",
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
field: "sttpFullPath",
|
||||||
|
operator: "contains",
|
||||||
|
value: "ENV,ENVM,WT,"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "sttpCode",
|
||||||
|
operator: "eq",
|
||||||
|
value: "WTRV"
|
||||||
|
},
|
||||||
|
baseid.value !== 'all' ? {
|
||||||
|
field: "baseId",
|
||||||
|
operator: "contains",
|
||||||
|
value: baseid.value
|
||||||
|
} : null
|
||||||
|
].filter(Boolean)
|
||||||
|
},
|
||||||
|
select: [
|
||||||
|
"stcd", "stnm", "lgtd", "lttd",
|
||||||
|
"baseId", "baseName", "siteStepSort"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getVmsstbprpt(params)
|
||||||
|
|
||||||
|
// if (!res?.data?.length) {
|
||||||
|
// select.value.options = []
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
let data = res?.data?.date || res?.data || []
|
||||||
|
// 设置默认选中值(第一个站点的 stcd)
|
||||||
|
if (res.data) {
|
||||||
|
select.value.value = data?.data[0]?.stcd
|
||||||
|
} else {
|
||||||
|
select.value.value = ''
|
||||||
|
}
|
||||||
|
// 按 baseId 分组
|
||||||
|
const dataMapNameMap: Record<string, any[]> = {}
|
||||||
|
data.data.forEach((item: any) => {
|
||||||
|
const { baseId } = item
|
||||||
|
if (dataMapNameMap[baseId]) {
|
||||||
|
dataMapNameMap[baseId].push(item)
|
||||||
|
} else {
|
||||||
|
dataMapNameMap[baseId] = [item]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 构建树形结构
|
||||||
|
const dataMapNameArr: any[] = []
|
||||||
|
const otherArr: any[] = []
|
||||||
|
|
||||||
|
Object.keys(dataMapNameMap).forEach((baseId: string) => {
|
||||||
|
const stations = dataMapNameMap[baseId]
|
||||||
|
|
||||||
|
const treeItem = {
|
||||||
|
title: stations[0]?.baseName,
|
||||||
|
value: baseId,
|
||||||
|
selectable: false,
|
||||||
|
children: stations
|
||||||
|
.sort((a, b) => a.siteStepSort - b.siteStepSort)
|
||||||
|
.map((station) => ({
|
||||||
|
title: station.stnm,
|
||||||
|
value: station.stcd,
|
||||||
|
lgtd: station.lgtd,
|
||||||
|
lttd: station.lttd
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 区分普通基地和 other 基地
|
||||||
|
if (+baseId) {
|
||||||
|
dataMapNameArr.push(treeItem)
|
||||||
|
} else if (baseId === 'other') {
|
||||||
|
otherArr.push(treeItem)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 按 jiDiList 顺序排序普通基地
|
||||||
|
dataMapNameArr.sort((a, b) => {
|
||||||
|
const indexA = jiDiList.value.findIndex((item: any) => item.baseid === a.value)
|
||||||
|
const indexB = jiDiList.value.findIndex((item: any) => item.baseid === b.value)
|
||||||
|
return indexA - indexB
|
||||||
|
})
|
||||||
|
|
||||||
|
// 合并结果并设置选项
|
||||||
|
select.value.options = [...dataMapNameArr, ...otherArr]
|
||||||
|
|
||||||
|
|
||||||
|
// debugger
|
||||||
|
// if (baseid.value == 'all') {
|
||||||
|
// select.value.value = '008640202300001021'
|
||||||
|
// }
|
||||||
|
// else if (data.data.length > 0) {
|
||||||
|
// select.value.value = data.data[0].stcd
|
||||||
|
// }
|
||||||
|
getshuiwenList()
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取站点数据失败:', error)
|
||||||
|
select.value.options = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//水温年内分布
|
||||||
|
const getshuiwenList = async () => {
|
||||||
|
if (loading.value) return; // 防止重复请求
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "stcd",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": select.value.value
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "year",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": datetimePicker.value.value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sort": [
|
||||||
|
{
|
||||||
|
"field": "month",
|
||||||
|
"dir": "asc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res = await yearListGetKendoListCust(params)
|
||||||
|
let data = res?.data?.data || res?.data || []
|
||||||
|
|
||||||
|
// 处理空数据情况
|
||||||
|
if (data.length === 0) {
|
||||||
|
showemit.value = false
|
||||||
|
waterTempData.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showemit.value = true
|
||||||
|
|
||||||
|
// 更新响应式数据
|
||||||
|
waterTempData.value = data
|
||||||
|
|
||||||
|
// 重新渲染图表
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!chartInstance) {
|
||||||
|
initChart()
|
||||||
|
} else {
|
||||||
|
const option = getChartOption()
|
||||||
|
chartInstance.setOption(option, true)
|
||||||
|
}
|
||||||
|
// 强制重绘,确保尺寸正确
|
||||||
|
setTimeout(() => {
|
||||||
|
chartInstance?.resize()
|
||||||
|
}, 100)
|
||||||
|
}, 50)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取水温数据失败:', error)
|
||||||
|
showemit.value = false
|
||||||
|
waterTempData.value = []
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getChartOption = () => {
|
const getChartOption = () => {
|
||||||
const { unit } = getUnitConfigByCode('Other', 'ACTUALTEMP')
|
const { unit } = getUnitConfigByCode('Other', 'ACTUALTEMP')
|
||||||
const legendData = ['实测值', '天然']
|
const legendData = ['实测值', '天然']
|
||||||
@ -45,7 +360,8 @@ const getChartOption = () => {
|
|||||||
const actualData: (number | null)[] = []
|
const actualData: (number | null)[] = []
|
||||||
const naturalData: (number | null)[] = []
|
const naturalData: (number | null)[] = []
|
||||||
|
|
||||||
data.forEach((item: any) => {
|
// 使用响应式数据waterTempData替代静态data
|
||||||
|
waterTempData.value.forEach((item: any) => {
|
||||||
xData.push(`${item.monthInt}月`)
|
xData.push(`${item.monthInt}月`)
|
||||||
actualData.push(item.actualTemp === null ? null : transUnit(item.actualTemp))
|
actualData.push(item.actualTemp === null ? null : transUnit(item.actualTemp))
|
||||||
naturalData.push(item.naturalTemp === null ? null : transUnit(item.naturalTemp))
|
naturalData.push(item.naturalTemp === null ? null : transUnit(item.naturalTemp))
|
||||||
@ -65,7 +381,7 @@ const getChartOption = () => {
|
|||||||
color: '#ffffff',
|
color: '#ffffff',
|
||||||
fontSize: 14
|
fontSize: 14
|
||||||
},
|
},
|
||||||
formatter: function(params: any) {
|
formatter: function (params: any) {
|
||||||
if (!params || params.length === 0) return '';
|
if (!params || params.length === 0) return '';
|
||||||
let result = `<div style="font-weight: bold; margin-bottom: 8px;">${params[0].axisValue}</div>`;
|
let result = `<div style="font-weight: bold; margin-bottom: 8px;">${params[0].axisValue}</div>`;
|
||||||
params.forEach((item: any) => {
|
params.forEach((item: any) => {
|
||||||
@ -77,6 +393,18 @@ const getChartOption = () => {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: 'inside',
|
||||||
|
start: 0,
|
||||||
|
end: 100,
|
||||||
|
xAxisIndex: [0],
|
||||||
|
filterMode: 'filter',
|
||||||
|
zoomOnMouseWheel: true,
|
||||||
|
moveOnMouseMove: false,
|
||||||
|
moveOnMouseWheel: false
|
||||||
|
}
|
||||||
|
],
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
boundaryGap: true,
|
boundaryGap: true,
|
||||||
@ -96,12 +424,12 @@ const getChartOption = () => {
|
|||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: true,
|
show: true,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#bfbfbf',
|
color: '#bfbfbf',
|
||||||
type: 'solid'
|
type: 'solid'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
interval: 0,
|
interval: 0,
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
@ -154,7 +482,7 @@ const getChartOption = () => {
|
|||||||
legend: {
|
legend: {
|
||||||
data: legendData
|
data: legendData
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
top: 30,
|
top: 30,
|
||||||
bottom: 50,
|
bottom: 50,
|
||||||
right: 15,
|
right: 15,
|
||||||
@ -204,6 +532,10 @@ const initChart = async () => {
|
|||||||
const option = getChartOption()
|
const option = getChartOption()
|
||||||
chartInstance.setOption(option, false)
|
chartInstance.setOption(option, false)
|
||||||
|
|
||||||
|
// 添加点击事件监听
|
||||||
|
chartInstance.off('click')
|
||||||
|
chartInstance.on('click', handleChartClick)
|
||||||
|
|
||||||
// 强制重绘,确保图表尺寸正确
|
// 强制重绘,确保图表尺寸正确
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
chartInstance?.resize()
|
chartInstance?.resize()
|
||||||
@ -222,7 +554,13 @@ const handleResize = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
// 初始化图表
|
||||||
initChart()
|
initChart()
|
||||||
|
|
||||||
|
// 加载初始数据
|
||||||
|
if (select.value.value) {
|
||||||
|
getshuiwenList()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@ -232,18 +570,43 @@ onBeforeUnmount(() => {
|
|||||||
chartInstance = null
|
chartInstance = null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
//监听子组件的数据变化
|
||||||
|
const handlePanelChange1 = (data) => {
|
||||||
|
console.log('当前所有控件状态:', data);
|
||||||
|
|
||||||
|
// 当选择器或日期变化时,重新加载图表数据
|
||||||
|
if (data.moreSelect || data.datetime) {
|
||||||
|
select.value.value = data.moreSelect
|
||||||
|
getshuiwenList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const baseid = ref('')
|
||||||
|
watch(
|
||||||
|
() => JidiSelectEventStore.selectedItem,
|
||||||
|
(newVal) => {
|
||||||
|
baseid.value = newVal.wbsCode;
|
||||||
|
getselectData()
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.water-temp-chart-container {
|
.water-temp-chart-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 290px;
|
||||||
min-height: 290px;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-wrapper {
|
.chart-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 290px;
|
}
|
||||||
|
|
||||||
|
:deep(.ant-spin-nested-loading) {
|
||||||
|
height: 290px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -3,7 +3,8 @@
|
|||||||
<SidePanelItem title="水温监测工作开展情况">
|
<SidePanelItem title="水温监测工作开展情况">
|
||||||
<a-spin :spinning="loading" tip="加载中...">
|
<a-spin :spinning="loading" tip="加载中...">
|
||||||
<div class="facility-grid">
|
<div class="facility-grid">
|
||||||
<div v-for="facility in facilities" :key="facility.name" class="facility-card">
|
<div v-for="facility in facilities" :key="facility.name" class="facility-card"
|
||||||
|
@click="handleFacilityClick(facility)">
|
||||||
<div style="
|
<div style="
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 62px;
|
height: 62px;
|
||||||
@ -25,6 +26,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
|
|
||||||
|
<!-- 弹框 -->
|
||||||
|
<a-modal v-model:open="modalVisible" :title="'水温监测工作开展情况'" :footer="null" width="1536px" @cancel="handleCloseModal">
|
||||||
|
<ShuiwenjiancegongzuoEJ v-if="currentFacility" :activeKey="currentFacility.key" :tabs="facilities" :baseId="baseid" />
|
||||||
|
</a-modal>
|
||||||
</SidePanelItem>
|
</SidePanelItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -33,7 +39,7 @@ import { ref, onMounted, watch } from "vue";
|
|||||||
import SidePanelItem from "@/components/SidePanelItem/index.vue";
|
import SidePanelItem from "@/components/SidePanelItem/index.vue";
|
||||||
import { getKendoListCust, baseEvnmAutoMonitorGetKendoListCust } from "@/api/sw";
|
import { getKendoListCust, baseEvnmAutoMonitorGetKendoListCust } from "@/api/sw";
|
||||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||||
|
import ShuiwenjiancegongzuoEJ from "./shuiwenjiancegongzuoEJ.vue"
|
||||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||||
// 定义组件名(便于调试和递归)
|
// 定义组件名(便于调试和递归)
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@ -46,17 +52,38 @@ const facilities = ref([
|
|||||||
name: "表层水温",
|
name: "表层水温",
|
||||||
count: 0,
|
count: 0,
|
||||||
icon: "icon iconfont icon-shuizhijiancezhan",
|
icon: "icon iconfont icon-shuizhijiancezhan",
|
||||||
|
key:'26'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "垂向水温",
|
name: "垂向水温",
|
||||||
count: 0,
|
count: 0,
|
||||||
icon: "icon iconfont icon-diwenshuijianhuan",
|
icon: "icon iconfont icon-diwenshuijianhuan",
|
||||||
|
key:'27'
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Loading 状态
|
// Loading 状态
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
// 弹框相关状态
|
||||||
|
const modalVisible = ref(false);
|
||||||
|
const currentFacility = ref<any>(null);
|
||||||
|
|
||||||
|
// 点击处理函数
|
||||||
|
const handleFacilityClick = (facility: any) => {
|
||||||
|
// console.log(facility);
|
||||||
|
currentFacility.value = facility;
|
||||||
|
modalVisible.value = true;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭弹框
|
||||||
|
const handleCloseModal = () => {
|
||||||
|
modalVisible.value = false;
|
||||||
|
currentFacility.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
// 防重复请求
|
// 防重复请求
|
||||||
if (loading.value) return;
|
if (loading.value) return;
|
||||||
@ -79,7 +106,7 @@ const init = async () => {
|
|||||||
"field": "baseId",
|
"field": "baseId",
|
||||||
"operator": "eq",
|
"operator": "eq",
|
||||||
"value": baseid.value
|
"value": baseid.value
|
||||||
}:null
|
} : null
|
||||||
].filter(Boolean)
|
].filter(Boolean)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,548 @@
|
|||||||
|
<template>
|
||||||
|
<div class="shuiwenjiancegongzwo-ej-container">
|
||||||
|
<!-- Tab切换 -->
|
||||||
|
<a-tabs v-model:activeKey="tabIndex" @change="handleTabChange">
|
||||||
|
<a-tab-pane v-for="tab in tabs" :key="tab.key" :tab="tab.name" />
|
||||||
|
</a-tabs>
|
||||||
|
|
||||||
|
<!-- 搜索表单 -->
|
||||||
|
<div class="search-form">
|
||||||
|
<a-space size="middle">
|
||||||
|
<div>选择水电站:</div>
|
||||||
|
<a-select v-model:value="searchData.stcd.dataDimensionData" placeholder="请选择水电站" style="width: 200px"
|
||||||
|
@change="handleHydropowerStationChange">
|
||||||
|
<a-select-option v-for="station in hydropowerStationList" :key="station.wbsCode"
|
||||||
|
:value="station.wbsCode">
|
||||||
|
{{ station.wbsName }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-select v-model:value="searchData.stnm" placeholder=" " style="width: 200px" allow-clear
|
||||||
|
@change="handleStationChange">
|
||||||
|
<a-select-option v-for="station in stationDataList" :key="station.wbsCode" :value="station.stcd">
|
||||||
|
{{ station.stnm }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<!-- <a-input v-model:value="searchData.stnm" placeholder="请输入测站名称" style="width: 200px" allow-clear /> -->
|
||||||
|
|
||||||
|
<a-button type="primary" @click="handleSearch">查询</a-button>
|
||||||
|
<a-tooltip title="重置">
|
||||||
|
<a-button @click="handleReset">重置</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据表格 -->
|
||||||
|
<a-table :columns="columns" :data-source="tableData" :loading="loading" :pagination="pagination"
|
||||||
|
:scroll="{ y: tableHeight }" row-key="stcd" @change="handleTableChange">
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<!-- 监测状态 -->
|
||||||
|
<template v-if="column.key === 'coenvwState'">
|
||||||
|
<a-tooltip placement="top">
|
||||||
|
<template #title>
|
||||||
|
<ol>
|
||||||
|
<li>最近1天有监测数据为在线,否则为离线。</li>
|
||||||
|
</ol>
|
||||||
|
</template>
|
||||||
|
<a-tag :color="record.coenvwState > 0 ? 'green' : '#999'">
|
||||||
|
{{ record.coenvwState > 0 ? '在线' : '离线' }}
|
||||||
|
</a-tag>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 操作 -->
|
||||||
|
<template v-else-if="column.key === 'action'">
|
||||||
|
<a @click="handleViewDetail(record)" class="text_hocer" >查看详情</a>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed, watch, onMounted } from 'vue'
|
||||||
|
import { vmsstbprptGetKendoList, wbsbGetKendoList, getVmsstbprpt } from '@/api/sw'
|
||||||
|
import { useModelStore } from "@/store/modules/model";
|
||||||
|
|
||||||
|
const modelStore = useModelStore();
|
||||||
|
// ==================== Props 定义 ====================
|
||||||
|
const props = defineProps<{
|
||||||
|
baseId?: string
|
||||||
|
tabs?: any[]
|
||||||
|
activeKey?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// ==================== 状态管理 ====================
|
||||||
|
const tabIndex = ref(props.activeKey || '26')
|
||||||
|
const loading = ref(false)
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
const pagination = ref({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
total: 0,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showTotal: (total: number) => `共 ${total} 条`,
|
||||||
|
pageSizeOptions: ['10', '20', '50', '100']
|
||||||
|
})
|
||||||
|
const tableHeight = 'calc(48vh)'
|
||||||
|
|
||||||
|
// 水电站列表数据
|
||||||
|
const hydropowerStationList = ref<any[]>([])
|
||||||
|
const stationDataList: any = ref([])
|
||||||
|
const searchData = ref<any>({
|
||||||
|
stcd: {
|
||||||
|
dataDimensionType: 'hyBase',
|
||||||
|
stcdId: '',
|
||||||
|
dataDimensionData: props.baseId || 'all'
|
||||||
|
},
|
||||||
|
stnm: null
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== 计算合并信息 ====================
|
||||||
|
const getRowSpanInfo = (dataIndex: string) => {
|
||||||
|
const spanMap = new Map()
|
||||||
|
|
||||||
|
if (!tableData.value || tableData.value.length === 0) {
|
||||||
|
return spanMap
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentGroupStart = 0
|
||||||
|
let currentValue = tableData.value[0][dataIndex]
|
||||||
|
|
||||||
|
for (let i = 0; i < tableData.value.length; i++) {
|
||||||
|
const value = tableData.value[i][dataIndex]
|
||||||
|
|
||||||
|
if (value !== currentValue) {
|
||||||
|
// 记录当前组的起始位置和行数
|
||||||
|
spanMap.set(currentGroupStart, i - currentGroupStart)
|
||||||
|
currentGroupStart = i
|
||||||
|
currentValue = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理最后一组
|
||||||
|
spanMap.set(currentGroupStart, tableData.value.length - currentGroupStart)
|
||||||
|
|
||||||
|
return spanMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 监听 Props 变化 ====================
|
||||||
|
// const baseId = ref('')
|
||||||
|
watch(
|
||||||
|
() => props.baseId,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal && newVal !== searchData.value.stcd.dataDimensionData) {
|
||||||
|
searchData.value.stcd.dataDimensionData = newVal
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.activeKey,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal && newVal !== tabIndex.value) {
|
||||||
|
tabIndex.value = newVal
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== 列配置 ====================
|
||||||
|
const columns = computed(() => {
|
||||||
|
const baseColumns = [
|
||||||
|
{
|
||||||
|
title: '所属基地',
|
||||||
|
dataIndex: 'baseName',
|
||||||
|
key: 'baseName',
|
||||||
|
width: 150,
|
||||||
|
customCell: (record: any, index: number) => {
|
||||||
|
const spanMap = getRowSpanInfo('baseName')
|
||||||
|
const rowSpan = spanMap.get(index)
|
||||||
|
|
||||||
|
if (rowSpan === undefined) {
|
||||||
|
// 被合并的行,不显示
|
||||||
|
return { rowSpan: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一行,设置合并行数
|
||||||
|
return { rowSpan }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '测站名称',
|
||||||
|
dataIndex: 'stnm',
|
||||||
|
key: 'stnm',
|
||||||
|
width: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '电站',
|
||||||
|
dataIndex: 'ennm',
|
||||||
|
key: 'ennm',
|
||||||
|
width: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '建成时间',
|
||||||
|
dataIndex: 'jcdt',
|
||||||
|
key: 'jcdt',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '监测指标',
|
||||||
|
dataIndex: 'stindx',
|
||||||
|
key: 'stindx',
|
||||||
|
width: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '监测状态',
|
||||||
|
key: 'coenvwState',
|
||||||
|
dataIndex: 'coenvwState',
|
||||||
|
width: 100,
|
||||||
|
align: 'center' as const
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 100,
|
||||||
|
align: 'center' as const,
|
||||||
|
fixed: 'right' as const
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return baseColumns.filter(Boolean)
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== 过滤条件构建 ====================
|
||||||
|
const buildSearchFilter = () => {
|
||||||
|
const filters: any[] = []
|
||||||
|
|
||||||
|
// 基地ID过滤
|
||||||
|
if (searchData.value?.stcd?.dataDimensionData && searchData.value.stcd.dataDimensionData !== 'all') {
|
||||||
|
filters.push({
|
||||||
|
field: 'baseId',
|
||||||
|
operator: 'eq',
|
||||||
|
value: searchData.value.stcd.dataDimensionData
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测站ID过滤
|
||||||
|
if (searchData.value?.stcd?.stcdId) {
|
||||||
|
filters.push({
|
||||||
|
field: 'rstcd',
|
||||||
|
operator: 'eq',
|
||||||
|
value: searchData.value.stcd.stcdId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测站名称模糊搜索
|
||||||
|
if (searchData.value?.stnm) {
|
||||||
|
filters.push({
|
||||||
|
field: 'rstcd',
|
||||||
|
operator: 'eq',
|
||||||
|
value: searchData.value.stnm
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tab特定过滤
|
||||||
|
switch (tabIndex.value) {
|
||||||
|
case '26':
|
||||||
|
filters.push(
|
||||||
|
{
|
||||||
|
field: 'mway',
|
||||||
|
operator: 'eq',
|
||||||
|
dataType: 'string',
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'sttpCode',
|
||||||
|
operator: 'eq',
|
||||||
|
dataType: 'string',
|
||||||
|
value: 'WTRV'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break
|
||||||
|
case '27':
|
||||||
|
filters.push(
|
||||||
|
{
|
||||||
|
field: 'mway',
|
||||||
|
operator: 'eq',
|
||||||
|
dataType: 'string',
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'sttpCode',
|
||||||
|
operator: 'eq',
|
||||||
|
dataType: 'string',
|
||||||
|
value: 'WTVT'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
logic: 'and',
|
||||||
|
filters: filters.filter((f) => f.value !== undefined && f.value !== null && f.value !== '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== API调用 ====================
|
||||||
|
const fetchData = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const filter = buildSearchFilter()
|
||||||
|
const params = {
|
||||||
|
filter: filter,
|
||||||
|
select: [
|
||||||
|
'baseName',
|
||||||
|
'stnm',
|
||||||
|
'ennm',
|
||||||
|
'jcdt',
|
||||||
|
'stindx',
|
||||||
|
'coenvwState',
|
||||||
|
'sttpCode',
|
||||||
|
'stcd',
|
||||||
|
'rstcd',
|
||||||
|
'stCode',
|
||||||
|
'stName',
|
||||||
|
'dvtp'
|
||||||
|
],
|
||||||
|
sort: [
|
||||||
|
{ field: 'baseStepSort', dir: 'asc' },
|
||||||
|
{ field: 'hbrvcd', dir: 'asc' },
|
||||||
|
{ field: 'rstcdStepSort', dir: 'asc' },
|
||||||
|
{ field: 'siteStepSort', dir: 'asc' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('【请求参数】', params)
|
||||||
|
const res = await vmsstbprptGetKendoList(params)
|
||||||
|
console.log('【响应数据】', res)
|
||||||
|
|
||||||
|
// 数据处理
|
||||||
|
let total = res.data.total
|
||||||
|
let records = res?.data?.data || res?.data
|
||||||
|
// debugger
|
||||||
|
// if (Array.isArray(res?.data?.data)) {
|
||||||
|
// records = res.data.data
|
||||||
|
// total = res.data.data.length
|
||||||
|
// }
|
||||||
|
|
||||||
|
tableData.value = records || []
|
||||||
|
pagination.value.total = total
|
||||||
|
loading.value = false
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取水文监测数据失败:', error)
|
||||||
|
tableData.value = []
|
||||||
|
pagination.value.total = 0
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getselect = async () => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"field": "wbsType",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "PSB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "treeLevel",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sort": [
|
||||||
|
{
|
||||||
|
"field": "orderIndex",
|
||||||
|
"dir": "asc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await wbsbGetKendoList(params)
|
||||||
|
console.log('【水电站列表】', res)
|
||||||
|
|
||||||
|
// 数据处理:提取水电站列表
|
||||||
|
if (res?.data?.data && Array.isArray(res.data.data)) {
|
||||||
|
hydropowerStationList.value = res.data.data
|
||||||
|
console.log('站点数据列表', stationDataList.value)
|
||||||
|
getselectTwo(searchData.value.stcd.dataDimensionData)
|
||||||
|
console.log('【水电站数量】', hydropowerStationList.value.length)
|
||||||
|
} else {
|
||||||
|
console.warn('【警告】未获取到有效的水电站数据')
|
||||||
|
hydropowerStationList.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('【错误】获取水电站列表失败:', error)
|
||||||
|
hydropowerStationList.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getselectTwo = async (code: any) => {
|
||||||
|
console.log('站点数据列表')
|
||||||
|
const params = {
|
||||||
|
"filter": {
|
||||||
|
"logic": "and",
|
||||||
|
"filters": [
|
||||||
|
code != 'all' ? {
|
||||||
|
"field": "baseId",
|
||||||
|
"operator": "contains",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": code
|
||||||
|
} : null,
|
||||||
|
{
|
||||||
|
"field": "sttpCode",
|
||||||
|
"operator": "eq",
|
||||||
|
"dataType": "string",
|
||||||
|
"value": "ENG"
|
||||||
|
}
|
||||||
|
].filter(Boolean)
|
||||||
|
},
|
||||||
|
"sort": code !== 'all'
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
"field": "baseId",
|
||||||
|
"dir": "asc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "rvcdStepSort",
|
||||||
|
"dir": "asc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "rstcdStepSort",
|
||||||
|
"dir": "asc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "siteStepSort",
|
||||||
|
"dir": "asc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
"field": "ttpwr",
|
||||||
|
"dir": "desc"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"select": [
|
||||||
|
"stcd",
|
||||||
|
"stnm"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const res = await getVmsstbprpt(params)
|
||||||
|
// console.log('结果', res)
|
||||||
|
console.log('站点数据列表', res?.data?.data)
|
||||||
|
stationDataList.value = res?.data?.data || res?.data
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 事件处理 ====================
|
||||||
|
const handleHydropowerStationChange = (value: string) => {
|
||||||
|
console.log('【水电站选择变化】', value)
|
||||||
|
// 清空测站选择
|
||||||
|
searchData.value.stnm = null
|
||||||
|
searchData.value.stcd.stcdId = ''
|
||||||
|
// 获取该水电站下的测站列表
|
||||||
|
getselectTwo(value)
|
||||||
|
// 重新查询数据
|
||||||
|
// pagination.value.current = 1
|
||||||
|
// fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleStationChange = (value: string | undefined) => {
|
||||||
|
console.log('【测站选择变化】', value)
|
||||||
|
// 更新测站ID
|
||||||
|
if (value) {
|
||||||
|
searchData.value.stcd.stcdId = value
|
||||||
|
} else {
|
||||||
|
searchData.value.stcd.stcdId = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
console.log('【搜索】', searchData.value)
|
||||||
|
pagination.value.current = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
console.log('【重置】')
|
||||||
|
searchData.value = {
|
||||||
|
stcd: {
|
||||||
|
dataDimensionType: 'hyBase',
|
||||||
|
stcdId: '',
|
||||||
|
dataDimensionData: props.baseId || 'all'
|
||||||
|
},
|
||||||
|
stnm: null
|
||||||
|
}
|
||||||
|
pagination.value.current = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTabChange = (key: string) => {
|
||||||
|
console.log('【Tab切换】', key)
|
||||||
|
tabIndex.value = key
|
||||||
|
pagination.value.current = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTableChange = (pag: any) => {
|
||||||
|
pagination.value.current = pag.current
|
||||||
|
pagination.value.pageSize = pag.pageSize
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleViewDetail = (record: any) => {
|
||||||
|
if (record) {
|
||||||
|
modelStore.modalVisible = true;
|
||||||
|
modelStore.params.sttp = "wt_point";
|
||||||
|
modelStore.title = record.stnm + "详情信息";
|
||||||
|
// modelStore.isBasicEdit = true;
|
||||||
|
modelStore.params.stcd = record.stcd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 后续实现详情查看功能
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 生命周期 ====================
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('【组件挂载】水文监测工作二级页面已加载')
|
||||||
|
fetchData()
|
||||||
|
getselect()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.shuiwenjiancegongzwo-ej-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.search-form {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-wrapper) {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.text_hocer{
|
||||||
|
color: #2f6b98;
|
||||||
|
}
|
||||||
|
.text_hocer:hover{
|
||||||
|
color: #40a9ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -2,7 +2,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<SidePanelItem title="沿程水温变化" :prompt="prompts" :moreSelect="select" :datetimePicker="datetimePicker"
|
<SidePanelItem title="沿程水温变化" :prompt="prompts" :moreSelect="select" :datetimePicker="datetimePicker"
|
||||||
@update-values="handlePanelChange1">
|
@update-values="handlePanelChange1">
|
||||||
<a-spin :spinning="loading" tip="加载中..." >
|
<a-spin :spinning="loading" tip="加载中...">
|
||||||
<div v-show="showemit && !loading" ref="chartRef" class="chart-container"></div>
|
<div v-show="showemit && !loading" ref="chartRef" class="chart-container"></div>
|
||||||
<div v-show="!showemit && !loading" class="chart-container"> <a-empty /></div>
|
<div v-show="!showemit && !loading" class="chart-container"> <a-empty /></div>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
@ -17,8 +17,12 @@ import type { ECharts } from "echarts";
|
|||||||
import SidePanelItem from "@/components/SidePanelItem/index.vue";
|
import SidePanelItem from "@/components/SidePanelItem/index.vue";
|
||||||
import { getKendoListCust, wbsbGetKendoList } from "@/api/sw";
|
import { getKendoListCust, wbsbGetKendoList } from "@/api/sw";
|
||||||
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
|
||||||
|
|
||||||
import { da } from "element-plus/es/locale/index.mjs";
|
import { da } from "element-plus/es/locale/index.mjs";
|
||||||
import { f } from "vue-router/dist/router-CWoNjPRp.mjs";
|
import { f } from "vue-router/dist/router-CWoNjPRp.mjs";
|
||||||
|
import { useModelStore } from "@/store/modules/model";
|
||||||
|
|
||||||
|
const modelStore = useModelStore();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -141,8 +145,8 @@ let chartInstance: ECharts | null = null;
|
|||||||
// 静态数据 - 站点名称
|
// 静态数据 - 站点名称
|
||||||
const stationNames = ref([]);
|
const stationNames = ref([]);
|
||||||
|
|
||||||
// 静态数据 - 水温值 (°C),班多无数据设为 null
|
// 静态数据 - 水温值 (°C),班多无数据设为 null,使用对象格式携带stcd信息
|
||||||
const waterTemperatures = ref([]);
|
const waterTemperatures = ref<{ value: number | null; stcd: string; stnm: string }[]>([]);
|
||||||
|
|
||||||
// 使用 computed 使 currentTime 响应 dataOne.value 的变化
|
// 使用 computed 使 currentTime 响应 dataOne.value 的变化
|
||||||
const currentTime = computed(() => dataOne.value || getCurrentHourTime());
|
const currentTime = computed(() => dataOne.value || getCurrentHourTime());
|
||||||
@ -309,6 +313,22 @@ const initChart = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
chartInstance.setOption(option);
|
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_point";
|
||||||
|
modelStore.title = params.data.stnm + "详情信息";
|
||||||
|
// modelStore.isBasicEdit = true;
|
||||||
|
modelStore.params.stcd = params.data.stcd;
|
||||||
|
modelStore.params.date = paramsOne.tm;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理窗口大小变化
|
// 处理窗口大小变化
|
||||||
@ -337,9 +357,9 @@ const init = async () => {
|
|||||||
let res = await getKendoListCust(params);
|
let res = await getKendoListCust(params);
|
||||||
let data = res.data.data || res.data
|
let data = res.data.data || res.data
|
||||||
|
|
||||||
if(data.length > 0){
|
if (data.length > 0) {
|
||||||
showemit.value = true
|
showemit.value = true
|
||||||
}else{
|
} else {
|
||||||
showemit.value = false
|
showemit.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,10 +368,14 @@ const init = async () => {
|
|||||||
.map((item: any) => item.stnm);
|
.map((item: any) => item.stnm);
|
||||||
console.log(stationNames.value);
|
console.log(stationNames.value);
|
||||||
|
|
||||||
|
// 修改为对象格式,携带stcd和stnm信息
|
||||||
waterTemperatures.value = data
|
waterTemperatures.value = data
|
||||||
.filter((item: any) => item.sttp == "2")
|
.filter((item: any) => item.sttp == "2")
|
||||||
.map((item: any) => item.temperature);
|
.map((item: any) => ({
|
||||||
// waterTemperatures.value = res.data.data.map((item: any) => item.temperature);
|
value: item.temperature,
|
||||||
|
stcd: item.stcd,
|
||||||
|
stnm: item.stnm
|
||||||
|
}));
|
||||||
console.log(waterTemperatures.value);
|
console.log(waterTemperatures.value);
|
||||||
|
|
||||||
// 数据获取完成后,初始化或更新图表
|
// 数据获取完成后,初始化或更新图表
|
||||||
@ -477,7 +501,7 @@ const getSelectConfig = async () => {
|
|||||||
} else if (filterSelectOptions(dataMapNameArr)[0]?.children) {
|
} else if (filterSelectOptions(dataMapNameArr)[0]?.children) {
|
||||||
select.value.value = filterSelectOptions(dataMapNameArr)[0]?.children[0]?.value
|
select.value.value = filterSelectOptions(dataMapNameArr)[0]?.children[0]?.value
|
||||||
} else if (filterSelectOptions(dataMapNameArr)[0]?.value) {
|
} else if (filterSelectOptions(dataMapNameArr)[0]?.value) {
|
||||||
select.value.value = filterSelectOptions(dataMapNameArr)[0]?.value
|
select.value.value = filterSelectOptions(dataMapNameArr)[0]?.value
|
||||||
} else {
|
} else {
|
||||||
select.value.value = ''
|
select.value.value = ''
|
||||||
}
|
}
|
||||||
@ -574,12 +598,13 @@ onBeforeUnmount(() => {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.chart-container {
|
.chart-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 252px ;
|
height: 252px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
:deep(.ant-spin-nested-loading ){
|
|
||||||
|
:deep(.ant-spin-nested-loading) {
|
||||||
height: 252px !important;
|
height: 252px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -11,8 +11,12 @@ export const useModelStore = defineStore('model', () => {
|
|||||||
|
|
||||||
const params = ref<{
|
const params = ref<{
|
||||||
sttp: string;
|
sttp: string;
|
||||||
|
stcd: any;
|
||||||
|
date: any;
|
||||||
}>({
|
}>({
|
||||||
sttp: 'eng'
|
sttp: 'eng',
|
||||||
|
stcd: '',
|
||||||
|
date: '',
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
params,
|
params,
|
||||||
|
|||||||
@ -113,3 +113,6 @@ svg {
|
|||||||
.ant-empty-description {
|
.ant-empty-description {
|
||||||
color: rgba(0, 0, 0, 0.85);
|
color: rgba(0, 0, 0, 0.85);
|
||||||
}
|
}
|
||||||
|
.ant-select-tree-node-selected{
|
||||||
|
background-color: #bae7ff !important;
|
||||||
|
}
|
||||||
|
|||||||
@ -22,7 +22,8 @@ service.interceptors.request.use(
|
|||||||
if (
|
if (
|
||||||
config.url.includes('/dec-lygk-base-server') ||
|
config.url.includes('/dec-lygk-base-server') ||
|
||||||
config.url.includes('/wmp-env-server') ||
|
config.url.includes('/wmp-env-server') ||
|
||||||
config.url.includes('/wmp-sys-server')
|
config.url.includes('/wmp-sys-server') ||
|
||||||
|
config.url.includes('/dec-modules-usm-springcloud-starter')
|
||||||
) {
|
) {
|
||||||
config.headers._appid = '974975A6-47FD-4C04-9ACD-68938D2992BD';
|
config.headers._appid = '974975A6-47FD-4C04-9ACD-68938D2992BD';
|
||||||
config.headers._isolateid = '5b34aecb-adfb-4dfc-ad95-21505a9eb388';
|
config.headers._isolateid = '5b34aecb-adfb-4dfc-ad95-21505a9eb388';
|
||||||
|
|||||||
@ -145,7 +145,7 @@ const showMapModal17 = () => {
|
|||||||
<div class="rightContent">
|
<div class="rightContent">
|
||||||
<RightDrawer>
|
<RightDrawer>
|
||||||
<a-button @click="showMapModal">打开电站弹窗</a-button>
|
<a-button @click="showMapModal">打开电站弹窗</a-button>
|
||||||
<!-- <a-button @click="showMapModal1">打开水温弹窗</a-button> -->
|
<a-button @click="showMapModal1">打开水温弹窗</a-button>
|
||||||
<!-- <a-button @click="showMapModal2">打开水质弹窗</a-button> -->
|
<!-- <a-button @click="showMapModal2">打开水质弹窗</a-button> -->
|
||||||
<!-- <a-button @click="showMapModal3">打开栖息地弹窗</a-button> -->
|
<!-- <a-button @click="showMapModal3">打开栖息地弹窗</a-button> -->
|
||||||
<!-- <a-button @click="showMapModal4">打开栖息地流量弹窗</a-button> -->
|
<!-- <a-button @click="showMapModal4">打开栖息地流量弹窗</a-button> -->
|
||||||
@ -161,7 +161,7 @@ const showMapModal17 = () => {
|
|||||||
<!-- <a-button @click="showMapModal14">打开低温水减缓设施-叠梁门弹窗</a-button> -->
|
<!-- <a-button @click="showMapModal14">打开低温水减缓设施-叠梁门弹窗</a-button> -->
|
||||||
<!-- <a-button @click="showMapModal15">打开前置挡墙弹窗</a-button> -->
|
<!-- <a-button @click="showMapModal15">打开前置挡墙弹窗</a-button> -->
|
||||||
<!-- <a-button @click="showMapModal16">打开隔水幕墙弹窗</a-button> -->
|
<!-- <a-button @click="showMapModal16">打开隔水幕墙弹窗</a-button> -->
|
||||||
<a-button @click="showMapModal17">打开夹岩双层取水弹窗</a-button>
|
<!-- <a-button @click="showMapModal17">打开夹岩双层取水弹窗</a-button> -->
|
||||||
|
|
||||||
<jidiInfoMod />
|
<jidiInfoMod />
|
||||||
<shuidianhuangjingjieruMod />
|
<shuidianhuangjingjieruMod />
|
||||||
|
|||||||
@ -74,6 +74,16 @@ export default ({ mode }: ConfigEnv): UserConfig => {
|
|||||||
new RegExp('^/api/wmp-sys-server'),
|
new RegExp('^/api/wmp-sys-server'),
|
||||||
'/api/wmp-sys-server'
|
'/api/wmp-sys-server'
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
'/api/dec-modules-usm-springcloud-starter': {
|
||||||
|
target: 'https://211.99.26.225:12122',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
rewrite: path =>
|
||||||
|
path.replace(
|
||||||
|
new RegExp('^/api/dec-modules-usm-springcloud-starter'),
|
||||||
|
'/api/dec-modules-usm-springcloud-starter'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user