import { DBModel } from "../models/index.js"; import ResponseUtil from "../utils/responseUtil.js"; class HandlerHealthProfile { constructor() { } // 白名单:只允许写入 schema 定义的顶层字段(兼容 'profile.name' 等点号路径) static PROFILE_FIELDS = ["userId", "profile", "location", "health"]; // 单页最大条数,避免 pageSize 传超大值一次拖库 static MAX_PAGE_SIZE = 200; // 解析分页参数并夹紧上限 static parsePaging(query = {}) { const page = Math.max(1, parseInt(query.page) || 1); const rawSize = parseInt(query.pageSize) || 20; const pageSize = Math.min(Math.max(1, rawSize), HandlerHealthProfile.MAX_PAGE_SIZE); return { page, pageSize }; } static pickFields(body) { const picked = {}; for (const key of Object.keys(body || {})) { const allowed = HandlerHealthProfile.PROFILE_FIELDS.some( (f) => key === f || key.startsWith(f + ".") ); if (allowed) { picked[key] = body[key]; } } return picked; } async getProfiles(ctx) { try { const { userId, name, mobile, sortBy } = ctx.request.query; const { page, pageSize } = HandlerHealthProfile.parsePaging(ctx.request.query); const result = await DBModel.HealthProfile.findProfiles({ page, pageSize, userId, name, mobile, sortBy, }); return ResponseUtil.success(ctx, result, "查询成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } // 查询"我的"健康档案列表:强制以登录用户身份查询,忽略请求中的 userId async getMyProfiles(ctx) { try { const { name, mobile, sortBy } = ctx.request.query; const { page, pageSize } = HandlerHealthProfile.parsePaging(ctx.request.query); const userId = ctx.state.user?._id; const result = await DBModel.HealthProfile.findProfiles({ page, pageSize, userId, name, mobile, sortBy, }); return ResponseUtil.success(ctx, result, "查询成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } // 查询"我的"单个健康档案:非本人档案一律按不存在处理 async getMyProfileById(ctx) { try { const { id } = ctx.params; if (!id) { return ResponseUtil.badRequest(ctx, "缺少档案ID"); } const profile = await HandlerHealthProfile.findOwnProfile(ctx, id); if (!profile) { return ResponseUtil.notFound(ctx, "健康档案不存在"); } return ResponseUtil.success(ctx, { profile }, "查询成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } // 新增"我的"健康档案:userId 以 token 为准,避免写到他人名下 async createMyProfile(ctx) { try { const body = HandlerHealthProfile.pickFields(ctx.request.body); body.userId = ctx.state.user?._id; const newProfile = await DBModel.HealthProfile.createProfile(body); return ResponseUtil.success(ctx, { profile: newProfile }, "创建成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } // 更新"我的"健康档案:先校验归属,再更新 // 注意:入参使用 "profile.name" 这类点号路径, // 因为 schema 在更新姓名时会额外写入 "profile.pinyin",与整体替换 profile 对象会冲突 async updateMyProfile(ctx) { try { const { id } = ctx.params; if (!id) { return ResponseUtil.badRequest(ctx, "缺少档案ID"); } const profile = await HandlerHealthProfile.findOwnProfile(ctx, id); if (!profile) { return ResponseUtil.notFound(ctx, "健康档案不存在"); } const update = HandlerHealthProfile.pickFields(ctx.request.body); delete update.userId; // 不允许通过请求转移档案归属 const updatedProfile = await DBModel.HealthProfile.updateProfileById(id, update); return ResponseUtil.success(ctx, { profile: updatedProfile }, "更新成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } // 删除"我的"健康档案:先校验归属,再删除 async deleteMyProfile(ctx) { try { const { id } = ctx.params; if (!id) { return ResponseUtil.badRequest(ctx, "缺少档案ID"); } const profile = await HandlerHealthProfile.findOwnProfile(ctx, id); if (!profile) { return ResponseUtil.notFound(ctx, "健康档案不存在"); } await DBModel.HealthProfile.deleteProfileById(id); return ResponseUtil.success(ctx, { profile }, "删除成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } // 按 id 查找档案并校验归属,非本人档案返回 null static async findOwnProfile(ctx, id) { const profile = await DBModel.HealthProfile.findProfileById(id); const userId = ctx.state.user?._id; if (!profile || String(profile.userId) !== String(userId)) { return null; } return profile; } async getProfileById(ctx) { try { const { id } = ctx.params; if (!id) { return ResponseUtil.badRequest(ctx, "缺少档案ID"); } const profile = await DBModel.HealthProfile.findProfileById(id); if (!profile) { return ResponseUtil.notFound(ctx, "健康档案不存在"); } return ResponseUtil.success(ctx, { profile }, "查询成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } async createProfile(ctx) { try { const body = ctx.request.body; const newProfile = await DBModel.HealthProfile.createProfile(HandlerHealthProfile.pickFields(body)); return ResponseUtil.success(ctx, { profile: newProfile }, "创建成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } async updateProfile(ctx) { try { const { id } = ctx.params; const update = ctx.request.body; if (!id) { return ResponseUtil.badRequest(ctx, "缺少档案ID"); } const updatedProfile = await DBModel.HealthProfile.updateProfileById(id, HandlerHealthProfile.pickFields(update)); if (!updatedProfile) { return ResponseUtil.notFound(ctx, "健康档案不存在"); } return ResponseUtil.success(ctx, { profile: updatedProfile }, "更新成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } async deleteProfile(ctx) { try { const { id } = ctx.params; if (!id) { return ResponseUtil.badRequest(ctx, "缺少档案ID"); } const deletedProfile = await DBModel.HealthProfile.deleteProfileById(id); if (!deletedProfile) { return ResponseUtil.notFound(ctx, "健康档案不存在"); } return ResponseUtil.success(ctx, { profile: deletedProfile }, "删除成功"); } catch (err) { return ResponseUtil.internalError(ctx, err.message); } } } export { HandlerHealthProfile };