feat: build collaboration workspaces

This commit is contained in:
2026-07-03 03:02:36 -07:00
parent bf3dd256ab
commit 4ba2a11b88
53 changed files with 9557 additions and 29 deletions

184
modules/alerts/types.ts Normal file
View File

@@ -0,0 +1,184 @@
import type { IncidentSeverity } from "@/modules/core/types";
export const ALERT_RULE_TYPE_VALUES = ["health", "care", "device", "incident", "admission", "other"] as const;
export type AlertRuleType = (typeof ALERT_RULE_TYPE_VALUES)[number];
export const ALERT_RULE_STATUS_VALUES = ["enabled", "disabled"] as const;
export type AlertRuleStatus = (typeof ALERT_RULE_STATUS_VALUES)[number];
export const ALERT_TRIGGER_STATUS_VALUES = ["open", "acknowledged", "resolved", "closed"] as const;
export type AlertTriggerStatus = (typeof ALERT_TRIGGER_STATUS_VALUES)[number];
export const ALERT_RULE_TYPE_LABELS: Record<AlertRuleType, string> = {
health: "健康",
care: "护理",
device: "设备",
incident: "应急",
admission: "入住",
other: "其他",
};
export const ALERT_RULE_STATUS_LABELS: Record<AlertRuleStatus, string> = {
enabled: "启用",
disabled: "停用",
};
export const ALERT_TRIGGER_STATUS_LABELS: Record<AlertTriggerStatus, string> = {
open: "待处理",
acknowledged: "已确认",
resolved: "已解决",
closed: "已关闭",
};
export type AlertRule = {
id: string;
organizationId: string;
name: string;
ruleType: AlertRuleType;
severity: IncidentSeverity;
status: AlertRuleStatus;
conditionSummary: string;
suggestion: string;
createdAt: string;
updatedAt: string;
};
export type AlertTrigger = {
id: string;
organizationId: string;
ruleId?: string;
ruleName: string;
elderId?: string;
elderName: string;
title: string;
description: string;
status: AlertTriggerStatus;
source: string;
handledByAccountId?: string;
handledByName?: string;
handledAt?: string;
handlingNotes: string;
createdAt: string;
updatedAt: string;
};
export type AlertCenterData = {
metrics: {
enabledRules: number;
openTriggers: number;
criticalTriggers: number;
resolvedTriggers: number;
};
rules: AlertRule[];
triggers: AlertTrigger[];
};
export type AlertRuleInput = {
name: string;
ruleType: AlertRuleType;
severity: IncidentSeverity;
status: AlertRuleStatus;
conditionSummary: string;
suggestion: string;
};
export type AlertTriggerInput = {
ruleId?: string;
elderId?: string;
title: string;
description: string;
status: AlertTriggerStatus;
source: string;
handlingNotes: string;
};
type ValidationSuccess<T> = {
success: true;
data: T;
};
type ValidationFailure = {
success: false;
reason: string;
};
export type ValidationResult<T> = ValidationSuccess<T> | ValidationFailure;
const INCIDENT_SEVERITY_VALUES = ["info", "warning", "critical"] as const satisfies readonly IncidentSeverity[];
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function readString(source: Record<string, unknown>, key: string): string {
const value = source[key];
return typeof value === "string" ? value.trim() : "";
}
function readOptionalString(source: Record<string, unknown>, key: string): string | undefined {
const value = readString(source, key);
return value || undefined;
}
function readEnum<T extends string>(value: unknown, values: readonly T[]): T | null {
return typeof value === "string" ? values.find((item) => item === value) ?? null : null;
}
export function validateAlertRuleInput(value: unknown): ValidationResult<AlertRuleInput> {
if (!isRecord(value)) {
return { success: false, reason: "请求数据格式无效" };
}
const name = readString(value, "name");
if (!name) {
return { success: false, reason: "规则名称不能为空" };
}
const ruleType = readEnum(value.ruleType, ALERT_RULE_TYPE_VALUES);
const severity = readEnum(value.severity, INCIDENT_SEVERITY_VALUES);
const status = readEnum(value.status, ALERT_RULE_STATUS_VALUES);
if (!ruleType || !severity || !status) {
return { success: false, reason: "规则类型、级别或状态无效" };
}
return {
success: true,
data: {
name,
ruleType,
severity,
status,
conditionSummary: readString(value, "conditionSummary"),
suggestion: readString(value, "suggestion"),
},
};
}
export function validateAlertTriggerInput(value: unknown): ValidationResult<AlertTriggerInput> {
if (!isRecord(value)) {
return { success: false, reason: "请求数据格式无效" };
}
const title = readString(value, "title");
if (!title) {
return { success: false, reason: "触发记录标题不能为空" };
}
const status = readEnum(value.status, ALERT_TRIGGER_STATUS_VALUES);
if (!status) {
return { success: false, reason: "触发记录状态无效" };
}
return {
success: true,
data: {
ruleId: readOptionalString(value, "ruleId"),
elderId: readOptionalString(value, "elderId"),
title,
description: readString(value, "description"),
status,
source: readString(value, "source"),
handlingNotes: readString(value, "handlingNotes"),
},
};
}