WholeProcessPlatform/frontend/src/modules/EnvironmentalQuality/TwoLayers/HJMZDTwoLays.vue

595 lines
15 KiB
Vue
Raw Normal View History

2026-06-02 14:52:44 +08:00
<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>
2026-06-02 14:52:44 +08:00
</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';
2026-06-02 14:52:44 +08:00
// ==================== Props 定义 ====================
interface Props {
tc: {
stcd: string;
startTime: string;
endTime: string;
sfdb: string;
};
calculateFlag?: {
calculateFlag: number;
};
2026-06-02 14:52:44 +08:00
}
const props = defineProps<Props>();
2026-06-02 14:52:44 +08:00
// ==================== 响应式状态 ====================
const formRef = ref();
const tableRef = ref();
const col = ref<any[]>([]);
2026-06-02 14:52:44 +08:00
// ✅ 表单状态(替代之前的 sfdb ref
const formState = reactive({
sfdb: '1'
});
2026-06-02 14:52:44 +08:00
// ==================== 固定列配置 ====================
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; // 暂时直接显示原始值
2026-06-02 14:52:44 +08:00
}
}
];
2026-06-02 14:52:44 +08:00
// ==================== 动态列计算 ====================
const columns = computed(() => {
if (!col.value.length) return columnList;
return [...columnList, ...col.value];
});
2026-06-02 14:52:44 +08:00
// ==================== 筛选条件计算 ====================
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;
});
2026-06-02 14:52:44 +08:00
// ==================== 方法定义 ====================
// 搜索表单提交
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
2026-06-02 14:52:44 +08:00
}
: null,
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: tableFilter.value.startTime
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: tableFilter.value.endTime
2026-06-02 14:52:44 +08:00
}
].filter(Boolean);
const filter = {
logic: 'and',
filters
};
// 触发表格刷新
tableRef.value?.getList(filter);
};
2026-06-02 14:52:44 +08:00
// 重置表单
const handleReset = () => {
formState.sfdb = '1';
onFinish();
};
2026-06-02 14:52:44 +08:00
// TODO: 【预留】获取动态列配置 - 您需要实现的API调用逻辑
const getCol = async (params: any) => {
try {
const lo = await columYaoshu(params);
col.value = lo || [];
} catch (error) {
console.error('获取列配置失败:', error);
}
};
2026-06-02 14:52:44 +08:00
// 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
2026-06-02 14:52:44 +08:00
}
]
2026-06-02 14:52:44 +08:00
}
};
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]}`;
}
}
}
2026-06-02 14:52:44 +08:00
return {
dataIndexRaw: '',
key: item.ys.toLowerCase(),
// ✅ Vue3 版本title 支持函数返回 VNode
title: () =>
h('div', [
h(
'p',
2026-06-02 14:52:44 +08:00
{
style: {
overflow: 'hidden',
textOverflow: 'ellipsis',
wordBreak: 'keep-all'
}
2026-06-02 14:52:44 +08:00
},
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,
2026-06-02 14:52:44 +08:00
{
content: h(
'div',
`预警标准: ${
matchedItem.isAsc === 1
? `>${matchedItem.maxVal}`
: `<${matchedItem.minVal}`
}`
),
trigger: 'hover'
2026-06-02 14:52:44 +08:00
},
() =>
h(
'span',
{
style: { color: 'red', cursor: 'pointer' }
// TODO: 【您需要实现】单位转换渲染
2026-06-02 14:52:44 +08:00
},
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 || [];
}
};
2026-06-02 14:52:44 +08:00
// 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' }
2026-06-02 14:52:44 +08:00
}
};
2026-06-02 14:52:44 +08:00
return unitConfig[tbCode]?.[ys] || { unit: '' };
};
2026-06-02 14:52:44 +08:00
/**
* 带单位的值渲染根据要素类型设置不同小数位数不带单位
* @param value 数值
* @param tbCode 表代码
* @param ys 要素代码
* @returns 格式化后的字符串不带单位
*/
const transUnitRender = (value: any, tbCode: string, ys: string) => {
if (value === null || value === undefined || value === '') return '-';
2026-06-02 14:52:44 +08:00
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;
};
2026-06-02 14:52:44 +08:00
/**
* 纯单位转换不带渲染
* @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);
};
2026-06-02 14:52:44 +08:00
// ==================== 监听器 ====================
// 监听 tc 和 formState.sfdb 变化,重新获取列配置
watch(
() => [props.tc.stcd, props.tc.startTime, props.tc.endTime, formState.sfdb],
([stcd, startTime, endTime]) => {
if (!stcd) {
return;
}
2026-06-18 09:29:15 +08:00
//
tableRef.value.tableData = [];
getCol({ stcd, startTime, endTime });
},
{ immediate: false } // 不在初始化时立即执行,由 onMounted 处理
);
2026-06-02 14:52:44 +08:00
// 初始化
onMounted(() => {
nextTick(() => {});
getCol({
stcd: props.tc.stcd,
startTime: props.tc.startTime,
endTime: props.tc.endTime
});
});
2026-06-02 14:52:44 +08:00
// 自定义数据转换
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
2026-06-02 14:52:44 +08:00
</script>
<style scoped>
/* 如需添加样式,请在此处编写 */
</style>