Files
teatea-pension/modules/core/server/default-workspace-data.ts

1612 lines
51 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { eq } from "drizzle-orm";
import { getDatabase } from "@/modules/core/server/db";
import {
admissions,
alertRules,
alertTriggers,
beds,
buildings,
campuses,
careTasks,
chronicConditions,
deviceAssets,
elders,
familyContacts,
familyFeedback,
familyVisitAppointments,
floors,
healthAnomalyReviews,
healthProfiles,
maintenanceTickets,
notices,
rooms,
systemIncidents,
vitalRecords,
} from "@/modules/core/server/schema";
type SeedRoom = {
buildingName: string;
campusName: string;
code: string;
floorLevel: number;
floorName: string;
name: string;
capacity: number;
};
type SeedBed = {
code: string;
notes: string;
roomCode: string;
status: "available" | "occupied" | "maintenance" | "disabled";
};
type SeedElder = {
age: number;
careLevel: "self-care" | "semi-assisted" | "assisted" | "intensive";
gender: "male" | "female" | "other";
medicalNotes: string;
name: string;
phone: string;
primaryContact: string;
status: "active" | "pending" | "discharged";
};
type SeedAdmission = {
bedCode: string;
elderName: string;
notes: string;
status: "active" | "transferred" | "discharged";
};
type SeedHealthProfile = {
allergyNotes: string;
careRestrictions: string;
elderName: string;
emergencyNotes: string;
medicalHistory: string;
medicationNotes: string;
};
type SeedVitalRecord = {
bloodGlucoseTenths?: number;
diastolicBp?: number;
elderName: string;
heartRate?: number;
notes: string;
recordedHoursAgo: number;
source: "manual" | "device" | "import";
spo2?: number;
systolicBp?: number;
temperatureTenths?: number;
weightTenths?: number;
};
type SeedChronicCondition = {
elderName: string;
followUpNotes: string;
name: string;
status: "active" | "controlled" | "resolved";
treatmentNotes: string;
};
type SeedHealthReview = {
description: string;
elderName: string;
resolutionNotes: string;
severity: "info" | "warning" | "critical";
status: "pending" | "reviewed" | "resolved";
title: string;
vitalIndex: number;
};
type SeedCareTask = {
assigneeLabel: string;
careType: "daily_care" | "meal" | "medication" | "rehab" | "inspection" | "cleaning" | "other";
completedHoursAgo?: number;
elderName: string;
executionNotes: string;
priority: "low" | "normal" | "high" | "urgent";
scheduledHoursOffset: number;
status: "pending" | "in_progress" | "completed" | "cancelled";
title: string;
};
type SeedSystemIncident = {
acknowledgedHoursAgo?: number;
createdHoursAgo: number;
description: string;
resolvedHoursAgo?: number;
severity: "info" | "warning" | "critical";
source: string;
status: "open" | "acknowledged" | "resolved" | "closed";
title: string;
};
type SeedDeviceAsset = {
category: string;
code: string;
lastInspectedHoursAgo?: number;
location: string;
name: string;
notes: string;
status: "active" | "maintenance" | "disabled" | "retired";
};
type SeedMaintenanceTicket = {
assigneeLabel: string;
description: string;
deviceCode: string;
priority: "low" | "normal" | "high" | "urgent";
resolutionNotes: string;
status: "open" | "assigned" | "resolved" | "closed" | "cancelled";
title: string;
};
type SeedNotice = {
audience: string;
content: string;
publishedHoursAgo?: number;
status: "draft" | "published" | "retracted";
title: string;
};
type SeedAlertRule = {
conditionSummary: string;
name: string;
ruleType: "health" | "care" | "device" | "incident" | "admission" | "other";
severity: "info" | "warning" | "critical";
status: "enabled" | "disabled";
suggestion: string;
};
type SeedAlertTrigger = {
createdHoursAgo: number;
description: string;
elderName?: string;
handlingNotes: string;
ruleName: string;
source: string;
status: "open" | "acknowledged" | "resolved" | "closed";
title: string;
};
type SeedFamilyContact = {
elderName: string;
name: string;
notes: string;
phone: string;
relationship: string;
status: "active" | "suspended" | "archived";
};
type SeedFamilyVisit = {
contactName: string;
elderName: string;
notes: string;
scheduledHoursOffset: number;
status: "requested" | "approved" | "completed" | "cancelled";
};
type SeedFamilyFeedback = {
contactName: string;
content: string;
elderName: string;
feedbackType: "service" | "care" | "meal" | "environment" | "other";
responseNotes: string;
status: "open" | "in_progress" | "resolved" | "closed";
};
const DEFAULT_ROOMS: SeedRoom[] = [
{ campusName: "主院区", buildingName: "护理楼", floorName: "一层", floorLevel: 1, code: "A101", name: "阳光房", capacity: 2 },
{ campusName: "主院区", buildingName: "护理楼", floorName: "一层", floorLevel: 1, code: "A102", name: "康养房", capacity: 2 },
{ campusName: "主院区", buildingName: "护理楼", floorName: "二层", floorLevel: 2, code: "A201", name: "记忆照护房", capacity: 2 },
{ campusName: "主院区", buildingName: "护理楼", floorName: "二层", floorLevel: 2, code: "A202", name: "重点照护房", capacity: 2 },
{ campusName: "主院区", buildingName: "护理楼", floorName: "三层", floorLevel: 3, code: "A301", name: "失能照护房", capacity: 2 },
{ campusName: "主院区", buildingName: "护理楼", floorName: "三层", floorLevel: 3, code: "A302", name: "安宁照护房", capacity: 2 },
{ campusName: "主院区", buildingName: "康复楼", floorName: "一层", floorLevel: 1, code: "R101", name: "康复观察房", capacity: 2 },
{ campusName: "主院区", buildingName: "康复楼", floorName: "一层", floorLevel: 1, code: "R102", name: "短住评估房", capacity: 2 },
{ campusName: "主院区", buildingName: "康复楼", floorName: "二层", floorLevel: 2, code: "R201", name: "术后康复房", capacity: 2 },
{ campusName: "主院区", buildingName: "康复楼", floorName: "二层", floorLevel: 2, code: "R202", name: "认知训练房", capacity: 2 },
{ campusName: "北苑院区", buildingName: "颐养楼", floorName: "一层", floorLevel: 1, code: "B101", name: "自理房", capacity: 2 },
{ campusName: "北苑院区", buildingName: "颐养楼", floorName: "二层", floorLevel: 2, code: "B201", name: "亲情套房", capacity: 2 },
{ campusName: "北苑院区", buildingName: "颐养楼", floorName: "二层", floorLevel: 2, code: "B202", name: "陪护套房", capacity: 2 },
{ campusName: "南苑院区", buildingName: "医养楼", floorName: "一层", floorLevel: 1, code: "S101", name: "医养观察房", capacity: 2 },
{ campusName: "南苑院区", buildingName: "医养楼", floorName: "一层", floorLevel: 1, code: "S102", name: "短期托养房", capacity: 2 },
];
const DEFAULT_BEDS: SeedBed[] = [
{ code: "A101-1", roomCode: "A101", status: "occupied", notes: "靠窗,已完成入住评估" },
{ code: "A101-2", roomCode: "A101", status: "available", notes: "可安排半护理老人入住" },
{ code: "A102-1", roomCode: "A102", status: "occupied", notes: "夜间巡护重点关注" },
{ code: "A102-2", roomCode: "A102", status: "maintenance", notes: "床头呼叫器检修中" },
{ code: "A201-1", roomCode: "A201", status: "occupied", notes: "记忆照护专区" },
{ code: "A201-2", roomCode: "A201", status: "available", notes: "靠近护理站" },
{ code: "A202-1", roomCode: "A202", status: "occupied", notes: "压疮风险重点巡查" },
{ code: "A202-2", roomCode: "A202", status: "disabled", notes: "待更换护栏" },
{ code: "A301-1", roomCode: "A301", status: "occupied", notes: "失能照护,配置防跌倒垫" },
{ code: "A301-2", roomCode: "A301", status: "available", notes: "鼻饲护理设备已消毒待用" },
{ code: "A302-1", roomCode: "A302", status: "available", notes: "家属陪伴预约优先" },
{ code: "A302-2", roomCode: "A302", status: "maintenance", notes: "氧气接口保养" },
{ code: "R101-1", roomCode: "R101", status: "occupied", notes: "康复训练后休息床位" },
{ code: "R101-2", roomCode: "R101", status: "available", notes: "临时观察床位" },
{ code: "R102-1", roomCode: "R102", status: "available", notes: "短住评估床位" },
{ code: "R102-2", roomCode: "R102", status: "available", notes: "短住评估床位" },
{ code: "R201-1", roomCode: "R201", status: "occupied", notes: "术后康复第 2 周" },
{ code: "R201-2", roomCode: "R201", status: "available", notes: "康复床位候补" },
{ code: "R202-1", roomCode: "R202", status: "occupied", notes: "认知训练老人长期床位" },
{ code: "R202-2", roomCode: "R202", status: "available", notes: "靠近活动室" },
{ code: "B101-1", roomCode: "B101", status: "occupied", notes: "自理老人长期床位" },
{ code: "B101-2", roomCode: "B101", status: "available", notes: "低照护需求床位" },
{ code: "B201-1", roomCode: "B201", status: "available", notes: "亲属探访便利" },
{ code: "B201-2", roomCode: "B201", status: "available", notes: "亲情套房备用床" },
{ code: "B202-1", roomCode: "B202", status: "occupied", notes: "陪护套房,家属每周探访" },
{ code: "B202-2", roomCode: "B202", status: "available", notes: "可接收短住老人" },
{ code: "S101-1", roomCode: "S101", status: "occupied", notes: "医养观察,夜间吸氧" },
{ code: "S101-2", roomCode: "S101", status: "disabled", notes: "待更换床垫" },
{ code: "S102-1", roomCode: "S102", status: "available", notes: "短期托养床位" },
{ code: "S102-2", roomCode: "S102", status: "available", notes: "短期托养床位" },
];
const DEFAULT_ELDERS: SeedElder[] = [
{
name: "王桂兰",
gender: "female",
age: 82,
careLevel: "intensive",
status: "active",
primaryContact: "张敏",
phone: "13800000001",
medicalNotes: "高血压,需晨晚血压记录。",
},
{
name: "李建国",
gender: "male",
age: 76,
careLevel: "semi-assisted",
status: "active",
primaryContact: "李明",
phone: "13800000002",
medicalNotes: "餐后散步陪同,关注睡眠情况。",
},
{
name: "周玉珍",
gender: "female",
age: 88,
careLevel: "assisted",
status: "active",
primaryContact: "周强",
phone: "13800000003",
medicalNotes: "糖尿病饮食,餐前血糖提醒。",
},
{
name: "赵国华",
gender: "male",
age: 91,
careLevel: "intensive",
status: "active",
primaryContact: "赵琳",
phone: "13800000004",
medicalNotes: "夜间翻身,两小时巡房。",
},
{
name: "孙秀梅",
gender: "female",
age: 73,
careLevel: "semi-assisted",
status: "active",
primaryContact: "孙磊",
phone: "13800000005",
medicalNotes: "膝关节康复训练,每日下午一次。",
},
{
name: "刘长青",
gender: "male",
age: 68,
careLevel: "self-care",
status: "active",
primaryContact: "刘洋",
phone: "13800000006",
medicalNotes: "自理,需定期复查用药。",
},
{
name: "陈秀英",
gender: "female",
age: 69,
careLevel: "self-care",
status: "pending",
primaryContact: "陈佳",
phone: "13800000007",
medicalNotes: "待完成入住评估。",
},
{
name: "何德明",
gender: "male",
age: 84,
careLevel: "assisted",
status: "pending",
primaryContact: "何静",
phone: "13800000008",
medicalNotes: "家属已提交体检资料,等待床位确认。",
},
{
name: "吴佩兰",
gender: "female",
age: 79,
careLevel: "semi-assisted",
status: "discharged",
primaryContact: "吴昊",
phone: "13800000009",
medicalNotes: "已退住,保留历史档案。",
},
{
name: "郑文远",
gender: "male",
age: 72,
careLevel: "self-care",
status: "discharged",
primaryContact: "郑洁",
phone: "13800000010",
medicalNotes: "短住康复结束后退住。",
},
{
name: "马淑芬",
gender: "female",
age: 86,
careLevel: "intensive",
status: "active",
primaryContact: "马晨",
phone: "13800000011",
medicalNotes: "吞咽困难,晚餐需软食并观察呛咳。",
},
{
name: "胡志强",
gender: "male",
age: 80,
careLevel: "assisted",
status: "active",
primaryContact: "胡悦",
phone: "13800000012",
medicalNotes: "术后康复,需记录每日步行距离。",
},
{
name: "高兰英",
gender: "female",
age: 77,
careLevel: "semi-assisted",
status: "active",
primaryContact: "高磊",
phone: "13800000013",
medicalNotes: "轻度认知障碍,活动后需陪同返回房间。",
},
{
name: "钱松柏",
gender: "male",
age: 89,
careLevel: "intensive",
status: "active",
primaryContact: "钱宁",
phone: "13800000014",
medicalNotes: "慢阻肺,夜间吸氧,重点关注血氧。",
},
{
name: "林玉琴",
gender: "female",
age: 71,
careLevel: "self-care",
status: "active",
primaryContact: "林涛",
phone: "13800000015",
medicalNotes: "短住托养,需协助完成初次健康档案。",
},
{
name: "曹文海",
gender: "male",
age: 83,
careLevel: "assisted",
status: "pending",
primaryContact: "曹颖",
phone: "13800000016",
medicalNotes: "已预约下周入住,等待家属确认床位。",
},
{
name: "罗海燕",
gender: "female",
age: 75,
careLevel: "semi-assisted",
status: "pending",
primaryContact: "罗杰",
phone: "13800000017",
medicalNotes: "需补充近期体检报告。",
},
{
name: "邓启明",
gender: "male",
age: 70,
careLevel: "self-care",
status: "discharged",
primaryContact: "邓可",
phone: "13800000018",
medicalNotes: "试住结束后转家庭照护。",
},
];
const DEFAULT_ADMISSIONS: SeedAdmission[] = [
{ elderName: "王桂兰", bedCode: "A101-1", status: "active", notes: "默认工作区入住记录" },
{ elderName: "李建国", bedCode: "A102-1", status: "active", notes: "默认工作区入住记录" },
{ elderName: "周玉珍", bedCode: "A201-1", status: "active", notes: "记忆照护专区入住" },
{ elderName: "赵国华", bedCode: "A202-1", status: "active", notes: "重点照护入住" },
{ elderName: "孙秀梅", bedCode: "R101-1", status: "active", notes: "康复观察入住" },
{ elderName: "刘长青", bedCode: "B101-1", status: "active", notes: "自理区入住" },
{ elderName: "马淑芬", bedCode: "A301-1", status: "active", notes: "失能照护入住" },
{ elderName: "胡志强", bedCode: "R201-1", status: "active", notes: "术后康复入住" },
{ elderName: "高兰英", bedCode: "R202-1", status: "active", notes: "认知训练入住" },
{ elderName: "钱松柏", bedCode: "S101-1", status: "active", notes: "医养观察入住" },
{ elderName: "林玉琴", bedCode: "B202-1", status: "active", notes: "短住托养入住" },
{ elderName: "吴佩兰", bedCode: "B201-1", status: "discharged", notes: "历史退住记录" },
{ elderName: "邓启明", bedCode: "A301-2", status: "discharged", notes: "试住退住记录" },
];
const DEFAULT_HEALTH_PROFILES: SeedHealthProfile[] = [
{
elderName: "王桂兰",
allergyNotes: "青霉素过敏",
medicalHistory: "高血压十余年,偶发胸闷。",
medicationNotes: "晨服降压药,晚间复核血压。",
careRestrictions: "低盐饮食,避免剧烈活动。",
emergencyNotes: "胸闷或血压持续升高时立即联系医生。",
},
{
elderName: "周玉珍",
allergyNotes: "无明确药物过敏史",
medicalHistory: "2 型糖尿病,轻度认知障碍。",
medicationNotes: "餐前血糖监测,按医嘱用药。",
careRestrictions: "控糖饮食,夜间加强巡护。",
emergencyNotes: "低血糖症状时立即补糖并记录。",
},
{
elderName: "赵国华",
allergyNotes: "海鲜过敏",
medicalHistory: "脑梗后遗症,长期卧床风险。",
medicationNotes: "抗凝药按时服用。",
careRestrictions: "两小时翻身,防跌倒,防压疮。",
emergencyNotes: "意识异常或血氧下降时立即启动应急流程。",
},
{
elderName: "刘长青",
allergyNotes: "",
medicalHistory: "冠心病随访。",
medicationNotes: "自主管理用药,护理员每日提醒。",
careRestrictions: "避免爬楼和长时间站立。",
emergencyNotes: "胸痛需立即报告。",
},
{
elderName: "马淑芬",
allergyNotes: "头孢类药物过敏",
medicalHistory: "脑梗后吞咽功能下降,近期体重下降。",
medicationNotes: "晚间营养补充剂,服药后观察吞咽。",
careRestrictions: "软食,进食时保持坐位,餐后半小时内不平卧。",
emergencyNotes: "呛咳、紫绀或呼吸急促时立即通知医生。",
},
{
elderName: "胡志强",
allergyNotes: "",
medicalHistory: "髋关节术后康复中。",
medicationNotes: "按医嘱服用止痛药和抗凝药。",
careRestrictions: "转移位需双人协助,禁止独自上下楼。",
emergencyNotes: "伤口渗血或疼痛加重时联系康复医生。",
},
{
elderName: "高兰英",
allergyNotes: "无明确药物过敏史",
medicalHistory: "轻度认知障碍,夜间偶发迷路。",
medicationNotes: "睡前药物由护理员核对。",
careRestrictions: "外出活动需佩戴定位牌。",
emergencyNotes: "离开活动区超过 10 分钟未返回时启动寻人流程。",
},
{
elderName: "钱松柏",
allergyNotes: "",
medicalHistory: "慢阻肺,长期吸入治疗。",
medicationNotes: "吸入剂每日两次,夜间低流量吸氧。",
careRestrictions: "避免受凉和烟味刺激。",
emergencyNotes: "血氧低于 90 或呼吸困难时立即启动应急流程。",
},
{
elderName: "林玉琴",
allergyNotes: "无",
medicalHistory: "短住托养,既往骨质疏松。",
medicationNotes: "钙剂和维生素 D 每日提醒。",
careRestrictions: "浴室需防滑协助。",
emergencyNotes: "跌倒后即刻评估并通知家属。",
},
];
const DEFAULT_VITAL_RECORDS: SeedVitalRecord[] = [
{
elderName: "王桂兰",
recordedHoursAgo: 2,
source: "manual",
systolicBp: 158,
diastolicBp: 96,
heartRate: 88,
temperatureTenths: 367,
spo2: 96,
bloodGlucoseTenths: 62,
weightTenths: 612,
notes: "血压偏高,已安排复测。",
},
{
elderName: "李建国",
recordedHoursAgo: 5,
source: "device",
systolicBp: 128,
diastolicBp: 78,
heartRate: 76,
temperatureTenths: 365,
spo2: 98,
notes: "体征平稳。",
},
{
elderName: "周玉珍",
recordedHoursAgo: 7,
source: "manual",
systolicBp: 134,
diastolicBp: 82,
heartRate: 80,
temperatureTenths: 366,
spo2: 97,
bloodGlucoseTenths: 118,
notes: "餐后血糖偏高,已记录饮食。",
},
{
elderName: "赵国华",
recordedHoursAgo: 12,
source: "manual",
systolicBp: 146,
diastolicBp: 88,
heartRate: 92,
temperatureTenths: 381,
spo2: 91,
notes: "体温和血氧异常,需复核。",
},
{
elderName: "马淑芬",
recordedHoursAgo: 3,
source: "manual",
systolicBp: 142,
diastolicBp: 86,
heartRate: 96,
temperatureTenths: 369,
spo2: 94,
bloodGlucoseTenths: 73,
weightTenths: 486,
notes: "晚餐前复测,吞咽情况稳定。",
},
{
elderName: "胡志强",
recordedHoursAgo: 9,
source: "device",
systolicBp: 124,
diastolicBp: 76,
heartRate: 82,
temperatureTenths: 364,
spo2: 98,
weightTenths: 705,
notes: "康复训练后体征平稳。",
},
{
elderName: "高兰英",
recordedHoursAgo: 15,
source: "manual",
systolicBp: 136,
diastolicBp: 84,
heartRate: 78,
temperatureTenths: 366,
spo2: 97,
bloodGlucoseTenths: 65,
notes: "夜间巡护记录,情绪平稳。",
},
{
elderName: "钱松柏",
recordedHoursAgo: 1,
source: "device",
systolicBp: 150,
diastolicBp: 88,
heartRate: 104,
temperatureTenths: 372,
spo2: 89,
notes: "夜间血氧低,已安排吸氧复核。",
},
{
elderName: "林玉琴",
recordedHoursAgo: 22,
source: "import",
systolicBp: 118,
diastolicBp: 72,
heartRate: 70,
temperatureTenths: 363,
spo2: 99,
bloodGlucoseTenths: 58,
weightTenths: 552,
notes: "入院体检导入记录。",
},
{
elderName: "王桂兰",
recordedHoursAgo: 26,
source: "device",
systolicBp: 145,
diastolicBp: 90,
heartRate: 84,
temperatureTenths: 366,
spo2: 97,
notes: "前一日夜间复测,血压较高。",
},
{
elderName: "周玉珍",
recordedHoursAgo: 30,
source: "manual",
systolicBp: 130,
diastolicBp: 80,
heartRate: 74,
temperatureTenths: 365,
spo2: 98,
bloodGlucoseTenths: 92,
notes: "晨间血糖记录。",
},
];
const DEFAULT_CHRONIC_CONDITIONS: SeedChronicCondition[] = [
{
elderName: "王桂兰",
name: "高血压",
status: "active",
treatmentNotes: "规律服药,晨晚血压监测。",
followUpNotes: "每周汇总血压趋势。",
},
{
elderName: "周玉珍",
name: "糖尿病",
status: "active",
treatmentNotes: "控糖饮食,餐前餐后血糖记录。",
followUpNotes: "异常血糖进入复核队列。",
},
{
elderName: "刘长青",
name: "冠心病",
status: "controlled",
treatmentNotes: "按医嘱服药,避免劳累。",
followUpNotes: "月度复诊提醒。",
},
{
elderName: "马淑芬",
name: "吞咽功能障碍",
status: "active",
treatmentNotes: "软食和吞咽训练,餐中观察呛咳。",
followUpNotes: "每三天评估进食量和体重。",
},
{
elderName: "胡志强",
name: "髋关节术后康复",
status: "active",
treatmentNotes: "每日步态训练,逐步增加步行距离。",
followUpNotes: "康复师每周复评。",
},
{
elderName: "高兰英",
name: "轻度认知障碍",
status: "controlled",
treatmentNotes: "认知训练和日常定向提醒。",
followUpNotes: "观察夜间离床次数。",
},
{
elderName: "钱松柏",
name: "慢阻肺",
status: "active",
treatmentNotes: "吸入治疗和低流量吸氧。",
followUpNotes: "每日汇总夜间血氧趋势。",
},
{
elderName: "林玉琴",
name: "骨质疏松",
status: "controlled",
treatmentNotes: "补钙、维生素 D 和防跌倒宣教。",
followUpNotes: "短住结束前出具照护建议。",
},
{
elderName: "吴佩兰",
name: "膝关节退行性病变",
status: "resolved",
treatmentNotes: "历史康复记录归档。",
followUpNotes: "退住后无需跟进。",
},
];
const DEFAULT_HEALTH_REVIEWS: SeedHealthReview[] = [
{
elderName: "王桂兰",
vitalIndex: 0,
severity: "warning",
status: "pending",
title: "血压异常",
description: "收缩压和舒张压偏高,需要复测并确认用药。",
resolutionNotes: "",
},
{
elderName: "赵国华",
vitalIndex: 3,
severity: "critical",
status: "pending",
title: "血氧和体温异常",
description: "血氧低于阈值且体温偏高,需要立即复核。",
resolutionNotes: "",
},
{
elderName: "周玉珍",
vitalIndex: 2,
severity: "info",
status: "reviewed",
title: "餐后血糖偏高",
description: "餐后血糖高于日常水平。",
resolutionNotes: "已调整晚餐主食并安排次日复测。",
},
{
elderName: "钱松柏",
vitalIndex: 7,
severity: "critical",
status: "pending",
title: "夜间血氧低",
description: "设备记录血氧低于 90需要确认吸氧和呼吸状态。",
resolutionNotes: "",
},
{
elderName: "马淑芬",
vitalIndex: 4,
severity: "warning",
status: "reviewed",
title: "体重下降观察",
description: "近期体重偏低,需要结合进食量继续观察。",
resolutionNotes: "已通知营养师调整晚间加餐。",
},
{
elderName: "王桂兰",
vitalIndex: 9,
severity: "info",
status: "resolved",
title: "血压复核完成",
description: "前一日夜间血压偏高,今日已复测。",
resolutionNotes: "晨间复测仍偏高,转入本日待处理复核。",
},
];
const DEFAULT_CARE_TASKS: SeedCareTask[] = [
{
elderName: "王桂兰",
title: "晨间协助洗漱与翻身",
careType: "daily_care",
priority: "normal",
status: "pending",
scheduledHoursOffset: 1,
assigneeLabel: "一号护理组",
executionNotes: "",
},
{
elderName: "孙秀梅",
title: "膝关节康复训练陪同",
careType: "rehab",
priority: "high",
status: "in_progress",
scheduledHoursOffset: -1,
assigneeLabel: "康复护理组",
executionNotes: "已完成热身,等待康复师复核动作。",
},
{
elderName: "周玉珍",
title: "餐前血糖记录与助餐",
careType: "meal",
priority: "normal",
status: "completed",
scheduledHoursOffset: -4,
completedHoursAgo: 3,
assigneeLabel: "二号护理组",
executionNotes: "餐前血糖已记录,午餐摄入约八成。",
},
{
elderName: "赵国华",
title: "重点照护夜间巡检补记",
careType: "inspection",
priority: "urgent",
status: "pending",
scheduledHoursOffset: -2,
assigneeLabel: "夜班护理组",
executionNotes: "",
},
{
elderName: "刘长青",
title: "用药提醒与胸痛询问",
careType: "medication",
priority: "high",
status: "pending",
scheduledHoursOffset: 3,
assigneeLabel: "三号护理组",
executionNotes: "",
},
{
elderName: "马淑芬",
title: "晚餐软食进食观察",
careType: "meal",
priority: "urgent",
status: "pending",
scheduledHoursOffset: 2,
assigneeLabel: "重点护理组",
executionNotes: "",
},
{
elderName: "胡志强",
title: "步行训练记录",
careType: "rehab",
priority: "normal",
status: "completed",
scheduledHoursOffset: -6,
completedHoursAgo: 5,
assigneeLabel: "康复护理组",
executionNotes: "扶行 80 米,未诉明显疼痛。",
},
{
elderName: "高兰英",
title: "活动室返回陪同",
careType: "daily_care",
priority: "normal",
status: "in_progress",
scheduledHoursOffset: 0,
assigneeLabel: "二号护理组",
executionNotes: "已到活动室,等待小组活动结束。",
},
{
elderName: "钱松柏",
title: "夜间吸氧设备检查",
careType: "inspection",
priority: "urgent",
status: "pending",
scheduledHoursOffset: -1,
assigneeLabel: "夜班护理组",
executionNotes: "",
},
{
elderName: "林玉琴",
title: "短住入院宣教",
careType: "other",
priority: "low",
status: "completed",
scheduledHoursOffset: -24,
completedHoursAgo: 23,
assigneeLabel: "接待护理组",
executionNotes: "已完成房间设施、防跌倒和呼叫器使用说明。",
},
{
elderName: "赵国华",
title: "床单位清洁消毒",
careType: "cleaning",
priority: "normal",
status: "cancelled",
scheduledHoursOffset: -8,
assigneeLabel: "保洁协同组",
executionNotes: "因临时复查延期,已改派夜班完成。",
},
];
const DEFAULT_SYSTEM_INCIDENTS: SeedSystemIncident[] = [
{
severity: "warning",
status: "open",
title: "床头呼叫器待检修",
description: "A102-2 床位呼叫器处于检修状态,完成后可恢复使用。",
source: "默认工作区初始化",
createdHoursAgo: 2,
},
{
severity: "info",
status: "acknowledged",
title: "本周护理评估待完成",
description: "陈秀英、何德明等待入住评估,可在老人档案和床位工作区继续处理。",
source: "默认工作区初始化",
createdHoursAgo: 6,
acknowledgedHoursAgo: 5,
},
{
severity: "critical",
status: "resolved",
title: "夜间巡房异常已处理",
description: "重点照护房夜间巡房提醒已恢复,保留事件用于状态页验证。",
source: "默认工作区初始化",
createdHoursAgo: 14,
acknowledgedHoursAgo: 13,
resolvedHoursAgo: 11,
},
{
severity: "critical",
status: "open",
title: "S101 医养观察房血氧告警",
description: "钱松柏夜间血氧持续低于阈值,需要护理组和医生复核。",
source: "生命体征设备",
createdHoursAgo: 1,
},
{
severity: "warning",
status: "acknowledged",
title: "A302 氧气接口保养延期",
description: "A302-2 氧气接口保养未按计划完成,床位暂不安排入住。",
source: "设备巡检",
createdHoursAgo: 20,
acknowledgedHoursAgo: 18,
},
{
severity: "info",
status: "closed",
title: "短住托养资料归档完成",
description: "林玉琴短住托养资料已录入并完成家属确认。",
source: "接待护理组",
createdHoursAgo: 28,
acknowledgedHoursAgo: 27,
resolvedHoursAgo: 24,
},
];
const DEFAULT_DEVICE_ASSETS: SeedDeviceAsset[] = [
{
name: "A102 床头呼叫器",
code: "DEV-CALL-A102-2",
category: "呼叫系统",
location: "护理楼 A102-2",
status: "maintenance",
lastInspectedHoursAgo: 6,
notes: "按键回弹异常,已临时更换备用呼叫器。",
},
{
name: "S101 血氧监测仪",
code: "DEV-SPO2-S101",
category: "生命体征设备",
location: "医养楼 S101",
status: "active",
lastInspectedHoursAgo: 3,
notes: "夜间连续监测,数据接入健康复核。",
},
{
name: "A302 氧气接口",
code: "DEV-OXY-A302-2",
category: "供氧设施",
location: "护理楼 A302-2",
status: "maintenance",
lastInspectedHoursAgo: 20,
notes: "保养延期,床位暂不安排吸氧需求老人。",
},
{
name: "活动室康复步行带",
code: "DEV-REHAB-R101",
category: "康复设备",
location: "康复楼一层活动室",
status: "active",
lastInspectedHoursAgo: 30,
notes: "适用于步态训练和扶行评估。",
},
];
const DEFAULT_MAINTENANCE_TICKETS: SeedMaintenanceTicket[] = [
{
deviceCode: "DEV-CALL-A102-2",
title: "床头呼叫器按键失灵",
description: "A102-2 床位呼叫器偶发无响应,需要更换按键模块。",
priority: "high",
status: "assigned",
assigneeLabel: "设备运维组",
resolutionNotes: "已备件,预计今日 17:00 前完成。",
},
{
deviceCode: "DEV-OXY-A302-2",
title: "氧气接口保养延期",
description: "A302-2 氧气接口未完成季度保养。",
priority: "urgent",
status: "open",
assigneeLabel: "后勤维修",
resolutionNotes: "",
},
{
deviceCode: "DEV-REHAB-R101",
title: "康复步行带日常校准",
description: "例行速度校准和安全带检查。",
priority: "normal",
status: "resolved",
assigneeLabel: "康复设备供应商",
resolutionNotes: "已完成速度校准,安全带状态正常。",
},
];
const DEFAULT_NOTICES: SeedNotice[] = [
{
title: "本周家属探访安排",
content: "周六上午开放护理楼一层和康复楼探访,请各护理组提前确认老人状态和陪同人员。",
audience: "护理组、前台接待",
status: "published",
publishedHoursAgo: 4,
},
{
title: "夜间重点巡房提醒",
content: "钱松柏、赵国华、马淑芬列入今晚重点巡房名单,请夜班护理组按时记录。",
audience: "夜班护理组",
status: "published",
publishedHoursAgo: 10,
},
{
title: "设备巡检培训材料",
content: "呼叫器、供氧接口和血氧监测仪巡检 SOP 已更新,待主管确认后发布。",
audience: "设备运维组",
status: "draft",
},
];
const DEFAULT_ALERT_RULES: SeedAlertRule[] = [
{
name: "血氧低值连续告警",
ruleType: "health",
severity: "critical",
status: "enabled",
conditionSummary: "设备上报血氧连续低于 92% 超过 10 分钟。",
suggestion: "通知医生复核,护理组检查吸氧设备和体位。",
},
{
name: "高优先级护理任务逾期",
ruleType: "care",
severity: "warning",
status: "enabled",
conditionSummary: "高或紧急护理任务超过计划时间仍未完成。",
suggestion: "联系责任护理组并记录延误原因。",
},
{
name: "设备维修工单未派单",
ruleType: "device",
severity: "warning",
status: "enabled",
conditionSummary: "高优先级维修工单创建后 2 小时仍处于待处理。",
suggestion: "通知设备运维组完成派单。",
},
];
const DEFAULT_ALERT_TRIGGERS: SeedAlertTrigger[] = [
{
ruleName: "血氧低值连续告警",
elderName: "钱松柏",
title: "S101 血氧低值需复核",
description: "夜间血氧连续低于阈值,已同步到安全应急事件。",
status: "open",
source: "生命体征设备",
handlingNotes: "",
createdHoursAgo: 1,
},
{
ruleName: "高优先级护理任务逾期",
elderName: "赵国华",
title: "重点照护夜间巡检逾期",
description: "夜间巡检补记任务已超过计划时间。",
status: "acknowledged",
source: "护理任务",
handlingNotes: "夜班主管已确认,等待补录。",
createdHoursAgo: 2,
},
{
ruleName: "设备维修工单未派单",
title: "氧气接口保养待派单",
description: "A302 氧气接口保养延期,维修工单仍待处理。",
status: "open",
source: "设备运维",
handlingNotes: "",
createdHoursAgo: 5,
},
];
const DEFAULT_FAMILY_CONTACTS: SeedFamilyContact[] = [
{ elderName: "王桂兰", name: "张敏", relationship: "女儿", phone: "13800000001", status: "active", notes: "主要联系人,每周六探访。" },
{ elderName: "钱松柏", name: "钱宁", relationship: "儿子", phone: "13800000011", status: "active", notes: "关注夜间吸氧情况。" },
{ elderName: "林玉琴", name: "林晓", relationship: "女儿", phone: "13800000014", status: "active", notes: "短住托养资料已确认。" },
{ elderName: "赵国华", name: "赵蕾", relationship: "孙女", phone: "13800000016", status: "active", notes: "希望接收护理反馈。" },
];
const DEFAULT_FAMILY_VISITS: SeedFamilyVisit[] = [
{ elderName: "王桂兰", contactName: "张敏", scheduledHoursOffset: 30, status: "approved", notes: "安排护理楼一层会客区。" },
{ elderName: "钱松柏", contactName: "钱宁", scheduledHoursOffset: 8, status: "requested", notes: "需医生确认夜间血氧情况后再回复。" },
{ elderName: "林玉琴", contactName: "林晓", scheduledHoursOffset: -20, status: "completed", notes: "已完成探访和短住事项确认。" },
];
const DEFAULT_FAMILY_FEEDBACK: SeedFamilyFeedback[] = [
{
elderName: "赵国华",
contactName: "赵蕾",
feedbackType: "care",
content: "希望夜间巡房后能同步重点观察结果。",
status: "in_progress",
responseNotes: "护理主管已跟进,今晚开始补充巡房备注。",
},
{
elderName: "林玉琴",
contactName: "林晓",
feedbackType: "environment",
content: "短住房间清洁和呼叫器说明比较清楚。",
status: "resolved",
responseNotes: "已记录为接待服务反馈。",
},
];
function hasRows(rows: unknown[]): boolean {
return rows.length > 0;
}
export async function seedDefaultWorkspaceData(organizationId: string): Promise<void> {
const database = getDatabase();
const [existingRooms, existingBeds, existingElders, existingAdmissions] = await Promise.all([
database.select({ id: rooms.id }).from(rooms).where(eq(rooms.organizationId, organizationId)).limit(1),
database.select({ id: beds.id }).from(beds).where(eq(beds.organizationId, organizationId)).limit(1),
database.select({ id: elders.id }).from(elders).where(eq(elders.organizationId, organizationId)).limit(1),
database.select({ id: admissions.id }).from(admissions).where(eq(admissions.organizationId, organizationId)).limit(1),
]);
if ([existingRooms, existingBeds, existingElders, existingAdmissions].some(hasRows)) {
return;
}
await database.transaction(async (transaction) => {
const uniqueCampusNames = Array.from(new Set(DEFAULT_ROOMS.map((room) => room.campusName)));
const campusRows = await transaction
.insert(campuses)
.values(
uniqueCampusNames.map((name) => ({
organizationId,
name,
address: `${name}养老服务院区`,
})),
)
.returning();
if (campusRows.length !== uniqueCampusNames.length) {
throw new Error("默认院区初始化失败");
}
const campusIdByName = new Map(campusRows.map((campus) => [campus.name, campus.id]));
const uniqueBuildings = Array.from(
new Map(DEFAULT_ROOMS.map((room) => [`${room.campusName}/${room.buildingName}`, room])).values(),
);
const buildingRows = await transaction
.insert(buildings)
.values(
uniqueBuildings.map((building) => {
const campusId = campusIdByName.get(building.campusName);
if (!campusId) {
throw new Error("默认楼栋初始化失败");
}
return {
organizationId,
campusId,
name: building.buildingName,
};
}),
)
.returning();
if (buildingRows.length !== uniqueBuildings.length) {
throw new Error("默认楼栋初始化失败");
}
const buildingIdByKey = new Map(
buildingRows.map((building, index) => {
const source = uniqueBuildings[index];
if (!source) {
throw new Error("默认楼栋初始化失败");
}
return [`${source.campusName}/${source.buildingName}`, building.id];
}),
);
const uniqueFloors = Array.from(
new Map(
DEFAULT_ROOMS.map((room) => [
`${room.campusName}/${room.buildingName}/${room.floorLevel}`,
room,
]),
).values(),
);
const floorRows = await transaction
.insert(floors)
.values(
uniqueFloors.map((floor) => {
const buildingId = buildingIdByKey.get(`${floor.campusName}/${floor.buildingName}`);
if (!buildingId) {
throw new Error("默认楼层初始化失败");
}
return {
organizationId,
buildingId,
name: floor.floorName,
level: floor.floorLevel,
};
}),
)
.returning();
if (floorRows.length !== uniqueFloors.length) {
throw new Error("默认楼层初始化失败");
}
const floorIdByKey = new Map(
floorRows.map((floor, index) => {
const source = uniqueFloors[index];
if (!source) {
throw new Error("默认楼层初始化失败");
}
return [`${source.campusName}/${source.buildingName}/${source.floorLevel}`, floor.id];
}),
);
const roomRows = await transaction
.insert(rooms)
.values(
DEFAULT_ROOMS.map((room) => {
const floorId = floorIdByKey.get(`${room.campusName}/${room.buildingName}/${room.floorLevel}`);
if (!floorId) {
throw new Error("默认房间初始化失败");
}
return {
organizationId,
floorId,
name: room.name,
code: room.code,
capacity: room.capacity,
};
}),
)
.returning();
if (roomRows.length !== DEFAULT_ROOMS.length) {
throw new Error("默认房间初始化失败");
}
const roomIdByCode = new Map(roomRows.map((room) => [room.code, room.id]));
const bedRows = await transaction
.insert(beds)
.values(
DEFAULT_BEDS.map((bed) => {
const roomId = roomIdByCode.get(bed.roomCode);
if (!roomId) {
throw new Error("默认床位初始化失败");
}
return {
organizationId,
roomId,
code: bed.code,
status: bed.status,
notes: bed.notes,
};
}),
)
.returning();
if (bedRows.length !== DEFAULT_BEDS.length) {
throw new Error("默认床位初始化失败");
}
const elderRows = await transaction
.insert(elders)
.values(DEFAULT_ELDERS.map((elder) => ({ ...elder, organizationId })))
.returning();
if (elderRows.length !== DEFAULT_ELDERS.length) {
throw new Error("默认老人档案初始化失败");
}
const elderIdByName = new Map(elderRows.map((elder) => [elder.name, elder.id]));
const bedIdByCode = new Map(bedRows.map((bed) => [bed.code, bed.id]));
await transaction.insert(admissions).values(
DEFAULT_ADMISSIONS.map((admission) => {
const elderId = elderIdByName.get(admission.elderName);
const bedId = bedIdByCode.get(admission.bedCode);
if (!elderId || !bedId) {
throw new Error("默认入住初始化失败");
}
return {
organizationId,
elderId,
bedId,
status: admission.status,
dischargedAt: admission.status === "discharged" ? new Date() : undefined,
notes: admission.notes,
};
}),
);
const now = new Date();
await transaction.insert(careTasks).values(
DEFAULT_CARE_TASKS.map((task) => {
const elderId = elderIdByName.get(task.elderName);
if (!elderId) {
throw new Error("默认护理任务初始化失败");
}
const completedAt = task.completedHoursAgo === undefined ? undefined : new Date(now.getTime() - task.completedHoursAgo * 60 * 60 * 1000);
return {
organizationId,
elderId,
title: task.title,
careType: task.careType,
priority: task.priority,
status: task.status,
scheduledAt: new Date(now.getTime() + task.scheduledHoursOffset * 60 * 60 * 1000),
assigneeLabel: task.assigneeLabel,
executionNotes: task.executionNotes,
completedAt,
};
}),
);
await transaction.insert(healthProfiles).values(
DEFAULT_HEALTH_PROFILES.map((profile) => {
const elderId = elderIdByName.get(profile.elderName);
if (!elderId) {
throw new Error("默认健康档案初始化失败");
}
return {
organizationId,
elderId,
allergyNotes: profile.allergyNotes,
medicalHistory: profile.medicalHistory,
medicationNotes: profile.medicationNotes,
careRestrictions: profile.careRestrictions,
emergencyNotes: profile.emergencyNotes,
};
}),
);
const vitalRows = await transaction
.insert(vitalRecords)
.values(
DEFAULT_VITAL_RECORDS.map((vital) => {
const elderId = elderIdByName.get(vital.elderName);
if (!elderId) {
throw new Error("默认生命体征初始化失败");
}
return {
organizationId,
elderId,
recordedAt: new Date(now.getTime() - vital.recordedHoursAgo * 60 * 60 * 1000),
source: vital.source,
systolicBp: vital.systolicBp,
diastolicBp: vital.diastolicBp,
heartRate: vital.heartRate,
temperatureTenths: vital.temperatureTenths,
spo2: vital.spo2,
bloodGlucoseTenths: vital.bloodGlucoseTenths,
weightTenths: vital.weightTenths,
notes: vital.notes,
};
}),
)
.returning();
if (vitalRows.length !== DEFAULT_VITAL_RECORDS.length) {
throw new Error("默认生命体征初始化失败");
}
await transaction.insert(chronicConditions).values(
DEFAULT_CHRONIC_CONDITIONS.map((condition) => {
const elderId = elderIdByName.get(condition.elderName);
if (!elderId) {
throw new Error("默认慢病记录初始化失败");
}
return {
organizationId,
elderId,
name: condition.name,
status: condition.status,
treatmentNotes: condition.treatmentNotes,
followUpNotes: condition.followUpNotes,
};
}),
);
await transaction.insert(healthAnomalyReviews).values(
DEFAULT_HEALTH_REVIEWS.map((review) => {
const elderId = elderIdByName.get(review.elderName);
const vital = vitalRows[review.vitalIndex];
if (!elderId || !vital) {
throw new Error("默认健康异常复核初始化失败");
}
return {
organizationId,
elderId,
vitalRecordId: vital.id,
severity: review.severity,
status: review.status,
title: review.title,
description: review.description,
resolutionNotes: review.resolutionNotes,
};
}),
);
await transaction.insert(systemIncidents).values(
DEFAULT_SYSTEM_INCIDENTS.map((incident) => ({
organizationId,
severity: incident.severity,
status: incident.status,
title: incident.title,
description: incident.description,
source: incident.source,
acknowledgedAt:
incident.acknowledgedHoursAgo === undefined ? undefined : new Date(now.getTime() - incident.acknowledgedHoursAgo * 60 * 60 * 1000),
resolvedAt:
incident.resolvedHoursAgo === undefined ? undefined : new Date(now.getTime() - incident.resolvedHoursAgo * 60 * 60 * 1000),
createdAt: new Date(now.getTime() - incident.createdHoursAgo * 60 * 60 * 1000),
updatedAt: new Date(
now.getTime() -
(incident.resolvedHoursAgo ?? incident.acknowledgedHoursAgo ?? incident.createdHoursAgo) * 60 * 60 * 1000,
),
})),
);
const deviceRows = await transaction
.insert(deviceAssets)
.values(
DEFAULT_DEVICE_ASSETS.map((device) => ({
organizationId,
name: device.name,
code: device.code,
category: device.category,
location: device.location,
status: device.status,
lastInspectedAt:
device.lastInspectedHoursAgo === undefined ? undefined : new Date(now.getTime() - device.lastInspectedHoursAgo * 60 * 60 * 1000),
notes: device.notes,
})),
)
.returning();
if (deviceRows.length !== DEFAULT_DEVICE_ASSETS.length) {
throw new Error("默认设备台账初始化失败");
}
const deviceIdByCode = new Map(deviceRows.map((device) => [device.code, device.id]));
await transaction.insert(maintenanceTickets).values(
DEFAULT_MAINTENANCE_TICKETS.map((ticket) => {
const deviceId = deviceIdByCode.get(ticket.deviceCode);
if (!deviceId) {
throw new Error("默认维修工单初始化失败");
}
return {
organizationId,
deviceId,
title: ticket.title,
description: ticket.description,
priority: ticket.priority,
status: ticket.status,
assigneeLabel: ticket.assigneeLabel,
resolutionNotes: ticket.resolutionNotes,
resolvedAt: ticket.status === "resolved" || ticket.status === "closed" ? now : undefined,
};
}),
);
await transaction.insert(notices).values(
DEFAULT_NOTICES.map((notice) => ({
organizationId,
title: notice.title,
content: notice.content,
audience: notice.audience,
status: notice.status,
publishedAt: notice.publishedHoursAgo === undefined ? undefined : new Date(now.getTime() - notice.publishedHoursAgo * 60 * 60 * 1000),
})),
);
const alertRuleRows = await transaction
.insert(alertRules)
.values(DEFAULT_ALERT_RULES.map((rule) => ({ ...rule, organizationId })))
.returning();
if (alertRuleRows.length !== DEFAULT_ALERT_RULES.length) {
throw new Error("默认预警规则初始化失败");
}
const alertRuleIdByName = new Map(alertRuleRows.map((rule) => [rule.name, rule.id]));
await transaction.insert(alertTriggers).values(
DEFAULT_ALERT_TRIGGERS.map((trigger) => {
const ruleId = alertRuleIdByName.get(trigger.ruleName);
const elderId = trigger.elderName ? elderIdByName.get(trigger.elderName) : undefined;
if (!ruleId || (trigger.elderName && !elderId)) {
throw new Error("默认预警触发记录初始化失败");
}
return {
organizationId,
ruleId,
elderId,
title: trigger.title,
description: trigger.description,
status: trigger.status,
source: trigger.source,
handlingNotes: trigger.handlingNotes,
handledAt: trigger.status === "open" ? undefined : now,
createdAt: new Date(now.getTime() - trigger.createdHoursAgo * 60 * 60 * 1000),
updatedAt: now,
};
}),
);
const familyContactRows = await transaction
.insert(familyContacts)
.values(
DEFAULT_FAMILY_CONTACTS.map((contact) => {
const elderId = elderIdByName.get(contact.elderName);
if (!elderId) {
throw new Error("默认家属联系人初始化失败");
}
return {
organizationId,
elderId,
name: contact.name,
relationship: contact.relationship,
phone: contact.phone,
status: contact.status,
notes: contact.notes,
};
}),
)
.returning();
if (familyContactRows.length !== DEFAULT_FAMILY_CONTACTS.length) {
throw new Error("默认家属联系人初始化失败");
}
const familyContactIdByKey = new Map(
familyContactRows.map((contact) => [`${contact.elderId}/${contact.name}`, contact.id]),
);
await transaction.insert(familyVisitAppointments).values(
DEFAULT_FAMILY_VISITS.map((visit) => {
const elderId = elderIdByName.get(visit.elderName);
const contactId = elderId ? familyContactIdByKey.get(`${elderId}/${visit.contactName}`) : undefined;
if (!elderId || !contactId) {
throw new Error("默认探访预约初始化失败");
}
return {
organizationId,
elderId,
contactId,
scheduledAt: new Date(now.getTime() + visit.scheduledHoursOffset * 60 * 60 * 1000),
status: visit.status,
notes: visit.notes,
handledAt: visit.status === "requested" ? undefined : now,
};
}),
);
await transaction.insert(familyFeedback).values(
DEFAULT_FAMILY_FEEDBACK.map((feedback) => {
const elderId = elderIdByName.get(feedback.elderName);
const contactId = elderId ? familyContactIdByKey.get(`${elderId}/${feedback.contactName}`) : undefined;
if (!elderId || !contactId) {
throw new Error("默认家属反馈初始化失败");
}
return {
organizationId,
elderId,
contactId,
feedbackType: feedback.feedbackType,
content: feedback.content,
status: feedback.status,
responseNotes: feedback.responseNotes,
handledAt: feedback.status === "open" ? undefined : now,
};
}),
);
});
}