Browse Source

Merge branch 'master' of http://47.107.245.0:3000/xiongxing/kyj-yanglao-web-new

xiongxing 3 tháng trước cách đây
mục cha
commit
03a381c88b
30 tập tin đã thay đổi với 17258 bổ sung0 xóa
  1. 38 0
      src/api/elderly/apply/check-in.ts
  2. 479 0
      src/api/social-work/index.ts
  3. 1522 0
      src/views/elderly/apply/nine-precautions/MMSE/AddForm.vue
  4. 336 0
      src/views/elderly/apply/nine-precautions/MMSE/index.vue
  5. 806 0
      src/views/elderly/apply/nine-precautions/asphyxiation-by-choking/AddForm.vue
  6. 296 0
      src/views/elderly/apply/nine-precautions/asphyxiation-by-choking/index.vue
  7. 1200 0
      src/views/elderly/apply/nine-precautions/attack/AddForm.vue
  8. 339 0
      src/views/elderly/apply/nine-precautions/attack/index.vue
  9. 1166 0
      src/views/elderly/apply/nine-precautions/commit-suicide/AddForm.vue
  10. 333 0
      src/views/elderly/apply/nine-precautions/commit-suicide/index.vue
  11. 1237 0
      src/views/elderly/apply/nine-precautions/communication/AddForm.vue
  12. 335 0
      src/views/elderly/apply/nine-precautions/communication/index.vue
  13. 770 0
      src/views/elderly/apply/nine-precautions/daily-life/AddForm.vue
  14. 297 0
      src/views/elderly/apply/nine-precautions/daily-life/index.vue
  15. 587 0
      src/views/elderly/apply/nine-precautions/empyrosis/AddForm.vue
  16. 297 0
      src/views/elderly/apply/nine-precautions/empyrosis/index.vue
  17. 905 0
      src/views/elderly/apply/nine-precautions/equilibrium/AddForm.vue
  18. 297 0
      src/views/elderly/apply/nine-precautions/equilibrium/index.vue
  19. 630 0
      src/views/elderly/apply/nine-precautions/fall-down/AddForm.vue
  20. 297 0
      src/views/elderly/apply/nine-precautions/fall-down/index.vue
  21. 579 0
      src/views/elderly/apply/nine-precautions/fall-prevention-measures/AddForm.vue
  22. 297 0
      src/views/elderly/apply/nine-precautions/fall-prevention-measures/index.vue
  23. 1042 0
      src/views/elderly/apply/nine-precautions/nutritional-risk/AddForm.vue
  24. 228 0
      src/views/elderly/apply/nine-precautions/nutritional-risk/index.vue
  25. 912 0
      src/views/elderly/apply/nine-precautions/pressure-sores/AddForm.vue
  26. 297 0
      src/views/elderly/apply/nine-precautions/pressure-sores/index.vue
  27. 455 0
      src/views/elderly/apply/nine-precautions/risk-disclosure-statement/Form.vue
  28. 177 0
      src/views/elderly/apply/nine-precautions/risk-disclosure-statement/index.vue
  29. 807 0
      src/views/elderly/apply/nine-precautions/wander-away/AddForm.vue
  30. 297 0
      src/views/elderly/apply/nine-precautions/wander-away/index.vue

+ 38 - 0
src/api/elderly/apply/check-in.ts

@@ -38,3 +38,41 @@ export const getCheckInRecordId = (id, status) => {
     url: `elderlyInfo/getCheckInDetail?checkInRecordId=${id}&status=${status}`,
   })
 }
+
+// 获取服务安全风险知情告知书列表
+export const getSafetyRiskNoticePage = (params) => {
+  return request.get({
+    url: 'elderly/safetyRiskNotice/page',
+    params
+  })
+}
+
+// 获取服务安全风险知情告知书详情
+export const getSafetyRiskNoticeById = (id) => {
+  return request.get({
+    url: `elderly/safetyRiskNotice/get?id=${id}`
+  })
+}
+
+// 新增服务安全风险知情告知书
+export const addSafetyRiskNotice = (data) => {
+  return request.post({
+    url: 'elderly/safetyRiskNotice/add',
+    data
+  })
+}
+
+// 更新服务安全风险知情告知书
+export const updateSafetyRiskNotice = (data) => {
+  return request.put({
+    url: 'elderly/safetyRiskNotice/update',
+    data
+  })
+}
+
+// 删除服务安全风险知情告知书
+export const deleteSafetyRiskNotice = (id) => {
+  return request.delete({
+    url: `elderly/safetyRiskNotice/delete?id=${id}`
+  })
+}

+ 479 - 0
src/api/social-work/index.ts

@@ -733,3 +733,482 @@ export const dangerousGoodsDelete = async (id: number) => {
 export const dangerousGoodsExport = async (id: number) => {
   return await request.download({ url: '/elderly-dangerous-goods/export?id=' + id })
 }
+
+
+// ==================== 防噎食评估表 ====================
+
+// 防噎食评估表数据接口
+export interface AsphyxiationFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  riskLevel?: string      // 风险等级(none/low/medium/high)
+  assessor?: string       // 评估人(冗余字段,便于查询)
+  assessDate?: string     // 评估日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建防噎食评估记录
+export const asphyxiationCreate = async (data: AsphyxiationFormData) => {
+  return await request.post({ url: '/elderly-assess-asphyxiation/create', data })
+}
+
+// 更新防噎食评估记录
+export const asphyxiationUpdate = async (data: AsphyxiationFormData) => {
+  return await request.put({ url: '/elderly-assess-asphyxiation/update', data })
+}
+
+// 根据ID获取防噎食评估记录
+export const asphyxiationGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-asphyxiation/get?id=' + id })
+}
+
+// 获取长者的防噎食评估记录
+export const asphyxiationGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-asphyxiation/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询防噎食评估记录
+export const asphyxiationPage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-asphyxiation/page', params })
+}
+
+// 删除防噎食评估记录
+export const asphyxiationDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-asphyxiation/delete?id=${id}` })
+}
+
+// 导出防噎食评估记录
+export const asphyxiationExport = async (id: number) => {
+  return await request.download({ url: '/elderly-asphyxiation/export?id=' + id })
+}
+
+
+// ==================== 防压疮评估表 ====================
+
+// 防压疮评估表数据接口
+export interface PressureSoresFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  totalScore?: number     // 评估总得分
+  riskLevel?: string      // 风险等级(none/low/medium/high)
+  assessor?: string       // 评估人(冗余字段,便于查询)
+  assessDate?: string     // 评估日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建防压疮评估记录
+export const pressureSoresCreate = async (data: PressureSoresFormData) => {
+  return await request.post({ url: '/elderly-assess-pressure-sores/create', data })
+}
+
+// 更新防压疮评估记录
+export const pressureSoresUpdate = async (data: PressureSoresFormData) => {
+  return await request.put({ url: '/elderly-assess-pressure-sores/update', data })
+}
+
+// 根据ID获取防压疮评估记录
+export const pressureSoresGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-pressure-sores/get?id=' + id })
+}
+
+// 获取长者的防压疮评估记录
+export const pressureSoresGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-pressure-sores/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询防压疮评估记录
+export const pressureSoresPage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-pressure-sores/page', params })
+}
+
+// 删除防压疮评估记录
+export const pressureSoresDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-pressure-sores/delete?id=${id}` })
+}
+
+// 导出防压疮评估记录
+export const pressureSoresExport = async (id: number) => {
+  return await request.download({ url: '/elderly-pressure-sores/export?id=' + id })
+}
+
+
+// ==================== 跌倒风险评估表 ====================
+
+// 跌倒风险评估表数据接口
+export interface FallDownFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  totalScore?: number     // 评估总得分
+  riskLevel?: string      // 风险等级(none/low/medium/high)
+  assessor?: string       // 评估人(冗余字段,便于查询)
+  assessDate?: string     // 评估日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建跌倒风险评估记录
+export const fallDownCreate = async (data: FallDownFormData) => {
+  return await request.post({ url: '/elderly-assess-fall-down/create', data })
+}
+
+// 更新跌倒风险评估记录
+export const fallDownUpdate = async (data: FallDownFormData) => {
+  return await request.put({ url: '/elderly-assess-fall-down/update', data })
+}
+
+// 根据ID获取跌倒风险评估记录
+export const fallDownGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-fall-down/get?id=' + id })
+}
+
+// 获取长者的跌倒风险评估记录
+export const fallDownGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-fall-down/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询跌倒风险评估记录
+export const fallDownPage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-fall-down/page', params })
+}
+
+// 删除跌倒风险评估记录
+export const fallDownDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-fall-down/delete?id=${id}` })
+}
+
+// 导出跌倒风险评估记录
+export const fallDownExport = async (id: number) => {
+  return await request.download({ url: '/elderly-fall-down/export?id=' + id })
+}
+
+
+// ==================== 防坠床评估表 ====================
+
+// 防坠床评估表数据接口
+export interface FallPreventionFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  totalScore?: number     // 评估总得分
+  riskLevel?: string      // 风险等级(none/low/medium/high)
+  assessor?: string       // 评估人(冗余字段,便于查询)
+  assessDate?: string     // 评估日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建防坠床评估记录
+export const fallPreventionCreate = async (data: FallPreventionFormData) => {
+  return await request.post({ url: '/elderly-assess-fall-prevention/create', data })
+}
+
+// 更新防坠床评估记录
+export const fallPreventionUpdate = async (data: FallPreventionFormData) => {
+  return await request.put({ url: '/elderly-assess-fall-prevention/update', data })
+}
+
+// 根据ID获取防坠床评估记录
+export const fallPreventionGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-fall-prevention/get?id=' + id })
+}
+
+// 获取长者的防坠床评估记录
+export const fallPreventionGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-fall-prevention/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询防坠床评估记录
+export const fallPreventionPage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-fall-prevention/page', params })
+}
+
+// 删除防坠床评估记录
+export const fallPreventionDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-fall-prevention/delete?id=${id}` })
+}
+
+// 导出防坠床评估记录
+export const fallPreventionExport = async (id: number) => {
+  return await request.download({ url: '/elderly-fall-prevention/export?id=' + id })
+}
+
+
+// ==================== 防烫伤评估表 ====================
+
+// 防烫伤评估表数据接口
+export interface BurnPreventionFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  totalScore?: number     // 评估总得分
+  riskLevel?: string      // 风险等级(none/low/medium/high)
+  assessor?: string       // 评估人(冗余字段,便于查询)
+  assessDate?: string     // 评估日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建防烫伤评估记录
+export const burnPreventionCreate = async (data: BurnPreventionFormData) => {
+  return await request.post({ url: '/elderly-assess-burn-prevention/create', data })
+}
+
+// 更新防烫伤评估记录
+export const burnPreventionUpdate = async (data: BurnPreventionFormData) => {
+  return await request.put({ url: '/elderly-assess-burn-prevention/update', data })
+}
+
+// 根据ID获取防烫伤评估记录
+export const burnPreventionGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-burn-prevention/get?id=' + id })
+}
+
+// 获取长者的防烫伤评估记录
+export const burnPreventionGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-burn-prevention/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询防烫伤评估记录
+export const burnPreventionPage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-burn-prevention/page', params })
+}
+
+// 删除防烫伤评估记录
+export const burnPreventionDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-burn-prevention/delete?id=${id}` })
+}
+
+// 导出防烫伤评估记录
+export const burnPreventionExport = async (id: number) => {
+  return await request.download({ url: '/elderly-burn-prevention/export?id=' + id })
+}
+
+
+// ==================== 防走失风险评估表 ====================
+
+// 防走失风险评估表数据接口
+export interface WanderAwayFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  totalScore?: number     // 评估总得分
+  riskLevel?: string      // 风险等级(none/low/medium/high)
+  assessor?: string       // 评估人(冗余字段,便于查询)
+  assessDate?: string     // 评估日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建防走失风险评估记录
+export const wanderAwayCreate = async (data: WanderAwayFormData) => {
+  return await request.post({ url: '/elderly-assess-wander-away/create', data })
+}
+
+// 更新防走失风险评估记录
+export const wanderAwayUpdate = async (data: WanderAwayFormData) => {
+  return await request.put({ url: '/elderly-assess-wander-away/update', data })
+}
+
+// 根据ID获取防走失风险评估记录
+export const wanderAwayGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-wander-away/get?id=' + id })
+}
+
+// 获取长者的防走失风险评估记录
+export const wanderAwayGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-wander-away/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询防走失风险评估记录
+export const wanderAwayPage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-wander-away/page', params })
+}
+
+// 删除防走失风险评估记录
+export const wanderAwayDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-wander-away/delete?id=${id}` })
+}
+
+// 导出防走失风险评估记录
+export const wanderAwayExport = async (id: number) => {
+  return await request.download({ url: '/elderly-wander-away/export?id=' + id })
+}
+
+
+// ==================== 老年人平衡能力测试表 ====================
+
+// 老年人平衡能力测试表数据接口
+export interface EquilibriumFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  totalScore?: number     // 评估总得分
+  riskLevel?: string      // 风险等级(none/low/medium/high)
+  assessor?: string       // 评估人(冗余字段,便于查询)
+  assessDate?: string     // 评估日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建老年人平衡能力测试记录
+export const equilibriumCreate = async (data: EquilibriumFormData) => {
+  return await request.post({ url: '/elderly-assess-equilibrium/create', data })
+}
+
+// 更新老年人平衡能力测试记录
+export const equilibriumUpdate = async (data: EquilibriumFormData) => {
+  return await request.put({ url: '/elderly-assess-equilibrium/update', data })
+}
+
+// 根据ID获取老年人平衡能力测试记录
+export const equilibriumGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-equilibrium/get?id=' + id })
+}
+
+// 获取长者的老年人平衡能力测试记录
+export const equilibriumGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-equilibrium/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询老年人平衡能力测试记录
+export const equilibriumPage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-equilibrium/page', params })
+}
+
+// 删除老年人平衡能力测试记录
+export const equilibriumDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-equilibrium/delete?id=${id}` })
+}
+
+// 导出老年人平衡能力测试记录
+export const equilibriumExport = async (id: number) => {
+  return await request.download({ url: '/elderly-equilibrium/export?id=' + id })
+}
+
+
+// ==================== 日常生活活动能力评估表(Barthel指数) ====================
+
+// 日常生活活动能力评估表数据接口
+export interface DailyLifeFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  totalScore?: number     // 评估总得分
+  resultLevel?: string    // 结果等级(complete_dependence/large_help/need_help/basic_independent)
+  assessor?: string       // 评估人(冗余字段,便于查询)
+  assessDate?: string     // 评估日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建日常生活活动能力评估记录
+export const dailyLifeCreate = async (data: DailyLifeFormData) => {
+  return await request.post({ url: '/elderly-assess-daily-life/create', data })
+}
+
+// 更新日常生活活动能力评估记录
+export const dailyLifeUpdate = async (data: DailyLifeFormData) => {
+  return await request.put({ url: '/elderly-assess-daily-life/update', data })
+}
+
+// 根据ID获取日常生活活动能力评估记录
+export const dailyLifeGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-daily-life/get?id=' + id })
+}
+
+// 获取长者的日常生活活动能力评估记录
+export const dailyLifeGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-daily-life/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询日常生活活动能力评估记录
+export const dailyLifePage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-daily-life/page', params })
+}
+
+// 删除日常生活活动能力评估记录
+export const dailyLifeDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-daily-life/delete?id=${id}` })
+}
+
+// 导出日常生活活动能力评估记录
+export const dailyLifeExport = async (id: number) => {
+  return await request.download({ url: '/elderly-daily-life/export?id=' + id })
+}
+
+// ==================== 营养风险评估表 ====================
+
+// 营养风险评估表数据接口
+export interface NutritionalRiskFormData {
+  id?: number
+  elderId: number
+  tenantId: number
+  assessData: string           // JSON 字符串存储所有表单数据
+  // 基本信息
+  height?: number              // 身高(m)
+  weight?: number              // 体重(Kg)
+  // 初筛分数
+  initialScore?: number        // 初筛总分(满分14分)
+  // 评估分数
+  assessScore?: number         // 评估分数(满分16分)
+  // 测量分数
+  measureScore?: number        // 测量分数(满分2分)
+  // 年龄调整
+  ageAdjust?: number           // 年龄调整分(0或1分)
+  // 总分
+  totalScore?: number          // 量表总分(满分30分)
+  // 结果
+  resultLevel?: string         // 结果等级(good/at_risk/malnutrition)
+  assessor?: string            // 评估人
+  assessDate?: string          // 评估日期
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建营养风险评估记录
+export const nutritionalRiskCreate = async (data: NutritionalRiskFormData) => {
+  return await request.post({ url: '/elderly-assess-nutritional-risk/create', data })
+}
+
+// 更新营养风险评估记录
+export const nutritionalRiskUpdate = async (data: NutritionalRiskFormData) => {
+  return await request.put({ url: '/elderly-assess-nutritional-risk/update', data })
+}
+
+// 根据ID获取营养风险评估记录
+export const nutritionalRiskGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-assess-nutritional-risk/get?id=' + id })
+}
+
+// 获取长者的营养风险评估记录
+export const nutritionalRiskGetByElderId = async (elderId: number) => {
+  return await request.get({ url: '/elderly-assess-nutritional-risk/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询营养风险评估记录
+export const nutritionalRiskPage = async (params: any) => {
+  return await request.get({ url: '/elderly-assess-nutritional-risk/page', params })
+}
+
+// 删除营养风险评估记录
+export const nutritionalRiskDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-assess-nutritional-risk/delete?id=${id}` })
+}
+
+// 导出营养风险评估记录
+export const nutritionalRiskExport = async (id: number) => {
+  return await request.download({ url: '/elderly-assess-nutritional-risk/export?id=' + id })
+}

+ 1522 - 0
src/views/elderly/apply/nine-precautions/MMSE/AddForm.vue

@@ -0,0 +1,1522 @@
+<template>
+  <el-drawer
+    v-model="dialogVisible"
+    :title="title"
+    resizable
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :destroy-on-close="true"
+    size="70%"
+    :before-close="handleClosed"
+  >
+
+    <div class="mmse-form">
+      <h1 class="form-title">简易精神状态评价量表</h1>
+        <!-- 基本信息 -->
+        <el-row :gutter="40">
+          <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+            <text>长者姓名</text>
+            <search-the-elderly ref="selectElderRef" :disabled="isDetail" @update_elder="elderUp" v-model="dataForm.elderName" :tId="dataForm.tenantId"/>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+            <text>档案号</text>
+            <el-input v-if="!isDetail" v-model="dataForm.contractNumber" disabled />
+            <el-text v-else disabled="">{{dataForm.contractNumber}}</el-text>
+          </el-col>
+        </el-row>
+        <el-row :gutter="40">
+          <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+            <text>入院日期</text>
+            <el-input v-if="!isDetail" :model-value="dayjs(dataForm.checkInTime).format('YYYY-MM-DD')=='Invalid Date'?'':dayjs(dataForm.checkInTime).format('YYYY-MM-DD')" disabled />
+            <el-text v-else disabled="">{{dayjs(dataForm.checkInTime).format('YYYY-MM-DD')}}</el-text>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+            <text>床位号</text>
+            <el-input v-if="!isDetail" v-model="dataForm.bedName" disabled />
+            <el-text v-else disabled="">{{dataForm.bedName}}</el-text>
+          </el-col>
+        </el-row>
+
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>评估人</text>
+          <el-input :disabled="isDetail" v-model="form.assessor"  />
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>评估日期</text>
+          <el-date-picker :disabled="isDetail" v-model="form.assessDate" type="date" style="width: 100%;"/>
+
+        </el-col>
+      </el-row>
+
+        <!-- 表单内容区域 -->
+        <div class="form-body">
+          <!-- 总分显示 -->
+          <div class="total-score-section">
+            <div class="total-score">
+              <span class="score-label">总分:</span>
+              <span class="score-value">{{ totalScore }}</span>
+              <span class="score-max">/ 30分</span>
+            </div>
+
+          </div>
+
+          <!-- 一、定向力 (10分) -->
+          <div class="section">
+            <div class="section-title">一、定向力(10分)</div>
+
+            <div class="form-item">
+              <span class="item-number">1.</span>
+              <span class="item-label">时间定向(5分):</span>
+              <div class="score-group">
+                <div class="score-row">
+                  <span>今年是哪一年?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.year" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>现在是什么季节?</span>
+                  <el-radio-group  :disabled="isDetail" v-model="form.orientation.season" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>现在是几月份?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.month" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>今天是几号?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.day" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>今天是星期几?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.weekDay" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+              </div>
+            </div>
+
+            <div class="form-item">
+              <span class="item-number">2.</span>
+              <span class="item-label">地点定向(5分):</span>
+              <div class="score-group">
+                <div class="score-row">
+                  <span>你住在那个省?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.province" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>你住在那个县(区)?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.county" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>你住在那个乡(街道)?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.town" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>咱们现在在哪个养老院?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.nursingHome" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>咱们现在在第几层楼?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.orientation.floor" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <!-- 二、记忆力 (3分) -->
+          <div class="section">
+            <div class="section-title">二、记忆力(3分)</div>
+            <div class="form-item">
+              <span class="item-number">3.</span>
+              <span class="item-label">告诉你三种东西,我说完后,请你重复一遍并记住,待会还会问你(各1分,共3分):</span>
+              <el-radio-group :disabled="isDetail" v-model="form.memory.score" size="small">
+                <el-radio :value="3">3分</el-radio>
+                <el-radio :value="2">2分</el-radio>
+                <el-radio :value="1">1分</el-radio>
+                <el-radio :value="0">0分</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 三、注意力和计算力 (5分) -->
+          <div class="section">
+            <div class="section-title">三、注意力和计算力(5分)</div>
+            <div class="form-item">
+              <span class="item-number">4.</span>
+              <span class="item-label">100-7=?连续减5次(93、86、79、72、65。各1分,共5分。若错了,但下一个答案正确,只记一次错误):</span>
+              <el-radio-group :disabled="isDetail" v-model="form.attention.score" size="small">
+                <el-radio :value="5">5分</el-radio>
+                <el-radio :value="4">4分</el-radio>
+                <el-radio :value="3">3分</el-radio>
+                <el-radio :value="2">2分</el-radio>
+                <el-radio :value="1">1分</el-radio>
+                <el-radio :value="0">0分</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 四、回忆能力 (3分) -->
+          <div class="section">
+            <div class="section-title">四、回忆能力(3分)</div>
+            <div class="form-item">
+              <span class="item-number">5.</span>
+              <span class="item-label">现在请你说出我刚才告诉你让你记住的那些东西?</span>
+              <el-radio-group :disabled="isDetail" v-model="form.recall.score" size="small">
+                <el-radio :value="3">3分</el-radio>
+                <el-radio :value="2">2分</el-radio>
+                <el-radio :value="1">1分</el-radio>
+                <el-radio :value="0">0分</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 五、命名能力 (2分) -->
+          <div class="section">
+            <div class="section-title">五、命名能力(2分)</div>
+            <div class="form-item">
+              <span class="item-number">6.</span>
+              <span class="item-label">命名能力:</span>
+              <div class="score-group">
+                <div class="score-row">
+                  <span>出示手表,问这个是什么东西?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.naming.watch" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+                <div class="score-row">
+                  <span>出示钢笔,问这个是什么东西?</span>
+                  <el-radio-group :disabled="isDetail" v-model="form.naming.pen" size="small">
+                    <el-radio :value="1">正确(1分)</el-radio>
+                    <el-radio :value="0">错误(0分)</el-radio>
+                  </el-radio-group>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <!-- 六、复述能力 (1分) -->
+          <div class="section">
+            <div class="section-title">六、复述能力(1分)</div>
+            <div class="form-item">
+              <span class="item-number">7.</span>
+              <span class="item-label">我现在说一句话,请跟我清楚的重复一遍(四十四只石狮子)!</span>
+              <el-radio-group :disabled="isDetail" v-model="form.repetition.score" size="small">
+                <el-radio :value="1">正确(1分)</el-radio>
+                <el-radio :value="0">错误(0分)</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 七、阅读能力 (1分) -->
+          <div class="section">
+            <div class="section-title">七、阅读能力(1分)</div>
+            <div class="form-item">
+              <span class="item-number">8.</span>
+              <span class="item-label">(闭上你的眼睛)请你念念这句话,并按上面意思去做!</span>
+              <el-radio-group :disabled="isDetail" v-model="form.reading.score" size="small">
+                <el-radio :value="1">正确(1分)</el-radio>
+                <el-radio :value="0">错误(0分)</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 八、三步命令 (3分) -->
+          <div class="section">
+            <div class="section-title">八、三步命令(3分)</div>
+            <div class="form-item">
+              <span class="item-number">9.</span>
+              <span class="item-label">我给您一张纸请您按我说的去做,现在开始:"用右手拿着这张纸,用两只手将它对折起来,放在您的左腿上。"(每个动作1分,共3分):</span>
+              <el-radio-group :disabled="isDetail" v-model="form.threeStepCommand.score" size="small">
+                <el-radio :value="3">3分</el-radio>
+                <el-radio :value="2">2分</el-radio>
+                <el-radio :value="1">1分</el-radio>
+                <el-radio :value="0">0分</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 九、书写能力 (1分) -->
+          <div class="section">
+            <div class="section-title">九、书写能力(1分)</div>
+            <div class="form-item">
+              <span class="item-number">10.</span>
+              <span class="item-label">书写能力要求受试者自己写一句完整的句子:</span>
+              <el-radio-group :disabled="isDetail" v-model="form.writing.score" size="small">
+                <el-radio :value="1">正确(1分)</el-radio>
+                <el-radio :value="0">错误(0分)</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 十、结构能力 (1分) -->
+          <div class="section">
+            <div class="section-title">十、结构能力(1分)</div>
+            <div class="form-item">
+              <span class="item-number">11.</span>
+              <span class="item-label">(出示图案)请你照上面图案画下来!</span>
+              <div class="structure-content">
+                <div class="structure-image">
+                  <!-- 两个重叠的五边形图案 -->
+                  <svg viewBox="0 0 200 120" class="pentagon-svg">
+                    <!-- 左侧五边形 -->
+                    <polygon points="50,10 90,30 90,80 50,100 10,80 10,30" fill="none" stroke="#333" stroke-width="2"/>
+                    <!-- 右侧五边形 -->
+                    <polygon points="110,10 150,30 150,80 110,100 70,80 70,30" fill="none" stroke="#333" stroke-width="2"/>
+                  </svg>
+                </div>
+                <el-radio-group :disabled="isDetail" v-model="form.structure.score" size="small">
+                  <el-radio :value="1">正确(1分)</el-radio>
+                  <el-radio :value="0">错误(0分)</el-radio>
+                </el-radio-group>
+              </div>
+            </div>
+          </div>
+
+          <!-- 风险程度判断 -->
+          <div class="section risk-section">
+            <div class="section-title">风险程度判断</div>
+            <div class="risk-judgment">
+              <el-radio-group :disabled="isDetail" v-model="form.riskLevel" >
+                <el-radio value="none" style="margin-right: 10px">无风险:MMSE ≥27分</el-radio>
+                <el-radio value="low" style="margin-right: 10px">低风险:MMSE 26-21分</el-radio>
+                <el-radio value="medium" style="margin-right: 10px">中风险:MMSE 10-20分</el-radio>
+                <el-radio value="high" style="margin-right: 10px">高风险:MMSE ≤9分</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 预防措施 -->
+          <div class="section">
+            <div class="section-title">预防措施</div>
+            <div class="form-item">
+              <el-checkbox-group :disabled="isDetail" v-model="form.preventiveMeasures" class="preventive-measures">
+                <el-checkbox value="diet">饮食与生活习惯管理</el-checkbox>
+                <el-checkbox value="environment">环境优化与安全保障</el-checkbox>
+                <el-checkbox value="emotion">情绪与行为干预</el-checkbox>
+                <el-checkbox value="monitoring">健康监测</el-checkbox>
+                <el-checkbox value="personalized">个性化活动(计算能力训练、方向感知觉训练、记忆力训练等)</el-checkbox>
+                <el-checkbox value="other">其他</el-checkbox>
+              </el-checkbox-group>
+              <template v-if="form.preventiveMeasures.includes('other')">
+                <el-input v-model="form.preventiveMeasuresOther" class="other-input" placeholder="请输入其他预防措施" />
+              </template>
+            </div>
+          </div>
+        </div>
+    </div>
+
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary" v-show="!isDetail" @click="submitForm">确定</el-button>
+      <el-button v-if="isDetail"  type="success" @click="handleExport">打印</el-button>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref } from 'vue'
+
+import dayjs from 'dayjs'
+
+import {mmseCreate, mmseGetById, mmseUpdate} from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const selectElderRef = ref() // 表单 Ref
+const isDetail = ref(false) // 是否详情打开
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+let dataForm = ref({
+  // 表单字段
+  id: undefined,
+  idCard: '',
+  contractNumber: '', //档案号
+  elderName: '',//长者姓名
+  bedName: '', //床位号
+  elderAge: '', //年龄
+  elderSex: '', //性别
+  checkInTime: '', //入院日期
+  elderId: '',
+  tenantId: undefined
+})
+
+
+
+
+const elderUp = (e) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.checkInTime = e.checkInTime
+  dataForm.value.contractNumber = e.contractNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== MMSE 表单序列化方法 ==========
+
+/** 计算总分 */
+const totalScore = computed(() => {
+  const orientationScore = 
+    (form.orientation.year || 0) +
+    (form.orientation.season || 0) +
+    (form.orientation.month || 0) +
+    (form.orientation.day || 0) +
+    (form.orientation.weekDay || 0) +
+    (form.orientation.province || 0) +
+    (form.orientation.county || 0) +
+    (form.orientation.town || 0) +
+    (form.orientation.nursingHome || 0) +
+    (form.orientation.floor || 0)
+  
+  const namingScore = (form.naming.watch || 0) + (form.naming.pen || 0)
+  
+  return orientationScore +
+    (form.memory.score || 0) +
+    (form.attention.score || 0) +
+    (form.recall.score || 0) +
+    namingScore +
+    (form.repetition.score || 0) +
+    (form.reading.score || 0) +
+    (form.threeStepCommand.score || 0) +
+    (form.writing.score || 0) +
+    (form.structure.score || 0)
+})
+
+/** 风险程度文本 */
+const riskLevelText = computed(() => {
+  const score = totalScore.value
+  if (score >= 27) return '无风险'
+  if (score >= 21) return '低风险'
+  if (score >= 10) return '中风险'
+  return '高风险'
+})
+
+/** 风险程度样式类 */
+const riskLevelClass = computed(() => {
+  const score = totalScore.value
+  if (score >= 27) return 'risk-none'
+  if (score >= 21) return 'risk-low'
+  if (score >= 10) return 'risk-medium'
+  return 'risk-high'
+})
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    // 基本信息
+    assessor: form.assessor || '',
+    assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : '',
+    
+    // 各项评分
+    orientation: { ...form.orientation },
+    memory: { ...form.memory },
+    attention: { ...form.attention },
+    recall: { ...form.recall },
+    naming: { ...form.naming },
+    repetition: { ...form.repetition },
+    reading: { ...form.reading },
+    threeStepCommand: { ...form.threeStepCommand },
+    writing: { ...form.writing },
+    structure: { ...form.structure },
+    
+    // 总分
+    totalScore: totalScore.value,
+    
+    // 风险程度
+    riskLevel: form.riskLevel || '',
+    
+    // 预防措施
+    preventiveMeasures: form.preventiveMeasures || [],
+    preventiveMeasuresOther: form.preventiveMeasuresOther || ''
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  // 基本信息
+  form.assessor = formData.assessor || ''
+  form.assessDate = formData.assessDate ? dayjs(formData.assessDate).toDate() : ''
+
+  // 各项评分
+  form.orientation = {
+    year: formData.orientation?.year ?? 0,
+    season: formData.orientation?.season ?? 0,
+    month: formData.orientation?.month ?? 0,
+    day: formData.orientation?.day ?? 0,
+    weekDay: formData.orientation?.weekDay ?? 0,
+    province: formData.orientation?.province ?? 0,
+    county: formData.orientation?.county ?? 0,
+    town: formData.orientation?.town ?? 0,
+    nursingHome: formData.orientation?.nursingHome ?? 0,
+    floor: formData.orientation?.floor ?? 0
+  }
+  form.memory = { score: formData.memory?.score ?? 0 }
+  form.attention = { score: formData.attention?.score ?? 0 }
+  form.recall = { score: formData.recall?.score ?? 0 }
+  form.naming = {
+    watch: formData.naming?.watch ?? 0,
+    pen: formData.naming?.pen ?? 0
+  }
+  form.repetition = { score: formData.repetition?.score ?? 0 }
+  form.reading = { score: formData.reading?.score ?? 0 }
+  form.threeStepCommand = { score: formData.threeStepCommand?.score ?? 0 }
+  form.writing = { score: formData.writing?.score ?? 0 }
+  form.structure = { score: formData.structure?.score ?? 0 }
+
+  // 风险程度
+  form.riskLevel = formData.riskLevel || ''
+
+  // 预防措施
+  form.preventiveMeasures = formData.preventiveMeasures || []
+  form.preventiveMeasuresOther = formData.preventiveMeasuresOther || ''
+}
+
+/** 重置 MMSE 表单数据 */
+const resetMMSEForm = () => {
+  form.assessor = ''
+  form.assessDate = ''
+
+  // 定向力
+  form.orientation = {
+    year: 0,
+    season: 0,
+    month: 0,
+    day: 0,
+    weekDay: 0,
+    province: 0,
+    county: 0,
+    town: 0,
+    nursingHome: 0,
+    floor: 0
+  }
+
+  // 其他评分
+  form.memory = { score: 0 }
+  form.attention = { score: 0 }
+  form.recall = { score: 0 }
+  form.naming = { watch: 0, pen: 0 }
+  form.repetition = { score: 0 }
+  form.reading = { score: 0 }
+  form.threeStepCommand = { score: 0 }
+  form.writing = { score: 0 }
+  form.structure = { score: 0 }
+
+  // 风险程度
+  form.riskLevel = ''
+
+  // 预防措施
+  form.preventiveMeasures = []
+  form.preventiveMeasuresOther = ''
+}
+
+/** 加载评估数据 */
+const loadAttackRiskData = async (id: number) => {
+  try {
+    const res = await mmseGetById(id)
+    if (res) {
+      // 填充长者基本信息
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.checkInTime = res.checkInTime || ''
+      dataForm.value.contractNumber = res.fileNumber || ''
+      dataForm.value.elderAge = res.elderAge || ''
+
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      // 解析 assessmentData
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+/** 打开弹窗 */
+const open = async (tenantId, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-MMSE评估"
+    // 加载 MMSE 数据
+    await loadAttackRiskData(id)
+  } else {
+    title.value = "新增-MMSE评估"
+
+  }
+}
+
+
+const form = reactive({
+  // 基本信息
+  assessor: '',
+  assessDate: '',
+
+  // 定向力 (10分)
+  orientation: {
+    year: 0,
+    season: 0,
+    month: 0,
+    day: 0,
+    weekDay: 0,
+    province: 0,
+    county: 0,
+    town: 0,
+    nursingHome: 0,
+    floor: 0
+  },
+
+  // 记忆力 (3分)
+  memory: { score: 0 },
+
+  // 注意力和计算力 (5分)
+  attention: { score: 0 },
+
+  // 回忆能力 (3分)
+  recall: { score: 0 },
+
+  // 命名能力 (2分)
+  naming: { watch: 0, pen: 0 },
+
+  // 复述能力 (1分)
+  repetition: { score: 0 },
+
+  // 阅读能力 (1分)
+  reading: { score: 0 },
+
+  // 三步命令 (3分)
+  threeStepCommand: { score: 0 },
+
+  // 书写能力 (1分)
+  writing: { score: 0 },
+
+  // 结构能力 (1分)
+  structure: { score: 0 },
+
+  // 风险程度
+  riskLevel: '',
+
+  // 预防措施
+  preventiveMeasures: [],
+  preventiveMeasuresOther: ''
+})
+
+// MMSE 不需要下拉选项,使用 radio 和 checkbox 直接评分
+
+
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  if (formLoading.value) {
+    return
+  }
+  formLoading.value = true
+  // 提交请求
+  try {
+    const assessData = serializeFormData()
+    const tempParams = {
+      ...dataForm.value,
+      assessData: JSON.stringify(assessData),
+      totalScore: totalScore.value,
+      assessor: form.assessor,
+      assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      const res = await mmseUpdate(tempParams)
+      if (res) {
+        message.success(t('common.updateSuccess'))
+        dialogVisible.value = false
+        // 发送操作成功的事件
+        emit('success')
+      }
+    } else {
+      const res = await mmseCreate(tempParams)
+      if (res) {
+        message.success(t('common.createSuccess'))
+        dialogVisible.value = false
+        // 发送操作成功的事件
+        emit('success')
+      }
+    }
+  } finally {
+    setTimeout(() => {
+      formLoading.value = false
+    }, 500)
+  }
+}
+
+
+
+/** 重置表单 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    idCard: '',
+    contractNumber: '', //档案号
+    elderName: '',//长者姓名
+    bedName: '', //床位号
+    elderAge: '', //年龄
+    elderSex: '', //性别
+    checkInTime: '', //入院日期
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  // 重置 MMSE 表单
+  resetMMSEForm()
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+/** 导出PDF */
+const handleExport = () => {
+  // 创建打印窗口
+  const printWindow = window.open('', '_blank')
+  if (!printWindow) {
+    message.error('请允许弹出窗口')
+    return
+  }
+
+  // 辅助函数:获取评分状态
+  const getScoreMark = (score) => score === 1 ? '☑ 正确 (1分)' : '☐ 错误 (0分)'
+  const getMemoryMark = (score) => {
+    const marks = ['☐ 0分', '☐ 1分', '☐ 2分', '☐ 3分']
+    if (score >= 0 && score <= 3) marks[score] = marks[score].replace('☐', '☑')
+    return marks.join('  ')
+  }
+  const getAttentionMark = (score) => {
+    const marks = ['☐ 0分', '☐ 1分', '☐ 2分', '☐ 3分', '☐ 4分', '☐ 5分']
+    if (score >= 0 && score <= 5) marks[score] = marks[score].replace('☐', '☑')
+    return marks.join('  ')
+  }
+  const getRecallMark = (score) => {
+    const marks = ['☐ 0分', '☐ 1分', '☐ 2分', '☐ 3分']
+    if (score >= 0 && score <= 3) marks[score] = marks[score].replace('☐', '☑')
+    return marks.join('  ')
+  }
+  const getThreeStepMark = (score) => {
+    const marks = ['☐ 0分', '☐ 1分', '☐ 2分', '☐ 3分']
+    if (score >= 0 && score <= 3) marks[score] = marks[score].replace('☐', '☑')
+    return marks.join('  ')
+  }
+  const getNamingMark = (score) => score === 1 ? '☑ 正确 (1分)' : '☐ 错误 (0分)'
+
+  // 构建打印内容
+  const printContent = `
+    <!DOCTYPE html>
+    <html>
+    <head>
+      <meta charset="UTF-8">
+      <title>MMSE评估表 - ${dataForm.value.elderName || ''}</title>
+      <style>
+        @media print {
+          @page { size: A4 portrait; margin: 15mm; }
+        }
+        body { 
+          font-family: 'SimSun', 'Microsoft YaHei', serif; 
+          font-size: 11pt; 
+          line-height: 1.5; 
+          color: #333;
+        }
+        .header { 
+          text-align: center; 
+          margin-bottom: 20px; 
+          border-bottom: 2px solid #333;
+          padding-bottom: 10px;
+        }
+        .header h1 { 
+          font-size: 18pt; 
+          margin: 0; 
+          letter-spacing: 2px;
+        }
+        .header .sub-title {
+          font-size: 12pt;
+          color: #666;
+          margin-top: 5px;
+        }
+        .info-section {
+          margin-bottom: 15px;
+          padding: 10px;
+          border: 1px solid #999;
+          background: #fafafa;
+        }
+        .info-row {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 20px;
+        }
+        .info-item {
+          display: flex;
+          align-items: center;
+        }
+        .info-item .label {
+          font-weight: bold;
+          margin-right: 8px;
+          color: #555;
+        }
+        .info-item .value {
+          border-bottom: 1px solid #333;
+          min-width: 80px;
+          padding: 0 5px;
+          text-align: center;
+        }
+        .score-summary {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          padding: 10px 15px;
+          background: #f0f0f0;
+          border: 2px solid #333;
+          margin-bottom: 15px;
+        }
+        .total-score { 
+          font-size: 14pt; 
+          font-weight: bold;
+        }
+        .total-score .score-value {
+          color: #d9534f;
+          font-size: 18pt;
+        }
+        .risk-level { 
+          font-size: 12pt; 
+          font-weight: bold; 
+          padding: 5px 15px;
+        }
+        .risk-none { color: #5cb85c; }
+        .risk-low { color: #f0ad4e; }
+        .risk-medium { color: #d9534f; }
+        .risk-high { color: #d9534f; background: #ffe6e6; padding: 5px 10px; border-radius: 3px; }
+        
+        .section { 
+          margin-bottom: 12px; 
+          border: 1px solid #999;
+        }
+        .section-header { 
+          font-weight: bold; 
+          background: #e8e8e8; 
+          padding: 8px 12px;
+          border-bottom: 1px solid #999;
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+        }
+        .section-title {
+          font-size: 12pt;
+        }
+        .section-score {
+          font-size: 11pt;
+          color: #666;
+        }
+        .question {
+          padding: 8px 12px;
+          border-bottom: 1px dashed #ccc;
+          display: flex;
+          justify-content: space-between;
+          align-items: flex-start;
+        }
+        .question:last-child {
+          border-bottom: none;
+        }
+        .question-text {
+          flex: 1;
+          padding-right: 15px;
+        }
+        .question-number {
+          font-weight: bold;
+          margin-right: 8px;
+          color: #555;
+        }
+        .question-desc {
+          font-size: 10pt;
+          color: #666;
+          margin-top: 3px;
+        }
+        .answer-options {
+          white-space: nowrap;
+          font-size: 10pt;
+          color: #555;
+        }
+        .structure-image {
+          text-align: center;
+          padding: 10px;
+          background: #fafafa;
+          margin: 10px 0;
+        }
+        .structure-image svg {
+          width: 200px;
+          height: 120px;
+        }
+        
+        .measures-section {
+          margin-top: 15px;
+          border: 1px solid #999;
+        }
+        .measures-title {
+          font-weight: bold;
+          background: #e8e8e8;
+          padding: 8px 12px;
+          border-bottom: 1px solid #999;
+        }
+        .measures-content {
+          padding: 10px 12px;
+        }
+        .measure-item {
+          margin-bottom: 5px;
+          font-size: 10pt;
+        }
+        .measure-other {
+          margin-left: 20px;
+          margin-top: 5px;
+          border-bottom: 1px solid #333;
+          min-width: 200px;
+          display: inline-block;
+        }
+        
+        .signature-section {
+          margin-top: 30px;
+          display: flex;
+          justify-content: space-between;
+        }
+        .signature-item {
+          width: 45%;
+        }
+        .signature-label {
+          margin-bottom: 5px;
+        }
+        .signature-line {
+          border-bottom: 1px solid #333;
+          height: 30px;
+        }
+        .date-line {
+          border-bottom: 1px solid #333;
+          height: 30px;
+          width: 150px;
+        }
+        
+        .footer-note {
+          margin-top: 20px;
+          font-size: 9pt;
+          color: #666;
+          text-align: center;
+          border-top: 1px solid #ccc;
+          padding-top: 10px;
+        }
+      </style>
+    </head>
+    <body>
+      <div class="header">
+        <h1>简易精神状态评价量表(MMSE)</h1>
+        <div class="sub-title">Mini-Mental State Examination</div>
+      </div>
+      
+      <div class="info-section">
+        <div class="info-row">
+          <div class="info-item">
+            <span class="label">长者姓名:</span>
+            <span class="value">${dataForm.value.elderName || ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">档案号:</span>
+            <span class="value">${dataForm.value.contractNumber || ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">床位号:</span>
+            <span class="value">${dataForm.value.bedName || ''}</span>
+          </div>
+        </div>
+        <div class="info-row" style="margin-top: 10px;">
+          <div class="info-item">
+            <span class="label">评估日期:</span>
+            <span class="value">${form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">评估人:</span>
+            <span class="value">${form.assessor || ''}</span>
+          </div>
+        </div>
+      </div>
+
+      <div class="score-summary">
+        <div class="total-score">
+          总分:<span class="score-value">${totalScore.value}</span> / 30分
+        </div>
+      </div>
+
+      <!-- 一、定向力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">一、定向力(10分)</span>
+          <span class="section-score">得分:${(form.orientation.year || 0) + (form.orientation.season || 0) + (form.orientation.month || 0) + (form.orientation.day || 0) + (form.orientation.weekDay || 0) + (form.orientation.province || 0) + (form.orientation.county || 0) + (form.orientation.town || 0) + (form.orientation.nursingHome || 0) + (form.orientation.floor || 0)} / 10分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">1.</span>
+            <div>
+              <div>时间定向(5分)</div>
+              <div class="question-desc">今年是哪一年?现在是什么季节?现在是几月份?今天是几号?今天是星期几?</div>
+            </div>
+          </div>
+          <div class="answer-options">
+            ${getScoreMark(form.orientation.year)}<br>
+            ${getScoreMark(form.orientation.season)}<br>
+            ${getScoreMark(form.orientation.month)}<br>
+            ${getScoreMark(form.orientation.day)}<br>
+            ${getScoreMark(form.orientation.weekDay)}
+          </div>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">2.</span>
+            <div>
+              <div>地点定向(5分)</div>
+              <div class="question-desc">你住在那个省?你住在那个县(区)?你住在那个乡(街道)?咱们现在在哪个养老院?咱们现在在第几层楼?</div>
+            </div>
+          </div>
+          <div class="answer-options">
+            ${getScoreMark(form.orientation.province)}<br>
+            ${getScoreMark(form.orientation.county)}<br>
+            ${getScoreMark(form.orientation.town)}<br>
+            ${getScoreMark(form.orientation.nursingHome)}<br>
+            ${getScoreMark(form.orientation.floor)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 二、记忆力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">二、记忆力(3分)</span>
+          <span class="section-score">得分:${form.memory.score || 0} / 3分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">3.</span>
+            <div>
+              <div>告诉你三种东西,我说完后,请你重复一遍并记住,待会还会问你(各1分,共3分)</div>
+              <div class="question-desc">例如:皮球、国旗、树木</div>
+            </div>
+          </div>
+          <div class="answer-options">
+            ${getMemoryMark(form.memory.score || 0)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 三、注意力和计算力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">三、注意力和计算力(5分)</span>
+          <span class="section-score">得分:${form.attention.score || 0} / 5分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">4.</span>
+            <div>
+              <div>100-7=?连续减5次(93、86、79、72、65。各1分,共5分)</div>
+              <div class="question-desc">若错了,但下一个答案正确,只记一次错误</div>
+            </div>
+          </div>
+          <div class="answer-options">
+            ${getAttentionMark(form.attention.score || 0)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 四、回忆能力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">四、回忆能力(3分)</span>
+          <span class="section-score">得分:${form.recall.score || 0} / 3分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">5.</span>
+            <div>现在请你说出我刚才告诉你让你记住的那些东西?</div>
+          </div>
+          <div class="answer-options">
+            ${getRecallMark(form.recall.score || 0)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 五、命名能力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">五、命名能力(2分)</span>
+          <span class="section-score">得分:${(form.naming.watch || 0) + (form.naming.pen || 0)} / 2分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">6.</span>
+            <div>出示手表,问这个是什么东西?</div>
+          </div>
+          <div class="answer-options">
+            ${getNamingMark(form.naming.watch || 0)}
+          </div>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number"></span>
+            <div>出示钢笔,问这个是什么东西?</div>
+          </div>
+          <div class="answer-options">
+            ${getNamingMark(form.naming.pen || 0)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 六、复述能力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">六、复述能力(1分)</span>
+          <span class="section-score">得分:${form.repetition.score || 0} / 1分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">7.</span>
+            <div>我现在说一句话,请跟我清楚的重复一遍(四十四只石狮子)!</div>
+          </div>
+          <div class="answer-options">
+            ${getScoreMark(form.repetition.score || 0)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 七、阅读能力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">七、阅读能力(1分)</span>
+          <span class="section-score">得分:${form.reading.score || 0} / 1分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">8.</span>
+            <div>(闭上你的眼睛)请你念念这句话,并按上面意思去做!</div>
+          </div>
+          <div class="answer-options">
+            ${getScoreMark(form.reading.score || 0)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 八、三步命令 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">八、三步命令(3分)</span>
+          <span class="section-score">得分:${form.threeStepCommand.score || 0} / 3分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">9.</span>
+            <div>
+              <div>我给您一张纸请您按我说的去做,现在开始:</div>
+              <div class="question-desc">"用右手拿着这张纸,用两只手将它对折起来,放在您的左腿上。"(每个动作1分,共3分)</div>
+            </div>
+          </div>
+          <div class="answer-options">
+            ${getThreeStepMark(form.threeStepCommand.score || 0)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 九、书写能力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">九、书写能力(1分)</span>
+          <span class="section-score">得分:${form.writing.score || 0} / 1分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">10.</span>
+            <div>书写能力要求受试者自己写一句完整的句子</div>
+          </div>
+          <div class="answer-options">
+            ${getScoreMark(form.writing.score || 0)}
+          </div>
+        </div>
+      </div>
+
+      <!-- 十、结构能力 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">十、结构能力(1分)</span>
+          <span class="section-score">得分:${form.structure.score || 0} / 1分</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <span class="question-number">11.</span>
+            <div>(出示图案)请你照上面图案画下来!</div>
+          </div>
+          <div class="answer-options">
+            ${getScoreMark(form.structure.score || 0)}
+          </div>
+        </div>
+        <div class="structure-image">
+          <svg viewBox="0 0 200 120">
+            <polygon points="50,10 90,30 90,80 50,100 10,80 10,30" fill="none" stroke="#333" stroke-width="2"/>
+            <polygon points="110,10 150,30 150,80 110,100 70,80 70,30" fill="none" stroke="#333" stroke-width="2"/>
+          </svg>
+        </div>
+      </div>
+
+      <!-- 风险程度判断 -->
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">风险程度判断</span>
+        </div>
+        <div class="question">
+          <div class="question-text">
+            <div style="display: flex; gap: 30px; flex-wrap: wrap;">
+              <span>${form.riskLevel === 'none' ? '☑' : '☐'} 无风险:MMSE ≥27分</span>
+              <span>${form.riskLevel === 'low' ? '☑' : '☐'} 低风险:MMSE 26-21分</span>
+              <span>${form.riskLevel === 'medium' ? '☑' : '☐'} 中风险:MMSE 10-20分</span>
+              <span>${form.riskLevel === 'high' ? '☑' : '☐'} 高风险:MMSE ≤9分</span>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="measures-section">
+        <div class="measures-title">预防措施</div>
+        <div class="measures-content">
+          <div class="measure-item">${form.preventiveMeasures?.includes('diet') ? '☑' : '☐'} 饮食与生活习惯管理</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('environment') ? '☑' : '☐'} 环境优化与安全保障</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('emotion') ? '☑' : '☐'} 情绪与行为干预</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('monitoring') ? '☑' : '☐'} 健康监测</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('personalized') ? '☑' : '☐'} 个性化活动(计算能力训练、方向感知觉训练、记忆力训练等)</div>
+          <div class="measure-item">
+            ${form.preventiveMeasures?.includes('other') ? '☑' : '☐'} 其他
+            ${form.preventiveMeasures?.includes('other') ? '<span class="measure-other">' + (form.preventiveMeasuresOther || '') + '</span>' : ''}
+          </div>
+        </div>
+      </div>
+
+      <div class="signature-section">
+        <div class="signature-item">
+          <div class="signature-label">家属/评估员签名:</div>
+          <div class="signature-line"></div>
+        </div>
+        <div class="signature-item">
+          <div class="signature-label">日期:</div>
+          <div class="date-line"></div>
+        </div>
+      </div>
+
+      <div class="footer-note">
+        注:MMSE总分30分,≥27分为认知功能正常,26-21分为轻度认知障碍,10-20分为中度认知障碍,≤9分为重度认知障碍
+      </div>
+    </body>
+    </html>
+  `
+
+  // 写入内容并打印
+  printWindow.document.write(printContent)
+  printWindow.document.close()
+  
+  // 延迟打印,确保样式加载完成
+  setTimeout(() => {
+    printWindow.print()
+  }, 500)
+}
+
+</script>
+
+<style scoped lang="scss">
+.mmse-form {
+  max-width: 1200px;
+  margin: 0 auto;
+  background: #fff;
+
+  .form-title {
+    text-align: center;
+    font-size: 24px;
+    font-weight: bold;
+    margin-bottom: 20px;
+  }
+
+
+
+    .info-row {
+      display: flex;
+      gap: 40px;
+      width: 100%;
+      flex-direction: row;
+      align-items: center;
+      margin-bottom: 10px;
+
+      .info-item {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        .label {
+          width: 82px;
+          text-align: right;
+          margin-right: 4px;
+          white-space: nowrap;
+        }
+      }
+    }
+
+
+  .form-body {
+    border: 1px solid #333;
+    padding: 15px;
+  }
+
+  .section {
+    margin-bottom: 20px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .section-title {
+      font-weight: bold;
+      margin-bottom: 10px;
+    }
+  }
+
+  .form-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
+    flex-wrap: wrap;
+    gap: 8px;
+
+    .item-number {
+      font-weight: bold;
+      min-width: 25px;
+    }
+
+    .item-label {
+      white-space: nowrap;
+      min-width: fit-content;
+    }
+
+  }
+
+  .other-input {
+    width: 200px;
+    margin-left: 10px;
+  }
+
+  // 调整 Element Plus 组件样式
+  :deep(.el-input__inner) {
+    height: 28px;
+    line-height: 28px;
+    border-top: none;
+    border-left: none;
+    border-right: none;
+    border-radius: 0;
+    padding: 0 4px;
+
+    &:focus {
+      border-color: #409eff;
+    }
+  }
+
+
+  :deep(.el-checkbox__label),
+  :deep(.el-radio__label) {
+    padding-left: 4px;
+  }
+}
+.row{
+  margin-bottom: 12px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  text{
+    text-align: right;
+    margin-right: 4px;
+    width: 82px;
+  }
+}
+
+// MMSE 特有样式
+.total-score-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  margin-bottom: 20px;
+
+  .total-score {
+    display: flex;
+    align-items: baseline;
+    gap: 4px;
+
+    .score-label {
+      font-size: 16px;
+      font-weight: bold;
+    }
+
+    .score-value {
+      font-size: 28px;
+      font-weight: bold;
+      color: #409eff;
+    }
+
+    .score-max {
+      font-size: 14px;
+      color: #909399;
+    }
+  }
+
+  .risk-level {
+    font-size: 16px;
+    font-weight: bold;
+    padding: 8px 16px;
+    border-radius: 4px;
+
+    &.risk-none {
+      color: #67c23a;
+      background: #f0f9eb;
+    }
+
+    &.risk-low {
+      color: #e6a23c;
+      background: #fdf6ec;
+    }
+
+    &.risk-medium {
+      color: #f56c6c;
+      background: #fef0f0;
+    }
+
+    &.risk-high {
+      color: #f56c6c;
+      background: #fef0f0;
+      border: 1px solid #f56c6c;
+    }
+  }
+}
+
+.score-group {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  margin-left: 35px;
+  margin-top: 8px;
+  width: 100%;
+
+  .score-row {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 8px 12px;
+    background: #fafafa;
+    border-radius: 4px;
+
+    span {
+      flex: 1;
+    }
+  }
+}
+
+.structure-content {
+  display: flex;
+  align-items: center;
+  gap: 20px;
+  margin-left: 35px;
+  margin-top: 8px;
+
+  .structure-image {
+    .pentagon-svg {
+      width: 200px;
+      height: 120px;
+      border: 1px solid #dcdfe6;
+      border-radius: 4px;
+      padding: 10px;
+    }
+  }
+}
+
+.risk-section {
+  background: #f5f7fa;
+  padding: 15px;
+  border-radius: 4px;
+
+  .risk-judgment {
+    margin-left: 35px;
+    margin-top: 10px;
+
+    :deep(.el-radio) {
+      display: block;
+      margin-bottom: 8px;
+      margin-right: 0;
+    }
+  }
+}
+
+.preventive-measures {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  margin-left: 35px;
+  margin-top: 8px;
+
+  :deep(.el-checkbox) {
+    margin-right: 0;
+    height: auto;
+    align-items: flex-start;
+
+    .el-checkbox__label {
+      white-space: normal;
+      line-height: 1.5;
+    }
+  }
+}
+</style>

+ 336 - 0
src/views/elderly/apply/nine-precautions/MMSE/index.vue

@@ -0,0 +1,336 @@
+<template>
+  <ContentWrap>
+    <!-- 保护性约束观察记录表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="输入评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+
+      <el-form-item label="评估日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessorDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择评估日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+
+      <ButtonAdd @click="openForm(undefined)"  />
+      <!--      <el-button @click="inputH" type="success"><Icon icon="fa:cloud-upload" :size="16" class="mr-1"/>导入</el-button>-->
+<!--      <ButtonImport @click="handleImportCard"  />-->
+
+
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="200" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="200" show-overflow-tooltip/>
+
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="200" show-overflow-tooltip/>
+
+
+      <el-table-column label="操作" align="center" width="200" >
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+
+
+  <Import
+    ref="importRef"
+    @success="getList"
+    :config="{
+      title: '导入',
+      downloadUrl: 'elderly-service-order/get-import-template',
+      excelTempName: '居家工单-【导入】模板',
+      importUrl: '/elderly-service-order/import',
+      failExportUrl: '',
+    }"
+  />
+
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import ButtonImport from "@/components/ButtonImport/src/ButtonImport.vue";
+import { useUserStore } from '@/store/modules/user'
+import {formatTimestamp, getCurrentMonthRange} from "@/utils/dateUtil";
+import Import from "@/components/ImportFile/index.vue";
+import {restraintCreatePage, restraintDelete} from "@/api/elderly/nursing/keep-fit";
+import {mmseDelete, mmseGetPage} from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const userStore = useUserStore()
+const loading = ref(true) // 列表的加载中
+const detailRef = ref()
+const importRef = ref()
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessorDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref() // 搜索的表单
+
+const inputH = () => {
+  importRef.value.open(queryParams.tenantIds[0])
+}
+// 打开导出弹窗
+const handleImportCard = async () => {
+
+  // showBatchExport.value = true
+}
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch,count)
+  // try {
+  //   let queryParams = {
+  //     pageNo: batch,
+  //     pageSize: count,
+  //     tenantId: userStore.orgTenantId[0]
+  //   }
+  //   const list = await careRecordsPage(queryParams)
+  //   if (list.length <= 0) {
+  //     message.error('暂无数据可以导出!')
+  //     return
+  //   }
+  //   const headers = [
+  //     { key: 'organizationName', title: '机构名称' },
+  //     { key: 'visitName', title: '姓名' },
+  //     { key: 'visitPhone', title: '手机号' },
+  //     { key: 'visitDate', title: '预约时间' },
+  //     { key: 'accompanyCount', title: '陪同人数' },
+  //     { key: 'reason', title: '理由' }
+  //   ]
+  //   exportWithExpandedObjectArrays(list, headers, `医疗护理记录${formatToDateTime()}.xlsx`, '医疗护理记录')
+  // } catch (_) {}
+
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    //let queryP = {...queryParams,discoveryTime:queryParams.discoveryTime?[queryParams.discoveryTime[0]+" 00:00:00",queryParams.discoveryTime[1]+" 23:59:59"]:null}
+    const data = await mmseGetPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessorDate= getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if(queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1){
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id,false)
+}
+
+const editRef = ref()
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id,false)
+}
+
+
+const openFormDetail = (row: any = {},id?: number) => {
+  formRef.value.open(row.tenantId,id,true)
+}
+
+
+
+
+
+const openClose = async (item) => {
+  try {
+    console.log("任务ID",item)
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      // 发起
+      try {
+        const res = await mmseDelete(item.id)
+        if (res){
+          message.success(t('common.updateSuccess'))
+        }
+      }catch(err) {}
+    }
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    // 取消的二次确认
+    await message.cancelConfirm()
+    // 发起取消
+    // await elderlyBakDel(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if(route.query && route.query.elderName){
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 806 - 0
src/views/elderly/apply/nine-precautions/asphyxiation-by-choking/AddForm.vue

@@ -0,0 +1,806 @@
+<template>
+  <el-drawer
+    v-model="dialogVisible"
+    :title="title"
+    resizable
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :destroy-on-close="true"
+    size="85%"
+    :before-close="handleClosed"
+  >
+    <div class="asphyxiation-form">
+      <h1 class="form-title">防噎食评估表</h1>
+      <!-- 基本信息 -->
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>长者姓名</text>
+          <search-the-elderly ref="selectElderRef" :disabled="isDetail" @update_elder="elderUp"
+            v-model="dataForm.elderName" :tId="dataForm.tenantId" />
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>性别</text>
+          <el-input v-if="!isDetail" v-model="dataForm.elderSex" disabled />
+          <el-text v-else disabled="">{{ dataForm.elderSex }}</el-text>
+        </el-col>
+      </el-row>
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>年龄</text>
+          <el-input v-if="!isDetail" v-model="dataForm.elderAge" disabled />
+          <el-text v-else disabled="">{{ dataForm.elderAge }}</el-text>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>房号/床号</text>
+          <el-input v-if="!isDetail" v-model="dataForm.bedName" disabled />
+          <el-text v-else disabled="">{{ dataForm.bedName }}</el-text>
+        </el-col>
+      </el-row>
+
+      <!-- 吞咽功能评估表格 -->
+      <div class="assessment-section">
+        <div class="section-title">吞咽功能评估</div>
+        <div class="assessment-table">
+          <table>
+            <thead>
+              <tr>
+                <th class="level-col">分级</th>
+                <th class="judge-col">判断</th>
+                <th class="rating-col">功能评级</th>
+                <th class="score-col">得分</th>
+              </tr>
+            </thead>
+            <tbody>
+              <tr v-for="(item, index) in swallowLevels" :key="index">
+                <td class="level">{{ item.level }}</td>
+                <td class="judge">{{ item.judge }}</td>
+                <td class="rating">{{ item.rating }}</td>
+                <td class="score">
+                  <el-radio
+                    v-model="form.assessment.level" :value="item.score" :disabled="isDetail"
+                    @change="updateRiskLevel">
+                    {{ item.score }}
+                  </el-radio>
+                </td>
+              </tr>
+              <tr class="result-row">
+                <td colspan="3" class="result-label">结果分级</td>
+                <td class="result-content">
+                  I级(5秒内)为无风险;I级(5秒以上)为低风险,II级为中风险;III级、IV级、V级为高风险
+                </td>
+              </tr>
+            </tbody>
+          </table>
+        </div>
+      </div>
+
+      <!-- 评估记录 -->
+      <div class="assessment-records">
+        <div class="record-section">
+          <div class="record-header">评估记录</div>
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
+              <el-form-item label="评估日期">
+                <el-date-picker v-model="form.assessment.assessDate" type="date" :disabled="isDetail" style="width: 100%;" />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
+              <el-form-item label="评估人签名">
+                <el-input v-model="form.assessment.assessor" :disabled="isDetail" />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
+              <el-form-item label="评级结果">
+                <el-input v-model="form.assessment.level" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
+              <el-form-item label="风险程度">
+                <el-tag :type="getRiskTagType(form.assessment.level)">
+                  {{ getRiskText(form.assessment.level) }}
+                </el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="24">
+              <el-form-item label="建议饮食">
+                <el-checkbox-group v-model="form.assessment.dietSuggestions" :disabled="isDetail">
+                  <el-checkbox label="普食">普食</el-checkbox>
+                  <el-checkbox label="软食">软食</el-checkbox>
+                  <el-checkbox label="半流食">半流食</el-checkbox>
+                  <el-checkbox label="流食">流食</el-checkbox>
+                  <el-checkbox label="鼻饲">鼻饲</el-checkbox>
+                </el-checkbox-group>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="prevention-section">
+        <div class="section-title">预防措施:</div>
+        <el-checkbox-group v-model="form.preventionMeasures" :disabled="isDetail" class="prevention-group">
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-checkbox label="合理控制食物大小">合理控制食物大小</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-checkbox label="细嚼慢咽">细嚼慢咽</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-checkbox label="进食时避免说话、大笑">进食时避免说话、大笑</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-checkbox label="进食时少量喝汤便于顺利咽下食物">进食时少量喝汤便于顺利咽下食物</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-checkbox label="饭后漱口,避免食物滞留口中">饭后漱口,避免食物滞留口中</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-checkbox label="用餐时调整体位,端坐位或半坐卧位,卧床者摇高床头>60°">用餐时调整体位,端坐位或半坐卧位,卧床者摇高床头&gt;60°</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="常多练习张口闭口、伸缩舌头、微笑动作,以训练口腔及面部肌肉">常多练习张口闭口、伸缩舌头、微笑动作,以训练口腔及面部肌肉</el-checkbox>
+            </el-col>
+          </el-row>
+        </el-checkbox-group>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-asphyxiation/create 或 PUT /elderly-assess-asphyxiation/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="elderName">长者姓名</el-descriptions-item>
+          <el-descriptions-item label="elderSex">长者性别</el-descriptions-item>
+          <el-descriptions-item label="elderAge">长者年龄</el-descriptions-item>
+          <el-descriptions-item label="bedName">房号/床号</el-descriptions-item>
+          <el-descriptions-item label="assessData">
+            JSON字符串,包含:<br/>
+            - assessment: 评估记录 {assessDate, assessor, level, dietSuggestions[]}<br/>
+            - preventionMeasures: 预防措施选项数组<br/>
+            - riskLevel: 风险等级(none/low/medium/high)
+          </el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人()</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期(YYYY-MM-DD)</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="risk-rules">
+          <div class="rules-title">风险等级规则:</div>
+          <el-tag type="success" class="rule-tag">I级(5秒内):无风险</el-tag>
+          <el-tag type="info" class="rule-tag">I级(5秒以上):低风险</el-tag>
+          <el-tag type="warning" class="rule-tag">II级:中风险</el-tag>
+          <el-tag type="danger" class="rule-tag">III、IV、V级:高风险</el-tag>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
+        v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive } from 'vue'
+import dayjs from 'dayjs'
+import {
+  asphyxiationCreate,
+  asphyxiationGetById,
+  asphyxiationUpdate,
+  asphyxiationGetByElderId
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const title = ref('')
+const dialogVisible = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+const isDetail = ref(false)
+const formLoading = ref(false)
+
+let dataForm = ref({
+  id: undefined,
+  elderName: '',
+  elderSex: '',
+  elderAge: '',
+  bedName: '',
+  elderId: '',
+  tenantId: undefined
+})
+
+const elderUp = (e: any) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.elderAge = e.elderAge
+}
+
+// 吞咽功能评估等级定义
+const swallowLevels = [
+  { level: 'I', judge: '坐位,5秒之内能不呛的一次性饮下 30mL 温水', rating: '1 级(正常)', score: 1 },
+  { level: 'I', judge: '坐位,5秒以上能不呛的一次性饮下 30mL 温水', rating: '1 级(优)', score: 2 },
+  { level: 'II', judge: '分两次喝完无噎呛', rating: '2 级(良)', score: 3 },
+  { level: 'III', judge: '能一次喝完,但有噎呛', rating: '3 级(中)', score: 4 },
+  { level: 'IV', judge: '分两次以上喝完,且有噎呛', rating: '4 级(可)', score: 5 },
+  { level: 'V', judge: '常常噎呛,难以全部喝完', rating: '5 级(差)', score: 6 }
+]
+
+// 表单数据
+const form = reactive({
+  assessment: {
+    assessDate: '',
+    assessor: '',
+    level: '',
+    dietSuggestions: []
+  },
+  preventionMeasures: [],
+  riskLevel: ''
+})
+
+// 获取风险等级文本
+const getRiskText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 1: return '无风险'
+    case 2: return '低风险'
+    case 3: return '中度风险'
+    case 4: return '高风险'
+    case 5: return '高风险'
+    case 6: return '高风险'
+    default: return '-'
+  }
+}
+
+// 获取风险等级标签类型
+const getRiskTagType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 1: return 'success'
+    case 2: return 'info'
+    case 3: return 'warning'
+    case 4: return 'danger'
+    case 5: return 'danger'
+    case 6: return 'danger'
+    default: return ''
+  }
+}
+
+// 更新风险等级
+const updateRiskLevel = () => {
+  const level = form.assessment.level
+  if (!level) return
+
+  // 根据选中的等级判断风险程度
+  // I级(5秒内)为无风险;I级(5秒以上)为低风险,II级为中风险;III级、IV级、V级为高风险
+  const selectedLevel = swallowLevels.find(item => item.level === level)
+  if (selectedLevel) {
+    const score = selectedLevel.score
+    if (score === 1) {
+      form.riskLevel = 'none'
+    } else if (score === 2) {
+      form.riskLevel = 'low'
+    } else if (score === 3) {
+      form.riskLevel = 'medium'
+    } else {
+      form.riskLevel = 'high'
+    }
+  }
+}
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    assessment: {
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : '',
+      assessor: form.assessment.assessor || '',
+      level: form.assessment.level || '',
+      dietSuggestions: form.assessment.dietSuggestions || []
+    },
+    preventionMeasures: form.preventionMeasures || [],
+    riskLevel: form.riskLevel
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  if (formData.assessment) {
+    form.assessment.assessDate = formData.assessment.assessDate ? dayjs(formData.assessment.assessDate).toDate() : ''
+    form.assessment.assessor = formData.assessment.assessor || ''
+    form.assessment.level = formData.assessment.level || ''
+    form.assessment.dietSuggestions = formData.assessment.dietSuggestions || []
+  }
+  form.preventionMeasures = formData.preventionMeasures || []
+  form.riskLevel = formData.riskLevel || ''
+}
+
+/** 重置表单数据 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    elderName: '',
+    elderSex: '',
+    elderAge: '',
+    bedName: '',
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  form.assessment = {
+    assessDate: '',
+    assessor: '',
+    level: '',
+    dietSuggestions: []
+  }
+  form.preventionMeasures = []
+  form.riskLevel = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId: any, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-防噎食评估表"
+    await loadData(id)
+  } else {
+    title.value = "新增-防噎食评估表"
+  }
+}
+
+/** 加载评估数据 */
+const loadData = async (id: number) => {
+  try {
+    const res = await asphyxiationGetById(id)
+    if (res) {
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+defineExpose({ open })
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (formLoading.value) return
+  if (!dataForm.value.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  formLoading.value = true
+  try {
+    const assessData = serializeFormData()
+    const tempParams = {
+      ...dataForm.value,
+      assessData: JSON.stringify(assessData),
+      riskLevel: form.riskLevel,
+      assessor: form.assessment.assessor || '',
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      const res = await asphyxiationUpdate(tempParams)
+      if (res) {
+        message.success(t('common.updateSuccess'))
+        dialogVisible.value = false
+        emit('success')
+      }
+    } else {
+      const res = await asphyxiationCreate(tempParams)
+      if (res) {
+        message.success(t('common.createSuccess'))
+        dialogVisible.value = false
+        emit('success')
+      }
+    }
+  } finally {
+    setTimeout(() => {
+      formLoading.value = false
+    }, 500)
+  }
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+/** 导出打印 */
+const handleExport = () => {
+  const printWindow = window.open('', '_blank')
+  if (!printWindow) {
+    message.error('请允许弹出窗口')
+    return
+  }
+
+  const assessmentRows = swallowLevels.map((item, index) => {
+    const checked = form.assessment.level === item.level ? '☑' : '☐'
+    return `
+      <tr>
+        <td class="level">${item.level}</td>
+        <td class="judge">${item.judge}</td>
+        <td class="rating">${item.rating}</td>
+        <td class="score">${checked}</td>
+      </tr>
+    `
+  }).join('')
+
+  const dietOptions = ['普食', '软食', '半流食', '流食', '鼻饲']
+  const dietChecks = dietOptions.map(diet => {
+    const checked = form.assessment.dietSuggestions.includes(diet) ? '☑' : '☐'
+    return `${checked}${diet}`
+  }).join(' ')
+
+  const recordSection = `
+    <div class="record-section">
+      <div class="record-title">评估记录</div>
+      <div class="record-row">
+        <span class="record-label">评估日期:</span>
+        <span class="record-value">${form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : ''}</span>
+        <span class="record-label">评估人签名:</span>
+        <span class="record-value">${form.assessment.assessor || ''}</span>
+        <span class="record-label">评级结果:</span>
+        <span class="record-value">${form.assessment.level || ''}</span>
+        <span class="record-label">风险程度:</span>
+        <span class="record-value">${getRiskText(form.assessment.level)}</span>
+      </div>
+      <div class="record-row">
+        <span class="record-label">建议饮食:</span>
+        <span class="record-value">${dietChecks}</span>
+      </div>
+    </div>
+  `
+
+  const preventionOptions = [
+    '合理控制食物大小',
+    '细嚼慢咽',
+    '进食时避免说话、大笑',
+    '进食时少量喝汤便于顺利咽下食物',
+    '饭后漱口,避免食物滞留口中',
+    '用餐时调整体位,端坐位或半坐卧位,卧床者摇高床头>60°',
+    '常多练习张口闭口、伸缩舌头、微笑动作,以训练口腔及面部肌肉'
+  ]
+  const preventionChecks = preventionOptions.map(option => {
+    const checked = form.preventionMeasures.includes(option) ? '☑' : '☐'
+    return `<div class="prevention-item">${checked}${option}</div>`
+  }).join('')
+
+  const printContent = `
+    <!DOCTYPE html>
+    <html>
+    <head>
+      <meta charset="UTF-8">
+      <title>防噎食评估表 - ${dataForm.value.elderName || ''}</title>
+      <style>
+        @media print {
+          @page { size: A4 portrait; margin: 10mm; }
+        }
+        body {
+          font-family: 'SimSun', 'Microsoft YaHei', serif;
+          font-size: 10pt;
+          line-height: 1.4;
+          color: #333;
+        }
+        .header {
+          text-align: center;
+          margin-bottom: 15px;
+          border-bottom: 2px solid #333;
+          padding-bottom: 10px;
+        }
+        .title {
+          font-size: 18pt;
+          font-weight: bold;
+          margin-bottom: 10px;
+        }
+        .basic-info {
+          display: flex;
+          justify-content: space-between;
+          margin-bottom: 15px;
+          flex-wrap: wrap;
+        }
+        .info-item {
+          margin-right: 20px;
+          margin-bottom: 5px;
+        }
+        .info-label {
+          font-weight: bold;
+        }
+        .section-title {
+          font-size: 12pt;
+          font-weight: bold;
+          margin: 15px 0 10px 0;
+          border-left: 4px solid #333;
+          padding-left: 8px;
+        }
+        table {
+          width: 100%;
+          border-collapse: collapse;
+          margin-bottom: 15px;
+        }
+        th, td {
+          border: 1px solid #333;
+          padding: 8px;
+          text-align: center;
+        }
+        th {
+          background-color: #f5f5f5;
+          font-weight: bold;
+        }
+        .level-col { width: 8%; }
+        .judge-col { width: 35%; }
+        .rating-col { width: 20%; }
+        .score-col { width: 12%; }
+        .result-row td {
+          background-color: #f9f9f9;
+        }
+        .record-section {
+          margin-bottom: 15px;
+          padding: 10px;
+          border: 1px solid #ddd;
+        }
+        .record-title {
+          font-weight: bold;
+          margin-bottom: 8px;
+          border-bottom: 1px solid #eee;
+          padding-bottom: 5px;
+        }
+        .record-row {
+          margin-bottom: 5px;
+        }
+        .record-label {
+          font-weight: bold;
+        }
+        .prevention-section {
+          margin-top: 15px;
+        }
+        .prevention-item {
+          margin-bottom: 5px;
+        }
+      </style>
+    </head>
+    <body>
+      <div class="header">
+        <div class="title">防噎食评估表</div>
+      </div>
+      <div class="basic-info">
+        <div class="info-item"><span class="info-label">姓名:</span>${dataForm.value.elderName || ''}</div>
+        <div class="info-item"><span class="info-label">性别:</span>${dataForm.value.elderSex || ''}</div>
+        <div class="info-item"><span class="info-label">年龄:</span>${dataForm.value.elderAge || ''}</div>
+        <div class="info-item"><span class="info-label">房号/床号:</span>${dataForm.value.bedName || ''}</div>
+      </div>
+
+      <div class="section-title">吞咽功能评估</div>
+      <table>
+        <thead>
+          <tr>
+            <th class="level-col">分级</th>
+            <th class="judge-col">判断</th>
+            <th class="rating-col">功能评级</th>
+            <th class="score-col">得分</th>
+          </tr>
+        </thead>
+        <tbody>
+          ${assessmentRows}
+          <tr class="result-row">
+            <td colspan="3" style="font-weight:bold;">结果分级</td>
+            <td style="text-align:left;">
+              I级(5秒内)为无风险;I级(5秒以上)为低风险,II级为中风险;III级、IV级、V级为高风险
+            </td>
+          </tr>
+        </tbody>
+      </table>
+
+      <div class="section-title">评估记录</div>
+      ${recordSection}
+
+      <div class="section-title prevention-section">预防措施</div>
+      ${preventionChecks}
+    </body>
+    </html>
+  `
+
+  printWindow.document.write(printContent)
+  printWindow.document.close()
+  printWindow.focus()
+  setTimeout(() => {
+    printWindow.print()
+  }, 250)
+}
+</script>
+
+<style scoped lang="scss">
+.asphyxiation-form {
+  padding: 0 20px;
+
+  .form-title {
+    text-align: center;
+    font-size: 20px;
+    font-weight: bold;
+    margin-bottom: 20px;
+    color: #333;
+  }
+
+  .row {
+    display: flex;
+    align-items: center;
+    margin-bottom: 15px;
+
+    text {
+      width: 100px;
+      flex-shrink: 0;
+      color: #606266;
+    }
+
+    .el-input,
+    .el-text {
+      flex: 1;
+    }
+  }
+
+  .assessment-section {
+    margin-top: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      table {
+        width: 100%;
+        border-collapse: collapse;
+        border: 1px solid #dcdfe6;
+
+        th,
+        td {
+          border: 1px solid #dcdfe6;
+          padding: 10px;
+          text-align: center;
+        }
+
+        th {
+          background-color: #f5f7fa;
+          font-weight: bold;
+          color: #606266;
+        }
+
+        .level-col,
+        .score-col {
+          width: 10%;
+        }
+
+        .judge-col {
+          width: 40%;
+        }
+
+        .rating-col {
+          width: 20%;
+        }
+
+        .result-row {
+          td {
+            background-color: #f5f7fa;
+          }
+
+          .result-label {
+            font-weight: bold;
+          }
+
+          .result-content {
+            text-align: left;
+            font-size: 12px;
+          }
+        }
+      }
+    }
+  }
+
+  .assessment-records {
+    margin-top: 20px;
+
+    .record-section {
+      margin-bottom: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+
+      .record-header {
+        font-size: 14px;
+        font-weight: bold;
+        margin-bottom: 15px;
+        color: #409eff;
+        border-bottom: 1px solid #e4e7ed;
+        padding-bottom: 10px;
+      }
+    }
+  }
+
+  .prevention-section {
+    margin-top: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .prevention-group {
+      .el-checkbox {
+        margin-bottom: 10px;
+        margin-right: 20px;
+      }
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+
+    .risk-rules {
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #fff;
+      border-radius: 4px;
+
+      .rules-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #606266;
+      }
+
+      .rule-tag {
+        margin-right: 10px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+}
+</style>

+ 296 - 0
src/views/elderly/apply/nine-precautions/asphyxiation-by-choking/index.vue

@@ -0,0 +1,296 @@
+<template>
+  <ContentWrap>
+    <!-- 防噎食评估表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="riskLevel" header-align="center" align="center" label="风险等级" min-width="120" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getRiskLevelType(scope.row.riskLevel)">
+            {{ getRiskLevelText(scope.row.riskLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from "@/utils/dateUtil";
+import {
+  asphyxiationDelete,
+  asphyxiationPage
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const userStore = useUserStore()
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch, count)
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await asphyxiationPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate = getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if (queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1) {
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id, false)
+}
+
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, false)
+}
+
+const openFormDetail = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, true)
+}
+
+const openClose = async (item: any) => {
+  try {
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      try {
+        const res = await asphyxiationDelete(item.id)
+        if (res) {
+          message.success(t('common.updateSuccess'))
+          await getList()
+        }
+      } catch (err) { }
+    }
+  } catch { }
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    await message.cancelConfirm()
+    message.success(t('common.delSuccess'))
+    await getList()
+  } catch { }
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if (route.query && route.query.elderName) {
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// 获取风险等级类型
+const getRiskLevelType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+// 获取风险等级文本
+const getRiskLevelText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中度风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 1200 - 0
src/views/elderly/apply/nine-precautions/attack/AddForm.vue

@@ -0,0 +1,1200 @@
+<template>
+  <el-drawer
+    v-model="dialogVisible"
+    :title="title"
+    resizable
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :destroy-on-close="true"
+    size="70%"
+    :before-close="handleClosed"
+  >
+
+    <div class="attack-risk-form">
+      <h1 class="form-title">攻击风险因素评估量表</h1>
+      <!-- 基本信息 -->
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>长者姓名</text>
+          <search-the-elderly ref="selectElderRef" :disabled="isDetail" @update_elder="elderUp" v-model="dataForm.elderName" :tId="dataForm.tenantId"/>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>档案号</text>
+          <el-input v-if="!isDetail" v-model="dataForm.contractNumber" disabled />
+          <el-text v-else disabled="">{{dataForm.contractNumber}}</el-text>
+        </el-col>
+      </el-row>
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>入院日期</text>
+          <el-input v-if="!isDetail" :model-value="dayjs(dataForm.checkInTime).format('YYYY-MM-DD')=='Invalid Date'?'':dayjs(dataForm.checkInTime).format('YYYY-MM-DD')" disabled />
+          <el-text v-else disabled="">{{dayjs(dataForm.checkInTime).format('YYYY-MM-DD')}}</el-text>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>床位号</text>
+          <el-input v-if="!isDetail" v-model="dataForm.bedName" disabled />
+          <el-text v-else disabled="">{{dataForm.bedName}}</el-text>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>评估人</text>
+          <el-input :disabled="isDetail" v-model="form.assessor"  />
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>评估日期</text>
+          <el-date-picker :disabled="isDetail" v-model="form.assessDate" type="date" style="width: 100%;"/>
+
+        </el-col>
+      </el-row>
+
+      <!-- 表单内容区域 -->
+      <div class="form-body">
+
+
+        <!-- 评估表格 -->
+        <div class="assessment-table">
+          <table>
+            <thead>
+              <tr>
+                <th class="content-col">评估内容</th>
+                <th class="level-col">级别</th>
+                <th class="select-col">选择</th>
+              </tr>
+            </thead>
+            <tbody>
+              <!-- I级 -->
+              <tr>
+                <td class="content" rowspan="7">
+                  <div class="content-title">存在右之一者,若为男性则有两项:</div>
+                  <div class="content-item">(1) 男性</div>
+                  <div class="content-item">(2) 精神分裂症,伴有幻听或被害妄想</div>
+                  <div class="content-item">(3) 躁狂</div>
+                  <div class="content-item">(4) 酒药依赖的脱瘾期</div>
+                  <div class="content-item">(5) 意识障碍伴行为紊乱</div>
+                  <div class="content-item">(6) 痴呆伴行为紊乱</div>
+                  <div class="content-item">(7) 既往人格不良者(有冲动、边缘型人格障碍)</div>
+                </td>
+                <td class="level" rowspan="7">I级</td>
+                <td class="select" rowspan="7">
+                  <el-radio-group v-model="form.attackLevel" :disabled="isDetail">
+                    <el-radio :value="1">  符合</el-radio>
+                  </el-radio-group>
+                </td>
+              </tr>
+              <tr></tr><tr></tr><tr></tr><tr></tr><tr></tr><tr></tr>
+              
+              <!-- II级 -->
+              <tr>
+                <td class="content" rowspan="3">
+                  <div class="content-title">存在右侧情形之一者</div>
+                  <div class="content-item">(1) 被动的言语攻击行为,表现为激惹性增高,如无对象的抱怨、发牢骚、说怪话</div>
+                  <div class="content-item">(2) 交谈时态度不好、抵触、有敌意或不信任</div>
+                  <div class="content-item">(3) 或精神分裂症有命令性幻听者</div>
+                </td>
+                <td class="level" rowspan="3">II级</td>
+                <td class="select" rowspan="3">
+                  <el-radio-group v-model="form.attackLevel" :disabled="isDetail">
+                    <el-radio :value="2">  符合</el-radio>
+                  </el-radio-group>
+                </td>
+              </tr>
+              <tr></tr><tr></tr>
+              
+              <!-- III级 -->
+              <tr>
+                <td class="content" rowspan="4">
+                  <div class="content-title">存在右侧情形之一者</div>
+                  <div class="content-item">(1) 主动的言语攻击行为,如有对象的辱骂</div>
+                  <div class="content-item">(2) 被动的躯体攻击行为如毁物</div>
+                  <div class="content-item">(3) 在交往时出现社交粗暴(交谈时突然离去、躲避、推挡他人善意的躯体接触)</div>
+                  <div class="content-item">(4) 既往曾有过主动的躯体攻击行为</div>
+                </td>
+                <td class="level" rowspan="4">III级</td>
+                <td class="select" rowspan="4">
+                  <el-radio-group v-model="form.attackLevel" :disabled="isDetail">
+                    <el-radio :value="3">  符合</el-radio>
+                  </el-radio-group>
+                </td>
+              </tr>
+              <tr></tr><tr></tr><tr></tr>
+              
+              <!-- IV级 -->
+              <tr>
+                <td class="content" rowspan="2">
+                  <div class="content-title">存在右侧情形之一者</div>
+                  <div class="content-item">(1) 有主动的躯体攻击行为,如踢、打、咬或使用物</div>
+                  <div class="content-item">(2) 攻击行为在一天内至少出现两次以上或攻击行为造成了他人肉体上的伤害</div>
+                </td>
+                <td class="level" rowspan="2">IV级</td>
+                <td class="select" rowspan="2">
+                  <el-radio-group v-model="form.attackLevel" :disabled="isDetail">
+                    <el-radio :value="4">  符合</el-radio>
+                  </el-radio-group>
+                </td>
+              </tr>
+              <tr></tr>
+            </tbody>
+          </table>
+        </div>
+
+        <!-- 风险程度判断 -->
+        <div class="risk-judgment-section">
+          <div class="risk-judgment-title">风险程度判断:</div>
+          <div class="risk-options">
+            <el-radio v-model="form.riskLevel" value="none" :disabled="isDetail">
+                无风险:无级别
+            </el-radio>
+            <el-radio v-model="form.riskLevel" value="low" :disabled="isDetail">
+                低风险:I级
+            </el-radio>
+            <el-radio v-model="form.riskLevel" value="medium" :disabled="isDetail">
+                中风险:II级
+            </el-radio>
+            <el-radio v-model="form.riskLevel" value="high" :disabled="isDetail">
+                高风险:III级、IV级
+            </el-radio>
+          </div>
+        </div>
+
+        <!-- 预防措施 -->
+        <div class="preventive-section">
+          <div class="preventive-title">预防措施:</div>
+          <div class="preventive-options">
+            <el-checkbox v-model="form.preventiveMeasures" value="patrol" :disabled="isDetail">
+              加强巡视
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" value="handover" :disabled="isDetail">
+              严格交接班
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" value="checkItems" :disabled="isDetail">
+              检查有无危险物品
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" value="emotion" :disabled="isDetail">
+              注重长者情绪行为
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" value="other" :disabled="isDetail">
+              其他
+            </el-checkbox>
+            <el-input v-if="form.preventiveMeasures.includes('other')" v-model="form.preventiveMeasuresOther" placeholder="请输入其他措施" :disabled="isDetail" class="other-input"/>
+          </div>
+        </div>
+
+        <!-- 签名区域 -->
+        <div class="signature-section">
+          <div class="signature-row">
+            <div class="signature-item">
+              <span class="signature-label">家属/监护人签名:</span>
+              <el-input v-model="form.familySignature" :disabled="isDetail" class="signature-input"/>
+            </div>
+
+          </div>
+        </div>
+
+        <!-- 说明 -->
+        <div class="note-section">
+          <div class="note-title">说明:</div>
+          <div class="note-content">
+            <p>1. 新入住长者应在长者入住24小时内完成首次评估;</p>
+            <p>2. 定期评估:</p>
+            <p class="indent">(1)认知照护专区:高风险1个月评估一次,中风险、低风险3个月评估一次;</p>
+            <p class="indent">(2)非认知照护专区:高风险1个月评估一次,中风险3个月评估一次,低风险6个月评估一次;</p>
+            <p>3. 当长者身体发生变化者,应及时进行动态评估。</p>
+          </div>
+        </div>
+      </div>
+
+    </div>
+
+
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button  v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary" v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch } from 'vue'
+
+import dayjs from 'dayjs'
+
+import { attackRiskCreate, attackRiskGetById, attackRiskUpdate, attackRiskGetByElderId } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const selectElderRef = ref() // 表单 Ref
+const isDetail = ref(false) // 是否详情打开
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+let dataForm = ref({
+  // 表单字段
+  id: undefined,
+  idCard: '',
+  contractNumber: '', //档案号
+  elderName: '',//长者姓名
+  bedName: '', //床位号
+  elderAge: '', //年龄
+  elderSex: '', //性别
+  checkInTime: '', //入院日期
+  elderId: '',
+  tenantId: undefined
+})
+
+
+
+
+const elderUp = (e) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.checkInTime = e.checkInTime
+  dataForm.value.contractNumber = e.contractNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+/** 风险程度文本 */
+const riskLevelText = computed(() => {
+  const level = form.attackLevel
+  if (!level || level === 0) return '无风险'
+  if (level === 1) return 'I级'
+  if (level === 2) return 'II级'
+  if (level === 3) return 'III级'
+  return 'IV级'
+})
+
+/** 风险程度样式类 */
+const riskLevelClass = computed(() => {
+  const level = form.attackLevel
+  if (!level || level === 0) return 'risk-none'
+  if (level === 1) return 'risk-low'
+  if (level === 2) return 'risk-medium'
+  return 'risk-high'
+})
+
+/** 自动判断风险等级 */
+const autoJudgeRiskLevel = () => {
+  const level = form.attackLevel
+  if (!level || level === 0) form.riskLevel = 'none'
+  else if (level === 1) form.riskLevel = 'low'
+  else if (level === 2) form.riskLevel = 'medium'
+  else form.riskLevel = 'high'
+}
+
+
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    // 基本信息
+    assessor: form.assessor || '',
+    assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : '',
+
+    // 攻击风险等级(1=I级,2=II级,3=III级,4=IV级)
+    attackLevel: form.attackLevel || 0,
+
+    // 风险程度
+    riskLevel: form.riskLevel || '',
+
+    // 预防措施
+    preventiveMeasures: form.preventiveMeasures || [],
+    preventiveMeasuresOther: form.preventiveMeasuresOther || '',
+
+    // 签名
+    familySignature: form.familySignature || '',
+    familySignDate: form.familySignDate ? dayjs(form.familySignDate).format('YYYY-MM-DD') : ''
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  // 基本信息
+  form.assessor = formData.assessor || ''
+  form.assessDate = formData.assessDate ? dayjs(formData.assessDate).toDate() : ''
+
+  // 攻击风险等级
+  form.attackLevel = formData.attackLevel || 0
+
+  // 风险程度
+  form.riskLevel = formData.riskLevel || ''
+
+  // 预防措施
+  form.preventiveMeasures = formData.preventiveMeasures || []
+  form.preventiveMeasuresOther = formData.preventiveMeasuresOther || ''
+
+  // 签名
+  form.familySignature = formData.familySignature || ''
+  form.familySignDate = formData.familySignDate ? dayjs(formData.familySignDate).toDate() : ''
+}
+
+/** 重置攻击风险因素评估表表单数据 */
+const resetAttackRiskForm = () => {
+  form.assessor = ''
+  form.assessDate = ''
+
+  // 攻击风险等级
+  form.attackLevel = 0
+
+  // 风险程度
+  form.riskLevel = ''
+
+  // 预防措施
+  form.preventiveMeasures = []
+  form.preventiveMeasuresOther = ''
+
+  // 签名
+  form.familySignature = ''
+  form.familySignDate = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-攻击风险因素评估"
+    // 加载评估数据
+    await loadAttackRiskData(id)
+  } else {
+    title.value = "新增-攻击风险因素评估"
+    
+  }
+}
+
+/** 加载评估数据 */
+const loadAttackRiskData = async (id: number) => {
+  try {
+    const res = await attackRiskGetById(id)
+    if (res) {
+      // 填充长者基本信息
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.checkInTime = res.checkInTime || ''
+      dataForm.value.contractNumber = res.fileNumber || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      // 解析 assessData
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+/** 根据长者ID加载评估数据 */
+const loadAttackRiskByElderId = async (elderId: number) => {
+  try {
+    const res = await attackRiskGetByElderId(elderId)
+    if (res && res.assessData) {
+      const formData = JSON.parse(res.assessData)
+      deserializeFormData(formData)
+    }
+  } catch (error) {
+    // 无历史数据,不处理
+  }
+}
+
+const form = reactive({
+  // 基本信息
+  assessor: '',
+  assessDate: '',
+
+  // 攻击风险等级(0=无,1=I级,2=II级,3=III级,4=IV级)
+  attackLevel: 0,
+
+  // 风险程度
+  riskLevel: '',
+
+  // 预防措施
+  preventiveMeasures: [],
+  preventiveMeasuresOther: '',
+
+  // 签名
+  familySignature: '',
+  familySignDate: ''
+})
+
+// 监听攻击等级变化,自动判断风险等级
+watch(() => form.attackLevel, () => {
+  autoJudgeRiskLevel()
+})
+
+
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  if (formLoading.value) {
+    return
+  }
+  formLoading.value = true
+  // 提交请求
+  try {
+    const assessData = serializeFormData()
+    const tempParams = {
+      ...dataForm.value,
+      assessData: JSON.stringify(assessData),
+      attackLevel: form.attackLevel,
+      riskLevel: form.riskLevel,
+      assessor: form.assessor,
+      assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      const res = await attackRiskUpdate(tempParams)
+      if (res) {
+        message.success(t('common.updateSuccess'))
+        dialogVisible.value = false
+        // 发送操作成功的事件
+        emit('success')
+      }
+    } else {
+      const res = await attackRiskCreate(tempParams)
+      if (res) {
+        message.success(t('common.createSuccess'))
+        dialogVisible.value = false
+        // 发送操作成功的事件
+        emit('success')
+      }
+    }
+  } finally {
+    setTimeout(() => {
+      formLoading.value = false
+    }, 500)
+  }
+}
+
+
+
+/** 重置表单 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    idCard: '',
+    contractNumber: '', //档案号
+    elderName: '',//长者姓名
+    bedName: '', //床位号
+    elderAge: '', //年龄
+    elderSex: '', //性别
+    checkInTime: '', //入院日期
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  // 重置攻击风险因素评估表表单
+  resetAttackRiskForm()
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+/** 导出打印 */
+const handleExport = () => {
+  // 创建打印窗口
+  const printWindow = window.open('', '_blank')
+  if (!printWindow) {
+    message.error('请允许弹出窗口')
+    return
+  }
+
+  // 构建打印内容
+  const printContent = `
+    <!DOCTYPE html>
+    <html>
+    <head>
+      <meta charset="UTF-8">
+      <title>攻击风险因素评估量表 - ${dataForm.value.elderName || ''}</title>
+      <style>
+        @media print {
+          @page { size: A4 portrait; margin: 15mm; }
+        }
+        body {
+          font-family: 'SimSun', 'Microsoft YaHei', serif;
+          font-size: 10pt;
+          line-height: 1.4;
+          color: #333;
+        }
+        .header {
+          text-align: center;
+          margin-bottom: 15px;
+          border-bottom: 2px solid #333;
+          padding-bottom: 10px;
+        }
+        .header h1 {
+          font-size: 16pt;
+          margin: 0;
+          letter-spacing: 2px;
+        }
+        .info-section {
+          margin-bottom: 15px;
+          padding: 10px;
+          border: 1px solid #999;
+          background: #fafafa;
+        }
+        .info-row {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 20px;
+        }
+        .info-item {
+          display: flex;
+          align-items: center;
+        }
+        .info-item .label {
+          font-weight: bold;
+          margin-right: 8px;
+          color: #555;
+        }
+        .info-item .value {
+          border-bottom: 1px solid #333;
+          min-width: 80px;
+          padding: 0 5px;
+          text-align: center;
+        }
+        .score-summary {
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          padding: 10px 15px;
+          background: #f0f0f0;
+          border: 2px solid #333;
+          margin-bottom: 15px;
+        }
+        .total-score {
+          font-size: 14pt;
+          font-weight: bold;
+        }
+        .total-score .score-value {
+          color: #d9534f;
+          font-size: 18pt;
+        }
+
+        .assessment-table {
+          width: 100%;
+          border-collapse: collapse;
+          margin-bottom: 15px;
+        }
+        .assessment-table th, .assessment-table td {
+          border: 1px solid #333;
+          padding: 8px;
+          text-align: left;
+          vertical-align: top;
+        }
+        .assessment-table th {
+          background: #e8e8e8;
+          font-weight: bold;
+          text-align: center;
+        }
+        .assessment-table .content-col {
+          width: 65%;
+        }
+        .assessment-table .level-col {
+          width: 10%;
+          text-align: center;
+        }
+        .assessment-table .select-col {
+          width: 25%;
+          text-align: center;
+        }
+        .assessment-table .content-title {
+          font-weight: bold;
+          margin-bottom: 5px;
+        }
+        .assessment-table .content-item {
+          margin-left: 15px;
+          margin-bottom: 3px;
+        }
+
+        .risk-judgment-section {
+          margin: 15px 0;
+          padding: 10px;
+          border: 1px solid #999;
+        }
+        .risk-judgment-title {
+          font-weight: bold;
+          margin-bottom: 10px;
+        }
+        .risk-options {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 15px;
+        }
+
+        .measures-section {
+          margin: 15px 0;
+          border: 1px solid #999;
+        }
+        .measures-title {
+          font-weight: bold;
+          background: #e8e8e8;
+          padding: 8px 12px;
+          border-bottom: 1px solid #999;
+        }
+        .measures-content {
+          padding: 10px 12px;
+        }
+        .measure-item {
+          margin-bottom: 8px;
+          font-size: 10pt;
+        }
+        .measure-other {
+          margin-left: 10px;
+          border-bottom: 1px solid #333;
+          min-width: 200px;
+          display: inline-block;
+        }
+
+        .signature-section {
+          margin-top: 20px;
+          padding: 15px;
+          border: 1px solid #999;
+        }
+        .signature-row {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+        }
+        .signature-item {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+        }
+        .signature-label {
+          font-weight: bold;
+        }
+        .signature-value {
+          border-bottom: 1px solid #333;
+          min-width: 150px;
+          height: 25px;
+        }
+
+        .note-section {
+          margin-top: 15px;
+          padding: 10px;
+          border: 1px solid #999;
+          background: #fafafa;
+        }
+        .note-title {
+          font-weight: bold;
+          margin-bottom: 8px;
+        }
+        .note-content {
+          font-size: 9pt;
+          line-height: 1.6;
+        }
+        .note-content p {
+          margin: 3px 0;
+        }
+        .note-content .indent {
+          margin-left: 20px;
+        }
+      </style>
+    </head>
+    <body>
+      <div class="header">
+        <h1>攻击风险因素评估量表</h1>
+      </div>
+
+      <div class="info-section">
+        <div class="info-row">
+          <div class="info-item">
+            <span class="label">长者姓名:</span>
+            <span class="value">${dataForm.value.elderName || ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">档案号:</span>
+            <span class="value">${dataForm.value.contractNumber || ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">床位号:</span>
+            <span class="value">${dataForm.value.bedName || ''}</span>
+          </div>
+        </div>
+        <div class="info-row" style="margin-top: 10px;">
+          <div class="info-item">
+            <span class="label">评估日期:</span>
+            <span class="value">${form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">评估人:</span>
+            <span class="value">${form.assessor || ''}</span>
+          </div>
+        </div>
+      </div>
+
+
+
+      <!-- 评估表格 -->
+      <table class="assessment-table">
+        <thead>
+          <tr>
+            <th class="content-col">评估内容</th>
+            <th class="level-col">级别</th>
+            <th class="select-col">选择</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td class="content">
+              <div class="content-title">存在右之一者,若为男性则有两项:</div>
+              <div class="content-item">(1) 男性</div>
+              <div class="content-item">(2) 精神分裂症,伴有幻听或被害妄想</div>
+              <div class="content-item">(3) 躁狂</div>
+              <div class="content-item">(4) 酒药依赖的脱瘾期</div>
+              <div class="content-item">(5) 意识障碍伴行为紊乱</div>
+              <div class="content-item">(6) 痴呆伴行为紊乱</div>
+              <div class="content-item">(7) 既往人格不良者(有冲动、边缘型人格障碍)</div>
+            </td>
+            <td class="level">I级</td>
+            <td class="select">${form.attackLevel === 1 ? '☑' : '☐'} 符合</td>
+          </tr>
+          <tr>
+            <td class="content">
+              <div class="content-title">存在右侧情形之一者</div>
+              <div class="content-item">(1) 被动的言语攻击行为,表现为激惹性增高,如无对象的抱怨、发牢骚、说怪话</div>
+              <div class="content-item">(2) 交谈时态度不好、抵触、有敌意或不信任</div>
+              <div class="content-item">(3) 或精神分裂症有命令性幻听者</div>
+            </td>
+            <td class="level">II级</td>
+            <td class="select">${form.attackLevel === 2 ? '☑' : '☐'} 符合</td>
+          </tr>
+          <tr>
+            <td class="content">
+              <div class="content-title">存在右侧情形之一者</div>
+              <div class="content-item">(1) 主动的言语攻击行为,如有对象的辱骂</div>
+              <div class="content-item">(2) 被动的躯体攻击行为如毁物</div>
+              <div class="content-item">(3) 在交往时出现社交粗暴(交谈时突然离去、躲避、推挡他人善意的躯体接触)</div>
+              <div class="content-item">(4) 既往曾有过主动的躯体攻击行为</div>
+            </td>
+            <td class="level">III级</td>
+            <td class="select">${form.attackLevel === 3 ? '☑' : '☐'} 符合</td>
+          </tr>
+          <tr>
+            <td class="content">
+              <div class="content-title">存在右侧情形之一者</div>
+              <div class="content-item">(1) 有主动的躯体攻击行为,如踢、打、咬或使用物</div>
+              <div class="content-item">(2) 攻击行为在一天内至少出现两次以上或攻击行为造成了他人肉体上的伤害</div>
+            </td>
+            <td class="level">IV级</td>
+            <td class="select">${form.attackLevel === 4 ? '☑' : '☐'} 符合</td>
+          </tr>
+        </tbody>
+      </table>
+
+      <!-- 风险程度判断 -->
+      <div class="risk-judgment-section">
+        <div class="risk-judgment-title">风险程度判断:</div>
+        <div class="risk-options">
+          <span class="risk-option">${form.riskLevel === 'none' ? '☑' : '☐'} 无风险:无级别</span>
+          <span class="risk-option">${form.riskLevel === 'low' ? '☑' : '☐'} 低风险:I级</span>
+          <span class="risk-option">${form.riskLevel === 'medium' ? '☑' : '☐'} 中风险:II级</span>
+          <span class="risk-option">${form.riskLevel === 'high' ? '☑' : '☐'} 高风险:III级、IV级</span>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="measures-section">
+        <div class="measures-title">预防措施</div>
+        <div class="measures-content">
+          <div class="measure-item">${form.preventiveMeasures?.includes('patrol') ? '☑' : '☐'} 加强巡视</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('handover') ? '☑' : '☐'} 严格交接班</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('checkItems') ? '☑' : '☐'} 检查有无危险物品</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('emotion') ? '☑' : '☐'} 注重长者情绪行为</div>
+          <div class="measure-item">
+            ${form.preventiveMeasures?.includes('other') ? '☑' : '☐'} 其他
+            ${form.preventiveMeasures?.includes('other') ? '<span class="measure-other">' + (form.preventiveMeasuresOther || '') + '</span>' : ''}
+          </div>
+        </div>
+      </div>
+
+      <!-- 签名区域 -->
+      <div class="signature-section">
+        <div class="signature-row">
+          <div class="signature-item">
+            <span class="signature-label">家属/监护人签名:</span>
+            <span class="signature-value">${form.familySignature || ''}</span>
+          </div>
+
+        </div>
+      </div>
+
+      <!-- 说明 -->
+      <div class="note-section">
+        <div class="note-title">说明:</div>
+        <div class="note-content">
+          <p>1. 新入住长者应在长者入住24小时内完成首次评估;</p>
+          <p>2. 定期评估:</p>
+          <p class="indent">(1)认知照护专区:高风险1个月评估一次,中风险、低风险3个月评估一次;</p>
+          <p class="indent">(2)非认知照护专区:高风险1个月评估一次,中风险3个月评估一次,低风险6个月评估一次;</p>
+          <p>3. 当长者身体发生变化者,应及时进行动态评估。</p>
+        </div>
+      </div>
+    </body>
+    </html>
+  `
+
+  // 写入内容并打印
+  printWindow.document.write(printContent)
+  printWindow.document.close()
+
+  // 延迟打印,确保样式加载完成
+  setTimeout(() => {
+    printWindow.print()
+  }, 500)
+}
+
+</script>
+
+<style scoped lang="scss">
+
+.form-title {
+  text-align: center;
+  font-size: 20px;
+  width: 100%;
+  margin-bottom: 20px;
+}
+
+.attack-risk-form {
+  max-width: 1200px;
+  margin: 0 auto;
+  background: #fff;
+
+
+
+
+
+  .info-row {
+    display: flex;
+    gap: 40px;
+    width: 100%;
+    flex-direction: row;
+    align-items: center;
+    margin-bottom: 10px;
+
+    .info-item {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .label {
+        width: 82px;
+        text-align: right;
+        margin-right: 4px;
+        white-space: nowrap;
+      }
+    }
+  }
+
+
+  .form-body {
+    border: 1px solid #333;
+    padding: 15px;
+  }
+
+  // 调整 Element Plus 组件样式
+  :deep(.el-input__inner) {
+    height: 28px;
+    line-height: 28px;
+    border-top: none;
+    border-left: none;
+    border-right: none;
+    border-radius: 0;
+    padding: 0 4px;
+
+    &:focus {
+      border-color: #409eff;
+    }
+  }
+
+  :deep(.el-checkbox__label),
+  :deep(.el-radio__label) {
+    padding-left: 4px;
+  }
+}
+.row{
+  margin-bottom: 12px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  text{
+    text-align: right;
+    margin-right: 4px;
+    width: 82px;
+  }
+}
+
+// NGASR自杀风险评估量表 特有样式
+.total-score-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  margin-bottom: 20px;
+
+  .total-score {
+    display: flex;
+    align-items: baseline;
+    gap: 4px;
+
+    .score-label {
+      font-size: 16px;
+      font-weight: bold;
+    }
+
+    .score-value {
+      font-size: 28px;
+      font-weight: bold;
+      color: #409eff;
+    }
+
+    .score-max {
+      font-size: 14px;
+      color: #909399;
+    }
+  }
+
+  .risk-level {
+    font-size: 16px;
+    font-weight: bold;
+    padding: 8px 16px;
+    border-radius: 4px;
+
+    &.risk-none {
+      color: #67c23a;
+      background: #f0f9eb;
+    }
+
+    &.risk-low {
+      color: #e6a23c;
+      background: #fdf6ec;
+    }
+
+    &.risk-medium {
+      color: #f56c6c;
+      background: #fef0f0;
+    }
+
+    &.risk-high {
+      color: #f56c6c;
+      background: #fef0f0;
+      border: 1px solid #f56c6c;
+    }
+  }
+}
+
+.assessment-table {
+  width: 100%;
+  border-collapse: collapse;
+  margin-bottom: 20px;
+
+  table {
+    width: 100%;
+    border: 1px solid #333;
+
+    th, td {
+      border: 1px solid #333;
+      padding: 12px;
+      text-align: left;
+      vertical-align: top;
+    }
+
+    th {
+      background: #f5f7fa;
+      font-weight: bold;
+      text-align: center;
+    }
+
+    .content-col {
+      width: 65%;
+    }
+
+    .level-col {
+      width: 10%;
+      text-align: center;
+    }
+
+    .select-col {
+      width: 25%;
+      text-align: center;
+    }
+
+    .content {
+      text-align: left;
+
+      .content-title {
+        font-weight: bold;
+        margin-bottom: 8px;
+      }
+
+      .content-item {
+        margin-left: 15px;
+        margin-bottom: 4px;
+        font-size: 13px;
+      }
+    }
+
+    .level {
+      text-align: center;
+      font-weight: bold;
+    }
+
+    .select {
+      text-align: center;
+
+      :deep(.el-radio) {
+        margin-right: 0;
+      }
+    }
+  }
+}
+
+.risk-judgment-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .risk-judgment-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .risk-options {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+
+    :deep(.el-radio) {
+      margin-right: 0;
+    }
+  }
+}
+
+.preventive-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .preventive-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .preventive-options {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+
+    :deep(.el-checkbox) {
+      margin-right: 20px;
+      margin-bottom: 8px;
+    }
+
+    .other-input {
+      width: 200px;
+      margin-left: 10px;
+    }
+  }
+}
+
+.signature-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .signature-row {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    gap: 20px;
+  }
+
+  .signature-item {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+
+    &.date-item {
+      :deep(.el-date-picker) {
+        width: 150px;
+      }
+    }
+  }
+
+  .signature-label {
+    font-weight: bold;
+    white-space: nowrap;
+  }
+
+  .signature-input {
+    width: 150px;
+  }
+
+  .date-picker {
+    width: 150px;
+  }
+}
+
+.note-section {
+  margin-top: 20px;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .note-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .note-content {
+    font-size: 13px;
+    line-height: 1.8;
+    color: #606266;
+
+    p {
+      margin: 5px 0;
+    }
+
+    .indent {
+      margin-left: 20px;
+    }
+  }
+}
+</style>

+ 339 - 0
src/views/elderly/apply/nine-precautions/attack/index.vue

@@ -0,0 +1,339 @@
+<template>
+  <ContentWrap>
+    <!-- 保护性约束观察记录表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+
+      <ButtonAdd @click="openForm(undefined)"  />
+      <!--      <el-button @click="inputH" type="success"><Icon icon="fa:cloud-upload" :size="16" class="mr-1"/>导入</el-button>-->
+      <!--      <ButtonImport @click="handleImportCard"  />-->
+
+
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="200" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="200" show-overflow-tooltip/>
+
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="200" show-overflow-tooltip/>
+
+
+      <el-table-column label="操作" align="center" width="200" >
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+
+
+  <Import
+    ref="importRef"
+    @success="getList"
+    :config="{
+      title: '导入',
+      downloadUrl: 'elderly-service-order/get-import-template',
+      excelTempName: '居家工单-【导入】模板',
+      importUrl: '/elderly-service-order/import',
+      failExportUrl: '',
+    }"
+  />
+
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import ButtonImport from "@/components/ButtonImport/src/ButtonImport.vue";
+import { useUserStore } from '@/store/modules/user'
+import {formatTimestamp, getCurrentMonthRange} from "@/utils/dateUtil";
+import Import from "@/components/ImportFile/index.vue";
+import {restraintCreatePage, restraintDelete} from "@/api/elderly/nursing/keep-fit";
+import {
+  attackRiskDelete, attackRiskPage,
+  ngasrDelete,
+  ngasrPage,
+  perceptionDelete,
+  perceptionPage
+} from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const userStore = useUserStore()
+const loading = ref(true) // 列表的加载中
+const detailRef = ref()
+const importRef = ref()
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref() // 搜索的表单
+
+
+// 打开导出弹窗
+const handleImportCard = async () => {
+
+  // showBatchExport.value = true
+}
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch,count)
+  // try {
+  //   let queryParams = {
+  //     pageNo: batch,
+  //     pageSize: count,
+  //     tenantId: userStore.orgTenantId[0]
+  //   }
+  //   const list = await careRecordsPage(queryParams)
+  //   if (list.length <= 0) {
+  //     message.error('暂无数据可以导出!')
+  //     return
+  //   }
+  //   const headers = [
+  //     { key: 'organizationName', title: '机构名称' },
+  //     { key: 'visitName', title: '姓名' },
+  //     { key: 'visitPhone', title: '手机号' },
+  //     { key: 'visitDate', title: '预约时间' },
+  //     { key: 'accompanyCount', title: '陪同人数' },
+  //     { key: 'reason', title: '理由' }
+  //   ]
+  //   exportWithExpandedObjectArrays(list, headers, `医疗护理记录${formatToDateTime()}.xlsx`, '医疗护理记录')
+  // } catch (_) {}
+
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    //let queryP = {...queryParams,discoveryTime:queryParams.discoveryTime?[queryParams.discoveryTime[0]+" 00:00:00",queryParams.discoveryTime[1]+" 23:59:59"]:null}
+    const data = await attackRiskPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate= getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if(queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1){
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id,false)
+}
+
+const editRef = ref()
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id,false)
+}
+
+
+const openFormDetail = (row: any = {},id?: number) => {
+  formRef.value.open(row.tenantId,id,true)
+}
+
+
+
+
+
+const openClose = async (item) => {
+  try {
+    console.log("任务ID",item)
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      // 发起
+      try {
+        const res = await attackRiskDelete(item.id)
+        if (res){
+          message.success(t('common.updateSuccess'))
+        }
+      }catch(err) {}
+    }
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    // 取消的二次确认
+    await message.cancelConfirm()
+    // 发起取消
+    // await elderlyBakDel(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if(route.query && route.query.elderName){
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 1166 - 0
src/views/elderly/apply/nine-precautions/commit-suicide/AddForm.vue

@@ -0,0 +1,1166 @@
+<template>
+  <el-drawer
+    v-model="dialogVisible"
+    :title="title"
+    resizable
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :destroy-on-close="true"
+    size="70%"
+    :before-close="handleClosed"
+  >
+
+    <div class="ngasr-form">
+      <h1 class="form-title">自杀风险评估量表</h1>
+      <!-- 基本信息 -->
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>长者姓名</text>
+          <search-the-elderly ref="selectElderRef" :disabled="isDetail" @update_elder="elderUp" v-model="dataForm.elderName" :tId="dataForm.tenantId"/>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>档案号</text>
+          <el-input v-if="!isDetail" v-model="dataForm.contractNumber" disabled />
+          <el-text v-else disabled="">{{dataForm.contractNumber}}</el-text>
+        </el-col>
+      </el-row>
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>入院日期</text>
+          <el-input v-if="!isDetail" :model-value="dayjs(dataForm.checkInTime).format('YYYY-MM-DD')=='Invalid Date'?'':dayjs(dataForm.checkInTime).format('YYYY-MM-DD')" disabled />
+          <el-text v-else disabled="">{{dayjs(dataForm.checkInTime).format('YYYY-MM-DD')}}</el-text>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>床位号</text>
+          <el-input v-if="!isDetail" v-model="dataForm.bedName" disabled />
+          <el-text v-else disabled="">{{dataForm.bedName}}</el-text>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>评估人</text>
+          <el-input :disabled="isDetail" v-model="form.assessor"  />
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>评估日期</text>
+          <el-date-picker :disabled="isDetail" v-model="form.assessDate" type="date" style="width: 100%;"/>
+
+        </el-col>
+      </el-row>
+
+      <!-- 表单内容区域 -->
+      <div class="form-body">
+        <!-- 总分显示 -->
+        <div class="total-score-section">
+          <div class="total-score">
+            <span class="score-label">评估总得分:</span>
+            <span class="score-value">{{ totalScore }}</span>
+            <span class="score-max">分</span>
+          </div>
+        </div>
+
+        <!-- 评估表格 -->
+        <div class="assessment-table">
+          <table>
+            <thead>
+              <tr>
+                <th class="risk-factor-col">危险因素</th>
+                <th class="score-yes-col">是</th>
+                <th class="score-no-col">否</th>
+                <th class="select-col">选择</th>
+              </tr>
+            </thead>
+            <tbody>
+              <tr v-for="(item, index) in riskFactors" :key="index">
+                <td class="risk-factor">{{ item.name }}</td>
+                <td class="score-yes">{{ item.yesScore }}分</td>
+                <td class="score-no">0分</td>
+                <td class="select">
+                  <el-radio-group v-model="form.riskScores[index]" :disabled="isDetail">
+                    <el-radio :value="item.yesScore" style="margin-right: 26px"> 是</el-radio>
+                    <el-radio :value="0">  否</el-radio>
+                  </el-radio-group>
+                </td>
+              </tr>
+            </tbody>
+          </table>
+        </div>
+
+        <!-- 风险程度判断 -->
+        <div class="risk-judgment-section">
+          <div class="risk-judgment-title">风险程度判断:</div>
+          <div class="risk-options">
+            <el-radio v-model="form.riskLevel" value="none" :disabled="isDetail">
+                无风险:0分
+            </el-radio>
+            <el-radio v-model="form.riskLevel" value="low" :disabled="isDetail">
+                低风险:1-5分
+            </el-radio>
+            <el-radio v-model="form.riskLevel" value="medium" :disabled="isDetail">
+                中风险:6-8分
+            </el-radio>
+            <el-radio v-model="form.riskLevel" value="high" :disabled="isDetail">
+                高风险:≥9分
+            </el-radio>
+          </div>
+        </div>
+
+        <!-- 预防措施 -->
+        <div class="preventive-section">
+          <div class="preventive-title">预防措施:</div>
+          <div class="preventive-options">
+            <el-checkbox v-model="form.preventiveMeasures" value="patrol" :disabled="isDetail">
+                加强巡视
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" value="handover" :disabled="isDetail">
+                严格交接班
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" value="checkItems" :disabled="isDetail">
+                检查有无危险物品
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" value="emotion" :disabled="isDetail">
+                注重长者情绪行为
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" value="other" :disabled="isDetail">
+                其他
+            </el-checkbox>
+            <el-input v-if="form.preventiveMeasures.includes('other')" v-model="form.preventiveMeasuresOther" placeholder="请输入其他措施" :disabled="isDetail" class="other-input"/>
+          </div>
+        </div>
+
+        <!-- 签名区域 -->
+        <div class="signature-section">
+          <div class="signature-row">
+            <div class="signature-item">
+              <span class="signature-label">家属/监护人签名:</span>
+              <el-input v-model="form.familySignature" :disabled="isDetail" class="signature-input"/>
+            </div>
+
+          </div>
+        </div>
+
+        <!-- 说明 -->
+        <div class="note-section">
+          <div class="note-title">说明:</div>
+          <div class="note-content">
+            <p>1. 新入住长者应在长者入住24小时内完成首次评估;</p>
+            <p>2. 定期评估:</p>
+            <p class="indent">(1)认知照护专区:高风险1个月评估一次,中风险、低风险3个月评估一次;</p>
+            <p class="indent">(2)非认知照护专区:高风险1个月评估一次,中风险3个月评估一次,低风险6个月评估一次;</p>
+            <p>3. 当长者身体发生变化者,应及时进行动态评估。</p>
+          </div>
+        </div>
+      </div>
+    </div>
+
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary" v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch } from 'vue'
+
+import dayjs from 'dayjs'
+
+import { ngasrCreate, ngasrGetById, ngasrUpdate, ngasrGetByElderId } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const selectElderRef = ref() // 表单 Ref
+const isDetail = ref(false) // 是否详情打开
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+let dataForm = ref({
+  // 表单字段
+  id: undefined,
+  idCard: '',
+  contractNumber: '', //档案号
+  elderName: '',//长者姓名
+  bedName: '', //床位号
+  elderAge: '', //年龄
+  elderSex: '', //性别
+  checkInTime: '', //入院日期
+  elderId: '',
+  tenantId: undefined
+})
+
+
+
+
+const elderUp = (e) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.checkInTime = e.checkInTime
+  dataForm.value.contractNumber = e.contractNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== NGASR自杀风险评估量表 表单序列化方法 ==========
+
+// 危险因素列表
+const riskFactors = [
+  { name: '绝望感', yesScore: 3 },
+  { name: '近期负性生活事件', yesScore: 1 },
+  { name: '被害妄想或有被害内容的幻听', yesScore: 1 },
+  { name: '情绪低落/兴趣丧失或愉快感缺乏', yesScore: 3 },
+  { name: '人际和社会功能退缩', yesScore: 1 },
+  { name: '言语流露自杀意图', yesScore: 1 },
+  { name: '计划采取自杀行动', yesScore: 3 },
+  { name: '自杀家族史', yesScore: 1 },
+  { name: '近亲人死亡或重要的亲密关系丧失', yesScore: 3 },
+  { name: '精神病史', yesScore: 1 },
+  { name: '鳏夫/寡妇', yesScore: 1 },
+  { name: '自杀未遂史', yesScore: 3 },
+  { name: '社会-经济地位低下', yesScore: 1 },
+  { name: '饮酒史或酒精滥用', yesScore: 1 },
+  { name: '罹患晚期疾病', yesScore: 1 }
+]
+
+
+
+/** 风险程度文本 */
+const riskLevelText = computed(() => {
+  const score = totalScore.value
+  if (score === 0) return '无风险'
+  if (score >= 1 && score <= 5) return '低风险'
+  if (score >= 6 && score <= 8) return '中风险'
+  return '高风险'
+})
+
+/** 风险程度样式类 */
+const riskLevelClass = computed(() => {
+  const score = totalScore.value
+  if (score === 0) return 'risk-none'
+  if (score >= 1 && score <= 5) return 'risk-low'
+  if (score >= 6 && score <= 8) return 'risk-medium'
+  return 'risk-high'
+})
+
+/** 自动判断风险等级 */
+const autoJudgeRiskLevel = () => {
+  const score = totalScore.value
+  if (score === 0) form.riskLevel = 'none'
+  else if (score >= 1 && score <= 5) form.riskLevel = 'low'
+  else if (score >= 6 && score <= 8) form.riskLevel = 'medium'
+  else form.riskLevel = 'high'
+}
+
+
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    // 基本信息
+    assessor: form.assessor || '',
+    assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : '',
+
+    // 各危险因素得分
+    riskScores: form.riskScores || [],
+
+    // 总分
+    totalScore: totalScore.value,
+
+    // 风险程度
+    riskLevel: form.riskLevel || '',
+
+    // 预防措施
+    preventiveMeasures: form.preventiveMeasures || [],
+    preventiveMeasuresOther: form.preventiveMeasuresOther || '',
+
+    // 签名
+    familySignature: form.familySignature || '',
+    familySignDate: form.familySignDate ? dayjs(form.familySignDate).format('YYYY-MM-DD') : ''
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  // 基本信息
+  form.assessor = formData.assessor || ''
+  form.assessDate = formData.assessDate ? dayjs(formData.assessDate).toDate() : ''
+
+  // 各危险因素得分
+  form.riskScores = formData.riskScores || new Array(15).fill(0)
+
+  // 风险程度
+  form.riskLevel = formData.riskLevel || ''
+
+  // 预防措施
+  form.preventiveMeasures = formData.preventiveMeasures || []
+  form.preventiveMeasuresOther = formData.preventiveMeasuresOther || ''
+
+  // 签名
+  form.familySignature = formData.familySignature || ''
+  form.familySignDate = formData.familySignDate ? dayjs(formData.familySignDate).toDate() : ''
+}
+
+/** 重置NGASR评估表表单数据 */
+const resetNGASRForm = () => {
+  form.assessor = ''
+  form.assessDate = ''
+
+  // 各危险因素得分(15个因素,初始为0)
+  form.riskScores = new Array(15).fill(0)
+
+  // 风险程度
+  form.riskLevel = ''
+
+  // 预防措施
+  form.preventiveMeasures = []
+  form.preventiveMeasuresOther = ''
+
+  // 签名
+  form.familySignature = ''
+  form.familySignDate = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-自杀风险评估"
+    // 加载评估数据
+    await loadNGASRData(id)
+  } else {
+    title.value = "新增-自杀风险评估"
+
+  }
+}
+
+/** 加载评估数据 */
+const loadNGASRData = async (id: number) => {
+  try {
+    const res = await ngasrGetById(id)
+    if (res) {
+      // 填充长者基本信息
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.checkInTime = res.checkInTime || ''
+      dataForm.value.contractNumber = res.fileNumber || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      // 解析 assessData
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+/** 根据长者ID加载评估数据 */
+const loadNGASRByElderId = async (elderId: number) => {
+  try {
+    const res = await ngasrGetByElderId(elderId)
+    if (res && res.assessData) {
+      const formData = JSON.parse(res.assessData)
+      deserializeFormData(formData)
+    }
+  } catch (error) {
+    // 无历史数据,不处理
+  }
+}
+
+const form = reactive({
+  // 基本信息
+  assessor: '',
+  assessDate: '',
+
+  // 各危险因素得分(15个因素)
+  riskScores: new Array(15).fill(0),
+
+  // 风险程度
+  riskLevel: '',
+
+  // 预防措施
+  preventiveMeasures: [],
+  preventiveMeasuresOther: '',
+
+  // 签名
+  familySignature: '',
+  familySignDate: ''
+})
+
+/** 计算总分 */
+const totalScore = computed(() => {
+  if (!form.riskScores || form.riskScores.length === 0) return 0
+  return form.riskScores.reduce((sum, score) => sum + (score || 0), 0)
+})
+
+// 监听总分变化,自动判断风险等级
+watch(totalScore, () => {
+  autoJudgeRiskLevel()
+})
+
+
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  if (formLoading.value) {
+    return
+  }
+  formLoading.value = true
+  // 提交请求
+  try {
+    const assessData = serializeFormData()
+    const tempParams = {
+      ...dataForm.value,
+      assessData: JSON.stringify(assessData),
+      totalScore: totalScore.value,
+      assessor: form.assessor,
+      assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      const res = await ngasrUpdate(tempParams)
+      if (res) {
+        message.success(t('common.updateSuccess'))
+        dialogVisible.value = false
+        // 发送操作成功的事件
+        emit('success')
+      }
+    } else {
+      const res = await ngasrCreate(tempParams)
+      if (res) {
+        message.success(t('common.createSuccess'))
+        dialogVisible.value = false
+        // 发送操作成功的事件
+        emit('success')
+      }
+    }
+  } finally {
+    setTimeout(() => {
+      formLoading.value = false
+    }, 500)
+  }
+}
+
+
+
+/** 重置表单 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    idCard: '',
+    contractNumber: '', //档案号
+    elderName: '',//长者姓名
+    bedName: '', //床位号
+    elderAge: '', //年龄
+    elderSex: '', //性别
+    checkInTime: '', //入院日期
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  // 重置NGASR评估表表单
+  resetNGASRForm()
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+/** 导出打印 */
+const handleExport = () => {
+  // 创建打印窗口
+  const printWindow = window.open('', '_blank')
+  if (!printWindow) {
+    message.error('请允许弹出窗口')
+    return
+  }
+
+  // 构建危险因素表格行
+  const riskFactorRows = riskFactors.map((item, index) => {
+    const score = form.riskScores[index] || 0
+    return `
+      <tr>
+        <td class="risk-factor">${item.name}</td>
+        <td class="score-yes">${item.yesScore}分</td>
+        <td class="score-no">0分</td>
+        <td class="select">${score === item.yesScore ? '☑ 是' : '☐ 是'} / ${score === 0 ? '☑ 否' : '☐ 否'}</td>
+      </tr>
+    `
+  }).join('')
+
+  // 构建打印内容
+  const printContent = `
+    <!DOCTYPE html>
+    <html>
+    <head>
+      <meta charset="UTF-8">
+      <title>自杀风险评估量表(NGASR) - ${dataForm.value.elderName || ''}</title>
+      <style>
+        @media print {
+          @page { size: A4 portrait; margin: 15mm; }
+        }
+        body {
+          font-family: 'SimSun', 'Microsoft YaHei', serif;
+          font-size: 11pt;
+          line-height: 1.5;
+          color: #333;
+        }
+        .header {
+          text-align: center;
+          margin-bottom: 20px;
+          border-bottom: 2px solid #333;
+          padding-bottom: 10px;
+        }
+        .header h1 {
+          font-size: 18pt;
+          margin: 0;
+          letter-spacing: 2px;
+        }
+        .info-section {
+          margin-bottom: 15px;
+          padding: 10px;
+          border: 1px solid #999;
+          background: #fafafa;
+        }
+        .info-row {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 20px;
+        }
+        .info-item {
+          display: flex;
+          align-items: center;
+        }
+        .info-item .label {
+          font-weight: bold;
+          margin-right: 8px;
+          color: #555;
+        }
+        .info-item .value {
+          border-bottom: 1px solid #333;
+          min-width: 80px;
+          padding: 0 5px;
+          text-align: center;
+        }
+        .score-summary {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          padding: 10px 15px;
+          background: #f0f0f0;
+          border: 2px solid #333;
+          margin-bottom: 15px;
+        }
+        .total-score {
+          font-size: 14pt;
+          font-weight: bold;
+        }
+        .total-score .score-value {
+          color: #d9534f;
+          font-size: 18pt;
+        }
+        .risk-level {
+          font-size: 12pt;
+          font-weight: bold;
+          padding: 5px 15px;
+        }
+        .risk-none { color: #5cb85c; }
+        .risk-low { color: #f0ad4e; }
+        .risk-medium { color: #d9534f; }
+        .risk-high { color: #d9534f; background: #ffe6e6; padding: 5px 10px; border-radius: 3px; }
+
+        .assessment-table {
+          width: 100%;
+          border-collapse: collapse;
+          margin-bottom: 15px;
+        }
+        .assessment-table th, .assessment-table td {
+          border: 1px solid #333;
+          padding: 8px;
+          text-align: left;
+        }
+        .assessment-table th {
+          background: #e8e8e8;
+          font-weight: bold;
+          text-align: center;
+        }
+        .assessment-table .risk-factor-col {
+          width: 45%;
+        }
+        .assessment-table .score-yes-col,
+        .assessment-table .score-no-col {
+          width: 12%;
+          text-align: center;
+        }
+        .assessment-table .select-col {
+          width: 31%;
+          text-align: center;
+        }
+        .assessment-table .risk-factor {
+          text-align: left;
+        }
+        .assessment-table .score-yes,
+        .assessment-table .score-no {
+          text-align: center;
+        }
+
+        .risk-judgment-section {
+          margin: 15px 0;
+          padding: 10px;
+          border: 1px solid #999;
+        }
+        .risk-judgment-title {
+          font-weight: bold;
+          margin-bottom: 10px;
+        }
+        .risk-options {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 15px;
+        }
+        .risk-option {
+          display: inline-block;
+        }
+
+        .measures-section {
+          margin: 15px 0;
+          border: 1px solid #999;
+        }
+        .measures-title {
+          font-weight: bold;
+          background: #e8e8e8;
+          padding: 8px 12px;
+          border-bottom: 1px solid #999;
+        }
+        .measures-content {
+          padding: 10px 12px;
+        }
+        .measure-item {
+          margin-bottom: 8px;
+          font-size: 10pt;
+        }
+        .measure-other {
+          margin-left: 10px;
+          border-bottom: 1px solid #333;
+          min-width: 200px;
+          display: inline-block;
+        }
+
+        .signature-section {
+          margin-top: 30px;
+          padding: 15px;
+          border: 1px solid #999;
+        }
+        .signature-row {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+        }
+        .signature-item {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+        }
+        .signature-label {
+          font-weight: bold;
+        }
+        .signature-value {
+          border-bottom: 1px solid #333;
+          min-width: 150px;
+          height: 25px;
+        }
+
+        .note-section {
+          margin-top: 20px;
+          padding: 15px;
+          border: 1px solid #999;
+          background: #fafafa;
+        }
+        .note-title {
+          font-weight: bold;
+          margin-bottom: 10px;
+        }
+        .note-content {
+          font-size: 10pt;
+          line-height: 1.8;
+        }
+        .note-content p {
+          margin: 5px 0;
+        }
+        .note-content .indent {
+          margin-left: 20px;
+        }
+      </style>
+    </head>
+    <body>
+      <div class="header">
+        <h1>自杀风险评估量表(NGASR)</h1>
+      </div>
+
+      <div class="info-section">
+        <div class="info-row">
+          <div class="info-item">
+            <span class="label">长者姓名:</span>
+            <span class="value">${dataForm.value.elderName || ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">档案号:</span>
+            <span class="value">${dataForm.value.contractNumber || ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">床位号:</span>
+            <span class="value">${dataForm.value.bedName || ''}</span>
+          </div>
+        </div>
+        <div class="info-row" style="margin-top: 10px;">
+          <div class="info-item">
+            <span class="label">评估日期:</span>
+            <span class="value">${form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">评估人:</span>
+            <span class="value">${form.assessor || ''}</span>
+          </div>
+        </div>
+      </div>
+
+      <div class="score-summary">
+        <div class="total-score">
+          总得分:<span class="score-value">${totalScore.value}</span> 分
+        </div>
+
+      </div>
+
+      <!-- 评估表格 -->
+      <table class="assessment-table">
+        <thead>
+          <tr>
+            <th class="risk-factor-col">危险因素</th>
+            <th class="score-yes-col">是</th>
+            <th class="score-no-col">否</th>
+            <th class="select-col">选择</th>
+          </tr>
+        </thead>
+        <tbody>
+          ${riskFactorRows}
+        </tbody>
+      </table>
+
+      <!-- 风险程度判断 -->
+      <div class="risk-judgment-section">
+        <div class="risk-judgment-title">风险程度判断:</div>
+        <div class="risk-options">
+          <span class="risk-option">${form.riskLevel === 'none' ? '☑' : '☐'} 无风险:0分</span>
+          <span class="risk-option">${form.riskLevel === 'low' ? '☑' : '☐'} 低风险:1-5分</span>
+          <span class="risk-option">${form.riskLevel === 'medium' ? '☑' : '☐'} 中风险:6-8分</span>
+          <span class="risk-option">${form.riskLevel === 'high' ? '☑' : '☐'} 高风险:≥9分</span>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="measures-section">
+        <div class="measures-title">预防措施</div>
+        <div class="measures-content">
+          <div class="measure-item">${form.preventiveMeasures?.includes('patrol') ? '☑' : '☐'} 加强巡视</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('handover') ? '☑' : '☐'} 严格交接班</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('checkItems') ? '☑' : '☐'} 检查有无危险物品</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('emotion') ? '☑' : '☐'} 注重长者情绪行为</div>
+          <div class="measure-item">
+            ${form.preventiveMeasures?.includes('other') ? '☑' : '☐'} 其他
+            ${form.preventiveMeasures?.includes('other') ? '<span class="measure-other">' + (form.preventiveMeasuresOther || '') + '</span>' : ''}
+          </div>
+        </div>
+      </div>
+
+      <!-- 签名区域 -->
+      <div class="signature-section">
+        <div class="signature-row">
+          <div class="signature-item">
+            <span class="signature-label">家属/监护人签名:</span>
+            <span class="signature-value">${form.familySignature || ''}</span>
+          </div>
+
+        </div>
+      </div>
+
+      <!-- 说明 -->
+      <div class="note-section">
+        <div class="note-title">说明:</div>
+        <div class="note-content">
+          <p>1. 新入住长者应在长者入住24小时内完成首次评估;</p>
+          <p>2. 定期评估:</p>
+          <p class="indent">(1)认知照护专区:高风险1个月评估一次,中风险、低风险3个月评估一次;</p>
+          <p class="indent">(2)非认知照护专区:高风险1个月评估一次,中风险3个月评估一次,低风险6个月评估一次;</p>
+          <p>3. 当长者身体发生变化者,应及时进行动态评估。</p>
+        </div>
+      </div>
+    </body>
+    </html>
+  `
+
+  // 写入内容并打印
+  printWindow.document.write(printContent)
+  printWindow.document.close()
+
+  // 延迟打印,确保样式加载完成
+  setTimeout(() => {
+    printWindow.print()
+  }, 500)
+}
+
+</script>
+
+<style scoped lang="scss">
+
+.form-title {
+  text-align: center;
+  font-size: 20px;
+  width: 100%;
+  margin-bottom: 20px;
+}
+
+.mmse-form {
+  max-width: 1200px;
+  margin: 0 auto;
+  background: #fff;
+
+
+
+
+
+  .info-row {
+    display: flex;
+    gap: 40px;
+    width: 100%;
+    flex-direction: row;
+    align-items: center;
+    margin-bottom: 10px;
+
+    .info-item {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .label {
+        width: 82px;
+        text-align: right;
+        margin-right: 4px;
+        white-space: nowrap;
+      }
+    }
+  }
+
+
+  .form-body {
+    border: 1px solid #333;
+    padding: 15px;
+  }
+
+  // 调整 Element Plus 组件样式
+  :deep(.el-input__inner) {
+    height: 28px;
+    line-height: 28px;
+    border-top: none;
+    border-left: none;
+    border-right: none;
+    border-radius: 0;
+    padding: 0 4px;
+
+    &:focus {
+      border-color: #409eff;
+    }
+  }
+
+  :deep(.el-checkbox__label),
+  :deep(.el-radio__label) {
+    padding-left: 4px;
+  }
+}
+.row{
+  margin-bottom: 12px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  text{
+    text-align: right;
+    margin-right: 4px;
+    width: 82px;
+  }
+}
+
+// NGASR自杀风险评估量表 特有样式
+.total-score-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  margin-bottom: 20px;
+
+  .total-score {
+    display: flex;
+    align-items: baseline;
+    gap: 4px;
+
+    .score-label {
+      font-size: 16px;
+      font-weight: bold;
+    }
+
+    .score-value {
+      font-size: 28px;
+      font-weight: bold;
+      color: #409eff;
+    }
+
+    .score-max {
+      font-size: 14px;
+      color: #909399;
+    }
+  }
+
+  .risk-level {
+    font-size: 16px;
+    font-weight: bold;
+    padding: 8px 16px;
+    border-radius: 4px;
+
+    &.risk-none {
+      color: #67c23a;
+      background: #f0f9eb;
+    }
+
+    &.risk-low {
+      color: #e6a23c;
+      background: #fdf6ec;
+    }
+
+    &.risk-medium {
+      color: #f56c6c;
+      background: #fef0f0;
+    }
+
+    &.risk-high {
+      color: #f56c6c;
+      background: #fef0f0;
+      border: 1px solid #f56c6c;
+    }
+  }
+}
+
+.assessment-table {
+  width: 100%;
+  border-collapse: collapse;
+  margin-bottom: 20px;
+
+  table {
+    width: 100%;
+    border: 1px solid #333;
+
+    th, td {
+      border: 1px solid #333;
+      padding: 12px;
+      text-align: left;
+    }
+
+    th {
+      background: #f5f7fa;
+      font-weight: bold;
+      text-align: center;
+    }
+
+    .criteria-col {
+      width: 60%;
+    }
+
+    .score-col {
+      width: 15%;
+      text-align: center;
+    }
+
+    .select-col {
+      width: 25%;
+      text-align: center;
+    }
+
+    .criteria {
+      text-align: left;
+    }
+
+    .score {
+      text-align: center;
+      font-weight: bold;
+    }
+
+    .select {
+      text-align: center;
+
+      :deep(.el-radio) {
+        margin-right: 0;
+      }
+    }
+  }
+}
+
+.remark-section {
+  margin: 15px 0;
+  padding: 12px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .remark-label {
+    font-weight: bold;
+    color: #606266;
+  }
+
+  .remark-text {
+    color: #606266;
+  }
+}
+
+.risk-judgment-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .risk-judgment-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .risk-options {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+
+    :deep(.el-radio) {
+      margin-right: 0;
+    }
+  }
+}
+
+.preventive-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .preventive-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .preventive-options {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+
+    :deep(.el-checkbox) {
+      margin-right: 20px;
+      margin-bottom: 8px;
+    }
+
+    .other-input {
+      width: 200px;
+      margin-left: 10px;
+    }
+  }
+}
+
+.signature-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .signature-row {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    gap: 20px;
+  }
+
+  .signature-item {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+
+    &.date-item {
+      :deep(.el-date-picker) {
+        width: 150px;
+      }
+    }
+  }
+
+  .signature-label {
+    font-weight: bold;
+    white-space: nowrap;
+  }
+
+  .signature-input {
+    width: 150px;
+  }
+
+  .date-picker {
+    width: 150px;
+  }
+}
+
+.note-section {
+  margin-top: 20px;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .note-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .note-content {
+    font-size: 13px;
+    line-height: 1.8;
+    color: #606266;
+
+    p {
+      margin: 5px 0;
+    }
+
+    .indent {
+      margin-left: 20px;
+    }
+  }
+}
+</style>

+ 333 - 0
src/views/elderly/apply/nine-precautions/commit-suicide/index.vue

@@ -0,0 +1,333 @@
+<template>
+  <ContentWrap>
+    <!-- 保护性约束观察记录表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+
+      <ButtonAdd @click="openForm(undefined)"  />
+      <!--      <el-button @click="inputH" type="success"><Icon icon="fa:cloud-upload" :size="16" class="mr-1"/>导入</el-button>-->
+      <!--      <ButtonImport @click="handleImportCard"  />-->
+
+
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="200" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="200" show-overflow-tooltip/>
+
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="200" show-overflow-tooltip/>
+
+
+      <el-table-column label="操作" align="center" width="200" >
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+
+
+  <Import
+    ref="importRef"
+    @success="getList"
+    :config="{
+      title: '导入',
+      downloadUrl: 'elderly-service-order/get-import-template',
+      excelTempName: '居家工单-【导入】模板',
+      importUrl: '/elderly-service-order/import',
+      failExportUrl: '',
+    }"
+  />
+
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import ButtonImport from "@/components/ButtonImport/src/ButtonImport.vue";
+import { useUserStore } from '@/store/modules/user'
+import {formatTimestamp, getCurrentMonthRange} from "@/utils/dateUtil";
+import Import from "@/components/ImportFile/index.vue";
+import {restraintCreatePage, restraintDelete} from "@/api/elderly/nursing/keep-fit";
+import {ngasrDelete, ngasrPage, perceptionDelete, perceptionPage} from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const userStore = useUserStore()
+const loading = ref(true) // 列表的加载中
+const detailRef = ref()
+const importRef = ref()
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref() // 搜索的表单
+
+
+// 打开导出弹窗
+const handleImportCard = async () => {
+
+  // showBatchExport.value = true
+}
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch,count)
+  // try {
+  //   let queryParams = {
+  //     pageNo: batch,
+  //     pageSize: count,
+  //     tenantId: userStore.orgTenantId[0]
+  //   }
+  //   const list = await careRecordsPage(queryParams)
+  //   if (list.length <= 0) {
+  //     message.error('暂无数据可以导出!')
+  //     return
+  //   }
+  //   const headers = [
+  //     { key: 'organizationName', title: '机构名称' },
+  //     { key: 'visitName', title: '姓名' },
+  //     { key: 'visitPhone', title: '手机号' },
+  //     { key: 'visitDate', title: '预约时间' },
+  //     { key: 'accompanyCount', title: '陪同人数' },
+  //     { key: 'reason', title: '理由' }
+  //   ]
+  //   exportWithExpandedObjectArrays(list, headers, `医疗护理记录${formatToDateTime()}.xlsx`, '医疗护理记录')
+  // } catch (_) {}
+
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    //let queryP = {...queryParams,discoveryTime:queryParams.discoveryTime?[queryParams.discoveryTime[0]+" 00:00:00",queryParams.discoveryTime[1]+" 23:59:59"]:null}
+    const data = await ngasrPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate= getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if(queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1){
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id,false)
+}
+
+const editRef = ref()
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id,false)
+}
+
+
+const openFormDetail = (row: any = {},id?: number) => {
+  formRef.value.open(row.tenantId,id,true)
+}
+
+
+
+
+
+const openClose = async (item) => {
+  try {
+    console.log("任务ID",item)
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      // 发起
+      try {
+        const res = await ngasrDelete(item.id)
+        if (res){
+          message.success(t('common.updateSuccess'))
+        }
+      }catch(err) {}
+    }
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    // 取消的二次确认
+    await message.cancelConfirm()
+    // 发起取消
+    // await elderlyBakDel(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if(route.query && route.query.elderName){
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 1237 - 0
src/views/elderly/apply/nine-precautions/communication/AddForm.vue

@@ -0,0 +1,1237 @@
+<template>
+  <el-drawer
+    v-model="dialogVisible"
+    :title="title"
+    resizable
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    :destroy-on-close="true"
+    size="70%"
+    :before-close="handleClosed"
+  >
+
+    <div class="mmse-form">
+      <h1 class="form-title">感知觉与沟通评估表</h1>
+      <!-- 基本信息 -->
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>长者姓名</text>
+          <search-the-elderly ref="selectElderRef" :disabled="isDetail" @update_elder="elderUp" v-model="dataForm.elderName" :tId="dataForm.tenantId"/>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>档案号</text>
+          <el-input v-if="!isDetail" v-model="dataForm.contractNumber" disabled />
+          <el-text v-else disabled="">{{dataForm.contractNumber}}</el-text>
+        </el-col>
+      </el-row>
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>入院日期</text>
+          <el-input v-if="!isDetail" :model-value="dayjs(dataForm.checkInTime).format('YYYY-MM-DD')=='Invalid Date'?'':dayjs(dataForm.checkInTime).format('YYYY-MM-DD')" disabled />
+          <el-text v-else disabled="">{{dayjs(dataForm.checkInTime).format('YYYY-MM-DD')}}</el-text>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>床位号</text>
+          <el-input v-if="!isDetail" v-model="dataForm.bedName" disabled />
+          <el-text v-else disabled="">{{dataForm.bedName}}</el-text>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>评估人</text>
+          <el-input :disabled="isDetail" v-model="form.assessor"  />
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>评估日期</text>
+          <el-date-picker :disabled="isDetail" v-model="form.assessDate" type="date" style="width: 100%;"/>
+
+        </el-col>
+      </el-row>
+
+      <!-- 表单内容区域 -->
+      <div class="form-body">
+        <!-- 总分显示 -->
+        <div class="total-score-section">
+          <div class="total-score">
+            <span class="score-label">总得分:</span>
+            <span class="score-value">{{ totalScore }}</span>
+            <span class="score-max">/ 4分</span>
+          </div>
+        </div>
+
+        <!-- 评估表格 -->
+        <div class="assessment-table">
+          <table>
+            <thead>
+              <tr>
+                <th class="criteria-col">评估准则</th>
+                <th class="score-col">分值</th>
+                <th class="select-col">选择</th>
+              </tr>
+            </thead>
+            <tbody>
+              <tr>
+                <td class="criteria">能看清书报上的标准字体</td>
+                <td class="score">0分</td>
+                <td class="select">
+                  <el-radio v-model="form.visionScore" :label="0" :disabled="isDetail"/>
+                </td>
+              </tr>
+              <tr>
+                <td class="criteria">能看清楚大字体;但看不清书报上的标准字体</td>
+                <td class="score">1分</td>
+                <td class="select">
+                  <el-radio v-model="form.visionScore" :label="1" :disabled="isDetail"/>
+                </td>
+              </tr>
+              <tr>
+                <td class="criteria">视力有限;看不清报纸大标题;但能辨认物体</td>
+                <td class="score">2分</td>
+                <td class="select">
+                  <el-radio v-model="form.visionScore" :label="2" :disabled="isDetail"/>
+                </td>
+              </tr>
+              <tr>
+                <td class="criteria">辨认物体有困难;但眼睛能跟随物体移动;只能看到光、颜色和形状</td>
+                <td class="score">3分</td>
+                <td class="select">
+                  <el-radio v-model="form.visionScore" :label="3" :disabled="isDetail"/>
+                </td>
+              </tr>
+              <tr>
+                <td class="criteria">没有视力;眼睛不能跟随物体移动</td>
+                <td class="score">4分</td>
+                <td class="select">
+                  <el-radio v-model="form.visionScore" :label="4" :disabled="isDetail"/>
+                </td>
+              </tr>
+            </tbody>
+          </table>
+        </div>
+
+        <!-- 备注 -->
+        <div class="remark-section">
+          <span class="remark-label">备注:</span>
+          <span class="remark-text">若平日戴老花镜或近视镜,应在佩戴眼镜的情况下评估。</span>
+        </div>
+
+        <!-- 风险程度判断 -->
+        <div class="risk-judgment-section">
+          <div class="risk-judgment-title">风险程度判断:</div>
+          <div class="risk-options">
+            <el-radio v-model="form.riskLevel" label="none" :disabled="isDetail">
+                无风险:0分
+            </el-radio>
+            <el-radio v-model="form.riskLevel" label="low" :disabled="isDetail">
+                低风险:1分
+            </el-radio>
+            <el-radio v-model="form.riskLevel" label="medium" :disabled="isDetail">
+                中风险:2分
+            </el-radio>
+            <el-radio v-model="form.riskLevel" label="high" :disabled="isDetail">
+                高风险:≥3分
+            </el-radio>
+          </div>
+        </div>
+
+        <!-- 预防措施 -->
+        <div class="preventive-section">
+          <div class="preventive-title">预防措施:</div>
+          <div class="preventive-options">
+            <el-checkbox v-model="form.preventiveMeasures" label="patrol" :disabled="isDetail">
+                加强巡查
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" label="food" :disabled="isDetail">
+                合理食物
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" label="expression" :disabled="isDetail">
+                观察表情
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" label="medication" :disabled="isDetail">
+                药物统一管控
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" label="feeding" :disabled="isDetail">
+                严格协助进食操作规程
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" label="card" :disabled="isDetail">
+                设立床头卡标识
+            </el-checkbox>
+            <el-checkbox v-model="form.preventiveMeasures" label="other" :disabled="isDetail">
+                其他
+            </el-checkbox>
+            <el-input v-if="form.preventiveMeasures.includes('other')" v-model="form.preventiveMeasuresOther" placeholder="请输入其他措施" :disabled="isDetail" class="other-input"/>
+          </div>
+        </div>
+
+        <!-- 签名区域 -->
+        <div class="signature-section">
+          <div class="signature-row">
+            <div class="signature-item">
+              <span class="signature-label">家属/监护人签名:</span>
+              <el-input v-model="form.familySignature" :disabled="isDetail" class="signature-input"/>
+            </div>
+<!--            <div class="signature-item date-item">-->
+<!--              <span class="signature-label">日期:</span>-->
+<!--              <el-date-picker v-model="form.familySignDate" type="date" :disabled="isDetail" class="date-picker"/>-->
+<!--            </div>-->
+          </div>
+        </div>
+
+        <!-- 说明 -->
+        <div class="note-section">
+          <div class="note-title">说明:</div>
+          <div class="note-content">
+            <p>1. 新入住长者应在长者入住24小时内完成首次评估;</p>
+            <p>2. 定期评估:</p>
+            <p class="indent">(1)认知照护专区:高风险1个月评估一次,中风险、低风险3个月评估一次;</p>
+            <p class="indent">(2)非认知照护专区:高风险1个月评估一次,中风险3个月评估一次,低风险6个月评估一次;</p>
+            <p>3. 当长者身体发生变化者,应及时进行动态评估。</p>
+          </div>
+        </div>
+      </div>
+    </div>
+
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary" v-show="!isDetail" @click="submitForm">确定</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref } from 'vue'
+
+import dayjs from 'dayjs'
+
+import { perceptionCreate, perceptionGetById, perceptionUpdate, perceptionGetByElderId } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const selectElderRef = ref() // 表单 Ref
+const isDetail = ref(false) // 是否详情打开
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+let dataForm = ref({
+  // 表单字段
+  id: undefined,
+  idCard: '',
+  contractNumber: '', //档案号
+  elderName: '',//长者姓名
+  bedName: '', //床位号
+  elderAge: '', //年龄
+  elderSex: '', //性别
+  checkInTime: '', //入院日期
+  elderId: '',
+  tenantId: undefined
+})
+
+
+
+
+const elderUp = (e) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.checkInTime = e.checkInTime
+  dataForm.value.contractNumber = e.contractNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 感知觉与沟通评估表 表单序列化方法 ==========
+
+/** 计算总分 */
+const totalScore = computed(() => {
+  return form.visionScore || 0
+})
+
+/** 风险程度文本 */
+const riskLevelText = computed(() => {
+  const score = totalScore.value
+  if (score === 0) return '无风险'
+  if (score === 1) return '低风险'
+  if (score === 2) return '中风险'
+  return '高风险'
+})
+
+/** 风险程度样式类 */
+const riskLevelClass = computed(() => {
+  const score = totalScore.value
+  if (score === 0) return 'risk-none'
+  if (score === 1) return 'risk-low'
+  if (score === 2) return 'risk-medium'
+  return 'risk-high'
+})
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    // 基本信息
+    assessor: form.assessor || '',
+    assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : '',
+
+    // 视力评分
+    visionScore: form.visionScore || 0,
+
+    // 总分
+    totalScore: totalScore.value,
+
+    // 风险程度
+    riskLevel: form.riskLevel || '',
+
+    // 预防措施
+    preventiveMeasures: form.preventiveMeasures || [],
+    preventiveMeasuresOther: form.preventiveMeasuresOther || '',
+
+    // 签名
+    familySignature: form.familySignature || '',
+    familySignDate: form.familySignDate ? dayjs(form.familySignDate).format('YYYY-MM-DD') : ''
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  // 基本信息
+  form.assessor = formData.assessor || ''
+  form.assessDate = formData.assessDate ? dayjs(formData.assessDate).toDate() : ''
+
+  // 视力评分
+  form.visionScore = formData.visionScore ?? 0
+
+  // 风险程度
+  form.riskLevel = formData.riskLevel || ''
+
+  // 预防措施
+  form.preventiveMeasures = formData.preventiveMeasures || []
+  form.preventiveMeasuresOther = formData.preventiveMeasuresOther || ''
+
+  // 签名
+  form.familySignature = formData.familySignature || ''
+  form.familySignDate = formData.familySignDate ? dayjs(formData.familySignDate).toDate() : ''
+}
+
+/** 重置感知觉与沟通评估表表单数据 */
+const resetPerceptionForm = () => {
+  form.assessor = ''
+  form.assessDate = ''
+
+  // 视力评分
+  form.visionScore = 0
+
+  // 风险程度
+  form.riskLevel = ''
+
+  // 预防措施
+  form.preventiveMeasures = []
+  form.preventiveMeasuresOther = ''
+
+  // 签名
+  form.familySignature = ''
+  form.familySignDate = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-感知觉与沟通评估"
+    // 加载评估数据
+    await loadPerceptionData(id)
+  } else {
+    title.value = "新增-感知觉与沟通评估"
+
+  }
+}
+
+/** 加载评估数据 */
+const loadPerceptionData = async (id: number) => {
+  try {
+    const res = await perceptionGetById(id)
+    if (res) {
+      // 填充长者基本信息
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.checkInTime = res.checkInTime || ''
+      dataForm.value.contractNumber = res.fileNumber || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      // 解析 assessData
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+/** 根据长者ID加载评估数据 */
+const loadPerceptionByElderId = async (elderId: number) => {
+  try {
+    const res = await perceptionGetByElderId(elderId)
+    if (res && res.assessData) {
+      const formData = JSON.parse(res.assessData)
+      deserializeFormData(formData)
+    }
+  } catch (error) {
+    // 无历史数据,不处理
+  }
+}
+
+const form = reactive({
+  // 基本信息
+  assessor: '',
+  assessDate: '',
+
+  // 视力评分(0-4分)
+  visionScore: 0,
+
+  // 风险程度
+  riskLevel: '',
+
+  // 预防措施
+  preventiveMeasures: [],
+  preventiveMeasuresOther: '',
+
+  // 签名
+  familySignature: '',
+  familySignDate: ''
+})
+
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  if (formLoading.value) {
+    return
+  }
+  formLoading.value = true
+  // 提交请求
+  try {
+    const assessData = serializeFormData()
+    const tempParams = {
+      ...dataForm.value,
+      assessData: JSON.stringify(assessData),
+      totalScore: totalScore.value,
+      assessor: form.assessor,
+      assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      const res = await perceptionUpdate(tempParams)
+      if (res) {
+        message.success(t('common.updateSuccess'))
+        dialogVisible.value = false
+        // 发送操作成功的事件
+        emit('success')
+      }
+    } else {
+      const res = await perceptionCreate(tempParams)
+      if (res) {
+        message.success(t('common.createSuccess'))
+        dialogVisible.value = false
+        // 发送操作成功的事件
+        emit('success')
+      }
+    }
+  } finally {
+    setTimeout(() => {
+      formLoading.value = false
+    }, 500)
+  }
+}
+
+
+
+/** 重置表单 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    idCard: '',
+    contractNumber: '', //档案号
+    elderName: '',//长者姓名
+    bedName: '', //床位号
+    elderAge: '', //年龄
+    elderSex: '', //性别
+    checkInTime: '', //入院日期
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  // 重置感知觉与沟通评估表表单
+  resetPerceptionForm()
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+/** 导出PDF */
+const handleExport = () => {
+  // 创建打印窗口
+  const printWindow = window.open('', '_blank')
+  if (!printWindow) {
+    message.error('请允许弹出窗口')
+    return
+  }
+
+  // 辅助函数:获取视力评分选项
+  const getVisionMark = (score) => {
+    const marks = [
+      { score: 0, text: '能看清书报上的标准字体(0分)' },
+      { score: 1, text: '能看清楚大字体(1分)' },
+      { score: 2, text: '视力有限,能辨认物体(2分)' },
+      { score: 3, text: '辨认物体有困难(3分)' },
+      { score: 4, text: '没有视力(4分)' }
+    ]
+    return marks.map(m => `${m.score === score ? '☑' : '☐'} ${m.text}`).join('<br>')
+  }
+
+  // 构建打印内容
+  const printContent = `
+    <!DOCTYPE html>
+    <html>
+    <head>
+      <meta charset="UTF-8">
+      <title>感知觉与沟通评估表 - ${dataForm.value.elderName || ''}</title>
+      <style>
+        @media print {
+          @page { size: A4 portrait; margin: 15mm; }
+        }
+        body {
+          font-family: 'SimSun', 'Microsoft YaHei', serif;
+          font-size: 11pt;
+          line-height: 1.5;
+          color: #333;
+        }
+        .header {
+          text-align: center;
+          margin-bottom: 20px;
+          border-bottom: 2px solid #333;
+          padding-bottom: 10px;
+        }
+        .header h1 {
+          font-size: 18pt;
+          margin: 0;
+          letter-spacing: 2px;
+        }
+        .info-section {
+          margin-bottom: 15px;
+          padding: 10px;
+          border: 1px solid #999;
+          background: #fafafa;
+        }
+        .info-row {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 20px;
+        }
+        .info-item {
+          display: flex;
+          align-items: center;
+        }
+        .info-item .label {
+          font-weight: bold;
+          margin-right: 8px;
+          color: #555;
+        }
+        .info-item .value {
+          border-bottom: 1px solid #333;
+          min-width: 80px;
+          padding: 0 5px;
+          text-align: center;
+        }
+        .score-summary {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          padding: 10px 15px;
+          background: #f0f0f0;
+          border: 2px solid #333;
+          margin-bottom: 15px;
+        }
+        .total-score {
+          font-size: 14pt;
+          font-weight: bold;
+        }
+        .total-score .score-value {
+          color: #d9534f;
+          font-size: 18pt;
+        }
+        .risk-level {
+          font-size: 12pt;
+          font-weight: bold;
+          padding: 5px 15px;
+        }
+        .risk-none { color: #5cb85c; }
+        .risk-low { color: #f0ad4e; }
+        .risk-medium { color: #d9534f; }
+        .risk-high { color: #d9534f; background: #ffe6e6; padding: 5px 10px; border-radius: 3px; }
+
+        .assessment-table {
+          width: 100%;
+          border-collapse: collapse;
+          margin-bottom: 15px;
+        }
+        .assessment-table th, .assessment-table td {
+          border: 1px solid #333;
+          padding: 10px;
+          text-align: left;
+        }
+        .assessment-table th {
+          background: #e8e8e8;
+          font-weight: bold;
+          text-align: center;
+        }
+        .assessment-table .criteria-col {
+          width: 60%;
+        }
+        .assessment-table .score-col {
+          width: 15%;
+          text-align: center;
+        }
+        .assessment-table .select-col {
+          width: 25%;
+          text-align: center;
+        }
+        .assessment-table .criteria {
+          text-align: left;
+        }
+        .assessment-table .score {
+          text-align: center;
+          font-weight: bold;
+        }
+
+        .remark-section {
+          margin: 15px 0;
+          padding: 10px;
+          border: 1px solid #999;
+          background: #fafafa;
+        }
+        .remark-label {
+          font-weight: bold;
+        }
+
+        .risk-judgment-section {
+          margin: 15px 0;
+          padding: 10px;
+          border: 1px solid #999;
+        }
+        .risk-judgment-title {
+          font-weight: bold;
+          margin-bottom: 10px;
+        }
+        .risk-options {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 20px;
+        }
+        .risk-option {
+          display: inline-block;
+        }
+
+        .measures-section {
+          margin: 15px 0;
+          border: 1px solid #999;
+        }
+        .measures-title {
+          font-weight: bold;
+          background: #e8e8e8;
+          padding: 8px 12px;
+          border-bottom: 1px solid #999;
+        }
+        .measures-content {
+          padding: 10px 12px;
+        }
+        .measure-item {
+          margin-bottom: 8px;
+          font-size: 10pt;
+        }
+        .measure-other {
+          margin-left: 10px;
+          border-bottom: 1px solid #333;
+          min-width: 200px;
+          display: inline-block;
+        }
+
+        .signature-section {
+          margin-top: 30px;
+          padding: 15px;
+          border: 1px solid #999;
+        }
+        .signature-row {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+        }
+        .signature-item {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+        }
+        .signature-label {
+          font-weight: bold;
+        }
+        .signature-value {
+          border-bottom: 1px solid #333;
+          min-width: 150px;
+          height: 25px;
+        }
+
+        .note-section {
+          margin-top: 20px;
+          padding: 15px;
+          border: 1px solid #999;
+          background: #fafafa;
+        }
+        .note-title {
+          font-weight: bold;
+          margin-bottom: 10px;
+        }
+        .note-content {
+          font-size: 10pt;
+          line-height: 1.8;
+        }
+        .note-content p {
+          margin: 5px 0;
+        }
+        .note-content .indent {
+          margin-left: 20px;
+        }
+      </style>
+    </head>
+    <body>
+      <div class="header">
+        <h1>感知觉与沟通评估表</h1>
+      </div>
+
+      <div class="info-section">
+        <div class="info-row">
+          <div class="info-item">
+            <span class="label">长者姓名:</span>
+            <span class="value">${dataForm.value.elderName || ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">档案号:</span>
+            <span class="value">${dataForm.value.contractNumber || ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">床位号:</span>
+            <span class="value">${dataForm.value.bedName || ''}</span>
+          </div>
+        </div>
+        <div class="info-row" style="margin-top: 10px;">
+          <div class="info-item">
+            <span class="label">评估日期:</span>
+            <span class="value">${form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">评估人:</span>
+            <span class="value">${form.assessor || ''}</span>
+          </div>
+        </div>
+      </div>
+
+      <div class="score-summary">
+        <div class="total-score">
+          总得分:<span class="score-value">${totalScore.value}</span> / 4分
+        </div>
+      </div>
+
+      <!-- 评估表格 -->
+      <table class="assessment-table">
+        <thead>
+          <tr>
+            <th class="criteria-col">评估准则</th>
+            <th class="score-col">分值</th>
+            <th class="select-col">选择</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td class="criteria">能看清书报上的标准字体</td>
+            <td class="score">0分</td>
+            <td class="select">${form.visionScore === 0 ? '☑' : '☐'}</td>
+          </tr>
+          <tr>
+            <td class="criteria">能看清楚大字体;但看不清书报上的标准字体</td>
+            <td class="score">1分</td>
+            <td class="select">${form.visionScore === 1 ? '☑' : '☐'}</td>
+          </tr>
+          <tr>
+            <td class="criteria">视力有限;看不清报纸大标题;但能辨认物体</td>
+            <td class="score">2分</td>
+            <td class="select">${form.visionScore === 2 ? '☑' : '☐'}</td>
+          </tr>
+          <tr>
+            <td class="criteria">辨认物体有困难;但眼睛能跟随物体移动;只能看到光、颜色和形状</td>
+            <td class="score">3分</td>
+            <td class="select">${form.visionScore === 3 ? '☑' : '☐'}</td>
+          </tr>
+          <tr>
+            <td class="criteria">没有视力;眼睛不能跟随物体移动</td>
+            <td class="score">4分</td>
+            <td class="select">${form.visionScore === 4 ? '☑' : '☐'}</td>
+          </tr>
+        </tbody>
+      </table>
+
+      <!-- 备注 -->
+      <div class="remark-section">
+        <span class="remark-label">备注:</span>
+        <span>若平日戴老花镜或近视镜,应在佩戴眼镜的情况下评估。</span>
+      </div>
+
+      <!-- 风险程度判断 -->
+      <div class="risk-judgment-section">
+        <div class="risk-judgment-title">风险程度判断:</div>
+        <div class="risk-options">
+          <span class="risk-option">${form.riskLevel === 'none' ? '☑' : '☐'} 无风险:0分</span>
+          <span class="risk-option">${form.riskLevel === 'low' ? '☑' : '☐'} 低风险:1分</span>
+          <span class="risk-option">${form.riskLevel === 'medium' ? '☑' : '☐'} 中风险:2分</span>
+          <span class="risk-option">${form.riskLevel === 'high' ? '☑' : '☐'} 高风险:≥3分</span>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="measures-section">
+        <div class="measures-title">预防措施</div>
+        <div class="measures-content">
+          <div class="measure-item">${form.preventiveMeasures?.includes('patrol') ? '☑' : '☐'} 加强巡查</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('food') ? '☑' : '☐'} 合理食物</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('expression') ? '☑' : '☐'} 观察表情</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('medication') ? '☑' : '☐'} 药物统一管控</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('feeding') ? '☑' : '☐'} 严格协助进食操作规程</div>
+          <div class="measure-item">${form.preventiveMeasures?.includes('card') ? '☑' : '☐'} 设立床头卡标识</div>
+          <div class="measure-item">
+            ${form.preventiveMeasures?.includes('other') ? '☑' : '☐'} 其他
+            ${form.preventiveMeasures?.includes('other') ? '<span class="measure-other">' + (form.preventiveMeasuresOther || '') + '</span>' : ''}
+          </div>
+        </div>
+      </div>
+
+      <!-- 签名区域 -->
+      <div class="signature-section">
+        <div class="signature-row">
+          <div class="signature-item">
+            <span class="signature-label">家属/监护人签名:</span>
+            <span class="signature-value">${form.familySignature || ''}</span>
+          </div>
+        </div>
+      </div>
+
+      <!-- 说明 -->
+      <div class="note-section">
+        <div class="note-title">说明:</div>
+        <div class="note-content">
+          <p>1. 新入住长者应在长者入住24小时内完成首次评估;</p>
+          <p>2. 定期评估:</p>
+          <p class="indent">(1)认知照护专区:高风险1个月评估一次,中风险、低风险3个月评估一次;</p>
+          <p class="indent">(2)非认知照护专区:高风险1个月评估一次,中风险3个月评估一次,低风险6个月评估一次;</p>
+          <p>3. 当长者身体发生变化者,应及时进行动态评估。</p>
+        </div>
+      </div>
+    </body>
+    </html>
+  `
+
+  // 写入内容并打印
+  printWindow.document.write(printContent)
+  printWindow.document.close()
+
+  // 延迟打印,确保样式加载完成
+  setTimeout(() => {
+    printWindow.print()
+  }, 500)
+}
+
+</script>
+
+<style scoped lang="scss">
+.mmse-form {
+  max-width: 1200px;
+  margin: 0 auto;
+  background: #fff;
+
+  .form-title {
+    text-align: center;
+    font-size: 24px;
+    font-weight: bold;
+    margin-bottom: 20px;
+  }
+
+
+
+  .info-row {
+    display: flex;
+    gap: 40px;
+    width: 100%;
+    flex-direction: row;
+    align-items: center;
+    margin-bottom: 10px;
+
+    .info-item {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .label {
+        width: 82px;
+        text-align: right;
+        margin-right: 4px;
+        white-space: nowrap;
+      }
+    }
+  }
+
+
+  .form-body {
+    border: 1px solid #333;
+    padding: 15px;
+  }
+
+  .section {
+    margin-bottom: 20px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .section-title {
+      font-weight: bold;
+      margin-bottom: 10px;
+    }
+  }
+
+  .form-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
+    flex-wrap: wrap;
+    gap: 8px;
+
+    .item-number {
+      font-weight: bold;
+      min-width: 25px;
+    }
+
+    .item-label {
+      white-space: nowrap;
+      min-width: fit-content;
+    }
+
+  }
+
+  .other-input {
+    width: 200px;
+    margin-left: 10px;
+  }
+
+  // 调整 Element Plus 组件样式
+  :deep(.el-input__inner) {
+    height: 28px;
+    line-height: 28px;
+    border-top: none;
+    border-left: none;
+    border-right: none;
+    border-radius: 0;
+    padding: 0 4px;
+
+    &:focus {
+      border-color: #409eff;
+    }
+  }
+
+
+  :deep(.el-checkbox__label),
+  :deep(.el-radio__label) {
+    padding-left: 4px;
+  }
+}
+.row{
+  margin-bottom: 12px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  text{
+    text-align: right;
+    margin-right: 4px;
+    width: 82px;
+  }
+}
+
+// 感知觉与沟通评估表 特有样式
+.total-score-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  margin-bottom: 20px;
+
+  .total-score {
+    display: flex;
+    align-items: baseline;
+    gap: 4px;
+
+    .score-label {
+      font-size: 16px;
+      font-weight: bold;
+    }
+
+    .score-value {
+      font-size: 28px;
+      font-weight: bold;
+      color: #409eff;
+    }
+
+    .score-max {
+      font-size: 14px;
+      color: #909399;
+    }
+  }
+
+  .risk-level {
+    font-size: 16px;
+    font-weight: bold;
+    padding: 8px 16px;
+    border-radius: 4px;
+
+    &.risk-none {
+      color: #67c23a;
+      background: #f0f9eb;
+    }
+
+    &.risk-low {
+      color: #e6a23c;
+      background: #fdf6ec;
+    }
+
+    &.risk-medium {
+      color: #f56c6c;
+      background: #fef0f0;
+    }
+
+    &.risk-high {
+      color: #f56c6c;
+      background: #fef0f0;
+      border: 1px solid #f56c6c;
+    }
+  }
+}
+
+.assessment-table {
+  width: 100%;
+  border-collapse: collapse;
+  margin-bottom: 20px;
+
+  table {
+    width: 100%;
+    border: 1px solid #333;
+
+    th, td {
+      border: 1px solid #333;
+      padding: 12px;
+      text-align: left;
+    }
+
+    th {
+      background: #f5f7fa;
+      font-weight: bold;
+      text-align: center;
+    }
+
+    .criteria-col {
+      width: 60%;
+    }
+
+    .score-col {
+      width: 15%;
+      text-align: center;
+    }
+
+    .select-col {
+      width: 25%;
+      text-align: center;
+    }
+
+    .criteria {
+      text-align: left;
+    }
+
+    .score {
+      text-align: center;
+      font-weight: bold;
+    }
+
+    .select {
+      text-align: center;
+
+      :deep(.el-radio) {
+        margin-right: 0;
+      }
+    }
+  }
+}
+
+.remark-section {
+  margin: 15px 0;
+  padding: 12px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .remark-label {
+    font-weight: bold;
+    color: #606266;
+  }
+
+  .remark-text {
+    color: #606266;
+  }
+}
+
+.risk-judgment-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .risk-judgment-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .risk-options {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+
+    :deep(.el-radio) {
+      margin-right: 0;
+    }
+  }
+}
+
+.preventive-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .preventive-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .preventive-options {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+
+    :deep(.el-checkbox) {
+      margin-right: 20px;
+      margin-bottom: 8px;
+    }
+
+    .other-input {
+      width: 200px;
+      margin-left: 10px;
+    }
+  }
+}
+
+.signature-section {
+  margin: 20px 0;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .signature-row {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    gap: 20px;
+  }
+
+  .signature-item {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+
+    &.date-item {
+      :deep(.el-date-picker) {
+        width: 150px;
+      }
+    }
+  }
+
+  .signature-label {
+    font-weight: bold;
+    white-space: nowrap;
+  }
+
+  .signature-input {
+    width: 150px;
+  }
+
+  .date-picker {
+    width: 150px;
+  }
+}
+
+.note-section {
+  margin-top: 20px;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+
+  .note-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 12px;
+    color: #303133;
+  }
+
+  .note-content {
+    font-size: 13px;
+    line-height: 1.8;
+    color: #606266;
+
+    p {
+      margin: 5px 0;
+    }
+
+    .indent {
+      margin-left: 20px;
+    }
+  }
+}
+</style>

+ 335 - 0
src/views/elderly/apply/nine-precautions/communication/index.vue

@@ -0,0 +1,335 @@
+<template>
+  <ContentWrap>
+    <!-- 保护性约束观察记录表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+
+      <ButtonAdd @click="openForm(undefined)"  />
+      <!--      <el-button @click="inputH" type="success"><Icon icon="fa:cloud-upload" :size="16" class="mr-1"/>导入</el-button>-->
+<!--      <ButtonImport @click="handleImportCard"  />-->
+
+
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="200" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="200" show-overflow-tooltip/>
+
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="200" show-overflow-tooltip/>
+
+
+      <el-table-column label="操作" align="center" width="200" >
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+
+
+  <Import
+    ref="importRef"
+    @success="getList"
+    :config="{
+      title: '导入',
+      downloadUrl: 'elderly-service-order/get-import-template',
+      excelTempName: '居家工单-【导入】模板',
+      importUrl: '/elderly-service-order/import',
+      failExportUrl: '',
+    }"
+  />
+
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import ButtonImport from "@/components/ButtonImport/src/ButtonImport.vue";
+import { useUserStore } from '@/store/modules/user'
+import {formatTimestamp, getCurrentMonthRange} from "@/utils/dateUtil";
+import Import from "@/components/ImportFile/index.vue";
+import {restraintCreatePage, restraintDelete} from "@/api/elderly/nursing/keep-fit";
+import {perceptionDelete, perceptionPage} from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const userStore = useUserStore()
+const loading = ref(true) // 列表的加载中
+const detailRef = ref()
+const importRef = ref()
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref() // 搜索的表单
+
+const inputH = () => {
+  importRef.value.open(queryParams.tenantIds[0])
+}
+// 打开导出弹窗
+const handleImportCard = async () => {
+
+  // showBatchExport.value = true
+}
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch,count)
+  // try {
+  //   let queryParams = {
+  //     pageNo: batch,
+  //     pageSize: count,
+  //     tenantId: userStore.orgTenantId[0]
+  //   }
+  //   const list = await careRecordsPage(queryParams)
+  //   if (list.length <= 0) {
+  //     message.error('暂无数据可以导出!')
+  //     return
+  //   }
+  //   const headers = [
+  //     { key: 'organizationName', title: '机构名称' },
+  //     { key: 'visitName', title: '姓名' },
+  //     { key: 'visitPhone', title: '手机号' },
+  //     { key: 'visitDate', title: '预约时间' },
+  //     { key: 'accompanyCount', title: '陪同人数' },
+  //     { key: 'reason', title: '理由' }
+  //   ]
+  //   exportWithExpandedObjectArrays(list, headers, `医疗护理记录${formatToDateTime()}.xlsx`, '医疗护理记录')
+  // } catch (_) {}
+
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    //let queryP = {...queryParams,discoveryTime:queryParams.discoveryTime?[queryParams.discoveryTime[0]+" 00:00:00",queryParams.discoveryTime[1]+" 23:59:59"]:null}
+    const data = await perceptionPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate= getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if(queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1){
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id,false)
+}
+
+const editRef = ref()
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id,false)
+}
+
+
+const openFormDetail = (row: any = {},id?: number) => {
+  formRef.value.open(row.tenantId,id,true)
+}
+
+
+
+
+
+const openClose = async (item) => {
+  try {
+    console.log("任务ID",item)
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      // 发起
+      try {
+        const res = await perceptionDelete(item.id)
+        if (res){
+          message.success(t('common.updateSuccess'))
+        }
+      }catch(err) {}
+    }
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    // 取消的二次确认
+    await message.cancelConfirm()
+    // 发起取消
+    // await elderlyBakDel(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if(route.query && route.query.elderName){
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 770 - 0
src/views/elderly/apply/nine-precautions/daily-life/AddForm.vue

@@ -0,0 +1,770 @@
+<template>
+  <el-drawer v-model="dialogVisible" :title="title" size="95%" :before-close="handleClosed">
+    <div class="assessment-form">
+      <div class="form-header">
+        <el-form :model="dataForm" :rules="rules" ref="formRef" label-width="80px">
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="姓名" prop="elderName">
+                <SelectElder ref="selectElderRef" :tenantId="dataForm.tenantId" @elder="elderUp" :disabled="isDetail"
+                  :elderName="dataForm.elderName" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="床号">
+                <el-input v-model="dataForm.bedName" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="性别">
+                <el-input v-model="dataForm.elderSex" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="年龄">
+                <el-input v-model="dataForm.elderAge" disabled />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="评估日期">
+                <el-date-picker
+                  v-model="form.assessDate"
+                  type="date"
+                  placeholder="选择日期"
+                  value-format="YYYY-MM-DD"
+                  :disabled="isDetail"
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
+      <!-- Barthel指数评分表 -->
+      <div class="barthel-section">
+        <div class="section-title">日常生活活动能力评估表(Barthel指数评分标准)</div>
+        <table class="assessment-table">
+          <thead>
+            <tr>
+              <th class="col-item">项目</th>
+              <th class="col-score">分数</th>
+              <th class="col-content">内容</th>
+              <th class="col-result">得分</th>
+            </tr>
+          </thead>
+          <tbody>
+            <!-- 1. 大便控制 -->
+            <tr>
+              <td class="col-item" rowspan="3">1. 大便控制</td>
+              <td class="col-score">10</td>
+              <td class="col-content">
+                <el-radio :label="10" v-model="form.scores[0]" :disabled="isDetail" @change="calculateTotal">无大便失禁,并可自行使用塞剂。</el-radio>
+              </td>
+              <td class="col-result" rowspan="3">
+                <span class="score-display">{{ form.scores[0] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[0]" :disabled="isDetail" @change="calculateTotal">偶有失禁(每周不超过一次)或使用塞剂时需人帮助。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[0]" :disabled="isDetail" @change="calculateTotal">需别人处理。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 2. 小便控制 -->
+            <tr>
+              <td class="col-item" rowspan="3">2. 小便控制</td>
+              <td class="col-score">10</td>
+              <td class="col-content">
+                <el-radio :label="10" v-model="form.scores[1]" :disabled="isDetail" @change="calculateTotal">日夜皆不会尿失禁,或可自行使用并清理尿套。</el-radio>
+              </td>
+              <td class="col-result" rowspan="3">
+                <span class="score-display">{{ form.scores[1] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[1]" :disabled="isDetail" @change="calculateTotal">偶尔会尿失禁(每周不超过一次)或尿急(无法等待便盆或无法及时赶到厕所)或需别人帮助处理尿套。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[1]" :disabled="isDetail" @change="calculateTotal">需别人处理。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 3. 个人卫生 -->
+            <tr>
+              <td class="col-item" rowspan="2">3. 个人卫生</td>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[2]" :disabled="isDetail" @change="calculateTotal">可独立完成洗脸、洗手、刷牙及梳头发。</el-radio>
+              </td>
+              <td class="col-result" rowspan="2">
+                <span class="score-display">{{ form.scores[2] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[2]" :disabled="isDetail" @change="calculateTotal">需别人处理。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 4. 入厕 -->
+            <tr>
+              <td class="col-item" rowspan="3">4. 入厕</td>
+              <td class="col-score">10</td>
+              <td class="col-content">
+                <el-radio :label="10" v-model="form.scores[3]" :disabled="isDetail" @change="calculateTotal">可自行进出厕所,不会弄脏衣物,并能穿好衣服,使用便盆者,可自行清理便盆。</el-radio>
+              </td>
+              <td class="col-result" rowspan="3">
+                <span class="score-display">{{ form.scores[3] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[3]" :disabled="isDetail" @change="calculateTotal">需帮助保持姿势平衡、整理衣物或使用卫生纸。使用便盆者,可自行取放,但须依赖他人清理。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[3]" :disabled="isDetail" @change="calculateTotal">需他人帮助。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 5. 进食 -->
+            <tr>
+              <td class="col-item" rowspan="3">5. 进食</td>
+              <td class="col-score">10</td>
+              <td class="col-content">
+                <el-radio :label="10" v-model="form.scores[4]" :disabled="isDetail" @change="calculateTotal">自己在合理的时间内(约10s 吃一口)可用筷子取眼前的食物。若需进食辅具时,应自行穿脱。</el-radio>
+              </td>
+              <td class="col-result" rowspan="3">
+                <span class="score-display">{{ form.scores[4] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[4]" :disabled="isDetail" @change="calculateTotal">需别人帮助穿脱进食辅具或只会用汤匙进食。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[4]" :disabled="isDetail" @change="calculateTotal">无法自行取食或耗费时间过长。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 6. 床和椅转移 -->
+            <tr>
+              <td class="col-item" rowspan="4">6. 床和椅转移</td>
+              <td class="col-score">15</td>
+              <td class="col-content">
+                <el-radio :label="15" v-model="form.scores[5]" :disabled="isDetail" @change="calculateTotal">可独立完成,包括轮椅的煞车及移开脚踏板。</el-radio>
+              </td>
+              <td class="col-result" rowspan="4">
+                <span class="score-display">{{ form.scores[5] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">10</td>
+              <td class="col-content">
+                <el-radio :label="10" v-model="form.scores[5]" :disabled="isDetail" @change="calculateTotal">需要稍微的协助(例如:予以轻扶以保持平衡)或需要口头指导。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[5]" :disabled="isDetail" @change="calculateTotal">可自行从床上坐起,但移位时仍需要别人帮助。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[5]" :disabled="isDetail" @change="calculateTotal">需别人帮助方可坐起来或需别人帮助方可移位。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 7. 行走于平地上 -->
+            <tr>
+              <td class="col-item" rowspan="4">7. 行走于平地上</td>
+              <td class="col-score">15</td>
+              <td class="col-content">
+                <el-radio :label="15" v-model="form.scores[6]" :disabled="isDetail" @change="calculateTotal">使用或不使用辅具皆可独立行走50m 以上。</el-radio>
+              </td>
+              <td class="col-result" rowspan="4">
+                <span class="score-display">{{ form.scores[6] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">10</td>
+              <td class="col-content">
+                <el-radio :label="10" v-model="form.scores[6]" :disabled="isDetail" @change="calculateTotal">需要稍微的扶持或口头指导方可行走50m 以上。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[6]" :disabled="isDetail" @change="calculateTotal">虽无法行走,但可独立操纵轮椅(包括转弯、进门、接近桌子)。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[6]" :disabled="isDetail" @change="calculateTotal">需别人帮助方可坐起来或需别人帮助方可移位。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 8. 穿脱衣服 -->
+            <tr>
+              <td class="col-item" rowspan="3">8. 穿脱衣服</td>
+              <td class="col-score">10</td>
+              <td class="col-content">
+                <el-radio :label="10" v-model="form.scores[7]" :disabled="isDetail" @change="calculateTotal">可自行穿脱衣服、鞋子及辅具。</el-radio>
+              </td>
+              <td class="col-result" rowspan="3">
+                <span class="score-display">{{ form.scores[7] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[7]" :disabled="isDetail" @change="calculateTotal">在别人帮助下,可完成一半以上的上述动作。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[7]" :disabled="isDetail" @change="calculateTotal">不能自行穿脱衣服。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 9. 上下楼梯 -->
+            <tr>
+              <td class="col-item" rowspan="3">9. 上下楼梯</td>
+              <td class="col-score">10</td>
+              <td class="col-content">
+                <el-radio :label="10" v-model="form.scores[8]" :disabled="isDetail" @change="calculateTotal">可自行上下楼梯(包括抓扶手、使用拐杖)。</el-radio>
+              </td>
+              <td class="col-result" rowspan="3">
+                <span class="score-display">{{ form.scores[8] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[8]" :disabled="isDetail" @change="calculateTotal">需要稍微帮助或口头指导。</el-radio>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[8]" :disabled="isDetail" @change="calculateTotal">无法上下楼梯。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 10. 洗澡 -->
+            <tr>
+              <td class="col-item" rowspan="2">10. 洗澡</td>
+              <td class="col-score">5</td>
+              <td class="col-content">
+                <el-radio :label="5" v-model="form.scores[9]" :disabled="isDetail" @change="calculateTotal">可独立完成(不论是盆浴或沐浴)。</el-radio>
+              </td>
+              <td class="col-result" rowspan="2">
+                <span class="score-display">{{ form.scores[9] }}</span>
+              </td>
+            </tr>
+            <tr>
+              <td class="col-score">0</td>
+              <td class="col-content">
+                <el-radio :label="0" v-model="form.scores[9]" :disabled="isDetail" @change="calculateTotal">需要别人帮助。</el-radio>
+              </td>
+            </tr>
+
+            <!-- 总分 -->
+            <tr class="total-row">
+              <td class="col-item">总分:</td>
+              <td class="col-score"></td>
+              <td class="col-content"></td>
+              <td class="col-result">
+                <span class="total-score">{{ form.totalScore }} 分</span>
+              </td>
+            </tr>
+          </tbody>
+        </table>
+
+        <!-- 评分结果 -->
+        <div class="result-section">
+          <div class="result-title">评分结果:</div>
+          <div class="result-rules">
+            <el-tag :type="form.totalScore < 20 ? 'danger' : ''" class="rule-tag">&lt;20分:生活完全依赖</el-tag>
+            <el-tag :type="form.totalScore >= 20 && form.totalScore <= 40 ? 'warning' : ''" class="rule-tag">20~40分:生活需要很大帮助</el-tag>
+            <el-tag :type="form.totalScore > 40 && form.totalScore <= 60 ? 'info' : ''" class="rule-tag">40~60分:生活需要帮忙</el-tag>
+            <el-tag :type="form.totalScore > 60 ? 'success' : ''" class="rule-tag">&gt;60分:生活基本自理</el-tag>
+          </div>
+          <div class="current-result" v-if="form.resultLevel">
+            <span class="result-label">当前评估结果:</span>
+            <el-tag :type="getResultTagType(form.resultLevel)" size="large">
+              {{ getResultText(form.resultLevel) }}
+            </el-tag>
+          </div>
+        </div>
+
+        <!-- 评估人签名 -->
+        <div class="assessor-section">
+          <el-form-item label="评估人签名:" label-width="100px">
+            <el-input v-model="form.assessor" :disabled="isDetail" style="width: 300px" />
+          </el-form-item>
+        </div>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-daily-life/create 或 PUT /elderly-assess-daily-life/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="assessData">JSON字符串,包含所有评估数据</el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期(YYYY-MM-DD)</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="section-title" style="margin-top: 15px;">assessData 字段详情</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="scores">10项评分数组 [大便控制, 小便控制, 个人卫生, 入厕, 进食, 床和椅转移, 行走于平地上, 穿脱衣服, 上下楼梯, 洗澡]</el-descriptions-item>
+          <el-descriptions-item label="totalScore">评估总得分(满分100分)</el-descriptions-item>
+          <el-descriptions-item label="resultLevel">结果等级:complete_dependence-生活完全依赖, large_help-生活需要很大帮助, need_help-生活需要帮忙, basic_independent-生活基本自理</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="risk-rules">
+          <div class="rules-title">评分结果规则:</div>
+          <el-tag type="danger" class="rule-tag">&lt;20分:生活完全依赖</el-tag>
+          <el-tag type="warning" class="rule-tag">20~40分:生活需要很大帮助</el-tag>
+          <el-tag type="info" class="rule-tag">40~60分:生活需要帮忙</el-tag>
+          <el-tag type="success" class="rule-tag">&gt;60分:生活基本自理</el-tag>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
+        v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, reactive } from 'vue'
+import dayjs from 'dayjs'
+import {
+  dailyLifeCreate,
+  dailyLifeGetById,
+  dailyLifeUpdate,
+  dailyLifeGetByElderId
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const title = ref('')
+const dialogVisible = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+const isDetail = ref(false)
+const formLoading = ref(false)
+
+let dataForm = ref({
+  id: undefined,
+  elderName: '',
+  elderSex: '',
+  elderAge: '',
+  bedName: '',
+  elderId: '',
+  tenantId: undefined
+})
+
+const elderUp = (e: any) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.elderAge = e.elderAge
+}
+
+// 表单数据 - 10项评估
+const form = reactive({
+  scores: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  // 10项评分
+  totalScore: 0,
+  resultLevel: '',
+  assessDate: '',
+  assessor: ''
+})
+
+// 计算总得分
+const calculateTotal = () => {
+  const total = form.scores.reduce((sum, score) => sum + (score || 0), 0)
+  form.totalScore = total
+
+  // 自动判断结果等级
+  if (total < 20) {
+    form.resultLevel = 'complete_dependence'
+  } else if (total >= 20 && total <= 40) {
+    form.resultLevel = 'large_help'
+  } else if (total > 40 && total <= 60) {
+    form.resultLevel = 'need_help'
+  } else if (total > 60) {
+    form.resultLevel = 'basic_independent'
+  }
+}
+
+// 获取结果等级文本
+const getResultText = (resultLevel: string) => {
+  switch (resultLevel) {
+    case 'complete_dependence': return '生活完全依赖'
+    case 'large_help': return '生活需要很大帮助'
+    case 'need_help': return '生活需要帮忙'
+    case 'basic_independent': return '生活基本自理'
+    default: return '-'
+  }
+}
+
+// 获取结果等级标签类型
+const getResultTagType = (resultLevel: string) => {
+  switch (resultLevel) {
+    case 'complete_dependence': return 'danger'
+    case 'large_help': return 'warning'
+    case 'need_help': return 'info'
+    case 'basic_independent': return 'success'
+    default: return ''
+  }
+}
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    scores: form.scores || [],
+    totalScore: form.totalScore || 0,
+    resultLevel: form.resultLevel || ''
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  if (formData.scores && formData.scores.length > 0) {
+    form.scores = formData.scores
+  } else {
+    form.scores = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+  }
+
+  form.totalScore = formData.totalScore || 0
+  form.resultLevel = formData.resultLevel || ''
+  form.assessor = formData.assessor || ''
+  form.assessDate = formData.assessDate || ''
+}
+
+/** 重置表单数据 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    elderName: '',
+    elderSex: '',
+    elderAge: '',
+    bedName: '',
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  form.scores = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+  form.totalScore = 0
+  form.resultLevel = ''
+  form.assessDate = ''
+  form.assessor = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId: any, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-日常生活活动能力评估表"
+    await loadData(id)
+  } else {
+    title.value = "新增-日常生活活动能力评估表"
+  }
+}
+
+/** 加载评估数据 */
+const loadData = async (id: number) => {
+  try {
+    const res = await dailyLifeGetById(id)
+    if (res) {
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      form.assessDate = res.assessDate || ''
+      form.assessor = res.assessor || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+        calculateTotal()
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+defineExpose({ open })
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (!dataForm.value.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  formLoading.value = true
+  try {
+    const formData = serializeFormData()
+    const payload = {
+      id: dataForm.value.id,
+      elderId: dataForm.value.elderId,
+      tenantId: dataForm.value.tenantId,
+      assessData: JSON.stringify(formData),
+      assessor: form.assessor,
+      assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      await dailyLifeUpdate(payload)
+      message.success(t('common.updateSuccess'))
+    } else {
+      await dailyLifeCreate(payload)
+      message.success(t('common.createSuccess'))
+    }
+    dialogVisible.value = false
+    emit('success')
+  } catch (error) {
+    message.error('提交失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 关闭弹窗 */
+const handleClosed = () => {
+  dialogVisible.value = false
+}
+
+/** 导出/打印 */
+const handleExport = () => {
+  message.info('打印功能开发中')
+}
+
+const rules = {
+  elderName: [{ required: true, message: '请选择长者', trigger: 'change' }]
+}
+</script>
+
+<style scoped lang="scss">
+.assessment-form {
+  padding: 0 20px;
+
+  .form-header {
+    margin-bottom: 20px;
+  }
+
+  .barthel-section {
+    margin-bottom: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      width: 100%;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      border-collapse: collapse;
+
+      thead {
+        background-color: #f5f7fa;
+        font-weight: bold;
+
+        th {
+          padding: 12px;
+          border: 1px solid #e4e7ed;
+          text-align: center;
+        }
+      }
+
+      tbody {
+        tr {
+          border-bottom: 1px solid #e4e7ed;
+
+          &:last-child {
+            border-bottom: none;
+          }
+
+          td {
+            padding: 12px;
+            border: 1px solid #e4e7ed;
+          }
+
+          .col-item {
+            width: 15%;
+            text-align: center;
+            font-weight: bold;
+            vertical-align: middle;
+          }
+
+          .col-score {
+            width: 10%;
+            text-align: center;
+            vertical-align: middle;
+          }
+
+          .col-content {
+            width: 65%;
+            vertical-align: middle;
+
+            .el-radio {
+              white-space: normal;
+              line-height: 1.5;
+              height: auto;
+              margin-right: 0;
+            }
+          }
+
+          .col-result {
+            width: 10%;
+            text-align: center;
+            vertical-align: middle;
+
+            .score-display {
+              font-size: 16px;
+              font-weight: bold;
+              color: #409eff;
+            }
+          }
+        }
+
+        .total-row {
+          background-color: #f5f7fa;
+          font-weight: bold;
+
+          .total-score {
+            font-size: 18px;
+            font-weight: bold;
+            color: #f56c6c;
+          }
+        }
+      }
+    }
+
+    .result-section {
+      margin-top: 15px;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .result-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+      }
+
+      .result-rules {
+        margin-bottom: 15px;
+
+        .rule-tag {
+          margin-right: 10px;
+          margin-bottom: 5px;
+        }
+      }
+
+      .current-result {
+        .result-label {
+          font-weight: bold;
+          margin-right: 10px;
+        }
+      }
+    }
+
+    .assessor-section {
+      margin-top: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+
+    .risk-rules {
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #fff;
+      border-radius: 4px;
+
+      .rules-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #606266;
+      }
+
+      .rule-tag {
+        margin-right: 10px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+}
+</style>

+ 297 - 0
src/views/elderly/apply/nine-precautions/daily-life/index.vue

@@ -0,0 +1,297 @@
+<template>
+  <ContentWrap>
+    <!-- 日常生活活动能力评估表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="totalScore" header-align="center" align="center" label="评估总得分" min-width="120" show-overflow-tooltip/>
+      <el-table-column prop="resultLevel" header-align="center" align="center" label="结果等级" min-width="150" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getResultLevelType(scope.row.resultLevel)">
+            {{ getResultLevelText(scope.row.resultLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from "@/utils/dateUtil";
+import {
+  dailyLifeDelete,
+  dailyLifePage
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const userStore = useUserStore()
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch, count)
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await dailyLifePage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate = getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if (queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1) {
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id, false)
+}
+
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, false)
+}
+
+const openFormDetail = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, true)
+}
+
+const openClose = async (item: any) => {
+  try {
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      try {
+        const res = await dailyLifeDelete(item.id)
+        if (res) {
+          message.success(t('common.updateSuccess'))
+          await getList()
+        }
+      } catch (err) { }
+    }
+  } catch { }
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    await message.cancelConfirm()
+    message.success(t('common.delSuccess'))
+    await getList()
+  } catch { }
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if (route.query && route.query.elderName) {
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// 获取结果等级类型
+const getResultLevelType = (resultLevel: string) => {
+  switch (resultLevel) {
+    case 'complete_dependence': return 'danger'
+    case 'large_help': return 'warning'
+    case 'need_help': return 'info'
+    case 'basic_independent': return 'success'
+    default: return ''
+  }
+}
+
+// 获取结果等级文本
+const getResultLevelText = (resultLevel: string) => {
+  switch (resultLevel) {
+    case 'complete_dependence': return '生活完全依赖'
+    case 'large_help': return '生活需要很大帮助'
+    case 'need_help': return '生活需要帮忙'
+    case 'basic_independent': return '生活基本自理'
+    default: return '-'
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 587 - 0
src/views/elderly/apply/nine-precautions/empyrosis/AddForm.vue

@@ -0,0 +1,587 @@
+<template>
+  <el-drawer v-model="dialogVisible" :title="title" size="90%" :before-close="handleClosed">
+    <div class="assessment-form">
+      <div class="form-header">
+        <el-form :model="dataForm" :rules="rules" ref="formRef" label-width="80px">
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="姓名" prop="elderName">
+                <SelectElder
+                  ref="selectElderRef" :tenantId="dataForm.tenantId" @elder="elderUp" :disabled="isDetail"
+                  v-model="dataForm.elderId" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="年龄">
+                <el-input v-model="dataForm.elderAge" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="性别">
+                <el-input v-model="dataForm.elderSex" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="房号/床号">
+                <el-input v-model="dataForm.bedName" disabled />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
+      <!-- 危险因素评估表 -->
+      <div class="risk-factors-section">
+        <div class="section-title">危险因素评估</div>
+        <table class="assessment-table">
+          <thead>
+            <tr>
+              <th class="col-factor">危险因素</th>
+              <th class="col-score-header">是</th>
+              <th class="col-score-header">否</th>
+              <th class="col-result">得分</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr v-for="(item, itemIndex) in riskFactors" :key="itemIndex">
+              <td class="col-factor">{{ item.name }}</td>
+              <td class="col-score-header">
+                <el-radio-group v-model="form.assessment.scores[itemIndex]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="item.yesScore">{{ item.yesScore }}分</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score-header">
+                <el-radio-group v-model="form.assessment.scores[itemIndex]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="item.noScore">{{ item.noScore }}分</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[itemIndex] }}</td>
+            </tr>
+          </tbody>
+        </table>
+
+        <!-- 风险程度判断 -->
+        <div class="risk-judgment">
+          <span class="judgment-title">风险程度判断:</span>
+          <el-radio-group v-model="form.riskLevel" :disabled="isDetail">
+            <el-radio label="none">无风险:≤1分</el-radio>
+            <el-radio label="low">低风险:2分</el-radio>
+            <el-radio label="medium">中风险:3分</el-radio>
+            <el-radio label="high">高风险:≥4分</el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+
+      <!-- 评估记录 -->
+      <div class="assessment-records">
+        <div class="record-section">
+          <div class="record-header">评估记录</div>
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="评估日期:" label-width="120px">
+                <el-date-picker
+                  v-model="form.assessment.assessDate"
+                  type="date"
+                  placeholder="选择日期"
+                  value-format="YYYY-MM-DD"
+                  :disabled="isDetail"
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="评估人签名:" label-width="120px">
+                <el-input v-model="form.assessment.assessor" :disabled="isDetail" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="评估总得分:" label-width="120px">
+                <span class="score-text">{{ form.assessment.totalScore }} 分</span>
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="风险等级结果:" label-width="120px">
+                <el-tag :type="getRiskTagType(form.riskLevel)">
+                  {{ getRiskText(form.riskLevel) }}
+                </el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+         
+     
+          
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="prevention-section">
+        <div class="section-title">预防措施:</div>
+        <el-checkbox-group v-model="form.preventionMeasures" :disabled="isDetail" class="prevention-group">
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="严禁老人自行冲泡热水袋">严禁老人自行冲泡热水袋</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="严密观察长者,避免接触高温设备">严密观察长者,避免接触高温设备</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="进食,饮水和洗浴时,应测试温度,避免水温过高">进食,饮水和洗浴时,应测试温度,避免水温过高</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="独自洗澡长者做好水温控制先开冷水再开热水,然后将水温调节在45℃再冲洗">独自洗澡长者做好水温控制先开冷水再开热水,然后将水温调节在45℃再冲洗</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="进食热食和热汤时,告知老人待温热后再食用">进食热食和热汤时,告知老人待温热后再食用</el-checkbox>
+            </el-col>
+          </el-row>
+        </el-checkbox-group>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-burn-prevention/create 或 PUT /elderly-assess-burn-prevention/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="elderName">长者姓名</el-descriptions-item>
+          <el-descriptions-item label="elderSex">长者性别</el-descriptions-item>
+          <el-descriptions-item label="elderAge">长者年龄</el-descriptions-item>
+          <el-descriptions-item label="bedName">房号/床号</el-descriptions-item>
+          <el-descriptions-item label="assessData">
+            JSON字符串,包含:<br/>
+            - assessment: 评估记录 {assessDate, assessor, scores[], totalScore}<br/>
+            - preventionMeasures: 预防措施选项数组<br/>
+            - riskLevel: 风险等级(none/low/medium/high)
+          </el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人()</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期(YYYY-MM-DD)</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="risk-rules">
+          <div class="rules-title">风险等级规则:</div>
+          <el-tag type="success" class="rule-tag">≤1分:无风险</el-tag>
+          <el-tag type="info" class="rule-tag">2分:低风险</el-tag>
+          <el-tag type="warning" class="rule-tag">3分:中风险</el-tag>
+          <el-tag type="danger" class="rule-tag">≥4分:高风险</el-tag>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
+        v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive } from 'vue'
+import dayjs from 'dayjs'
+import {
+  burnPreventionCreate,
+  burnPreventionGetById,
+  burnPreventionUpdate,
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const title = ref('')
+const dialogVisible = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+const isDetail = ref(false)
+const formLoading = ref(false)
+
+let dataForm = ref({
+  id: undefined,
+  elderName: '',
+  elderSex: '',
+  elderAge: '',
+  bedName: '',
+  elderId: '',
+  tenantId: undefined
+})
+
+const elderUp = (e: any) => {
+  console.log(e)
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.elderAge = e.elderAge
+}
+
+// 危险因素定义
+const riskFactors = [
+  { name: '意识模糊、烦躁、嗜睡、昏迷等', yesScore: 1, noScore: 0 },
+  { name: '使用镇静催眠剂', yesScore: 1, noScore: 0 },
+  { name: '年龄≥70岁', yesScore: 1, noScore: 0 },
+  { name: '生活不能自理', yesScore: 1, noScore: 0 },
+  { name: '房间有暖水瓶、热水器等', yesScore: 1, noScore: 0 },
+  { name: '进行热疗操作', yesScore: 1, noScore: 0 },
+  { name: '热疗中无陪护', yesScore: 1, noScore: 0 },
+  { name: '使用约束用具', yesScore: 1, noScore: 0 }
+]
+
+// 表单数据
+const form = reactive({
+  assessment: {
+    assessDate: '',
+    assessor: '',
+    scores: new Array(8).fill(0),
+    totalScore: 0
+  },
+  preventionMeasures: [],
+  riskLevel: ''
+})
+
+// 计算总得分
+const calculateTotal = () => {
+  const scores = form.assessment.scores
+  const total = scores.reduce((sum, score) => sum + (score || 0), 0)
+  form.assessment.totalScore = total
+
+  // 自动判断风险等级
+  if (total <= 1) {
+    form.riskLevel = 'none'
+  } else if (total === 2) {
+    form.riskLevel = 'low'
+  } else if (total === 3) {
+    form.riskLevel = 'medium'
+  } else if (total >= 4) {
+    form.riskLevel = 'high'
+  }
+}
+
+// 获取风险等级文本
+const getRiskText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+
+// 获取风险等级标签类型
+const getRiskTagType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    assessment: {
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : '',
+      assessor: form.assessment.assessor || '',
+      scores: form.assessment.scores || [],
+      totalScore: form.assessment.totalScore || 0
+    },
+    preventionMeasures: form.preventionMeasures || [],
+    riskLevel: form.riskLevel || ''
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  if (formData.assessment) {
+    form.assessment.assessDate = formData.assessment.assessDate ? dayjs(formData.assessment.assessDate).toDate() : ''
+    form.assessment.assessor = formData.assessment.assessor || ''
+    form.assessment.scores = formData.assessment.scores || new Array(8).fill(0)
+    form.assessment.totalScore = formData.assessment.totalScore || 0
+  }
+  form.preventionMeasures = formData.preventionMeasures || []
+  form.riskLevel = formData.riskLevel || ''
+}
+
+/** 重置表单数据 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    elderName: '',
+    elderSex: '',
+    elderAge: '',
+    bedName: '',
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  form.assessment = {
+    assessDate: '',
+    assessor: '',
+    scores: new Array(8).fill(0),
+    totalScore: 0
+  }
+  form.preventionMeasures = []
+  form.riskLevel = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId: any, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-防烫伤评估表"
+    await loadData(id)
+  } else {
+    title.value = "新增-防烫伤评估表"
+  }
+}
+
+/** 加载评估数据 */
+const loadData = async (id: number) => {
+  try {
+    const res = await burnPreventionGetById(id)
+    if (res) {
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+defineExpose({ open })
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (!dataForm.value.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  formLoading.value = true
+  try {
+    const formData = serializeFormData()
+    const payload = {
+      id: dataForm.value.id,
+      elderId: dataForm.value.elderId,
+      tenantId: dataForm.value.tenantId,
+      elderName: dataForm.value.elderName,
+      elderSex: dataForm.value.elderSex,
+      elderAge: dataForm.value.elderAge,
+      bedName: dataForm.value.bedName,
+      assessData: JSON.stringify(formData),
+      riskLevel: form.riskLevel,
+      assessor: form.assessment.assessor,
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      await burnPreventionUpdate(payload)
+      message.success(t('common.updateSuccess'))
+    } else {
+      await burnPreventionCreate(payload)
+      message.success(t('common.createSuccess'))
+    }
+    dialogVisible.value = false
+    emit('success')
+  } catch (error) {
+    message.error('提交失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 关闭弹窗 */
+const handleClosed = () => {
+  dialogVisible.value = false
+}
+
+/** 导出/打印 */
+const handleExport = () => {
+  message.info('打印功能开发中')
+}
+
+const rules = {
+  elderName: [{ required: true, message: '请选择长者', trigger: 'change' }]
+}
+</script>
+
+<style scoped lang="scss">
+.assessment-form {
+  padding: 0 20px;
+
+  .form-header {
+    margin-bottom: 20px;
+  }
+
+  .risk-factors-section {
+    margin-bottom: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      width: 100%;
+      border-collapse: collapse;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      overflow: hidden;
+
+      thead {
+        background-color: #f5f7fa;
+        font-weight: bold;
+
+        th {
+          padding: 12px;
+          border: 1px solid #e4e7ed;
+          text-align: center;
+          font-weight: bold;
+        }
+      }
+
+      tbody {
+        td {
+          padding: 12px;
+          border: 1px solid #e4e7ed;
+          vertical-align: middle;
+        }
+      }
+
+      .col-factor {
+        width: 50%;
+        text-align: left;
+      }
+
+      .col-score-header {
+        width: 20%;
+        text-align: center;
+      }
+
+      .col-result {
+        width: 10%;
+        text-align: center;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+
+    .risk-judgment {
+      margin-top: 15px;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .judgment-title {
+        font-weight: bold;
+        margin-right: 15px;
+      }
+    }
+  }
+
+  .assessment-records {
+    margin-top: 20px;
+
+    .record-section {
+      margin-bottom: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+
+      .record-header {
+        font-size: 14px;
+        font-weight: bold;
+        margin-bottom: 15px;
+        color: #409eff;
+        border-bottom: 1px solid #e4e7ed;
+        padding-bottom: 10px;
+      }
+
+      .score-text {
+        font-size: 16px;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+  }
+
+  .prevention-section {
+    margin-top: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .prevention-group {
+      .el-checkbox {
+        margin-bottom: 10px;
+        margin-right: 20px;
+      }
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+
+    .risk-rules {
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #fff;
+      border-radius: 4px;
+
+      .rules-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #606266;
+      }
+
+      .rule-tag {
+        margin-right: 10px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+}
+</style>

+ 297 - 0
src/views/elderly/apply/nine-precautions/empyrosis/index.vue

@@ -0,0 +1,297 @@
+<template>
+  <ContentWrap>
+    <!-- 防烫伤评估表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="totalScore" header-align="center" align="center" label="评估总得分" min-width="120" show-overflow-tooltip/>
+      <el-table-column prop="riskLevel" header-align="center" align="center" label="风险等级" min-width="120" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getRiskLevelType(scope.row.riskLevel)">
+            {{ getRiskLevelText(scope.row.riskLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from "@/utils/dateUtil";
+import {
+  burnPreventionDelete,
+  burnPreventionPage
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const userStore = useUserStore()
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch, count)
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await burnPreventionPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate = getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if (queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1) {
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id, false)
+}
+
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, false)
+}
+
+const openFormDetail = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, true)
+}
+
+const openClose = async (item: any) => {
+  try {
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      try {
+        const res = await burnPreventionDelete(item.id)
+        if (res) {
+          message.success(t('common.updateSuccess'))
+          await getList()
+        }
+      } catch (err) { }
+    }
+  } catch { }
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    await message.cancelConfirm()
+    message.success(t('common.delSuccess'))
+    await getList()
+  } catch { }
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if (route.query && route.query.elderName) {
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// 获取风险等级类型
+const getRiskLevelType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+// 获取风险等级文本
+const getRiskLevelText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 905 - 0
src/views/elderly/apply/nine-precautions/equilibrium/AddForm.vue

@@ -0,0 +1,905 @@
+<template>
+  <el-drawer v-model="dialogVisible" :title="title" size="95%" :before-close="handleClosed">
+    <div class="assessment-form">
+      <div class="form-header">
+        <el-form :model="dataForm" :rules="rules" ref="formRef" label-width="80px">
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="姓名" prop="elderName">
+                <SelectElder ref="selectElderRef" :tenantId="dataForm.tenantId" @elder="elderUp" :disabled="isDetail"
+                  :elderName="dataForm.elderName" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="年龄">
+                <el-input v-model="dataForm.elderAge" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="性别">
+                <el-input v-model="dataForm.elderSex" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="房号/床号">
+                <el-input v-model="dataForm.bedName" disabled />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
+      <!-- 平衡能力测试表 -->
+      <div class="balance-test-section">
+        <div class="section-title">老年人平衡能力测试表</div>
+        <div class="assessment-table">
+          <div class="table-header">
+            <div class="col-category">测试类别</div>
+            <div class="col-item">测试项目</div>
+            <div class="col-desc">描述</div>
+            <div class="col-standard">评分标准</div>
+            <div class="col-score">得分</div>
+          </div>
+
+          <!-- 静态平衡能力 - 双脚并拢站立 -->
+          <div class="table-row">
+            <div class="col-category" rowspan="5">静态平衡能力</div>
+            <div class="col-item">双脚并拢站立</div>
+            <div class="col-desc">双脚同一水平并列靠拢站立,双手自然下垂,保持姿势尽可能超过10秒钟。</div>
+            <div class="col-standard">
+              <div>0分:≥10秒</div>
+              <div>1分:5-9秒</div>
+              <div>2分:0-4秒</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.staticBalance[0]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 静态平衡能力 - 双脚前后位站立 -->
+          <div class="table-row">
+            <div class="col-item">双脚前后位站立</div>
+            <div class="col-desc">双脚成直线一前一后站立,前脚的后跟紧贴后脚的脚尖,双手自然下垂,保持姿势尽可能超过10秒钟。</div>
+            <div class="col-standard">
+              <div>0分:≥10秒</div>
+              <div>1分:5-9秒</div>
+              <div>2分:0-4秒</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.staticBalance[1]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 静态平衡能力 - 闭眼双脚并拢站立 -->
+          <div class="table-row">
+            <div class="col-item">闭眼双脚并拢站立</div>
+            <div class="col-desc">闭上双眼,双脚同一水平并列靠拢站立,双手自然下垂,保持姿势尽可能超过10秒钟。</div>
+            <div class="col-standard">
+              <div>0分:≥10秒</div>
+              <div>1分:5-9秒</div>
+              <div>2分:0-4秒</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.staticBalance[2]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 静态平衡能力 - 不闭眼单腿站立 -->
+          <div class="table-row">
+            <div class="col-item">不闭眼单腿站立</div>
+            <div class="col-desc">双手叉腰,单腿站立,抬起脚离地6厘米以上,保持姿势尽可能超过10秒钟。</div>
+            <div class="col-standard">
+              <div>0分:≥10秒</div>
+              <div>1分:5-9秒</div>
+              <div>2分:0-4秒</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.staticBalance[3]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 静态平衡能力 - 闭眼单腿站立 -->
+          <div class="table-row">
+            <div class="col-item">闭眼单腿站立</div>
+            <div class="col-desc">闭上双眼,双手叉腰,单腿站立,抬起脚离地6厘米以上,保持姿势尽可能超过10秒钟。</div>
+            <div class="col-standard">
+              <div>0分:≥10秒</div>
+              <div>1分:5-9秒</div>
+              <div>2分:0-4秒</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.staticBalance[4]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 姿势控制能力 - 由站立位坐下 -->
+          <div class="table-row">
+            <div class="col-category" rowspan="4">姿势控制能力</div>
+            <div class="col-item">由站立位坐下</div>
+            <div class="col-desc">站在椅子前面,弯曲膝盖和大腿,轻轻坐下。</div>
+            <div class="col-standard">
+              <div>0分:能够轻松坐下起立而不需扶手</div>
+              <div>1分:能够自己坐下起立,但略感吃力,需尝试数次或扶住扶手才能完成</div>
+              <div>2分:不能独立完成动作</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.postureControl[0]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 姿势控制能力 - 由坐姿到站立 -->
+          <div class="table-row">
+            <div class="col-item">由坐姿到站立</div>
+            <div class="col-desc">坐在椅子上,靠腿部力量站起。</div>
+            <div class="col-standard">
+              <div>0分:能够轻松坐下起立而不需扶手</div>
+              <div>1分:能够自己坐下起立,但略感吃力,需尝试数次或扶住扶手才能完成</div>
+              <div>2分:不能独立完成动作</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.postureControl[1]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 姿势控制能力 - 由站立位蹲下 -->
+          <div class="table-row">
+            <div class="col-item">由站立位蹲下</div>
+            <div class="col-desc">双脚分开站立与肩同宽,弯曲膝盖下蹲。</div>
+            <div class="col-standard">
+              <div>0分:能够轻松坐下、蹲下、起立而不需要扶手</div>
+              <div>1分:能够自己蹲下、起立,但略感吃力,需尝试数次或扶住旁边的固定物体才能完成</div>
+              <div>2分:不能独立完成动作</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.postureControl[2]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 姿势控制能力 - 由下蹲姿势到站立 -->
+          <div class="table-row">
+            <div class="col-item">由下蹲姿势到站立</div>
+            <div class="col-desc">由下蹲姿势靠腿部力量站起。</div>
+            <div class="col-standard">
+              <div>0分:能够轻松坐下、蹲下、起立而不需要扶手</div>
+              <div>1分:能够自己蹲下、起立,但略感吃力,需尝试数次或扶住旁边的固定物体才能完成</div>
+              <div>2分:不能独立完成动作</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.postureControl[3]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+                <el-radio :label="2">2</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 动态平衡能力 - 起步 -->
+          <div class="table-row">
+            <div class="col-category" rowspan="8">动态平衡能力</div>
+            <div class="col-item">起步</div>
+            <div class="col-desc">
+              <div>①能立即迈步出发不犹豫。</div>
+              <div>②需要想一想或尝试几次才能迈步。</div>
+            </div>
+            <div class="col-standard">
+              <div>① = 0</div>
+              <div>② = 1</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.dynamicBalance[0]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 动态平衡能力 - 步高 -->
+          <div class="table-row">
+            <div class="col-item">步高</div>
+            <div class="col-desc">
+              <div>①脚抬离地面,干净利落。</div>
+              <div>②脚拖着地面走路。</div>
+            </div>
+            <div class="col-standard">
+              <div>① = 0</div>
+              <div>② = 1</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.dynamicBalance[1]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 动态平衡能力 - 步长 -->
+          <div class="table-row">
+            <div class="col-item">步长</div>
+            <div class="col-desc">
+              <div>①每步跨度长于脚长。</div>
+              <div>②不敢大步走,走小碎步。</div>
+            </div>
+            <div class="col-standard">
+              <div>① = 0</div>
+              <div>② = 1</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.dynamicBalance[2]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 动态平衡能力 - 脚步的匀称性 -->
+          <div class="table-row">
+            <div class="col-item">脚步的匀称性</div>
+            <div class="col-desc">
+              <div>①步子均匀,每步的长度和高度一致。</div>
+              <div>②步子不匀称,时长时短,一脚深一脚浅。</div>
+            </div>
+            <div class="col-standard">
+              <div>① = 0</div>
+              <div>② = 1</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.dynamicBalance[3]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 动态平衡能力 - 步行的连续性 -->
+          <div class="table-row">
+            <div class="col-item">步行的连续性</div>
+            <div class="col-desc">
+              <div>①连续迈步,中间没有停顿。</div>
+              <div>②步子不连贯,有时需要停顿。</div>
+            </div>
+            <div class="col-standard">
+              <div>① = 0</div>
+              <div>② = 1</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.dynamicBalance[4]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 动态平衡能力 - 步行的直线性 -->
+          <div class="table-row">
+            <div class="col-item">步行的直线性</div>
+            <div class="col-desc">
+              <div>①能沿直线行走。</div>
+              <div>②不能走直线,偏向一边。</div>
+            </div>
+            <div class="col-standard">
+              <div>① = 0</div>
+              <div>② = 1</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.dynamicBalance[5]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 动态平衡能力 - 走动时躯干平稳性 -->
+          <div class="table-row">
+            <div class="col-item">走动时躯干平稳性</div>
+            <div class="col-desc">
+              <div>①躯干平稳不左右摇晃。</div>
+              <div>②摇晃或手需向两边伸开来保持平衡。</div>
+            </div>
+            <div class="col-standard">
+              <div>① = 0</div>
+              <div>② = 1</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.dynamicBalance[6]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+
+          <!-- 动态平衡能力 - 走动时转身 -->
+          <div class="table-row">
+            <div class="col-item">走动时转身</div>
+            <div class="col-desc">
+              <div>①躯干平稳,转身连续,转身时步行连续。</div>
+              <div>②摇晃,转身前需停步或转身时脚步有停顿。</div>
+            </div>
+            <div class="col-standard">
+              <div>① = 0</div>
+              <div>② = 1</div>
+            </div>
+            <div class="col-score">
+              <el-radio-group v-model="form.dynamicBalance[7]" :disabled="isDetail" @change="calculateTotal">
+                <el-radio :label="0">0</el-radio>
+                <el-radio :label="1">1</el-radio>
+              </el-radio-group>
+            </div>
+          </div>
+        </div>
+
+        <!-- 风险程度判断 -->
+        <div class="risk-judgment">
+          <span class="judgment-title">风险程度判断:</span>
+          <el-radio-group v-model="form.riskLevel" :disabled="isDetail">
+            <el-radio label="none">无风险:0分</el-radio>
+            <el-radio label="low">低风险:1-4分</el-radio>
+            <el-radio label="medium">中风险:5-16分</el-radio>
+            <el-radio label="high">高风险:≥17分</el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+
+      <!-- 评估记录 -->
+      <div class="assessment-records">
+        <div class="record-section">
+          <div class="record-header">评估记录</div>
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="评估日期:" label-width="120px">
+                <el-date-picker
+                  v-model="form.assessDate"
+                  type="date"
+                  placeholder="选择日期"
+                  value-format="YYYY-MM-DD"
+                  :disabled="isDetail"
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="评估人签名:" label-width="120px">
+                <el-input v-model="form.assessor" :disabled="isDetail" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="评估总得分:" label-width="120px">
+                <span class="score-text">{{ form.totalScore }} 分</span>
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="风险等级结果:" label-width="120px">
+                <el-tag :type="getRiskTagType(form.riskLevel)">
+                  {{ getRiskText(form.riskLevel) }}
+                </el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-equilibrium/create 或 PUT /elderly-assess-equilibrium/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="elderName">长者姓名</el-descriptions-item>
+          <el-descriptions-item label="elderSex">长者性别</el-descriptions-item>
+          <el-descriptions-item label="elderAge">长者年龄</el-descriptions-item>
+          <el-descriptions-item label="bedName">房号/床号</el-descriptions-item>
+          <el-descriptions-item label="assessData">
+            JSON字符串,包含:<br/>
+            - staticBalance: 静态平衡能力数组 [5项,每项0-2分]<br/>
+            - postureControl: 姿势控制能力数组 [4项,每项0-2分]<br/>
+            - dynamicBalance: 动态平衡能力数组 [8项,每项0-1分]<br/>
+            - totalScore: 评估总得分<br/>
+            - riskLevel: 风险等级(none/low/medium/high)
+          </el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期(YYYY-MM-DD)</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="risk-rules">
+          <div class="rules-title">风险等级规则:</div>
+          <el-tag type="success" class="rule-tag">0分:无风险</el-tag>
+          <el-tag type="info" class="rule-tag">1-4分:低风险</el-tag>
+          <el-tag type="warning" class="rule-tag">5-16分:中风险</el-tag>
+          <el-tag type="danger" class="rule-tag">≥17分:高风险</el-tag>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
+        v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, reactive } from 'vue'
+import dayjs from 'dayjs'
+import {
+  equilibriumCreate,
+  equilibriumGetById,
+  equilibriumUpdate,
+  equilibriumGetByElderId
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const title = ref('')
+const dialogVisible = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+const isDetail = ref(false)
+const formLoading = ref(false)
+
+let dataForm = ref({
+  id: undefined,
+  elderName: '',
+  elderSex: '',
+  elderAge: '',
+  bedName: '',
+  elderId: '',
+  tenantId: undefined
+})
+
+const elderUp = (e: any) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.elderAge = e.elderAge
+}
+
+// 表单数据
+const form = reactive({
+  staticBalance: [0, 0, 0, 0, 0],      // 静态平衡能力 5项
+  postureControl: [0, 0, 0, 0],        // 姿势控制能力 4项
+  dynamicBalance: [0, 0, 0, 0, 0, 0, 0, 0], // 动态平衡能力 8项
+  totalScore: 0,
+  riskLevel: '',
+  assessDate: '',
+  assessor: ''
+})
+
+// 计算总得分
+const calculateTotal = () => {
+  const staticTotal = form.staticBalance.reduce((sum, score) => sum + (score || 0), 0)
+  const postureTotal = form.postureControl.reduce((sum, score) => sum + (score || 0), 0)
+  const dynamicTotal = form.dynamicBalance.reduce((sum, score) => sum + (score || 0), 0)
+  const total = staticTotal + postureTotal + dynamicTotal
+  form.totalScore = total
+
+  // 自动判断风险等级
+  if (total === 0) {
+    form.riskLevel = 'none'
+  } else if (total >= 1 && total <= 4) {
+    form.riskLevel = 'low'
+  } else if (total >= 5 && total <= 16) {
+    form.riskLevel = 'medium'
+  } else if (total >= 17) {
+    form.riskLevel = 'high'
+  }
+}
+
+// 获取风险等级文本
+const getRiskText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+
+// 获取风险等级标签类型
+const getRiskTagType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    staticBalance: form.staticBalance || [],
+    postureControl: form.postureControl || [],
+    dynamicBalance: form.dynamicBalance || [],
+    totalScore: form.totalScore || 0,
+    riskLevel: form.riskLevel || ''
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  if (formData.staticBalance && formData.staticBalance.length > 0) {
+    form.staticBalance = formData.staticBalance
+  } else {
+    form.staticBalance = [0, 0, 0, 0, 0]
+  }
+
+  if (formData.postureControl && formData.postureControl.length > 0) {
+    form.postureControl = formData.postureControl
+  } else {
+    form.postureControl = [0, 0, 0, 0]
+  }
+
+  if (formData.dynamicBalance && formData.dynamicBalance.length > 0) {
+    form.dynamicBalance = formData.dynamicBalance
+  } else {
+    form.dynamicBalance = [0, 0, 0, 0, 0, 0, 0, 0]
+  }
+
+  form.totalScore = formData.totalScore || 0
+  form.riskLevel = formData.riskLevel || ''
+}
+
+/** 重置表单数据 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    elderName: '',
+    elderSex: '',
+    elderAge: '',
+    bedName: '',
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  form.staticBalance = [0, 0, 0, 0, 0]
+  form.postureControl = [0, 0, 0, 0]
+  form.dynamicBalance = [0, 0, 0, 0, 0, 0, 0, 0]
+  form.totalScore = 0
+  form.riskLevel = ''
+  form.assessDate = ''
+  form.assessor = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId: any, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-老年人平衡能力测试表"
+    await loadData(id)
+  } else {
+    title.value = "新增-老年人平衡能力测试表"
+  }
+}
+
+/** 加载评估数据 */
+const loadData = async (id: number) => {
+  try {
+    const res = await equilibriumGetById(id)
+    if (res) {
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      form.assessDate = res.assessDate || ''
+      form.assessor = res.assessor || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+        calculateTotal()
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+defineExpose({ open })
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (!dataForm.value.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  formLoading.value = true
+  try {
+    const formData = serializeFormData()
+    const payload = {
+      id: dataForm.value.id,
+      elderId: dataForm.value.elderId,
+      tenantId: dataForm.value.tenantId,
+      elderName: dataForm.value.elderName,
+      elderSex: dataForm.value.elderSex,
+      elderAge: dataForm.value.elderAge,
+      bedName: dataForm.value.bedName,
+      assessData: JSON.stringify(formData),
+      assessor: form.assessor,
+      assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      await equilibriumUpdate(payload)
+      message.success(t('common.updateSuccess'))
+    } else {
+      await equilibriumCreate(payload)
+      message.success(t('common.createSuccess'))
+    }
+    dialogVisible.value = false
+    emit('success')
+  } catch (error) {
+    message.error('提交失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 关闭弹窗 */
+const handleClosed = () => {
+  dialogVisible.value = false
+}
+
+/** 导出/打印 */
+const handleExport = () => {
+  message.info('打印功能开发中')
+}
+
+const rules = {
+  elderName: [{ required: true, message: '请选择长者', trigger: 'change' }]
+}
+</script>
+
+<style scoped lang="scss">
+.assessment-form {
+  padding: 0 20px;
+
+  .form-header {
+    margin-bottom: 20px;
+  }
+
+  .balance-test-section {
+    margin-bottom: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      overflow: hidden;
+
+      .table-header {
+        display: flex;
+        background-color: #f5f7fa;
+        font-weight: bold;
+        border-bottom: 1px solid #e4e7ed;
+
+        .col-category {
+          width: 10%;
+          padding: 12px;
+          border-right: 1px solid #e4e7ed;
+          text-align: center;
+        }
+
+        .col-item {
+          width: 12%;
+          padding: 12px;
+          border-right: 1px solid #e4e7ed;
+          text-align: center;
+        }
+
+        .col-desc {
+          width: 35%;
+          padding: 12px;
+          border-right: 1px solid #e4e7ed;
+          text-align: center;
+        }
+
+        .col-standard {
+          width: 30%;
+          padding: 12px;
+          border-right: 1px solid #e4e7ed;
+          text-align: center;
+        }
+
+        .col-score {
+          width: 13%;
+          padding: 12px;
+          text-align: center;
+        }
+      }
+
+      .table-row {
+        display: flex;
+        border-bottom: 1px solid #e4e7ed;
+
+        &:last-child {
+          border-bottom: none;
+        }
+
+        .col-category {
+          width: 10%;
+          padding: 12px;
+          border-right: 1px solid #e4e7ed;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-weight: bold;
+        }
+
+        .col-item {
+          width: 12%;
+          padding: 12px;
+          border-right: 1px solid #e4e7ed;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-weight: bold;
+        }
+
+        .col-desc {
+          width: 35%;
+          padding: 12px;
+          border-right: 1px solid #e4e7ed;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          line-height: 1.6;
+        }
+
+        .col-standard {
+          width: 30%;
+          padding: 12px;
+          border-right: 1px solid #e4e7ed;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          line-height: 1.6;
+        }
+
+        .col-score {
+          width: 13%;
+          padding: 12px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+
+          .el-radio-group {
+            display: flex;
+            flex-direction: row;
+            gap: 8px;
+          }
+        }
+      }
+    }
+
+    .risk-judgment {
+      margin-top: 15px;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .judgment-title {
+        font-weight: bold;
+        margin-right: 15px;
+      }
+    }
+  }
+
+  .assessment-records {
+    margin-top: 20px;
+
+    .record-section {
+      margin-bottom: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+
+      .record-header {
+        font-size: 14px;
+        font-weight: bold;
+        margin-bottom: 15px;
+        color: #409eff;
+        border-bottom: 1px solid #e4e7ed;
+        padding-bottom: 10px;
+      }
+
+      .score-text {
+        font-size: 16px;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+
+    .risk-rules {
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #fff;
+      border-radius: 4px;
+
+      .rules-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #606266;
+      }
+
+      .rule-tag {
+        margin-right: 10px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+}
+</style>

+ 297 - 0
src/views/elderly/apply/nine-precautions/equilibrium/index.vue

@@ -0,0 +1,297 @@
+<template>
+  <ContentWrap>
+    <!-- 老年人平衡能力测试表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="totalScore" header-align="center" align="center" label="评估总得分" min-width="120" show-overflow-tooltip/>
+      <el-table-column prop="riskLevel" header-align="center" align="center" label="风险等级" min-width="120" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getRiskLevelType(scope.row.riskLevel)">
+            {{ getRiskLevelText(scope.row.riskLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from "@/utils/dateUtil";
+import {
+  equilibriumDelete,
+  equilibriumPage
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const userStore = useUserStore()
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch, count)
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await equilibriumPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate = getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if (queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1) {
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id, false)
+}
+
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, false)
+}
+
+const openFormDetail = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, true)
+}
+
+const openClose = async (item: any) => {
+  try {
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      try {
+        const res = await equilibriumDelete(item.id)
+        if (res) {
+          message.success(t('common.updateSuccess'))
+          await getList()
+        }
+      } catch (err) { }
+    }
+  } catch { }
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    await message.cancelConfirm()
+    message.success(t('common.delSuccess'))
+    await getList()
+  } catch { }
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if (route.query && route.query.elderName) {
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// 获取风险等级类型
+const getRiskLevelType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+// 获取风险等级文本
+const getRiskLevelText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 630 - 0
src/views/elderly/apply/nine-precautions/fall-down/AddForm.vue

@@ -0,0 +1,630 @@
+<template>
+  <el-drawer v-model="dialogVisible" :title="title" size="90%" :before-close="handleClosed">
+    <div class="assessment-form">
+      <div class="form-header">
+        <el-form :model="dataForm" :rules="rules" ref="formRef" label-width="80px">
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="姓名" prop="elderName">
+                <SelectElder ref="selectElderRef" :tenantId="dataForm.tenantId" @elder="elderUp" :disabled="isDetail"
+                  :elderName="dataForm.elderName" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="年龄">
+                <el-input v-model="dataForm.elderAge" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="性别">
+                <el-input v-model="dataForm.elderSex" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="房号/床号">
+                <el-input v-model="dataForm.bedName" disabled />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
+      <!-- 危险因素评估表 -->
+      <div class="risk-factors-section">
+        <div class="section-title">危险因素评估</div>
+        <table class="assessment-table">
+          <thead>
+            <tr>
+              <th class="col-factor">危险因素</th>
+              <th class="col-standard">评估标准(分)</th>
+              <th class="col-score">得分</th>
+            </tr>
+          </thead>
+          <tbody>
+            <!-- 跌倒史 -->
+            <tr>
+              <td class="col-factor">跌倒史</td>
+              <td class="col-standard">
+                <el-radio-group v-model="form.assessment.scores[0]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="25">有=25</el-radio>
+                  <el-radio :label="0">无=0</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">{{ form.assessment.scores[0] }}</td>
+            </tr>
+
+            <!-- 超过一个医学诊断 -->
+            <tr>
+              <td class="col-factor">超过一个医学诊断</td>
+              <td class="col-standard">
+                <el-radio-group v-model="form.assessment.scores[1]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="15">有=15</el-radio>
+                  <el-radio :label="0">无=0</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">{{ form.assessment.scores[1] }}</td>
+            </tr>
+
+            <!-- 使用助行器具 -->
+            <tr>
+              <td class="col-factor">使用助行器具</td>
+              <td class="col-standard">
+                <el-radio-group v-model="form.assessment.scores[2]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="0">无/卧床/坐轮椅/护士协助=0</el-radio>
+                  <el-radio :label="15">拐杖/手杖/助行器=15</el-radio>
+                  <el-radio :label="30">依扶家具/墙壁=30</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">{{ form.assessment.scores[2] }}</td>
+            </tr>
+
+            <!-- 静脉输液/肝素锁 -->
+            <tr>
+              <td class="col-factor">静脉输液/肝素锁</td>
+              <td class="col-standard">
+                <el-radio-group v-model="form.assessment.scores[3]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="20">有=20</el-radio>
+                  <el-radio :label="0">无=0</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">{{ form.assessment.scores[3] }}</td>
+            </tr>
+
+            <!-- 步态 -->
+            <tr>
+              <td class="col-factor">步态</td>
+              <td class="col-standard">
+                <el-radio-group v-model="form.assessment.scores[4]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="0">正常/卧床/不能移动=0</el-radio>
+                  <el-radio :label="10">虚弱=10(指乏力)</el-radio>
+                  <el-radio :label="20">受损=20(指患者从椅子上站立困难,起立时需要借助椅背或多次尝试,残疾或功能障碍)</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">{{ form.assessment.scores[4] }}</td>
+            </tr>
+
+            <!-- 精神状态 -->
+            <tr>
+              <td class="col-factor">精神状态</td>
+              <td class="col-standard">
+                <el-radio-group v-model="form.assessment.scores[5]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="15">高估或忘记限制=15</el-radio>
+                  <el-radio :label="0">正确评估自己能力=0</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">{{ form.assessment.scores[5] }}</td>
+            </tr>
+          </tbody>
+        </table>
+
+        <!-- 风险程度判断 -->
+        <div class="risk-judgment">
+          <span class="judgment-title">风险程度判断:</span>
+          <el-radio-group v-model="form.riskLevel" :disabled="isDetail">
+            <el-radio label="none">无风险:0分</el-radio>
+            <el-radio label="low">低风险:10-24分</el-radio>
+            <el-radio label="medium">中风险:25-45分</el-radio>
+            <el-radio label="high">高风险:≥46分</el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+
+      <!-- 评估记录 -->
+      <div class="assessment-records">
+        <div class="record-section">
+          <div class="record-header">评估记录</div>
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="评估日期:" label-width="120px">
+                <el-date-picker
+                  v-model="form.assessment.assessDate"
+                  type="date"
+                  placeholder="选择日期"
+                  value-format="YYYY-MM-DD"
+                  :disabled="isDetail"
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="评估人签名:" label-width="120px">
+                <el-input v-model="form.assessment.assessor" :disabled="isDetail" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="评估总得分:" label-width="120px">
+                <span class="score-text">{{ form.assessment.totalScore }} 分</span>
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="风险等级结果:" label-width="120px">
+                <el-tag :type="getRiskTagType(form.riskLevel)">
+                  {{ getRiskText(form.riskLevel) }}
+                </el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="prevention-section">
+        <div class="section-title">预防措施:</div>
+        <el-checkbox-group v-model="form.preventionMeasures" :disabled="isDetail" class="prevention-group">
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="保持房间和周围环境安全,光线充足、无杂物,地面干燥避免湿滑">保持房间和周围环境安全,光线充足、无杂物,地面干燥避免湿滑</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="下床活动的动作宜缓慢,先在床边坐5-10分钟,无头晕等不适时再下床活动">下床活动的动作宜缓慢,先在床边坐5-10分钟,无头晕等不适时再下床活动</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="避免衣裤过长及鞋子过大,选择防滑鞋">避免衣裤过长及鞋子过大,选择防滑鞋</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="当有需要而护理员不在旁时请呼叫铃">当有需要而护理员不在旁时请呼叫铃</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="上下楼梯时,要扶好扶手">上下楼梯时,要扶好扶手</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="选择合适的手杖或步行器">选择合适的手杖或步行器</el-checkbox>
+            </el-col>
+          </el-row>
+        </el-checkbox-group>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-fall-down/create 或 PUT /elderly-assess-fall-down/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="elderName">长者姓名</el-descriptions-item>
+          <el-descriptions-item label="elderSex">长者性别</el-descriptions-item>
+          <el-descriptions-item label="elderAge">长者年龄</el-descriptions-item>
+          <el-descriptions-item label="bedName">房号/床号</el-descriptions-item>
+          <el-descriptions-item label="assessData">
+            JSON字符串,包含:<br/>
+            - assessment: 评估记录 {assessDate, assessor, scores[], totalScore}<br/>
+            - preventionMeasures: 预防措施选项数组<br/>
+            - riskLevel: 风险等级(none/low/medium/high)
+          </el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人()</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期(YYYY-MM-DD)</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="risk-rules">
+          <div class="rules-title">风险等级规则:</div>
+          <el-tag type="success" class="rule-tag">0分:无风险</el-tag>
+          <el-tag type="info" class="rule-tag">10-24分:低风险</el-tag>
+          <el-tag type="warning" class="rule-tag">25-45分:中风险</el-tag>
+          <el-tag type="danger" class="rule-tag">≥46分:高风险</el-tag>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button
+        style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
+        v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, reactive } from 'vue'
+import dayjs from 'dayjs'
+import {
+  fallDownCreate,
+  fallDownGetById,
+  fallDownUpdate,
+  fallDownGetByElderId
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const title = ref('')
+const dialogVisible = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+const isDetail = ref(false)
+const formLoading = ref(false)
+
+let dataForm = ref({
+  id: undefined,
+  elderName: '',
+  elderSex: '',
+  elderAge: '',
+  bedName: '',
+  elderId: '',
+  tenantId: undefined
+})
+
+const elderUp = (e: any) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.elderAge = e.elderAge
+}
+
+// 表单数据
+const form = reactive({
+  assessment: {
+    assessDate: '',
+    assessor: '',
+    scores: new Array(6).fill(0),
+    totalScore: 0
+  },
+  preventionMeasures: [],
+  riskLevel: ''
+})
+
+// 计算总得分
+const calculateTotal = () => {
+  const scores = form.assessment.scores
+  const total = scores.reduce((sum, score) => sum + (score || 0), 0)
+  form.assessment.totalScore = total
+
+  // 自动判断风险等级
+  if (total === 0) {
+    form.riskLevel = 'none'
+  } else if (total >= 10 && total <= 24) {
+    form.riskLevel = 'low'
+  } else if (total >= 25 && total <= 45) {
+    form.riskLevel = 'medium'
+  } else if (total >= 46) {
+    form.riskLevel = 'high'
+  }
+}
+
+// 获取风险等级文本
+const getRiskText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+
+// 获取风险等级标签类型
+const getRiskTagType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    assessment: {
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : '',
+      assessor: form.assessment.assessor || '',
+      scores: form.assessment.scores || [],
+      totalScore: form.assessment.totalScore || 0
+    },
+    preventionMeasures: form.preventionMeasures || [],
+    riskLevel: form.riskLevel
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  if (formData.assessment) {
+    form.assessment.assessDate = formData.assessment.assessDate ? dayjs(formData.assessment.assessDate).toDate() : ''
+    form.assessment.assessor = formData.assessment.assessor || ''
+    form.assessment.scores = formData.assessment.scores || new Array(6).fill(0)
+    form.assessment.totalScore = formData.assessment.totalScore || 0
+  }
+  form.preventionMeasures = formData.preventionMeasures || []
+  form.riskLevel = formData.riskLevel || ''
+}
+
+/** 重置表单数据 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    elderName: '',
+    elderSex: '',
+    elderAge: '',
+    bedName: '',
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  form.assessment = {
+    assessDate: '',
+    assessor: '',
+    scores: new Array(6).fill(0),
+    totalScore: 0
+  }
+  form.preventionMeasures = []
+  form.riskLevel = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId: any, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-跌倒风险评估表"
+    await loadData(id)
+  } else {
+    title.value = "新增-跌倒风险评估表"
+  }
+}
+
+/** 加载评估数据 */
+const loadData = async (id: number) => {
+  try {
+    const res = await fallDownGetById(id)
+    if (res) {
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+defineExpose({ open })
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (!dataForm.value.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  formLoading.value = true
+  try {
+    const formData = serializeFormData()
+    const payload = {
+      id: dataForm.value.id,
+      elderId: dataForm.value.elderId,
+      tenantId: dataForm.value.tenantId,
+      elderName: dataForm.value.elderName,
+      elderSex: dataForm.value.elderSex,
+      elderAge: dataForm.value.elderAge,
+      bedName: dataForm.value.bedName,
+      assessData: JSON.stringify(formData),
+      riskLevel: form.riskLevel,
+      assessor: form.assessment.assessor,
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      await fallDownUpdate(payload)
+      message.success(t('common.updateSuccess'))
+    } else {
+      await fallDownCreate(payload)
+      message.success(t('common.createSuccess'))
+    }
+    dialogVisible.value = false
+    emit('success')
+  } catch (error) {
+    message.error('提交失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 关闭弹窗 */
+const handleClosed = () => {
+  dialogVisible.value = false
+}
+
+/** 导出/打印 */
+const handleExport = () => {
+  message.info('打印功能开发中')
+}
+
+const rules = {
+  elderName: [{ required: true, message: '请选择长者', trigger: 'change' }]
+}
+</script>
+
+<style scoped lang="scss">
+.assessment-form {
+  padding: 0 20px;
+
+  .form-header {
+    margin-bottom: 20px;
+  }
+
+  .risk-factors-section {
+    margin-bottom: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      width: 100%;
+      border-collapse: collapse;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      overflow: hidden;
+
+      th, td {
+        padding: 12px;
+        border: 1px solid #e4e7ed;
+      }
+
+      thead {
+        background-color: #f5f7fa;
+        font-weight: bold;
+      }
+
+      .col-factor {
+        width: 15%;
+        text-align: center;
+        font-weight: bold;
+      }
+
+      .col-standard {
+        width: 75%;
+        text-align: left;
+
+        .el-radio-group {
+          display: flex;
+          flex-direction: column;
+          gap: 8px;
+        }
+      }
+
+      .col-score {
+        width: 10%;
+        text-align: center;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+
+    .risk-judgment {
+      margin-top: 15px;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .judgment-title {
+        font-weight: bold;
+        margin-right: 15px;
+      }
+    }
+  }
+
+  .assessment-records {
+    margin-top: 20px;
+
+    .record-section {
+      margin-bottom: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+
+      .record-header {
+        font-size: 14px;
+        font-weight: bold;
+        margin-bottom: 15px;
+        color: #409eff;
+        border-bottom: 1px solid #e4e7ed;
+        padding-bottom: 10px;
+      }
+
+      .score-text {
+        font-size: 16px;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+  }
+
+  .prevention-section {
+    margin-top: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .prevention-group {
+      .el-checkbox {
+        margin-bottom: 10px;
+        margin-right: 20px;
+      }
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+
+    .risk-rules {
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #fff;
+      border-radius: 4px;
+
+      .rules-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #606266;
+      }
+
+      .rule-tag {
+        margin-right: 10px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+}
+</style>

+ 297 - 0
src/views/elderly/apply/nine-precautions/fall-down/index.vue

@@ -0,0 +1,297 @@
+<template>
+  <ContentWrap>
+    <!-- 跌倒风险评估表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="totalScore" header-align="center" align="center" label="评估总得分" min-width="120" show-overflow-tooltip/>
+      <el-table-column prop="riskLevel" header-align="center" align="center" label="风险等级" min-width="120" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getRiskLevelType(scope.row.riskLevel)">
+            {{ getRiskLevelText(scope.row.riskLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from "@/utils/dateUtil";
+import {
+  fallDownDelete,
+  fallDownPage
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const userStore = useUserStore()
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch, count)
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await fallDownPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate = getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if (queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1) {
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id, false)
+}
+
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, false)
+}
+
+const openFormDetail = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, true)
+}
+
+const openClose = async (item: any) => {
+  try {
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      try {
+        const res = await fallDownDelete(item.id)
+        if (res) {
+          message.success(t('common.updateSuccess'))
+          await getList()
+        }
+      } catch (err) { }
+    }
+  } catch { }
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    await message.cancelConfirm()
+    message.success(t('common.delSuccess'))
+    await getList()
+  } catch { }
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if (route.query && route.query.elderName) {
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// 获取风险等级类型
+const getRiskLevelType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+// 获取风险等级文本
+const getRiskLevelText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 579 - 0
src/views/elderly/apply/nine-precautions/fall-prevention-measures/AddForm.vue

@@ -0,0 +1,579 @@
+<template>
+  <el-drawer v-model="dialogVisible" :title="title" size="90%" :before-close="handleClosed">
+    <div class="assessment-form">
+      <div class="form-header">
+        <el-form :model="dataForm" :rules="rules" ref="formRef" label-width="80px">
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="姓名" prop="elderName">
+                <SelectElder ref="selectElderRef" :tenantId="dataForm.tenantId" @elder="elderUp" :disabled="isDetail"
+                  :elderName="dataForm.elderName" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="年龄">
+                <el-input v-model="dataForm.elderAge" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="性别">
+                <el-input v-model="dataForm.elderSex" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="房号/床号">
+                <el-input v-model="dataForm.bedName" disabled />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
+      <!-- 危险因素评估表 -->
+      <div class="risk-factors-section">
+        <div class="section-title">危险因素评估</div>
+        <table class="assessment-table">
+          <thead>
+            <tr>
+              <th class="col-factor">危险因素</th>
+              <th class="col-score-header">是</th>
+              <th class="col-score-header">否</th>
+              <th class="col-result">得分</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr v-for="(item, itemIndex) in riskFactors" :key="itemIndex">
+              <td class="col-factor">{{ item.name }}</td>
+              <td class="col-score-header">
+                <el-radio-group v-model="form.assessment.scores[itemIndex]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="item.yesScore">{{ item.yesScore }}分</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score-header">
+                <el-radio-group v-model="form.assessment.scores[itemIndex]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="item.noScore">{{ item.noScore }}分</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[itemIndex] }}</td>
+            </tr>
+          </tbody>
+        </table>
+
+        <!-- 风险程度判断 -->
+        <div class="risk-judgment">
+          <span class="judgment-title">风险程度判断:</span>
+          <el-radio-group v-model="form.riskLevel" :disabled="isDetail">
+            <el-radio label="none">无风险:≤1分</el-radio>
+            <el-radio label="low">低风险:2分</el-radio>
+            <el-radio label="medium">中风险:3分</el-radio>
+            <el-radio label="high">高风险:≥4分</el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+
+      <!-- 评估记录 -->
+      <div class="assessment-records">
+        <div class="record-section">
+          <div class="record-header">评估记录</div>
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="评估日期:" label-width="120px">
+                <el-date-picker
+                  v-model="form.assessment.assessDate"
+                  type="date"
+                  placeholder="选择日期"
+                  value-format="YYYY-MM-DD"
+                  :disabled="isDetail"
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="评估人签名:" label-width="120px">
+                <el-input v-model="form.assessment.assessor" :disabled="isDetail" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="评估总得分:" label-width="120px">
+                <span class="score-text">{{ form.assessment.totalScore }} 分</span>
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="风险等级结果:" label-width="120px">
+                <el-tag :type="getRiskTagType(form.riskLevel)">
+                  {{ getRiskText(form.riskLevel) }}
+                </el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="prevention-section">
+        <div class="section-title">预防措施:</div>
+        <el-checkbox-group v-model="form.preventionMeasures" :disabled="isDetail" class="prevention-group">
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="加勤巡视,随时发现安全隐患">加勤巡视,随时发现安全隐患</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="睡觉时拉起两侧床栏如需下床请将床栏放下,切勿翻越床栏">睡觉时拉起两侧床栏如需下床请将床栏放下,切勿翻越床栏</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="常检查床的牢固性,发现不稳定时立即对床进行加固">常检查床的牢固性,发现不稳定时立即对床进行加固</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="发现老人睡在床边缘时,应将老人调整到床中央">发现老人睡在床边缘时,应将老人调整到床中央</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="翻身时叮嘱老人动作要慢,幅度要小确保安全">翻身时叮嘱老人动作要慢,幅度要小确保安全</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="将生活用品、尿壶便器等放于易拿之处">将生活用品、尿壶便器等放于易拿之处</el-checkbox>
+            </el-col>
+          </el-row>
+        </el-checkbox-group>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-fall-prevention/create 或 PUT /elderly-assess-fall-prevention/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="elderName">长者姓名</el-descriptions-item>
+          <el-descriptions-item label="elderSex">长者性别</el-descriptions-item>
+          <el-descriptions-item label="elderAge">长者年龄</el-descriptions-item>
+          <el-descriptions-item label="bedName">房号/床号</el-descriptions-item>
+          <el-descriptions-item label="assessData">
+            JSON字符串,包含:<br/>
+            - assessment: 评估记录 {assessDate, assessor, scores[], totalScore}<br/>
+            - preventionMeasures: 预防措施选项数组<br/>
+            - riskLevel: 风险等级(none/low/medium/high)
+          </el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人()</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期(YYYY-MM-DD)</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="risk-rules">
+          <div class="rules-title">风险等级规则:</div>
+          <el-tag type="success" class="rule-tag">≤1分:无风险</el-tag>
+          <el-tag type="info" class="rule-tag">2分:低风险</el-tag>
+          <el-tag type="warning" class="rule-tag">3分:中风险</el-tag>
+          <el-tag type="danger" class="rule-tag">≥4分:高风险</el-tag>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
+        v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, reactive } from 'vue'
+import dayjs from 'dayjs'
+import {
+  fallPreventionCreate,
+  fallPreventionGetById,
+  fallPreventionUpdate,
+  fallPreventionGetByElderId
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const title = ref('')
+const dialogVisible = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+const isDetail = ref(false)
+const formLoading = ref(false)
+
+let dataForm = ref({
+  id: undefined,
+  elderName: '',
+  elderSex: '',
+  elderAge: '',
+  bedName: '',
+  elderId: '',
+  tenantId: undefined
+})
+
+const elderUp = (e: any) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.elderAge = e.elderAge
+}
+
+// 危险因素定义
+const riskFactors = [
+  { name: '最近一年曾有不明原因的坠床或跌倒经历', yesScore: 1, noScore: 0 },
+  { name: '意识障碍', yesScore: 1, noScore: 0 },
+  { name: '近期有癫痫病史', yesScore: 1, noScore: 0 },
+  { name: '视力障碍', yesScore: 1, noScore: 0 },
+  { name: '活动障碍,肢体偏瘫', yesScore: 3, noScore: 0 },
+  { name: '年龄大于或等于 65 岁', yesScore: 1, noScore: 0 },
+  { name: '体能虚弱', yesScore: 3, noScore: 0 },
+  { name: '头晕、眩晕、体位性低血压', yesScore: 2, noScore: 0 },
+  { name: '服用影响意识或行动的药物,如催眠剂、镇静安神药物,利尿剂、抗癫痫剂、麻醉止痛剂', yesScore: 1, noScore: 0 },
+  { name: '吸毒、酗酒史', yesScore: 1, noScore: 0 },
+  { name: '住院中无人陪伴', yesScore: 1, noScore: 0 },
+  { name: '睡气垫床', yesScore: 1, noScore: 0 }
+]
+
+// 表单数据
+const form = reactive({
+  assessment: {
+    assessDate: '',
+    assessor: '',
+    scores: new Array(12).fill(0),
+    totalScore: 0
+  },
+  preventionMeasures: [],
+  riskLevel: ''
+})
+
+// 计算总得分
+const calculateTotal = () => {
+  const scores = form.assessment.scores
+  const total = scores.reduce((sum, score) => sum + (score || 0), 0)
+  form.assessment.totalScore = total
+
+  // 自动判断风险等级
+  if (total <= 1) {
+    form.riskLevel = 'none'
+  } else if (total === 2) {
+    form.riskLevel = 'low'
+  } else if (total === 3) {
+    form.riskLevel = 'medium'
+  } else if (total >= 4) {
+    form.riskLevel = 'high'
+  }
+}
+
+// 获取风险等级文本
+const getRiskText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+
+// 获取风险等级标签类型
+const getRiskTagType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    assessment: {
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : '',
+      assessor: form.assessment.assessor || '',
+      scores: form.assessment.scores || [],
+      totalScore: form.assessment.totalScore || 0
+    },
+    preventionMeasures: form.preventionMeasures || [],
+    riskLevel: form.riskLevel
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  if (formData.assessment) {
+    form.assessment.assessDate = formData.assessment.assessDate ? dayjs(formData.assessment.assessDate).toDate() : ''
+    form.assessment.assessor = formData.assessment.assessor || ''
+    form.assessment.scores = formData.assessment.scores || new Array(12).fill(0)
+    form.assessment.totalScore = formData.assessment.totalScore || 0
+  }
+  form.preventionMeasures = formData.preventionMeasures || []
+  form.riskLevel = formData.riskLevel || ''
+}
+
+/** 重置表单数据 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    elderName: '',
+    elderSex: '',
+    elderAge: '',
+    bedName: '',
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  form.assessment = {
+    assessDate: '',
+    assessor: '',
+    scores: new Array(12).fill(0),
+    totalScore: 0
+  }
+  form.preventionMeasures = []
+  form.riskLevel = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId: any, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-防坠床评估表"
+    await loadData(id)
+  } else {
+    title.value = "新增-防坠床评估表"
+  }
+}
+
+/** 加载评估数据 */
+const loadData = async (id: number) => {
+  try {
+    const res = await fallPreventionGetById(id)
+    if (res) {
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+defineExpose({ open })
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (!dataForm.value.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  formLoading.value = true
+  try {
+    const formData = serializeFormData()
+    const payload = {
+      id: dataForm.value.id,
+      elderId: dataForm.value.elderId,
+      tenantId: dataForm.value.tenantId,
+      elderName: dataForm.value.elderName,
+      elderSex: dataForm.value.elderSex,
+      elderAge: dataForm.value.elderAge,
+      bedName: dataForm.value.bedName,
+      assessData: JSON.stringify(formData),
+      riskLevel: form.riskLevel,
+      assessor: form.assessment.assessor,
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      await fallPreventionUpdate(payload)
+      message.success(t('common.updateSuccess'))
+    } else {
+      await fallPreventionCreate(payload)
+      message.success(t('common.createSuccess'))
+    }
+    dialogVisible.value = false
+    emit('success')
+  } catch (error) {
+    message.error('提交失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 关闭弹窗 */
+const handleClosed = () => {
+  dialogVisible.value = false
+}
+
+/** 导出/打印 */
+const handleExport = () => {
+  message.info('打印功能开发中')
+}
+
+const rules = {
+  elderName: [{ required: true, message: '请选择长者', trigger: 'change' }]
+}
+</script>
+
+<style scoped lang="scss">
+.assessment-form {
+  padding: 0 20px;
+
+  .form-header {
+    margin-bottom: 20px;
+  }
+
+  .risk-factors-section {
+    margin-bottom: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      width: 100%;
+      border-collapse: collapse;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      overflow: hidden;
+
+      th, td {
+        padding: 12px;
+        border: 1px solid #e4e7ed;
+        text-align: center;
+      }
+
+      thead {
+        background-color: #f5f7fa;
+        font-weight: bold;
+      }
+
+      .col-factor {
+        width: 50%;
+        text-align: left;
+      }
+
+      .col-score-header {
+        width: 20%;
+      }
+
+      .col-result {
+        width: 10%;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+
+    .risk-judgment {
+      margin-top: 15px;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .judgment-title {
+        font-weight: bold;
+        margin-right: 15px;
+      }
+    }
+  }
+
+  .assessment-records {
+    margin-top: 20px;
+
+    .record-section {
+      margin-bottom: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+
+      .record-header {
+        font-size: 14px;
+        font-weight: bold;
+        margin-bottom: 15px;
+        color: #409eff;
+        border-bottom: 1px solid #e4e7ed;
+        padding-bottom: 10px;
+      }
+
+      .score-text {
+        font-size: 16px;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+  }
+
+  .prevention-section {
+    margin-top: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .prevention-group {
+      .el-checkbox {
+        margin-bottom: 10px;
+        margin-right: 20px;
+      }
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+
+    .risk-rules {
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #fff;
+      border-radius: 4px;
+
+      .rules-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #606266;
+      }
+
+      .rule-tag {
+        margin-right: 10px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+}
+</style>

+ 297 - 0
src/views/elderly/apply/nine-precautions/fall-prevention-measures/index.vue

@@ -0,0 +1,297 @@
+<template>
+  <ContentWrap>
+    <!-- 防坠床评估表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="totalScore" header-align="center" align="center" label="评估总得分" min-width="120" show-overflow-tooltip/>
+      <el-table-column prop="riskLevel" header-align="center" align="center" label="风险等级" min-width="120" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getRiskLevelType(scope.row.riskLevel)">
+            {{ getRiskLevelText(scope.row.riskLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from "@/utils/dateUtil";
+import {
+  fallPreventionDelete,
+  fallPreventionPage
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const userStore = useUserStore()
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch, count)
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await fallPreventionPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate = getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if (queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1) {
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id, false)
+}
+
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, false)
+}
+
+const openFormDetail = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, true)
+}
+
+const openClose = async (item: any) => {
+  try {
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      try {
+        const res = await fallPreventionDelete(item.id)
+        if (res) {
+          message.success(t('common.updateSuccess'))
+          await getList()
+        }
+      } catch (err) { }
+    }
+  } catch { }
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    await message.cancelConfirm()
+    message.success(t('common.delSuccess'))
+    await getList()
+  } catch { }
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if (route.query && route.query.elderName) {
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// 获取风险等级类型
+const getRiskLevelType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+// 获取风险等级文本
+const getRiskLevelText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 1042 - 0
src/views/elderly/apply/nine-precautions/nutritional-risk/AddForm.vue

@@ -0,0 +1,1042 @@
+<template>
+  <el-drawer v-model="dialogVisible" :title="title" size="95%" :before-close="handleClosed">
+    <div class="assessment-form">
+      <div class="form-header">
+        <el-form :model="dataForm" :rules="rules" ref="formRef" label-width="80px">
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="姓名" prop="elderName">
+                <SelectElder ref="selectElderRef" :tenantId="dataForm.tenantId" @elder="elderUp" :disabled="isDetail"
+                  :elderName="dataForm.elderName" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="年龄">
+                <el-input v-model="dataForm.elderAge" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="性别">
+                <el-input v-model="dataForm.elderSex" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="时间">
+                <el-date-picker
+                  v-model="form.assessDate"
+                  type="date"
+                  placeholder="选择日期"
+                  value-format="YYYY-MM-DD"
+                  :disabled="isDetail"
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="身高(m)">
+                <el-input-number v-model="form.height" :min="0" :max="3" :precision="2" :step="0.01" :disabled="isDetail" style="width: 100%" @change="calculateBMI" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="体重(Kg)">
+                <el-input-number v-model="form.weight" :min="0" :max="200" :precision="1" :step="0.5" :disabled="isDetail" style="width: 100%" @change="calculateBMI" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6" v-if="form.bmi">
+              <el-form-item label="BMI">
+                <span class="bmi-value">{{ form.bmi.toFixed(1) }}</span>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
+      <!-- 营养风险评估表 -->
+      <div class="nutritional-section">
+
+
+        <!-- 初筛部分 -->
+        <div class="subsection-title">初筛</div>
+        <table class="assessment-table">
+          <thead>
+            <tr>
+              <th class="col-item">项目</th>
+              <th class="col-score-0">0分</th>
+              <th class="col-score-1">1分</th>
+              <th class="col-score-2">2分</th>
+              <th class="col-score-3">3分</th>
+            </tr>
+          </thead>
+          <tbody>
+            <!-- 1. BMI -->
+            <tr>
+              <td class="col-item">1. BMI</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.initialScores[0]" :disabled="isDetail" @change="calculateScores">BMI&lt;19<br/>或 BMI≥28</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.initialScores[0]" :disabled="isDetail" @change="calculateScores">19≤BMI&lt;21<br/>或 26≤BMI&lt;28</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="2" v-model="form.initialScores[0]" :disabled="isDetail" @change="calculateScores">21≤BMI&lt;23<br/>或24≤BMI&lt;26</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="3" v-model="form.initialScores[0]" :disabled="isDetail" @change="calculateScores">23≤BMI≤24</el-radio>
+              </td>
+            </tr>
+
+            <!-- 2. 近3个月体重变化 -->
+            <tr>
+              <td class="col-item">2. 近3个月体重变化</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.initialScores[1]" :disabled="isDetail" @change="calculateScores">减少或增加≥3Kg</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.initialScores[1]" :disabled="isDetail" @change="calculateScores">不知道</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="2" v-model="form.initialScores[1]" :disabled="isDetail" @change="calculateScores">1Kg≤减少&lt;3Kg<br/>或1Kg≤增加&lt;3Kg</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="3" v-model="form.initialScores[1]" :disabled="isDetail" @change="calculateScores">0Kg&lt;减少&lt;1Kg<br/>或0Kg&lt;增加&lt;1Kg</el-radio>
+              </td>
+            </tr>
+
+            <!-- 3. 活动能力 -->
+            <tr>
+              <td class="col-item">3. 活动能力</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.initialScores[2]" :disabled="isDetail" @change="calculateScores">卧床</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.initialScores[2]" :disabled="isDetail" @change="calculateScores">需要依赖工具活动</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="2" v-model="form.initialScores[2]" :disabled="isDetail" @change="calculateScores">独立户外活动</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 4. 牙齿状况 -->
+            <tr>
+              <td class="col-item">4. 牙齿状况</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.initialScores[3]" :disabled="isDetail" @change="calculateScores">全口或半口缺</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.initialScores[3]" :disabled="isDetail" @change="calculateScores">用义齿</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="2" v-model="form.initialScores[3]" :disabled="isDetail" @change="calculateScores">正常</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 5. 神经精神疾病 -->
+            <tr>
+              <td class="col-item">5. 神经精神疾病</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.initialScores[4]" :disabled="isDetail" @change="calculateScores">严重认知障碍或抑郁</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.initialScores[4]" :disabled="isDetail" @change="calculateScores">轻度认知障碍或抑郁</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="2" v-model="form.initialScores[4]" :disabled="isDetail" @change="calculateScores">无认知障碍或抑郁</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 6. 近三个月有无饮食量变化 -->
+            <tr>
+              <td class="col-item">6. 近三个月有无饮食量变化</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.initialScores[5]" :disabled="isDetail" @change="calculateScores">严重增加或减少</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.initialScores[5]" :disabled="isDetail" @change="calculateScores">增加或减少</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="2" v-model="form.initialScores[5]" :disabled="isDetail" @change="calculateScores">无变化</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+          </tbody>
+        </table>
+
+        <!-- 初筛提示 -->
+        <div class="initial-tip">
+          <p>总分14分,&lt;12分提示有营养不良风险,继续以下评估;≥12分提示无营养不良风险,无需以下评估。</p>
+          <p class="score-display">初筛分数(小计满分14分):<span class="score-value">{{ form.initialScore }}</span> 分</p>
+        </div>
+
+        <!-- 评估部分 -->
+        <div class="subsection-title">评估</div>
+        <table class="assessment-table">
+          <thead>
+            <tr>
+              <th class="col-item">项目</th>
+              <th class="col-score-0">0分</th>
+              <th class="col-score-05">0.5分</th>
+              <th class="col-score-1">1分</th>
+              <th class="col-score-2">2分</th>
+            </tr>
+          </thead>
+          <tbody>
+            <!-- 7. 患慢性病数>3种 -->
+            <tr>
+              <td class="col-item">7. 患慢性病数&gt;3种</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[0]" :disabled="isDetail" @change="calculateScores">是</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[0]" :disabled="isDetail" @change="calculateScores">否</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 8. 服药时间在一个月以上的药物种类>3种 -->
+            <tr>
+              <td class="col-item">8. 服药时间在一个月以上的药物种类&gt;3种</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[1]" :disabled="isDetail" @change="calculateScores">是</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[1]" :disabled="isDetail" @change="calculateScores">否</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 9. 是否独居 -->
+            <tr>
+              <td class="col-item">9. 是否独居</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[2]" :disabled="isDetail" @change="calculateScores">是</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[2]" :disabled="isDetail" @change="calculateScores">否</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 10. 睡眠时间 -->
+            <tr>
+              <td class="col-item">10. 睡眠时间</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[3]" :disabled="isDetail" @change="calculateScores">&lt;5h/d</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[3]" :disabled="isDetail" @change="calculateScores">≥5h/d</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 11. 户外独立活动时间 -->
+            <tr>
+              <td class="col-item">11. 户外独立活动时间</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[4]" :disabled="isDetail" @change="calculateScores">&lt;1h/d</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[4]" :disabled="isDetail" @change="calculateScores">≥1h/d</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 12. 文化程度 -->
+            <tr>
+              <td class="col-item">12. 文化程度</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[5]" :disabled="isDetail" @change="calculateScores">小学及以下</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[5]" :disabled="isDetail" @change="calculateScores">中学及以上</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 13. 自我感觉经济状况 -->
+            <tr>
+              <td class="col-item">13. 自我感觉经济状况</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[6]" :disabled="isDetail" @change="calculateScores">差</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="0.5" v-model="form.assessScores[6]" :disabled="isDetail" @change="calculateScores">一般</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[6]" :disabled="isDetail" @change="calculateScores">良好</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 14. 进食能力 -->
+            <tr>
+              <td class="col-item">14. 进食能力</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[7]" :disabled="isDetail" @change="calculateScores">依靠别人</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[7]" :disabled="isDetail" @change="calculateScores">自行进食稍有困难</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="2" v-model="form.assessScores[7]" :disabled="isDetail" @change="calculateScores">自行进食</el-radio>
+              </td>
+            </tr>
+
+            <!-- 15. 一天餐次 -->
+            <tr>
+              <td class="col-item">15. 一天餐次</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[8]" :disabled="isDetail" @change="calculateScores">1次</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[8]" :disabled="isDetail" @change="calculateScores">2次</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="2" v-model="form.assessScores[8]" :disabled="isDetail" @change="calculateScores">3次及以上</el-radio>
+              </td>
+            </tr>
+
+            <!-- 16. 每天摄入奶类/豆制品/鱼肉类 -->
+            <tr>
+              <td class="col-item">16. 每天摄入奶类:<br/>每天摄入豆制品:<br/>每天摄入鱼/肉/蛋类食品</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[9]" :disabled="isDetail" @change="calculateScores">0-1项</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="0.5" v-model="form.assessScores[9]" :disabled="isDetail" @change="calculateScores">2项</el-radio>
+              </td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[9]" :disabled="isDetail" @change="calculateScores">3项</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 17. 每天烹调油摄入量 -->
+            <tr>
+              <td class="col-item">17. 每天烹调油摄入量</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.assessScores[10]" :disabled="isDetail" @change="calculateScores">≥25g</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.assessScores[10]" :disabled="isDetail" @change="calculateScores">&lt;25g</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 18. 是否每天吃蔬菜水果500g以上 -->
+            <tr>
+              <td class="col-item">18. 是否每天吃蔬菜水果500g及以上</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.measureScores[0]" :disabled="isDetail" @change="calculateScores">否</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.measureScores[0]" :disabled="isDetail" @change="calculateScores">是</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 19. 小腿围 -->
+            <tr>
+              <td class="col-item">19. 小腿围</td>
+              <td class="col-score">
+                <el-radio :label="0" v-model="form.measureScores[1]" :disabled="isDetail" @change="calculateScores">&lt;31cm</el-radio>
+              </td>
+              <td class="col-score">—</td>
+              <td class="col-score">
+                <el-radio :label="1" v-model="form.measureScores[1]" :disabled="isDetail" @change="calculateScores">≥31cm</el-radio>
+              </td>
+              <td class="col-score">—</td>
+            </tr>
+
+            <!-- 20. 腰围 -->
+            <tr>
+              <td class="col-item">20. 腰围</td>
+              <td class="col-score" colspan="2">
+                <div class="waist-row">
+                  <span class="waist-label">男:</span>
+                  <el-radio :label="0" v-model="form.waistScore" :disabled="isDetail" @change="onWaistChange">&gt;90cm</el-radio>
+                </div>
+                <div class="waist-row">
+                  <span class="waist-label">女:</span>
+                  <el-radio :label="2" v-model="form.waistScore" :disabled="isDetail" @change="onWaistChange">&gt;80cm</el-radio>
+                </div>
+              </td>
+              <td class="col-score" colspan="2">
+                <div class="waist-row">
+                  <el-radio :label="1" v-model="form.waistScore" :disabled="isDetail" @change="onWaistChange">≤90cm</el-radio>
+                </div>
+                <div class="waist-row">
+                  <el-radio :label="3" v-model="form.waistScore" :disabled="isDetail" @change="onWaistChange">≤80cm</el-radio>
+                </div>
+              </td>
+            </tr>
+          </tbody>
+        </table>
+
+        <!-- 测量输入 -->
+        <div class="measure-inputs">
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="小腿围(cm):">
+                <el-input-number v-model="form.calfCircumference" :min="0" :max="100" :precision="1" :disabled="isDetail" style="width: 150px" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="腰围(cm):">
+                <el-input-number v-model="form.waistCircumference" :min="0" :max="200" :precision="1" :disabled="isDetail" style="width: 150px" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+
+        <!-- 年龄调整 -->
+        <div class="age-adjust">
+          <p>年龄超过70岁总分加1分,即年龄调整增加的分值:<span class="score-value">{{ form.ageAdjust }}</span>分,年龄&lt;70岁:0分,年龄≥70岁:1分</p>
+        </div>
+
+        <!-- 分数汇总 -->
+        <div class="score-summary">
+          <div class="summary-item">
+            <span class="label">初筛分数(小计满分14分):</span>
+            <span class="value">{{ form.initialScore }} 分</span>
+          </div>
+          <div class="summary-item">
+            <span class="label">评估分数(小计满分16分):</span>
+            <span class="value">{{ form.assessScore }} 分</span>
+          </div>
+          <div class="summary-item">
+            <span class="label">量表总分(满分30分):</span>
+            <span class="value total">{{ form.totalScore }} 分</span>
+          </div>
+        </div>
+
+        <!-- 评分标准 -->
+        <div class="scoring-standard">
+          <div class="standard-title">评分标准:</div>
+          <div class="standard-content">
+            <p>若初筛总分≥12分提示无营养不良风险,无需评估;</p>
+            <p>若初筛总分&lt;12分提示有营养不良风险,继续评估;</p>
+            <p>若营养不良风险评估总分(初筛+评估)≥24分,表示营养状况良好;</p>
+            <p>若营养不良风险评估总分(初筛+评估)&gt;24分,当BMI≥24(或男性腰围&gt;90cm,女性腰围&gt;80cm)时,提示可能是肥胖/超重型营养不良或有营养不良风险;</p>
+            <p>若营养不良风险评估总分(初筛+评估)17分~24分,表示有营养不良风险;</p>
+            <p>若营养不良风险评估总分(初筛+评估)≤17分,表示有营养不良。</p>
+          </div>
+          <div class="current-result" v-if="form.resultLevel">
+            <span class="result-label">当前评估结果:</span>
+            <el-tag :type="getResultTagType(form.resultLevel)" size="large">
+              {{ getResultText(form.resultLevel) }}
+            </el-tag>
+          </div>
+        </div>
+
+        <!-- 评估人签名 -->
+        <div class="assessor-section">
+          <el-form-item label="评估人签名:" label-width="100px">
+            <el-input v-model="form.assessor" :disabled="isDetail" style="width: 300px" />
+          </el-form-item>
+        </div>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-nutritional-risk/create 或 PUT /elderly-assess-nutritional-risk/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="assessData">JSON字符串,包含所有评估数据</el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="subsection-title" style="margin-top: 15px;">assessData 字段详情</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="assessDate">评估日期</el-descriptions-item>
+          <el-descriptions-item label="height">身高(m)</el-descriptions-item>
+          <el-descriptions-item label="weight">体重(Kg)</el-descriptions-item>
+          <el-descriptions-item label="bmi">BMI指数</el-descriptions-item>
+          <el-descriptions-item label="initialScores">初筛分数数组[6项],每项0-3分</el-descriptions-item>
+          <el-descriptions-item label="initialScore">初筛总分(满分14分)</el-descriptions-item>
+          <el-descriptions-item label="assessScores">评估分数数组[11项]</el-descriptions-item>
+          <el-descriptions-item label="assessScore">评估分数(满分15分)</el-descriptions-item>
+          <el-descriptions-item label="measureScores">测量分数数组[2项]:18.蔬菜水果, 19.小腿围</el-descriptions-item>
+          <el-descriptions-item label="measureScore">测量分数(满分3分)</el-descriptions-item>
+          <el-descriptions-item label="waistScore">第20题腰围:0=男>90cm, 1=男≤90cm, 2=女>80cm, 3=女≤80cm</el-descriptions-item>
+          <el-descriptions-item label="calfCircumference">小腿围测量值(cm)</el-descriptions-item>
+          <el-descriptions-item label="waistCircumference">腰围测量值(cm)</el-descriptions-item>
+          <el-descriptions-item label="ageAdjust">年龄调整分(≥70岁为1分)</el-descriptions-item>
+          <el-descriptions-item label="totalScore">量表总分(满分30分)</el-descriptions-item>
+          <el-descriptions-item label="resultLevel">结果等级:good-营养状况良好, at_risk-有营养不良风险, malnutrition-有营养不良</el-descriptions-item>
+        </el-descriptions>
+      </div>
+    </div>
+
+    <template #footer>
+      <div style="flex: auto">
+        <el-button v-if="!isDetail" type="primary" @click="submitForm">保存</el-button>
+        <el-button v-if="!isDetail" @click="handleClosed">取消</el-button>
+        <el-button v-if="isDetail" @click="handleClosed">关闭</el-button>
+        <el-button v-if="isDetail" type="primary" @click="handleExport">打印</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, nextTick } from 'vue'
+import { useAppStore } from '@/store/modules/app'
+import {
+  nutritionalRiskCreate,
+  nutritionalRiskUpdate,
+  nutritionalRiskGetById,
+  NutritionalRiskFormData
+} from '@/api/social-work'
+
+const message = useMessage()
+const appStore = useAppStore()
+const emit = defineEmits(['success'])
+
+const dialogVisible = ref(false)
+const title = ref('新增营养风险评估')
+const isDetail = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+
+const dataForm = reactive({
+  id: undefined as number | undefined,
+  elderId: undefined as number | undefined,
+  tenantId: appStore.getTenantId,
+  elderName: '',
+  elderSex: '',
+  elderAge: ''
+})
+
+const form = reactive({
+  assessDate: '',
+  height: undefined as number | undefined,
+  weight: undefined as number | undefined,
+  bmi: undefined as number | undefined,
+  // 初筛分数(6项,每项0-3分)
+  initialScores: [undefined, undefined, undefined, undefined, undefined, undefined] as (number | undefined)[],
+  // 评估分数(11项)
+  assessScores: [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined] as (number | undefined)[],
+  // 测量分数(2项:18.蔬菜水果, 19.小腿围)
+  measureScores: [undefined, undefined] as (number | undefined)[],
+  // 腰围分数(0:男>90cm, 1:男≤90cm, 2:女>80cm, 3:女≤80cm)
+  waistScore: undefined as number | undefined,
+  // 测量值
+  calfCircumference: undefined as number | undefined,
+  waistCircumference: undefined as number | undefined,
+  // 分数汇总
+  initialScore: 0,
+  assessScore: 0,
+  measureScore: 0,
+  ageAdjust: 0,
+  totalScore: 0,
+  resultLevel: '',
+  assessor: ''
+})
+
+const calculateBMI = () => {
+  if (form.height && form.weight) {
+    form.bmi = form.weight / (form.height * form.height)
+    // 根据BMI自动计算第1题分数
+    if (form.bmi < 19 || form.bmi >= 28) {
+      form.initialScores[0] = 0
+    } else if ((form.bmi >= 19 && form.bmi < 21) || (form.bmi >= 26 && form.bmi < 28)) {
+      form.initialScores[0] = 1
+    } else if ((form.bmi >= 21 && form.bmi < 23) || (form.bmi >= 24 && form.bmi < 26)) {
+      form.initialScores[0] = 2
+    } else if (form.bmi >= 23 && form.bmi <= 24) {
+      form.initialScores[0] = 3
+    }
+    calculateScores()
+  }
+}
+
+const calculateScores = () => {
+  // 计算初筛分数(满分14分)
+  form.initialScore = form.initialScores.reduce((sum, score) => sum + (score || 0), 0)
+
+  // 计算评估分数(满分15分)- 11项
+  form.assessScore = form.assessScores.reduce((sum, score) => sum + (score || 0), 0)
+
+  // 计算测量分数(满分3分:18题1分 + 19题1分 + 20题1分)
+  let measureScore = form.measureScores.reduce((sum, score) => sum + (score || 0), 0)
+  // 第20题腰围分数(0或1分)
+  if (form.waistScore !== undefined) {
+    // 0:男>90cm(0分), 1:男≤90cm(1分), 2:女>80cm(0分), 3:女≤80cm(1分)
+    measureScore += (form.waistScore === 1 || form.waistScore === 3) ? 1 : 0
+  }
+  form.measureScore = measureScore
+
+  // 年龄调整(≥70岁加1分)
+  const age = parseInt(dataForm.elderAge) || 0
+  form.ageAdjust = age >= 70 ? 1 : 0
+
+  // 计算总分
+  form.totalScore = form.initialScore + form.assessScore + form.measureScore + form.ageAdjust
+
+  // 判断结果等级
+  if (form.initialScore >= 12) {
+    // 初筛通过,无营养不良风险
+    form.resultLevel = 'good'
+  } else {
+    // 初筛未通过,根据总分判断
+    if (form.totalScore >= 24) {
+      // 检查是否肥胖/超重
+      if (form.bmi && form.bmi >= 24) {
+        form.resultLevel = 'at_risk' // 肥胖/超重型营养不良或有营养不良风险
+      } else {
+        form.resultLevel = 'good'
+      }
+    } else if (form.totalScore > 17 && form.totalScore < 24) {
+      form.resultLevel = 'at_risk'
+    } else {
+      form.resultLevel = 'malnutrition'
+    }
+  }
+}
+
+// 腰围选择变化处理(男女互斥)
+const onWaistChange = () => {
+  calculateScores()
+}
+
+const getResultTagType = (level: string) => {
+  const typeMap: Record<string, string> = {
+    'good': 'success',
+    'at_risk': 'warning',
+    'malnutrition': 'danger'
+  }
+  return typeMap[level] || 'info'
+}
+
+const getResultText = (level: string) => {
+  const textMap: Record<string, string> = {
+    'good': '营养状况良好',
+    'at_risk': '有营养不良风险',
+    'malnutrition': '有营养不良'
+  }
+  return textMap[level] || level
+}
+
+const resetForm = () => {
+  dataForm.id = undefined
+  dataForm.elderId = undefined
+  dataForm.elderName = ''
+  dataForm.elderSex = ''
+  dataForm.elderAge = ''
+
+  form.assessDate = ''
+  form.height = undefined
+  form.weight = undefined
+  form.bmi = undefined
+  form.initialScores = [undefined, undefined, undefined, undefined, undefined, undefined]
+  form.assessScores = [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
+  form.measureScores = [undefined, undefined]
+  form.waistScore = undefined
+  form.calfCircumference = undefined
+  form.waistCircumference = undefined
+  form.initialScore = 0
+  form.assessScore = 0
+  form.measureScore = 0
+  form.ageAdjust = 0
+  form.totalScore = 0
+  form.resultLevel = ''
+  form.assessor = ''
+}
+
+const elderUp = (row: any) => {
+  dataForm.elderId = row.id
+  dataForm.elderName = row.name
+  dataForm.elderSex = row.sex
+  dataForm.elderAge = row.age
+  // 年龄变化时重新计算
+  calculateScores()
+}
+
+const open = async (id?: number) => {
+  resetForm()
+  title.value = '新增营养风险评估'
+  isDetail.value = false
+  dialogVisible.value = true
+  await nextTick()
+  selectElderRef.value?.reset()
+}
+
+const openEdit = async (row: any, id: number) => {
+  resetForm()
+  title.value = '编辑营养风险评估'
+  isDetail.value = false
+  dialogVisible.value = true
+  await nextTick()
+  await loadData(row, id)
+}
+
+const openDetail = async (row: any, id: number) => {
+  resetForm()
+  title.value = '营养风险评估详情'
+  isDetail.value = true
+  dialogVisible.value = true
+  await nextTick()
+  await loadData(row, id)
+}
+
+const loadData = async (row: any, id: number) => {
+  try {
+    const res = await nutritionalRiskGetById(id)
+    if (res) {
+      Object.assign(dataForm, {
+        id: res.id,
+        elderId: res.elderId,
+        elderName: res.elderName,
+        elderSex: res.elderSex,
+        elderAge: res.elderAge
+      })
+
+      // 解析assessData
+      if (res.assessData) {
+        const assessData = JSON.parse(res.assessData)
+        Object.assign(form, assessData)
+      }
+
+      form.assessor = res.assessor || ''
+      form.assessDate = res.assessDate || ''
+      form.initialScore = res.initialScore || 0
+      form.assessScore = res.assessScore || 0
+      form.measureScore = res.measureScore || 0
+      form.ageAdjust = res.ageAdjust || 0
+      form.totalScore = res.totalScore || 0
+      form.resultLevel = res.resultLevel || ''
+    }
+  } catch (error) {
+    console.error('加载数据失败:', error)
+  }
+}
+
+const submitForm = async () => {
+  if (!dataForm.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  const assessData = {
+    assessDate: form.assessDate,
+    height: form.height,
+    weight: form.weight,
+    bmi: form.bmi,
+    initialScores: form.initialScores,
+    assessScores: form.assessScores,
+    measureScores: form.measureScores,
+    waistScore: form.waistScore,
+    calfCircumference: form.calfCircumference,
+    waistCircumference: form.waistCircumference,
+    initialScore: form.initialScore,
+    assessScore: form.assessScore,
+    measureScore: form.measureScore,
+    ageAdjust: form.ageAdjust,
+    totalScore: form.totalScore,
+    resultLevel: form.resultLevel
+  }
+
+  const submitData: NutritionalRiskFormData = {
+    id: dataForm.id,
+    elderId: dataForm.elderId,
+    tenantId: dataForm.tenantId,
+    assessData: JSON.stringify(assessData),
+    assessor: form.assessor,
+    assessDate: form.assessDate
+  }
+
+  try {
+    if (dataForm.id) {
+      await nutritionalRiskUpdate(submitData)
+      message.success('更新成功')
+    } else {
+      await nutritionalRiskCreate(submitData)
+      message.success('创建成功')
+    }
+    dialogVisible.value = false
+    emit('success')
+  } catch (error) {
+    console.error('提交失败:', error)
+    message.error('提交失败')
+  }
+}
+
+const handleClosed = () => {
+  dialogVisible.value = false
+}
+
+const handleExport = () => {
+  message.info('打印功能开发中')
+}
+
+const rules = {
+  elderName: [{ required: true, message: '请选择长者', trigger: 'change' }]
+}
+
+defineExpose({
+  open,
+  openEdit,
+  openDetail
+})
+</script>
+
+<style scoped lang="scss">
+.assessment-form {
+  padding: 0 20px;
+
+  .form-header {
+    margin-bottom: 20px;
+
+    .bmi-value {
+      font-size: 16px;
+      font-weight: bold;
+      color: #409eff;
+    }
+  }
+
+  .nutritional-section {
+    margin-bottom: 20px;
+
+    .section-title {
+      font-size: 18px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      text-align: center;
+      border-bottom: 2px solid #409eff;
+      padding-bottom: 10px;
+    }
+
+    .subsection-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin: 20px 0 10px 0;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      width: 100%;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      border-collapse: collapse;
+
+      thead {
+        background-color: #f5f7fa;
+        font-weight: bold;
+
+        th {
+          padding: 12px;
+          border: 1px solid #e4e7ed;
+          text-align: center;
+        }
+
+        .col-item {
+          width: 20%;
+        }
+
+        .col-score-0,
+        .col-score-05,
+        .col-score-1,
+        .col-score-2,
+        .col-score-3 {
+          width: 20%;
+        }
+      }
+
+      tbody {
+        tr {
+          border-bottom: 1px solid #e4e7ed;
+
+          &:last-child {
+            border-bottom: none;
+          }
+
+          td {
+            padding: 12px;
+            border: 1px solid #e4e7ed;
+          }
+
+          .col-item {
+            width: 20%;
+            text-align: center;
+            font-weight: bold;
+            vertical-align: middle;
+          }
+
+          .col-score {
+            width: 20%;
+            text-align: center;
+            vertical-align: middle;
+
+            .el-radio {
+              white-space: normal;
+              line-height: 1.5;
+              height: auto;
+              margin-right: 0;
+            }
+
+            .waist-row {
+              margin-bottom: 5px;
+
+              &:last-child {
+                margin-bottom: 0;
+              }
+
+              .waist-label {
+                font-weight: bold;
+                margin-right: 10px;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    .initial-tip {
+      margin: 15px 0;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      p {
+        margin: 5px 0;
+      }
+
+      .score-display {
+        font-weight: bold;
+      }
+
+      .score-value {
+        font-size: 18px;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+
+    .measure-inputs {
+      margin: 15px 0;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+    }
+
+    .age-adjust {
+      margin: 15px 0;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .score-value {
+        font-size: 18px;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+
+    .score-summary {
+      margin: 20px 0;
+      padding: 20px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+      border: 2px solid #409eff;
+
+      .summary-item {
+        margin: 10px 0;
+        font-size: 16px;
+
+        .label {
+          font-weight: bold;
+        }
+
+        .value {
+          font-size: 18px;
+          font-weight: bold;
+          color: #409eff;
+
+          &.total {
+            color: #f56c6c;
+            font-size: 20px;
+          }
+        }
+      }
+    }
+
+    .scoring-standard {
+      margin: 20px 0;
+      padding: 20px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .standard-title {
+        font-size: 16px;
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #333;
+      }
+
+      .standard-content {
+        p {
+          margin: 5px 0;
+          line-height: 1.6;
+        }
+      }
+
+      .current-result {
+        margin-top: 15px;
+        padding-top: 15px;
+        border-top: 1px solid #e4e7ed;
+
+        .result-label {
+          font-weight: bold;
+          margin-right: 10px;
+        }
+      }
+    }
+
+    .assessor-section {
+      margin-top: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+  }
+}
+</style>

+ 228 - 0
src/views/elderly/apply/nine-precautions/nutritional-risk/index.vue

@@ -0,0 +1,228 @@
+<script setup lang="ts">
+import { onMounted, ref, reactive } from 'vue'
+import { ContentWrap } from '@/components/ContentWrap'
+import { nutritionalRiskPage, nutritionalRiskDelete } from '@/api/social-work'
+import AddForm from './AddForm.vue'
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from '@/utils/dateUtil'
+import {tableHeaderColor} from "@/utils/table";
+
+const userStore = useUserStore()
+const message = useMessage()
+const formRef = ref<InstanceType<typeof AddForm>>()
+
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await nutritionalRiskPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  if (!queryFormRef.value) return
+  queryFormRef.value.resetFields()
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.assessDate = getCurrentMonthRange()
+  handleQuery()
+}
+
+const openForm = (id?: number) => {
+  formRef.value?.open(id)
+}
+
+const openFormEdit = (row: any, id: number) => {
+  formRef.value?.openEdit(row, id)
+}
+
+const openFormDetail = (row: any, id: number) => {
+  formRef.value?.openDetail(row, id)
+}
+
+const openClose = async (row: any) => {
+  try {
+    await message.confirm('确认删除该记录吗?')
+    await nutritionalRiskDelete(row.id)
+    message.success('删除成功')
+    getList()
+  } catch (error) {
+    // 用户取消操作
+  }
+}
+
+const handleExport = () => {
+  message.info('导出功能开发中')
+}
+
+const getResultLevelType = (level: string) => {
+  const typeMap: Record<string, string> = {
+    'good': 'success',
+    'at_risk': 'warning',
+    'malnutrition': 'danger'
+  }
+  return typeMap[level] || 'info'
+}
+
+const getResultLevelText = (level: string) => {
+  const textMap: Record<string, string> = {
+    'good': '营养状况良好',
+    'at_risk': '有营养不良风险',
+    'malnutrition': '有营养不良'
+  }
+  return textMap[level] || level
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<template>
+  <ContentWrap>
+    <!-- 营养风险评估表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="initialScore" header-align="center" align="center" label="初筛分数" min-width="100" show-overflow-tooltip/>
+      <el-table-column prop="assessScore" header-align="center" align="center" label="评估分数" min-width="100" show-overflow-tooltip/>
+      <el-table-column prop="totalScore" header-align="center" align="center" label="量表总分" min-width="100" show-overflow-tooltip/>
+      <el-table-column prop="resultLevel" header-align="center" align="center" label="评估结果" min-width="150" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getResultLevelType(scope.row.resultLevel)">
+            {{ getResultLevelText(scope.row.resultLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+</template>
+
+<style scoped lang="scss">
+</style>

+ 912 - 0
src/views/elderly/apply/nine-precautions/pressure-sores/AddForm.vue

@@ -0,0 +1,912 @@
+<template>
+  <el-drawer v-model="dialogVisible" :title="title" resizable :close-on-click-modal="false" :close-on-press-escape="false"
+    :destroy-on-close="true" size="85%" :before-close="handleClosed">
+    <div class="pressure-sores-form">
+      <h1 class="form-title">防压疮评估表</h1>
+      <!-- 基本信息 -->
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>长者姓名</text>
+          <search-the-elderly ref="selectElderRef" :disabled="isDetail" @update_elder="elderUp"
+            v-model="dataForm.elderName" :tId="dataForm.tenantId" />
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>性别</text>
+          <el-input v-if="!isDetail" v-model="dataForm.elderSex" disabled />
+          <el-text v-else disabled="">{{ dataForm.elderSex }}</el-text>
+        </el-col>
+      </el-row>
+      <el-row :gutter="40">
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>年龄</text>
+          <el-input v-if="!isDetail" v-model="dataForm.elderAge" disabled />
+          <el-text v-else disabled="">{{ dataForm.elderAge }}</el-text>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" class="row">
+          <text>房号/床号</text>
+          <el-input v-if="!isDetail" v-model="dataForm.bedName" disabled />
+          <el-text v-else disabled="">{{ dataForm.bedName }}</el-text>
+        </el-col>
+      </el-row>
+
+      <!-- 评估项目表格 -->
+      <div class="assessment-section">
+        <div class="section-title">等级量表</div>
+        <div class="assessment-table">
+          <table>
+            <thead>
+              <tr>
+                <th class="item-col">评估项目</th>
+                <th class="score-col">1 分</th>
+                <th class="score-col">2 分</th>
+                <th class="score-col">3 分</th>
+                <th class="score-col">4 分</th>
+                <th class="result-col">得分</th>
+
+              </tr>
+            </thead>
+            <tbody>
+              <tr v-for="(item, index) in assessmentItems" :key="index">
+                <td class="item-name">{{ item.name }}</td>
+                <td class="option">{{ item.options[0] }}</td>
+                <td class="option">{{ item.options[1] }}</td>
+                <td class="option">{{ item.options[2] }}</td>
+                <td class="option">{{ item.options[3] }}</td>
+                <td class="result">
+                  <el-radio-group v-model="form.assessments[0].scores[index]" :disabled="isDetail"
+                    @change="calculateTotalScore(0)">
+                    <el-radio :value="1">1</el-radio>
+                    <el-radio :value="2">2</el-radio>
+                    <el-radio :value="3">3</el-radio>
+                    <el-radio :value="4">4</el-radio>
+                  </el-radio-group>
+                </td>
+
+
+              </tr>
+            </tbody>
+          </table>
+        </div>
+      </div>
+
+      <!-- 评估记录 -->
+      <div class="assessment-records">
+        <div v-for="(record, index) in form.assessments" :key="index" class="record-section">
+          <div class="record-header">第{{ index + 1 }}次评估</div>
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-form-item label="评估日期">
+                <el-date-picker v-model="record.assessDate" type="date" :disabled="isDetail" style="width: 100%;" />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-form-item label="评估人签名">
+                <el-input v-model="record.assessor" :disabled="isDetail" />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+              <el-form-item label="评估总得分">
+                <el-input v-model="record.totalScore" disabled />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="24">
+              <el-form-item label="风险等级结果">
+                <el-tag :type="getRiskTagType(record.riskLevel)">
+                  {{ getRiskText(record.riskLevel) }}
+                </el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 评分说明 -->
+      <div class="scoring-note">
+        <div class="note-title">评分说明:</div>
+        <div class="note-content">
+          <p>注:分值 6-23 分,最高分 23 分,最低分 6 分</p>
+          <p>得分越低,发生压疮的危险性越高 18 分是发生压疮危险的临界值</p>
+          <p>风险程度判断:无风险: >18 分;低风险: 15-18 分;中风险: 13-14 分;高风险: ≤12 分</p>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="prevention-section">
+        <div class="section-title">预防措施:</div>
+        <el-checkbox-group v-model="form.preventionMeasures" :disabled="isDetail" class="prevention-group">
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="避免局部组织长期受压,常更换卧位">避免局部组织长期受压,常更换卧位</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="使用保护性用具,如气垫床、翻身枕、泡沫敷料、水垫等">使用保护性用具,如气垫床、翻身枕、泡沫敷料、水垫等</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="翻身时动作规范,避免拖、拉、拽等动作">翻身时动作规范,避免拖、拉、拽等动作</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="选择吸汗不刺激宽松衣物,保持衣物及床单平整清洁">选择吸汗不刺激宽松衣物,保持衣物及床单平整清洁</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="保持皮肤清洁干燥,皮肤受到二便污染时及时清洗">保持皮肤清洁干燥,皮肤受到二便污染时及时清洗</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="定期为长者进行温水擦浴及按摩,促进局部血液循环">定期为长者进行温水擦浴及按摩,促进局部血液循环</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="改善机体营养状况,增加蛋白质、维生素合微量元素的摄入">改善机体营养状况,增加蛋白质、维生素合微量元素的摄入</el-checkbox>
+            </el-col>
+          </el-row>
+        </el-checkbox-group>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-pressure-sores/create 或 PUT /elderly-assess-pressure-sores/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="elderName">长者姓名</el-descriptions-item>
+          <el-descriptions-item label="elderSex">长者性别</el-descriptions-item>
+          <el-descriptions-item label="elderAge">长者年龄</el-descriptions-item>
+          <el-descriptions-item label="bedName">房号/床号</el-descriptions-item>
+          <el-descriptions-item label="assessData">
+            JSON字符串,包含:<br/>
+            - assessments: 3次评估记录数组 [{assessDate, assessor, scores[], totalScore, riskLevel}]<br/>
+            - preventionMeasures: 预防措施选项数组<br/>
+            - totalScore: 评估总得分(取最高得分)<br/>
+            - riskLevel: 风险等级(none/low/medium/high)
+          </el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人()</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期(YYYY-MM-DD)</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="risk-rules">
+          <div class="rules-title">风险等级规则:</div>
+          <el-tag type="success" class="rule-tag">&gt;18分:无风险</el-tag>
+          <el-tag type="info" class="rule-tag">15-18分:低风险</el-tag>
+          <el-tag type="warning" class="rule-tag">13-14分:中风险</el-tag>
+          <el-tag type="danger" class="rule-tag">≤12分:高风险</el-tag>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
+        v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, reactive } from 'vue'
+import dayjs from 'dayjs'
+import {
+  pressureSoresCreate,
+  pressureSoresGetById,
+  pressureSoresUpdate,
+  pressureSoresGetByElderId
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const title = ref('')
+const dialogVisible = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+const isDetail = ref(false)
+const formLoading = ref(false)
+
+let dataForm = ref({
+  id: undefined,
+  elderName: '',
+  elderSex: '',
+  elderAge: '',
+  bedName: '',
+  elderId: '',
+  tenantId: undefined
+})
+
+const elderUp = (e: any) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.elderAge = e.elderAge
+}
+
+// 评估项目定义
+const assessmentItems = [
+  { name: '感觉', options: ['完全受限', '非常受限', '轻度受限', '未受限'] },
+  { name: '潮湿', options: ['持续潮湿', '潮湿', '有时潮湿', '很少潮湿'] },
+  { name: '活动力', options: ['限制卧床', '可以坐椅子', '偶而行走', '经常行走'] },
+  { name: '移动力', options: ['完全无法移动', '严重受限', '轻度受限', '未受限'] },
+  { name: '营养', options: ['非常差', '可能不足够', '足够', '非常好'] },
+  { name: '摩擦力和剪切力', options: ['有问题', '有潜在问题', '无明显问题', ''] }
+]
+
+// 表单数据
+const form = reactive({
+  assessments: [
+    { assessDate: '', assessor: '', scores: new Array(6).fill(0), totalScore: 0, riskLevel: '' },
+
+  ],
+  preventionMeasures: []
+})
+
+// 计算总分和风险等级
+const calculateTotalScore = (index: number) => {
+  const scores = form.assessments[index].scores
+  const validScores = scores.filter(s => s > 0)
+  if (validScores.length < 6) {
+    form.assessments[index].totalScore = 0
+    form.assessments[index].riskLevel = ''
+    return
+  }
+
+  const total = scores.reduce((sum, score) => sum + (score || 0), 0)
+  form.assessments[index].totalScore = total
+
+  // 风险等级判断:>18分无风险,15-18分低风险,13-14分中风险,≤12分高风险
+  if (total > 18) {
+    form.assessments[index].riskLevel = 'none'
+  } else if (total >= 15 && total <= 18) {
+    form.assessments[index].riskLevel = 'low'
+  } else if (total >= 13 && total <= 14) {
+    form.assessments[index].riskLevel = 'medium'
+  } else {
+    form.assessments[index].riskLevel = 'high'
+  }
+}
+
+// 获取风险等级文本
+const getRiskText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+
+// 获取风险等级标签类型
+const getRiskTagType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+// 计算总的风险等级(取最高风险)
+const overallRiskLevel = computed(() => {
+  const riskLevels = form.assessments.map(a => a.riskLevel).filter(Boolean)
+  if (riskLevels.includes('high')) return 'high'
+  if (riskLevels.includes('medium')) return 'medium'
+  if (riskLevels.includes('low')) return 'low'
+  if (riskLevels.includes('none')) return 'none'
+  return ''
+})
+
+// 计算最高的总得分
+const overallTotalScore = computed(() => {
+  const scores = form.assessments.map(a => a.totalScore).filter(s => s > 0)
+  if (scores.length === 0) return 0
+  return Math.max(...scores)
+})
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    assessments: form.assessments.map(a => ({
+      assessDate: a.assessDate ? dayjs(a.assessDate).format('YYYY-MM-DD') : '',
+      assessor: a.assessor || '',
+      scores: a.scores || [],
+      totalScore: a.totalScore || 0,
+      riskLevel: a.riskLevel || ''
+    })),
+    preventionMeasures: form.preventionMeasures || [],
+    totalScore: overallTotalScore.value,
+    riskLevel: overallRiskLevel.value
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  if (formData.assessments && formData.assessments.length > 0) {
+    formData.assessments.forEach((a: any, index: number) => {
+      if (index < 3) {
+        form.assessments[index].assessDate = a.assessDate ? dayjs(a.assessDate).toDate() : ''
+        form.assessments[index].assessor = a.assessor || ''
+        form.assessments[index].scores = a.scores || new Array(6).fill(0)
+        form.assessments[index].totalScore = a.totalScore || 0
+        form.assessments[index].riskLevel = a.riskLevel || ''
+      }
+    })
+  }
+  form.preventionMeasures = formData.preventionMeasures || []
+}
+
+/** 重置表单数据 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    elderName: '',
+    elderSex: '',
+    elderAge: '',
+    bedName: '',
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  form.assessments = [
+    { assessDate: '', assessor: '', scores: new Array(6).fill(0), totalScore: 0, riskLevel: '' },
+
+  ]
+  form.preventionMeasures = []
+}
+
+/** 打开弹窗 */
+const open = async (tenantId: any, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-防压疮评估表"
+    await loadData(id)
+  } else {
+    title.value = "新增-防压疮评估表"
+  }
+}
+
+/** 加载评估数据 */
+const loadData = async (id: number) => {
+  try {
+    const res = await pressureSoresGetById(id)
+    if (res) {
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+defineExpose({ open })
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (formLoading.value) return
+  if (!dataForm.value.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  formLoading.value = true
+  try {
+    const assessData = serializeFormData()
+    const tempParams = {
+      ...dataForm.value,
+      assessData: JSON.stringify(assessData),
+      totalScore: overallTotalScore.value,
+      riskLevel: overallRiskLevel.value,
+      assessor: form.assessments[0]?.assessor || '',
+      assessDate: form.assessments[0]?.assessDate ? dayjs(form.assessments[0].assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      const res = await pressureSoresUpdate(tempParams)
+      if (res) {
+        message.success(t('common.updateSuccess'))
+        dialogVisible.value = false
+        emit('success')
+      }
+    } else {
+      const res = await pressureSoresCreate(tempParams)
+      if (res) {
+        message.success(t('common.createSuccess'))
+        dialogVisible.value = false
+        emit('success')
+      }
+    }
+  } finally {
+    setTimeout(() => {
+      formLoading.value = false
+    }, 500)
+  }
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+/** 导出打印 */
+const handleExport = () => {
+  const printWindow = window.open('', '_blank')
+  if (!printWindow) {
+    message.error('请允许弹出窗口')
+    return
+  }
+
+  const assessmentRows = assessmentItems.map((item, index) => {
+    const score1 = form.assessments[0].scores[index] || '-'
+    const score2 = form.assessments[1].scores[index] || '-'
+    const score3 = form.assessments[2].scores[index] || '-'
+    return `
+      <tr>
+        <td class="item-name">${item.name}</td>
+        <td class="option">${item.options[0]}</td>
+        <td class="option">${item.options[1]}</td>
+        <td class="option">${item.options[2]}</td>
+        <td class="option">${item.options[3] || ''}</td>
+        <td class="result">${score1}</td>
+        <td class="result">${score2}</td>
+        <td class="result">${score3}</td>
+      </tr>
+    `
+  }).join('')
+
+  const recordSections = form.assessments.map((record, index) => {
+    return `
+      <div class="record-section">
+        <div class="record-title">第${index + 1}次评估</div>
+        <div class="record-row">
+          <span class="record-label">评估日期:</span>
+          <span class="record-value">${record.assessDate ? dayjs(record.assessDate).format('YYYY-MM-DD') : ''}</span>
+          <span class="record-label">评估人签名:</span>
+          <span class="record-value">${record.assessor || ''}</span>
+          <span class="record-label">评估总得分:</span>
+          <span class="record-value">${record.totalScore || 0} 分</span>
+          <span class="record-label">风险等级结果:</span>
+          <span class="record-value">${getRiskText(record.riskLevel)}</span>
+        </div>
+      </div>
+    `
+  }).join('')
+
+  const preventionOptions = [
+    '避免局部组织长期受压,常更换卧位',
+    '使用保护性用具,如气垫床、翻身枕、泡沫敷料、水垫等',
+    '翻身时动作规范,避免拖、拉、拽等动作',
+    '选择吸汗不刺激宽松衣物,保持衣物及床单平整清洁',
+    '保持皮肤清洁干燥,皮肤受到二便污染时及时清洗',
+    '定期为长者进行温水擦浴及按摩,促进局部血液循环',
+    '改善机体营养状况,增加蛋白质、维生素合微量元素的摄入'
+  ]
+  const preventionChecks = preventionOptions.map(option => {
+    const checked = form.preventionMeasures.includes(option) ? '☑' : '☐'
+    return `<div class="prevention-item">${checked}${option}</div>`
+  }).join('')
+
+  const printContent = `
+    <!DOCTYPE html>
+    <html>
+    <head>
+      <meta charset="UTF-8">
+      <title>防压疮评估表 - ${dataForm.value.elderName || ''}</title>
+      <style>
+        @media print {
+          @page { size: A4 portrait; margin: 10mm; }
+        }
+        body {
+          font-family: 'SimSun', 'Microsoft YaHei', serif;
+          font-size: 10pt;
+          line-height: 1.4;
+          color: #333;
+        }
+        .header {
+          text-align: center;
+          margin-bottom: 15px;
+          border-bottom: 2px solid #333;
+          padding-bottom: 10px;
+        }
+        .title {
+          font-size: 18pt;
+          font-weight: bold;
+          margin-bottom: 10px;
+        }
+        .basic-info {
+          display: flex;
+          justify-content: space-between;
+          margin-bottom: 15px;
+          flex-wrap: wrap;
+        }
+        .info-item {
+          margin-right: 20px;
+          margin-bottom: 5px;
+        }
+        .info-label {
+          font-weight: bold;
+        }
+        .section-title {
+          font-size: 12pt;
+          font-weight: bold;
+          margin: 15px 0 10px 0;
+          border-left: 4px solid #333;
+          padding-left: 8px;
+        }
+        table {
+          width: 100%;
+          border-collapse: collapse;
+          margin-bottom: 15px;
+        }
+        th, td {
+          border: 1px solid #333;
+          padding: 8px;
+          text-align: center;
+        }
+        th {
+          background-color: #f5f5f5;
+          font-weight: bold;
+        }
+        .item-col { width: 12%; }
+        .score-col { width: 12%; }
+        .result-col { width: 10%; }
+        .item-name { font-weight: bold; }
+        .record-section {
+          margin-bottom: 15px;
+          padding: 10px;
+          border: 1px solid #ddd;
+        }
+        .record-title {
+          font-weight: bold;
+          margin-bottom: 8px;
+          border-bottom: 1px solid #eee;
+          padding-bottom: 5px;
+        }
+        .record-row {
+          margin-bottom: 5px;
+        }
+        .record-label {
+          font-weight: bold;
+        }
+        .scoring-note {
+          margin: 15px 0;
+          padding: 10px;
+          background-color: #f9f9f9;
+          border: 1px solid #ddd;
+        }
+        .note-title {
+          font-weight: bold;
+          margin-bottom: 5px;
+        }
+        .prevention-section {
+          margin-top: 15px;
+        }
+        .prevention-item {
+          margin-bottom: 5px;
+        }
+      </style>
+    </head>
+    <body>
+      <div class="header">
+        <div class="title">防压疮评估表</div>
+      </div>
+      <div class="basic-info">
+        <div class="info-item"><span class="info-label">姓名:</span>${dataForm.value.elderName || ''}</div>
+        <div class="info-item"><span class="info-label">性别:</span>${dataForm.value.elderSex || ''}</div>
+        <div class="info-item"><span class="info-label">年龄:</span>${dataForm.value.elderAge || ''}</div>
+        <div class="info-item"><span class="info-label">房号/床号:</span>${dataForm.value.bedName || ''}</div>
+      </div>
+
+      <div class="section-title">等级量表</div>
+      <table>
+        <thead>
+          <tr>
+            <th class="item-col">评估项目</th>
+            <th class="score-col">1 分</th>
+            <th class="score-col">2 分</th>
+            <th class="score-col">3 分</th>
+            <th class="score-col">4 分</th>
+            <th class="result-col">第1次</th>
+            <th class="result-col">第2次</th>
+            <th class="result-col">第3次</th>
+          </tr>
+        </thead>
+        <tbody>
+          ${assessmentRows}
+        </tbody>
+      </table>
+
+      <div class="section-title">评估记录</div>
+      ${recordSections}
+
+      <div class="scoring-note">
+        <div class="note-title">评分说明:</div>
+        <div class="note-content">
+          <p>注:分值 6-23 分,最高分 23 分,最低分 6 分</p>
+          <p>得分越低,发生压疮的危险性越高 18 分是发生压疮危险的临界值</p>
+          <p>风险程度判断:无风险: >18 分;低风险: 15-18 分;中风险: 13-14 分;高风险: ≤12 分</p>
+        </div>
+      </div>
+
+      <div class="section-title prevention-section">预防措施</div>
+      ${preventionChecks}
+    </body>
+    </html>
+  `
+
+  printWindow.document.write(printContent)
+  printWindow.document.close()
+  printWindow.focus()
+  setTimeout(() => {
+    printWindow.print()
+  }, 250)
+}
+</script>
+
+<style scoped lang="scss">
+.pressure-sores-form {
+  padding: 0 20px;
+
+  .form-title {
+    text-align: center;
+    font-size: 20px;
+    font-weight: bold;
+    margin-bottom: 20px;
+    color: #333;
+  }
+
+  .row {
+    display: flex;
+    align-items: center;
+    margin-bottom: 15px;
+
+    text {
+      width: 100px;
+      flex-shrink: 0;
+      color: #606266;
+    }
+
+    .el-input,
+    .el-text {
+      flex: 1;
+    }
+  }
+
+  .assessment-section {
+    margin-top: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      table {
+        width: 100%;
+        border-collapse: collapse;
+        border: 1px solid #dcdfe6;
+
+        th,
+        td {
+          border: 1px solid #dcdfe6;
+          padding: 10px;
+          text-align: center;
+        }
+
+        th {
+          background-color: #f5f7fa;
+          font-weight: bold;
+          color: #606266;
+        }
+
+        .item-col {
+          width: 12%;
+        }
+
+        .score-col {
+          width: 12%;
+        }
+
+        .result-col {
+          width: 10%;
+        }
+
+        .item-name {
+          font-weight: bold;
+        }
+
+        .result {
+          .el-radio-group {
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            gap: 5px;
+          }
+
+          .el-radio {
+            margin-right: 0;
+            height: 20px;
+          }
+        }
+      }
+    }
+  }
+
+  .assessment-records {
+    margin-top: 20px;
+
+    .record-section {
+      margin-bottom: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+
+      .record-header {
+        font-size: 14px;
+        font-weight: bold;
+        margin-bottom: 15px;
+        color: #409eff;
+        border-bottom: 1px solid #e4e7ed;
+        padding-bottom: 10px;
+      }
+    }
+  }
+
+  .scoring-note {
+    margin-top: 20px;
+    padding: 15px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .note-title {
+      font-size: 14px;
+      font-weight: bold;
+      margin-bottom: 10px;
+      color: #333;
+    }
+
+    .note-content {
+      p {
+        margin: 5px 0;
+        color: #606266;
+        font-size: 13px;
+      }
+    }
+  }
+
+  .prevention-section {
+    margin-top: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .prevention-group {
+      .el-checkbox {
+        margin-bottom: 10px;
+        margin-right: 20px;
+      }
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+
+    .risk-rules {
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #fff;
+      border-radius: 4px;
+
+      .rules-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #606266;
+      }
+
+      .rule-tag {
+        margin-right: 10px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+}
+
+/**
+ * 提交给后端的参数说明
+ * 
+ * 创建/更新接口:POST /elderly-assess-pressure-sores/create 或 PUT /elderly-assess-pressure-sores/update
+ * 
+ * Request Body:
+ * {
+ *   id?: number,                    // 记录ID(更新时必填)
+ *   elderId: number,                // 长者ID
+ *   tenantId: number,               // 机构ID
+ *   elderName: string,              // 长者姓名
+ *   elderSex: string,               // 长者性别
+ *   elderAge: string | number,      // 长者年龄
+ *   bedName: string,                // 房号/床号
+ *   assessData: string,             // JSON字符串,包含以下字段:
+ *                                   // {
+ *                                   //   assessments: [              // 3次评估记录数组
+ *                                   //     {
+ *                                   //       assessDate: string,     // 评估日期(YYYY-MM-DD)
+ *                                   //       assessor: string,       // 评估人签名
+ *                                   //       scores: number[],       // 6项评分数组(每项1-4分)
+ *                                   //       totalScore: number,     // 评估总得分(6-24分)
+ *                                   //       riskLevel: string       // 风险等级:none/low/medium/high
+ *                                   //     }
+ *                                   //   ],
+ *                                   //   preventionMeasures: string[], // 预防措施选项数组
+ *                                   //   totalScore: number,         // 评估总得分(取最高得分)
+ *                                   //   riskLevel: string           // 风险等级:none/low/medium/high
+ *                                   // }
+ *   assessor: string,               // 评估人()
+ *   assessDate: string              // 评估日期(冗余字段,第一次评估的日期,YYYY-MM-DD)
+ * }
+ * 
+ * 风险等级规则:
+ * - totalScore > 18  → riskLevel = 'none'   (无风险)
+ * - 15 ≤ totalScore ≤ 18 → riskLevel = 'low'    (低风险)
+ * - 13 ≤ totalScore ≤ 14 → riskLevel = 'medium' (中风险)
+ * - totalScore ≤ 12 → riskLevel = 'high'   (高风险)
+ * 
+ * 评估项目(6项,每项1-4分):
+ * 1. 感觉:1=完全受限, 2=非常受限, 3=轻度受限, 4=未受限
+ * 2. 潮湿:1=持续潮湿, 2=潮湿, 3=有时潮湿, 4=很少潮湿
+ * 3. 活动力:1=限制卧床, 2=可以坐椅子, 3=偶而行走, 4=经常行走
+ * 4. 移动力:1=完全无法移动, 2=严重受限, 3=轻度受限, 4=未受限
+ * 5. 营养:1=非常差, 2=可能不足够, 3=足够, 4=非常好
+ * 6. 摩擦力和剪切力:1=有问题, 2=有潜在问题, 3=无明显问题
+ * 
+ * 预防措施选项:
+ * - 避免局部组织长期受压,常更换卧位
+ * - 使用保护性用具,如气垫床、翻身枕、泡沫敷料、水垫等
+ * - 翻身时动作规范,避免拖、拉、拽等动作
+ * - 选择吸汗不刺激宽松衣物,保持衣物及床单平整清洁
+ * - 保持皮肤清洁干燥,皮肤受到二便污染时及时清洗
+ * - 定期为长者进行温水擦浴及按摩,促进局部血液循环
+ * - 改善机体营养状况,增加蛋白质、维生素合微量元素的摄入
+ */
+</style>

+ 297 - 0
src/views/elderly/apply/nine-precautions/pressure-sores/index.vue

@@ -0,0 +1,297 @@
+<template>
+  <ContentWrap>
+    <!-- 防压疮评估表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="totalScore" header-align="center" align="center" label="评估总得分" min-width="120" show-overflow-tooltip/>
+      <el-table-column prop="riskLevel" header-align="center" align="center" label="风险等级" min-width="120" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getRiskLevelType(scope.row.riskLevel)">
+            {{ getRiskLevelText(scope.row.riskLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from "@/utils/dateUtil";
+import {
+  pressureSoresDelete,
+  pressureSoresPage
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const userStore = useUserStore()
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch, count)
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await pressureSoresPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate = getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if (queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1) {
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id, false)
+}
+
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, false)
+}
+
+const openFormDetail = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, true)
+}
+
+const openClose = async (item: any) => {
+  try {
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      try {
+        const res = await pressureSoresDelete(item.id)
+        if (res) {
+          message.success(t('common.updateSuccess'))
+          await getList()
+        }
+      } catch (err) { }
+    }
+  } catch { }
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    await message.cancelConfirm()
+    message.success(t('common.delSuccess'))
+    await getList()
+  } catch { }
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if (route.query && route.query.elderName) {
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// 获取风险等级类型
+const getRiskLevelType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+// 获取风险等级文本
+const getRiskLevelText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 455 - 0
src/views/elderly/apply/nine-precautions/risk-disclosure-statement/Form.vue

@@ -0,0 +1,455 @@
+<template>
+  <Dialog
+    v-model="dialogVisible"
+    :title="dialogTitle"
+    width="80%"
+    class="risk-disclosure-statement-form"
+    scroll
+    @close="handleClosed"
+  >
+    <el-form
+      ref="formRef"
+      :model="dataForm"
+      label-width="120px"
+      :rules="dataRule"
+      v-loading="loading"
+    >
+      <!-- 长者搜索 - 参照 ProcessForm.vue 中的 SelectElder 使用方式 -->
+      <div class="section-title">长者信息</div>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="长者姓名" prop="elderId">
+            <SelectElder
+              ref="selectElderRef"
+              v-model="dataForm.elderId"
+              @elder="handleSelectElder"
+              type="1"
+              :tId="dataForm.tenantId"
+              :disabled="isEdit"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="证件号码">
+            <TgInput v-model="dataForm.idCard" disabled />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <!-- 长者详情展示 - 对应图片中的表一表头信息 -->
+      <div v-if="elderDetail.id" class="elder-detail-wrap">
+        <el-descriptions :column="4" border size="small">
+          <el-descriptions-item label="区/楼层">{{ elderDetail.floorName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="姓名">{{ elderDetail.elderName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="性别">{{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, elderDetail.elderSex) || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="年龄">{{ elderDetail.elderAge || '-' }}岁</el-descriptions-item>
+          <el-descriptions-item label="床号">{{ elderDetail.bedName || '-' }}</el-descriptions-item>
+        </el-descriptions>
+      </div>
+
+      <!-- 服务安全风险告知书内容 -->
+      <div class="section-title">服务安全风险知情告知书</div>
+      <div class="notice-content">
+        <p class="notice-header">尊敬的老年人/相关第三方/监护人:</p>
+        <p class="notice-text">
+          您好!感谢您对本机构的信任和支持。
+        </p>
+        <p class="notice-text">
+          经我院评估您或您相关第三方的身体状况,您或您亲属在我院养老期间,存在下列服务安全风险。为保证对您或您相关第三方的服务质量,特向您告知!我院将针对老年人的情况做好相关防范措施,请您理解、配合、并支持相关工作措施的落实。
+        </p>
+
+        <!-- 风险项目列表 -->
+        <div class="risk-list">
+          <div v-for="(item, index) in riskItems" :key="index" class="risk-item">
+            <el-checkbox v-model="item.checked" :label="item.name" />
+            <span class="risk-label">风险程度:</span>
+            <el-radio-group v-model="item.riskLevel" size="small">
+              <el-radio label="low">低危</el-radio>
+              <el-radio label="medium">中危</el-radio>
+              <el-radio label="high">高危</el-radio>
+            </el-radio-group>
+          </div>
+        </div>
+
+        <!-- 其他风险 -->
+        <el-form-item label="其它服务风险:" class="other-risk">
+          <TgTextarea v-model="dataForm.otherRisk" placeholder="请输入其他服务风险" :rows="2" />
+        </el-form-item>
+      </div>
+
+      <!-- 签名区域 -->
+      <div class="section-title">签字确认</div>
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="首次告知签名:" label-width="170">
+            <div style="display: flex;flex-direction: row">
+              <div style="display: flex;align-items: center;width: 560px">
+                通过对老年人的整体评估,老年人有可能发生:
+                <TgInput v-model="dataForm.firstInformer" placeholder="输入风险" style="width: 250px;margin-left: 10px"/>
+              </div>
+              其风险及防范措施已向老年人或相关第三方进行了如实告知。
+            </div>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="护理人员签名" label-width="170">
+            <TgInput v-model="dataForm.firstNurse" placeholder="签字人" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="老年人/相关第三方签字" label-width="170">
+            <TgInput v-model="dataForm.firstSign" placeholder="签字人" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="签字日期">
+            <TgDatePicker v-model="dataForm.firstSignDate" type="date" placeholder="选择日期" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <!-- 第二次告知签名 -->
+      <el-divider />
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="第二次告知签名:" label-width="170">
+            <div style="display: flex;flex-direction: row">
+              <div style="display: flex;align-items: center;width: 700px">
+                通过对老年人的整体评估,随着病情的发展变化,老年人有可能发生:
+                <TgInput v-model="dataForm.firstInformer" placeholder="输入风险" style="width: 250px;margin-left: 10px"/>
+              </div>
+              其风险及防范措施已向老年人或相关第三方进行了如实告知。
+            </div>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="护理人员" label-width="170">
+            <TgInput v-model="dataForm.secondNurse" placeholder="签字人" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="变动风险" label-width="170">
+            <TgInput v-model="dataForm.changedRisk" placeholder="变动风险描述" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="风险程度">
+            <el-radio-group v-model="dataForm.changedRiskLevel" size="small">
+              <el-radio label="low">低危</el-radio>
+              <el-radio label="medium">中危</el-radio>
+              <el-radio label="high">高危</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="老年人/相关第三方签字" label-width="170">
+            <TgInput v-model="dataForm.secondSign" placeholder="签字人" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="签字日期">
+            <TgDatePicker v-model="dataForm.secondSignDate" type="date" placeholder="选择日期" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <!-- 其他备注 -->
+      <el-divider />
+      <el-form-item label="其他">
+        <TgTextarea v-model="dataForm.remark" placeholder="请输入其他备注信息" :rows="3" />
+      </el-form-item>
+
+      <!-- 底部签名 -->
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="护理人员">
+            <TgInput v-model="dataForm.finalNurse" placeholder="护理人员签字" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="老年人/相关第三方签字" label-width="170">
+            <TgInput v-model="dataForm.finalSign" placeholder="签字人" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12" :offset="12">
+          <el-form-item label="签字日期" label-width="170">
+            <TgDatePicker v-model="dataForm.finalSignDate" type="date" placeholder="选择日期" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="handleClosed">取消</el-button>
+      <el-button type="primary" @click="submitForm" :loading="submitLoading">确定</el-button>
+    </template>
+  </Dialog>
+</template>
+
+<script setup lang="ts">
+import { DICT_TYPE, getDictLabel } from '@/utils/dict'
+import { getElderInfoById } from '@/api/elderly/elder/elderly-Info'
+import {
+  addSafetyRiskNotice,
+  updateSafetyRiskNotice,
+  getSafetyRiskNoticeById
+} from '@/api/elderly/apply/check-in'
+import { getTenantId } from '@/utils/auth'
+import { formatTime } from '@/utils'
+
+defineOptions({ name: 'RiskDisclosureStatementForm' })
+
+const emit = defineEmits(['success'])
+
+const dialogVisible = ref(false)
+const dialogTitle = ref('新增服务安全风险知情告知书')
+const loading = ref(false)
+const submitLoading = ref(false)
+const isEdit = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+
+// 长者详情
+const elderDetail = ref<any>({})
+
+// 风险项目
+const riskItems = ref([
+  { name: '噎食', checked: false, riskLevel: '' },
+  { name: '食品药品误食', checked: false, riskLevel: '' },
+  { name: '压疮', checked: false, riskLevel: '' },
+  { name: '烫伤', checked: false, riskLevel: '' },
+  { name: '坠床', checked: false, riskLevel: '' },
+  { name: '跌倒', checked: false, riskLevel: '' },
+  { name: '他伤或自伤', checked: false, riskLevel: '' },
+  { name: '走失', checked: false, riskLevel: '' }
+])
+
+// 表单数据
+const dataForm = reactive({
+  id: undefined,
+  elderId: '',
+  idCard: '',
+  tenantId: undefined,
+  // 风险项目数据 (JSON格式存储)
+  riskItemsJson: '',
+  otherRisk: '',
+  // 首次告知签名
+  firstInformer: '',
+  firstNurse: '',
+  firstSign: '',
+  firstSignDate: '',
+  // 第二次告知签名
+  secondInformer: '',
+  secondNurse: '',
+  secondSign: '',
+  secondSignDate: '',
+  changedRisk: '',
+  changedRiskLevel: '',
+  // 其他
+  remark: '',
+  finalNurse: '',
+  finalSign: '',
+  finalSignDate: ''
+})
+
+// 表单校验规则
+const dataRule = {
+  elderId: [{ required: true, message: '长者不能为空', trigger: 'change' }]
+}
+
+// 选择长者 - 参照 ProcessForm.vue 中的使用方式
+const handleSelectElder = async (item: any) => {
+  if (item && item.id) {
+    dataForm.elderId = item.id
+    dataForm.idCard = item.idCard || ''
+    // 获取长者详情
+    try {
+      const res = await getElderInfoById(item.id)
+      elderDetail.value = res
+    } catch (e) {
+      console.error('获取长者详情失败', e)
+    }
+  }
+}
+
+// 打开弹窗
+const open = async (row?: any) => {
+  dialogVisible.value = true
+  isEdit.value = false
+  dialogTitle.value = '新增服务安全风险知情告知书'
+  resetForm()
+  dataForm.tenantId = getTenantId()
+
+  if (row && row.id) {
+    isEdit.value = true
+    dialogTitle.value = '编辑服务安全风险知情告知书'
+    loading.value = true
+    try {
+      const res = await getSafetyRiskNoticeById(row.id)
+      Object.assign(dataForm, res)
+      // 解析风险项目
+      if (res.riskItemsJson) {
+        const savedRiskItems = JSON.parse(res.riskItemsJson)
+        riskItems.value = riskItems.value.map(item => {
+          const saved = savedRiskItems.find((s: any) => s.name === item.name)
+          return saved || item
+        })
+      }
+      // 获取长者详情
+      if (res.elderId) {
+        const elderRes = await getElderInfoById(res.elderId)
+        elderDetail.value = elderRes
+      }
+    } catch (e) {
+      console.error('获取详情失败', e)
+    } finally {
+      loading.value = false
+    }
+  }
+}
+
+// 重置表单
+const resetForm = () => {
+  Object.assign(dataForm, {
+    id: undefined,
+    elderId: '',
+    idCard: '',
+    tenantId: getTenantId(),
+    riskItemsJson: '',
+    otherRisk: '',
+    firstInformer: '',
+    firstNurse: '',
+    firstSign: '',
+    firstSignDate: '',
+    secondInformer: '',
+    secondNurse: '',
+    secondSign: '',
+    secondSignDate: '',
+    changedRisk: '',
+    changedRiskLevel: '',
+    remark: '',
+    finalNurse: '',
+    finalSign: '',
+    finalSignDate: ''
+  })
+  elderDetail.value = {}
+  riskItems.value = [
+    { name: '噎食', checked: false, riskLevel: '' },
+    { name: '食品药品误食', checked: false, riskLevel: '' },
+    { name: '压疮', checked: false, riskLevel: '' },
+    { name: '烫伤', checked: false, riskLevel: '' },
+    { name: '坠床', checked: false, riskLevel: '' },
+    { name: '跌倒', checked: false, riskLevel: '' },
+    { name: '他伤或自伤', checked: false, riskLevel: '' },
+    { name: '走失', checked: false, riskLevel: '' }
+  ]
+}
+
+// 关闭弹窗
+const handleClosed = () => {
+  dialogVisible.value = false
+}
+
+// 提交表单
+const submitForm = async () => {
+  if (!formRef.value) return
+  const valid = await formRef.value.validate()
+  if (!valid) return
+
+  submitLoading.value = true
+  try {
+    // 处理风险项目数据
+    const selectedRisks = riskItems.value.filter(item => item.checked)
+    const submitData = {
+      ...dataForm,
+      riskItemsJson: JSON.stringify(selectedRisks)
+    }
+
+    if (isEdit.value) {
+      await updateSafetyRiskNotice(submitData)
+    } else {
+      await addSafetyRiskNotice(submitData)
+    }
+    message.success('操作成功')
+    dialogVisible.value = false
+    emit('success')
+  } catch (e) {
+    console.error('提交失败', e)
+  } finally {
+    submitLoading.value = false
+  }
+}
+
+defineExpose({ open })
+</script>
+
+<style scoped lang="scss">
+.section-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #333;
+  margin: 20px 0 15px;
+  padding-left: 10px;
+  border-left: 4px solid #409eff;
+}
+
+.elder-detail-wrap {
+  margin: 15px 0;
+  padding: 15px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+}
+
+.notice-content {
+  padding: 15px;
+  background-color: #fafafa;
+  border-radius: 4px;
+  margin-bottom: 20px;
+
+  .notice-header {
+    font-weight: bold;
+    margin-bottom: 10px;
+  }
+
+  .notice-text {
+    text-indent: 2em;
+    line-height: 1.8;
+    margin-bottom: 10px;
+  }
+}
+
+.risk-list {
+  margin: 15px 0;
+
+  .risk-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 10px;
+    padding: 8px;
+    background-color: #fff;
+    border-radius: 4px;
+
+    .risk-label {
+      margin-left: 20px;
+      margin-right: 10px;
+      color: #666;
+    }
+
+    :deep(.el-checkbox) {
+      min-width: 120px;
+    }
+  }
+}
+
+.other-risk {
+  margin-top: 15px;
+}
+</style>

+ 177 - 0
src/views/elderly/apply/nine-precautions/risk-disclosure-statement/index.vue

@@ -0,0 +1,177 @@
+<script setup lang="ts">
+import { DICT_TYPE, getDictLabel } from '@/utils/dict'
+import {
+  getSafetyRiskNoticePage,
+  deleteSafetyRiskNotice
+} from '@/api/elderly/apply/check-in'
+import { formatTime } from '@/utils'
+import SafetyRiskNoticeForm from './Form.vue'
+
+defineOptions({ name: 'RiskDisclosureStatement' })
+
+const message = useMessage()
+const { t } = useI18n()
+
+// 列表数据
+const loading = ref(false)
+const list = ref([])
+const total = ref(0)
+
+// 查询参数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: undefined,
+  floorName: undefined
+})
+const queryFormRef = ref()
+
+// 获取列表
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await getSafetyRiskNoticePage(queryParams)
+    list.value = data.list || []
+    total.value = data.total || 0
+  } finally {
+    loading.value = false
+  }
+}
+
+// 搜索
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+// 重置
+const resetQuery = () => {
+  queryFormRef.value?.resetFields()
+  handleQuery()
+}
+
+// 新增
+const formRef = ref()
+const handleAdd = () => {
+  formRef.value?.open()
+}
+
+// 编辑
+const handleEdit = (row: any) => {
+  formRef.value?.open(row)
+}
+
+// 删除
+const handleDelete = async (row: any) => {
+  try {
+    await message.confirm('确认删除该记录吗?')
+    await deleteSafetyRiskNotice(row.id)
+    message.success('删除成功')
+    getList()
+  } catch (e) {
+    // 用户取消
+  }
+}
+
+// 初始化
+onMounted(() => {
+  getList()
+})
+</script>
+
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="80px"
+    >
+      <el-form-item label="长者姓名" prop="elderName">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="请输入长者姓名"
+          class="!w-240px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="楼层" prop="floorName">
+        <el-input
+          v-model="queryParams.floorName"
+          placeholder="请输入楼层"
+          class="!w-240px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery">
+          <Icon icon="ep:search" class="mr-5px" /> 搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon icon="ep:refresh" class="mr-5px" /> 重置
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <TabBarBtn>
+      <template #next>
+        <el-button type="primary" @click="handleAdd">
+          <Icon icon="ep:plus" class="mr-5px" /> 新增告知书
+        </el-button>
+      </template>
+    </TabBarBtn>
+
+    <el-table v-loading="loading" :data="list" stripe>
+      <el-table-column type="index" label="序号" width="60" align="center" />
+      <el-table-column label="长者姓名" prop="elderName" min-width="100" />
+      <el-table-column label="性别" prop="elderSex" min-width="80">
+        <template #default="{ row }">
+          {{ getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, row.elderSex) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="年龄" prop="elderAge" min-width="80" />
+      <el-table-column label="楼层" prop="floorName" min-width="100" />
+      <el-table-column label="床号" prop="bedName" min-width="100" />
+      <el-table-column label="首次告知日期" prop="firstSignDate" min-width="120">
+        <template #default="{ row }">
+          {{ row.firstSignDate ? formatTime(row.firstSignDate, 'yyyy-MM-dd') : '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="第二次告知日期" prop="secondSignDate" min-width="120">
+        <template #default="{ row }">
+          {{ row.secondSignDate ? formatTime(row.secondSignDate, 'yyyy-MM-dd') : '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" prop="createTime" min-width="150">
+        <template #default="{ row }">
+          {{ row.createTime ? formatTime(row.createTime, 'yyyy-MM-dd HH:mm') : '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="180" fixed="right">
+        <template #default="{ row }">
+          <el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
+          <el-button link type="danger" @click="handleDelete(row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 新增/编辑弹窗 -->
+  <SafetyRiskNoticeForm ref="formRef" @success="getList" />
+</template>
+
+<style scoped lang="scss">
+</style>

+ 807 - 0
src/views/elderly/apply/nine-precautions/wander-away/AddForm.vue

@@ -0,0 +1,807 @@
+<template>
+  <el-drawer v-model="dialogVisible" :title="title" size="90%" :before-close="handleClosed">
+    <div class="assessment-form">
+      <div class="form-header">
+        <el-form :model="dataForm" :rules="rules" ref="formRef" label-width="80px">
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="姓名" prop="elderName">
+                <SelectElder
+                    ref="selectElderRef" :tenantId="dataForm.tenantId" @up="elderUp" :disabled="isDetail"
+                  :elderName="dataForm.elderName" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="年龄">
+                <el-input v-model="dataForm.elderAge" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="性别">
+                <el-input v-model="dataForm.elderSex" disabled />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="房号/床号">
+                <el-input v-model="dataForm.bedName" disabled />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
+      <!-- 危险因素评估表 -->
+      <div class="risk-factors-section">
+        <div class="section-title">危险因素评估</div>
+        <table class="assessment-table">
+          <thead>
+            <tr>
+              <th class="col-category">评估项目</th>
+              <th class="col-item">具体项目</th>
+              <th class="col-option">选项</th>
+              <th class="col-score">分值</th>
+              <th class="col-result">得分</th>
+            </tr>
+          </thead>
+          <tbody>
+            <!-- 基本资料 - 年龄 -->
+            <tr>
+              <td class="col-category" rowspan="3">基本资料</td>
+              <td class="col-item">年龄</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[0]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">≥60岁</el-radio>
+                  <el-radio :label="0">≤60岁</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[0] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[0] }}</td>
+            </tr>
+
+            <!-- 基本资料 - 性别 -->
+            <tr>
+              <td class="col-item">性别</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[1]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">男性</el-radio>
+                  <el-radio :label="0">女性</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[1] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[1] }}</td>
+            </tr>
+
+            <!-- 基本资料 - 文化程度 -->
+            <tr>
+              <td class="col-item">文化程度</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[2]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="0">受过高等教育</el-radio>
+                  <el-radio :label="1">未受高等教育</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[2] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[2] }}</td>
+            </tr>
+
+            <!-- 走失既往史 -->
+            <tr>
+              <td class="col-category">走失既往史</td>
+              <td class="col-item">有无走失过现象</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[3]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[3] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[3] }}</td>
+            </tr>
+
+            <!-- 意识状态 -->
+            <tr>
+              <td class="col-category">意识状态</td>
+              <td class="col-item">意识障碍</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[4]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[4] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[4] }}</td>
+            </tr>
+
+            <!-- 心理状态 -->
+            <tr>
+              <td class="col-category">心理状态</td>
+              <td class="col-item">情绪低落、焦虑抑郁等</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[5]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[5] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[5] }}</td>
+            </tr>
+
+            <!-- 疾病史 - 心脑血管 -->
+            <tr>
+              <td class="col-category" rowspan="5">疾病史</td>
+              <td class="col-item">心脑血管(脑出血、脑梗塞、脑萎缩等)</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[6]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[6] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[6] }}</td>
+            </tr>
+
+            <!-- 疾病史 - 术后认知障碍 -->
+            <tr>
+              <td class="col-item">术后认知障碍</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[7]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[7] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[7] }}</td>
+            </tr>
+
+            <!-- 疾病史 - 定向力障碍 -->
+            <tr>
+              <td class="col-item">定向力障碍脑炎、肝性脑病、酒精性脑病</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[8]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[8] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[8] }}</td>
+            </tr>
+
+            <!-- 疾病史 - 记忆力障碍 -->
+            <tr>
+              <td class="col-item">记忆力或认知功能障碍(智障、老年痴呆等)</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[9]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[9] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[9] }}</td>
+            </tr>
+
+            <!-- 疾病史 - 精神行为异常 -->
+            <tr>
+              <td class="col-item">有精神行为异常(精神分裂、抑郁等)</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[10]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[10] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[10] }}</td>
+            </tr>
+
+            <!-- 药物影响认知 - 抗抑郁药 -->
+            <tr>
+              <td class="col-category" rowspan="3">药物影响认知</td>
+              <td class="col-item">抗抑郁药</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[11]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[11] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[11] }}</td>
+            </tr>
+
+            <!-- 药物影响认知 - 抗癫痫药 -->
+            <tr>
+              <td class="col-item">抗癫痫药</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[12]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[12] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[12] }}</td>
+            </tr>
+
+            <!-- 药物影响认知 - 心脏病药 -->
+            <tr>
+              <td class="col-item">心脏病药</td>
+              <td class="col-option">
+                <el-radio-group v-model="form.assessment.scores[13]" :disabled="isDetail" @change="calculateTotal">
+                  <el-radio :label="1">有</el-radio>
+                  <el-radio :label="0">无</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="col-score">
+                <span v-if="form.assessment.scores[13] === 1">1</span>
+                <span v-else>0</span>
+              </td>
+              <td class="col-result">{{ form.assessment.scores[13] }}</td>
+            </tr>
+          </tbody>
+        </table>
+
+        <!-- 风险程度判断 -->
+        <div class="risk-judgment">
+          <span class="judgment-title">风险程度判断:</span>
+          <el-radio-group v-model="form.riskLevel" :disabled="isDetail">
+            <el-radio label="none">无风险:0-3分</el-radio>
+            <el-radio label="low">低风险:4分</el-radio>
+            <el-radio label="medium">中风险:5-6分</el-radio>
+            <el-radio label="high">高风险:≥7分</el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+
+      <!-- 评估记录 -->
+      <div class="assessment-records">
+        <div class="record-section">
+          <div class="record-header">评估记录</div>
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="评估日期:" label-width="90px">
+                <el-date-picker
+                  v-model="form.assessment.assessDate"
+                  type="date"
+                  placeholder="选择日期"
+                  value-format="YYYY-MM-DD"
+                  :disabled="isDetail"
+                  style="width: 100%"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="评估人签名:" label-width="100px">
+                <el-input v-model="form.assessment.assessor" :disabled="isDetail" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="评估总得分:" label-width="100px">
+                <span class="score-text">{{ form.assessment.totalScore }} 分</span>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="风险等级结果:" label-width="100px">
+                <el-tag :type="getRiskTagType(form.riskLevel)">
+                  {{ getRiskText(form.riskLevel) }}
+                </el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+
+      <!-- 预防措施 -->
+      <div class="prevention-section">
+        <div class="section-title">预防措施:</div>
+        <el-checkbox-group v-model="form.preventionMeasures" :disabled="isDetail" class="prevention-group">
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+              <el-checkbox label="重点观察,加强巡视">重点观察,加强巡视</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+              <el-checkbox label="严格加强交班制度,重点床头交接清点人数">严格加强交班制度,重点床头交接清点人数</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+              <el-checkbox label="在老人房间门口坐特殊、容易记忆的标识,便于老人的辨认">在老人房间门口坐特殊、容易记忆的标识,便于老人的辨认</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="定期了解长者心理变化,对情绪或活动异常的长者加强观察,主动沟通,尽量满足合理要求,避免外出">定期了解长者心理变化,对情绪或活动异常的长者加强观察,主动沟通,尽量满足合理要求,避免外出</el-checkbox>
+            </el-col>
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+              <el-checkbox label="失智长者需在家属陪同下并填写请假单后方可外出">失智长者需在家属陪同下并填写请假单后方可外出</el-checkbox>
+            </el-col>
+          </el-row>
+        </el-checkbox-group>
+      </div>
+
+      <!-- 提交参数字段说明 -->
+      <div class="api-params-section">
+        <div class="section-title">接口参数说明</div>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="接口地址">POST /elderly-assess-wander-away/create 或 PUT /elderly-assess-wander-away/update</el-descriptions-item>
+          <el-descriptions-item label="id">记录ID(更新时必填)</el-descriptions-item>
+          <el-descriptions-item label="elderId">长者ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="tenantId">机构ID(必填)</el-descriptions-item>
+          <el-descriptions-item label="elderName">长者姓名</el-descriptions-item>
+          <el-descriptions-item label="elderSex">长者性别</el-descriptions-item>
+          <el-descriptions-item label="elderAge">长者年龄</el-descriptions-item>
+          <el-descriptions-item label="bedName">房号/床号</el-descriptions-item>
+          <el-descriptions-item label="assessData">
+            JSON字符串,包含:<br/>
+            - assessment: 评估记录 {assessDate, assessor, scores[], totalScore}<br/>
+            - preventionMeasures: 预防措施选项数组<br/>
+            - riskLevel: 风险等级(none/low/medium/high)
+          </el-descriptions-item>
+          <el-descriptions-item label="assessor">评估人()</el-descriptions-item>
+          <el-descriptions-item label="assessDate">评估日期(YYYY-MM-DD)</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="risk-rules">
+          <div class="rules-title">风险等级规则:</div>
+          <el-tag type="success" class="rule-tag">0-3分:无风险</el-tag>
+          <el-tag type="info" class="rule-tag">4分:低风险</el-tag>
+          <el-tag type="warning" class="rule-tag">5-6分:中风险</el-tag>
+          <el-tag type="danger" class="rule-tag">≥7分:高风险</el-tag>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleClosed">关闭</el-button>
+      <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
+      <el-button style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
+        v-show="!isDetail" @click="submitForm">确定</el-button>
+    </template>
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive } from 'vue'
+import dayjs from 'dayjs'
+import {
+  wanderAwayCreate,
+  wanderAwayGetById,
+  wanderAwayUpdate,
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const title = ref('')
+const dialogVisible = ref(false)
+const formRef = ref()
+const selectElderRef = ref()
+const isDetail = ref(false)
+const formLoading = ref(false)
+
+let dataForm = ref({
+  id: undefined,
+  elderName: '',
+  elderSex: '',
+  elderAge: '',
+  bedName: '',
+  elderId: '',
+  tenantId: undefined
+})
+
+const elderUp = (e: any) => {
+  dataForm.value.elderName = e.elderName
+  dataForm.value.elderId = e.id
+  dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
+  dataForm.value.bedName = e.bedName || ''
+  dataForm.value.elderAge = e.elderAge
+}
+
+// 表单数据 - 14项评估
+const form = reactive({
+  assessment: {
+    assessDate: '',
+    assessor: '',
+    scores: new Array(14).fill(0),
+    totalScore: 0
+  },
+  preventionMeasures: [],
+  riskLevel: ''
+})
+
+// 计算总得分
+const calculateTotal = () => {
+  const scores = form.assessment.scores
+  const total = scores.reduce((sum, score) => sum + (score || 0), 0)
+  form.assessment.totalScore = total
+
+  // 自动判断风险等级(更新中风险范围为5-6分)
+  if (total <= 3) {
+    form.riskLevel = 'none'
+  } else if (total === 4) {
+    form.riskLevel = 'low'
+  } else if (total >= 5 && total <= 6) {
+    form.riskLevel = 'medium'
+  } else if (total >= 7) {
+    form.riskLevel = 'high'
+  }
+}
+
+// 获取风险等级文本
+const getRiskText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+
+// 获取风险等级标签类型
+const getRiskTagType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+/** 将表单数据序列化为 JSON 对象 */
+const serializeFormData = () => {
+  return {
+    assessment: {
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : '',
+      assessor: form.assessment.assessor || '',
+      scores: form.assessment.scores || [],
+      totalScore: form.assessment.totalScore || 0
+    },
+    preventionMeasures: form.preventionMeasures || [],
+    riskLevel: form.riskLevel || ''
+  }
+}
+
+/** 将 JSON 对象反序列化为表单数据 */
+const deserializeFormData = (formData: Record<string, any>) => {
+  if (!formData) return
+
+  if (formData.assessment) {
+    form.assessment.assessDate = formData.assessment.assessDate ? dayjs(formData.assessment.assessDate).toDate() : ''
+    form.assessment.assessor = formData.assessment.assessor || ''
+    form.assessment.scores = formData.assessment.scores || new Array(14).fill(0)
+    form.assessment.totalScore = formData.assessment.totalScore || 0
+  }
+  form.preventionMeasures = formData.preventionMeasures || []
+  form.riskLevel = formData.riskLevel || ''
+}
+
+/** 重置表单数据 */
+const resetForm = () => {
+  dataForm.value = {
+    id: undefined,
+    elderName: '',
+    elderSex: '',
+    elderAge: '',
+    bedName: '',
+    elderId: '',
+    tenantId: undefined
+  }
+  formRef.value?.resetFields()
+
+  form.assessment = {
+    assessDate: '',
+    assessor: '',
+    scores: new Array(14).fill(0),
+    totalScore: 0
+  }
+  form.preventionMeasures = []
+  form.riskLevel = ''
+}
+
+/** 打开弹窗 */
+const open = async (tenantId: any, id?: any, detail: boolean = false) => {
+  resetForm()
+  dialogVisible.value = true
+  dataForm.value.id = id || undefined
+  dataForm.value.tenantId = tenantId
+  isDetail.value = detail
+  if (id) {
+    title.value = "编辑-防走失风险评估表"
+    await loadData(id)
+  } else {
+    title.value = "新增-防走失风险评估表"
+  }
+}
+
+/** 加载评估数据 */
+const loadData = async (id: number) => {
+  try {
+    const res = await wanderAwayGetById(id)
+    if (res) {
+      dataForm.value.elderName = res.elderName || ''
+      dataForm.value.elderId = res.elderId || ''
+      dataForm.value.elderSex = res.elderSex || ''
+      dataForm.value.bedName = res.bedName || ''
+      dataForm.value.elderAge = res.elderAge || ''
+      await selectElderRef.value.upData(res.elderName, res.elderId)
+      if (res.assessData) {
+        const formData = JSON.parse(res.assessData)
+        deserializeFormData(formData)
+      }
+    }
+  } catch (error) {
+    message.error('加载评估数据失败')
+  }
+}
+
+defineExpose({ open })
+
+const emit = defineEmits(['success'])
+
+/** 提交表单 */
+const submitForm = async () => {
+  if (!dataForm.value.elderId) {
+    message.error('请选择长者')
+    return
+  }
+
+  formLoading.value = true
+  try {
+    const formData = serializeFormData()
+    const payload = {
+      id: dataForm.value.id,
+      elderId: dataForm.value.elderId,
+      tenantId: dataForm.value.tenantId,
+      elderName: dataForm.value.elderName,
+      elderSex: dataForm.value.elderSex,
+      elderAge: dataForm.value.elderAge,
+      bedName: dataForm.value.bedName,
+      assessData: JSON.stringify(formData),
+      riskLevel: form.riskLevel,
+      assessor: form.assessment.assessor,
+      assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : ''
+    }
+
+    if (dataForm.value.id) {
+      await wanderAwayUpdate(payload)
+      message.success(t('common.updateSuccess'))
+    } else {
+      await wanderAwayCreate(payload)
+      message.success(t('common.createSuccess'))
+    }
+    dialogVisible.value = false
+    emit('success')
+  } catch (error) {
+    message.error('提交失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 关闭弹窗 */
+const handleClosed = () => {
+  dialogVisible.value = false
+}
+
+/** 导出/打印 */
+const handleExport = () => {
+  message.info('打印功能开发中')
+}
+
+const rules = {
+  elderName: [{ required: true, message: '请选择长者', trigger: 'change' }]
+}
+</script>
+
+<style scoped lang="scss">
+.assessment-form {
+  padding: 0 20px;
+
+  .form-header {
+    margin-bottom: 20px;
+  }
+
+  .risk-factors-section {
+    margin-bottom: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .assessment-table {
+      width: 100%;
+      border-collapse: collapse;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+      overflow: hidden;
+
+      thead {
+        background-color: #f5f7fa;
+        font-weight: bold;
+
+        th {
+          padding: 12px;
+          border: 1px solid #e4e7ed;
+          text-align: center;
+          font-weight: bold;
+        }
+      }
+
+      tbody {
+        td {
+          padding: 12px;
+          border: 1px solid #e4e7ed;
+          vertical-align: middle;
+        }
+      }
+
+      .col-category {
+        width: 12%;
+        text-align: center;
+        font-weight: bold;
+        background-color: #fafafa;
+      }
+
+      .col-item {
+        width: 30%;
+        text-align: left;
+      }
+
+      .col-option {
+        width: 30%;
+        text-align: left;
+
+        .el-radio-group {
+          display: flex;
+          flex-direction: column;
+          gap: 8px;
+        }
+      }
+
+      .col-score {
+        width: 14%;
+        text-align: center;
+      }
+
+      .col-result {
+        width: 14%;
+        text-align: center;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+
+    .risk-judgment {
+      margin-top: 15px;
+      padding: 15px;
+      background-color: #f5f7fa;
+      border-radius: 4px;
+
+      .judgment-title {
+        font-weight: bold;
+        margin-right: 15px;
+      }
+    }
+  }
+
+  .assessment-records {
+    margin-top: 20px;
+
+    .record-section {
+      margin-bottom: 20px;
+      padding: 15px;
+      border: 1px solid #e4e7ed;
+      border-radius: 4px;
+
+      .record-header {
+        font-size: 14px;
+        font-weight: bold;
+        margin-bottom: 15px;
+        color: #409eff;
+        border-bottom: 1px solid #e4e7ed;
+        padding-bottom: 10px;
+      }
+
+      .score-text {
+        font-size: 16px;
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+  }
+
+  .prevention-section {
+    margin-top: 20px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #409eff;
+      padding-left: 10px;
+    }
+
+    .prevention-group {
+      .el-checkbox {
+        margin-bottom: 10px;
+        margin-right: 20px;
+      }
+    }
+  }
+
+  .api-params-section {
+    margin-top: 30px;
+    padding: 20px;
+    background-color: #f5f7fa;
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      color: #333;
+      border-left: 4px solid #67c23a;
+      padding-left: 10px;
+    }
+
+    .risk-rules {
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #fff;
+      border-radius: 4px;
+
+      .rules-title {
+        font-weight: bold;
+        margin-bottom: 10px;
+        color: #606266;
+      }
+
+      .rule-tag {
+        margin-right: 10px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+}
+</style>

+ 297 - 0
src/views/elderly/apply/nine-precautions/wander-away/index.vue

@@ -0,0 +1,297 @@
+<template>
+  <ContentWrap>
+    <!-- 防走失风险评估表 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="110px"
+    >
+      <el-form-item label="长者姓名">
+        <el-input
+          v-model="queryParams.elderName"
+          placeholder="长者姓名"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="评估人">
+        <el-input
+          v-model="queryParams.assessor"
+          placeholder="评估人"
+          class="!w-240px"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="记录日期">
+        <el-date-picker
+          size="default"
+          ref="selectRef"
+          class="!w-240px"
+          v-model="queryParams.assessDate"
+          type="daterange"
+          :clearable="true"
+          :editable="false"
+          placeholder="选择记录日期"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          date-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="handleQuery" style="margin-left: 2vw"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <div class="mb-10px">
+      <ButtonAdd @click="openForm(undefined)" />
+    </div>
+    <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
+      <el-table-column header-align="center" align="center" label="序号" width="60">
+        <template #default="scope">
+          {{
+            scope.$index + (queryParams.pageNo * queryParams.pageSize - queryParams.pageSize) + 1
+          }}
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="elderName" header-align="center" align="center" label="长者姓名" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessor" header-align="center" align="center" label="评估人" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="assessDate" header-align="center" align="center" label="记录日期" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="totalScore" header-align="center" align="center" label="评估总得分" min-width="120" show-overflow-tooltip/>
+      <el-table-column prop="riskLevel" header-align="center" align="center" label="风险等级" min-width="120" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag :type="getRiskLevelType(scope.row.riskLevel)">
+            {{ getRiskLevelText(scope.row.riskLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="creator" header-align="center" align="center" label="记录人" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="操作" align="center" width="200">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openFormEdit(scope.row, scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="warning"
+            @click="openFormDetail(scope.row,scope.row.id)"
+          >
+            详情
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="openClose(scope.row)"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <AddForm ref="formRef" @success="getList" />
+
+  <!-- 通用批量导出弹窗 -->
+  <BatchExportDialog
+    :show="showBatchExport"
+    :title="exportConfig.title"
+    :loading="exportLoading"
+    :batch-min="exportConfig.batchMin"
+    :batch-max="exportConfig.batchMax"
+    :count-min="exportConfig.countMin"
+    :count-max="exportConfig.countMax"
+    :default-batch="exportConfig.defaultBatch"
+    :default-count="exportConfig.defaultCount"
+    :description="exportConfig.description"
+    @update:show="showBatchExport = $event"
+    @confirm="handleBatchExport"
+    @cancel="showBatchExport = false"
+  />
+</template>
+
+<script setup lang="ts">
+import AddForm from "./AddForm.vue";
+import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
+import { useUserStore } from '@/store/modules/user'
+import { getCurrentMonthRange } from "@/utils/dateUtil";
+import {
+  wanderAwayDelete,
+  wanderAwayPage
+} from "@/api/social-work";
+
+const message = useMessage()
+const { t } = useI18n()
+const userStore = useUserStore()
+const loading = ref(true)
+const total = ref(0)
+const list = ref([])
+
+// 状态管理
+const showBatchExport = ref(false)
+const exportConfig = ref({
+  title: '',
+  batchMin: 1,
+  batchMax: 999,
+  countMin: 1,
+  countMax: 200,
+  defaultBatch: 1,
+  defaultCount: 200,
+  description: [] as string[]
+})
+const exportLoading = ref(false)
+
+let queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  elderName: '',
+  assessor: '',
+  assessDate: getCurrentMonthRange(),
+  tenantIds: userStore.orgTenantId
+})
+const queryFormRef = ref()
+
+// 处理批量导出
+const handleBatchExport = async (batch: number, count: number) => {
+  exportLoading.value = true
+  console.log(batch, count)
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await wanderAwayPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  if (!queryFormRef.value) return
+  const valid = await queryFormRef.value.validate()
+  if (!valid) return
+  queryParams.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryParams.elderName = ''
+  queryParams.assessor = ''
+  queryParams.tenantIds = userStore.orgTenantId
+  queryParams.assessDate = getCurrentMonthRange()
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (id?: number) => {
+  if (queryParams.tenantIds.length == 0 || queryParams.tenantIds.length > 1) {
+    message.error('新增只能选择一个机构')
+    return
+  }
+  formRef.value.open(queryParams.tenantIds[0], id, false)
+}
+
+const openFormEdit = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, false)
+}
+
+const openFormDetail = (row: any = {}, id?: number) => {
+  formRef.value.open(row.tenantId, id, true)
+}
+
+const openClose = async (item: any) => {
+  try {
+    const res = await message.confirm('确定要删除吗?', '提示')
+    if (res == 'confirm') {
+      try {
+        const res = await wanderAwayDelete(item.id)
+        if (res) {
+          message.success(t('common.updateSuccess'))
+          await getList()
+        }
+      } catch (err) { }
+    }
+  } catch { }
+}
+
+/** 取消按钮操作 */
+const cancelDelete = async (id: number) => {
+  try {
+    await message.cancelConfirm()
+    message.success(t('common.delSuccess'))
+    await getList()
+  } catch { }
+}
+
+const route = useRoute()
+/** 初始化 **/
+onMounted(() => {
+  if (route.query && route.query.elderName) {
+    queryParams.elderName = route.query.elderName as string
+  }
+  getList()
+})
+
+// 表头格式
+const tableHeaderColor = ({ rowIndex }: any) => {
+  if (rowIndex === 0) {
+    return {
+      backgroundColor: '#f8f8f9',
+      color: '#666666',
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// 获取风险等级类型
+const getRiskLevelType = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return 'success'
+    case 'low': return 'info'
+    case 'medium': return 'warning'
+    case 'high': return 'danger'
+    default: return ''
+  }
+}
+
+// 获取风险等级文本
+const getRiskLevelText = (riskLevel: string) => {
+  switch (riskLevel) {
+    case 'none': return '无风险'
+    case 'low': return '低风险'
+    case 'medium': return '中风险'
+    case 'high': return '高风险'
+    default: return '-'
+  }
+}
+</script>
+
+<style scoped lang="scss"></style>