修改测试问题

This commit is contained in:
guanj
2026-06-11 20:27:37 +08:00
parent bda7373133
commit 1a09c31669
61 changed files with 3393 additions and 2406 deletions

View File

@@ -1208,6 +1208,7 @@ const handleClick = async (tab?: any) => {
}
//运行趋势
if (dataSet.value.includes('_devRunTrend')) {
tableLoading.value=true
setTimeout(async () => {
if (tab.props != undefined) await (datePickerRef.value && datePickerRef.value?.setInterval(5))

View File

@@ -1,22 +1,30 @@
<template>
<div class="near-realtime-data">
<div class="view_bot">
<template v-for="(section, sectionIndex) in tableSections" :key="sectionIndex">
<vxe-table class="near-realtime-table" border height="" width="100%" :data="[section.row]"
:column-config="tableColumnConfig" :tooltip-config="tableTooltipConfig">
<vxe-colgroup v-for="(item, colIndex) in section.abcItems" :key="`abc-${colIndex}`" align="center"
:title="item.otherName" :width="getMetricWidth(section)">
<vxe-column align="center" :field="`v${colIndex}A`" :title="item.phaseLabels[0]"
:width="getPhaseWidth(section)" :formatter="cellFormatter"></vxe-column>
<vxe-column align="center" :field="`v${colIndex}B`" :title="item.phaseLabels[1]"
:width="getPhaseWidth(section)" :formatter="cellFormatter"></vxe-column>
<vxe-column align="center" :field="`v${colIndex}C`" :title="item.phaseLabels[2]"
:width="getPhaseWidth(section)" :formatter="cellFormatter"></vxe-column>
</vxe-colgroup>
<vxe-column v-for="(item, colIndex) in section.scalarItems" :key="`scalar-${colIndex}`"
align="center" :field="`s${colIndex}`" :title="item.otherName" :width="getMetricWidth(section)"
show-overflow :formatter="cellFormatter"></vxe-column>
<template v-for="(item, colIndex) in section.columns" :key="colIndex">
<vxe-colgroup v-if="item.type === 'abc'" align="center" :title="getPrimaryTitle(item.data)"
:width="getMetricWidth(section)">
<vxe-column align="center" :field="`v${colIndex}A`" :title="item.data.phaseLabels![0]"
:width="getPhaseWidth(section)" :formatter="cellFormatter"></vxe-column>
<vxe-column align="center" :field="`v${colIndex}B`" :title="item.data.phaseLabels![1]"
:width="getPhaseWidth(section)" :formatter="cellFormatter"></vxe-column>
<vxe-column align="center" :field="`v${colIndex}C`" :title="item.data.phaseLabels![2]"
:width="getPhaseWidth(section)" :formatter="cellFormatter"></vxe-column>
</vxe-colgroup>
<vxe-colgroup v-else-if="item.type === 't-multi'" align="center"
:title="getPrimaryTitle(item.data)" :width="getMetricWidth(section)">
<vxe-column v-for="(sub, subIndex) in item.data.subItems" :key="subIndex" align="center"
:field="`t${colIndex}_${subIndex}`" :title="sub.subTitle"
:width="getSubColWidth(section, item.data.subItems!.length)"
:formatter="cellFormatter"></vxe-column>
</vxe-colgroup>
<vxe-column v-else align="center" :field="`s${colIndex}`" :title="getScalarTitle(item.data)"
:width="getMetricWidth(section)" show-overflow :formatter="cellFormatter"></vxe-column>
</template>
<vxe-column v-for="emptyIndex in section.emptySlotCount" :key="`empty-${emptyIndex}`" align="center"
:width="getMetricWidth(section)"></vxe-column>
</vxe-table>
@@ -32,27 +40,36 @@
import { mainHeight } from '@/utils/layout'
import { ref } from 'vue'
const ROW_WITH_ABC = 4
const ROW_WITH_GROUP = 4
const ROW_SCALAR_ONLY = 5
const SECONDARY_KEYWORDS = ['正序', '负序', '零序', '无功', '有功', '视在'] as const
interface SubColumn {
subTitle: string
value: unknown
}
interface DisplayMetric {
name: string
otherName: string
unit?: string | null
type: 'abc' | 'scalar' | 't-multi'
valueA?: unknown
valueB?: unknown
valueC?: unknown
valueM?: unknown
phaseLabels: [string, string, string]
sort: number
phaseLabels?: [string, string, string]
subItems?: SubColumn[]
}
interface MetricItem {
type: 'abc' | 'scalar'
type: 'abc' | 'scalar' | 't-multi'
data: DisplayMetric
}
interface TableSection {
abcItems: DisplayMetric[]
scalarItems: DisplayMetric[]
columns: MetricItem[]
row: Record<string, unknown>
slotsPerRow: number
emptySlotCount: number
@@ -64,6 +81,7 @@ interface RawMetricItem {
unit?: string | null
phase?: string
sort?: number
otherNameSort?: number
data?: unknown
otherName?: string
valueA?: unknown
@@ -72,9 +90,14 @@ interface RawMetricItem {
valueM?: unknown
}
interface NameGroup {
name: string
items: RawMetricItem[]
}
const PHASE_GROUPS = [
{ keys: ['A', 'B', 'C'], labels: ['A相', 'B相', 'C相'] as [string, string, string] },
{ keys: ['AB', 'BC', 'CA'], labels: ['AB', 'BC', 'CA'] as [string, string, string] },
{ keys: ['AB', 'BC', 'CA'], labels: ['AB', 'BC', 'CA'] as [string, string, string] },
]
const height = mainHeight(345)
@@ -87,6 +110,9 @@ const getMetricWidth = (section: TableSection) => `${100 / section.slotsPerRow}%
const getPhaseWidth = (section: TableSection) => `${100 / section.slotsPerRow / 3}%`
const getSubColWidth = (section: TableSection, subCount: number) =>
`${100 / section.slotsPerRow / subCount}%`
const formatCellValue = (value: unknown): string | number => {
if (value == null || value === 3.14159) return '/'
return typeof value === 'number' || typeof value === 'string' ? value : String(value)
@@ -94,140 +120,200 @@ const formatCellValue = (value: unknown): string | number => {
const cellFormatter = ({ cellValue }: { cellValue: unknown }) => formatCellValue(cellValue)
const buildOtherName = (name: string, unit?: string | null) => (unit ? `${name}(${unit})` : name)
const buildTitle = (name: string, unit?: string | null) => (unit ? `${name}(${unit})` : name)
const getSharedUnit = (items: RawMetricItem[]) => {
const units = [...new Set(items.map(item => item.unit ?? null))]
return units.length === 1 ? units[0] : null
}
const getPrimaryTitle = (item: DisplayMetric) => buildTitle(item.name, item.unit)
const getScalarTitle = (item: DisplayMetric) => buildTitle(item.otherName || item.name, item.unit)
const isNewFormat = (item: RawMetricItem) => item.targetId != null && item.phase != null && 'data' in item
const hasAbcValues = (item: DisplayMetric | RawMetricItem) =>
item.valueA != null || item.valueB != null || item.valueC != null
const isGroupedColumn = (item: MetricItem) => item.type === 'abc' || item.type === 't-multi'
const normalizeOldItem = (item: RawMetricItem): DisplayMetric => ({
otherName: item.otherName || buildOtherName(item.name || ''),
valueA: item.valueA,
valueB: item.valueB,
valueC: item.valueC,
valueM: item.valueM,
phaseLabels: ['A相', 'B相', 'C相'],
sort: item.sort ?? 0,
})
const getHarmonicOrder = (name: string) => {
const match = name.match(/^(\d+(?:\.\d+)?)次/)
return match ? parseFloat(match[1]) : null
const extractSubTitle = (otherName: string) => {
for (const keyword of SECONDARY_KEYWORDS) {
if (otherName.includes(keyword)) return keyword
}
return otherName
}
const getGroupKey = (item: RawMetricItem) => `${item.targetId}_${item.name}`
const groupNewFormatData = (list: RawMetricItem[]): DisplayMetric[] => {
const groupMap = new Map<string, { name: string; unit: string | null; sort: number; phases: Record<string, unknown> }>()
const groupByName = (list: RawMetricItem[]): NameGroup[] => {
const order: string[] = []
const map = new Map<string, RawMetricItem[]>()
list.forEach(item => {
const key = getGroupKey(item)
if (!groupMap.has(key)) {
groupMap.set(key, {
name: item.name || '',
unit: item.unit ?? null,
sort: item.sort ?? 0,
phases: {},
})
}
if (item.phase != null) {
groupMap.get(key)!.phases[item.phase] = item.data
const name = item.name || ''
if (!map.has(name)) {
order.push(name)
map.set(name, [])
}
map.get(name)!.push(item)
})
return Array.from(groupMap.values())
.sort((a, b) => {
if (a.sort !== b.sort) return a.sort - b.sort
const orderA = getHarmonicOrder(a.name)
const orderB = getHarmonicOrder(b.name)
if (orderA != null && orderB != null) return orderA - orderB
return a.name.localeCompare(b.name, 'zh-CN')
})
.map(group => {
const otherName = buildOtherName(group.name, group.unit)
const phaseKeys = Object.keys(group.phases)
return order.map(name => ({ name, items: map.get(name)! }))
}
if (phaseKeys.length === 1 && phaseKeys[0] === 'T') {
return {
otherName,
valueM: group.phases.T,
phaseLabels: ['A相', 'B相', 'C相'],
sort: group.sort,
}
}
for (const { keys, labels } of PHASE_GROUPS) {
if (keys.some(key => group.phases[key] != null)) {
return {
otherName,
valueA: group.phases[keys[0]],
valueB: group.phases[keys[1]],
valueC: group.phases[keys[2]],
phaseLabels: labels,
sort: group.sort,
}
}
}
const buildAbcMetric = (name: string, items: RawMetricItem[]): DisplayMetric => {
const phaseMap: Record<string, unknown> = {}
items.forEach(item => {
if (item.phase != null) phaseMap[item.phase] = item.data
})
for (const { keys, labels } of PHASE_GROUPS) {
if (keys.some(key => phaseMap[key] != null)) {
return {
otherName,
valueM: phaseKeys.length === 1 ? group.phases[phaseKeys[0]] : undefined,
valueA: group.phases.A ?? group.phases.AB,
valueB: group.phases.B ?? group.phases.BC,
valueC: group.phases.C ?? group.phases.CA,
phaseLabels: group.phases.AB != null ? ['AB', 'BC', 'CA'] : ['A相', 'B相', 'C相'],
sort: group.sort,
name,
otherName: items[0].otherName || name,
unit: items[0].unit ?? null,
type: 'abc',
valueA: phaseMap[keys[0]],
valueB: phaseMap[keys[1]],
valueC: phaseMap[keys[2]],
phaseLabels: labels,
}
})
}
}
return {
name,
otherName: items[0].otherName || name,
unit: items[0].unit ?? null,
type: 'abc',
valueA: phaseMap.A ?? phaseMap.AB,
valueB: phaseMap.B ?? phaseMap.BC,
valueC: phaseMap.C ?? phaseMap.CA,
phaseLabels: phaseMap.AB != null ? ['AB相', 'BC相', 'CA相'] : ['A相', 'B相', 'C相'],
}
}
const buildTMetric = (name: string, items: RawMetricItem[]): DisplayMetric => {
const needSubHeader = items.some(item => (item.otherName || item.name || '') !== name)
if (!needSubHeader) {
return {
name,
otherName: items[0].otherName || name,
unit: items[0].unit ?? null,
type: 'scalar',
valueM: items[0].data,
}
}
const sharedUnit = getSharedUnit(items)
const unitsDiffer = sharedUnit == null && new Set(items.map(item => item.unit ?? null)).size > 1
return {
name,
otherName: name,
unit: sharedUnit,
type: 't-multi',
subItems: items.map(item => {
const keyword = extractSubTitle(item.otherName || item.name || '')
return {
subTitle: unitsDiffer ? buildTitle(keyword, item.unit) : keyword,
value: item.data,
}
}),
}
}
const groupToMetric = (group: NameGroup): DisplayMetric => {
const { name, items } = group
const phases = items.map(item => item.phase)
const allT = phases.every(phase => phase === 'T')
if (allT) return buildTMetric(name, items)
return buildAbcMetric(name, items)
}
const normalizeOldItem = (item: RawMetricItem): DisplayMetric => {
const name = item.name || ''
const otherName = item.otherName || name
const hasAbc = item.valueA != null || item.valueB != null || item.valueC != null
if (hasAbc) {
return {
name,
otherName,
unit: item.unit ?? null,
type: 'abc',
valueA: item.valueA,
valueB: item.valueB,
valueC: item.valueC,
phaseLabels: ['A相', 'B相', 'C相'],
}
}
return {
name,
otherName,
unit: item.unit ?? null,
type: 'scalar',
valueM: item.valueM,
}
}
const normalizeMetrics = (data: RawMetricItem[]): DisplayMetric[] => {
if (!data?.length) return []
if (isNewFormat(data[0])) {
return groupNewFormatData(data)
return groupByName(data).map(groupToMetric)
}
return data.map(normalizeOldItem).sort((a, b) => a.sort - b.sort)
return data.map(normalizeOldItem)
}
const buildRow = (abcItems: DisplayMetric[], scalarItems: DisplayMetric[]) => {
const toMetricItem = (data: DisplayMetric): MetricItem => ({
type: data.type,
data,
})
const buildRow = (columns: MetricItem[]) => {
const row: Record<string, unknown> = {}
abcItems.forEach((item, index) => {
row[`v${index}A`] = item.valueA
row[`v${index}B`] = item.valueB
row[`v${index}C`] = item.valueC
})
scalarItems.forEach((item, index) => {
row[`s${index}`] = item.valueM
columns.forEach((item, colIndex) => {
if (item.type === 'abc') {
row[`v${colIndex}A`] = item.data.valueA
row[`v${colIndex}B`] = item.data.valueB
row[`v${colIndex}C`] = item.data.valueC
} else if (item.type === 't-multi') {
item.data.subItems?.forEach((sub, subIndex) => {
row[`t${colIndex}_${subIndex}`] = sub.value
})
} else {
row[`s${colIndex}`] = item.data.valueM
}
})
return row
}
const buildTableSections = (abcList: DisplayMetric[], scalarList: DisplayMetric[]) => {
const unified: MetricItem[] = [
...abcList.map(data => ({ type: 'abc' as const, data })),
...scalarList.map(data => ({ type: 'scalar' as const, data })),
]
const buildTableSections = (metrics: DisplayMetric[]) => {
const unified = metrics.map(toMetricItem)
const sections: TableSection[] = []
let index = 0
while (index < unified.length) {
const hasAbc = unified[index].type === 'abc'
const maxCount = hasAbc ? ROW_WITH_ABC : ROW_SCALAR_ONLY
const chunk = unified.slice(index, index + maxCount)
index += chunk.length
const remaining = unified.length - index
let slotsPerRow = isGroupedColumn(unified[index]) ? ROW_WITH_GROUP : ROW_SCALAR_ONLY
if (slotsPerRow === ROW_SCALAR_ONLY) {
const peekCount = Math.min(ROW_SCALAR_ONLY, remaining)
if (unified.slice(index, index + peekCount).some(isGroupedColumn)) {
slotsPerRow = ROW_WITH_GROUP
}
}
const columns = unified.slice(index, index + Math.min(slotsPerRow, remaining))
index += columns.length
const abcItems = chunk.filter(item => item.type === 'abc').map(item => item.data)
const scalarItems = chunk.filter(item => item.type === 'scalar').map(item => item.data)
const slotsPerRow = abcItems.length > 0 ? ROW_WITH_ABC : ROW_SCALAR_ONLY
const metricCount = abcItems.length + scalarItems.length
sections.push({
abcItems,
scalarItems,
row: buildRow(abcItems, scalarItems),
columns,
row: buildRow(columns),
slotsPerRow,
emptySlotCount: slotsPerRow - metricCount,
emptySlotCount: Math.max(0, slotsPerRow - columns.length),
})
}
@@ -236,11 +322,7 @@ const buildTableSections = (abcList: DisplayMetric[], scalarList: DisplayMetric[
const setData = (data: RawMetricItem[], _targetType?: unknown) => {
const list = JSON.parse(JSON.stringify(data || [])) as RawMetricItem[]
const metrics = normalizeMetrics(list)
const abcList = metrics.filter(item => hasAbcValues(item))
const scalarList = metrics.filter(item => !hasAbcValues(item))
tableSections.value = buildTableSections(abcList, scalarList)
tableSections.value = buildTableSections(normalizeMetrics(list))
}
defineExpose({ setData })

View File

@@ -73,7 +73,7 @@ const tableStore: any = new TableStore({
sortable: true,
formatter: (row: any) => {
//row.cellValue = row.cellValue + '' ? row.cellValue.toFixed(2) : '/'
row.cellValue = row.cellValue != null ? Number(row.cellValue).toFixed(2) : '-'
row.cellValue = row.cellValue != null ? Number(row.cellValue).toFixed(2) : '/'
if (String(row.cellValue).split('.')[1] == '00') {
row.cellValue = String(row.cellValue).split('.')[0]
}
@@ -88,7 +88,7 @@ const tableStore: any = new TableStore({
formatter: (row: any) => {
// console.log('🚀 ~ row.cellValue:', row.cellValue)
return row.cellValue ? (row.cellValue - 0).toFixed(2) : '-'
return row.cellValue ? (row.cellValue - 0).toFixed(2) : '/'
},
sortable: true
},
@@ -97,7 +97,7 @@ const tableStore: any = new TableStore({
title: '相别',
minWidth: 80,
formatter: (row: any) => {
return row.cellValue || '-'
return row.cellValue || '/'
}
},
{
@@ -151,12 +151,14 @@ const tableStore: any = new TableStore({
loading.value = true
row.loading1 = false
if (res != undefined) {
boxoList.value = row
boxoList.value.systemType = 'YPT'
boxoList.value.engineeringName = tableParams.value.engineeringName
boxoList.value.featureAmplitude =
row.featureAmplitude != null ? Number(row.featureAmplitude / 100) : '-'
boxoList.value.persistTime = row.persistTime ? row.persistTime.toFixed(2) : '-'
boxoList.value = {
...row,
systemType: 'YPT',
engineeringName: tableParams.value.engineeringName,
featureAmplitude:
row.featureAmplitude != null ? Number(row.featureAmplitude / 100) : '-',
persistTime: row.persistTime ? row.persistTime.toFixed(2) : '-',
}
wp.value = res.data
view.value = false
view2.value = true

View File

@@ -127,6 +127,8 @@ const countOptions: any = ref([])
// Harmonic_Type
// portable-harmonic
const legendDictList: any = ref([])
queryByCode(
props?.TrendList?.lineType == 0
? 'apf-harmonic'

View File

@@ -1,7 +1,7 @@
<template>
<div>
<div v-show="!isWaveCharts">
<TableHeader showExport ref="headerRef" @onResetForm="onResetForm">
<TableHeader showExport ref="headerRef" :showQuery="false" @onResetForm="onResetForm">
<template v-slot:operation>
<el-button type="primary" icon="el-icon-Operation" @click="openFilterDialog">事件筛选</el-button>
</template>
@@ -57,7 +57,8 @@ const multiConditionRef = ref()
const tableStore = new TableStore({
url: '/cs-harmonic-boot/data/getEventByItem',
method: 'POST',
paramsPOST: true,
// paramsPOST: true,
exportName: '暂态事件',
showPage: false,
publicHeight: 355,
column: [
@@ -151,10 +152,12 @@ const tableStore = new TableStore({
isWaveCharts.value = true
row.loading1 = false
if (res != undefined) {
boxoList.value = row
boxoList.value.featureAmplitude =
row.featureAmplitude != '-' ? (row.featureAmplitude - 0) / 100 : null
boxoList.value.systemType = 'YPT'
boxoList.value = {
...row,
featureAmplitude:
row.featureAmplitude != '-' ? (row.featureAmplitude - 0) / 100 : null,
systemType: 'YPT',
}
wp.value = res.data

View File

@@ -4,7 +4,7 @@
<div class="SelectBox">
<div class="boxTitle" @click="clickAllSelect">未绑定数据</div>
<div class="boxCenter">
<el-input maxlength="32" show-word-limit v-model.trim="filterText" :suffix-icon="Search"
<el-input maxlength="32" show-word-limit v-model.trim="filterText" :suffix-icon="Search"
style="width: 100%" placeholder="请输入搜索内容" clearable></el-input>
<el-tree ref="leftTree" default-expand-all :data="leftData" :props="defaultProps" show-checkbox
node-key="id" :filter-node-method="filterNode">
@@ -36,7 +36,7 @@
<div class="SelectBox">
<div class="boxTitle" @click="clickCancelAllSelect">已绑定数据</div>
<div class="boxCenter">
<el-input maxlength="32" show-word-limit v-model.trim="filterText1" :suffix-icon="Search"
<el-input maxlength="32" show-word-limit v-model.trim="filterText1" :suffix-icon="Search"
style="width: 100%" placeholder="请输入搜索内容" clearable></el-input>
<el-tree ref="rightTree" default-expand-all :data="rightData" :props="defaultProps" show-checkbox
node-key="id" :filter-node-method="filterNode">
@@ -78,17 +78,19 @@ export default {
this.leftData = val
const config = useConfig()
this.leftData.forEach(item => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.icon = 'el-icon-Platform'
// item.color = config.getColorVal('elementUiPrimary')
item.color = item.runStatus == 2 ? '#2ab914' : "#e26257"
item.children.forEach(item2 => {
item2.icon = 'el-icon-List'
item2.color = config.getColorVal('elementUiPrimary')
item2.icon = 'local-监测点'
// item2.color = config.getColorVal('elementUiPrimary')
item2.color = item.runStatus == 2 ? '#2ab914' : "#e26257"
item2.children.forEach(item3 => {
item3.icon = 'el-icon-Platform'
item3.icon = 'el-icon-List'
item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) {
item3.color = '#e26257 !important'
}
// if (item3.runStatus === 1) {
// item3.color = '#e26257 !important'
// }
})
})
})
@@ -100,17 +102,19 @@ export default {
const config = useConfig()
this.$emit('getData', this.rightData)
this.rightData.forEach(item => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.icon = 'el-icon-Platform'
// item.color = config.getColorVal('elementUiPrimary')
item.color = item.runStatus == 2 ? '#2ab914' : "#e26257"
item.children.forEach(item2 => {
item2.icon = 'el-icon-List'
item2.color = config.getColorVal('elementUiPrimary')
item2.icon = 'local-监测点'
// item2.color = config.getColorVal('elementUiPrimary')
item2.color = item.runStatus == 2 ? '#2ab914' : "#e26257"
item2.children.forEach(item3 => {
item3.icon = 'el-icon-Platform'
item3.icon = 'el-icon-List'
item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) {
item3.color = '#e26257 !important'
}
// if (item3.runStatus === 1) {
// item3.color = '#e26257 !important'
// }
})
})
})