WholeProcessPlatform/frontend/src/modules/EnvironmentalQuality/TwoLayers/HJMZDTwoLays.vue
2026-06-18 09:29:15 +08:00

595 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<div>
<!-- 搜索表单 - 使用 Ant Design Vue 原生组件 -->
<a-form
ref="formRef"
:model="formState"
layout="inline"
@finish="onFinish"
style="margin-bottom: 16px"
>
<a-form-item label="达标状态" name="sfdb">
<a-select
v-model:value="formState.sfdb"
placeholder="请选择"
allow-clear
style="width: 150px"
>
<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-option :value="'2'">无目标等级/无数据</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" html-type="submit">查询</a-button>
<Tooltip title="重置">
<a-button @click="handleReset">重置</a-button>
</Tooltip>
</a-space>
</a-form-item>
</a-form>
<!-- 数据表格 -->
<BasicTable
ref="tableRef"
:columns="columns"
:list-url="
props.calculateFlag?.calculateFlag == 1
? dataGetKendoListCust
: NodataGetKendoListCust
"
:scrollY="500"
:search-params="{ sort: [{ field: 'tm', dir: 'desc' }] }"
:transform-data="customTransform"
/>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch, onMounted, h, nextTick } from 'vue';
import { omit } from 'lodash';
import { Button, Tooltip, Popover } from 'ant-design-vue';
import BasicTable from '@/components/BasicTable/index.vue';
import {
ruleGetKendoListCust,
noAuthGetKendoListCust,
stbprpGetStbprpYsByStcd,
dataGetKendoListCust,
NodataGetKendoListCust
} from '@/api/sz';
// ==================== Props 定义 ====================
interface Props {
tc: {
stcd: string;
startTime: string;
endTime: string;
sfdb: string;
};
calculateFlag?: {
calculateFlag: number;
};
}
const props = defineProps<Props>();
// ==================== 响应式状态 ====================
const formRef = ref();
const tableRef = ref();
const col = ref<any[]>([]);
// ✅ 表单状态(替代之前的 sfdb ref
const formState = reactive({
sfdb: '1'
});
// ==================== 固定列配置 ====================
const columnList = [
{
dataIndexRaw: '',
key: 'tm',
title: '时间',
dataIndex: 'tm',
children: [],
visible: true,
fixed: '',
ellipsis: true,
wrap: false,
dictType: '',
dictCode: '',
dictDatas: {},
fromType: '',
dataType: 'date',
dataFormat: '',
selectMode: '',
unit: '',
remark: '',
rules: '',
ruleTips: '',
setting: {},
chartColor: '',
elementCode: '',
disabledDate: true,
sorter: true,
multiLink: false
},
{
dataIndexRaw: '',
key: 'wwqtg',
title: '水质要求',
dataIndex: 'wwqtgName',
children: [],
visible: true,
fixed: '',
ellipsis: true,
wrap: false,
dictType: '',
dictCode: '',
dictDatas: {},
fromType: '',
dataFormat: '',
selectMode: '',
unit: '',
remark: '',
rules: '',
ruleTips: '',
setting: {},
chartColor: '',
elementCode: '',
sorter: true,
disabledDate: true,
multiLink: false,
width: 100
},
{
dataIndexRaw: '',
key: 'wqGrd',
title: '水质等级',
dataIndex: 'wqgrdName',
children: [],
visible: true,
fixed: '',
ellipsis: true,
wrap: false,
dictType: '',
dictCode: '',
dictDatas: {},
fromType: '',
dataFormat: '',
selectMode: '',
unit: '',
remark: '',
rules: '',
ruleTips: '',
setting: {},
chartColor: '',
elementCode: '',
sorter: true,
disabledDate: true,
multiLink: false,
width: 100
},
{
dataIndexRaw: 'sfdb',
key: 'sfdb',
title: '是否达标',
dataIndex: 'sfdbName',
children: [],
visible: true,
fixed: '',
ellipsis: true,
wrap: false,
// TODO: 【您需要实现】字典转换逻辑 - BasicTable 不支持 dictType/dictCode
// 需要在 customRender 中手动处理
dictType: 'dataDict',
dictCode: 'sd_wq_r.sfdb',
dictDatas: {},
fromType: 'select',
dataFormat: '',
selectMode: '',
unit: '',
remark: '',
rules: '',
ruleTips: '',
setting: {},
chartColor: '',
elementCode: '',
sorter: true,
disabledDate: true,
multiLink: false,
width: 100,
// ✅ Vue3 版本需要添加 customRender
customRender: ({ record }: any) => {
// TODO: 【您需要实现】字典转换逻辑
// 示例return getDictLabel('sd_wq_r.sfdb', record.sfdbName)
return record.sfdbName; // 暂时直接显示原始值
}
}
];
// ==================== 动态列计算 ====================
const columns = computed(() => {
if (!col.value.length) return columnList;
return [...columnList, ...col.value];
});
// ==================== 筛选条件计算 ====================
const tableFilter = computed(() => {
let res: any = {
stcd: props.tc.stcd,
sfdb: formState.sfdb === '2' ? '' : formState.sfdb,
startTime: props.tc.startTime,
endTime: props.tc.endTime
};
if (res.sfdb === '') res = omit(res, 'sfdb');
return res;
});
// ==================== 方法定义 ====================
// 搜索表单提交
const onFinish = () => {
const filters: any[] = [
{
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: tableFilter.value.stcd
},
formState.sfdb
? {
field: 'sfdb',
operator: 'eq',
dataType: 'string',
value: formState.sfdb
}
: null,
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: tableFilter.value.startTime
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: tableFilter.value.endTime
}
].filter(Boolean);
const filter = {
logic: 'and',
filters
};
// 触发表格刷新
tableRef.value?.getList(filter);
};
// 重置表单
const handleReset = () => {
formState.sfdb = '1';
onFinish();
};
// TODO: 【预留】获取动态列配置 - 您需要实现的API调用逻辑
const getCol = async (params: any) => {
try {
const lo = await columYaoshu(params);
col.value = lo || [];
} catch (error) {
console.error('获取列配置失败:', error);
}
};
// TODO: 【预留】处理列配置的核心逻辑 - 您需要实现
const columYaoshu = async (params: any) => {
// API 1: 获取预警规则限值
let params3 = {
filter: {
logic: 'and',
filters: [
{
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: params?.stcd
}
]
}
};
const MaxData = await ruleGetKendoListCust(params3);
// API 2: 获取数据范围
let params2 = {
filter: {
logic: 'and',
filters: [
{
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: params?.stcd
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: params?.endTime
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: params?.startTime
}
]
}
};
const noAuthRes = await noAuthGetKendoListCust(params2);
const noAuthResData = noAuthRes?.data?.data || [];
// API 3: 获取要素配置
let params1 = {
stcd: params?.stcd,
tbCode: 'WQ_R',
endTime: params.endTime,
startTime: params.startTime
};
const res = await stbprpGetStbprpYsByStcd(params1);
if (res?.data?.data) {
const processedColumns = res.data.data
.filter((item: any) => item.enable === '1')
.map((item: any) => {
const _t = item.ysShowName;
const reg = /[(][^()]+[)]/;
// TODO: 【您需要实现】单位转换工具函数
const _u = getUnitConfigByCode('WQ_R', item.ys)?.unit;
if (_u) {
item.ysShowName = reg.test(_t)
? _t.replace(reg, `(${_u})`)
: `${_t}(${_u})`;
}
let showValue = '';
if (noAuthResData.length) {
const { max, min } = noAuthResData[0];
const ys = item.ys;
const maxValue = max.filter((e: any) => e[ys]);
const minValue = min.filter((e: any) => e[ys]);
if (maxValue.length && minValue.length) {
showValue = `(${minValue[0]?.[ys]}-${maxValue[0]?.[ys]})`;
} else {
if (minValue.length) {
showValue = `>${minValue[0]?.[ys]}`;
}
if (maxValue.length) {
showValue = `<${maxValue[0]?.[ys]}`;
}
}
}
return {
dataIndexRaw: '',
key: item.ys.toLowerCase(),
// ✅ Vue3 版本title 支持函数返回 VNode
title: () =>
h('div', [
h(
'p',
{
style: {
overflow: 'hidden',
textOverflow: 'ellipsis',
wordBreak: 'keep-all'
}
},
item.ysShowName
),
h('p', showValue)
]),
dataIndex: item.ys.toLowerCase(),
children: [],
visible: true,
fixed: '',
sorter: true,
ellipsis: true,
wrap: false,
dictType: '',
dictCode: '',
dictDatas: {},
// ✅ Vue3 版本:使用 customRender 替代 render
customRender: ({ record }: any) => {
// TODO: 【您需要传入】MaxData 数据
const datalist = MaxData?.data?.data;
const dynamicDataIndex = item.ys;
const dynamicDataName = item.ysShowName;
const matchedItem = datalist.find(
(m: any) => m.ys === dynamicDataIndex
);
// 判断是否超标
if (
matchedItem &&
(matchedItem.isAsc == 1
? matchedItem?.maxVal
: matchedItem.minVal) &&
record[dynamicDataIndex?.toLowerCase()] &&
((matchedItem.isAsc == 1 &&
record[dynamicDataIndex?.toLowerCase()] >
matchedItem?.maxVal) ||
(matchedItem.isAsc != 1 &&
record[dynamicDataIndex?.toLowerCase()] < matchedItem.minVal))
) {
// ✅ Vue3 版本:使用 h() 函数创建 VNode
return h(
Popover,
{
content: h(
'div',
`预警标准: ${
matchedItem.isAsc === 1
? `>${matchedItem.maxVal}`
: `<${matchedItem.minVal}`
}`
),
trigger: 'hover'
},
() =>
h(
'span',
{
style: { color: 'red', cursor: 'pointer' }
// TODO: 【您需要实现】单位转换渲染
},
transUnitRender(
record[dynamicDataIndex?.toLowerCase()],
'WQ_R',
dynamicDataIndex
)
)
);
}
// 正常显示
// TODO: 【您需要实现】单位转换渲染
return transUnitRender(
record[dynamicDataIndex?.toLowerCase()],
'WQ_R',
dynamicDataIndex
);
},
fromType: '',
dataType: '',
dataFormat: '',
selectMode: '',
unit: '',
remark: '',
rules: '',
ruleTips: '',
setting: {},
chartColor: '',
elementCode: '',
disabledDate: true,
multiLink: false
};
});
console.log(processedColumns);
onFinish();
return processedColumns || [];
}
};
// TODO: 【预留】单位转换工具函数 - 您需要实现
// ==================== 单位转换工具函数区域 ====================
/**
* 根据表代码和要素代码获取单位配置
* @param tbCode 表代码 (如 'WQ_R')
* @param ys 要素代码 (如 'DOX', 'CODCR')
* @returns 单位配置对象 { unit: string }
*/
const getUnitConfigByCode = (tbCode: string, ys: string) => {
// TODO: 【您需要实现】单位配置映射
const unitConfig: Record<string, Record<string, { unit: string }>> = {
WQ_R: {
PH: { unit: '' },
DOX: { unit: 'mg/L' },
CODMN: { unit: 'mg/L' },
CODCR: { unit: 'mg/L' },
NH3N: { unit: 'mg/L' },
TP: { unit: 'mg/L' },
TN: { unit: 'mg/L' },
WTMP: { unit: '℃' },
COND: { unit: 'μS/cm' },
CLARITY: { unit: 'm' }
}
};
return unitConfig[tbCode]?.[ys] || { unit: '' };
};
/**
* 带单位的值渲染(根据要素类型设置不同小数位数,不带单位)
* @param value 数值
* @param tbCode 表代码
* @param ys 要素代码
* @returns 格式化后的字符串(不带单位)
*/
const transUnitRender = (value: any, tbCode: string, ys: string) => {
if (value === null || value === undefined || value === '') return '-';
const numValue = Number(value);
if (isNaN(numValue)) return String(value);
// 根据不同要素类型设置小数位数
let formattedValue: string;
if (ys === 'WTMP' || ys === 'PH') {
// 水温和PH保留一位小数
formattedValue = numValue.toFixed(1);
} else if (ys === 'COND') {
// 电导率不要小数
formattedValue = Math.round(numValue).toString();
} else {
// 其他要素保留两位小数
formattedValue = numValue.toFixed(2);
}
return formattedValue;
};
/**
* 纯单位转换(不带渲染)
* @param value 数值
* @param tbCode 表代码
* @param ys 要素代码
* @returns 转换后的数值
*/
const transUnit = (value: any, tbCode: string, ys: string) => {
if (value === null || value === undefined) return null;
return Number(value);
};
// ==================== 监听器 ====================
// 监听 tc 和 formState.sfdb 变化,重新获取列配置
watch(
() => [props.tc.stcd, props.tc.startTime, props.tc.endTime, formState.sfdb],
([stcd, startTime, endTime]) => {
if (!stcd) {
return;
}
//
tableRef.value.tableData = [];
getCol({ stcd, startTime, endTime });
},
{ immediate: false } // 不在初始化时立即执行,由 onMounted 处理
);
// 初始化
onMounted(() => {
nextTick(() => {});
getCol({
stcd: props.tc.stcd,
startTime: props.tc.startTime,
endTime: props.tc.endTime
});
});
// 自定义数据转换
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
</script>
<style scoped>
/* 如需添加样式,请在此处编写 */
</style>