feat(web): 告警管理前端页面 + 路由注册 + bugfix
新增: - AlertList 告警列表页: 状态筛选/确认/忽略操作 - AlertRuleList 告警规则页: 创建/编辑/启停管理 - alerts + deviceReadings 前端 API 层 - App.tsx 路由注册 + MainLayout 标题 fallback - wiki/frontend.md 更新页面清单 修复: - ArticleEditor: 修复 unused variable 构建错误 - FollowUpTaskList: 修复 filter(Boolean) 类型窄化问题
This commit is contained in:
109
apps/web/src/api/health/alerts.ts
Normal file
109
apps/web/src/api/health/alerts.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import client from '../client';
|
||||
import type { PaginatedResponse } from '../types';
|
||||
|
||||
// --- Types ---
|
||||
export interface Alert {
|
||||
id: string;
|
||||
patient_id: string;
|
||||
rule_id: string;
|
||||
severity: string;
|
||||
title: string;
|
||||
detail?: Record<string, unknown>;
|
||||
status: string;
|
||||
acknowledged_by?: string;
|
||||
acknowledged_at?: string;
|
||||
resolved_at?: string;
|
||||
created_at: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface AlertRule {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
device_type: string;
|
||||
condition_type: string;
|
||||
condition_params: Record<string, unknown>;
|
||||
severity: string;
|
||||
is_active: boolean;
|
||||
apply_tags?: Record<string, unknown>;
|
||||
notify_roles: unknown[];
|
||||
cooldown_minutes: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface CreateAlertRuleReq {
|
||||
name: string;
|
||||
description?: string;
|
||||
device_type: string;
|
||||
condition_type: string;
|
||||
condition_params: Record<string, unknown>;
|
||||
severity?: string;
|
||||
apply_tags?: Record<string, unknown>;
|
||||
notify_roles?: unknown[];
|
||||
cooldown_minutes?: number;
|
||||
}
|
||||
|
||||
export interface UpdateAlertRuleReq {
|
||||
name?: string;
|
||||
description?: string;
|
||||
condition_params?: Record<string, unknown>;
|
||||
severity?: string;
|
||||
apply_tags?: Record<string, unknown>;
|
||||
notify_roles?: unknown[];
|
||||
cooldown_minutes?: number;
|
||||
version: number;
|
||||
}
|
||||
|
||||
// --- Alert API ---
|
||||
export async function listAlerts(params?: {
|
||||
patient_id?: string;
|
||||
status?: string;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}) {
|
||||
const res = await client.get('/health/alerts', { params });
|
||||
return res.data.data as PaginatedResponse<Alert>;
|
||||
}
|
||||
|
||||
export async function acknowledgeAlert(id: string, version: number) {
|
||||
const res = await client.put(`/health/alerts/${id}/acknowledge`, { version });
|
||||
return res.data.data as Alert;
|
||||
}
|
||||
|
||||
export async function dismissAlert(id: string, version: number) {
|
||||
const res = await client.put(`/health/alerts/${id}/dismiss`, { version });
|
||||
return res.data.data as Alert;
|
||||
}
|
||||
|
||||
export async function resolveAlert(id: string, version: number) {
|
||||
const res = await client.put(`/health/alerts/${id}/resolve`, { version });
|
||||
return res.data.data as Alert;
|
||||
}
|
||||
|
||||
// --- Alert Rule API ---
|
||||
export async function listAlertRules(params?: {
|
||||
device_type?: string;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}) {
|
||||
const res = await client.get('/health/alert-rules', { params });
|
||||
return res.data.data as PaginatedResponse<AlertRule>;
|
||||
}
|
||||
|
||||
export async function createAlertRule(data: CreateAlertRuleReq) {
|
||||
const res = await client.post('/health/alert-rules', data);
|
||||
return res.data.data as AlertRule;
|
||||
}
|
||||
|
||||
export async function updateAlertRule(id: string, data: UpdateAlertRuleReq) {
|
||||
const res = await client.put(`/health/alert-rules/${id}`, data);
|
||||
return res.data.data as AlertRule;
|
||||
}
|
||||
|
||||
export async function deactivateAlertRule(id: string, version: number) {
|
||||
const res = await client.put(`/health/alert-rules/${id}/deactivate`, { version });
|
||||
return res.data.data as AlertRule;
|
||||
}
|
||||
70
apps/web/src/api/health/deviceReadings.ts
Normal file
70
apps/web/src/api/health/deviceReadings.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import client from '../client';
|
||||
import type { PaginatedResponse } from '../types';
|
||||
|
||||
// --- Types ---
|
||||
export interface DeviceReading {
|
||||
id: string;
|
||||
device_id?: string;
|
||||
device_type: string;
|
||||
device_model?: string;
|
||||
raw_value: Record<string, unknown>;
|
||||
measured_at: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface HourlyReading {
|
||||
id: string;
|
||||
device_type: string;
|
||||
hour_start: string;
|
||||
min_val?: number;
|
||||
max_val?: number;
|
||||
avg_val: number;
|
||||
sample_count: number;
|
||||
}
|
||||
|
||||
export interface BatchReadingRequest {
|
||||
device_id: string;
|
||||
device_model?: string;
|
||||
readings: {
|
||||
device_type: string;
|
||||
values: Record<string, unknown>;
|
||||
measured_at: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface BatchResult {
|
||||
accepted: number;
|
||||
duplicates: number;
|
||||
earliest?: string;
|
||||
latest?: string;
|
||||
}
|
||||
|
||||
// --- API ---
|
||||
export async function batchCreateReadings(patientId: string, data: BatchReadingRequest) {
|
||||
const res = await client.post(`/health/patients/${patientId}/device-readings/batch`, data);
|
||||
return res.data.data as BatchResult;
|
||||
}
|
||||
|
||||
export async function queryReadings(params: {
|
||||
patient_id: string;
|
||||
device_type?: string;
|
||||
hours?: number;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}) {
|
||||
const { patient_id, ...query } = params;
|
||||
const res = await client.get(`/health/patients/${patient_id}/device-readings`, { params: query });
|
||||
return res.data.data as PaginatedResponse<DeviceReading>;
|
||||
}
|
||||
|
||||
export async function queryHourlyReadings(params: {
|
||||
patient_id: string;
|
||||
device_type: string;
|
||||
days?: number;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}) {
|
||||
const { patient_id, ...query } = params;
|
||||
const res = await client.get(`/health/patients/${patient_id}/device-readings/hourly`, { params: query });
|
||||
return res.data.data as PaginatedResponse<HourlyReading>;
|
||||
}
|
||||
Reference in New Issue
Block a user