Files

182 lines
4.6 KiB
TypeScript

export const GENDER_VALUES = ["male", "female", "other"] as const;
export type Gender = (typeof GENDER_VALUES)[number];
export const CARE_LEVEL_VALUES = ["self-care", "semi-assisted", "assisted", "intensive"] as const;
export type CareLevel = (typeof CARE_LEVEL_VALUES)[number];
export const ELDER_STATUS_VALUES = ["active", "pending", "discharged"] as const;
export type ElderStatus = (typeof ELDER_STATUS_VALUES)[number];
export const GENDER_LABELS: Record<Gender, string> = {
male: "男",
female: "女",
other: "其他",
};
export const CARE_LEVEL_LABELS: Record<CareLevel, string> = {
"self-care": "自理",
"semi-assisted": "半失能",
assisted: "失能",
intensive: "重点照护",
};
export const ELDER_STATUS_LABELS: Record<ElderStatus, string> = {
active: "在院",
pending: "待入住",
discharged: "已退住",
};
export type Elder = {
id: string;
organizationId?: string;
name: string;
gender: Gender;
age: number;
careLevel: CareLevel;
room: string;
bed: string;
bedId?: string;
status: ElderStatus;
primaryContact: string;
phone: string;
medicalNotes: string;
createdAt: string;
updatedAt: string;
};
export type ElderInput = Omit<Elder, "id" | "createdAt" | "updatedAt">;
type ValidationSuccess<T> = {
success: true;
data: T;
};
type ValidationFailure = {
success: false;
reason: string;
};
export type ValidationResult<T> = ValidationSuccess<T> | ValidationFailure;
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function readRequiredString(
source: Record<string, unknown>,
key: keyof ElderInput,
label: string,
): ValidationResult<string> {
const value = source[key];
if (typeof value !== "string" || value.trim().length === 0) {
return { success: false, reason: `${label}不能为空` };
}
return { success: true, data: value.trim() };
}
function readOptionalString(source: Record<string, unknown>, key: string): string | undefined {
const value = source[key];
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : undefined;
}
function readEnum<T extends string>(
source: Record<string, unknown>,
key: keyof ElderInput,
values: readonly T[],
label: string,
): ValidationResult<T> {
const value = source[key];
if (typeof value !== "string") {
return { success: false, reason: `${label}无效` };
}
const matched = values.find((item) => item === value);
if (!matched) {
return { success: false, reason: `${label}无效` };
}
return { success: true, data: matched };
}
function readAge(source: Record<string, unknown>): ValidationResult<number> {
const value = source.age;
const numeric = typeof value === "number" ? value : Number(value);
if (!Number.isInteger(numeric) || numeric < 0 || numeric > 130) {
return { success: false, reason: "年龄需为0到130之间的整数" };
}
return { success: true, data: numeric };
}
export function validateElderInput(value: unknown): ValidationResult<ElderInput> {
if (!isRecord(value)) {
return { success: false, reason: "请求数据格式无效" };
}
const name = readRequiredString(value, "name", "姓名");
if (!name.success) {
return name;
}
const gender = readEnum(value, "gender", GENDER_VALUES, "性别");
if (!gender.success) {
return gender;
}
const age = readAge(value);
if (!age.success) {
return age;
}
const careLevel = readEnum(value, "careLevel", CARE_LEVEL_VALUES, "护理等级");
if (!careLevel.success) {
return careLevel;
}
const room = readOptionalString(value, "room") ?? "";
const bed = readOptionalString(value, "bed") ?? "";
const bedId = readOptionalString(value, "bedId");
const status = readEnum(value, "status", ELDER_STATUS_VALUES, "状态");
if (!status.success) {
return status;
}
const primaryContact = readRequiredString(value, "primaryContact", "联系人");
if (!primaryContact.success) {
return primaryContact;
}
const phone = readRequiredString(value, "phone", "联系电话");
if (!phone.success) {
return phone;
}
const medicalNotesValue = value.medicalNotes;
const medicalNotes = typeof medicalNotesValue === "string" ? medicalNotesValue.trim() : "";
return {
success: true,
data: {
name: name.data,
gender: gender.data,
age: age.data,
careLevel: careLevel.data,
room,
bed,
bedId,
status: status.data,
primaryContact: primaryContact.data,
phone: phone.data,
medicalNotes,
},
};
}