Files
CN_Tool_client/frontend/src/views/steady/checksquare/components/ChecksquareTaskTable.vue

313 lines
9.4 KiB
Vue
Raw Normal View History

<template>
<ProTable
ref="proTable"
row-key="taskId"
:columns="columns"
:request-api="getTableList"
:search-col="{ xs: 1, sm: 2, md: 2, lg: 4, xl: 4 }"
>
<template #tableHeader>
<el-button type="primary" :icon="Plus" @click="emit('createTask')">新增校验任务</el-button>
</template>
<template #operation="{ row }">
<el-button type="primary" link :icon="View" @click="emit('detail', row)">详情</el-button>
</template>
</ProTable>
</template>
<script setup lang="ts">
import { computed, h, reactive, ref } from 'vue'
import { ElDatePicker, ElTag, ElTreeSelect } from 'element-plus'
import { Plus, View } from '@element-plus/icons-vue'
import ProTable from '@/components/ProTable/index.vue'
import type { ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
import type { SteadyDataView } from '@/api/steady/steadyDataView/interface'
import {
buildChecksquareTaskQueryParams,
formatChecksquarePercent,
formatChecksquareTaskStatus,
resolveChecksquareTaskStatusType,
resolveChecksquareText,
type ChecksquareTaskSearchParams
} from '../utils/checksquareTaskTable'
defineOptions({
name: 'ChecksquareTaskTable'
})
const props = defineProps<{
ledgerTree: SteadyDataView.SteadyLedgerNode[]
indicatorTree: SteadyDataView.SteadyIndicatorNode[]
requestApi: (params: SteadyDataView.SteadyChecksquareTaskQueryParams) => Promise<any>
}>()
const emit = defineEmits<{
createTask: []
detail: [row: SteadyDataView.SteadyChecksquareTask]
}>()
const proTable = ref<ProTableInstance>()
interface ChecksquareFilterTreeNode {
label: string
value: string
disabled?: boolean
children?: ChecksquareFilterTreeNode[]
}
const normalizeLineFilterTree = (nodes: SteadyDataView.SteadyLedgerNode[]): ChecksquareFilterTreeNode[] => {
return nodes.map(node => ({
label: node.name,
value: node.id,
disabled: node.level !== 3 || node.selectable === false,
children: node.children?.length ? normalizeLineFilterTree(node.children) : undefined
}))
}
const normalizeIndicatorFilterTree = (
nodes: SteadyDataView.SteadyIndicatorNode[],
parentKey = ''
): ChecksquareFilterTreeNode[] => {
return nodes.map((node, index) => {
const isLeaf = !node.children?.length
const value =
isLeaf && node.indicatorCode
? node.indicatorCode
: node.id || `${parentKey}${node.groupCode || node.name || 'node'}-${index}`
return {
label: node.unit ? `${node.name}${node.unit}` : node.name,
value,
disabled: !isLeaf || !node.indicatorCode,
children: node.children?.length ? normalizeIndicatorFilterTree(node.children, `${value}-`) : undefined
}
})
}
const lineFilterTree = computed(() => normalizeLineFilterTree(props.ledgerTree))
const indicatorFilterTree = computed(() => normalizeIndicatorFilterTree(props.indicatorTree))
const splitTreeSelectValues = (value?: string) => {
return (value || '')
.split(',')
.map(item => item.trim())
.filter(Boolean)
}
const normalizeTreeSelectValues = (value: unknown) => {
const rawValues = Array.isArray(value) ? value : value === undefined || value === null || value === '' ? [] : [value]
return Array.from(
new Set(
rawValues
.filter((item): item is string | number => typeof item === 'string' || typeof item === 'number')
.map(item => String(item).trim())
.filter(Boolean)
)
)
}
const renderTimeRangeSearch = ({ searchParam }: { searchParam: ChecksquareTaskSearchParams }) =>
h(ElDatePicker, {
modelValue: searchParam.taskTimeRange,
type: 'datetimerange',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
clearable: true,
'onUpdate:modelValue': (value: string[] | null) => {
searchParam.taskTimeRange = value || undefined
}
})
const renderLineSearch = ({ searchParam }: { searchParam: ChecksquareTaskSearchParams }) =>
h(ElTreeSelect, {
class: 'checksquare-search-tree-select',
style: { width: '100%' },
modelValue: splitTreeSelectValues(searchParam.lineId),
data: lineFilterTree.value,
nodeKey: 'value',
multiple: true,
showCheckbox: true,
collapseTags: true,
collapseTagsTooltip: true,
maxCollapseTags: 1,
filterable: true,
clearable: true,
defaultExpandAll: true,
checkStrictly: true,
props: { label: 'label', children: 'children', disabled: 'disabled' },
placeholder: '请选择监测点',
'onUpdate:modelValue': (value: unknown) => {
const selectedValues = normalizeTreeSelectValues(value)
searchParam.lineId = selectedValues.length ? selectedValues.join(',') : undefined
}
})
const renderIndicatorSearch = ({ searchParam }: { searchParam: ChecksquareTaskSearchParams }) =>
h(ElTreeSelect, {
class: 'checksquare-search-tree-select',
style: { width: '100%' },
modelValue: splitTreeSelectValues(searchParam.indicatorCode),
data: indicatorFilterTree.value,
nodeKey: 'value',
multiple: true,
showCheckbox: true,
collapseTags: true,
collapseTagsTooltip: true,
maxCollapseTags: 1,
filterable: true,
clearable: true,
defaultExpandAll: true,
checkStrictly: true,
props: { label: 'label', children: 'children', disabled: 'disabled' },
placeholder: '请选择稳态指标',
'onUpdate:modelValue': (value: unknown) => {
const selectedValues = normalizeTreeSelectValues(value)
searchParam.indicatorCode = selectedValues.length ? selectedValues.join(',') : undefined
}
})
const columns = reactive<ColumnProps<SteadyDataView.SteadyChecksquareTask>[]>([
{ type: 'index', fixed: 'left', width: 70, label: '序号' },
{
prop: 'taskNo',
label: '任务编号',
minWidth: 180,
render: ({ row }) => resolveChecksquareText(row.taskNo)
},
{
prop: 'lineId',
label: '监测点ID',
isShow: false,
isSetting: false,
search: {
label: '监测点',
order: 2,
render: renderLineSearch
}
},
{
prop: 'lineName',
label: '监测点名称',
minWidth: 160,
render: ({ row }) => resolveChecksquareText(row.lineName || row.lineId)
},
{
prop: 'indicatorCode',
label: '稳态指标',
isShow: false,
isSetting: false,
search: {
label: '稳态指标',
order: 3,
render: renderIndicatorSearch
}
},
{
prop: 'timeStart',
label: '开始时间',
minWidth: 170,
render: ({ row }) => resolveChecksquareText(row.timeStart),
search: {
label: '检测时间',
key: 'taskTimeRange',
order: 1,
render: renderTimeRangeSearch
}
},
{
prop: 'timeEnd',
label: '结束时间',
minWidth: 170,
render: ({ row }) => resolveChecksquareText(row.timeEnd)
},
{
prop: 'taskStatus',
label: '任务状态',
minWidth: 110,
render: ({ row }) =>
h(
ElTag,
{ type: resolveChecksquareTaskStatusType(row.taskStatus), effect: 'plain' },
() => formatChecksquareTaskStatus(row.taskStatus)
)
},
{
prop: 'itemCount',
label: '检测项数',
minWidth: 100,
align: 'center',
render: ({ row }) => resolveChecksquareText(row.itemCount)
},
{
prop: 'abnormalItemCount',
label: '异常项数',
minWidth: 100,
align: 'center',
render: ({ row }) => resolveChecksquareText(row.abnormalItemCount),
search: {
label: '异常状态',
key: 'hasAbnormal',
order: 4,
el: 'select'
},
enum: [
{ label: '存在异常', value: true },
{ label: '全部', value: false }
],
isFilterEnum: false
},
{
prop: 'maxMissingRate',
label: '最大缺失率',
minWidth: 120,
align: 'center',
render: ({ row }) => formatChecksquarePercent(row.maxMissingRate)
},
{
prop: 'createTime',
label: '创建时间',
minWidth: 170,
render: ({ row }) => resolveChecksquareText(row.createTime)
},
{ prop: 'operation', label: '操作', fixed: 'right', width: 96 }
])
const getTableList = (params: ChecksquareTaskSearchParams) => {
return props.requestApi(buildChecksquareTaskQueryParams(params))
}
const refresh = () => {
proTable.value?.getTableList()
}
defineExpose({
refresh
})
</script>
<style scoped lang="scss">
.checksquare-search-tree-select {
width: 100%;
}
:deep(.checksquare-search-tree-select .el-select__wrapper) {
min-height: 32px;
}
:deep(.checksquare-search-tree-select .el-select__selection) {
min-width: 0;
}
:deep(.checksquare-search-tree-select .el-select__tags-text) {
display: inline-block;
max-width: 120px;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: bottom;
white-space: nowrap;
}
</style>