فهرست منبع

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

xiongxing 2 هفته پیش
والد
کامیت
64cc6b7fca
35فایلهای تغییر یافته به همراه11792 افزوده شده و 1122 حذف شده
  1. 50 0
      src/api/social-work/index.ts
  2. 1 1
      src/api/system/tenantPackage/index.ts
  3. BIN
      src/views/elderly/apply/check-in/颐年集团广州养老服务合同-校对启用版202606.pdf
  4. 205 15
      src/views/elderly/contracts/ContractManageForm.vue
  5. 361 593
      src/views/elderly/contracts/check-in-tab/AddForm.vue
  6. 8 48
      src/views/elderly/contracts/check-in-tab/index.vue
  7. 200 13
      src/views/elderly/contracts/components/AttachmentSelector.vue
  8. 215 0
      src/views/elderly/contracts/components/CheckInInformationBody.vue
  9. 1196 0
      src/views/elderly/contracts/components/CheckInRegistrationBody.vue
  10. 24 44
      src/views/elderly/contracts/components/ContractBody.vue
  11. 195 0
      src/views/elderly/contracts/components/ElderSafetyCommitmentBody.vue
  12. 514 0
      src/views/elderly/contracts/delegation-agent-confirmation-form/AddForm.vue
  13. 312 0
      src/views/elderly/contracts/delegation-agent-confirmation-form/index.vue
  14. 761 0
      src/views/elderly/contracts/elder-safety-commitment/AddForm.vue
  15. 312 0
      src/views/elderly/contracts/elder-safety-commitment/index.vue
  16. 514 0
      src/views/elderly/contracts/explanation-examination-report-items copy/AddForm.vue
  17. 312 0
      src/views/elderly/contracts/explanation-examination-report-items copy/index.vue
  18. 514 0
      src/views/elderly/contracts/explanation-examination-report-items/AddForm.vue
  19. 312 0
      src/views/elderly/contracts/explanation-examination-report-items/index.vue
  20. 514 0
      src/views/elderly/contracts/guardian-party-b/AddForm.vue
  21. 312 0
      src/views/elderly/contracts/guardian-party-b/index.vue
  22. 514 0
      src/views/elderly/contracts/identification-document-partyb/AddForm.vue
  23. 312 0
      src/views/elderly/contracts/identification-document-partyb/index.vue
  24. 514 0
      src/views/elderly/contracts/outing-confirmation-form/AddForm.vue
  25. 312 0
      src/views/elderly/contracts/outing-confirmation-form/index.vue
  26. 514 0
      src/views/elderly/contracts/power-of-attorney/AddForm.vue
  27. 312 0
      src/views/elderly/contracts/power-of-attorney/index.vue
  28. 2 406
      src/views/elderly/contracts/risk-disclosure-statement/AddForm.vue
  29. 2 2
      src/views/elderly/contracts/risk-disclosure-statement/index.vue
  30. 514 0
      src/views/elderly/contracts/room-facilities-equipment/AddForm.vue
  31. 312 0
      src/views/elderly/contracts/room-facilities-equipment/index.vue
  32. 514 0
      src/views/elderly/contracts/service-charging-standards-institution/AddForm.vue
  33. 312 0
      src/views/elderly/contracts/service-charging-standards-institution/index.vue
  34. 514 0
      src/views/elderly/contracts/signature-proxy-application/AddForm.vue
  35. 312 0
      src/views/elderly/contracts/signature-proxy-application/index.vue

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

