- 更新纵坐标刻度算法,优化小数趋势图范围显示 - 添加稳态趋势图全屏模式和共享工具组件 - 实现多图联动的鼠标悬停竖线同步功能 - 调整主线线宽分档策略,降低最大线宽限制 - 重构稳态趋势工具栏,优化谐波次数选择逻辑 - 添加周时间周期搜索支持和自定义时间范围选择 - 完善稳态数据表格和指示器浮动面板功能 - 优化稳态趋势图性能,添加LTB采样和动画控制 - 修复数据表格打开前的趋势数据验证问题 - 统一时间轴标签格式化和网格对齐处理
223 lines
6.1 KiB
Vue
223 lines
6.1 KiB
Vue
<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>
|