From 0c5861e807c62b4d8813d71466e954580d277bc7 Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 2 Jul 2026 10:30:01 +0800 Subject: [PATCH] =?UTF-8?q?style=EF=BC=9A=E9=A6=96=E9=A1=B5=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F/=E7=AD=9B=E9=80=89=E6=A1=86=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/dashboard/DeviceSection.vue | 268 ++++++++++++++++++--- src/locales/en-US.js | 1 + src/locales/zh-CN.js | 1 + src/pages/index.vue | 7 +- 4 files changed, 236 insertions(+), 41 deletions(-) diff --git a/src/components/dashboard/DeviceSection.vue b/src/components/dashboard/DeviceSection.vue index 0c53458..c9138ff 100644 --- a/src/components/dashboard/DeviceSection.vue +++ b/src/components/dashboard/DeviceSection.vue @@ -44,21 +44,8 @@ {{ t('deviceOverview.rateTrend') }} - - - {{ currentPeriodLabel }} - - - - - - - {{ t('deviceOverview.onlyScheduled') }} - - - - {{ t('deviceOverview.skipHoliday') }} - + + @@ -66,6 +53,37 @@ + + + + {{ t('functionCommon.moreFilter') }} + + + + {{ t('deviceOverview.trendPeriod') }} + + + {{ draftPeriodLabel }} + + + + + + {{ t('deviceOverview.onlyScheduled') }} + + + + {{ t('deviceOverview.skipHoliday') }} + + + + + {{ t('functionCommon.reset') }} + {{ t('functionCommon.confirm') }} + + + + @@ -106,6 +124,7 @@ import { useI18n } from 'vue-i18n' import request from '@/utils/request' const { t } = useI18n() +const trendFilterPopupRef = ref(null) const deviceData = reactive({ totalDevices: 0, @@ -121,6 +140,11 @@ const deviceData = reactive({ const currentPeriod = ref('LAST_7_DAYS') const onlyScheduled = ref(true) const skipHoliday = ref(false) +const draftTrendFilter = reactive({ + period: 'LAST_7_DAYS', + onlyScheduled: true, + skipHoliday: false +}) const periodRange = computed(() => [ { text: t('deviceOverview.periodLastWeek'), value: 'LAST_WEEK' }, @@ -130,8 +154,8 @@ const periodRange = computed(() => [ { text: t('deviceOverview.periodThisMonth'), value: 'THIS_MONTH' } ]) -const periodIndex = computed(() => { - const idx = periodRange.value.findIndex(item => item.value === currentPeriod.value) +const draftPeriodIndex = computed(() => { + const idx = periodRange.value.findIndex(item => item.value === draftTrendFilter.period) return idx >= 0 ? idx : 0 }) @@ -147,6 +171,10 @@ const currentPeriodLabel = computed(() => { return periodLabelMap.value[currentPeriod.value] || t('deviceOverview.periodLast7Days') }) +const draftPeriodLabel = computed(() => { + return periodLabelMap.value[draftTrendFilter.period] || t('deviceOverview.periodLast7Days') +}) + const rankingTitle = computed(() => { const period = currentPeriodLabel.value return t('deviceOverview.utilizationRanking').replace('近7日', period) @@ -180,12 +208,7 @@ const rankingChartOpts = { dataLabel: true, legend: { show: false }, xAxis: { disableGrid: true, max: 100, axisLabel: { padding: [0, 0, 0, 10] } }, - yAxis: { disableGrid: true, axisLabel: { padding: [0, 10, 0, 0], formatter: function(value) { - if (value.length > 10) { - return value.substring(0, 10) + '...'; - } - return value; - } } }, + yAxis: { disableGrid: true, axisLabel: { padding: [0, 10, 0, 0], formatter: formatRankingAxisLabel } }, extra: { bar: { type: 'group', @@ -206,6 +229,23 @@ const rankingChartData = reactive({ series: [{ name: '', data: [] }] }) +function formatRankingAxisLabel(value) { + return truncateByDisplayWidth(value, 6) +} + +function truncateByDisplayWidth(value, maxWidth) { + const text = String(value || '') + let width = 0 + let result = '' + for (const char of text) { + const charWidth = /[^\x00-\xff]/.test(char) ? 1 : 0.5 + if (width + charWidth > maxWidth) return result + '...' + width += charWidth + result += char + } + return text +} + const ITEM_HEIGHT_PX = 30 const MAX_VISIBLE = 6 const rankingScrollHeight = computed(() => { @@ -363,18 +403,56 @@ function onDeviceChange(e) { loadDeviceRateTrend() } -function onPeriodChange(e) { - const idx = e.detail.value +function syncDraftTrendFilter() { + draftTrendFilter.period = currentPeriod.value + draftTrendFilter.onlyScheduled = onlyScheduled.value + draftTrendFilter.skipHoliday = skipHoliday.value +} + +function openTrendFilterDrawer() { + syncDraftTrendFilter() + trendFilterPopupRef.value?.open() +} + +function closeTrendFilterDrawer() { + trendFilterPopupRef.value?.close() +} + +function onTrendFilterPeriodChange(e) { + const idx = Number(e?.detail?.value || 0) const val = periodRange.value[idx]?.value if (!val) return - currentPeriod.value = val - loadRateTrend() - loadUtilizationRanking() - loadDeviceRateTrend() + draftTrendFilter.period = val } -function onSwitchChange() { - loadRateTrend() +async function refreshTrendData() { + await Promise.all([ + loadRateTrend(), + loadUtilizationRanking(), + loadDeviceRateTrend() + ]) +} + +async function confirmTrendFilterDrawer() { + const changed = currentPeriod.value !== draftTrendFilter.period || + onlyScheduled.value !== draftTrendFilter.onlyScheduled || + skipHoliday.value !== draftTrendFilter.skipHoliday + currentPeriod.value = draftTrendFilter.period + onlyScheduled.value = draftTrendFilter.onlyScheduled + skipHoliday.value = draftTrendFilter.skipHoliday + closeTrendFilterDrawer() + if (changed) await refreshTrendData() +} + +async function resetTrendFilterDrawer() { + draftTrendFilter.period = 'LAST_7_DAYS' + draftTrendFilter.onlyScheduled = true + draftTrendFilter.skipHoliday = false + currentPeriod.value = draftTrendFilter.period + onlyScheduled.value = draftTrendFilter.onlyScheduled + skipHoliday.value = draftTrendFilter.skipHoliday + closeTrendFilterDrawer() + await refreshTrendData() } onMounted(async () => { @@ -509,24 +587,136 @@ defineExpose({ loadDeviceOverview, loadRateTrend, loadUtilizationRanking, loadDe color: #999999; } -.switch-bar { +.trend-filter-icon { + width: 56rpx; + height: 56rpx; display: flex; align-items: center; - margin-bottom: 20rpx; - gap: 32rpx; + justify-content: center; + border-radius: 12rpx; + background: #f0f2f5; + + &:active { + background: #e8ecf0; + } } -.switch-item { +:deep(.trend-filter-popup.right .uni-popup__content-transition) { + transform: none !important; +} + +.filter-drawer { + width: 630rpx; + height: calc(100vh - var(--status-bar-height)); + margin-top: var(--status-bar-height); + background: #f5f5f7; + display: flex; + flex-direction: column; + overflow: hidden; + border-radius: 28rpx 0 0 28rpx; +} + +.drawer-header { + height: 104rpx; + padding: 18rpx 34rpx 0; + background: #ffffff; display: flex; align-items: center; - gap: 8rpx; + box-sizing: border-box; } -.switch-label { - font-size: 24rpx; - color: #666666; +.drawer-title { + color: #1f2937; + font-size: 34rpx; + line-height: 1.3; + font-weight: 700; } +.drawer-body { + flex: 1; + min-height: 0; + padding: 28rpx 28rpx 0; + box-sizing: border-box; +} + +.drawer-field, +.drawer-switch-field { + background: #ffffff; + border-radius: 16rpx; + padding: 24rpx 26rpx; + margin-bottom: 22rpx; + box-sizing: border-box; +} + +.drawer-field { + display: flex; + flex-direction: column; + gap: 16rpx; +} + +.drawer-switch-field { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20rpx; +} + +.drawer-label { + font-size: 26rpx; + color: #374151; + font-weight: 500; +} + +.drawer-picker { + height: 72rpx; + border: 1rpx solid #d9dde5; + border-radius: 10rpx; + padding: 0 20rpx; + display: flex; + align-items: center; + justify-content: space-between; + box-sizing: border-box; +} + +.drawer-picker-text { + min-width: 0; + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 26rpx; + color: #1f2937; +} + +.drawer-actions { + flex: 0 0 auto; + padding: 22rpx 28rpx calc(22rpx + env(safe-area-inset-bottom)); + background: #ffffff; + display: flex; + gap: 18rpx; + box-sizing: border-box; +} + +.drawer-action { + flex: 1; + height: 76rpx; + border-radius: 12rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 28rpx; + font-weight: 600; +} + +.drawer-action.reset { + color: #4b5563; + background: #f3f4f6; +} + +.drawer-action.confirm { + color: #ffffff; + background: #1a3a5c; +} .chart-box { width: 100%; height: 450rpx; diff --git a/src/locales/en-US.js b/src/locales/en-US.js index 1a1dc0b..eaee1de 100644 --- a/src/locales/en-US.js +++ b/src/locales/en-US.js @@ -143,6 +143,7 @@ export default { rateTrend: 'Utilization / Boot Rate Trend', onlyScheduled: 'Scheduled Only', skipHoliday: 'Skip Holidays', + trendPeriod: 'Trend Period', periodLastWeek: 'Last Week', periodThisWeek: 'This Week', periodLast7Days: 'Last 7 Days', diff --git a/src/locales/zh-CN.js b/src/locales/zh-CN.js index d19e168..7fba026 100644 --- a/src/locales/zh-CN.js +++ b/src/locales/zh-CN.js @@ -143,6 +143,7 @@ export default { rateTrend: '稼动率/开机率趋势', onlyScheduled: '只统计排产设备', skipHoliday: '跳过节假日', + trendPeriod: '统计周期', periodLastWeek: '上周', periodThisWeek: '本周', periodLast7Days: '近7日', diff --git a/src/pages/index.vue b/src/pages/index.vue index a223b4b..4ea79de 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -1,4 +1,4 @@ -