export const FAMILY_CONTACT_STATUS_VALUES = ["active", "suspended", "archived"] as const; export type FamilyContactStatus = (typeof FAMILY_CONTACT_STATUS_VALUES)[number]; export const FAMILY_VISIT_STATUS_VALUES = ["requested", "approved", "completed", "cancelled"] as const; export type FamilyVisitStatus = (typeof FAMILY_VISIT_STATUS_VALUES)[number]; export const FAMILY_FEEDBACK_TYPE_VALUES = ["service", "care", "meal", "environment", "other"] as const; export type FamilyFeedbackType = (typeof FAMILY_FEEDBACK_TYPE_VALUES)[number]; export const FAMILY_FEEDBACK_STATUS_VALUES = ["open", "in_progress", "resolved", "closed"] as const; export type FamilyFeedbackStatus = (typeof FAMILY_FEEDBACK_STATUS_VALUES)[number]; export const FAMILY_CONTACT_STATUS_LABELS: Record = { active: "有效", suspended: "暂停", archived: "归档", }; export const FAMILY_VISIT_STATUS_LABELS: Record = { requested: "待确认", approved: "已确认", completed: "已完成", cancelled: "已取消", }; export const FAMILY_FEEDBACK_TYPE_LABELS: Record = { service: "服务", care: "照护", meal: "餐饮", environment: "环境", other: "其他", }; export const FAMILY_FEEDBACK_STATUS_LABELS: Record = { open: "待处理", in_progress: "处理中", resolved: "已解决", closed: "已关闭", }; export type FamilyContact = { id: string; organizationId: string; elderId: string; elderName: string; name: string; relationship: string; phone: string; status: FamilyContactStatus; notes: string; createdAt: string; updatedAt: string; }; export type FamilyVisitAppointment = { id: string; organizationId: string; elderId: string; elderName: string; contactId?: string; contactName: string; scheduledAt: string; status: FamilyVisitStatus; notes: string; handledByAccountId?: string; handledByName?: string; handledAt?: string; createdAt: string; updatedAt: string; }; export type FamilyFeedback = { id: string; organizationId: string; elderId: string; elderName: string; contactId?: string; contactName: string; feedbackType: FamilyFeedbackType; content: string; status: FamilyFeedbackStatus; responseNotes: string; handledByAccountId?: string; handledByName?: string; handledAt?: string; createdAt: string; updatedAt: string; }; export type FamilyServiceData = { metrics: { activeContacts: number; pendingVisits: number; openFeedback: number; resolvedFeedback: number; }; elderOptions: Array<{ id: string; name: string }>; contacts: FamilyContact[]; visits: FamilyVisitAppointment[]; feedback: FamilyFeedback[]; }; export type FamilyContactInput = { elderId: string; name: string; relationship: string; phone: string; status: FamilyContactStatus; notes: string; }; export type FamilyVisitInput = { elderId: string; contactId?: string; scheduledAt: string; status: FamilyVisitStatus; notes: string; }; export type FamilyFeedbackInput = { elderId: string; contactId?: string; feedbackType: FamilyFeedbackType; content: string; status: FamilyFeedbackStatus; responseNotes: string; }; type ValidationSuccess = { success: true; data: T; }; type ValidationFailure = { success: false; reason: string; }; export type ValidationResult = ValidationSuccess | ValidationFailure; function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function readString(source: Record, key: string): string { const value = source[key]; return typeof value === "string" ? value.trim() : ""; } function readOptionalString(source: Record, key: string): string | undefined { const value = readString(source, key); return value || undefined; } function readEnum(value: unknown, values: readonly T[]): T | null { return typeof value === "string" ? values.find((item) => item === value) ?? null : null; } function validateRequiredDate(value: string, label: string): ValidationResult { return value && !Number.isNaN(new Date(value).getTime()) ? { success: true, data: value } : { success: false, reason: `${label}无效` }; } export function validateFamilyContactInput(value: unknown): ValidationResult { if (!isRecord(value)) { return { success: false, reason: "请求数据格式无效" }; } const elderId = readString(value, "elderId"); const name = readString(value, "name"); const relationship = readString(value, "relationship"); const phone = readString(value, "phone"); if (!elderId || !name || !relationship || !phone) { return { success: false, reason: "老人、家属姓名、关系和手机号不能为空" }; } const status = readEnum(value.status, FAMILY_CONTACT_STATUS_VALUES); if (!status) { return { success: false, reason: "家属联系人状态无效" }; } return { success: true, data: { elderId, name, relationship, phone, status, notes: readString(value, "notes") } }; } export function validateFamilyVisitInput(value: unknown): ValidationResult { if (!isRecord(value)) { return { success: false, reason: "请求数据格式无效" }; } const elderId = readString(value, "elderId"); if (!elderId) { return { success: false, reason: "探访预约必须选择老人" }; } const scheduledAt = validateRequiredDate(readString(value, "scheduledAt"), "预约时间"); if (!scheduledAt.success) { return scheduledAt; } const status = readEnum(value.status, FAMILY_VISIT_STATUS_VALUES); if (!status) { return { success: false, reason: "探访预约状态无效" }; } return { success: true, data: { elderId, contactId: readOptionalString(value, "contactId"), scheduledAt: scheduledAt.data, status, notes: readString(value, "notes"), }, }; } export function validateFamilyFeedbackInput(value: unknown): ValidationResult { if (!isRecord(value)) { return { success: false, reason: "请求数据格式无效" }; } const elderId = readString(value, "elderId"); const content = readString(value, "content"); if (!elderId || !content) { return { success: false, reason: "反馈必须选择老人并填写内容" }; } const feedbackType = readEnum(value.feedbackType, FAMILY_FEEDBACK_TYPE_VALUES); const status = readEnum(value.status, FAMILY_FEEDBACK_STATUS_VALUES); if (!feedbackType || !status) { return { success: false, reason: "反馈类型或状态无效" }; } return { success: true, data: { elderId, contactId: readOptionalString(value, "contactId"), feedbackType, content, status, responseNotes: readString(value, "responseNotes"), }, }; }