Преглед на файлове

feat(stat): 设备利用率新增近六个月统计切换

Zimo преди 1 седмица
родител
ревизия
e61e1368ea
променени са 2 файла, в които са добавени 61 реда и са изтрити 10 реда
  1. 3 0
      src/api/pms/stat/index.ts
  2. 58 10
      src/views/pms/stat/rdkb/rd-rate.vue

+ 3 - 0
src/api/pms/stat/index.ts

@@ -174,6 +174,9 @@ export const IotStatApi = {
   getRdSevenDayUtilization: async () => {
     return await request.get({ url: `/rq/stat/rd/device/sevenDayUtilization` })
   },
+  getRdSixMonthUtilization: async () => {
+    return await request.get({ url: `/rq/stat/rd/device/sixMonthUtilization` })
+  },
   getRyRate: async (params: any) => {
     return await request.get({ url: `/rq/stat/ry/device/utilizationRate`, params })
   },

+ 58 - 10
src/views/pms/stat/rdkb/rd-rate.vue

@@ -8,19 +8,28 @@ import {
   createTooltip,
   FONT_FAMILY,
   formatDateLabel,
+  formatMonthLabel,
   THEME
 } from '@/utils/kb'
 import { IotStatApi } from '@/api/pms/stat'
 
+type RateRange = 'week' | 'sixMonth'
+
 const chartData = ref<ChartData>({
   xAxis: [],
   series: []
 })
 
 const chartRef = ref<HTMLDivElement>()
+const activeRange = ref<RateRange>('week')
+const rangeOptions: Array<{ label: string; value: RateRange }> = [
+  { label: '近一周', value: 'week' },
+  { label: '近六个月', value: 'sixMonth' }
+]
 let chart: echarts.ECharts | null = null
 const router = useRouter()
 let chartClickBound = false
+let loadRequestId = 0
 
 function formatRate(value: number) {
   return `${Number(value || 0).toFixed(2)}%`
@@ -57,7 +66,7 @@ function getChartOption(data: ChartData): echarts.EChartsOption {
         fontWeight: 500,
         fontFamily: FONT_FAMILY,
         formatter(value: string) {
-          return formatDateLabel(value)
+          return activeRange.value === 'sixMonth' ? formatMonthLabel(value) : formatDateLabel(value)
         }
       }
     },
@@ -152,9 +161,10 @@ function getChartDayRange() {
   const endDate = dayjs(xAxis[xAxis.length - 1])
   if (!startDate.isValid() || !endDate.isValid()) return null
 
+  const rangeUnit = activeRange.value === 'sixMonth' ? 'month' : 'day'
   return [
-    startDate.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
-    endDate.endOf('day').format('YYYY-MM-DD HH:mm:ss')
+    startDate.startOf(rangeUnit).format('YYYY-MM-DD HH:mm:ss'),
+    endDate.endOf(rangeUnit).format('YYYY-MM-DD HH:mm:ss')
   ]
 }
 
@@ -191,9 +201,15 @@ function destroyChart() {
   }
 }
 
-async function loadChart() {
+async function loadChart(range: RateRange = activeRange.value) {
+  const requestId = ++loadRequestId
   try {
-    const res = await IotStatApi.getRdSevenDayUtilization()
+    const res =
+      range === 'sixMonth'
+        ? await IotStatApi.getRdSixMonthUtilization()
+        : await IotStatApi.getRdSevenDayUtilization()
+    if (requestId !== loadRequestId) return
+
     chartData.value = {
       xAxis: res.xAxis || [],
       series: (res.series || []).map((item) => ({
@@ -203,6 +219,7 @@ async function loadChart() {
     }
     renderChart()
   } catch (error) {
+    if (requestId !== loadRequestId) return
     console.error('获取设备利用率失败:', error)
     chartData.value = {
       xAxis: [],
@@ -212,6 +229,10 @@ async function loadChart() {
   }
 }
 
+watch(activeRange, (range) => {
+  loadChart(range)
+})
+
 onMounted(() => {
   initChart()
   loadChart()
@@ -228,12 +249,19 @@ onUnmounted(() => {
 
 <template>
   <div class="panel flex flex-col">
-    <div class="panel-title">
-      <div class="icon-decorator">
-        <span></span>
-        <span></span>
+    <div class="panel-title flex items-center justify-between">
+      <div class="kb-panel-title-text flex items-center">
+        <div class="icon-decorator">
+          <span></span>
+          <span></span>
+        </div>
+        设备利用率
       </div>
-      设备利用率
+      <el-segmented
+        v-model="activeRange"
+        :options="rangeOptions"
+        size="small"
+        class="rate-range-switch" />
     </div>
     <div ref="chartRef" class="flex-1 min-h-0"></div>
   </div>
@@ -241,4 +269,24 @@ onUnmounted(() => {
 
 <style lang="scss" scoped>
 @import url('@/styles/kb.scss');
+
+.rate-range-switch {
+  --el-segmented-item-selected-color: #03409b;
+  --el-segmented-item-selected-bg-color: rgb(255 255 255 / 86%);
+  --el-segmented-bg-color: rgb(31 91 184 / 10%);
+  --el-segmented-item-hover-bg-color: rgb(255 255 255 / 56%);
+
+  min-height: calc(26px * var(--kb-scale, 1));
+  padding: calc(2px * var(--kb-scale, 1));
+  border: 1px solid rgb(31 91 184 / 12%);
+  transform: translateY(calc(-2px * var(--kb-scale, 1)));
+
+  :deep(.el-segmented__item) {
+    min-height: calc(22px * var(--kb-scale, 1));
+    padding: 0 calc(7px * var(--kb-scale, 1));
+    font-size: calc(13px * var(--kb-scale, 1));
+    font-weight: 600;
+    color: #29527f;
+  }
+}
 </style>