Files
CN_Tool_client/frontend/src/views/steady/steadyTrend/components/SteadyTrendToolbar.vue
yexb 055e69fff7 feat(steady): 完善稳态数据视图功能
- 更新纵坐标刻度算法,优化小数趋势图范围显示
- 添加稳态趋势图全屏模式和共享工具组件
- 实现多图联动的鼠标悬停竖线同步功能
- 调整主线线宽分档策略,降低最大线宽限制
- 重构稳态趋势工具栏,优化谐波次数选择逻辑
- 添加周时间周期搜索支持和自定义时间范围选择
- 完善稳态数据表格和指示器浮动面板功能
- 优化稳态趋势图性能,添加LTB采样和动画控制
- 修复数据表格打开前的趋势数据验证问题
- 统一时间轴标签格式化和网格对齐处理
2026-05-27 08:06:12 +08:00

223 lines
6.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<section class="card trend-toolbar">
<div class="toolbar-field toolbar-field--time">
<span class="toolbar-field__label">时间</span>
<TimePeriodSearch
class="trend-toolbar__time"
:unit="modelValue.timeUnit"
:model-value="modelValue.timeBaseDate"
@update:unit="handleTimeUnitChange"
@update:model-value="handleTimeBaseDateChange"
/>
</div>
<div class="toolbar-field">
<span class="toolbar-field__label">统计</span>
<el-select
:model-value="modelValue.statType"
placeholder="选择统计类型"
@update:model-value="updateField('statType', $event)"
>
<el-option v-for="item in statOptions" :key="item" :label="statLabelMap[item]" :value="item" />
</el-select>
</div>
<div class="toolbar-field">
<span class="toolbar-field__label">数据质量</span>
<el-switch
:model-value="modelValue.qualityFlag ?? 0"
class="quality-switch"
width="72"
inline-prompt
active-text="有效"
inactive-text="无效"
:active-value="0"
:inactive-value="1"
@update:model-value="handleQualityFlagChange"
/>
</div>
<div v-if="showHarmonicOrders" class="toolbar-field harmonic-select">
<span class="toolbar-field__label">谐波次数</span>
<el-select
:model-value="modelValue.harmonicOrders"
multiple
placeholder="选择谐波次数"
@update:model-value="handleHarmonicOrdersChange"
>
<el-option v-for="item in harmonicOrderOptions" :key="item" :label="`${item}次`" :value="item" />
</el-select>
</div>
<div class="toolbar-actions">
<el-button type="primary" :loading="loading" @click="emit('query')">查询</el-button>
<el-button @click="emit('reset')">重置</el-button>
</div>
</section>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import type { SteadyTrend } from '@/api/steady/steadyTrend/interface'
import TimePeriodSearch from '@/views/components/TimePeriodSearch/index.vue'
import { buildTimePeriodRange, type TimePeriodUnit } from '@/views/components/TimePeriodSearch/timePeriod'
import { MAX_HARMONIC_ORDER_COUNT } from '../utils/selectionRules'
import type { SteadyTrendFormState } from '../utils/trendPayload'
defineOptions({
name: 'SteadyTrendToolbar'
})
const props = defineProps<{
modelValue: SteadyTrendFormState
statOptions: SteadyTrend.SteadyTrendStatType[]
showHarmonicOrders: boolean
loading: boolean
}>()
const emit = defineEmits<{
'update:modelValue': [value: SteadyTrendFormState]
query: []
reset: []
}>()
const harmonicOrderOptions = Array.from({ length: 49 }, (_item, index) => index + 2)
const statLabelMap: Record<SteadyTrend.SteadyTrendStatType, string> = {
AVG: '平均值',
MAX: '最大值',
MIN: '最小值',
CP95: '95%概率大值'
}
const updateField = <K extends keyof SteadyTrendFormState>(field: K, value: SteadyTrendFormState[K]) => {
emit('update:modelValue', {
...props.modelValue,
[field]: value
})
}
const handleQualityFlagChange = (value: string | number | boolean) => {
updateField('qualityFlag', Number(value))
}
const normalizeHarmonicOrders = (orders: number[]) => {
return Array.from(
new Set(
orders
.map(item => Number(item))
.filter(item => Number.isInteger(item) && item >= 2 && item <= 50)
)
).sort((left, right) => left - right)
}
const updateHarmonicOrders = (orders: number[]) => {
const nextOrders = normalizeHarmonicOrders(orders)
if (nextOrders.length > MAX_HARMONIC_ORDER_COUNT) {
ElMessage.warning(`谐波次数最多选择 ${MAX_HARMONIC_ORDER_COUNT}`)
const currentOrders = normalizeHarmonicOrders(props.modelValue.harmonicOrders)
updateField(
'harmonicOrders',
currentOrders.length ? currentOrders : nextOrders.slice(0, MAX_HARMONIC_ORDER_COUNT)
)
return
}
updateField('harmonicOrders', nextOrders)
}
const handleHarmonicOrdersChange = (value: number[]) => {
updateHarmonicOrders(value)
}
const updateTimeRange = (unit: TimePeriodUnit, baseDate: Date) => {
emit('update:modelValue', {
...props.modelValue,
timeUnit: unit,
timeBaseDate: baseDate,
timeRange: buildTimePeriodRange(unit, baseDate)
})
}
const handleTimeUnitChange = (value: TimePeriodUnit) => {
updateTimeRange(value, props.modelValue.timeBaseDate)
}
const handleTimeBaseDateChange = (value: Date) => {
updateTimeRange(props.modelValue.timeUnit, value)
}
</script>
<style scoped lang="scss">
.trend-toolbar {
display: grid;
grid-template-columns: minmax(360px, 1.35fr) repeat(3, minmax(0, 1fr)) auto;
gap: 10px;
align-items: center;
padding: 12px;
}
.toolbar-field {
display: flex;
min-width: 0;
align-items: center;
gap: 6px;
}
.toolbar-field--time {
min-width: 0;
}
.toolbar-field__label {
flex: 0 0 auto;
color: #606266;
font-size: 14px;
white-space: nowrap;
}
.toolbar-field :deep(.el-select) {
flex: 1 1 0;
min-width: 0;
}
.quality-switch {
min-width: 72px;
}
.trend-toolbar__time {
flex: 1 1 0;
min-width: 0;
}
.trend-toolbar__time :deep(.time-period-search__unit) {
width: 72px;
flex: 0 0 72px;
}
.trend-toolbar__time :deep(.time-period-search__picker) {
width: 136px;
flex: 0 0 136px;
}
.harmonic-select {
grid-column: auto;
}
.toolbar-actions {
display: flex;
grid-column: 5;
justify-content: flex-end;
gap: 8px;
}
@media (max-width: 1280px) {
.trend-toolbar {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.toolbar-actions {
justify-content: flex-start;
}
}
</style>