# Conflicts: # frontend/src/views/machine/freqConverter/components/freqConverterDipChart.vue
821 lines
20 KiB
Vue
821 lines
20 KiB
Vue
<template>
|
|
<el-card class="dip-chart-card" shadow="never">
|
|
<template #header>
|
|
<div class="card-header">
|
|
<div class="card-header-main">
|
|
<div class="card-title">耐受图</div>
|
|
<div class="card-subtitle">
|
|
{{ selectedMappingText }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="header-actions">
|
|
<el-button type="primary" plain :icon="Download" :disabled="!hasChartData" @click="downloadChartImage">
|
|
下载图片
|
|
</el-button>
|
|
<el-button type="primary" plain :icon="Document" :disabled="!hasChartData" @click="exportChartData">
|
|
导出数据
|
|
</el-button>
|
|
<el-button
|
|
v-if="!props.autoDrawCurve"
|
|
type="primary"
|
|
plain
|
|
class="draw-curve-button"
|
|
@click="drawCharacteristicCurve"
|
|
>
|
|
绘制特性曲线
|
|
</el-button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="chart-wrapper">
|
|
<MyEchart ref="chartRef" :options="chartOptions"/>
|
|
</div>
|
|
</el-card>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import {computed, nextTick, ref, watch} from 'vue'
|
|
import {ElMessage} from 'element-plus'
|
|
import {Document, Download} from '@element-plus/icons-vue'
|
|
import * as XLSX from 'xlsx'
|
|
import MyEchart from '@/components/echarts/line/index.vue'
|
|
|
|
type ChartPointStatus = 'pass' | 'fail'
|
|
|
|
interface ChartPoint {
|
|
duration: number
|
|
residualVoltage: number
|
|
status: ChartPointStatus
|
|
}
|
|
|
|
interface CharacteristicCurvePoint {
|
|
duration: number
|
|
residualVoltage: number
|
|
time: string | null
|
|
timeMs: number | null
|
|
}
|
|
|
|
interface NormalizedTolerantPoint {
|
|
duration: number
|
|
residualVoltage: number
|
|
tolerant: number | null
|
|
status: ChartPointStatus
|
|
time: string | null
|
|
timeMs: number | null
|
|
}
|
|
|
|
const props = defineProps<{
|
|
selectedMapping?: Record<string, any> | null
|
|
webMsgSend?: any
|
|
resultData?: any
|
|
autoDrawCurve?: boolean
|
|
}>()
|
|
|
|
const STATUS_COLOR_MAP: Record<ChartPointStatus, string> = {
|
|
pass: '#4e73df',
|
|
fail: '#4b4b4b'
|
|
}
|
|
|
|
const CHARACTERISTIC_POINT_COLOR = '#ff4d4f'
|
|
|
|
const chartPoints = ref<ChartPoint[]>([])
|
|
const characteristicCurveData = ref<CharacteristicCurvePoint[]>([])
|
|
const characteristicCurveVisible = ref(false)
|
|
const chartRef = ref<any>(null)
|
|
|
|
const selectedMappingText = computed(() => {
|
|
if (!props.selectedMapping) {
|
|
return '未选择变频器'
|
|
}
|
|
|
|
return `变频器:${props.selectedMapping.freqConverterName || '-'}`
|
|
})
|
|
|
|
const xAxisMin = computed(() => {
|
|
return 0.001
|
|
// if (!positiveDurations.value.length) {
|
|
// return 0.001
|
|
// }
|
|
//
|
|
// const minValue = Math.min(...positiveDurations.value)
|
|
// return Math.min(0.001, Number(minValue.toFixed(3)))
|
|
})
|
|
|
|
const xAxisMax = computed(() => {
|
|
return 1000
|
|
// if (!positiveDurations.value.length) {
|
|
// return 60
|
|
// }
|
|
//
|
|
// const maxValue = Math.max(...positiveDurations.value)
|
|
// return Math.max(Number((maxValue * 1.05).toFixed(3)), 60)
|
|
})
|
|
|
|
const sortedChartPoints = computed(() => {
|
|
return [...chartPoints.value].sort((a, b) => {
|
|
if (a.duration !== b.duration) {
|
|
return a.duration - b.duration
|
|
}
|
|
|
|
return a.residualVoltage - b.residualVoltage
|
|
})
|
|
})
|
|
|
|
const sortedCharacteristicCurveData = computed(() => {
|
|
return [...characteristicCurveData.value].sort((a, b) => {
|
|
// 保留1位小数
|
|
let aResidualVoltage = Math.floor(a.residualVoltage * 10) / 10
|
|
let bResidualVoltage = Math.floor(b.residualVoltage * 10) / 10
|
|
if (aResidualVoltage != bResidualVoltage) {
|
|
return a.residualVoltage - b.residualVoltage;
|
|
} else {
|
|
let aDuration = a.duration * 1000 - a.duration * 1000 % 10
|
|
let bDuration = b.duration * 1000 - b.duration * 1000 % 10
|
|
if (aDuration != bDuration) {
|
|
return a.duration - b.duration
|
|
} else if (a.timeMs !== null && b.timeMs !== null && a.timeMs !== b.timeMs) {
|
|
return a.timeMs - b.timeMs
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
// if (a.timeMs !== null && b.timeMs !== null && a.timeMs !== b.timeMs) {
|
|
// return a.timeMs - b.timeMs
|
|
// } else {
|
|
// return 0
|
|
// }
|
|
//
|
|
// return a.residualVoltage - b.residualVoltage
|
|
})
|
|
})
|
|
|
|
const solidCharacteristicCurveSeriesData = computed(() => {
|
|
if (!characteristicCurveVisible.value) {
|
|
return [] as Array<[number, number, string]>
|
|
}
|
|
|
|
return sortedCharacteristicCurveData.value.map(item => [item.duration, item.residualVoltage, '特性曲线'])
|
|
})
|
|
|
|
const characteristicCurvePointSeriesData = computed(() => {
|
|
return sortedCharacteristicCurveData.value.map(item => ({
|
|
value: [item.duration, item.residualVoltage, '特性点']
|
|
}))
|
|
})
|
|
|
|
const passPointSeriesData = computed(() => {
|
|
return sortedChartPoints.value
|
|
.filter(item => item.status === 'pass')
|
|
.map(item => ({
|
|
value: [item.duration, item.residualVoltage, getStatusText(item.status)]
|
|
}))
|
|
})
|
|
|
|
const failPointSeriesData = computed(() => {
|
|
return sortedChartPoints.value
|
|
.filter(item => item.status === 'fail')
|
|
.map(item => ({
|
|
value: [item.duration, item.residualVoltage, getStatusText(item.status)]
|
|
}))
|
|
})
|
|
|
|
const hasChartData = computed(() => {
|
|
return sortedChartPoints.value.length > 0 || sortedCharacteristicCurveData.value.length > 0
|
|
})
|
|
|
|
const formatLogDurationLabel = (value: number) => {
|
|
if (!Number.isFinite(value)) {
|
|
return ''
|
|
}
|
|
|
|
if (value >= 1) {
|
|
return `${Number(value.toFixed(2))}`
|
|
}
|
|
|
|
return `${Number(value.toFixed(3))}`
|
|
}
|
|
|
|
const sanitizeFileName = (value: string) => {
|
|
return value.replace(/[\\/:*?"<>|]/g, '_').trim() || '未命名变频器'
|
|
}
|
|
|
|
const buildFileName = (prefix: string, suffix: string) => {
|
|
const freqConverterName = sanitizeFileName(props.selectedMapping?.freqConverterName || '未命名变频器')
|
|
return `${prefix}_${freqConverterName}.${suffix}`
|
|
}
|
|
|
|
const triggerDownload = (url: string, fileName: string) => {
|
|
const link = document.createElement('a')
|
|
link.style.display = 'none'
|
|
link.href = url
|
|
link.download = fileName
|
|
document.body.appendChild(link)
|
|
link.click()
|
|
document.body.removeChild(link)
|
|
}
|
|
|
|
const toNumber = (value: unknown) => {
|
|
const result = Number(value)
|
|
return Number.isFinite(result) ? result : null
|
|
}
|
|
|
|
const parsePointTime = (value: unknown) => {
|
|
if (typeof value !== 'string') {
|
|
return {
|
|
time: null,
|
|
timeMs: null
|
|
}
|
|
}
|
|
|
|
const normalizedValue = value.trim()
|
|
const match = normalizedValue.match(
|
|
/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})\.(\d{3})$/
|
|
)
|
|
|
|
if (!match) {
|
|
return {
|
|
time: normalizedValue || null,
|
|
timeMs: null
|
|
}
|
|
}
|
|
|
|
const [, year, month, day, hour, minute, second, millisecond] = match
|
|
const parsedDate = new Date(
|
|
Number(year),
|
|
Number(month) - 1,
|
|
Number(day),
|
|
Number(hour),
|
|
Number(minute),
|
|
Number(second),
|
|
Number(millisecond)
|
|
)
|
|
|
|
if (
|
|
parsedDate.getFullYear() !== Number(year) ||
|
|
parsedDate.getMonth() !== Number(month) - 1 ||
|
|
parsedDate.getDate() !== Number(day) ||
|
|
parsedDate.getHours() !== Number(hour) ||
|
|
parsedDate.getMinutes() !== Number(minute) ||
|
|
parsedDate.getSeconds() !== Number(second) ||
|
|
parsedDate.getMilliseconds() !== Number(millisecond)
|
|
) {
|
|
return {
|
|
time: normalizedValue,
|
|
timeMs: null
|
|
}
|
|
}
|
|
|
|
return {
|
|
time: normalizedValue,
|
|
timeMs: parsedDate.getTime()
|
|
}
|
|
}
|
|
|
|
const normalizeTolerantValue = (value: unknown) => {
|
|
if (value === undefined || value === null || value === '') {
|
|
return null
|
|
}
|
|
|
|
const result = Number(value)
|
|
if ([0, 1, 2].includes(result)) {
|
|
return result
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
const normalizeDuration = (source: Record<string, any>) => {
|
|
return toNumber(
|
|
source.durationMs !== undefined && source.durationMs !== null
|
|
? Number(source.durationMs) / 1000
|
|
: source.duration ?? source.x ?? source.dipDuration ?? source.retainTime ?? source.durationValue
|
|
)
|
|
}
|
|
|
|
const normalizeResidualVoltageValue = (source: Record<string, any>) => {
|
|
return toNumber(source.residualVoltage ?? source.y ?? source.residual ?? source.voltage ?? source.residual_value)
|
|
}
|
|
|
|
const normalizeStatus = (value: unknown): ChartPointStatus => {
|
|
const rawValue = `${value ?? ''}`.trim().toLowerCase()
|
|
|
|
if (
|
|
value === 0 ||
|
|
rawValue === '0' ||
|
|
rawValue === 'false' ||
|
|
rawValue === 'fail' ||
|
|
rawValue === 'failed' ||
|
|
rawValue.includes('不耐受')
|
|
) {
|
|
return 'fail'
|
|
}
|
|
|
|
return 'pass'
|
|
}
|
|
|
|
const normalizeTolerantPoint = (source: Record<string, any>): NormalizedTolerantPoint | null => {
|
|
const duration = normalizeDuration(source)
|
|
const residualVoltage = normalizeResidualVoltageValue(source)
|
|
const {time, timeMs} = parsePointTime(source.time)
|
|
|
|
if (duration === null || residualVoltage === null) {
|
|
return null
|
|
}
|
|
|
|
if (duration <= 0 || residualVoltage < 0 || residualVoltage > 100) {
|
|
return null
|
|
}
|
|
|
|
const tolerant = normalizeTolerantValue(
|
|
source.tolerant ??
|
|
source.endure ??
|
|
source.isEndure ??
|
|
source.tolerable ??
|
|
source.isTolerable ??
|
|
source.status ??
|
|
source.pointStatus ??
|
|
source.result ??
|
|
source.state
|
|
)
|
|
|
|
return {
|
|
duration,
|
|
residualVoltage,
|
|
tolerant,
|
|
time,
|
|
timeMs,
|
|
status:
|
|
tolerant === 0
|
|
? 'fail'
|
|
: tolerant === 1
|
|
? 'pass'
|
|
: normalizeStatus(
|
|
source.tolerant ??
|
|
source.endure ??
|
|
source.isEndure ??
|
|
source.tolerable ??
|
|
source.isTolerable ??
|
|
source.status ??
|
|
source.pointStatus ??
|
|
source.result ??
|
|
source.state
|
|
)
|
|
}
|
|
}
|
|
|
|
const getStatusText = (status: ChartPointStatus) => {
|
|
return status === 'fail' ? '不耐受' : '耐受'
|
|
}
|
|
|
|
const normalizePoint = (source: Record<string, any>): ChartPoint | null => {
|
|
const point = normalizeTolerantPoint(source)
|
|
if (!point || point.tolerant === 2) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
duration: point.duration,
|
|
residualVoltage: point.residualVoltage,
|
|
status: point.status
|
|
}
|
|
}
|
|
|
|
const extractCharacteristicCurvePoints = (payload: any) => {
|
|
const result: CharacteristicCurvePoint[] = []
|
|
const seen = new Set<string>()
|
|
const rootPayload = payload?.data && typeof payload.data === 'object' ? payload.data : payload
|
|
|
|
const walk = (node: any) => {
|
|
if (!node) {
|
|
return
|
|
}
|
|
|
|
if (Array.isArray(node)) {
|
|
node.forEach(item => walk(item))
|
|
return
|
|
}
|
|
|
|
if (typeof node !== 'object') {
|
|
return
|
|
}
|
|
|
|
const point = normalizeTolerantPoint(node)
|
|
if (point?.tolerant === 2) {
|
|
const key = point.time ? `${point.time}|${point.duration}|${point.residualVoltage}` : `${point.duration}|${point.residualVoltage}`
|
|
if (!seen.has(key)) {
|
|
seen.add(key)
|
|
result.push({
|
|
duration: point.duration,
|
|
residualVoltage: point.residualVoltage,
|
|
time: point.time,
|
|
timeMs: point.timeMs
|
|
})
|
|
}
|
|
}
|
|
|
|
Object.values(node).forEach(item => {
|
|
if (item && typeof item === 'object') {
|
|
walk(item)
|
|
}
|
|
})
|
|
}
|
|
|
|
walk(rootPayload)
|
|
return result
|
|
}
|
|
|
|
const mergeCharacteristicCurvePoints = (points: CharacteristicCurvePoint[]) => {
|
|
if (!points.length) {
|
|
return
|
|
}
|
|
|
|
const existingPointMap = new Map(
|
|
characteristicCurveData.value.map(item => [
|
|
item.time ? `${item.time}|${item.duration}|${item.residualVoltage}` : `${item.duration}|${item.residualVoltage}`,
|
|
item
|
|
] as const)
|
|
)
|
|
|
|
points.forEach(item => {
|
|
const key = item.time ? `${item.time}|${item.duration}|${item.residualVoltage}` : `${item.duration}|${item.residualVoltage}`
|
|
existingPointMap.set(key, item)
|
|
})
|
|
|
|
characteristicCurveData.value = Array.from(existingPointMap.values())
|
|
}
|
|
|
|
const extractPoints = (payload: any) => {
|
|
const result: ChartPoint[] = []
|
|
const seen = new Set<string>()
|
|
const rootPayload = payload?.data && typeof payload.data === 'object' ? payload.data : payload
|
|
|
|
const walk = (node: any) => {
|
|
if (!node) {
|
|
return
|
|
}
|
|
|
|
if (Array.isArray(node)) {
|
|
node.forEach(item => walk(item))
|
|
return
|
|
}
|
|
|
|
if (typeof node !== 'object') {
|
|
return
|
|
}
|
|
|
|
const point = normalizePoint(node)
|
|
if (point) {
|
|
const key = `${point.duration}|${point.residualVoltage}`
|
|
if (!seen.has(key)) {
|
|
seen.add(key)
|
|
result.push(point)
|
|
}
|
|
}
|
|
|
|
Object.values(node).forEach(item => {
|
|
if (item && typeof item === 'object') {
|
|
walk(item)
|
|
}
|
|
})
|
|
}
|
|
|
|
walk(rootPayload)
|
|
return result
|
|
}
|
|
|
|
const updateCharacteristicCurveVisibility = () => {
|
|
if (props.autoDrawCurve) {
|
|
characteristicCurveVisible.value = characteristicCurveData.value.length > 0
|
|
}
|
|
}
|
|
|
|
const drawCharacteristicCurve = () => {
|
|
if (!sortedCharacteristicCurveData.value.length) {
|
|
characteristicCurveVisible.value = false
|
|
ElMessage.warning('暂无特性曲线点')
|
|
return
|
|
}
|
|
|
|
characteristicCurveVisible.value = true
|
|
}
|
|
|
|
const downloadChartImage = async () => {
|
|
if (!hasChartData.value) {
|
|
ElMessage.warning('暂无可下载的图表数据')
|
|
return
|
|
}
|
|
|
|
await nextTick()
|
|
|
|
const chartInstance = chartRef.value?.getChartInstance?.()
|
|
if (!chartInstance) {
|
|
ElMessage.warning('图表尚未渲染完成')
|
|
return
|
|
}
|
|
|
|
const imageUrl = chartInstance.getDataURL({
|
|
type: 'png',
|
|
pixelRatio: 2,
|
|
backgroundColor: '#ffffff'
|
|
})
|
|
|
|
triggerDownload(imageUrl, buildFileName('变频器耐受图', 'png'))
|
|
ElMessage.success('图表图片导出成功')
|
|
}
|
|
|
|
const exportChartData = () => {
|
|
if (!hasChartData.value) {
|
|
ElMessage.warning('暂无可导出的点位数据')
|
|
return
|
|
}
|
|
|
|
const workbook = XLSX.utils.book_new()
|
|
|
|
if (sortedChartPoints.value.length) {
|
|
const pointSheet = XLSX.utils.json_to_sheet(
|
|
sortedChartPoints.value.map((item, index) => ({
|
|
序号: index + 1,
|
|
持续时间_s: item.duration,
|
|
残余电压_pct: item.residualVoltage,
|
|
状态: getStatusText(item.status)
|
|
}))
|
|
)
|
|
XLSX.utils.book_append_sheet(workbook, pointSheet, '耐受点')
|
|
}
|
|
|
|
if (sortedCharacteristicCurveData.value.length) {
|
|
const curveSheet = XLSX.utils.json_to_sheet(
|
|
sortedCharacteristicCurveData.value.map((item, index) => ({
|
|
序号: index + 1,
|
|
持续时间_s: item.duration,
|
|
残余电压_pct: item.residualVoltage,
|
|
时间: item.time ?? ''
|
|
}))
|
|
)
|
|
XLSX.utils.book_append_sheet(workbook, curveSheet, '特性点')
|
|
}
|
|
|
|
const workbookBuffer = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'})
|
|
const blob = new Blob([workbookBuffer], {
|
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
})
|
|
const blobUrl = window.URL.createObjectURL(blob)
|
|
|
|
try {
|
|
triggerDownload(blobUrl, buildFileName('变频器耐受图数据', 'xlsx'))
|
|
ElMessage.success('点位数据导出成功')
|
|
} finally {
|
|
window.URL.revokeObjectURL(blobUrl)
|
|
}
|
|
}
|
|
|
|
const chartOptions = computed(() => {
|
|
return {
|
|
title: {
|
|
text: ''
|
|
},
|
|
grid: {
|
|
top: 30,
|
|
left: 48,
|
|
right: 22,
|
|
bottom: 52
|
|
},
|
|
tooltip: {
|
|
trigger: 'item',
|
|
formatter(params: any) {
|
|
const rawValue = Array.isArray(params.value) ? params.value : params.value?.value
|
|
if (!Array.isArray(rawValue)) {
|
|
return ''
|
|
}
|
|
|
|
const [duration, residualVoltage, statusText] = rawValue
|
|
return [
|
|
`类型: ${params.seriesName}`,
|
|
`持续时间: ${duration} s`,
|
|
`残余电压: ${residualVoltage} %`,
|
|
...(statusText ? [`状态: ${statusText}`] : [])
|
|
].join('<br/>')
|
|
}
|
|
},
|
|
legend: {
|
|
top: 0,
|
|
right: 0,
|
|
data: ['特性曲线', '特性点', '耐受点', '不耐受点']
|
|
},
|
|
xAxis: {
|
|
type: 'log',
|
|
name: '持续时间(s)',
|
|
nameLocation: 'middle',
|
|
nameGap: 34,
|
|
min: xAxisMin.value,
|
|
max: xAxisMax.value,
|
|
logBase: 10,
|
|
minorTick: {
|
|
show: true,
|
|
splitNumber: 10
|
|
},
|
|
minorSplitLine: {
|
|
show: false,
|
|
lineStyle: {
|
|
color: '#e8edf6'
|
|
}
|
|
},
|
|
splitLine: {
|
|
show: true,
|
|
lineStyle: {
|
|
color: '#cfd8e6'
|
|
}
|
|
},
|
|
axisLabel: {
|
|
formatter(value: number) {
|
|
return formatLogDurationLabel(value)
|
|
}
|
|
}
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
name: '残余电压',
|
|
min: 0,
|
|
max: 100,
|
|
interval: 10,
|
|
minorTick: {
|
|
show: true,
|
|
splitNumber: 2
|
|
},
|
|
minorSplitLine: {
|
|
show: true,
|
|
lineStyle: {
|
|
color: '#e8edf6'
|
|
}
|
|
},
|
|
splitLine: {
|
|
lineStyle: {
|
|
color: '#cfd8e6'
|
|
}
|
|
},
|
|
axisLabel: {
|
|
formatter(value: number) {
|
|
return `${value}%`
|
|
}
|
|
}
|
|
},
|
|
dataZoom: [],
|
|
series: [
|
|
{
|
|
name: '特性曲线',
|
|
type: 'line',
|
|
smooth: true,
|
|
showSymbol: false,
|
|
lineStyle: {
|
|
color: CHARACTERISTIC_POINT_COLOR,
|
|
width: 3
|
|
},
|
|
itemStyle: {
|
|
color: CHARACTERISTIC_POINT_COLOR
|
|
},
|
|
data: solidCharacteristicCurveSeriesData.value
|
|
},
|
|
{
|
|
name: '特性点',
|
|
type: 'scatter',
|
|
symbolSize: 10,
|
|
itemStyle: {
|
|
color: CHARACTERISTIC_POINT_COLOR
|
|
},
|
|
data: characteristicCurvePointSeriesData.value
|
|
},
|
|
{
|
|
name: '耐受点',
|
|
type: 'scatter',
|
|
symbolSize: 10,
|
|
itemStyle: {
|
|
color: STATUS_COLOR_MAP.pass
|
|
},
|
|
data: passPointSeriesData.value
|
|
},
|
|
{
|
|
name: '不耐受点',
|
|
type: 'scatter',
|
|
symbolSize: 10,
|
|
itemStyle: {
|
|
color: STATUS_COLOR_MAP.fail
|
|
},
|
|
data: failPointSeriesData.value
|
|
}
|
|
],
|
|
options: {
|
|
animation: false
|
|
}
|
|
}
|
|
})
|
|
|
|
watch(
|
|
() => props.autoDrawCurve,
|
|
newValue => {
|
|
characteristicCurveVisible.value = newValue ? characteristicCurveData.value.length > 0 : false
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
|
|
watch(
|
|
() => props.webMsgSend,
|
|
newValue => {
|
|
if (!newValue) {
|
|
return
|
|
}
|
|
|
|
const nextPoints = extractPoints(newValue)
|
|
if (nextPoints.length) {
|
|
const existingPointMap = new Map(
|
|
chartPoints.value.map(item => [`${item.duration}|${item.residualVoltage}`, item] as const)
|
|
)
|
|
|
|
nextPoints.forEach(item => {
|
|
const key = `${item.duration}|${item.residualVoltage}`
|
|
existingPointMap.set(key, item)
|
|
})
|
|
|
|
chartPoints.value = Array.from(existingPointMap.values())
|
|
}
|
|
|
|
mergeCharacteristicCurvePoints(extractCharacteristicCurvePoints(newValue))
|
|
updateCharacteristicCurveVisibility()
|
|
},
|
|
{deep: true}
|
|
)
|
|
|
|
watch(
|
|
() => props.resultData,
|
|
newValue => {
|
|
if (!newValue) {
|
|
return
|
|
}
|
|
|
|
chartPoints.value = extractPoints(newValue)
|
|
characteristicCurveData.value = extractCharacteristicCurvePoints(newValue)
|
|
updateCharacteristicCurveVisibility()
|
|
},
|
|
{deep: true, immediate: true}
|
|
)
|
|
|
|
watch(
|
|
() => props.selectedMapping,
|
|
() => {
|
|
chartPoints.value = []
|
|
characteristicCurveData.value = []
|
|
characteristicCurveVisible.value = false
|
|
}
|
|
)
|
|
</script>
|
|
|
|
<style scoped>
|
|
.dip-chart-card {
|
|
border: 1px solid var(--el-border-color-light);
|
|
}
|
|
|
|
:deep(.dip-chart-card .el-card__header) {
|
|
padding: 10px 14px;
|
|
}
|
|
|
|
:deep(.dip-chart-card .el-card__body) {
|
|
padding: 10px 14px 14px;
|
|
}
|
|
|
|
.card-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
}
|
|
|
|
.header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.card-header-main {
|
|
min-width: 0;
|
|
}
|
|
|
|
.card-title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: var(--el-text-color-primary);
|
|
}
|
|
|
|
.card-subtitle {
|
|
margin-top: 4px;
|
|
font-size: 13px;
|
|
color: var(--el-text-color-secondary);
|
|
}
|
|
|
|
.chart-wrapper {
|
|
height: 400px;
|
|
}
|
|
</style>
|