<script setup lang="ts">
|
import { computed } from 'vue'
|
import VChart from 'vue-echarts'
|
import type { FormationItem, FormationSettings, FormationStepSelection } from '@/api/formationReports'
|
import { formationCurveMetrics } from '@/utils/formationCycleChart'
|
import { formationCycleKey, formationSelectedSteps, formationStepGroups, formationStepSeries, formationStepChartOption, type FormationStepGroup } from '@/utils/formationStepChart'
|
const props = defineProps<{ items: FormationItem[]; cycle: number | null; settings: FormationSettings; readonly: boolean }>()
|
const emit = defineEmits<{ change: [settings: Partial<FormationSettings>] }>()
|
const metrics = computed(() => formationCurveMetrics.filter(metric => (props.settings.metrics ?? formationCurveMetrics.map(value => value.key)).includes(metric.key)))
|
function choices(item: FormationItem, group: FormationStepGroup) {
|
return (item.chargeSteps?.[props.cycle ?? -1] ?? []).filter(step => step.direction === 'UNKNOWN' || step.direction === (group === 'charge' ? 'CHARGE' : 'DISCHARGE'))
|
}
|
function choose(item: FormationItem, group: FormationStepGroup, values: number[]) {
|
if (props.cycle === null) return
|
const selection: FormationStepSelection = { charge: formationSelectedSteps(item, props.cycle, 'charge', props.settings), discharge: formationSelectedSteps(item, props.cycle, 'discharge', props.settings) }
|
selection[group] = values
|
// 人工未知工步归入一个分组时,从另一组移除,避免同一范围冒充两类工步。
|
const other = group === 'charge' ? 'discharge' : 'charge'
|
selection[other] = selection[other].filter(value => !values.includes(value))
|
emit('change', { curveStepSelections: { ...props.settings.curveStepSelections, [formationCycleKey(item, props.cycle)]: selection } })
|
}
|
function toggle(key: string) {
|
const hidden = props.settings.hiddenSeriesKeys ?? []
|
emit('change', { hiddenSeriesKeys: hidden.includes(key) ? hidden.filter(value => value !== key) : [...hidden, key] })
|
}
|
function color(key: string, value: string | null) { if (value) emit('change', { seriesColors: { ...props.settings.seriesColors, [key]: value } }) }
|
</script>
|
|
<template>
|
<section v-for="group in formationStepGroups" :key="group.key" class="step-curve-group" :data-group="group.key">
|
<h3>{{ group.title }}工步曲线</h3>
|
<div v-if="cycle !== null" class="step-selectors"><label v-for="item in items" :key="formationCycleKey(item, cycle)">
|
<span>{{ item.source.name }} · {{ item.source.batteryGroup }} / {{ item.source.batteryNo }}</span>
|
<el-select :model-value="formationSelectedSteps(item, cycle, group.key, settings)" multiple :disabled="readonly || !item.cycleNos.includes(cycle)" :aria-label="`${group.title}工步 ${item.source.name} ${item.source.batteryNo}`" :placeholder="item.cycleNos.includes(cycle) ? '选择实际工步' : '无该循环'" @update:model-value="choose(item, group.key, $event)">
|
<el-option v-for="step in choices(item, group.key)" :key="step.stepNo" :value="step.stepNo" :label="`${step.stepNo} ${step.name || '未命名工步'}${step.direction === 'UNKNOWN' ? '(类型未知,人工指定)' : ''}`" />
|
</el-select>
|
</label></div>
|
<template v-if="cycle !== null">
|
<div class="step-legend"><div v-for="series in formationStepSeries(items, cycle, group.key, settings)" :key="series.key" class="chart-legend-item">
|
<el-color-picker v-if="!readonly" :model-value="series.color" :aria-label="`${series.name}颜色`" @change="color(series.key, $event)" />
|
<i v-else :style="{ background: series.color }" />
|
<button type="button" :disabled="readonly" :aria-pressed="!series.hidden" :class="{ hidden: series.hidden }" @click="toggle(series.key)">{{ series.name }}</button>
|
</div></div>
|
<div v-if="formationStepSeries(items, cycle, group.key, settings).some(series => series.records.length)" class="step-charts">
|
<article v-for="metric in metrics" :key="metric.key" class="chart-card"><h4>{{ metric.title }} ({{ metric.unit }})</h4><VChart class="metric-chart" :option="formationStepChartOption(metric, items, cycle, group.key, settings)" :update-options="{ notMerge: true }" autoresize /></article>
|
</div>
|
<el-empty v-else description="所选工步暂无已保存实时数据" :image-size="60" />
|
<p v-if="!metrics.length">当前未启用曲线指标</p>
|
<p v-else-if="formationStepSeries(items, cycle, group.key, settings).length && formationStepSeries(items, cycle, group.key, settings).every(series => series.hidden)">当前全部曲线已隐藏</p>
|
</template>
|
</section>
|
</template>
|
|
<style scoped>
|
.step-curve-group{min-width:0;border-top:1px solid #d8e1e9;padding:16px 24px}.step-curve-group h3{font-size:14px}.step-selectors{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.step-selectors label{display:flex;flex-direction:column;gap:6px;min-width:0;font-size:12px;overflow-wrap:anywhere}.step-selectors .el-select{width:100%;min-width:0}.step-legend{display:flex;flex-wrap:wrap;gap:12px;padding:14px 0}.chart-legend-item{display:flex;gap:6px;align-items:flex-start;min-width:0;max-width:100%}.chart-legend-item .el-color-picker{flex-shrink:0}.chart-legend-item i{width:14px;height:14px;flex-shrink:0;margin-top:4px}.chart-legend-item button{font:inherit;font-size:12px;text-align:left;overflow-wrap:anywhere;min-width:0;background:none;border:0;cursor:pointer;color:#52606d}.chart-legend-item button:disabled{cursor:default}.chart-legend-item button.hidden{text-decoration:line-through;opacity:.5}.step-charts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.chart-card{min-width:0;border:1px solid #d8e1e9}.chart-card h4{padding:8px 12px;margin:0;font-size:13px}.metric-chart{height:260px;width:100%}@media(max-width:900px){.step-charts,.step-selectors{grid-template-columns:minmax(0,1fr)}}@media(max-width:680px){.step-curve-group{padding:12px}}
|
</style>
|