From 8975a7dd637d238a968b8eeb946df1fe4d2f04ca Mon Sep 17 00:00:00 2001 From: liuyun Date: Wed, 14 Oct 2026 18:56:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(c1):=20=E6=9C=8D=E5=8A=A1=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E5=88=97=E8=A1=A8/=E5=BB=BA=E6=A1=A3/=E8=AF=A6?= =?UTF-8?q?=E6=83=85/=E7=8A=B6=E6=80=81=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - elder api 封装(RESTful /elder 六接口)+ 十态常量与日期格式化 - 列表页用 ty-crud(姓名/性别/护理等级/待遇状态/出生日期 + 姓名·状态筛选) - 建档表单(身份证 18 位校验+出生日期带出、等级绑定评估结论副本联动校验) - 详情弹窗(完整信息 + 十态状态变更 + 状态日志时间线) - ty-crud 增 showCreate、ty-dialog 注入 dialog-id 以支持自定义建档与自关闭详情 Co-Authored-By: Claude Sonnet 4.6 --- components.d.ts | 14 + src/api/elder.ts | 125 +++++++++ src/components/ty-crud.vue | 5 +- src/components/ty-dialog.vue | 1 + .../ltc/elder/components/elder-detail.vue | 126 +++++++++ src/pages/ltc/elder/components/elder-form.vue | 256 ++++++++++++++++++ src/pages/ltc/elder/constants.ts | 84 ++++++ src/pages/ltc/elder/index.vue | 95 ++++++- 8 files changed, 704 insertions(+), 2 deletions(-) create mode 100644 src/api/elder.ts create mode 100644 src/pages/ltc/elder/components/elder-detail.vue create mode 100644 src/pages/ltc/elder/components/elder-form.vue create mode 100644 src/pages/ltc/elder/constants.ts diff --git a/components.d.ts b/components.d.ts index b792c67..07cd891 100644 --- a/components.d.ts +++ b/components.d.ts @@ -22,7 +22,11 @@ declare module 'vue' { ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] + ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] + ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] ElDialog: typeof import('element-plus/es')['ElDialog'] + ElDivider: typeof import('element-plus/es')['ElDivider'] ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] @@ -49,8 +53,11 @@ declare module 'vue' { ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] ElTag: typeof import('element-plus/es')['ElTag'] + ElTimeline: typeof import('element-plus/es')['ElTimeline'] + ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem'] ElTree: typeof import('element-plus/es')['ElTree'] ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] + ElUpload: typeof import('element-plus/es')['ElUpload'] Icon: typeof import('./src/components/icon/icon.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] @@ -88,7 +95,11 @@ declare global { const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] const ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] + const ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] + const ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] + const ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] const ElDialog: typeof import('element-plus/es')['ElDialog'] + const ElDivider: typeof import('element-plus/es')['ElDivider'] const ElDrawer: typeof import('element-plus/es')['ElDrawer'] const ElDropdown: typeof import('element-plus/es')['ElDropdown'] const ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] @@ -115,8 +126,11 @@ declare global { const ElTable: typeof import('element-plus/es')['ElTable'] const ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] const ElTag: typeof import('element-plus/es')['ElTag'] + const ElTimeline: typeof import('element-plus/es')['ElTimeline'] + const ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem'] const ElTree: typeof import('element-plus/es')['ElTree'] const ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] + const ElUpload: typeof import('element-plus/es')['ElUpload'] const Icon: typeof import('./src/components/icon/icon.vue')['default'] const RouterLink: typeof import('vue-router')['RouterLink'] const RouterView: typeof import('vue-router')['RouterView'] diff --git a/src/api/elder.ts b/src/api/elder.ts new file mode 100644 index 0000000..410fa24 --- /dev/null +++ b/src/api/elder.ts @@ -0,0 +1,125 @@ +import { http } from '@/api/http' +import type { PageResult } from '@/types/crud' + +/** + * 老人档案(elder)实体。字段字典锚点见 shared/data-model spec(ltc_elder)。 + * - 日期字段(birthDate/benefitStart 等)后端经 TransformInterceptor 序列化为毫秒时间戳; + * - idCardNo 列表返回掩码、详情(admin/qc)返回明文; + * - assessEvidenceFile 为评估结论副本的 MinIO key。 + */ +export interface Elder { + id: string + locCode?: string + name: string + gender: string + idCardNo: string + birthDate?: number + phone?: string | null + address?: string + guardianName?: string | null + guardianPhone?: string | null + insurNo?: string + insurType?: string + insurYears?: number | null + insurVerifyStatus?: string | null + insurVerifyDate?: number | null + assessLevel?: string | null + careLevel?: string | null + assessDate?: number | null + assessOrg?: string | null + assessEvidenceFile?: string | null + benefitStart?: number | null + benefitEnd?: number | null + treatStatus: string + statusSource?: string | null + statusChangeDate?: number | null + hospStart?: number | null + hospEnd?: number | null + note?: string | null + createdAt?: number + updatedAt?: number +} + +export interface ElderListQuery { + page: number + pageSize: number + name?: string + treatStatus?: string +} + +/** 建档入参(日期字段为 YYYY-MM-DD 字符串,与 staff 建档入参一致)。 */ +export interface ElderCreateData { + locCode: string + name: string + gender: string + idCardNo: string + phone?: string + address: string + guardianName?: string + guardianPhone?: string + insurNo: string + insurType: string + insurYears?: number + insurVerifyStatus?: string + insurVerifyDate?: string + assessLevel?: string + careLevel?: string + assessDate?: string + assessOrg?: string + assessEvidenceFile?: string + benefitStart?: string + benefitEnd?: string + hospStart?: string + hospEnd?: string + note?: string +} + +export interface ElderStatusLog { + id: string + elderId: string + fromStatus: string + toStatus: string + changeReason: string + source: string + operatorId: string + evidenceFile: string | null + changedAt: number +} + +/** 老人分页列表(身份证服务端掩码)。 */ +export function listElders(query: ElderListQuery, signal?: AbortSignal): Promise> { + const params: Record = { page: query.page, pageSize: query.pageSize } + if (query.name) params.name = query.name + if (query.treatStatus) params.treatStatus = query.treatStatus + return http.get>('/elder', { params, signal }) +} + +/** 建档。 */ +export function createElder(data: ElderCreateData): Promise { + return http.post('/elder', data) +} + +/** 详情(admin/qc 身份证明文并留痕,其余掩码)。 */ +export function getElder(id: string): Promise { + return http.get(`/elder/${id}`) +} + +/** 变更待遇状态(changeReason 必填)。 */ +export function changeElderStatus( + id: string, + data: { toStatus: string; changeReason: string }, +): Promise<{ id: string; fromStatus: string; toStatus: string }> { + return http.post(`/elder/${id}/status`, data) +} + +/** 状态变更历史(按时间倒序)。 */ +export function getStatusLog(id: string): Promise { + return http.get(`/elder/${id}/status/log`) +} + +/** 上传评估结论副本到 MinIO,返回 file key。 */ +export function uploadEvidence(file: File): Promise<{ key: string }> { + const fd = new FormData() + fd.append('file', file) + return http.post<{ key: string }>('/elder/assess-evidence', fd) +} diff --git a/src/components/ty-crud.vue b/src/components/ty-crud.vue index b5df406..b5e8bf7 100644 --- a/src/components/ty-crud.vue +++ b/src/components/ty-crud.vue @@ -12,7 +12,7 @@
- + 新增{{ entityName }} @@ -122,6 +122,8 @@ const props = withDefaults( selection?: boolean /** 新增按钮所需权限码(无该权限且非超管时隐藏新增按钮)。 */ createPermission?: string + /** 是否显示内置「新增」按钮(false 时可改用 #toolbar 插槽自定义建档入口)。 */ + showCreate?: boolean actionsWidth?: number | string }>(), { @@ -132,6 +134,7 @@ const props = withDefaults( actions: () => ['edit', 'delete'], collapseCount: 2, selection: false, + showCreate: true, actionsWidth: 140, }, ) diff --git a/src/components/ty-dialog.vue b/src/components/ty-dialog.vue index 1cb432f..ab00c9b 100644 --- a/src/components/ty-dialog.vue +++ b/src/components/ty-dialog.vue @@ -12,6 +12,7 @@