916 lines
21 KiB
Vue
916 lines
21 KiB
Vue
<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';
|
||
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>
|