@@ -1232,3 +1232,53 @@ export const nutritionalRiskDelete = async (id: number) => {
 export const nutritionalRiskExport = async (id: number) => {
   return await request.download({ url: '/elderly-assess-nutritional-risk/export?id=' + id })
 }
+
+
+// ==================== 入住登记表(附件2) ====================
+
+// 入住登记表数据接口
+export interface CheckInRegistrationFormData {
+  id?: number
+  elderId: number | string
+  tenantId: number
+  assessData: string      // JSON 字符串存储所有表单数据
+  assessor?: string       // 记录人(冗余字段,便于查询)
+  assessDate?: string     // 记录日期(冗余字段,便于查询)
+  createdAt?: string
+  updatedAt?: string
+}
+
+// 创建入住登记表记录
+export const checkInRegistrationCreate = async (data: CheckInRegistrationFormData) => {
+  return await request.post({ url: '/elderly-check-in-registration/create', data })
+}
+
+// 更新入住登记表记录
+export const checkInRegistrationUpdate = async (data: CheckInRegistrationFormData) => {
+  return await request.put({ url: '/elderly-check-in-registration/update', data })
+}
+
+// 根据ID获取入住登记表记录
+export const checkInRegistrationGetById = async (id: number) => {
+  return await request.get({ url: '/elderly-check-in-registration/get?id=' + id })
+}
+
+// 获取长者的入住登记表记录
+export const checkInRegistrationGetByElderId = async (elderId: number | string) => {
+  return await request.get({ url: '/elderly-check-in-registration/get-by-elder-id?elderId=' + elderId })
+}
+
+// 分页查询入住登记表记录
+export const checkInRegistrationPage = async (params: any) => {
+  return await request.get({ url: '/elderly-check-in-registration/page', params })
+}
+
+// 删除入住登记表记录
+export const checkInRegistrationDelete = async (id: number) => {
+  return await request.delete({ url: `/elderly-check-in-registration/delete?id=${id}` })
+}
+
+// 导出入住登记表记录
+export const checkInRegistrationExport = async (id: number) => {
+  return await request.download({ url: '/elderly-check-in-registration/export?id=' + id })
+}

+ 1 - 1
src/api/system/tenantPackage/index.ts

@@ -29,7 +29,7 @@ export const createTenantPackage = (data: TenantPackageVO) => {
 
 // 修改租户套餐
 export const updateTenantPackage = (data: TenantPackageVO) => {
-  return request.put({ url: '/system/tenant-package/update', data })
+  return request.put({ url: '/system/tenant-package/update', data, timeout:45000 })
 }
 
 // 删除租户套餐

BIN
src/views/elderly/apply/check-in/颐年集团广州养老服务合同-校对启用版202606.pdf


+ 205 - 15
src/views/elderly/contracts/ContractManageForm.vue

@@ -5,6 +5,9 @@ import ContractBody from './components/ContractBody.vue'
 import AttachmentPage from './components/AttachmentPage.vue'
 import AttachmentSelector from './components/AttachmentSelector.vue'
 import RiskDisclosureBody from './components/RiskDisclosureBody.vue'
+import CheckInRegistrationBody from './components/CheckInRegistrationBody.vue'
+import CheckInInformationBody from './components/CheckInInformationBody.vue'
+import ElderSafetyCommitmentBody from './components/ElderSafetyCommitmentBody.vue'
 
 const message = useMessage()
 
@@ -38,7 +41,12 @@ const attachmentList = [
 
 const attachments = reactive<Record<string, any>>(
   attachmentList.reduce((acc: any, item) => {
-    acc[`attach_${item.no}`] = null
+    // 固定内容附件(3=入住须知)默认展示,不需要从列表选择
+    if (item.no === 3) {
+      acc[`attach_${item.no}`] = { title: item.title }
+    } else {
+      acc[`attach_${item.no}`] = null
+    }
     return acc
   }, {} as Record<string, any>)
 )
@@ -54,6 +62,111 @@ const riskDisclosureForm = reactive<Record<string, any>>({
   partyCDate: ''
 })
 
+const safetyCommitmentForm = reactive<Record<string, any>>({
+  elderSign: '',
+  guardianSign: '',
+  signDate: ''
+})
+
+const checkInRegistrationForm = reactive<Record<string, any>>({
+  checkInNo: '',
+  formDate: '',
+  elderName: '',
+  gender: '',
+  age: '',
+  photo: '',
+  nationality: '',
+  birthDate: '',
+  nativePlace: '',
+  householdPlace: '',
+  nation: '',
+  nationOther: '',
+  politicalStatus: '',
+  maritalStatus: '',
+  idCardType: '',
+  idCardNo: '',
+  educationLevel: '',
+  residentialAddress: '',
+  guarantorName: '',
+  guarantorRelation: '',
+  guarantorPhone: '',
+  guarantorIdCardType: '',
+  guarantorIdCardNo: '',
+  guarantorAddress: '',
+  guarantorEmail: '',
+  secondContactName: '',
+  secondContactPhone: '',
+  medicalPaymentMethod: '',
+  medicalPaymentOther: '',
+  incomeSource: [],
+  incomeSourceOther: '',
+  preResidence: '',
+  preResidenceHomeType: '',
+  preResidenceHomeOther: '',
+  checkInReason: '',
+  pastHistory: {
+    hasDisease: false,
+    diseases: [{ name: '', confirmTime: '' }, { name: '', confirmTime: '' }],
+    hasSurgery: false,
+    surgeries: [{ name: '', time: '' }, { name: '', time: '' }],
+    hasTrauma: false,
+    traumas: [{ part: '', time: '' }, { part: '', time: '' }]
+  },
+  currentDiseases: [
+    { name: '', confirmTime: '', currentStatus: '' },
+    { name: '', confirmTime: '', currentStatus: '' }
+  ],
+  medicalSituation: {
+    regularVisit: { none: true, reason: '', frequency: '', frequencyUnit: '' },
+    hospitalization: {
+      none: true,
+      count: '',
+      records: [
+        { inTime: '', outTime: '', reason: '', hospital: '' },
+        { inTime: '', outTime: '', reason: '', hospital: '' }
+      ]
+    },
+    emergency: {
+      none: true,
+      count: '',
+      records: [{ time: '', reason: '', hospital: '' }]
+    }
+  },
+  discomfortSymptoms: {
+    none: true,
+    items: [],
+    other: ''
+  },
+  allergyHistory: {
+    drug: { none: true, detail: '' },
+    food: { none: true, detail: '' },
+    environment: { none: true, detail: '' }
+  },
+  geriatricSyndrome: {
+    fall: { none: true, detail: '' },
+    memoryDecline: { none: true, detail: '' },
+    weightLoss: { none: true, weight: '' },
+    urinaryIncontinence: { none: true, count: '' },
+    sleepDisorder: { none: true, types: [], other: '' },
+    pain: { none: true, part: '' },
+    visionAbnormal: { none: true, types: [], degree: '' },
+    hearingLoss: { none: true, detail: '' }
+  },
+  mentalStatus: {
+    none: true,
+    items: [],
+    other: ''
+  },
+  languageExpression: [],
+  languageExpressionOther: '',
+  otherNotes: '',
+  partyBSign: '',
+  partyCSign: '',
+  signDate: ''
+})
+
+const checkInInformationForm = ref({})
+
 const contractSignatureData = ref<Record<string, any>>({
   partyASign: '',
   partyALegalSign: '',
@@ -103,7 +216,12 @@ const open = (row?: any) => {
   isTextMode.value = false
   isPrint.value = false
   attachmentList.forEach((it) => {
-    attachments[`attach_${it.no}`] = null
+    // 固定内容附件(3=入住须知)默认展示,不需要从列表选择
+    if (it.no === 3) {
+      attachments[`attach_${it.no}`] = { title: it.title }
+    } else {
+      attachments[`attach_${it.no}`] = null
+    }
   })
   riskDisclosureForm.elderName = ''
   riskDisclosureForm.assessor = ''
@@ -112,6 +230,24 @@ const open = (row?: any) => {
   riskDisclosureForm.partyBDate = ''
   riskDisclosureForm.partyCSign = ''
   riskDisclosureForm.partyCDate = ''
+
+  // 重置长者安全承诺书表单
+  safetyCommitmentForm.elderSign = ''
+  safetyCommitmentForm.guardianSign = ''
+  safetyCommitmentForm.signDate = ''
+
+  // 重置入住登记表表单
+  Object.keys(checkInRegistrationForm).forEach((key) => {
+    const val = (checkInRegistrationForm as any)[key]
+    if (Array.isArray(val)) {
+      ;(checkInRegistrationForm as any)[key] = []
+    } else if (typeof val === 'object' && val !== null) {
+      ;(checkInRegistrationForm as any)[key] = JSON.parse(JSON.stringify(val))
+    } else {
+      ;(checkInRegistrationForm as any)[key] = ''
+    }
+  })
+
   contractSignatureData.value.partyASign = ''
   contractSignatureData.value.partyALegalSign = ''
   contractSignatureData.value.partyADate = ''
@@ -249,11 +385,48 @@ const handleAttachmentSelect = (row: any) => {
   const key = selectorVisible.value.current
   if (key) {
     attachments[key] = row
-    message.success(`已选择:${row.title}`)
+    // 附件 2:入住登记表,解析 assessData 到表单
+    if (key === 'attach_2' && row.assessData) {
+      try {
+        const data = JSON.parse(row.assessData)
+        if (data.checkInRegistration) {
+          Object.assign(checkInRegistrationForm, data.checkInRegistration)
+        } else {
+          Object.assign(checkInRegistrationForm, data)
+        }
+      } catch (error) {
+        console.error('解析入住登记表数据失败', error)
+      }
+    }
+    // 附件 4:长者安全承诺书,解析 assessData 到表单
+    if (key === 'attach_4' && row.assessData) {
+      try {
+        const data = JSON.parse(row.assessData)
+        if (data.safetyCommitment) {
+          Object.assign(safetyCommitmentForm, data.safetyCommitment)
+        }
+      } catch (error) {
+        console.error('解析长者安全承诺书数据失败', error)
+      }
+    }
+    message.success(`已选择:${row[activeTitleField(key)] || attachTitle(key)}`)
   }
   selectorVisible.value.show = false
 }
 
+const attachTitle = (key: string) => {
+  const no = Number(key.replace('attach_', ''))
+  const item = attachmentList.find((it) => it.no === no)
+  return item?.title || '附件数据'
+}
+
+const activeTitleField = (key: string) => {
+  const map: Record<string, string> = {
+    attach_2: 'elderName'
+  }
+  return map[key] || 'title'
+}
+
 const handleAttachmentSelectorClose = () => {
   selectorVisible.value.show = false
 }
@@ -268,7 +441,7 @@ const renderAttachmentContent = (key: string) => {
 <template>
   <el-drawer
     v-model="visible"
-    title="合同管理"
+    title="电子合同"
     size="70vw"
     direction="rtl"
     class="contract-manage-drawer"
@@ -284,8 +457,9 @@ const renderAttachmentContent = (key: string) => {
           </el-tooltip>
           <el-button type="primary" :loading="formLoading" size="small" @click="handleSave">保存</el-button>
           <el-button size="small" @click="handleClose">关闭</el-button>
-          <el-button type="success" size="small" @click="handlePrint">打印</el-button>
-          <el-button type="warning" size="small" @click="handleExport">导出</el-button>
+          <el-tooltip placement="bottom" content="打印时目标打印机选择「Microsoft Print to PDF」;导出时目标打印机选择「另存为 PDF」">
+            <el-button type="success" size="small" @click="handlePrint">打印/导出</el-button>
+          </el-tooltip>
         </div>
       </div>
 
@@ -314,9 +488,24 @@ const renderAttachmentContent = (key: string) => {
             <div v-if="attach.no === 1" class="attachment-content">
               <RiskDisclosureBody v-model="riskDisclosureForm" :is-text-mode="isTextMode" />
             </div>
-            <div v-else class="attachment-body">
-              <p><strong>已选择:</strong>{{ renderAttachmentContent(`attach_${attach.no}`) }}</p>
-              <p><strong>版本:</strong>{{ data?.version || '-' }}</p>
+            <div v-else-if="attach.no === 2" class="attachment-content">
+              <CheckInRegistrationBody
+                v-model="checkInRegistrationForm"
+                :is-text-mode="isTextMode"
+                :elder-id="recordRow?.elderId"
+              />
+            </div>
+            <div v-else-if="attach.no === 3" class="attachment-content">
+              <CheckInInformationBody
+                v-model="checkInInformationForm"
+                :is-text-mode="isTextMode"
+                :elder-id="recordRow?.elderId"
+              />
+            </div>
+            <div v-else-if="attach.no === 4" class="attachment-content">
+              <ElderSafetyCommitmentBody v-model="safetyCommitmentForm" :is-text-mode="isTextMode" />
+            </div>
+            <div v-else class="attachment-body">           
               <p><strong>日期:</strong>{{ data?.createTime || '-' }}</p>
               <p style="color: #999; font-size: 13px;">
                 (此处为附件内容占位,实际各附件将由对应列表页提供完整内容排版)
@@ -326,18 +515,13 @@ const renderAttachmentContent = (key: string) => {
         </AttachmentPage>
       </div>
 
-      <!-- <div class="content-footer" v-if="!isPrint">
-        <el-button type="primary" :loading="formLoading" @click="handleSave">保存</el-button>
-        <el-button @click="handleClose">关闭</el-button>
-        <el-button type="success" @click="handlePrint">打印</el-button>
-        <el-button type="warning" @click="handleExport">导出</el-button>
-      </div> -->
     </div>
   </el-drawer>
 
   <AttachmentSelector
     v-model:visible="selectorVisible.show"
     :title="selectorVisible.title"
+    :current="selectorVisible.current"
     :list="selectorVisible.list"
     @select="handleAttachmentSelect"
     @update:visible="handleAttachmentSelectorClose"
@@ -358,6 +542,12 @@ const renderAttachmentContent = (key: string) => {
         >
           <!-- 附件1:知情同意书,使用 RiskDisclosureBody -->
           <RiskDisclosureBody v-if="attach.no === 1" v-model="riskDisclosureForm" :is-text-mode="true" />
+          <!-- 附件2:入住登记表,使用 CheckInRegistrationBody -->
+          <CheckInRegistrationBody v-else-if="attach.no === 2" v-model="checkInRegistrationForm" :is-text-mode="true" :elder-id="recordRow?.elderId" />
+          <!-- 附件3:入住须知,使用 CheckInInformationBody -->
+          <CheckInInformationBody v-else-if="attach.no === 3" :is-text-mode="true" />
+          <!-- 附件4:长者安全承诺书,使用 ElderSafetyCommitmentBody -->
+          <ElderSafetyCommitmentBody v-else-if="attach.no === 4" v-model="safetyCommitmentForm" :is-text-mode="true" />
           <!-- 其他附件:展示标题和信息 -->
           <div v-else class="a4-page">
             <div class="print-attachment-header">

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 361 - 593
src/views/elderly/contracts/check-in-tab/AddForm.vue


+ 8 - 48
src/views/elderly/contracts/check-in-tab/index.vue

@@ -17,7 +17,7 @@
         />
       </el-form-item>
 
-      <el-form-item label="评估人">
+      <el-form-item label="记录人">
         <el-input
           v-model="queryParams.assessor"
           placeholder="长者姓名"
@@ -70,16 +70,9 @@
 
 
       <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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
-        <template #default="scope">
-          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
-            {{ getRiskLevelInfo(scope.row.assessData).text }}
-          </el-tag>
-        </template>
-      </el-table-column>
+      <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 prop="createTime" header-align="center" align="center" label="记录人" min-width="200" show-overflow-tooltip/>
 
 
       <el-table-column label="操作" align="center" width="200" >
@@ -129,9 +122,8 @@ import AddForm from "./AddForm.vue";
 import ButtonAdd from "@/components/ButtonAdd/src/ButtonAdd.vue";
 import { useUserStore } from '@/store/modules/user'
 import {
-  attackRiskDelete, attackRiskPage,
+  checkInRegistrationDelete, checkInRegistrationPage,
 } from "@/api/social-work";
-import { getRiskLevelInfo } from "@/utils/risk-assessment";
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 const userStore = useUserStore()
@@ -166,47 +158,15 @@ let queryParams = reactive({
 })
 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)
+    const data = await checkInRegistrationPage(queryParams)
     list.value = data.list
     total.value = data.total
   } finally {
@@ -265,7 +225,7 @@ const openClose = async (item) => {
     if (res == 'confirm') {
       // 发起
       try {
-        const res = await attackRiskDelete(item.id)
+        const res = await checkInRegistrationDelete(item.id)
         if (res){
           message.success(t('common.updateSuccess'))
         }

+ 200 - 13
src/views/elderly/contracts/components/AttachmentSelector.vue

@@ -1,10 +1,35 @@
 <script setup lang="ts">
-import { ref, watch } from 'vue'
+import { ref, watch, computed, reactive } from 'vue'
+import { checkInRegistrationPage } from '@/api/social-work'
+
+export interface SelectorConfig {
+  api?: (params: any) => Promise<any>
+  columns?: Array<{
+    prop?: string
+    label: string
+    width?: number | string
+    minWidth?: number | string
+    align?: string
+    formatter?: (row: any) => string
+  }>
+  searchFields?: Array<{
+    prop: string
+    label: string
+    placeholder?: string
+    type?: 'input' | 'date'
+  }>
+  titleField?: string
+  dateField?: string
+  versionField?: string
+}
 
 const props = defineProps<{
   visible?: boolean
   title?: string
+  current?: string
   list?: any[]
+  config?: SelectorConfig
+  extraParams?: Record<string, any>
 }>()
 
 const emit = defineEmits<{
@@ -14,16 +39,132 @@ const emit = defineEmits<{
 
 const localVisible = ref(false)
 const selectedRow = ref<any>(null)
+const loading = ref(false)
+const dataList = ref<any[]>([])
+const queryParams = reactive<Record<string, any>>({})
+const pagination = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  total: 0
+})
+
+// 不同附件类型对应的默认配置
+const defaultConfigMap: Record<string, SelectorConfig> = {
+  attach_2: {
+    api: checkInRegistrationPage,
+    columns: [
+      { prop: 'elderName', label: '长者姓名', minWidth: 120, align: 'center' },
+      { prop: 'assessor', label: '记录人', minWidth: 120, align: 'center' },
+      { prop: 'assessDate', label: '记录日期', width: 140, align: 'center' },
+      { prop: 'createTime', label: '创建时间', width: 160, align: 'center' }
+    ],
+    searchFields: [
+      { prop: 'elderName', label: '长者姓名', placeholder: '请输入长者姓名', type: 'input' }
+    ],
+    titleField: 'elderName',
+    dateField: 'assessDate',
+    versionField: 'version'
+  }
+}
+
+const activeConfig = computed<SelectorConfig>(() => {
+  const custom = props.config || {}
+  const defaults = props.current ? defaultConfigMap[props.current] : undefined
+  return {
+    ...defaults,
+    ...custom,
+    columns: custom.columns ?? defaults?.columns ?? [
+      { prop: 'title', label: '名称/说明', minWidth: 260 },
+      { prop: 'version', label: '版本', width: 100, align: 'center' },
+      { prop: 'createTime', label: '日期/创建时间', width: 160, align: 'center' }
+    ],
+    searchFields: custom.searchFields ?? defaults?.searchFields ?? [],
+    titleField: custom.titleField ?? defaults?.titleField ?? 'title',
+    dateField: custom.dateField ?? defaults?.dateField ?? 'createTime',
+    versionField: custom.versionField ?? defaults?.versionField ?? 'version'
+  }
+})
+
+const displayList = computed(() => {
+  if (props.list && props.list.length > 0) return props.list
+  return dataList.value
+})
+
+const resetQuery = () => {
+  activeConfig.value.searchFields?.forEach((field) => {
+    queryParams[field.prop] = ''
+  })
+  pagination.pageNo = 1
+}
+
+const fetchData = async () => {
+  const api = activeConfig.value.api
+  if (!api) {
+    // 无接口时回退到默认模拟数据
+    dataList.value = [
+      { id: 1, title: '示例数据1 - 2026年1月版本', createTime: '2026-01-15', version: 'V1.0' },
+      { id: 2, title: '示例数据2 - 2026年3月版本', createTime: '2026-03-20', version: 'V1.1' },
+      { id: 3, title: '示例数据3 - 2026年5月版本', createTime: '2026-05-10', version: 'V2.0' }
+    ]
+    return
+  }
+
+  loading.value = true
+  try {
+    const params: any = {
+      pageNo: pagination.pageNo,
+      pageSize: pagination.pageSize,
+      ...props.extraParams
+    }
+    activeConfig.value.searchFields?.forEach((field) => {
+      if (queryParams[field.prop]) {
+        params[field.prop] = queryParams[field.prop]
+      }
+    })
+    const res = await api(params)
+    if (res && res.list) {
+      dataList.value = res.list
+      pagination.total = res.total || 0
+    } else if (Array.isArray(res)) {
+      dataList.value = res
+      pagination.total = res.length
+    } else {
+      dataList.value = []
+      pagination.total = 0
+    }
+  } catch (error) {
+    dataList.value = [  { id: 1, title: '示例数据1 - 2026年1月版本', createTime: '2026-01-15', version: 'V1.0' },
+      { id: 2, title: '示例数据2 - 2026年3月版本', createTime: '2026-03-20', version: 'V1.1' },
+      { id: 3, title: '示例数据3 - 2026年5月版本', createTime: '2026-05-10', version: 'V2.0' }]
+    pagination.total = 0
+  } finally {
+    loading.value = false
+  }
+}
 
 watch(
   () => props.visible,
   (val) => {
     localVisible.value = val || false
-    if (val) selectedRow.value = null
+    if (val) {
+      selectedRow.value = null
+      resetQuery()
+      fetchData()
+    }
   },
   { immediate: true }
 )
 
+watch(
+  () => props.current,
+  () => {
+    if (localVisible.value) {
+      resetQuery()
+      fetchData()
+    }
+  }
+)
+
 const close = () => {
   localVisible.value = false
   emit('update:visible', false)
@@ -39,18 +180,28 @@ const handleConfirm = () => {
   close()
 }
 
-const mockList = ref<any[]>([
-  { id: 1, title: '示例数据1 - 2026年1月版本', createTime: '2026-01-15', version: 'V1.0' },
-  { id: 2, title: '示例数据2 - 2026年3月版本', createTime: '2026-03-20', version: 'V1.1' },
-  { id: 3, title: '示例数据3 - 2026年5月版本', createTime: '2026-05-10', version: 'V2.0' }
-])
+const handleSearch = () => {
+  pagination.pageNo = 1
+  fetchData()
+}
+
+const handlePageChange = (page: number) => {
+  pagination.pageNo = page
+  fetchData()
+}
+
+const renderCell = (row: any, column: any) => {
+  if (column.formatter) return column.formatter(row)
+  const val = column.prop ? row[column.prop] : ''
+  return val ?? '-'
+}
 </script>
 
 <template>
   <el-drawer
     v-model="localVisible"
-    :title="`选择${title}数据`"
-    size="60%"
+    :title="`选择${title || '附件'}数据`"
+    size="65%"
     direction="rtl"
     destroy-on-close
     @close="close"
@@ -63,19 +214,41 @@ const mockList = ref<any[]>([
       style="margin-bottom: 12px;"
     />
 
+
     <el-table
-      :data="list && list.length > 0 ? list : mockList"
+      v-loading="loading"
+      :data="displayList"
       border
       highlight-current-row
       @current-change="handleSelect"
       style="width: 100%"
     >
       <el-table-column type="index" label="序号" width="60" align="center" />
-      <el-table-column prop="title" label="名称/说明" min-width="260" />
-      <el-table-column prop="version" label="版本" width="100" align="center" />
-      <el-table-column prop="createTime" label="日期/创建时间" width="160" align="center" />
+      <el-table-column
+        v-for="column in activeConfig.columns"
+        :key="column.prop || column.label"
+        :prop="column.prop"
+        :label="column.label"
+        :width="column.width"
+        :min-width="column.minWidth"
+        :align="column.align || 'left'"
+      >
+        <template #default="{ row }">
+          {{ renderCell(row, column) }}
+        </template>
+      </el-table-column>
     </el-table>
 
+    <div class="selector-pagination">
+      <el-pagination
+        v-model:current-page="pagination.pageNo"
+        :page-size="pagination.pageSize"
+        :total="pagination.total"
+        layout="total, prev, pager, next"
+        @current-change="handlePageChange"
+      />
+    </div>
+
     <template #footer>
       <div style="text-align: right;">
         <el-button @click="close">取消</el-button>
@@ -84,3 +257,17 @@ const mockList = ref<any[]>([
     </template>
   </el-drawer>
 </template>
+
+<style scoped lang="scss">
+.selector-search {
+  padding: 0 0 12px;
+  border-bottom: 1px solid #ebeef5;
+  margin-bottom: 12px;
+}
+
+.selector-pagination {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 215 - 0
src/views/elderly/contracts/components/CheckInInformationBody.vue

@@ -0,0 +1,215 @@
+<script setup lang="ts">
+const props = withDefaults(defineProps<{
+  isTextMode?: boolean
+}>(), {
+  isTextMode: false
+})
+</script>
+
+<template>
+  <div class="check-in-information">
+    <div class="attachment-no">附件3</div>
+    <div class="attachment-title">《入住须知》</div>
+
+    <div class="content">
+      <p class="salutation"><strong>尊敬的长者:</strong></p>
+      <p class="indent">您好!</p>
+      <p class="indent">
+        欢迎您入住颐年集团旗下养老机构,在这里您可享受细致、以人为本的贴心服务,感受家的温馨,尽享长者尊贵!
+      </p>
+
+      <h3>一、入住准备</h3>
+      <p>请根据需要选择携带以下物品:</p>
+      <ol>
+        <li>
+          需换洗的衣物包含衣服、鞋、袜以及毛巾;需注意,鞋子应具备防滑功能,尺码合适,尽量选择无需系带的款式。
+        </li>
+        <li>
+          洗漱用品:请依据个人需求自行准备牙刷、牙膏、口杯、须刨、香皂、洗发水、淋浴露等物品。
+        </li>
+        <li>
+          日用品包含:水杯、润肤露、爽身粉、洗洁精、梳子、纸巾以及浴巾。
+        </li>
+        <li>
+          衣物标签:入住之前,请家属完成“长者名字”的衣物标签缝制工作。
+        </li>
+        <li>
+          药品:对于生活无法自理的长者,若自带药品,在附有医生医嘱的情况下,可交由我院工作人员。我院会依据长者的护理级别及医嘱,按时提醒长者服用药品。
+        </li>
+        <li>
+          其他辅助器具:助听器、轮椅、拐杖、助行器、气垫床、坐便椅等。
+        </li>
+        <li>
+          请勿将贵重物品及钱财带入养老院,院方不承担相关保管责任,长者可预留少量备用现金(金额在 500 元以下)。
+        </li>
+      </ol>
+
+      <h3>二、温馨提示</h3>
+      <ol>
+        <li>
+          本养老服务中心已为入住长者配备房间内必备的家电及家具用品,若长者需自行携带相关物品,须经本院同意后方可带入。
+        </li>
+        <li>
+          应遵守各项规章制度,服从管理人员的管理。进出院区以及亲属进行探访时,需在前台进行登记。接待来访的时间为:9:00-11:00 时,14:30-17:00 时。
+        </li>
+        <li>
+          原则上,禁止携带各类宠物入住。严禁携带对长者安全存在影响的物品(如具有刺激性、怪气味的物品,锐器,易燃、易爆及挥发性物品)进入院区。
+        </li>
+        <li>
+          请妥善爱护房间及院区内的公共财物,若有损坏,需按照物品价值进行赔偿。
+        </li>
+        <li>
+          若长者需要持有房间钥匙,请妥善保管。若钥匙遗失,需缴纳重新配制钥匙的费用。离开房间时,请关闭好门窗及水电。
+        </li>
+      </ol>
+
+      <h3>三、办理入住手续时请提供以下资料</h3>
+      <ol>
+        <li>
+          入住长者的户口本(户主页与本人页)以及身份证(正面与反面)复印件,《托养服务合同》丙方(监护人)的户口本(户主页与本人页)以及身份证(正面与反面)复印件。
+        </li>
+        <li>
+          入住长者近期免冠一寸彩色照片三张。
+        </li>
+        <li>
+          入住时需提交长者在三个月内由二级或以上医院出具的体检报告,检查项目包括但不限于详见以下《体验项目单》:
+        </li>
+      </ol>
+
+      <div class="exam-title">《体检项目单》</div>
+      <table class="exam-table" border="1" cellspacing="0" cellpadding="0">
+        <tbody>
+          <tr>
+            <td colspan="2">一般检查(附:常规体检表)</td>
+          </tr>
+          <tr>
+            <td colspan="2">心电图</td>
+          </tr>
+          <tr>
+            <td colspan="2">X光胸片</td>
+          </tr>
+          <tr>
+            <td colspan="2">腹部B超(男性肝胆脾双肾膀胱 /女性肝胆脾双肾加子宫附件)</td>
+          </tr>
+          <tr>
+            <td colspan="2">骨密度检测</td>
+          </tr>
+          <tr>
+            <td rowspan="6" class="exam-category">化验</td>
+            <td>血常规</td>
+          </tr>
+          <tr>
+            <td>肝功能</td>
+          </tr>
+          <tr>
+            <td>肾功能</td>
+          </tr>
+          <tr>
+            <td>血脂四项</td>
+          </tr>
+          <tr>
+            <td>小便常规</td>
+          </tr>
+          <tr>
+            <td>传染病五项(甲肝、丙肝、乙肝两对半、梅毒、艾滋)</td>
+          </tr>
+        </tbody>
+      </table>
+
+      <h3>四、本《入住须知》最终解释和修订权归本公司所有。</h3>
+      <p class="indent">
+        本单位将竭诚为您提供服务,若有需求,请与前台联系。
+      </p>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.check-in-information {
+  width: 210mm;
+  max-width: 100%;
+  margin: 0 auto;
+  font-family: 'SimSun', 'Microsoft YaHei', serif;
+  font-size: 14px;
+  color: #333;
+  background: #fff;
+  padding: 5mm;
+
+  /* 打印模式优化 */
+  @media print {
+    width: 210mm;
+    max-width: 210mm;
+    padding: 5mm;
+    border: none;
+    margin: 0;
+  }
+}
+
+.attachment-no {
+  text-align: left;
+  font-size: 14px;
+  margin-bottom: 8px;
+}
+
+.attachment-title {
+  text-align: center;
+  font-size: 20px;
+  font-weight: bold;
+  margin-bottom: 20px;
+}
+
+.content {
+  line-height: 1.8;
+}
+
+.salutation {
+  margin-bottom: 0;
+}
+
+.indent {
+  text-indent: 2em;
+  margin: 0;
+}
+
+h3 {
+  font-size: 15px;
+  font-weight: bold;
+  margin-top: 16px;
+  margin-bottom: 8px;
+}
+
+ol {
+  margin: 0 0 12px 0;
+  padding-left: 2em;
+}
+
+li {
+  margin-bottom: 4px;
+}
+
+.exam-title {
+  text-align: center;
+  font-size: 15px;
+  font-weight: bold;
+  margin: 12px 0;
+}
+
+.exam-table {
+  width: 100%;
+  border-collapse: collapse;
+  margin-bottom: 16px;
+
+  td {
+    border: 1px solid #333;
+    padding: 6px 10px;
+    font-size: 13px;
+    line-height: 1.6;
+  }
+
+  .exam-category {
+    text-align: center;
+    vertical-align: middle;
+    width: 80px;
+  }
+}
+</style>

+ 1196 - 0
src/views/elderly/contracts/components/CheckInRegistrationBody.vue

@@ -0,0 +1,1196 @@
+<script setup lang="ts">
+import { reactive, watch } from 'vue'
+import dayjs from 'dayjs'
+import FieldItem from './FieldItem.vue'
+import SignatureItem from './SignatureItem.vue'
+
+export interface CheckInRegistrationForm {
+  checkInNo?: string
+  formDate?: string
+  elderName?: string
+  gender?: string
+  age?: string | number
+  photo?: string
+  nationality?: string
+  birthDate?: string
+  nativePlace?: string
+  householdPlace?: string
+  nation?: string
+  nationOther?: string
+  politicalStatus?: string
+  maritalStatus?: string
+  idCardType?: string
+  idCardNo?: string
+  educationLevel?: string
+  residentialAddress?: string
+  guarantorName?: string
+  guarantorRelation?: string
+  guarantorPhone?: string
+  guarantorIdCardType?: string
+  guarantorIdCardNo?: string
+  guarantorAddress?: string
+  guarantorEmail?: string
+  secondContactName?: string
+  secondContactPhone?: string
+  medicalPaymentMethod?: string
+  medicalPaymentOther?: string
+  incomeSource?: string[]
+  incomeSourceOther?: string
+  preResidenceHomeType?: string[]
+  preResidenceHomeOther?: string
+  checkInReason?: string
+  pastHistoryDiseaseNone?: boolean
+  pastHistoryDiseaseName1?: string
+  pastHistoryDiseaseTime1?: string
+  pastHistoryDiseaseName2?: string
+  pastHistoryDiseaseTime2?: string
+  pastHistorySurgery?: boolean
+  pastHistorySurgeryName?: string
+  pastHistorySurgeryTime?: string
+  pastHistoryTrauma?: boolean
+  pastHistoryTraumaPart1?: string
+  pastHistoryTraumaTime1?: string
+  pastHistoryTraumaPart2?: string
+  pastHistoryTraumaTime2?: string
+  currentDiseaseName1?: string
+  currentDiseaseTime1?: string
+  currentDiseaseStatus1?: string
+  currentDiseaseName2?: string
+  currentDiseaseTime2?: string
+  currentDiseaseStatus2?: string
+  regularVisitNone?: boolean
+  regularVisitReason?: string
+  regularVisitFreq?: string
+  hospitalizationNone?: boolean
+  hospitalizationCount?: string
+  emergencyNone?: boolean
+  emergencyCount?: string
+  discomfortSymptomsNone?: boolean
+  discomfortSymptomsList?: string[]
+  discomfortSymptomsOther?: string
+  allergyDrugNone?: boolean
+  allergyDrugDetail?: string
+  allergyFoodNone?: boolean
+  allergyFoodDetail?: string
+  allergyEnvNone?: boolean
+  allergyEnvDetail?: string
+  fallNone?: boolean
+  fallDetail?: string
+  memoryDeclineNone?: boolean
+  memoryDeclineDetail?: string
+  weightLossNone?: boolean
+  weightLossWeight?: string
+  urinaryIncontinenceNone?: boolean
+  urinaryIncontinenceCount?: string
+  sleepDisorderNone?: boolean
+  sleepDisorderTypes?: string[]
+  sleepDisorderOther?: string
+  painNone?: boolean
+  painPart?: string
+  visionAbnormalNone?: boolean
+  visionAbnormalTypes?: string[]
+  visionAbnormalDegree?: string
+  hearingLossNone?: boolean
+  hearingLossDetail?: string
+  mentalStatusNone?: boolean
+  mentalStatusList?: string[]
+  mentalStatusOther?: string
+  languageExpression?: string[]
+  languageExpressionOther?: string
+  otherNotes?: string
+  partyBSign?: string
+  partyCSign?: string
+  signDate?: string
+}
+
+const props = withDefaults(
+  defineProps<{
+    isTextMode?: boolean
+    modelValue?: CheckInRegistrationForm
+    elderId?: string | number
+  }>(),
+  {
+    isTextMode: false,
+    modelValue: () => ({}),
+    elderId: ''
+  }
+)
+
+const emit = defineEmits<{
+  (e: 'update:modelValue', val: CheckInRegistrationForm): void
+}>()
+
+const createDefaultForm = (): CheckInRegistrationForm => ({
+  checkInNo: '',
+  formDate: dayjs().format('YYYY-MM-DD'),
+  elderName: '',
+  gender: '',
+  age: '',
+  photo: '',
+  nationality: '中国',
+  birthDate: '',
+  nativePlace: '',
+  householdPlace: '',
+  nation: '汉族',
+  nationOther: '',
+  politicalStatus: '',
+  maritalStatus: '',
+  idCardType: '身份证',
+  idCardNo: '',
+  educationLevel: '',
+  residentialAddress: '',
+  guarantorName: '',
+  guarantorRelation: '',
+  guarantorPhone: '',
+  guarantorIdCardType: '身份证',
+  guarantorIdCardNo: '',
+  guarantorAddress: '',
+  guarantorEmail: '',
+  secondContactName: '',
+  secondContactPhone: '',
+  medicalPaymentMethod: '',
+  medicalPaymentOther: '',
+  incomeSource: [],
+  incomeSourceOther: '',
+  preResidenceHomeType: [],
+  preResidenceHomeOther: '',
+  checkInReason: '',
+  pastHistoryDiseaseNone: true,
+  pastHistoryDiseaseName1: '',
+  pastHistoryDiseaseTime1: '',
+  pastHistoryDiseaseName2: '',
+  pastHistoryDiseaseTime2: '',
+  pastHistorySurgery: false,
+  pastHistorySurgeryName: '',
+  pastHistorySurgeryTime: '',
+  pastHistoryTrauma: false,
+  pastHistoryTraumaPart1: '',
+  pastHistoryTraumaTime1: '',
+  pastHistoryTraumaPart2: '',
+  pastHistoryTraumaTime2: '',
+  currentDiseaseName1: '',
+  currentDiseaseTime1: '',
+  currentDiseaseStatus1: '',
+  currentDiseaseName2: '',
+  currentDiseaseTime2: '',
+  currentDiseaseStatus2: '',
+  regularVisitNone: true,
+  regularVisitReason: '',
+  regularVisitFreq: '',
+  hospitalizationNone: true,
+  hospitalizationCount: '',
+  emergencyNone: true,
+  emergencyCount: '',
+  discomfortSymptomsNone: true,
+  discomfortSymptomsList: [],
+  discomfortSymptomsOther: '',
+  allergyDrugNone: true,
+  allergyDrugDetail: '',
+  allergyFoodNone: true,
+  allergyFoodDetail: '',
+  allergyEnvNone: true,
+  allergyEnvDetail: '',
+  fallNone: true,
+  fallDetail: '',
+  memoryDeclineNone: true,
+  memoryDeclineDetail: '',
+  weightLossNone: true,
+  weightLossWeight: '',
+  urinaryIncontinenceNone: true,
+  urinaryIncontinenceCount: '',
+  sleepDisorderNone: true,
+  sleepDisorderTypes: [],
+  sleepDisorderOther: '',
+  painNone: true,
+  painPart: '',
+  visionAbnormalNone: true,
+  visionAbnormalTypes: [],
+  visionAbnormalDegree: '',
+  hearingLossNone: true,
+  hearingLossDetail: '',
+  mentalStatusNone: true,
+  mentalStatusList: [],
+  mentalStatusOther: '',
+  languageExpression: [],
+  languageExpressionOther: '',
+  otherNotes: '',
+  partyBSign: '',
+  partyCSign: '',
+  signDate: dayjs().format('YYYY-MM-DD')
+})
+
+const form = reactive<CheckInRegistrationForm>(createDefaultForm())
+
+watch(
+  () => props.modelValue,
+  (val) => {
+    if (val) Object.assign(form, createDefaultForm(), val)
+  },
+  { immediate: true, deep: true }
+)
+
+const emitForm = () => emit('update:modelValue', JSON.parse(JSON.stringify(form)))
+
+const updateForm = (key: keyof CheckInRegistrationForm, val: any) => {
+  ;(form as any)[key] = val
+  emitForm()
+}
+
+// 从长者选择返回值填充数据(基于实际API返回值映射)
+const fillFromElderData = (elder: Record<string, any>) => {
+  // 基本信息
+  form.elderName = elder.elderName || ''
+  form.gender = elder.elderSex === 1 ? '男' : elder.elderSex === 2 ? '女' : ''
+  form.age = elder.elderAge || ''
+  form.photo = elder.elderImage || elder.elderCover || ''
+
+  // 出生日期(处理时间戳或字符串)
+  if (elder.birthday) {
+    form.birthDate = typeof elder.birthday === 'number'
+      ? dayjs(elder.birthday).format('YYYY-MM-DD')
+      : elder.birthday
+  }
+
+  // 籍贯/户籍地址
+  form.nativePlace = elder.registeredResidenceAddress || elder.region || ''
+  form.householdPlace = elder.censusRegister || ''
+
+  // 民族
+  const nationMap: Record<string, string> = { '1': '汉族', '2': '蒙古族', '3': '回族', '4': '藏族' }
+  form.nation = elder.nationId ? (nationMap[String(elder.nationId)] || '汉族') : '汉族'
+
+  // 政治面貌
+  const polMap: Record<string, string> = { '1': '中共党员', '2': '共青团员', '3': '民主党派', '4': '群众' }
+  form.politicalStatus = elder.political ? polMap[String(elder.political)] || '' : ''
+
+  // 婚姻状况
+  const marMap: Record<number, string> = { 1: '未婚', 2: '已婚', 3: '丧偶', 4: '离异' }
+  form.maritalStatus = elder.maritalStatus ? marMap[Number(elder.maritalStatus)] || '' : ''
+
+  // 证件类型和号码
+  const paperMap: Record<number, string> = { 1: '身份证', 2: '护照', 3: '军官证', 4: '其他' }
+  form.idCardType = elder.papersType ? paperMap[Number(elder.papersType)] || '身份证' : '身份证'
+  form.idCardNo = elder.idCard || ''
+
+  // 文化程度
+  const eduMap: Record<number, string> = { 1: '文盲半文盲', 2: '小学', 3: '初中', 4: '高中/技校/中专', 5: '大学专科及以上', 6: '不详', 7: '大学专科及以上' }
+  form.educationLevel = elder.degreeEducation ? eduMap[Number(elder.degreeEducation)] || '' : ''
+
+  // 居住地址
+  form.residentialAddress = elder.address || ''
+
+  // 医疗费用支付方式
+  const payMap: Record<number, string> = { 1: '城镇职工基本医疗保险', 2: '城镇居民基本医疗保险', 3: '全公费', 4: '其它' }
+  form.medicalPaymentMethod = elder.paymentMethod ? payMap[Number(elder.paymentMethod)] || '' : ''
+
+  // 经济来源
+  if (elder.economySource) {
+    const srcMap: Record<string, string> = { '1': '退休金/养老金', '2': '子女补贴', '3': '亲友资助', '4': '其他补贴' }
+    form.incomeSource = elder.economySource.split(',').filter(Boolean).map((k: string) => srcMap[k] || k).filter(Boolean)
+  }
+
+  // 过敏史
+  if (elder.allergicDrug || elder.drugAllergy) {
+    form.allergyDrugNone = false
+    form.allergyDrugDetail = elder.allergicDrug || elder.drugAllergy || ''
+  }
+
+  // 入住编号
+  form.checkInNo = elder.fileNumber || elder.contractNumber || ''
+
+  emitForm()
+}
+
+// 修复:正确暴露方法名
+defineExpose({ fillFromElderData })
+
+// 打印模式 checkbox 渲染
+const printCheck = (checked: boolean) => (checked ? '\u2611' : '\u2610')
+
+// 不适症状选项
+const symptomOptions = ['头痛','头晕','心悸','胸闷','胸痛','慢性咳嗽','咳痰','呼吸困难','多饮','多尿','体重下降','乏力','关节疼痛','手脚麻木','视力模糊','眼花','耳鸣','尿急','尿痛','尿频','腹泻','恶心呕吐','食欲减退','乳房胀痛','体位性低血压']
+
+// 精神状况选项
+const mentalOptions = ['游走','日夜颠倒','语言攻击行为','肢体攻击行为','对物品的攻击行为','妄想','幻觉','焦虑/恐惧','自伤/自杀','重复行为']
+
+// 辅助方法 - 切换数组项
+const toggleArrayItem = (arrKey: keyof CheckInRegistrationForm, val: string) => {
+  const arr = (form as any)[arrKey] as string[]
+  const idx = arr.indexOf(val)
+  if (idx > -1) arr.splice(idx, 1)
+  else arr.push(val)
+  emitForm()
+}
+
+// 辅助方法 - 处理既往史"无"勾选(清空疾病名称)
+const onPastHistoryNoneChange = () => {
+  form.pastHistoryDiseaseNone = true
+  form.pastHistoryDiseaseName1 = ''
+  form.pastHistoryDiseaseTime1 = ''
+  emitForm()
+}
+
+// 辅助方法 - 处理行内input输入(用于疾病名称、时间等字段)
+const onInlineInput = (key: keyof CheckInRegistrationForm, e: Event) => {
+  const target = e.target as HTMLInputElement
+  ;(form as any)[key] = target.value
+  emitForm()
+}
+</script>
+
+<template>
+  <div class="check-in-registration">
+    <!-- 标题 -->
+    <div class="doc-title">附件 2 &nbsp;&nbsp;&nbsp; 入住登记表</div>
+    <div class="doc-meta">
+      <span>入住编号:<FieldItem :model-value="form.checkInNo" :is-text-mode="isTextMode" width="140px" @update:model-value="(v:any)=>updateForm('checkInNo',v)" /></span>
+      <span>日期:{{ form.signDate || '____年__月__日' }}</span>
+    </div>
+
+    <!-- 主表格 - A4宽度适配,严格7列布局 -->
+    <table class="reg-table" border="1" cellspacing="0" cellpadding="0">
+      <!-- 明确定义7列,按设计图比例分配 -->
+      <colgroup>
+        <col style="width:8%" />   <!-- 第1列:最左标签(老年人/担保人) - 紧凑 -->
+        <col style="width:14%" />  <!-- 第2列:标签/值 -->
+        <col style="width:14%" />  <!-- 第3列:值/标签 -->
+        <col style="width:14%" />  <!-- 第4列:标签/值 -->
+        <col style="width:14%" />  <!-- 第5列:值/标签 -->
+        <col style="width:14%" />  <!-- 第6列:标签/值 -->
+        <col style="width:17%" />  <!-- 第7列:照片/值 -->
+      </colgroup>
+      <tbody>
+
+      <!-- ========== 基本信息 + 照片区域(照片只覆盖前8行) ========== -->
+      <!-- 第1行:老年人 | 照片(rowspan=8) -->
+      <tr>
+        <td class="lbl">老年人</td>
+        <td><FieldItem :model-value="form.elderName" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('elderName',v)" /></td>
+        <td class="lbl">性别</td>
+        <td class="radio-cell">
+          <template v-if="!isTextMode">
+            <label><input type="radio" :checked="form.gender==='男'" @change="updateForm('gender','男')" /> 男</label>
+            <label><input type="radio" :checked="form.gender==='女'" @change="updateForm('gender','女')" /> 女</label>
+          </template>
+          <template v-else>{{ printCheck(form.gender==='男') }} 男 {{ printCheck(form.gender==='女') }} 女</template>
+        </td>
+        <td class="lbl">年龄</td>
+        <td><FieldItem :model-value="form.age" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('age',v)" /></td>
+        <td class="photo-cell" rowspan="8">
+          <div class="photo-box">
+            <template v-if="form.photo"><img :src="form.photo" class="elder-photo" alt=""/></template>
+            <template v-else><div class="photo-placeholder">照片</div></template>
+          </div>
+        </td>
+      </tr>
+
+      <!-- 第2行:国籍、出生日期 -->
+      <tr>
+        <td class="lbl">国籍</td>
+        <td colspan="2"><FieldItem :model-value="form.nationality" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('nationality',v)" /></td>
+        <td class="lbl">出生日期</td>
+        <td colspan="2"><FieldItem :model-value="form.birthDate" :is-text-mode="isTextMode" type="date" width="100%" @update:model-value="(v:any)=>updateForm('birthDate',v)" /></td>
+      </tr>
+
+      <!-- 第3行:籍贯、户籍地 -->
+      <tr>
+        <td class="lbl">籍贯</td>
+        <td colspan="2"><FieldItem :model-value="form.nativePlace" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('nativePlace',v)" /></td>
+        <td class="lbl">户籍地</td>
+        <td colspan="2"><FieldItem :model-value="form.householdPlace" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('householdPlace',v)" /></td>
+      </tr>
+
+      <!-- 第4行:民族、政治面貌 -->
+      <tr>
+        <td class="lbl">民族</td>
+        <td colspan="2" class="check-cell">
+          <template v-if="!isTextMode">
+            <label><input type="radio" :checked="form.nation==='汉族'" @change="updateForm('nation','汉族')" /> 汉族</label>
+            <label><input type="radio" :checked="form.nation==='其他'" @change="updateForm('nation','其他')" /> 其他:<input :value="form.nationOther" class="inline-input small" placeholder="" @input="onInlineInput('nationOther',$event)" /></label>
+          </template>
+          <template v-else>{{ printCheck(form.nation==='汉族') }} 汉族 {{ printCheck(form.nation==='其他') }} 其他:{{ form.nationOther }}</template>
+        </td>
+        <td class="lbl">政治面貌</td>
+        <td colspan="2"><FieldItem :model-value="form.politicalStatus" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('politicalStatus',v)" /></td>
+      </tr>
+
+      <!-- 第5行:婚姻状况 -->
+      <tr>
+        <td class="lbl">婚姻状况</td>
+        <td colspan="5" class="check-cell">
+          <template v-if="!isTextMode">
+            <label v-for="it in ['未婚','已婚','丧偶','离异','未说明婚姻情况']" :key="it"><input type="checkbox" :checked="form.maritalStatus===it" @change="()=>updateForm('maritalStatus',it)" /> {{ it }}</label>
+          </template>
+          <template v-else><template v-for="it in ['未婚','已婚','丧偶','离异','未说明婚姻情况']" :key="it">{{ printCheck(form.maritalStatus===it) }} {{ it }} </template></template>
+        </td>
+      </tr>
+
+      <!-- 第6行:证件类型、证件号码 -->
+      <tr>
+        <td class="lbl">证件类型</td>
+        <td colspan="2"><FieldItem :model-value="form.idCardType" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('idCardType',v)" /></td>
+        <td class="lbl">证件号码</td>
+        <td colspan="2"><FieldItem :model-value="form.idCardNo" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('idCardNo',v)" /></td>
+      </tr>
+
+      <!-- 第7行:文化程度 -->
+      <tr>
+        <td class="lbl">文化程度</td>
+        <td colspan="5" class="check-cell">
+          <template v-if="!isTextMode">
+            <label v-for="it in ['文盲半文盲','小学','初中','高中/技校/中专','大学专科及以上','不详']" :key="it"><input type="checkbox" :checked="form.educationLevel===it" @change="()=>updateForm('educationLevel',it)" /> {{ it }}</label>
+          </template>
+          <template v-else><template v-for="it in ['文盲半文盲','小学','初中','高中/技校/中专','大学专科及以上','不详']" :key="it">{{ printCheck(form.educationLevel===it) }} {{ it }} </template></template>
+        </td>
+      </tr>
+
+      <!-- 第8行:居住地址(照片rowspan=8结束) -->
+      <tr>
+        <td class="lbl">居住地址</td>
+        <td colspan="5"><FieldItem :model-value="form.residentialAddress" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('residentialAddress',v)" /></td>
+      </tr>
+
+      <!-- ========== 担保人/联系人区域(照片已结束,每行严格7列) ========== -->
+      <!-- 担保人第1行:担保人(1) | 姓名/名称(1) | guarantorName(1) | 关系(1) | guarantorRelation(1) | 手机号(1) | guarantorPhone(1) = 7列 -->
+      <tr>
+        <td class="lbl multi-line" rowspan="3">担保人/<br/>监护人/<br/>紧急<br/>联系人</td>
+        <td class="lbl">姓名/名称</td>
+        <td><FieldItem :model-value="form.guarantorName" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('guarantorName',v)" /></td>
+        <td class="lbl">关系</td>
+        <td><FieldItem :model-value="form.guarantorRelation" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('guarantorRelation',v)" /></td>
+        <td class="lbl">手机号</td>
+        <td><FieldItem :model-value="form.guarantorPhone" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('guarantorPhone',v)" /></td>
+      </tr>
+
+      <!-- 担保人第2行:证件类型(1) | guarantorIdCardType(1) | 证件号码(1) | guarantorIdCardNo(4) = 7列(已含担保人rowspan) -->
+      <tr>
+        <td class="lbl">证件类型</td>
+        <td><FieldItem :model-value="form.guarantorIdCardType" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('guarantorIdCardType',v)" /></td>
+        <td class="lbl" colspan="2">证件号码</td>
+        <td colspan="2"><FieldItem :model-value="form.guarantorIdCardNo" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('guarantorIdCardNo',v)" /></td>
+      </tr>
+
+      <!-- 担保人第3行:通信地址(1) | guarantorAddress(3) | 电子邮箱(1) | guarantorEmail(1) = 7列 -->
+      <tr>
+        <td class="lbl">通信地址</td>
+        <td colspan="3"><FieldItem :model-value="form.guarantorAddress" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('guarantorAddress',v)" /></td>
+        <td class="lbl">电子邮箱</td>
+        <td><FieldItem :model-value="form.guarantorEmail" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('guarantorEmail',v)" /></td>
+      </tr>
+
+      <!-- 第二联系人:标签(2) + 姓名(2) + 标签(1) + 手机号(2) = 7列 -->
+      <tr>
+        <td class="lbl" colspan="2">第二联系人</td>
+        <td colspan="2"><FieldItem :model-value="form.secondContactName" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('secondContactName',v)" /></td>
+        <td class="lbl">手机号</td>
+        <td colspan="2"><FieldItem :model-value="form.secondContactPhone" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('secondContactPhone',v)" /></td>
+      </tr>
+
+      <!-- 医疗费用支付方式 -->
+      <tr>
+        <td class="lbl multi-line">医疗费用<br/>支付方式</td>
+        <td colspan="6" class="check-cell">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.medicalPaymentMethod==='城镇职工基本医疗保险'" @change="()=>updateForm('medicalPaymentMethod','城镇职工基本医疗保险')" /> 城镇职工基本医疗保险</label>
+            <label><input type="checkbox" :checked="form.medicalPaymentMethod==='城镇居民基本医疗保险'" @change="()=>updateForm('medicalPaymentMethod','城镇居民基本医疗保险')" /> 城镇居民基本医疗保险</label>
+            <label><input type="checkbox" :checked="form.medicalPaymentMethod==='全公费'" @change="()=>updateForm('medicalPaymentMethod','全公费')" /> 全公费</label>
+            <label><input type="checkbox" :checked="form.medicalPaymentMethod==='其它'" @change="()=>updateForm('medicalPaymentMethod','其它')" /> 其它:<input :value="form.medicalPaymentOther" class="inline-input small" placeholder="" @input="onInlineInput('medicalPaymentOther',$event)" /></label>
+          </template>
+          <template v-else>{{ printCheck(form.medicalPaymentMethod==='城镇职工基本医疗保险') }} 城镇职工基本医疗 {{ printCheck(form.medicalPaymentMethod==='城镇居民基本医疗保险') }} 城镇居民基本医疗 {{ printCheck(form.medicalPaymentMethod==='全公费') }} 全公费 {{ printCheck(form.medicalPaymentMethod==='其它') }} 其它:{{ form.medicalPaymentOther }}</template>
+        </td>
+      </tr>
+
+      <!-- 经济来源 -->
+      <tr>
+        <td class="lbl">经济来源</td>
+        <td colspan="6" class="check-cell">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.incomeSource.includes('退休金/养老金')" @change="toggleArrayItem('incomeSource','退休金/养老金')" /> 退休金/养老金</label>
+            <label><input type="checkbox" :checked="form.incomeSource.includes('子女补贴')" @change="toggleArrayItem('incomeSource','子女补贴')" /> 子女补贴</label>
+            <label><input type="checkbox" :checked="form.incomeSource.includes('亲友资助')" @change="toggleArrayItem('incomeSource','亲友资助')" /> 亲友资助</label>
+            <label><input type="checkbox" :checked="form.incomeSource.includes('其他补贴')" @change="toggleArrayItem('incomeSource','其他补贴')" /> 其他补贴:<input :value="form.incomeSourceOther" class="inline-input small" placeholder="" @input="onInlineInput('incomeSourceOther',$event)" /></label>
+          </template>
+          <template v-else>{{ printCheck(form.incomeSource.includes('退休金/养老金')) }} 退休金/养老金 {{ printCheck(form.incomeSource.includes('子女补贴')) }} 子女补贴 {{ printCheck(form.incomeSource.includes('亲友资助')) }} 亲友资助 {{ printCheck(form.incomeSource.includes('其他补贴')) }} 其他补贴:{{ form.incomeSourceOther }}</template>
+        </td>
+      </tr>
+
+      <!-- 入住前居住 -->
+      <tr>
+        <td class="lbl multi-line">入住前<br/>居住</td>
+        <td colspan="6" class="check-cell">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.preResidenceHomeType.includes('家(独居)')" @change="toggleArrayItem('preResidenceHomeType','家(独居)')" /> 家(独居)</label>
+            <label><input type="checkbox" :checked="form.preResidenceHomeType.includes('配偶')" @change="toggleArrayItem('preResidenceHomeType','配偶')" /> 配偶</label>
+            <label><input type="checkbox" :checked="form.preResidenceHomeType.includes('子女')" @change="toggleArrayItem('preResidenceHomeType','子女')" /> 子女</label>
+            <label><input type="checkbox" :checked="form.preResidenceHomeType.includes('保姆')" @change="toggleArrayItem('preResidenceHomeType','保姆')" /> 保姆</label>
+            <label><input type="checkbox" :checked="form.preResidenceHomeType.includes('其他')" @change="toggleArrayItem('preResidenceHomeType','其他')" /> 其他:<input :value="form.preResidenceHomeOther" class="inline-input small" placeholder="" @input="onInlineInput('preResidenceHomeOther',$event)" /></label>
+            <label><input type="checkbox" :checked="form.preResidenceHomeType.includes('医院')" @change="toggleArrayItem('preResidenceHomeType','医院')" /> 医院</label>
+          </template>
+          <template v-else>{{ printCheck(form.preResidenceHomeType.includes('家(独居)')) }} 家(独居) {{ printCheck(form.preResidenceHomeType.includes('配偶')) }} 配偶 {{ printCheck(form.preResidenceHomeType.includes('子女')) }} 子女 {{ printCheck(form.preResidenceHomeType.includes('保姆')) }} 保姆 {{ printCheck(form.preResidenceHomeType.includes('其他')) }} 其他:{{ form.preResidenceHomeOther }} {{ printCheck(form.preResidenceHomeType.includes('医院')) }} 医院</template>
+        </td>
+      </tr>
+
+      <!-- 入住机构原因 -->
+      <tr>
+        <td class="lbl multi-line">入住机构<br/>原因</td>
+        <td colspan="6"><FieldItem :model-value="form.checkInReason" :is-text-mode="isTextMode" width="100%" @update:model-value="(v:any)=>updateForm('checkInReason',v)" /></td>
+      </tr>
+
+      <!-- ========== 健康状况 ========== -->
+      <!-- 健康状况rowspan=10覆盖:既往史2行 + 手术史1行 + 外伤史2行 + 现患疾病2行 + 就医情况3行 -->
+      <!-- 既往史第1行:健康(1) | 既往史(1) | 内容(5) = 7列 -->
+      <tr>
+        <td class="lbl multi-line" rowspan="10">健康状况</td>
+        <td class="lbl" rowspan="2">既往史</td>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.pastHistoryDiseaseNone" @change="onPastHistoryNoneChange" /> 无</label>
+            <label><input type="checkbox" :checked="!form.pastHistoryDiseaseNone" @change="updateForm('pastHistoryDiseaseNone',false)" /> 有:疾病名称:</label>
+            <input :value="form.pastHistoryDiseaseName1" class="inline-input medium" placeholder="" @input="onInlineInput('pastHistoryDiseaseName1',$event)" />
+            <span class="text-suffix">,确诊时间:</span>
+            <input :value="form.pastHistoryDiseaseTime1" class="inline-input small" placeholder="" @input="onInlineInput('pastHistoryDiseaseTime1',$event)" />
+          </template>
+          <template v-else>{{ printCheck(form.pastHistoryDiseaseNone) }} 无 {{ printCheck(!form.pastHistoryDiseaseNone) }} 有:疾病名称:{{ form.pastHistoryDiseaseName1 }} ,确诊时间:{{ form.pastHistoryDiseaseTime1 }}</template>
+        </td>
+      </tr>
+      <!-- 既往史第2行:(健康继续) | (既往史继续) | 内容(5) -->
+      <tr>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <span class="text-prefix ml20"></span>
+            <span class="text-suffix">疾病名称:</span>
+            <input :value="form.pastHistoryDiseaseName2" class="inline-input medium" placeholder="" @input="onInlineInput('pastHistoryDiseaseName2',$event)" />
+            <span class="text-suffix">,确诊时间:</span>
+            <input :value="form.pastHistoryDiseaseTime2" class="inline-input small" placeholder="" @input="onInlineInput('pastHistoryDiseaseTime2',$event)" />
+          </template>
+          <template v-else>疾病名称:{{ form.pastHistoryDiseaseName2 }} ,确诊时间:{{ form.pastHistoryDiseaseTime2 }}</template>
+        </td>
+      </tr>
+
+      <!-- 手术史:健康(1) | 手术史(1) | 内容(5) = 7列 -->
+      <tr>
+        <td class="lbl">手术史</td>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="!form.pastHistorySurgery" @change="updateForm('pastHistorySurgery',false)" /> 无</label>
+            <label><input type="checkbox" :checked="form.pastHistorySurgery" @change="updateForm('pastHistorySurgery',true)" /> 有:手术名称:</label>
+            <input :value="form.pastHistorySurgeryName" class="inline-input medium" placeholder="" @input="onInlineInput('pastHistorySurgeryName',$event)" />
+            <span class="text-suffix">,手术时间:</span>
+            <input :value="form.pastHistorySurgeryTime" class="inline-input small" placeholder="" @input="onInlineInput('pastHistorySurgeryTime',$event)" />
+          </template>
+          <template v-else>{{ printCheck(!form.pastHistorySurgery) }} 无 {{ printCheck(form.pastHistorySurgery) }} 有:手术名称:{{ form.pastHistorySurgeryName }} ,手术时间:{{ form.pastHistorySurgeryTime }}</template>
+        </td>
+      </tr>
+
+      <!-- 外伤史第1行:健康(1) | 外伤史(1 rowspan=2) | 内容(5) = 7列 -->
+      <tr>
+        <td class="lbl" rowspan="2">外伤史</td>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="!form.pastHistoryTrauma" @change="updateForm('pastHistoryTrauma',false)" /> 无</label>
+            <label><input type="checkbox" :checked="form.pastHistoryTrauma" @change="updateForm('pastHistoryTrauma',true)" /> 有:外伤部位:</label>
+            <input :value="form.pastHistoryTraumaPart1" class="inline-input medium" placeholder="" @input="onInlineInput('pastHistoryTraumaPart1',$event)" />
+            <span class="text-suffix">,发生时间:</span>
+            <input :value="form.pastHistoryTraumaTime1" class="inline-input small" placeholder="" @input="onInlineInput('pastHistoryTraumaTime1',$event)" />
+          </template>
+          <template v-else>{{ printCheck(!form.pastHistoryTrauma) }} 无 {{ printCheck(form.pastHistoryTrauma) }} 有:外伤部位:{{ form.pastHistoryTraumaPart1 }} ,发生时间:{{ form.pastHistoryTraumaTime1 }}</template>
+        </td>
+      </tr>
+      <!-- 外伤史第2行:(健康继续) | (外伤史继续) | 内容(5) -->
+      <tr>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <span class="text-prefix ml20"></span>
+            <span class="text-suffix">外伤部位:</span>
+            <input :value="form.pastHistoryTraumaPart2" class="inline-input medium" placeholder="" @input="onInlineInput('pastHistoryTraumaPart2',$event)" />
+            <span class="text-suffix">,发生时间:</span>
+            <input :value="form.pastHistoryTraumaTime2" class="inline-input small" placeholder="" @input="onInlineInput('pastHistoryTraumaTime2',$event)" />
+          </template>
+          <template v-else>外伤部位:{{ form.pastHistoryTraumaPart2 }} ,发生时间:{{ form.pastHistoryTraumaTime2 }}</template>
+        </td>
+      </tr>
+
+      <!-- 现患疾病 -->
+      <tr>
+        <td class="lbl" rowspan="2">现患疾病</td>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <span class="text-suffix">疾病名称:</span>
+            <input :value="form.currentDiseaseName1" class="inline-input medium" placeholder="" @input="onInlineInput('currentDiseaseName1',$event)" />
+            <span class="text-suffix">,确诊时间:</span>
+            <input :value="form.currentDiseaseTime1" class="inline-input small" placeholder="" @input="onInlineInput('currentDiseaseTime1',$event)" />
+            <span class="text-suffix">,目前状况:</span>
+            <input :value="form.currentDiseaseStatus1" class="inline-input small" placeholder="" @input="onInlineInput('currentDiseaseStatus1',$event)" />
+          </template>
+          <template v-else>疾病名称:{{ form.currentDiseaseName1 }} ,确诊时间:{{ form.currentDiseaseTime1 }} ,目前状况:{{ form.currentDiseaseStatus1 }}</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <span class="text-suffix">疾病名称:</span>
+            <input :value="form.currentDiseaseName2" class="inline-input medium" placeholder="" @input="onInlineInput('currentDiseaseName2',$event)" />
+            <span class="text-suffix">,确诊时间:</span>
+            <input :value="form.currentDiseaseTime2" class="inline-input small" placeholder="" @input="onInlineInput('currentDiseaseTime2',$event)" />
+            <span class="text-suffix">,目前状况:</span>
+            <input :value="form.currentDiseaseStatus2" class="inline-input small" placeholder="" @input="onInlineInput('currentDiseaseStatus2',$event)" />
+          </template>
+          <template v-else>疾病名称:{{ form.currentDiseaseName2 }} ,确诊时间:{{ form.currentDiseaseTime2 }} ,目前状况:{{ form.currentDiseaseStatus2 }}</template>
+        </td>
+      </tr>
+
+      <!-- 就医情况 -->
+      <tr>
+        <td class="lbl multi-line" rowspan="3">就医情况</td>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <span class="text-suffix">固定时间就诊:</span>
+            <label><input type="checkbox" :checked="form.regularVisitNone" @change="updateForm('regularVisitNone',true)" /> 无</label>
+            <label><input type="checkbox" :checked="!form.regularVisitNone" @change="updateForm('regularVisitNone',false)" /> 有(原因:</label>
+            <input :value="form.regularVisitReason" class="inline-input small" placeholder="" @input="onInlineInput('regularVisitReason',$event)" />
+            <span class="text-suffix">,频率:___次/月)</span>
+          </template>
+          <template v-else>固定时间就诊:{{ printCheck(form.regularVisitNone) }} 无 {{ printCheck(!form.regularVisitNone) }} 有(原因:{{ form.regularVisitReason }} ,频率:___次/月)</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <span class="text-suffix">近一年内住院情况:</span>
+            <label><input type="checkbox" :checked="form.hospitalizationNone" @change="updateForm('hospitalizationNone',true)" /> 未住院</label>
+            <label><input type="checkbox" :checked="!form.hospitalizationNone" @change="updateForm('hospitalizationNone',false)" /> 住过院(住院次数:<input :value="form.hospitalizationCount" class="inline-input tiny" placeholder="" @input="onInlineInput('hospitalizationCount',$event)" /> 次)</label>
+          </template>
+          <template v-else>近一年内住院情况:{{ printCheck(form.hospitalizationNone) }} 未住院 {{ printCheck(!form.hospitalizationNone) }} 住过院(住院次数:{{ form.hospitalizationCount }} 次)</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="5" class="disease-row">
+          <template v-if="!isTextMode">
+            <span class="text-suffix">近一年内急诊情况:</span>
+            <label><input type="checkbox" :checked="form.emergencyNone" @change="updateForm('emergencyNone',true)" /> 未去过</label>
+            <label><input type="checkbox" :checked="!form.emergencyNone" @change="updateForm('emergencyNone',false)" /> 去过急诊(去急诊次数:<input :value="form.emergencyCount" class="inline-input tiny" placeholder="" @input="onInlineInput('emergencyCount',$event)" /> 次)</label>
+          </template>
+          <template v-else>近一年内急诊情况:{{ printCheck(form.emergencyNone) }} 未去过 {{ printCheck(!form.emergencyNone) }} 去过急诊(去急诊次数:{{ form.emergencyCount }} 次)</template>
+        </td>
+      </tr>
+
+      <!-- 不适症状 -->
+      <tr>
+        <td class="lbl multi-line">不适症状<br/>(近一个<br/>月内情况)</td>
+        <td colspan="6" class="symptom-cell">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.discomfortSymptomsNone" @change="updateForm('discomfortSymptomsNone',true);form.discomfortSymptomsList=[]" /> 无</label>
+            <br/>
+            <label><input type="checkbox" :checked="!form.discomfortSymptomsNone" @change="updateForm('discomfortSymptomsNone',false)" /> 有(可多选)</label>
+            <div v-if="!form.discomfortSymptomsNone" class="symptom-list">
+              <label v-for="s in symptomOptions" :key="s" class="symptom-item">
+                <input type="checkbox" :checked="form.discomfortSymptomsList.includes(s)" @change="toggleArrayItem('discomfortSymptomsList',s)" /> {{ s }}
+              </label>
+              <span>其他:<input :value="form.discomfortSymptomsOther" class="inline-input small" placeholder="" @input="onInlineInput('discomfortSymptomsOther',$event)" /></span>
+            </div>
+          </template>
+          <template v-else>
+            {{ printCheck(form.discomfortSymptomsNone) }} 无
+            <template v-if="!form.discomfortSymptomsNone">{{ printCheck(true) }} 有:{{ form.discomfortSymptomsList.join('、') }} {{ form.discomfortSymptomsOther }}</template>
+          </template>
+        </td>
+      </tr>
+
+      <!-- 过敏史 -->
+      <tr>
+        <td class="lbl multi-line" rowspan="3">过敏史</td>
+        <td colspan="6" class="allergy-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.allergyDrugNone" @change="updateForm('allergyDrugNone',true);updateForm('allergyDrugDetail','')" /> 无药物过敏</label>
+            <label><input type="checkbox" :checked="!form.allergyDrugNone" @change="updateForm('allergyDrugNone',false)" /> 药物过敏:</label>
+            <input :value="form.allergyDrugDetail" class="inline-input large" placeholder="" @input="onInlineInput('allergyDrugDetail',$event)" />
+          </template>
+          <template v-else>{{ printCheck(form.allergyDrugNone) }} 无药物过敏 {{ printCheck(!form.allergyDrugNone) }} 药物过敏:{{ form.allergyDrugDetail }}</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="allergy-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.allergyFoodNone" @change="updateForm('allergyFoodNone',true);updateForm('allergyFoodDetail','')" /> 无食物过敏</label>
+            <label><input type="checkbox" :checked="!form.allergyFoodNone" @change="updateForm('allergyFoodNone',false)" /> 食物过敏:</label>
+            <input :value="form.allergyFoodDetail" class="inline-input large" placeholder="" @input="onInlineInput('allergyFoodDetail',$event)" />
+          </template>
+          <template v-else>{{ printCheck(form.allergyFoodNone) }} 无食物过敏 {{ printCheck(!form.allergyFoodNone) }} 食物过敏:{{ form.allergyFoodDetail }}</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="allergy-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.allergyEnvNone" @change="updateForm('allergyEnvNone',true);updateForm('allergyEnvDetail','')" /> 无环境过敏</label>
+            <label><input type="checkbox" :checked="!form.allergyEnvNone" @change="updateForm('allergyEnvNone',false)" /> 环境过敏:</label>
+            <input :value="form.allergyEnvDetail" class="inline-input large" placeholder="" @input="onInlineInput('allergyEnvDetail',$event)" />
+          </template>
+          <template v-else>{{ printCheck(form.allergyEnvNone) }} 无环境过敏 {{ printCheck(!form.allergyEnvNone) }} 环境过敏:{{ form.allergyEnvDetail }}</template>
+        </td>
+      </tr>
+
+      <!-- 老年综合征 -->
+      <tr>
+        <td class="lbl multi-line" rowspan="9">老年综合<br/>征</td>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.fallNone" @change="updateForm('fallNone',true);updateForm('fallDetail','')" /> 无跌倒</label>
+            <label><input type="checkbox" :checked="!form.fallNone" @change="updateForm('fallNone',false)" /> 有跌倒(</label>
+            <input :value="form.fallDetail" class="inline-input medium" placeholder="详情" @input="onInlineInput('fallDetail',$event)" />
+            <span>)</span>
+          </template>
+          <template v-else>{{ printCheck(form.fallNone) }} 无跌倒 {{ printCheck(!form.fallNone) }} 有跌倒({{ form.fallDetail }})</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.memoryDeclineNone" @change="updateForm('memoryDeclineNone',true);updateForm('memoryDeclineDetail','')" /> 无记忆力减退</label>
+            <label><input type="checkbox" :checked="!form.memoryDeclineNone" @change="updateForm('memoryDeclineNone',false)" /> 有记忆力减退(</label>
+            <input :value="form.memoryDeclineDetail" class="inline-input medium" placeholder="详情" @input="onInlineInput('memoryDeclineDetail',$event)" />
+            <span>)</span>
+          </template>
+          <template v-else>{{ printCheck(form.memoryDeclineNone) }} 无记忆力减退 {{ printCheck(!form.memoryDeclineNone) }} 有记忆力减退({{ form.memoryDeclineDetail }})</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.weightLossNone" @change="updateForm('weightLossNone',true);updateForm('weightLossWeight','')" /> 无体重下降</label>
+            <label><input type="checkbox" :checked="!form.weightLossNone" @change="updateForm('weightLossNone',false)" /> 有体重下降(半年内下降</label>
+            <input :value="form.weightLossWeight" class="inline-input tiny" placeholder="kg" @input="onInlineInput('weightLossWeight',$event)" />
+            <span>kg)</span>
+          </template>
+          <template v-else>{{ printCheck(form.weightLossNone) }} 无体重下降 {{ printCheck(!form.weightLossNone) }} 有体重下降(半年内下降{{ form.weightLossWeight }}kg)</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.urinaryIncontinenceNone" @change="updateForm('urinaryIncontinenceNone',true);updateForm('urinaryIncontinenceCount','')" /> 无尿失禁</label>
+            <label><input type="checkbox" :checked="!form.urinaryIncontinenceNone" @change="updateForm('urinaryIncontinenceNone',false)" /> 有尿失禁(</label>
+            <input :value="form.urinaryIncontinenceCount" class="inline-input small" placeholder="次数/日" @input="onInlineInput('urinaryIncontinenceCount',$event)" />
+            <span>次/日)</span>
+          </template>
+          <template v-else>{{ printCheck(form.urinaryIncontinenceNone) }} 无尿失禁 {{ printCheck(!form.urinaryIncontinenceNone) }} 有尿失禁({{ form.urinaryIncontinenceCount }}次/日)</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.sleepDisorderNone" @change="updateForm('sleepDisorderNone',true);form.sleepDisorderTypes=[]" /> 无睡眠障碍</label>
+            <label><input type="checkbox" :checked="!form.sleepDisorderNone" @change="updateForm('sleepDisorderNone',false)" /> 有睡眠障碍(</label>
+            <template v-if="!form.sleepDisorderNone">
+              <label v-for="st in ['入睡困难','早醒','夜间易醒','多梦']" :key="st" style="margin-right:4px;">
+                <input type="checkbox" :checked="form.sleepDisorderTypes.includes(st)" @change="toggleArrayItem('sleepDisorderTypes',st)" /> {{ st }}
+              </label>
+              <span>其他:<input :value="form.sleepDisorderOther" class="inline-input small" placeholder="" @input="onInlineInput('sleepDisorderOther',$event)" /></span>
+            </template>
+            <span>)</span>
+          </template>
+          <template v-else>{{ printCheck(form.sleepDisorderNone) }} 无睡眠障碍 {{ printCheck(!form.sleepDisorderNone) }} 有睡眠障碍({{ [...form.sleepDisorderTypes, form.sleepDisorderOther].filter(Boolean).join('、') }})</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.painNone" @change="updateForm('painNone',true);updateForm('painPart','')" /> 无疼痛</label>
+            <label><input type="checkbox" :checked="!form.painNone" @change="updateForm('painNone',false)" /> 有疼痛(部位:</label>
+            <input :value="form.painPart" class="inline-input medium" placeholder="" @input="onInlineInput('painPart',$event)" />
+            <span>)</span>
+          </template>
+          <template v-else>{{ printCheck(form.painNone) }} 无疼痛 {{ printCheck(!form.painNone) }} 有疼痛(部位:{{ form.painPart }})</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.visionAbnormalNone" @change="updateForm('visionAbnormalNone',true);form.visionAbnormalTypes=[]" /> 无视力异常</label>
+            <label><input type="checkbox" :checked="!form.visionAbnormalNone" @change="updateForm('visionAbnormalNone',false)" /> 有视力异常(</label>
+            <template v-if="!form.visionAbnormalNone">
+              <label v-for="vt in ['远视','近视','散光','白内障','青光眼']" :key="vt" style="margin-right:4px;">
+                <input type="checkbox" :checked="form.visionAbnormalTypes.includes(vt)" @change="toggleArrayItem('visionAbnormalTypes',vt)" /> {{ vt }}
+              </label>
+              <span>程度:<input :value="form.visionAbnormalDegree" class="inline-input small" placeholder="" @input="onInlineInput('visionAbnormalDegree',$event)" /></span>
+            </template>
+            <span>)</span>
+          </template>
+          <template v-else>{{ printCheck(form.visionAbnormalNone) }} 无视力异常 {{ printCheck(!form.visionAbnormalNone) }} 有视力异常({{ [...form.visionAbnormalTypes, form.visionAbnormalDegree].filter(Boolean).join('、') }})</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.hearingLossNone" @change="updateForm('hearingLossNone',true);updateForm('hearingLossDetail','')" /> 无听力障碍</label>
+            <label><input type="checkbox" :checked="!form.hearingLossNone" @change="updateForm('hearingLossNone',false)" /> 有听力障碍(</label>
+            <input :value="form.hearingLossDetail" class="inline-input medium" placeholder="详情" @input="onInlineInput('hearingLossDetail',$event)" />
+            <span>)</span>
+          </template>
+          <template v-else>{{ printCheck(form.hearingLossNone) }} 无听力障碍 {{ printCheck(!form.hearingLossNone) }} 有听力障碍({{ form.hearingLossDetail }})</template>
+        </td>
+      </tr>
+      <tr>
+        <td colspan="6" class="syndrome-row">
+          <template v-if="!isTextMode">
+            <label><input type="checkbox" :checked="form.mentalStatusNone" @change="updateForm('mentalStatusNone',true);form.mentalStatusList=[]" /> 无精神问题</label>
+            <label><input type="checkbox" :checked="!form.mentalStatusNone" @change="updateForm('mentalStatusNone',false)" /> 有(可多选)</label>
+            <div v-if="!form.mentalStatusNone" class="mental-list">
+              <label v-for="m in mentalOptions" :key="m" class="mental-item">
+                <input type="checkbox" :checked="form.mentalStatusList.includes(m)" @change="toggleArrayItem('mentalStatusList',m)" /> {{ m }}
+              </label>
+              <span>其他:<input :value="form.mentalStatusOther" class="inline-input small" placeholder="" @input="onInlineInput('mentalStatusOther',$event)" /></span>
+            </div>
+          </template>
+          <template v-else>
+            {{ printCheck(form.mentalStatusNone) }} 无精神问题
+            <template v-if="!form.mentalStatusNone">{{ printCheck(true) }} 有:{{ form.mentalStatusList.join('、') }} {{ form.mentalStatusOther }}</template>
+          </template>
+        </td>
+      </tr>
+
+      <!-- 语言表达 -->
+      <tr>
+        <td class="lbl">语言表达</td>
+        <td colspan="6" class="check-cell">
+          <template v-if="!isTextMode">
+            <label v-for="le in ['清晰','含糊','失语','方言']" :key="le"><input type="checkbox" :checked="form.languageExpression.includes(le)" @change="toggleArrayItem('languageExpression',le)" /> {{ le }}</label>
+            <span>其他:<input :value="form.languageExpressionOther" class="inline-input small" placeholder="" @input="onInlineInput('languageExpressionOther',$event)" /></span>
+          </template>
+          <template v-else>
+            <template v-for="le in ['清晰','含糊','失语','方言']" :key="le">{{ printCheck(form.languageExpression.includes(le)) }} {{ le }} </template>
+            其他:{{ form.languageExpressionOther }}
+          </template>
+        </td>
+      </tr>
+
+      <!-- 备注 -->
+      <tr>
+        <td class="lbl">备注</td>
+        <td colspan="6">
+          <template v-if="!isTextMode">
+            <textarea v-model="form.otherNotes" rows="3" class="remark-textarea" placeholder="请输入备注信息" @input="emitForm"></textarea>
+          </template>
+          <template v-else>{{ form.otherNotes || '无' }}</template>
+        </td>
+      </tr>
+
+      <!-- 签名区域:签章(2) + 乙方(2) + 签名(3) = 7列 -->
+      <tr>
+        <td class="lbl" rowspan="2" colspan="2">签章</td>
+        <td colspan="2">乙方(入住人/监护人)签章:</td>
+        <td colspan="3">
+          <SignatureItem v-model="form.partyBSign" :is-text-mode="isTextMode" />
+        </td>
+      </tr>
+      <tr>
+        <td colspan="2">丙方(机构负责人)签章:</td>
+        <td colspan="3">
+          <SignatureItem v-model="form.partyCSign" :is-text-mode="isTextMode" />
+        </td>
+      </tr>
+      <tr>
+        <td class="lbl" colspan="2">签署日期</td>
+        <td colspan="5">
+          <FieldItem :model-value="form.signDate" :is-text-mode="isTextMode" type="date" width="180px" @update:model-value="(v:any)=>updateForm('signDate',v)" />
+        </td>
+      </tr>
+      </tbody>
+    </table>
+  </div>
+</template>
+
+<style scoped lang="scss">
+/* A4纸宽度适配:210mm × 297mm,考虑打印边距后内容区约 190mm */
+.check-in-registration {
+  width: 210mm;
+  max-width: 100%;
+  margin: 0 auto;
+  font-family: 'SimSun', 'Microsoft YaHei', serif;
+  font-size: 14px;
+  color: #333;
+  background: #fff;
+  padding: 4mm;
+
+  /* 打印模式优化:A4纸尺寸 */
+  @media print {
+    width: 210mm;
+    max-width: 210mm;
+    padding: 1mm;
+    border: none;
+    margin: 0;
+  }
+}
+
+.doc-title {
+  text-align: center;
+  font-size: 22px;
+  font-weight: bold;
+  letter-spacing: 8px;
+  margin: 16px 0 12px;
+  color: #000;
+}
+
+.doc-meta {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 10px;
+  font-size: 14px;
+}
+
+/* 表格基础样式 - A4纸适配 */
+.reg-table {
+  width: 100%;
+  border-collapse: collapse;
+  table-layout: fixed; /* 固定表格布局,按比例分配列宽 */
+  font-size: 13px;
+
+  td {
+    border: 1px solid #333;
+    padding: 3mm 2mm;
+    vertical-align: middle;
+    word-break: break-all;
+  }
+
+  /* 打印模式 */
+  @media print {
+    td {
+      border-color: #000;
+      padding: 2mm 1.5mm;
+    }
+  }
+}
+
+/* 标签单元格 - 紧凑型,只留最小padding */
+.lbl {
+  background-color: #f5f7fa;
+  font-weight: bold;
+  text-align: center;
+  white-space: nowrap;
+  padding: 2mm 0mm !important; /* 标签列更紧凑 */
+
+  &.multi-line {
+    line-height: 1.4;
+    padding: 4px;
+  }
+
+  /* 打印模式 */
+  @media print {
+    background-color: #f0f0f0 !important;
+    -webkit-print-color-adjust: exact;
+    print-color-adjust: exact;
+  }
+}
+
+/* 列宽定义 - 已改用内联style精确控制 */
+/* .w80 { width: 80px; }
+.w120 { width: 120px; }
+.w60 { width: 60px; }
+.w90 { width: 90px; }
+.w50 { width: 50px; } */
+
+/* 单选格 */
+.radio-cell {
+  white-space: nowrap;
+
+  label {
+    margin-right: 12px;
+    cursor: pointer;
+
+    input[type="radio"] {
+      margin-right: 2px;
+    }
+  }
+}
+
+/* 多选格 */
+.check-cell {
+  label {
+    margin-right: 16px;
+    cursor: pointer;
+    white-space: nowrap;
+
+    input[type="checkbox"] {
+      margin-right: 2px;
+    }
+  }
+
+  @media print {
+    label {
+      margin-right: 12px;
+    }
+  }
+}
+
+/* 照片单元格 - 最右侧第7列,由colgroup控制宽度 */
+.photo-cell {
+  text-align: center;
+  vertical-align: top !important;
+  padding: 2mm 1mm;
+  background: #fafafa;
+
+  .photo-box {
+    width: 31mm;
+    height: 40mm;
+    
+    border: 1px solid #ddd;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    overflow: hidden;
+    background: #fff;
+
+    .elder-photo {
+      max-width: 100%;
+      max-height: 100%;
+      object-fit: cover;
+    }
+
+    .photo-placeholder {
+      color: #999;
+      font-size: 14px;
+    }
+  }
+
+  @media print {
+    background: #fff !important;
+  }
+}
+
+/* 行内输入框 */
+.inline-input {
+  border: 1px solid #dcdfe6;
+  border-radius: 3px;
+  padding: 2px 6px;
+  font-size: 13px;
+  outline: none;
+  vertical-align: middle;
+  background: #fff;
+
+  &:focus {
+    border-color: #409eff;
+  }
+
+  &.tiny { width: 40px; }
+  &.small { width: 80px; }
+  &.medium { width: 140px; }
+  &.large { width: 280px; }
+}
+
+/* 文本前后缀 */
+.text-prefix {
+  display: inline-block;
+  margin-left: 20px;
+}
+.ml20 { margin-left: 20px; }
+.text-suffix {
+  margin: 0 4px;
+  white-space: nowrap;
+}
+
+/* 疾病行 */
+.disease-row {
+  label {
+    white-space: nowrap;
+    input[type="checkbox"] { margin-right: 2px; }
+  }
+}
+
+/* 不适症状 */
+.symptom-cell {
+  line-height: 1.8;
+
+  .symptom-list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 4px 12px;
+    margin-top: 6px;
+    padding: 8px;
+    background: #fafafa;
+    border-radius: 4px;
+
+    .symptom-item {
+      margin: 0;
+    }
+  }
+}
+
+/* 过敏行 */
+.allergy-row {
+  label {
+    white-space: nowrap;
+    input[type="checkbox"] { margin-right: 2px; }
+  }
+}
+
+/* 老年综合征行 */
+.syndrome-row {
+  label {
+    white-space: nowrap;
+    input[type="checkbox"] { margin-right: 2px; }
+  }
+}
+
+/* 精神状态列表 */
+.mental-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 4px 12px;
+  margin-top: 6px;
+  padding: 8px;
+  background: #fafafa;
+  border-radius: 4px;
+
+  .mental-item {
+    margin: 0;
+  }
+}
+
+/* 备注文本域 */
+.remark-textarea {
+  width: 98%;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 6px 8px;
+  font-size: 13px;
+  font-family: inherit;
+  resize: vertical;
+  outline: none;
+  box-sizing: border-box;
+
+  &:focus {
+    border-color: #409eff;
+  }
+}
+
+/* 打印模式全局样式 */
+@media print {
+  .check-in-registration {
+    font-size: 12pt;
+  }
+
+  .doc-title {
+    font-size: 18pt;
+  }
+
+  .reg-table {
+    font-size: 11pt;
+  }
+
+  .inline-input,
+  .remark-textarea {
+    border: none;
+    border-bottom: 1px solid #333;
+    background: transparent;
+  }
+
+  .photo-box {
+    border: 1px solid #333;
+  }
+
+  .symptom-list,
+  .mental-list {
+    background: transparent;
+    border: none;
+  }
+}
+</style>

+ 24 - 44
src/views/elderly/contracts/components/ContractBody.vue

@@ -7,7 +7,8 @@ import { getCheckInDetailByElderId } from '@/api/elderly/apply/check-in'
 import { getOverheadListByType } from '@/api/elderly/fee/overheadCharge'
 import FieldItem from './FieldItem.vue'
 import SignatureItem from './SignatureItem.vue'
-
+import { useUserStore } from '@/store/modules/user'
+const userStore = useUserStore()
 const props = defineProps<{
   recordRow?: any
   isTextMode?: boolean
@@ -60,7 +61,7 @@ const contractForm = reactive({
   contractMonths: '',
   startDate: '',
   endDate: '',
-  servicePlace: '颐年集团养老服务机构',
+  servicePlace: userStore.getTenantName || '',
   bedFee: '',
   nurseFee: '',
   mealFee: '',
@@ -836,17 +837,9 @@ watch(
           &nbsp;&nbsp;(2)一次性收取的费用(如有请填写)。
         </p>
       </div>
-    </div>
+    
 
-    <!-- ========== 第7页:第三条 一次性费用及支付方式 ========== -->
-    <div class="a4-page">
-      <div class="page-header">
-        <div class="logo-line">
-          <span class="logo-circle">颐</span>
-          <span class="logo-text">颐年医养</span>
-        </div>
-        <span class="page-no-right">7</span>
-      </div>
+    
       <div class="page-content">
         <div v-for="(item, index) in oneTimeExpensesList" :key="item.id" class="content-text">
           &nbsp;&nbsp;&nbsp;&nbsp;{{ numberToCircle(index + 1) }}{{ displayExpenseName(item) }}
@@ -904,7 +897,7 @@ watch(
       </div>
     </div>
 
-    <!-- ========== 第8页:第三条 账户信息及后续 ========== -->
+    <!-- ========== 第8页:第三条 账户信息及后续 + 第四条 甲方权利及义务 ========== -->
     <div class="a4-page">
       <div class="page-header">
         <div class="logo-line">
@@ -959,19 +952,6 @@ watch(
         <p class="content-text">
           10.甲方在收到款项后应向付款人开具等额的合法收费发票。
         </p>
-      </div>
-    </div>
-
-    <!-- ========== 第9页:第四条 甲方权利及义务 ========== -->
-    <div class="a4-page">
-      <div class="page-header">
-        <div class="logo-line">
-          <span class="logo-circle">颐</span>
-          <span class="logo-text">颐年医养</span>
-        </div>
-        <span class="page-no-right">9</span>
-      </div>
-      <div class="page-content">
         <h2 class="section-title">第四条&nbsp;&nbsp;甲方权利及义务</h2>
         <h3 class="subsection-title">1.甲方权利</h3>
         <p class="content-text">
@@ -993,7 +973,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">10</span>
+        <span class="page-no-right">9</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1029,7 +1009,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">11</span>
+        <span class="page-no-right">10</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1063,7 +1043,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">12</span>
+        <span class="page-no-right">11</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1102,7 +1082,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">13</span>
+        <span class="page-no-right">12</span>
       </div>
       <div class="page-content">
         <h3 class="subsection-title">1.乙方的权利</h3>
@@ -1154,7 +1134,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">14</span>
+        <span class="page-no-right">13</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1199,7 +1179,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">15</span>
+        <span class="page-no-right">14</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1257,7 +1237,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">16</span>
+        <span class="page-no-right">15</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1331,7 +1311,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">18</span>
+        <span class="page-no-right">17</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1378,7 +1358,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">19</span>
+        <span class="page-no-right">18</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1412,7 +1392,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">20</span>
+        <span class="page-no-right">19</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1453,7 +1433,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">21</span>
+        <span class="page-no-right">20</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1521,7 +1501,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">23</span>
+        <span class="page-no-right">22</span>
       </div>
       <div class="page-content">
         <p class="content-text">
@@ -1574,7 +1554,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">24</span>
+        <span class="page-no-right">23</span>
       </div>
       <div class="page-content">
         <h2 class="section-title">第十四条&nbsp;&nbsp;合同生效及附件</h2>
@@ -1648,7 +1628,7 @@ watch(
           <span class="logo-circle">颐</span>
           <span class="logo-text">颐年医养</span>
         </div>
-        <span class="page-no-right">25</span>
+        <span class="page-no-right">24</span>
       </div>
       <div class="page-content">
         <p class="content-text" style="padding-left: 2em;">
@@ -1675,13 +1655,13 @@ watch(
         <div style="margin-top: 30px; font-size: 14px; line-height: 2.2;">
           <p>
             甲方(盖章):
-            <FieldItem v-model="contractForm.partyASign" :is-text-mode="isTextMode" width="260px" placeholder="(盖章处)" />
+            <SignatureItem :elder-id="props.recordRow.elderId" v-model="contractForm.partyASign" :is-text-mode="isTextMode" :width="260" :height="80" placeholder="(签字/盖章处)" title="甲方签字"  />
           </p>
           <div>
             法定代表人(签字):
             <SignatureItem :elder-id="props.recordRow.elderId" v-model="contractForm.partyALegalSign" :is-text-mode="isTextMode" :width="260" :height="80" placeholder="(签字处)" title="法定代表人签字" />
           </div>
-          <div>
+          <div style="margin-top: 6px;">
             日期:
             <FieldItem v-model="contractForm.partyADate" :is-text-mode="isTextMode" type="date" width="200px" placeholder="请选择日期" />
           </div>
@@ -1689,7 +1669,7 @@ watch(
             乙方(签字):
             <SignatureItem :elder-id="props.recordRow.elderId" v-model="contractForm.partyBSign" :is-text-mode="isTextMode" :width="260" :height="80" placeholder="(签字处)" title="乙方签字" />
           </div>
-          <div>
+          <div style="margin-top: 6px;">
             日期:
             <FieldItem v-model="contractForm.partyBDate" :is-text-mode="isTextMode" type="date" width="200px" placeholder="请选择日期" />
           </div>
@@ -1697,7 +1677,7 @@ watch(
             丙方(签字/盖章):
             <SignatureItem :elder-id="props.recordRow.elderId" v-model="contractForm.partyCSign" :is-text-mode="isTextMode" :width="260" :height="80" placeholder="(签字/盖章处)" title="丙方签字"  />
           </div>
-          <div>
+          <div style="margin-top: 6px;">
             日期:
             <FieldItem v-model="contractForm.partyCDate" :is-text-mode="isTextMode" type="date" width="200px" placeholder="请选择日期" />
           </div>

+ 195 - 0
src/views/elderly/contracts/components/ElderSafetyCommitmentBody.vue

@@ -0,0 +1,195 @@
+<script setup lang="ts">
+import { reactive, watch } from 'vue'
+import SignatureItem from './SignatureItem.vue'
+
+interface FormData {
+  elderSign?: string
+  guardianSign?: string
+  signDate?: string
+}
+
+const props = withDefaults(defineProps<{
+  isTextMode?: boolean
+  modelValue?: FormData
+}>(), {
+  isTextMode: false,
+  modelValue: () => ({})
+})
+
+const emit = defineEmits<{
+  (e: 'update:modelValue', val: FormData): void
+}>()
+
+const form = reactive<FormData>({
+  elderSign: '',
+  guardianSign: '',
+  signDate: ''
+})
+
+watch(
+  () => props.modelValue,
+  (val) => {
+    if (val) {
+      Object.assign(form, val)
+    }
+  },
+  { immediate: true, deep: true }
+)
+
+const updateForm = (key: keyof FormData, val: any) => {
+  ;(form as any)[key] = val
+  emit('update:modelValue', { ...form })
+}
+</script>
+
+<template>
+  <div class="elder-safety-commitment">
+    <div class="attachment-title" style="font-size: 16px;width: 100%;text-align: left;">附件4</div>
+    <div class="attachment-title">长者安全承诺书</div>
+    <div class="content">
+      <p class="indent">
+        为了确保养老机构的安全生产,保障全院人员的生命财产安全,我谨以诚挚的态度郑重承诺,严格遵守以下规定:
+      </p>
+
+      <p class="clause">
+        <span class="clause-title">电器设备管理:</span>
+        本人将严格按照养老机构的安全管理规定,不私自搭拉电线,不擅自购买或使用任何电器设备(如电热毯、小太阳暖风机、电动泡脚桶等)。
+      </p>
+
+      <p class="clause">
+        <span class="clause-title">消防安全管理:</span>
+        本人将严格按照养老机构的消防管理规定行事,绝不在室内吸烟,并承诺不私自购买烟草或向家属索要火源(如打火机、火柴、电子点烟器等)。如需吸烟,配合到指定吸烟区域吸烟,确保吸完烟后将烟头妥善处理后扔入指定垃圾桶并进行灭火。主动将烟草和火机交由工作人员保管。
+      </p>
+
+      <p class="clause">
+        <span class="clause-title">房间卫生安全管理:</span>
+        本人承诺保持房间整洁,不堆放杂物,不购买或使用易被误食的洗涤剂,也不购买或使用任何利器。
+      </p>
+
+      <p class="clause">
+        <span class="clause-title">电动轮椅管理:</span>
+        如购买电动轮椅,本人同意在不使用时将其交由楼层管理人员指定位置统一看管,保证不放置在房间内,并在充电时到指定室外充电点进行操作。
+      </p>
+
+      <p class="clause">
+        <span class="clause-title">禁止使用明火或烟雾物品:</span>
+        本人承诺不使用蚊香、艾条等具有明火或烟雾的物品,确保室内空气清新。
+      </p>
+
+      <p class="indent">
+        本人郑重承诺严格遵守以上规定。如违规将配合通知家属收回,同时被养老机构发函警告满三次,将自动作退住处理。对于任何违规行为所造成的后果,本人及家属将承担全部责任。
+      </p>
+
+      <p class="indent">
+        本人郑重承诺,如有违反以上规定,愿意接受相应的处罚和责任。
+      </p>
+    </div>
+
+    <!-- 签名区域 -->
+    <div class="sign-section">
+      <div class="sign-row">
+        <span class="sign-label">入住长者(签字按手印):</span>
+        <SignatureItem
+          v-model="form.elderSign"
+          :is-text-mode="isTextMode"
+          width="200"
+        />
+      </div>
+      <div class="sign-row">
+        <span class="sign-label">监护人/委托代理人(签字按手印):</span>
+        <SignatureItem
+          v-model="form.guardianSign"
+          :is-text-mode="isTextMode"
+          width="200"
+        />
+      </div>
+      <div class="sign-row date-row">
+        <span class="sign-label">签署日期:</span>
+        <template v-if="!isTextMode">
+          <el-date-picker
+            v-model="form.signDate"
+            type="date"
+            placeholder="请选择日期"
+            style="width: 160px"
+            @change="updateForm('signDate', form.signDate)"
+          />
+        </template>
+        <template v-else>
+          <span class="date-value">{{ form.signDate || '____年__月__日' }}</span>
+        </template>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.elder-safety-commitment {
+  width: 210mm;
+  max-width: 100%;
+  margin: 0 auto;
+  font-family: 'SimSun', 'Microsoft YaHei', serif;
+  font-size: 14px;
+  color: #333;
+  background: #fff;
+  padding: 5mm;
+
+  /* 打印模式优化 */
+  @media print {
+    width: 210mm;
+    max-width: 210mm;
+    padding: 5mm;
+    border: none;
+    margin: 0;
+  }
+}
+
+.attachment-title {
+  text-align: center;
+  font-size: 20px;
+  font-weight: bold;
+  margin-bottom: 20px;
+}
+
+.content {
+  line-height: 1.8;
+}
+
+.indent {
+  text-indent: 2em;
+  margin: 0 0 12px 0;
+}
+
+.clause {
+  text-indent: 2em;
+  margin: 0 0 10px 0;
+}
+
+.clause-title {
+  font-weight: bold;
+}
+
+.sign-section {
+  margin-top: 30px;
+  padding-left: 2em;
+}
+
+.sign-row {
+  display: flex;
+  align-items: center;
+  margin-bottom: 16px;
+}
+
+.sign-label {
+  white-space: nowrap;
+  margin-right: 8px;
+}
+
+.date-row {
+  margin-top: 8px;
+}
+
+.date-value {
+  min-width: 120px;
+  display: inline-block;
+}
+</style>

+ 514 - 0
src/views/elderly/contracts/delegation-agent-confirmation-form/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/delegation-agent-confirmation-form/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 761 - 0
src/views/elderly/contracts/elder-safety-commitment/AddForm.vue

@@ -0,0 +1,761 @@
+<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">
+        <ElderSafetyCommitmentBody
+          v-model="safetyCommitmentForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import ElderSafetyCommitmentBody from '../components/ElderSafetyCommitmentBody.vue'
+
+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) // 表单的加载中�?)修改时的数据加载;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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+
+/** 风险程度样式�?*/
+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'
+}
+
+/** 处理级别选择变化 - 清空其他级别的选中�?*/
+const handleLevelChange = (val: number) => {
+  // 根据选中的级别,清空其他级别的多选框
+  if (val === 1) {
+    form.attackLevel2Items = []
+    form.attackLevel3Items = []
+    form.attackLevel4Items = []
+  } else if (val === 2) {
+    form.attackLevel1Items = []
+    form.attackLevel3Items = []
+    form.attackLevel4Items = []
+  } else if (val === 3) {
+    form.attackLevel1Items = []
+    form.attackLevel2Items = []
+    form.attackLevel4Items = []
+  } else if (val === 4) {
+    form.attackLevel1Items = []
+    form.attackLevel2Items = []
+    form.attackLevel3Items = []
+  }
+}
+
+
+
+/** 将表单数据序列化�?JSON 对象 */
+const serializeFormData = () => {
+  return {
+    // 基本信息
+    assessor: form.assessor || '',
+    assessDate: form.assessDate ? dayjs(form.assessDate).format('YYYY-MM-DD') : '',
+
+    // 攻击风险等级�?=I级,2=II级,3=III级,4=IV级)
+    attackLevel: form.attackLevel || 0,
+
+    // 各级别选择的具体项
+    attackLevel1Items: form.attackLevel1Items || [],
+    attackLevel2Items: form.attackLevel2Items || [],
+    attackLevel3Items: form.attackLevel3Items || [],
+    attackLevel4Items: form.attackLevel4Items || [],
+
+    // 风险程度
+    riskLevel: form.riskLevel || '',
+
+    // 预防措施
+    preventiveMeasures: form.preventiveMeasures || [],
+    preventiveMeasuresOther: form.preventiveMeasuresOther || '',
+
+    // 签名
+    familySignature: form.familySignature || '',
+    familySignDate: form.familySignDate ? dayjs(form.familySignDate).format('YYYY-MM-DD') : '',
+
+    // 长者安全承诺书内容
+    safetyCommitment: {
+      elderSign: safetyCommitmentForm.elderSign || '',
+      guardianSign: safetyCommitmentForm.guardianSign || '',
+      signDate: safetyCommitmentForm.signDate || ''
+    }
+  }
+}
+
+/** �?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.attackLevel1Items = formData.attackLevel1Items || []
+  form.attackLevel2Items = formData.attackLevel2Items || []
+  form.attackLevel3Items = formData.attackLevel3Items || []
+  form.attackLevel4Items = formData.attackLevel4Items || []
+
+  // 风险程度
+  form.riskLevel = formData.riskLevel || ''
+
+  // 预防措施
+  form.preventiveMeasures = formData.preventiveMeasures || []
+  form.preventiveMeasuresOther = formData.preventiveMeasuresOther || ''
+
+  // 签名
+  form.familySignature = formData.familySignature || ''
+  form.familySignDate = formData.familySignDate ? dayjs(formData.familySignDate).toDate() : ''
+
+  // 长者安全承诺书内容
+  if (formData.safetyCommitment) {
+    safetyCommitmentForm.elderSign = formData.safetyCommitment.elderSign || ''
+    safetyCommitmentForm.guardianSign = formData.safetyCommitment.guardianSign || ''
+    safetyCommitmentForm.signDate = formData.safetyCommitment.signDate || ''
+  }
+}
+
+/** 重置攻击风险因素评估表表单数�?*/
+const resetAttackRiskForm = () => {
+  form.assessor = ''
+  form.assessDate = ''
+
+  // 攻击风险等级
+  form.attackLevel = 0
+
+  // 各级别选择的具体项
+  form.attackLevel1Items = []
+  form.attackLevel2Items = []
+  form.attackLevel3Items = []
+  form.attackLevel4Items = []
+
+  // 风险程度
+  form.riskLevel = ''
+
+  // 预防措施
+  form.preventiveMeasures = []
+  form.preventiveMeasuresOther = ''
+
+  // 签名
+  form.familySignature = ''
+  form.familySignDate = ''
+
+  // 长者安全承诺书
+  safetyCommitmentForm.elderSign = ''
+  safetyCommitmentForm.guardianSign = ''
+  safetyCommitmentForm.signDate = ''
+}
+
+/** 打开弹窗 */
+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: '',
+
+  // 攻击风险等级�?=无,1=I级,2=II级,3=III级,4=IV级)
+  attackLevel: 0,
+
+  // 各级别选择的具体项
+  attackLevel1Items: [], // I级选择的项�?-7�?
+  attackLevel2Items: [], // II级选择的项�?-3�?
+  attackLevel3Items: [], // III级选择的项�?-4�?
+  attackLevel4Items: [], // IV级选择的项�?-2�?
+
+  // 风险程度
+  riskLevel: '',
+
+  // 预防措施
+  preventiveMeasures: [],
+  preventiveMeasuresOther: '',
+
+  // 签名
+  familySignature: '',
+  familySignDate: ''
+})
+
+// 监听攻击等级变化,自动判断风险等�?
+watch(() => form.attackLevel, () => {
+  autoJudgeRiskLevel()
+})
+
+// 长者安全承诺书表单数据
+const safetyCommitmentForm = reactive({
+  elderSign: '',
+  guardianSign: '',
+  signDate: ''
+})
+
+
+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,
+      assessScore: form.attackLevel,
+      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()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/elder-safety-commitment/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 514 - 0
src/views/elderly/contracts/explanation-examination-report-items copy/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/explanation-examination-report-items copy/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 514 - 0
src/views/elderly/contracts/explanation-examination-report-items/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/explanation-examination-report-items/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 514 - 0
src/views/elderly/contracts/guardian-party-b/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/guardian-party-b/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 514 - 0
src/views/elderly/contracts/identification-document-partyb/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/identification-document-partyb/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 514 - 0
src/views/elderly/contracts/outing-confirmation-form/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/outing-confirmation-form/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 514 - 0
src/views/elderly/contracts/power-of-attorney/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/power-of-attorney/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 2 - 406
src/views/elderly/contracts/risk-disclosure-statement/AddForm.vue

@@ -63,7 +63,6 @@
 
     <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>
 
@@ -114,15 +113,7 @@ const elderUp = (e) => {
 
 // ========== 攻击风险因素评估量表 表单序列化方法 ==========
 
-/** 风险程度文本 */
-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(() => {
@@ -142,27 +133,7 @@ const autoJudgeRiskLevel = () => {
   else form.riskLevel = 'high'
 }
 
-/** 处理级别选择变化 - 清空其他级别的选中项 */
-const handleLevelChange = (val: number) => {
-  // 根据选中的级别,清空其他级别的多选框
-  if (val === 1) {
-    form.attackLevel2Items = []
-    form.attackLevel3Items = []
-    form.attackLevel4Items = []
-  } else if (val === 2) {
-    form.attackLevel1Items = []
-    form.attackLevel3Items = []
-    form.attackLevel4Items = []
-  } else if (val === 3) {
-    form.attackLevel1Items = []
-    form.attackLevel2Items = []
-    form.attackLevel4Items = []
-  } else if (val === 4) {
-    form.attackLevel1Items = []
-    form.attackLevel2Items = []
-    form.attackLevel3Items = []
-  }
-}
+ 
 
 
 
@@ -471,381 +442,6 @@ const handleClosed = () => {
   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;
-        }
-        .assessment-table .select {
-          text-align: center;
-          vertical-align: middle;
-        }
-        .assessment-table .print-multi-select {
-          margin-top: 8px;
-          padding-top: 8px;
-          border-top: 1px dashed #ccc;
-          font-size: 9pt;
-        }
-
-        .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">
-              <div>${form.attackLevel === 1 ? '☑' : '☐'} 符合</div>
-              <div class="print-multi-select">
-                ${[1,2,3,4,5,6,7].map(n => `${form.attackLevel1Items?.includes(n) ? '☑' : '☐'} ${n}`).join('&nbsp;&nbsp;')}
-              </div>
-            </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">
-              <div>${form.attackLevel === 2 ? '☑' : '☐'} 符合</div>
-              <div class="print-multi-select">
-                ${[1,2,3].map(n => `${form.attackLevel2Items?.includes(n) ? '☑' : '☐'} ${n}`).join('&nbsp;&nbsp;')}
-              </div>
-            </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">
-              <div>${form.attackLevel === 3 ? '☑' : '☐'} 符合</div>
-              <div class="print-multi-select">
-                ${[1,2,3,4].map(n => `${form.attackLevel3Items?.includes(n) ? '☑' : '☐'} ${n}`).join('&nbsp;&nbsp;')}
-              </div>
-            </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">
-              <div>${form.attackLevel === 4 ? '☑' : '☐'} 符合</div>
-              <div class="print-multi-select">
-                ${[1,2].map(n => `${form.attackLevel4Items?.includes(n) ? '☑' : '☐'} ${n}`).join('&nbsp;&nbsp;')}
-              </div>
-            </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="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>
 

+ 2 - 2
src/views/elderly/contracts/risk-disclosure-statement/index.vue

@@ -17,7 +17,7 @@
         />
       </el-form-item>
 
-      <el-form-item label="评估人">
+      <el-form-item label="记录人">
         <el-input
           v-model="queryParams.assessor"
           placeholder="长者姓名"
@@ -70,7 +70,7 @@
 
 
       <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="assessor" header-align="center" align="center" label="床位号" min-width="200" show-overflow-tooltip/>
       <el-table-column header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
         <template #default="scope">
           <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">

+ 514 - 0
src/views/elderly/contracts/room-facilities-equipment/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/room-facilities-equipment/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 514 - 0
src/views/elderly/contracts/service-charging-standards-institution/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/service-charging-standards-institution/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

+ 514 - 0
src/views/elderly/contracts/signature-proxy-application/AddForm.vue

@@ -0,0 +1,514 @@
+<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">
+        <RiskDisclosureBody
+          v-model="riskDisclosureForm"
+          :is-text-mode="isDetail"
+        />
+      </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>
+    </template>
+
+  </el-drawer>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref, watch, reactive } from 'vue'
+
+import dayjs from 'dayjs'
+import RiskDisclosureBody from '../components/RiskDisclosureBody.vue'
+
+import { attackRiskCreate, attackRiskUpdate } from "@/api/social-work";
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const title = ref('')
+const dialogVisible = ref(false) // 弹窗
+const formRef = ref() // 表单 Ref
+const riskDisclosureForm = 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||e.fileNumber
+  dataForm.value.elderAge = e.elderAge
+}
+
+// ========== 攻击风险因素评估量表 表单序列化方法 ==========
+
+
+
+
+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,
+      assessScore: form.attackLevel,
+      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 = () => {
+
+  formRef.value?.resetFields()
+
+ 
+}
+
+// 关闭表单
+const handleClosed = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+
+</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>

+ 312 - 0
src/views/elderly/contracts/signature-proxy-application/index.vue

@@ -0,0 +1,312 @@
+<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 header-align="center" align="center" label="风险等级" min-width="200" show-overflow-tooltip>
+        <template #default="scope">
+          <el-tag v-if="getRiskLevelInfo(scope.row.assessData).text" :type="getRiskLevelInfo(scope.row.assessData).type">
+            {{ getRiskLevelInfo(scope.row.assessData).text }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <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" />
+
+
+
+</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 {
+  attackRiskDelete, attackRiskPage,
+} from "@/api/social-work";
+import { getRiskLevelInfo } from "@/utils/risk-assessment";
+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(),
+  assessDate: [],
+  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()
+  queryParams.assessDate = []
+  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>

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است