From 2776a53e912d71955437d1f46bf7c129b1b21536 Mon Sep 17 00:00:00 2001 From: HVAC001 Date: Tue, 23 Sep 2025 11:09:49 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A2=84=E8=AD=A6=E5=88=86=E6=9E=90=EF=BC=88?= =?UTF-8?q?=E6=97=A5=E6=8A=A5=E6=9C=88=E6=8A=A5=E5=92=8C=E5=B9=B4=E6=8A=A5?= =?UTF-8?q?=EF=BC=89=E5=88=B6=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/alarm/analysis/Day.ts | 73 +++++++ src/api/alarm/analysis/Month.ts | 66 ++++++ src/api/alarm/analysis/Year.ts | 66 ++++++ src/views/alarm/analysis/day/CustomModal.vue | 125 ++++++++++++ src/views/alarm/analysis/day/Day.ts | 147 ++++++++++++++ .../alarm/analysis/day/GzpDetailModal.vue | 79 +++++++ src/views/alarm/analysis/day/index.vue | 174 ++++++++++++++++ .../alarm/analysis/month/CustomModal.vue | 123 +++++++++++ .../alarm/analysis/month/GzpDetailModal.vue | 78 +++++++ src/views/alarm/analysis/month/Month.ts | 149 ++++++++++++++ src/views/alarm/analysis/month/index.vue | 192 ++++++++++++++++++ src/views/alarm/analysis/year/CustomModal.vue | 119 +++++++++++ .../alarm/analysis/year/GzpDetailModal.vue | 76 +++++++ src/views/alarm/analysis/year/Year.ts | 145 +++++++++++++ src/views/alarm/analysis/year/index.vue | 170 ++++++++++++++++ 15 files changed, 1782 insertions(+) create mode 100644 src/api/alarm/analysis/Day.ts create mode 100644 src/api/alarm/analysis/Month.ts create mode 100644 src/api/alarm/analysis/Year.ts create mode 100644 src/views/alarm/analysis/day/CustomModal.vue create mode 100644 src/views/alarm/analysis/day/Day.ts create mode 100644 src/views/alarm/analysis/day/GzpDetailModal.vue create mode 100644 src/views/alarm/analysis/day/index.vue create mode 100644 src/views/alarm/analysis/month/CustomModal.vue create mode 100644 src/views/alarm/analysis/month/GzpDetailModal.vue create mode 100644 src/views/alarm/analysis/month/Month.ts create mode 100644 src/views/alarm/analysis/month/index.vue create mode 100644 src/views/alarm/analysis/year/CustomModal.vue create mode 100644 src/views/alarm/analysis/year/GzpDetailModal.vue create mode 100644 src/views/alarm/analysis/year/Year.ts create mode 100644 src/views/alarm/analysis/year/index.vue diff --git a/src/api/alarm/analysis/Day.ts b/src/api/alarm/analysis/Day.ts new file mode 100644 index 0000000..a952466 --- /dev/null +++ b/src/api/alarm/analysis/Day.ts @@ -0,0 +1,73 @@ +import { formatToDateTime } from '@/utils/dateUtil' +import { defHttp } from '@/utils/http/axios' + +// 类型定义 +export interface AlarmRecord { + id: string + instanceName: string + totalAlarms: number + alarmDuration: string + hasDetails?: boolean + // 动态小时数据 + hourCounts: { [key: `hour_${number}`]: number } + +} + +export interface AlarmApiResponse { + code: number + list: AlarmRecord[] + total: number + msg: string +} +export interface AlarmDetail { + tagname: string + alarmcount: number + alarmtime: number +} + +export interface AlarmQueryParams { + unit?: string + driverType?: '模型' | '规则' + date?: string +} + +// API接口 +export function fetchAlarmData(params: AlarmQueryParams): Promise { + return defHttp.get({ url: '/alarm/daily-report', params }) +} + +export function fetchAlarmDetails(id: string, date?: string) { + return defHttp.get({ + url: `/alarm/details/${id}`, + params: { date }, // 传递日期参数 + }) +} +export interface GzpAlarmDetail { + gzpName: string + startTime: string + endTime: string + duration: number +} + +export function fetchGzpAlarmDetails( + gzpName: string, + instanceId: string, + date?: string, +): Promise { + return defHttp.get({ + url: `/alarm/gzp-details/${gzpName}`, + params: { instanceId, date }, + }).then((res) => { + // 转换时间戳为格式化字符串 + return res.map((item: any) => ({ + gzpName: item.gzpName, + startTime: formatToDateTime(item.startTime), + endTime: formatToDateTime(item.endTime), + /* 后端controller层传过来的日期格式是对的 + 但前端收到的是ms(错误),可能是Java 后 + 端返回的 LocalDateTime 对象被 Spring 默认的 JSON 序列化器转换成了时间戳 + 故在前端进行时间转化 */ + duration: item.duration, + })) + }) +} diff --git a/src/api/alarm/analysis/Month.ts b/src/api/alarm/analysis/Month.ts new file mode 100644 index 0000000..889565a --- /dev/null +++ b/src/api/alarm/analysis/Month.ts @@ -0,0 +1,66 @@ +import { formatToDateTime } from '@/utils/dateUtil' +import { defHttp } from '@/utils/http/axios' + +export interface AlarmRecord { + id: string + instanceName: string + totalAlarms: number + alarmDuration: string + hasDetails?: boolean + dayCounts: { [key: `day_${number}`]: number } +} + +export interface AlarmApiResponse { + code: number + list: AlarmRecord[] + total: number + msg: string +} + +export interface AlarmDetail { + tagname: string + alarmcount: number + alarmtime: number +} + +export interface AlarmQueryParams { + unit?: string + driverType?: '模型' | '规则' + month?: string +} + +export interface GzpAlarmDetail { + gzpName: string + startTime: string + endTime: string + duration: number +} + +export function fetchAlarmData(params: AlarmQueryParams): Promise { + return defHttp.get({ url: '/alarm/monthly-report', params }) +} + +export function fetchAlarmDetails(id: string, month?: string): Promise { + return defHttp.get({ + url: `/alarm/monthly-details/${id}`, + params: { month }, + }) +} + +export function fetchGzpAlarmDetails( + gzpName: string, + instanceId: string, + month?: string, +): Promise { + return defHttp.get({ + url: `/alarm/monthly-gzp-details/${gzpName}`, + params: { instanceId, month }, + }).then((res: any) => { + return res.map((item: any) => ({ + gzpName: item.gzpName, + startTime: formatToDateTime(item.startTime), + endTime: formatToDateTime(item.endTime), + duration: item.duration, + })) + }) +} diff --git a/src/api/alarm/analysis/Year.ts b/src/api/alarm/analysis/Year.ts new file mode 100644 index 0000000..816baa3 --- /dev/null +++ b/src/api/alarm/analysis/Year.ts @@ -0,0 +1,66 @@ +import { formatToDateTime } from '@/utils/dateUtil' +import { defHttp } from '@/utils/http/axios' + +export interface AlarmRecord { + id: string + instanceName: string + totalAlarms: number + alarmDuration: string + hasDetails?: boolean + monthCounts: { [key: `month_${number}`]: number } +} + +export interface AlarmApiResponse { + code: number + list: AlarmRecord[] + total: number + msg: string +} + +export interface AlarmDetail { + tagname: string + alarmcount: number + alarmtime: number +} + +export interface AlarmQueryParams { + unit?: string + driverType?: '模型' | '规则' + year?: string +} + +export function fetchAlarmData(params: AlarmQueryParams): Promise { + return defHttp.get({ url: '/alarm/yearly-report', params }) +} + +export function fetchAlarmDetails(id: string, year?: string) { + return defHttp.get({ + url: `/alarm/yearly-details/${id}`, + params: { year }, + }) +} + +export interface GzpAlarmDetail { + gzpName: string + startTime: string + endTime: string + duration: number +} + +export function fetchGzpAlarmDetails( + gzpName: string, + instanceId: string, + year?: string, +): Promise { + return defHttp.get({ + url: `/alarm/yearly-gzp-details/${gzpName}`, + params: { instanceId, year }, + }).then((res) => { + return res.map((item: any) => ({ + gzpName: item.gzpName, + startTime: formatToDateTime(item.startTime), + endTime: formatToDateTime(item.endTime), + duration: item.duration, + })) + }) +} diff --git a/src/views/alarm/analysis/day/CustomModal.vue b/src/views/alarm/analysis/day/CustomModal.vue new file mode 100644 index 0000000..c4a632a --- /dev/null +++ b/src/views/alarm/analysis/day/CustomModal.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/src/views/alarm/analysis/day/Day.ts b/src/views/alarm/analysis/day/Day.ts new file mode 100644 index 0000000..21a3a2c --- /dev/null +++ b/src/views/alarm/analysis/day/Day.ts @@ -0,0 +1,147 @@ +import dayjs from 'dayjs' +import { h } from 'vue' +import type { BasicColumn, FormSchema } from '@/components/Table' + +interface HourColumn extends BasicColumn { + dataIndex: `hour_${number}` + ifShow?: boolean +} + +function generateHourColumns(): HourColumn[] { + return Array.from({ length: 24 }, (_, i) => ({ + title: `${i}时`, + dataIndex: `hour_${i}`, + width: 60, + align: 'center', + ifShow: true, + customRender: ({ text }: { text: number }) => { + if (text > 10) + return h('span', { style: { color: 'red', fontWeight: 'bold' } }, text) + else if (text > 0) + return h('span', { style: { color: 'blue' } }, text) + + return text || 0 + }, + })) +} + +export const columns: BasicColumn[] = [ + { + title: '实例名称', + dataIndex: 'instanceName', + width: 180, + fixed: 'left', + }, + ...generateHourColumns(), + { + title: '总报警数量', + dataIndex: 'totalAlarms', + width: 100, + fixed: 'right', + sorter: true, + }, + + { + title: '报警时长', + dataIndex: 'alarmDuration', + width: 100, + fixed: 'right', + }, +] + +export const detailColumns: BasicColumn[] = [ + { + title: '光字牌名称', + dataIndex: 'tagname', + width: 220, + }, + { + title: '报警数量', + dataIndex: 'alarmcount', + width: 100, + }, + + { + title: '报警时长', + dataIndex: 'alarmtime', + width: 180, + }, + +] + +interface SelectComponentProps { + options: Array<{ label: string, value: string }> + placeholder?: string + allowClear?: boolean +} + +export const searchFormSchemas: FormSchema[] = [ + { + field: 'unit', + label: '机组', + component: 'Select', + defaultValue: '1', + componentProps: { + options: [ + { label: '1号机组', value: '1' }, + ], + placeholder: '请选择机组', + allowClear: true, + + } as SelectComponentProps, + colProps: { span: 5 }, + }, + { + field: 'driverType', + label: '驱动类型', + component: 'Select', + defaultValue: '模型', + componentProps: { + options: [ + { label: '模型驱动', value: '模型' }, + { label: '规则驱动', value: '规则' }, + ], + placeholder: '请选择驱动类型', + allowClear: true, + + } as SelectComponentProps, + colProps: { span: 5 }, + }, + { + field: 'date', + label: '日期', + component: 'DatePicker', + defaultValue: dayjs().format('YYYY-MM-DD'), + componentProps: { + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + placeholder: '请选择日期', + allowClear: false, + + }, + colProps: { span: 8 }, + }, +] + +export const gzpDetailColumns: BasicColumn[] = [ + { + title: '光字牌名称', + dataIndex: 'gzpName', + width: 220, + }, + { + title: '开始时间', + dataIndex: 'startTime', + width: 180, + }, + { + title: '结束时间', + dataIndex: 'endTime', + width: 180, + }, + { + title: '超限时长', + dataIndex: 'duration', + width: 120, + }, +] diff --git a/src/views/alarm/analysis/day/GzpDetailModal.vue b/src/views/alarm/analysis/day/GzpDetailModal.vue new file mode 100644 index 0000000..df6401a --- /dev/null +++ b/src/views/alarm/analysis/day/GzpDetailModal.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/src/views/alarm/analysis/day/index.vue b/src/views/alarm/analysis/day/index.vue new file mode 100644 index 0000000..ca5e2e0 --- /dev/null +++ b/src/views/alarm/analysis/day/index.vue @@ -0,0 +1,174 @@ + + + + + diff --git a/src/views/alarm/analysis/month/CustomModal.vue b/src/views/alarm/analysis/month/CustomModal.vue new file mode 100644 index 0000000..870429c --- /dev/null +++ b/src/views/alarm/analysis/month/CustomModal.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/views/alarm/analysis/month/GzpDetailModal.vue b/src/views/alarm/analysis/month/GzpDetailModal.vue new file mode 100644 index 0000000..3260641 --- /dev/null +++ b/src/views/alarm/analysis/month/GzpDetailModal.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/views/alarm/analysis/month/Month.ts b/src/views/alarm/analysis/month/Month.ts new file mode 100644 index 0000000..304a338 --- /dev/null +++ b/src/views/alarm/analysis/month/Month.ts @@ -0,0 +1,149 @@ +import dayjs from 'dayjs' +import { h } from 'vue' +import type { BasicColumn, FormSchema } from '@/components/Table' + +interface DayColumn extends BasicColumn { + dataIndex: `day_${number}` + ifShow?: boolean +} + +function generateDayColumns(year: number, month: number): DayColumn[] { + const daysInMonth = dayjs(`${year}-${month}`).daysInMonth() + return Array.from({ length: daysInMonth }, (_, i) => { + const day = i + 1 + return { + title: `${day}日`, + dataIndex: `day_${day}`, + width: 60, + align: 'center', + ifShow: true, + customRender: ({ text }: { text: number }) => { + if (text > 10) + return h('span', { style: { color: 'red', fontWeight: 'bold' } }, text) + else if (text > 0) + return h('span', { style: { color: 'blue' } }, text) + + return text || 0 + }, + } + }) +} + +export const columns: BasicColumn[] = [ + { + title: '实例名称', + dataIndex: 'instanceName', + width: 180, + fixed: 'left', + }, + { + title: '总报警数量', + dataIndex: 'totalAlarms', + width: 100, + fixed: 'right', + sorter: true, + }, + { + title: '报警时长', + dataIndex: 'alarmDuration', + width: 100, + fixed: 'right', + }, +] + +export const detailColumns: BasicColumn[] = [ + { + title: '光字牌名称', + dataIndex: 'tagname', + width: 220, + fixed: 'left', + }, + { + title: '报警数量', + dataIndex: 'alarmcount', + width: 100, + }, + { + title: '报警时长', + dataIndex: 'alarmtime', + width: 120, + }, +] + +interface SelectComponentProps { + options: Array<{ label: string, value: string }> + placeholder?: string + allowClear?: boolean +} + +export const searchFormSchemas: FormSchema[] = [ + { + field: 'unit', + label: '机组', + component: 'Select', + defaultValue: '1', + componentProps: { + options: [ + { label: '1号机组', value: '1' }, + ], + placeholder: '请选择机组', + allowClear: true, + } as SelectComponentProps, + colProps: { span: 5 }, + }, + { + field: 'driverType', + label: '驱动类型', + component: 'Select', + defaultValue: '模型', + componentProps: { + options: [ + { label: '模型驱动', value: '模型' }, + { label: '规则驱动', value: '规则' }, + ], + placeholder: '请选择驱动类型', + allowClear: true, + + } as SelectComponentProps, + colProps: { span: 5 }, + }, + { + field: 'month', + label: '月份', + component: 'MonthPicker', + defaultValue: dayjs().format('YYYY-MM'), + componentProps: { + format: 'YYYY-MM', + valueFormat: 'YYYY-MM', + placeholder: '请选择月份', + allowClear: false, + }, + colProps: { span: 8 }, + }, +] + +export const gzpDetailColumns: BasicColumn[] = [ + { + title: '光字牌名称', + dataIndex: 'gzpName', + width: 200, + fixed: 'left', + }, + { + title: '开始时间', + dataIndex: 'startTime', + width: 180, + }, + { + title: '结束时间', + dataIndex: 'endTime', + width: 180, + }, + { + title: '超限时长', + dataIndex: 'duration', + width: 120, + }, +] + +export { generateDayColumns } diff --git a/src/views/alarm/analysis/month/index.vue b/src/views/alarm/analysis/month/index.vue new file mode 100644 index 0000000..bd45a79 --- /dev/null +++ b/src/views/alarm/analysis/month/index.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/src/views/alarm/analysis/year/CustomModal.vue b/src/views/alarm/analysis/year/CustomModal.vue new file mode 100644 index 0000000..f06b43b --- /dev/null +++ b/src/views/alarm/analysis/year/CustomModal.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/src/views/alarm/analysis/year/GzpDetailModal.vue b/src/views/alarm/analysis/year/GzpDetailModal.vue new file mode 100644 index 0000000..1df38f7 --- /dev/null +++ b/src/views/alarm/analysis/year/GzpDetailModal.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/src/views/alarm/analysis/year/Year.ts b/src/views/alarm/analysis/year/Year.ts new file mode 100644 index 0000000..65ef371 --- /dev/null +++ b/src/views/alarm/analysis/year/Year.ts @@ -0,0 +1,145 @@ +import dayjs from 'dayjs' +import { h } from 'vue' +import type { BasicColumn, FormSchema } from '@/components/Table' + +interface MonthColumn extends BasicColumn { + dataIndex: `month_${number}` + ifShow?: boolean +} + +function generateMonthColumns(): MonthColumn[] { + return Array.from({ length: 12 }, (_, i) => ({ + title: `${i + 1}月`, + dataIndex: `month_${i + 1}`, + width: 60, + align: 'center', + ifShow: true, + customRender: ({ text }: { text: number }) => { + if (text > 10) + return h('span', { style: { color: 'red' } }, text) + else if (text > 0 && text <= 10) + return h('span', { style: { color: 'blue' } }, text) + + return text + }, + })) +} + +export const columns: BasicColumn[] = [ + { + title: '实例名称', + dataIndex: 'instanceName', + width: 180, + fixed: 'left', + }, + ...generateMonthColumns(), + { + title: '总报警数量', + dataIndex: 'totalAlarms', + width: 100, + fixed: 'right', + sorter: true, + }, + { + title: '报警时长', + dataIndex: 'alarmDuration', + width: 100, + fixed: 'right', + }, +] + +export const detailColumns: BasicColumn[] = [ + { + title: '光字牌名称', + dataIndex: 'tagname', + width: 220, + }, + { + title: '报警数量', + dataIndex: 'alarmcount', + width: 100, + }, + { + title: '报警时长', + dataIndex: 'alarmtime', + width: 180, + }, +] + +interface SelectComponentProps { + options: Array<{ label: string, value: string }> + placeholder?: string + allowClear?: boolean +} + +export const searchFormSchemas: FormSchema[] = [ + { + field: 'unit', + label: '机组', + component: 'Select', + defaultValue: '1', + componentProps: { + options: [ + { label: '1号机组', value: '1' }, + ], + placeholder: '请选择机组', + allowClear: true, + + } as SelectComponentProps, + colProps: { span: 5 }, + }, + { + field: 'driverType', + label: '驱动类型', + component: 'Select', + defaultValue: '模型', + componentProps: { + options: [ + { label: '模型驱动', value: '模型' }, + { label: '规则驱动', value: '规则' }, + ], + placeholder: '请选择驱动类型', + allowClear: true, + + } as SelectComponentProps, + colProps: { span: 5 }, + }, + { + field: 'year', + label: '年份', + component: 'DatePicker', + defaultValue: dayjs().format('YYYY'), + componentProps: { + format: 'YYYY', + valueFormat: 'YYYY', + placeholder: '请选择年份', + allowClear: false, + picker: 'year', + + }, + colProps: { span: 8 }, + }, +] + +export const gzpDetailColumns: BasicColumn[] = [ + { + title: '光字牌名称', + dataIndex: 'gzpName', + width: 220, + }, + { + title: '开始时间', + dataIndex: 'startTime', + width: 180, + }, + { + title: '结束时间', + dataIndex: 'endTime', + width: 180, + }, + { + title: '超限时长', + dataIndex: 'duration', + width: 120, + }, +] diff --git a/src/views/alarm/analysis/year/index.vue b/src/views/alarm/analysis/year/index.vue new file mode 100644 index 0000000..3eaa5c7 --- /dev/null +++ b/src/views/alarm/analysis/year/index.vue @@ -0,0 +1,170 @@ + + + + +