595 lines
15 KiB
Vue
595 lines
15 KiB
Vue
<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>
|