Kaynağa Gözat

电子合同增加区域选择

chenjun 2 hafta önce
ebeveyn
işleme
1e39da32e7

+ 129 - 0
.workbuddy/memory/2026-08-07.md

@@ -0,0 +1,129 @@
+# 2026-08-07 工作日志
+
+## data-board/nine-safety-measures/index.vue — 修复 getMonthList 报错与红名单过滤
+
+问题:
+1. 控制台报错 `echartsApi.getMonthList is not a function`,阻塞页面后续加载。
+2. 红名单 `highRiskItems` 中后端仍返回「简易精神状态」,选择「防误食」后过滤为空。
+
+改动:
+- 月份筛选相关代码已整体移除:`filter.month`、`monthOptions` ref、`onMounted` 中的 `echartsApi.getMonthList()` 调用、`handleReset` 中的 `filter.month = ''`。月份下拉在模板中已不存在,属于残留代码。
+- 增强 `normalizeRiskName`:对 trim 后的名称做精确或包含匹配,把「简易精神状态」统一映射为「防误食」。
+- 增强 `filteredRedList`:过滤时对每个 risk 再次调用 `normalizeRiskName`,并同时支持带「防」前缀、去前缀、互相包含等多种匹配方式,避免后端字段不统一导致过滤失败。
+
+类型检查:NO_NINE_SAFETY_ERRORS。
+
+## data-board/nine-safety-measures/index.vue — 红名单数据源头替换「简易精神状态」
+
+用户要求:不要复杂的过滤兼容逻辑,直接把 `multiHighRiskElders[i].highRiskItems` 字符串里的「简易精神状态」替换成「防误食」。
+
+改动:
+- `redList` 映射中,`highRiskItems` 先整体 `replace(/简易精神状态/g, '防误食')`,再按逗号拆分,不再依赖 `normalizeRiskName` 逐元素映射。
+- `filteredRedList` 恢复为简单的 `r.risks.includes(redRiskFilter.value)`,因为数据源头已经统一为「防误食」。
+- `normalizeRiskName` 仍保留,继续用于图表等其他接口返回的九防名称映射。
+
+类型检查:NO_NINE_SAFETY_ERRORS。
+
+## data-board/nine-safety-measures/index.vue — 红名单筛选"只有全部有数据"根因
+
+现象:选「全部」有数据,选任何具体九防风险都 0 条。
+
+根因:后端 `highRiskItems` 字符串里风险项的分隔符不是 ASCII 逗号,而是**顿号「、」或全角逗号「,」**。原 `.split(',')` 拆不开,整串变成一个数组元素,导致数组 `includes('防误食')` 恒为 false(数组里只有一个长串 ≠ '防误食')。这也解释了上一版 normalize 逐元素版本同样失败。
+
+改动:
+- `risks` 解析 `split` 改为正则 `/[,,、\s]+/`,支持中英文逗号、顿号、空白统一拆分。
+- `filteredRedList` 改为宽松匹配:精确 / 去「防」前缀 / 子串包含,进一步兜底命名差异。
+
+类型检查:NO_NINE_SAFETY_ERRORS。
+
+## elderly/contracts — 合同主体增加合同类型下拉与湖北合同组件
+
+需求:
+- 合同主体分隔栏左侧文字、右侧增加「合同类型」下拉:广州地区合同 / 湖北地区合同 / 天河老人院合同(默认广州地区合同)。
+- 选中类型随首次保存写入 `contractFormUpdate.value.contractInfo`(JSON)。
+- 下次打开详情时解析该字段,据此渲染不同合同组件。
+- 复制一份合同组件作为「湖北合同」。
+
+改动:
+- `components/ContractBody.vue`:
+  - `contractForm` reactive 新增 `contractType: '广州地区合同'`(首字段)。
+  - 新增 prop `contractType?: string` 和 emit `'update:contractType'`。
+  - 新增 watch:父级下拉变化时同步到 `contractForm.contractType`。
+  - `fetchContractData` 末尾 emit `update:contractType`(用 `contractForm.contractType || '广州地区合同'`)。
+  - 保存(`saveContract` 与无 contractInfo 的兜底分支)均 `JSON.stringify({ ...contractForm })`,自动包含 contractType。
+- 新建 `components/ContractBodyHubei.vue` = ContractBody.vue 的副本(含上述 contractType 支持)。
+- `ContractManageForm.vue`:
+  - 新增 `contractType` ref(默认'广州地区合同')与 `contractTypeOptions`。
+  - `合同主体` 分隔栏改为 flex:左标题、右 `el-select`,新增 `.contract-type-bar` 等样式。
+  - `ContractBody` / `ContractBodyHubei` 用 `v-if="contractType !== '湖北地区合同'"` 条件渲染,二者共用 `ref="contractBodyRef"`,都接收 `:contract-type` 并监听 `@update:contract-type` 回写。
+  - 打印 Teleport 容器内同样条件渲染两个组件。
+  - `open()` 中重置 `contractType` 为默认,避免上一次选择残留;实际类型由详情加载后子组件回传再切换。
+
+注意:ContractBody.vue 中 `contractForm.attachments`、`contractFormUpdate.value.bedName/contractInfo` 等为既有类型告警(非本次引入),ContractBodyHubei.vue 因复制同样存在;本次 contractType 改动未引入任何新类型错误。
+
+## elderly/contracts — 修复合同组件运行时初始化报错
+
+报错:
+1. `ReferenceError: Cannot access 'contractForm' before initialization`(ContractBody.vue:91)
+2. `TypeError: Cannot read properties of null (reading 'emitsOptions')`(ContractManageForm.vue:428)
+
+根因:上一版在 `ContractBody.vue` 顶部添加了 `watch(() => props.contractType, ..., { immediate: true })`,回调里访问了 `contractForm.contractType`,但 `contractForm` 的 `reactive(...)` 声明在文件更下方。`<script setup>` 中变量存在暂时性死区(TDZ),`immediate: true` 的 watch 在 setup 执行期间立即触发,导致 `contractForm` 还未初始化就被访问。
+
+第二个 `emitsOptions` 错误是 Vue 在子组件 setup 失败后内部更新逻辑抛出的连锁错误。
+
+改动:
+- 在 `ContractBody.vue` 和 `ContractBodyHubei.vue` 中,把该 `watch` 块从 `contractForm` 声明之前移到 `contractForm` reactive 声明之后(即 `stageExpenses` 字段下方)。
+- 保持 `immediate: true` 逻辑不变:父组件下拉切换合同类型时仍同步写入本地表单。
+
+类型检查:本次修复未引入新类型错误;剩余告警均为原文件既有问题。
+
+## elderly/contracts — 修复合同类型切换回弹 + 二次修改确认
+
+现象:
+1. 默认广州合同 → 切湖北并保存 → 重开显示湖北 → 再选广州,会自动跳回湖北。
+2. 用户希望二次修改(已有保存记录)时弹确认框,确认后再保存。
+
+根因:子组件 `fetchContractData` 末尾 `emit('update:contractType', 存储的类型)`,且父组件 `@update:contract-type="contractType = $event"` 无差别覆盖。手动切换后 v-if 重挂载子组件,又会回传存储的旧类型,把下拉框拽回旧值(回弹)。
+
+改动:
+- `ContractManageForm.vue`:
+  - 新增 `savedContractType`(初次解析出的已保存类型)、`hasSavedContract`(是否已存在保存记录)、`contractTypeResolved`(是否已解析)三个 ref。
+  - 新增 `handleContractTypeEmit`:仅当 `!contractTypeResolved` 时接受子组件回传类型并解析,其余回传忽略(消除手动切换重挂载导致的回弹)。
+  - 新增 `handleContractExists(exists)`:记录合同是否已存在。
+  - 新增 `handleContractTypeChange`(async):下拉 `@change` 触发;若 `hasSavedContract` 且类型与 `savedContractType` 不同,弹 `ElMessageBox.confirm`;确认则把 `savedContractType` 更新为新选择,取消则把 `contractType` 回退到 `savedContractType`。首次创建(无保存)不弹框。
+  - `open()` 重置三个状态;两个 ContractBody/ContractBodyHubei(含打印 Teleport 内)均绑定 `:lock-contract-type="contractTypeResolved"` 并改 `@update:contract-type`/`@update:contract-exists` 到新 handler。
+  - import `ElMessageBox` from 'element-plus'。
+- `components/ContractBody.vue` 与 `ContractBodyHubei.vue`:
+  - defineEmits 增加 `update:contractExists`;props 增加 `lockContractType?: boolean`。
+  - `fetchContractData` 末尾:若 `props.lockContractType && props.contractType` 则 `contractForm.contractType = props.contractType`(手动切换时用父组件选中值,保证保存值正确);emit `update:contractExists`(依据 `contractFormUpdate.value.contractInfo` 是否存在);再 emit `update:contractType`。
+
+注意:初次加载(lock=false)用存储类型驱动下拉;手动切换(lock=true)用父组件选中值并忽略旧回传,避免回弹且保证保存为新类型。类型检查无新增错误。
+
+## elderly/fee/comprehensive-setting — 合同区域配置改为 value2 字段并放到合同模块配置内
+
+需求:合同默认区域配置项放在「合同模块配置」卡片内部,而不是独立成新的卡片;字段使用 `value2` 而不是 `orgType`。
+
+改动:
+- `src/views/elderly/fee/comprehensive-setting/index.vue`:
+  - 将「合同区域设置」作为第二个 child 放在「合同过期通知设置」同一个 `children` 数组内。
+  - 把标识字段从 `orgTypeField` 改为 `value2Field`。
+  - `handleEdit` 中:保存时 `value2Field` 项传 `value: ''`、`value2: c.value`。
+  - `getList` 中:回显时 `value2Field` 项读取 `r.value2`。
+- `src/views/elderly/contracts/ContractManageForm.vue`:
+  - `loadContractTypeConfig` 读取 `config.value2` 作为 `defaultContractType`。
+
+类型检查:`comprehensive-setting/index.vue` 与 `ContractManageForm.vue` 无新增错误;子组件剩余告警均为既有问题。
+
+## elderly/contracts — 修复保存时 "[object Object] is not valid JSON" 控制台报错
+
+现象:点击保存合同,控制台报 `SyntaxError: "[object Object]" is not valid JSON`(ContractBody.vue:820),但保存成功。
+
+根因:`saveContract` 中遍历 `props.attachmentIds` 时对每个 `row` 直接 `JSON.parse(row)`。当 `row` 已经是对象而非字符串时,`JSON.parse` 会把它隐式转成 `"[object Object]"` 再解析,导致 SyntaxError。该错误被内层 try-catch 捕获并 console.log,不影响外层保存流程,所以保存仍能成功。
+
+改动:
+- `src/views/elderly/contracts/components/ContractBody.vue`:
+  - 第 811 行改为 `const data = typeof row === 'string' ? JSON.parse(row) : row`,对象直接复用。
+- `src/views/elderly/contracts/components/ContractBodyHubei.vue`:
+  - 同步上述修复。
+
+类型检查:未引入新类型错误;剩余告警均为原文件既有问题。

+ 7 - 9
src/components/business-components/selectElder.vue

@@ -14,7 +14,7 @@
     <el-option v-for="item in list" :key="item.id" :label="formatLabel(item)" :value="item.id">
       <div class="flex items-center">
         <span>{{ item.elderName }}</span>
-        <span>{{ item.idCard }}</span>
+        <span>{{ item.idCard }}{{ (item.inStatus||0) == 2 ? ' - 已退住' : '' }}</span>
       </div>
     </el-option>
   </el-select>
@@ -100,8 +100,8 @@ const toggleTypeFmt = computed(() => {
   return formToggleType.value || false
 })
 
-const upData = async (str,id?:any, triggerEvent = true) => {
-  if(id && id!='NaN'){
+const upData = async (str, id?: any, triggerEvent = true) => {
+  if (id && id != 'NaN') {
     try {
       const res = await getElderInfoById(id)
       inputValue.value = res.id
@@ -109,12 +109,10 @@ const upData = async (str,id?:any, triggerEvent = true) => {
         emit('elder', res)
       }
       return res
-    }catch (e) {}
+    } catch (e) {}
   }
-
 }
 
-
 interface listType {
   id: number
   elderName: string
@@ -180,10 +178,11 @@ const getList = async () => {
         ? await getElderlyPage(queryParams)
         : await getElderlybedChangeRecordPage({
             ...queryParams,
-            identification: props.type,
+            identification: props.type
           })
     list.value = res.list
-  } catch (e) {}finally {
+  } catch (e) {
+  } finally {
     loading.value = false
   }
 }
@@ -225,7 +224,6 @@ const handleGetList = () => {
 }
 
 defineExpose({ upData })
-
 </script>
 <style scoped lang="scss">
 .flex {

+ 29 - 24
src/views/data-board/nine-safety-measures/index.vue

@@ -36,11 +36,9 @@ echarts.use([
 
 // ========================= 筛选条件 =========================
 const filter = reactive({
-  month: '' as string,
   buildId: '' as string | number,
   floorId: '' as string | number
 })
-const monthOptions = ref<string[]>([])
 // 楼栋、楼层使用真实接口
 const buildList = ref<any[]>([])
 const floorList = ref<any[]>([])
@@ -73,19 +71,21 @@ const nineRiskOptions = computed(() =>
 )
 const filteredRedList = computed(() => {
   if (!redRiskFilter.value) return redList.value
-  const keyword = redRiskFilter.value.replace('防', '')
-  return redList.value.filter((r: any) =>
-    Array.isArray(r.risks) &&
-    r.risks.some((risk: any) => {
-      const s = String(risk || '').trim()
-      if (!s) return false
-      return (
-        s === redRiskFilter.value ||
-        s.replace('防', '') === keyword ||
-        s.includes(redRiskFilter.value) ||
-        redRiskFilter.value.includes(s)
-      )
-    })
+  const filterValue = redRiskFilter.value.trim()
+  const keyword = filterValue.replace(/^防/, '')
+  return redList.value.filter(
+    (r: any) =>
+      Array.isArray(r.risks) &&
+      r.risks.some((risk: any) => {
+        const s = String(risk || '').trim()
+        if (!s) return false
+        return (
+          s === filterValue ||
+          s.replace(/^防/, '') === keyword ||
+          s.includes(filterValue) ||
+          filterValue.includes(s)
+        )
+      })
   )
 })
 const assessorWorkload = ref<any[]>([])
@@ -1101,11 +1101,15 @@ const loadAllData = async () => {
       nurseLevel: e.nurseLevelName,
       assessor: e.assessor,
       risks: (() => {
+        // 直接把原始数据里的「简易精神状态」替换为「防误食」,再做拆分
+        // 风险项之间可能是英文逗号 / 中文逗号 / 顿号 / 空白,统一拆分
         const raw = e.highRiskItems
-        const arr = Array.isArray(raw)
-          ? raw.map((s: any) => normalizeRiskName(String(s).trim()))
-          : String(raw || '').split(',').map((s: string) => normalizeRiskName(s.trim()))
-        return arr.filter(Boolean)
+        const str = Array.isArray(raw) ? raw.join(',') : String(raw || '')
+        return str
+          .replace(/简易精神状态/g, '防误食')
+          .split(/[,,、\s]+/)
+          .map((s: string) => s.trim())
+          .filter(Boolean)
       })(),
       highCount: e.highRiskCount ?? 0,
       assessDate: formatAssessDate(e.assessDate)
@@ -1125,7 +1129,6 @@ const handleFilterChange = () => {
   loadAllData()
 }
 const handleReset = () => {
-  filter.month = ''
   filter.buildId = ''
   filter.floorId = ''
   floorList.value = []
@@ -1150,8 +1153,12 @@ const formatAssessDate = (v: any): string => {
   return String(v)
 }
 // 后端把「防误食」命名为「简易精神状态」,前端统一做临时映射
-const normalizeRiskName = (name: string): string =>
-  name === '简易精神状态' ? '防误食' : name
+const normalizeRiskName = (name: string): string => {
+  const s = String(name || '').trim()
+  if (!s) return s
+  if (s === '简易精神状态' || s.includes('简易精神状态')) return '防误食'
+  return s
+}
 const riskTagColor = (name: string): string => {
   const map: Record<string, string> = {
     噎食: '#ff9966',
@@ -1169,8 +1176,6 @@ const riskTagColor = (name: string): string => {
 
 // ========================= 生命周期 =========================
 onMounted(async () => {
-  const months = await echartsApi.getMonthList()
-  monthOptions.value = months
   // 楼栋使用真实接口
   try {
     const tenantIds = userStore.orgTenantId

+ 165 - 13
src/views/elderly/contracts/ContractManageForm.vue

@@ -1,6 +1,8 @@
 <script setup lang="ts">
 import { reactive, ref, computed, nextTick } from 'vue'
+import { ElMessageBox } from 'element-plus'
 import ContractBody from './components/ContractBody.vue'
+import ContractBodyHubei from './components/ContractBodyHubei.vue'
 import AttachmentPage from './components/AttachmentPage.vue'
 import AttachmentSelector from './components/AttachmentSelector.vue'
 import RiskDisclosureBody from './components/RiskDisclosureBody.vue'
@@ -35,6 +37,7 @@ import {
   firstServiceProjectConfirmation_getById,
   changeConfirmationForm_getById
 } from '@/api/elderly/contracts'
+import { getBusinessParamsConfig } from '@/api/elderly/fee'
 
 const attachmentDetailMap: Record<string, (id: number | string) => Promise<any>> = {
   attach_1: riskDisclosure_getById,
@@ -60,6 +63,67 @@ const message = useMessage()
 const visible = ref(false)
 const formLoading = ref(false)
 
+// 合同类型:默认广州地区合同;保存到 contractInfo 后,下次打开据此渲染对应合同组件
+const contractType = ref('广州地区合同')
+// 从综合设置读取的默认合同区域
+const defaultContractType = ref('广州地区合同')
+const contractTypeOptions = [
+  { label: '广州地区合同', value: '广州地区合同' },
+  { label: '湖北地区合同', value: '湖北地区合同' },
+
+]
+// 初次加载时由子组件回传的合同类型(已保存的类型)
+const savedContractType = ref('广州地区合同')
+// 当前合同是否已存在(已有保存记录,二次修改需确认)
+const hasSavedContract = ref(false)
+// 是否已根据详情回传解析出合同类型:防止手动切换导致的子组件重挂载回传覆盖用户选择
+const contractTypeResolved = ref(false)
+
+// 子组件初次加载回传合同类型时,仅首次生效(解析保存的类型);其余回传忽略,避免回弹
+const handleContractTypeEmit = (val: string) => {
+  if (!contractTypeResolved.value) {
+    contractType.value = val
+    savedContractType.value = val
+    contractTypeResolved.value = true
+  }
+}
+
+// 子组件回传当前合同是否已存在
+const handleContractExists = (exists: boolean) => {
+  hasSavedContract.value = exists
+}
+
+// 用户手动切换合同类型:若已存在保存记录,需二次确认;取消则回退
+const handleContractTypeChange = async () => {
+  if (!hasSavedContract.value) return
+  if (contractType.value === savedContractType.value) return
+  try {
+    await ElMessageBox.confirm(
+      `当前合同已保存为「${savedContractType.value}」,确定要修改为「${contractType.value}」吗?修改后需要点击‘保存’才会生效。`,
+      '修改合同类型',
+      { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
+    )
+    // 确认:以新选择为准
+    savedContractType.value = contractType.value
+  } catch {
+    // 取消:回退到已保存类型
+    contractType.value = savedContractType.value
+  }
+}
+
+// 加载综合设置中的合同区域配置
+const loadContractTypeConfig = async () => {
+  try {
+    const res = await getBusinessParamsConfig()
+    const config = (res || []).find((item: any) => item.configName === '合同区域设置')
+    if (config && config.value2) {
+      defaultContractType.value = config.value2
+    }
+  } catch (e) {
+    console.error('加载合同区域配置失败', e)
+  }
+}
+
 const isTextMode = ref(false)
 const isPrint = ref(false)
 const contractBodyRef = ref<any>(null)
@@ -397,12 +461,19 @@ const selectorVisible = ref<{
 })
 
 const type_c = ref(1)
-const open = (row?: any, type = 1) => {
+const open = async (row?: any, type = 1) => {
   recordRow.value = row || null
   type_c.value = type
   isTextMode.value = type_c.value != 1
   formLoading.value = true
   isPrint.value = false
+  // 先加载综合设置中的默认合同区域
+  await loadContractTypeConfig()
+  // 每次打开重置合同类型状态,实际类型由详情加载后子组件回传解析
+  contractType.value = defaultContractType.value
+  savedContractType.value = defaultContractType.value
+  hasSavedContract.value = false
+  contractTypeResolved.value = false
   attachmentList.forEach((it) => {
     // 固定内容附件(3=入住须知)默认展示,不需要从列表选择
     if (it.no === 3) {
@@ -629,19 +700,58 @@ const renderAttachmentContent = (key: string) => {
 
       <div class="content-body">
         <!-- ============ 合同主体 ============ -->
-        <div class="section-divider">
-          <span>合同主体</span>
+        <div class="section-divider contract-type-bar">
+          <span class="bar-title">合同主体</span>
+          <div class="bar-action">
+            <span
+                class="bar-label"
+                style="color: #000000;background-color: #fff;border-radius: 4px;padding: 7px 12px;font-size: 12px;font-weight: bold;">合同类型:</span>
+            <el-select
+              v-model="contractType"
+              size="default"
+              style="width: 160px"
+              @change="handleContractTypeChange"
+            >
+              <el-option
+                v-for="opt in contractTypeOptions"
+                :key="opt.value"
+                :label="opt.label"
+                :value="opt.value"
+              />
+            </el-select>
+          </div>
         </div>
         <ContractBody
+          v-if="contractType !== '湖北地区合同'"
           ref="contractBodyRef"
           :record-row="recordRow"
           :is-text-mode="isTextMode"
           v-model="contractSignatureData"
           :attachment-ids="attachments"
           :visible="visible"
+          :contract-type="contractType"
+          :lock-contract-type="contractTypeResolved"
           @update:form-data="handFormData"
           @update:data="handleContractDataChange"
           @update:attachments="handleAttachmentsLoad"
+          @update:contract-type="handleContractTypeEmit"
+          @update:contract-exists="handleContractExists"
+        />
+        <ContractBodyHubei
+          v-else
+          ref="contractBodyRef"
+          :record-row="recordRow"
+          :is-text-mode="isTextMode"
+          v-model="contractSignatureData"
+          :attachment-ids="attachments"
+          :visible="visible"
+          :contract-type="contractType"
+          :lock-contract-type="contractTypeResolved"
+          @update:form-data="handFormData"
+          @update:data="handleContractDataChange"
+          @update:attachments="handleAttachmentsLoad"
+          @update:contract-type="handleContractTypeEmit"
+          @update:contract-exists="handleContractExists"
         />
 
         <!-- ============ 16个附件 ============ -->
@@ -767,15 +877,28 @@ const renderAttachmentContent = (key: string) => {
 
   <!-- ========== 打印容器:Teleport 到 body,确保是 body 直接子元素 ========== -->
   <Teleport to="body">
-    <div v-if="isPrint" class="print-container">
-      <!-- 合同主体 -->
-      <ContractBody
-        :record-row="recordRow"
-        :is-text-mode="true"
-        v-model="contractSignatureData"
-        :attachment-ids="attachments"
-        :visible="true"
-      />
+      <div v-if="isPrint" class="print-container">
+        <!-- 合同主体 -->
+        <ContractBody
+          v-if="contractType !== '湖北地区合同'"
+          :record-row="recordRow"
+          :is-text-mode="true"
+          v-model="contractSignatureData"
+          :attachment-ids="attachments"
+          :visible="true"
+          :contract-type="contractType"
+          :lock-contract-type="contractTypeResolved"
+        />
+        <ContractBodyHubei
+          v-else
+          :record-row="recordRow"
+          :is-text-mode="true"
+          v-model="contractSignatureData"
+          :attachment-ids="attachments"
+          :visible="true"
+          :contract-type="contractType"
+          :lock-contract-type="contractTypeResolved"
+        />
 
       <!-- 已选的附件 -->
       <template v-if="selectedAttachments.length > 0">
@@ -1061,7 +1184,6 @@ const renderAttachmentContent = (key: string) => {
   font-size: 15px;
   font-weight: bold;
   color: #666;
-  border-top: 1px dashed #ccc;
   position: relative;
 }
 
@@ -1073,6 +1195,36 @@ const renderAttachmentContent = (key: string) => {
   border: 1px solid #e4e7ed;
 }
 
+/* 合同主体栏:左侧标题、右侧合同类型下拉 */
+.section-divider.contract-type-bar {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  text-align: left;
+}
+
+.section-divider.contract-type-bar .bar-title {
+  font-size: 15px;
+  font-weight: bold;
+  color: #666;
+}
+
+.section-divider.contract-type-bar .bar-action {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  font-size: 13px;
+  font-weight: normal;
+  color: #555;
+}
+
+.section-divider.contract-type-bar .bar-label {
+  display: inline;
+  padding: 0;
+  background: none;
+  border: none;
+}
+
 .content-body {
   flex: 1;
   overflow-y: auto;

+ 29 - 1
src/views/elderly/contracts/components/ContractBody.vue

@@ -73,6 +73,9 @@ const props = defineProps<{
   modelValue?: any
   attachmentIds?: Record<string, any>
   visible?: boolean
+  contractType?: string
+  // 手动切换合同类型后,form.contractType 以父组件当前选择为准;初次加载时用存储的类型
+  lockContractType?: boolean
 }>()
 
 const emit = defineEmits<{
@@ -80,6 +83,8 @@ const emit = defineEmits<{
   (e: 'update:modelValue', val: any): void
   (e: 'update:attachments', val: any): void
   (e: 'update:formData', val: any): void
+  (e: 'update:contractType', val: string): void
+  (e: 'update:contractExists', val: boolean): void
 }>()
 
 const loading = ref(false)
@@ -91,6 +96,9 @@ const elderId = computed(() => {
 })
 
 const contractForm = reactive({
+  // 合同类型:广州地区合同 / 湖北地区合同 / 天河老人院合同(保存到 contractInfo 中,下次打开据此渲染对应合同组件)
+  // 默认从父组件传入的合同区域配置读取,未传入时兜底广州
+  contractType: props.contractType || '广州地区合同',
   contractNumber: '',
   elderName: '',
   elderGenderText: '',
@@ -190,6 +198,15 @@ const contractForm = reactive({
   stageExpenses: [] as any[]
 })
 
+// 父组件下拉切换合同类型时,同步到本地表单(保存时会写入 contractInfo)
+watch(
+  () => props.contractType,
+  (val) => {
+    if (val) contractForm.contractType = val
+  },
+  { immediate: true }
+)
+
 const parseIdCardBirth = (idCard: string): string => {
   if (!idCard) return ''
   const len = idCard.length
@@ -541,6 +558,17 @@ const fetchContractData = async (row: any) => {
         }
       }
     }
+    // 手动切换合同类型后(父组件已解析完成),以父组件当前选择为准,避免沿用旧合同类型
+    if (props.lockContractType && props.contractType) {
+      contractForm.contractType = props.contractType
+    }
+    // 回传合同是否已存在(已有保存记录,父组件据此决定是否二次确认)
+    emit(
+      'update:contractExists',
+      !!(contractFormUpdate.value && contractFormUpdate.value.contractInfo)
+    )
+    // 回传合同类型给父组件,父组件据此切换渲染对应合同组件(广州/湖北/天河)
+    emit('update:contractType', contractForm.contractType || '广州地区合同')
     console.log('接口获取到的合同详情:', contractFormUpdate.value)
   } catch (e) {
     console.log(e)
@@ -780,7 +808,7 @@ const saveContract = async () => {
 
         if (row) {
           try {
-            const data = JSON.parse(row)
+            const data = typeof row === 'string' ? JSON.parse(row) : row
 
             if (data.id) {
               contractForm.attachments[key] = { id: data.id }

+ 2605 - 0
src/views/elderly/contracts/components/ContractBodyHubei.vue

@@ -0,0 +1,2605 @@
+<script setup lang="ts">
+import { reactive, computed, ref, watch, onMounted } from 'vue'
+import { formatBackendDateTime } from '@/utils/formatTime'
+import { DICT_TYPE, getDictLabel } from '@/utils/dict'
+import { getTenantId } from '@/utils/auth'
+import { getCheckInDetailByContractId } 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'
+import { getElderlyContractById } from '@/api/elderly/elder/contract'
+import { updateContractDate } from '@/api/elderly/fee/leave-settle'
+import {
+  riskDisclosure_getById,
+  checkInRegistration_getById,
+  elderSafetyCommitment_getById,
+  outingConfirmation_getById,
+  signatureProxyApplication_getById,
+  powerOfAttorney_getById,
+  delegationAgentConfirmation_getById,
+  serviceChargingStandards_getById,
+  roomFacilitiesEquipment_getById,
+  explanationExaminationReport_getById,
+  partyBIdentificationDocument_getById,
+  guardianPartyB_getById,
+  registrationCertificateCivilAffairs_getById,
+  comprehensiveAssessmentCapabilities_getById,
+  firstServiceProjectConfirmation_getById,
+  changeConfirmationForm_getById
+} from '@/api/elderly/contracts'
+const userStore = useUserStore()
+
+const attachmentConfig: Record<
+  string,
+  { idField: string; getDetail: (id: number | string) => Promise<any> }
+> = {
+  attach_1: { idField: 'riskDisclosureId', getDetail: riskDisclosure_getById },
+  attach_2: { idField: 'checkInTabId', getDetail: checkInRegistration_getById },
+  attach_4: { idField: 'safetyCommitmentId', getDetail: elderSafetyCommitment_getById },
+  attach_5: { idField: 'outingConfirmationFormId', getDetail: outingConfirmation_getById },
+  attach_6: {
+    idField: 'signatureProxyApplicationId',
+    getDetail: signatureProxyApplication_getById
+  },
+  attach_7: { idField: 'powerOfAttorneyId', getDetail: powerOfAttorney_getById },
+  attach_8: {
+    idField: 'authorizedAgentConfirmationId',
+    getDetail: delegationAgentConfirmation_getById
+  },
+  attach_9: { idField: 'orgServiceScopeFeeId', getDetail: serviceChargingStandards_getById },
+  attach_10: { idField: 'roomFacilityListId', getDetail: roomFacilitiesEquipment_getById },
+  attach_11: { idField: 'physicalExamReportId', getDetail: explanationExaminationReport_getById },
+  attach_12: { idField: 'partyBCertificateId', getDetail: partyBIdentificationDocument_getById },
+  attach_13: { idField: 'partyBGuardianCertificateId', getDetail: guardianPartyB_getById },
+  attach_14: {
+    idField: 'partyACertificateId',
+    getDetail: registrationCertificateCivilAffairs_getById
+  },
+  attach_15: {
+    idField: 'elderlyAbilityEvaluationId',
+    getDetail: comprehensiveAssessmentCapabilities_getById
+  },
+  attach_16: {
+    idField: 'firstServiceConfirmationId',
+    getDetail: firstServiceProjectConfirmation_getById
+  },
+  attach_17: { idField: 'changeConfirmationId', getDetail: changeConfirmationForm_getById }
+}
+const props = defineProps<{
+  recordRow?: any
+  isTextMode?: boolean
+  signatureData?: any
+  modelValue?: any
+  attachmentIds?: Record<string, any>
+  visible?: boolean
+  contractType?: string
+  // 手动切换合同类型后,form.contractType 以父组件当前选择为准;初次加载时用存储的类型
+  lockContractType?: boolean
+}>()
+
+const emit = defineEmits<{
+  (e: 'update:data', val: any): void
+  (e: 'update:modelValue', val: any): void
+  (e: 'update:attachments', val: any): void
+  (e: 'update:formData', val: any): void
+  (e: 'update:contractType', val: string): void
+  (e: 'update:contractExists', val: boolean): void
+}>()
+
+const loading = ref(false)
+const detailData = ref<any>(null)
+
+const elderId = computed(() => {
+  if (!props.recordRow) return ''
+  return props.recordRow.elderId || props.recordRow.id || ''
+})
+
+const contractForm = reactive({
+  // 合同类型:广州地区合同 / 湖北地区合同 / 天河老人院合同(保存到 contractInfo 中,下次打开据此渲染对应合同组件)
+  // 默认从父组件传入的合同区域配置读取,未传入时兜底广州
+  contractType: props.contractType || '广州地区合同',
+  contractNumber: '',
+  elderName: '',
+  elderGenderText: '',
+  elderBirth: '',
+  elderPapersType: '',
+  elderIdCard: '',
+  elderAge: '',
+  elderAddress: '',
+  elderZip: '',
+  partyAName: '颐年健康产业(集团)有限公司',
+  partyACode: '',
+  partyAAddr: '',
+  partyAZip: '',
+  partyALegal: '',
+  partyAPhone: '',
+  partyCName: '',
+  partyCGenderText: '',
+  partyCBirth: '',
+  partyCPapersType: '',
+  partyCRelation: '',
+  partyCIdCard: '',
+  partyCPhone: '',
+  partyCAddress: '',
+  partyCHomeAddr: '',
+  partyCZip: '',
+  partyCWorkUnit: '',
+  partyCCommAddr: '',
+  nurseLevelName: '',
+  contractMonths: '',
+  startDate: '',
+  endDate: '',
+  servicePlace: userStore.getTenantName || '',
+  bedFee: '',
+  nurseFee: '',
+  mealFee: '',
+  manageFee: '',
+  totalFee: '',
+  // 费用相关扩展字段
+  roomType: '',
+  roomNo: '',
+  freeElectric: '',
+  freeWater: '',
+  hotWaterFee: '',
+  coldWaterFee: '',
+  electricFee: '',
+  diagnosisFee: '',
+  oneTimeEquipFee: '',
+  oneTimeEquipStart: '',
+  oneTimeEquipEnd: '',
+  depositFee: '',
+  depositType: '',
+  depositInterest: '',
+  depositInterestType: '0',
+  payMode: '1',
+  payMonthDay: '5',
+  paySeasonMonth: '1',
+  paySeasonDay: '5',
+  partyAAccountName: '',
+  partyABank: '',
+  partyAAccount: '',
+  partyCAccountName: '',
+  partyCBank: '',
+  partyCAccount: '',
+  depositRefund: '',
+  otherPayMode: '',
+  otherPayMode2: '',
+  // 合同续签/变更/解除
+  renewNoticeDays: '30',
+  moveOutDays: '3',
+  changeConfirmDays: '7',
+  priceAdjustNoticeDays: '30',
+  priceThreshold: '6',
+  priceObjDays: '15',
+  priceConfirmDays: '15',
+  leaveDays: '60',
+  depositAmt: '',
+  depositAmtCn: '',
+  depositAmt1: '',
+  depositAmtCn1: '',
+  depositAmt2: '',
+  depositAmtCn2: '',
+  disputeMode: '2',
+  copyCount: '叁',
+  partyACopy: '壹',
+  partyBCopy: '壹',
+  partyCCopy: '壹',
+  partyASign: '',
+  partyALegalSign: '',
+  partyADate: '',
+  partyBSign: '',
+  partyBDate: '',
+  partyCSign: '',
+  partyCDate: '',
+  // 费用明细列表
+  monthlyExpenses: [] as any[],
+  oneTimeExpenses: [] as any[],
+  stageExpenses: [] as any[]
+})
+
+// 父组件下拉切换合同类型时,同步到本地表单(保存时会写入 contractInfo)
+watch(
+  () => props.contractType,
+  (val) => {
+    if (val) contractForm.contractType = val
+  },
+  { immediate: true }
+)
+
+const parseIdCardBirth = (idCard: string): string => {
+  if (!idCard) return ''
+  const len = idCard.length
+  if (len === 18) {
+    return `${idCard.substring(6, 10)}年${idCard.substring(10, 12)}月${idCard.substring(12, 14)}日`
+  }
+  if (len === 15) {
+    return `19${idCard.substring(6, 8)}年${idCard.substring(8, 10)}月${idCard.substring(10, 12)}日`
+  }
+  return ''
+}
+
+const parseChineseDate = (dateStr: string): Date | null => {
+  if (!dateStr) return null
+  const match = dateStr.match(/^(\d{4})年(\d{2})月(\d{2})日$/)
+  if (!match) return null
+  const year = Number(match[1])
+  const month = Number(match[2]) - 1
+  const day = Number(match[3])
+  return new Date(year, month, day)
+}
+
+const calcMonthsBetween = (startStr: string, endStr: string): number | null => {
+  const start = parseChineseDate(startStr)
+  const end = parseChineseDate(endStr)
+  if (!start || !end || end < start) return null
+  // 直接按"年月差"计算整月数,末尾差几天不影响(如 2026-08-15 → 2028-08-14 = 24 个月)
+  return (end.getFullYear() - start.getFullYear()) * 12 + (end.getMonth() - start.getMonth())
+}
+
+const isIdCardType = (papersType: any): boolean => {
+  const label = getDictLabel(DICT_TYPE.PAPERS_TYPE, papersType)
+  return !!label && (label.includes('身份证') || label.includes('居民身份'))
+}
+
+const numToChinese = (num: number | string): string => {
+  const n = Number(num)
+  if (isNaN(n) || n < 0) return ''
+  if (n === 0) return '零元整'
+  const fractions = ['角', '分']
+  const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
+  const radices = ['', '拾', '佰', '仟']
+  const bigRadices = ['', '万', '亿']
+  const dStr = n.toFixed(2)
+  const parts = dStr.split('.')
+  let intPart = parts[0]
+  let decPart = parts[1]
+  let chinese = ''
+  let zeroFlag = false
+  for (let i = 0; i < intPart.length; i++) {
+    const ch = intPart.charAt(i)
+    const numDigit = parseInt(ch)
+    const pos = intPart.length - i - 1
+    const radixIdx = pos % 4
+    const bigRadixIdx = Math.floor(pos / 4)
+    if (numDigit === 0) {
+      zeroFlag = true
+    } else {
+      if (zeroFlag) {
+        chinese += '零'
+        zeroFlag = false
+      }
+      chinese += digit[numDigit] + radices[radixIdx]
+    }
+    if (radixIdx === 0 && numDigit !== 0) {
+      chinese += bigRadices[bigRadixIdx]
+    } else if (radixIdx === 0 && intPart.length > 4) {
+      const segStart = Math.max(0, intPart.length - (bigRadixIdx + 1) * 4)
+      const seg = intPart.substring(segStart, intPart.length - bigRadixIdx * 4)
+      if (parseInt(seg) > 0) {
+        chinese += bigRadices[bigRadixIdx]
+      }
+    }
+  }
+  chinese = chinese.replace(/零+/g, '零').replace(/零$/, '')
+  chinese += '元'
+  if (decPart === '00') {
+    chinese += '整'
+  } else {
+    const jiao = parseInt(decPart.charAt(0))
+    const fen = parseInt(decPart.charAt(1))
+    if (jiao > 0) chinese += digit[jiao] + fractions[0]
+    if (fen > 0) chinese += digit[fen] + fractions[1]
+    if (jiao === 0 && fen > 0) {
+      // 零元几分的情况
+    }
+  }
+  return chinese
+}
+
+const fillContractForm = (data: any) => {
+  if (!data) return
+  detailData.value = data
+  const contract = data.elderlyContractDO || {}
+
+  contractForm.contractNumber = contract.contractNumber || ''
+  contractForm.elderName = contract.elderName || data.elderName || ''
+
+  if (data.elderSex) {
+    contractForm.elderGenderText = Number(data.elderSex) === 1 ? '男' : '女'
+  }
+
+  if (data.idCard) {
+    contractForm.elderIdCard = data.idCard
+  }
+  if (data.papersType != null && data.papersType !== '' && data.papersType !== undefined) {
+    const papersNum = Number(data.papersType)
+    contractForm.elderPapersType = Number.isNaN(papersNum) ? data.papersType : papersNum
+  }
+  if (data.idCard && isIdCardType(contractForm.elderPapersType)) {
+    contractForm.elderBirth = parseIdCardBirth(data.idCard)
+  }
+
+  contractForm.elderAge = data.elderAge || ''
+  contractForm.elderAddress = data.elderAddress || ''
+  contractForm.elderZip = data.elderZip || ''
+
+  contractForm.nurseLevelName = data.nurseLevelName || ''
+
+  if (data.checkInTime) {
+    contractForm.startDate = formatBackendDateTime(data.checkInTime, 'YYYY年MM月DD日')
+  }
+  if (data.checkInDeadlineTime) {
+    contractForm.endDate = formatBackendDateTime(data.checkInDeadlineTime, 'YYYY年MM月DD日')
+  }
+
+  if (contract.beginTime) {
+    contractForm.startDate = formatBackendDateTime(contract.beginTime, 'YYYY年MM月DD日')
+  }
+  if (contract.expireTime) {
+    contractForm.endDate = formatBackendDateTime(contract.expireTime, 'YYYY年MM月DD日')
+  }
+
+  const monthly = data.monthlyExpenses || []
+  const findItem = (list: any[], key: string): any => {
+    return list.find(
+      (x: any) => (x.itemName || '').includes(key) || (x.itemCategoryName || '').includes(key)
+    )
+  }
+  const findAmt = (list: any[], key: string): string => {
+    const item = findItem(list, key)
+    return item ? String(item.actualAmount || item.amount || '') : ''
+  }
+  contractForm.bedFee = findAmt(monthly, '床位') || ''
+  contractForm.nurseFee = findAmt(monthly, '护理') || ''
+  contractForm.mealFee = findAmt(monthly, '膳食') || ''
+  contractForm.manageFee = findAmt(monthly, '服务') || ''
+
+  const total = monthly.reduce(
+    (sum: number, it: any) => sum + (Number(it.actualAmount) || Number(it.amount) || 0),
+    0
+  )
+  contractForm.totalFee = total > 0 ? String(total) : ''
+
+  const bedItem = findItem(monthly, '床位')
+  if (bedItem && bedItem.itemName) {
+    const m = bedItem.itemName.match(/^(.+?)\(/)
+    contractForm.roomType = m ? m[1] : bedItem.itemName
+  }
+  console.log('ADDD', data)
+  if (data.bedName) {
+    contractForm.roomNo = data.bedName
+  } else if (data.bedId) {
+    contractForm.roomNo = contractFormUpdate.value.bedName
+  }
+  if (data.bedType) {
+    contractForm.roomType = data.bedType
+  }
+
+  contractForm.monthlyExpenses = data.monthlyExpenses || []
+  //contractForm.oneTimeExpenses = data.oneTimeExpenses || []
+  contractForm.stageExpenses = data.stageExpenses || []
+  //天河颐养院需要过滤掉‘一次性设施费’
+  const oneTime = data.oneTimeExpenses || []
+  const filteredOneTime = oneTime.filter((item: { itemName: string; itemCategoryName: string }) => {
+    const name = item.itemName || ''
+    const category = item.itemCategoryName || ''
+    return !name.includes('一次性设施费') && !category.includes('一次性设施费')
+  })
+  contractForm.oneTimeExpenses = filteredOneTime || []
+  //console.log('一次性:', contractForm.oneTimeExpenses)
+
+  //const deposit = findItem(oneTime, '押金')
+  const firstItem = filteredOneTime.length > 0 ? filteredOneTime[0] : undefined // 取出数组第一个元素(对象)
+  if (firstItem) {
+    const depositAmt = Number(firstItem.actualAmount || firstItem.amount || 0)
+    contractForm.depositFee = String(depositAmt)
+    contractForm.depositAmt = String(depositAmt)
+    contractForm.depositAmtCn = numToChinese(depositAmt)
+    contractForm.depositAmt1 = String(depositAmt)
+    contractForm.depositAmtCn1 = numToChinese(depositAmt)
+    contractForm.depositAmt2 = String(depositAmt)
+    contractForm.depositAmtCn2 = numToChinese(depositAmt)
+    contractForm.depositType = firstItem.itemName || ''
+  }
+
+  const relative = (data.relativesList && data.relativesList[0]) || {}
+  contractForm.partyCName = relative.name || ''
+  if (relative.gender) {
+    contractForm.partyCGenderText = Number(relative.gender) === 1 ? '男' : '女'
+  }
+  if (relative.idCard) {
+    contractForm.partyCIdCard = relative.idCard
+  }
+  if (
+    relative.papersType != null &&
+    relative.papersType !== '' &&
+    relative.papersType !== undefined
+  ) {
+    const papersNum = Number(relative.papersType)
+    contractForm.partyCPapersType = Number.isNaN(papersNum) ? relative.papersType : papersNum
+  }
+  if (relative.idCard && isIdCardType(contractForm.partyCPapersType)) {
+    contractForm.partyCBirth = parseIdCardBirth(relative.idCard)
+  }
+  contractForm.partyCRelation = relative.relation || ''
+  contractForm.partyCPhone = relative.phone || ''
+  contractForm.partyCAddress = relative.address || relative.nowAddress || ''
+  contractForm.partyCHomeAddr = relative.nowAddress || ''
+  contractForm.partyCWorkUnit = relative.workUnit || ''
+
+  // 如果外部传入了签名数据(如打印时),覆盖合同表单中的签名字段
+  // 优先使用 v-model 传入的 modelValue,其次是 signatureData
+  const externalSignData = props.modelValue || props.signatureData
+  if (externalSignData) {
+    if (externalSignData.partyASign != null && externalSignData.partyASign !== '')
+      contractForm.partyASign = externalSignData.partyASign
+    if (externalSignData.partyALegalSign != null && externalSignData.partyALegalSign !== '')
+      contractForm.partyALegalSign = externalSignData.partyALegalSign
+    if (externalSignData.partyADate != null && externalSignData.partyADate !== '')
+      contractForm.partyADate = externalSignData.partyADate
+    if (externalSignData.partyBSign != null && externalSignData.partyBSign !== '')
+      contractForm.partyBSign = externalSignData.partyBSign
+    if (externalSignData.partyBDate != null && externalSignData.partyBDate !== '')
+      contractForm.partyBDate = externalSignData.partyBDate
+    if (externalSignData.partyCSign != null && externalSignData.partyCSign !== '')
+      contractForm.partyCSign = externalSignData.partyCSign
+    if (externalSignData.partyCDate != null && externalSignData.partyCDate !== '')
+      contractForm.partyCDate = externalSignData.partyCDate
+  }
+
+  emit('update:data', { ...contractForm })
+}
+
+const fetchContractData = async (row: any) => {
+  if (!row) return
+  // 切换人员/重新打开抽屉时,先清空上一个人的附件缓存,避免残留到当前合同
+  contractForm.attachments = {}
+  // // 如果已经有完整数据(如直接返回了elderlyContractDO),直接填充
+  // if (row.elderlyContractDO) {
+  //   console.log('有历史完整数据,直接填充')
+  //   fillContractForm(row)
+  //   return
+  // }
+  // console.log('合同id', row)
+  // // 否则调用接口获取
+  // const recordId = row.id
+  // if (!recordId) {
+  //   console.log('没有id,使用历史数据填充?')
+  //   fillContractForm(row)
+  //   return
+  // }
+  loading.value = true
+  try {
+    const res = await getElderlyContractById(props.recordRow.id)
+    //console.log('合同信息接口:', res)
+    //console.log('合同信息接口:', JSON.parse(res.contractInfo))
+    if (res) {
+      contractFormUpdate.value = res
+      // console.log('接口获取合同信息:', contractFormUpdate.value.contractInfo)
+      contractFormUpdate.value.id = props.recordRow.id
+      if (contractFormUpdate.value.contractInfo) {
+        try {
+          const parsedData = JSON.parse(contractFormUpdate.value.contractInfo)
+          //天河颐养院需要过滤掉‘一次性设施费’
+          const oneTime = parsedData.oneTimeExpenses || []
+          const filteredOneTime = oneTime.filter(
+            (item: { itemName: string; itemCategoryName: string }) => {
+              const name = item.itemName || ''
+              const category = item.itemCategoryName || ''
+              return !name.includes('一次性设施费') && !category.includes('一次性设施费')
+            }
+          )
+          parsedData.oneTimeExpenses = filteredOneTime || []
+          // console.log('一次性的:', parsedData.oneTimeExpenses)
+
+          if (parsedData) {
+            Object.assign(contractForm, parsedData)
+          }
+        } catch (e) {
+          console.error('解析合同信息失败', e)
+        }
+        const attachmentsMap: Record<string, any> = {}
+        const detailPromises: Promise<any>[] = []
+        Object.keys(attachmentConfig).forEach((key) => {
+          const config = attachmentConfig[key]
+          //console.log('config', config, key)
+          let id = undefined
+          try {
+            id = contractForm.attachments[key].id
+          } catch (e) {}
+          //console.log('id', id)
+          if (id) {
+            detailPromises.push(
+              config
+                .getDetail(id)
+                .then((detail) => {
+                  //console.log('获取详情', detail)
+                  attachmentsMap[key] = JSON.parse(detail.content)
+                })
+                .catch((err) => {
+                  console.error(`获取附件详情失败: ${key}`, err)
+                  attachmentsMap[key] = { id }
+                })
+            )
+          } else {
+            attachmentsMap[key] = null
+          }
+        })
+        if (detailPromises.length > 0) {
+          await Promise.all(detailPromises)
+        }
+
+        emit('update:attachments', attachmentsMap)
+        loading.value = false
+      } else {
+        console.log('保存')
+        try {
+          const checkInRes = await getCheckInDetailByContractId(row.id)
+          if (checkInRes) {
+            if (checkInRes) {
+            }
+            fillContractForm(checkInRes)
+          }
+          contractForm.roomNo = contractFormUpdate.value.bedName
+
+          try {
+            contractFormUpdate.value.contractInfo = JSON.stringify({ ...contractForm })
+            const saveRes = await updateContractDate(contractFormUpdate.value)
+            if (saveRes) {
+            }
+          } catch (error) {
+            console.log(error)
+          }
+        } catch (e) {
+          console.error('获取合同详情失败', e)
+        } finally {
+          loading.value = false
+        }
+      }
+    }
+    // 手动切换合同类型后(父组件已解析完成),以父组件当前选择为准,避免沿用旧合同类型
+    if (props.lockContractType && props.contractType) {
+      contractForm.contractType = props.contractType
+    }
+    // 回传合同是否已存在(已有保存记录,父组件据此决定是否二次确认)
+    emit(
+      'update:contractExists',
+      !!(contractFormUpdate.value && contractFormUpdate.value.contractInfo)
+    )
+    // 回传合同类型给父组件,父组件据此切换渲染对应合同组件(广州/湖北/天河)
+    emit('update:contractType', contractForm.contractType || '广州地区合同')
+    console.log('接口获取到的合同详情:', contractFormUpdate.value)
+  } catch (e) {
+    console.log(e)
+  }
+}
+
+// 用于避免抽屉关闭/打开相同数据时重复请求,同时在重新打开时强制刷新
+let lastFetchedKey: string | number | undefined
+
+const tryFetchContractData = () => {
+  const row = props.recordRow
+  if (!row || !props.visible) return
+  const key = row.id ?? row.elderId
+  if (key === lastFetchedKey) return
+  lastFetchedKey = key
+  fetchContractData(row)
+}
+
+watch(() => props.recordRow, tryFetchContractData, { immediate: true })
+watch(
+  () => props.visible,
+  (val) => {
+    if (!val) {
+      // 抽屉关闭后重置标记,下次打开同一条数据会重新请求接口
+      lastFetchedKey = undefined
+    } else {
+      tryFetchContractData()
+    }
+  }
+)
+
+watch(
+  () => props.signatureData,
+  (val) => {
+    if (!val) return
+    if (val.partyASign) contractForm.partyASign = val.partyASign
+    if (val.partyALegalSign) contractForm.partyALegalSign = val.partyALegalSign
+    if (val.partyADate) contractForm.partyADate = val.partyADate
+    if (val.partyBSign) contractForm.partyBSign = val.partyBSign
+    if (val.partyBDate) contractForm.partyBDate = val.partyBDate
+    if (val.partyCSign) contractForm.partyCSign = val.partyCSign
+    if (val.partyCDate) contractForm.partyCDate = val.partyCDate
+  },
+  { deep: true }
+)
+
+watch(
+  () => contractForm.depositAmt1,
+  (val) => {
+    const n = Number(val)
+    if (!isNaN(n) && n >= 0) {
+      contractForm.depositAmtCn1 = numToChinese(n)
+    }
+  }
+)
+
+watch(
+  () => contractForm.depositAmt2,
+  (val) => {
+    const n = Number(val)
+    if (!isNaN(n) && n >= 0) {
+      contractForm.depositAmtCn2 = numToChinese(n)
+    }
+  }
+)
+
+// 外部 modelValue 变化时,同步签名和日期字段到 contractForm
+watch(
+  () => props.modelValue,
+  (val) => {
+    if (!val) return
+    if (val.partyASign != null && val.partyASign !== '') contractForm.partyASign = val.partyASign
+    if (val.partyALegalSign != null && val.partyALegalSign !== '')
+      contractForm.partyALegalSign = val.partyALegalSign
+    if (val.partyADate != null && val.partyADate !== '') contractForm.partyADate = val.partyADate
+    if (val.partyBSign != null && val.partyBSign !== '') contractForm.partyBSign = val.partyBSign
+    if (val.partyBDate != null && val.partyBDate !== '') contractForm.partyBDate = val.partyBDate
+    if (val.partyCSign != null && val.partyCSign !== '') contractForm.partyCSign = val.partyCSign
+    if (val.partyCDate != null && val.partyCDate !== '') contractForm.partyCDate = val.partyCDate
+  },
+  { immediate: true, deep: true }
+)
+
+// 签名或日期变化时,同步给父组件(用于打印时共享签名数据)
+watch(
+  () => [
+    contractForm.partyASign,
+    contractForm.partyALegalSign,
+    contractForm.partyADate,
+    contractForm.partyBSign,
+    contractForm.partyBDate,
+    contractForm.partyCSign,
+    contractForm.partyCDate
+  ],
+  () => {
+    emit('update:data', { ...contractForm })
+    emit('update:modelValue', {
+      partyASign: contractForm.partyASign,
+      partyALegalSign: contractForm.partyALegalSign,
+      partyADate: contractForm.partyADate,
+      partyBSign: contractForm.partyBSign,
+      partyBDate: contractForm.partyBDate,
+      partyCSign: contractForm.partyCSign,
+      partyCDate: contractForm.partyCDate
+    })
+  }
+)
+
+const displayDate = computed(() => {
+  const today = new Date()
+  return `${today.getFullYear()}年${today.getMonth() + 1}月${today.getDate()}日`
+})
+
+// 费用相关动态列表
+const monthlyExpensesList = computed(() => contractForm.monthlyExpenses || [])
+const oneTimeExpensesList = computed(() => contractForm.oneTimeExpenses || [])
+const stageExpensesList = computed(() => contractForm.stageExpenses || [])
+
+const formatExpenseAmount = (val: any): string => {
+  if (val == null || val === '') return ''
+  return String(val)
+}
+
+const isDepositFee = (item: any): boolean => {
+  return (
+    item.isDeposit === 1 ||
+    (item.itemCategoryName || '').includes('押金') ||
+    (item.itemName || '').includes('押金')
+  )
+}
+
+const numberToCircle = (num: number): string => {
+  const circles = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩']
+  return circles[num - 1] || `${num}`
+}
+
+// 费用项显示名称:类别名(项目名)
+const displayExpenseName = (item: any): string => {
+  const category = item?.itemCategoryName || ''
+  const name = item?.itemName || ''
+  if (category && name && category !== name) {
+    return `${category}(${name})`
+  }
+  return category || name || ''
+}
+
+const bedList = ref<{ chargeName: string; id: string; price: number }[]>([])
+
+const loadBedTypes = async () => {
+  try {
+    const tenantId = getTenantId()
+    const res = await getOverheadListByType(1, tenantId)
+    bedList.value = res || []
+  } catch (e) {
+    bedList.value = []
+  }
+}
+
+const roomTypeOptions = computed(() => {
+  return bedList.value.map((item) => ({ label: item.chargeName, value: item.chargeName }))
+})
+
+const isAttachmentSelected = (no: number) => !!props.attachmentIds?.[`attach_${no}`]
+
+const attachmentTitleMap: Record<number, { title: string; subTitle?: string }> = {
+  1: { title: '《知情同意书》' },
+  2: { title: '《入住登记表》' },
+  3: { title: '《入住须知》' },
+  4: { title: '《长者安全承诺书》' },
+  5: { title: '《长者外出情况确认书》' },
+  6: { title: '《签名代理申请》' },
+  7: { title: '《授权委托书》' },
+  8: { title: '《委托代理人确认表》' },
+  9: { title: '《机构服务范围及收费标准》' },
+  10: { title: '《房间设施设备清单》' },
+  11: {
+    title: '二级甲等以上医院出具的《体检报告项目说明》',
+    subTitle: '(体检时间应在签订服务合同前30日以内)'
+  },
+  12: { title: '乙方有效证件(身份证、户口本)复印件' },
+  13: { title: '乙方监护人(丙方)身份证、户口本复印件' },
+  14: { title: '甲方登记证书及民政部门备案回执' },
+  15: { title: '老年人能力综合评估结果' },
+  16: { title: '首次服务项目确认表' },
+  17: { title: '变更事项确认表' }
+}
+
+const toChineseNumber = (num: number): string => {
+  const chars = [
+    '零',
+    '一',
+    '二',
+    '三',
+    '四',
+    '五',
+    '六',
+    '七',
+    '八',
+    '九',
+    '十',
+    '十一',
+    '十二',
+    '十三',
+    '十四',
+    '十五',
+    '十六',
+    '十七'
+  ]
+  return chars[num] || String(num)
+}
+
+const selectedAttachmentItems = computed(() => {
+  const items: { no: number; title: string; subTitle?: string }[] = []
+  for (let no = 1; no <= 17; no++) {
+    if (isAttachmentSelected(no)) {
+      const config = attachmentTitleMap[no]
+      if (config) {
+        items.push({ no, ...config })
+      }
+    }
+  }
+  return items
+})
+
+const page24AttachmentItems = computed(() => selectedAttachmentItems.value.slice(0, 14))
+const page25AttachmentItems = computed(() => selectedAttachmentItems.value.slice(14))
+
+const contractFormUpdate = ref({})
+
+const saveContract = async () => {
+  try {
+    // 保存时只保留当前选中的附件,防止历史/上一个人的附件残留
+    contractForm.attachments = {}
+    if (props.attachmentIds) {
+      Object.keys(props.attachmentIds).forEach((key) => {
+        const row = props.attachmentIds![key]
+
+        if (row) {
+          try {
+            const data = typeof row === 'string' ? JSON.parse(row) : row
+
+            if (data.id) {
+              contractForm.attachments[key] = { id: data.id }
+              const config = attachmentConfig[key]
+
+              contractFormUpdate.value[config.idField] = data.id
+            }
+          } catch (e) {
+            console.log(e)
+          }
+        } else {
+        }
+      })
+    }
+    contractFormUpdate.value.contractInfo = JSON.stringify({
+      ...contractForm
+      // attachments: contractForm.attachments
+    })
+    const saveRes = await updateContractDate(contractFormUpdate.value)
+    return saveRes
+  } catch (error) {
+    console.error('保存合同失败', error)
+    throw error
+  }
+}
+
+defineExpose({ saveContract })
+
+onMounted(async () => {
+  await loadBedTypes()
+})
+
+// 月度费用总额随明细自动汇总
+watch(
+  () => monthlyExpensesList.value.map((item: any) => item.actualAmount),
+  () => {
+    contractForm.totalFee = monthlyExpensesList.value
+      .reduce((sum: number, item: any) => sum + (Number(item.actualAmount) || 0), 0)
+      .toString()
+  },
+  { deep: true }
+)
+
+// 合同期限根据起止日期自动计算
+watch(
+  [() => contractForm.startDate, () => contractForm.endDate],
+  ([start, end]) => {
+    const months = calcMonthsBetween(start, end)
+    if (months !== null) {
+      contractForm.contractMonths = String(months)
+    }
+  },
+  { immediate: true }
+)
+</script>
+
+<template>
+  <div class="contract-body">
+    <!-- ========== 第1页:封面 ========== -->
+    <div class="a4-page cover-a4">
+      <div class="page-header">
+        <div class="logo-line">
+          <span class="logo-circle">颐</span>
+          <span class="logo-text">颐年医养</span>
+        </div>
+        <span class="page-no-right">-1-</span>
+      </div>
+      <div class="page-content cover-page">
+        <div class="cover-fields">
+          <p>
+            <span class="label">合同编号:</span>
+            <FieldItem
+              v-model="contractForm.contractNumber"
+              :is-text-mode="isTextMode"
+              width="180px"
+              placeholder="请输入合同编号"
+            />
+          </p>
+          <p>
+            <span class="label">长者姓名:</span>
+            <FieldItem
+              v-model="contractForm.elderName"
+              :is-text-mode="isTextMode"
+              width="180px"
+              placeholder="请输入长者姓名"
+            />
+          </p>
+        </div>
+        <h1 class="doc-title">养老机构服务合同</h1>
+        <p class="cover-issuer">
+          武汉市民政局<br />
+          武汉市市场监督管理局&nbsp;&nbsp;制定
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第2页:重要提示 ========== -->
+    <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">2</span>
+      </div>
+      <div class="page-content">
+        <h2 class="section-title">重要提示</h2>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;为了维护您的利益,请您在签署本合同(本协议)前,仔细阅读如下注意事项:
+        </p>
+        <p class="content-text">
+          一、您已阅读本合同(协议)、补充协议及相关文件的所有条款,并已知悉其含义,同时对涉及贵方权利与义务的内容给予了充分的注意。
+        </p>
+        <p class="content-text">二、您已确保提交的有关证件及资料是真实、合法、有效的。</p>
+        <p class="content-text">
+          三、您已确保向合同(协议)签署相关方所作的陈述、健康状况披露及其他信息披露均完整、充分、真实。
+        </p>
+        <p class="content-text">四、本合同(协议)所有条款均为签署方的真实意思表示。</p>
+      </div>
+    </div>
+
+    <!-- ========== 第3页:甲乙丙方信息 ========== -->
+    <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">3</span>
+      </div>
+      <div class="page-content">
+        <h3 class="subsection-title">甲方(养老机构):</h3>
+        <p class="content-text">
+          甲方运营机构:
+          <FieldItem
+            v-model="contractForm.partyAName"
+            :is-text-mode="isTextMode"
+            width="200px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          统一社会信用代码:
+          <FieldItem
+            v-model="contractForm.partyACode"
+            :is-text-mode="isTextMode"
+            width="200px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          地址:
+          <FieldItem
+            v-model="contractForm.partyAAddr"
+            :is-text-mode="isTextMode"
+            width="220px"
+            placeholder="请输入"
+          />
+          邮编:
+          <FieldItem
+            v-model="contractForm.partyAZip"
+            :is-text-mode="isTextMode"
+            width="100px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          法定代表人:
+          <FieldItem
+            v-model="contractForm.partyALegal"
+            :is-text-mode="isTextMode"
+            width="160px"
+            placeholder="请输入"
+          />
+          联系方式:
+          <FieldItem
+            v-model="contractForm.partyAPhone"
+            :is-text-mode="isTextMode"
+            width="160px"
+            placeholder="请输入"
+          />
+        </p>
+
+        <h3 class="subsection-title" style="margin-top: 16px">乙方(入住老年人)</h3>
+        <div class="content-text">
+          姓名:
+          <FieldItem
+            v-model="contractForm.elderName"
+            :is-text-mode="isTextMode"
+            width="140px"
+            placeholder="请输入"
+          />
+          &nbsp;&nbsp;性别:
+          <FieldItem
+            v-model="contractForm.elderGenderText"
+            :is-text-mode="isTextMode"
+            width="60px"
+            placeholder="男/女"
+          />
+          &nbsp;&nbsp;出生年月日:
+          <FieldItem
+            v-model="contractForm.elderBirth"
+            :is-text-mode="isTextMode"
+            type="date"
+            width="200px"
+            placeholder="请选择日期"
+          />
+        </div>
+        <div class="content-text">
+          证件类型:
+          <FieldItem
+            v-model="contractForm.elderPapersType"
+            :is-text-mode="isTextMode"
+            type="dict"
+            dictType="PAPERS_TYPE"
+            width="200px"
+            placeholder="请选择证件类型"
+          />
+        </div>
+        <p class="content-text">
+          证件号码:
+          <FieldItem
+            v-model="contractForm.elderIdCard"
+            :is-text-mode="isTextMode"
+            width="220px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          家庭地址:
+          <FieldItem
+            v-model="contractForm.elderAddress"
+            :is-text-mode="isTextMode"
+            width="260px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          户籍所在地:
+          <FieldItem
+            v-model="contractForm.elderAddress"
+            :is-text-mode="isTextMode"
+            width="260px"
+            placeholder="请输入"
+          />
+          邮编:
+          <FieldItem
+            v-model="contractForm.elderZip"
+            :is-text-mode="isTextMode"
+            width="100px"
+            placeholder="请输入"
+          />
+        </p>
+
+        <h3 class="subsection-title" style="margin-top: 16px"
+          >丙方(老年人家属/监护人/担保人/委托代理人的个人或组织)</h3
+        >
+        <div class="content-text">
+          姓名:
+          <FieldItem
+            v-model="contractForm.partyCName"
+            :is-text-mode="isTextMode"
+            width="140px"
+            placeholder="请输入"
+          />
+          &nbsp;&nbsp;性别:
+          <FieldItem
+            v-model="contractForm.partyCGenderText"
+            :is-text-mode="isTextMode"
+            width="60px"
+            placeholder="男/女"
+          />
+          &nbsp;&nbsp;出生年月:
+          <FieldItem
+            v-model="contractForm.partyCBirth"
+            :is-text-mode="isTextMode"
+            type="date"
+            width="200px"
+            placeholder="请选择日期"
+          />
+        </div>
+        <p class="content-text">
+          与乙方关系:
+          <FieldItem
+            v-model="contractForm.partyCRelation"
+            :is-text-mode="isTextMode"
+            width="140px"
+            placeholder="请输入"
+          />
+        </p>
+        <div class="content-text">
+          证件类型:
+          <FieldItem
+            v-model="contractForm.partyCPapersType"
+            :is-text-mode="isTextMode"
+            type="dict"
+            dictType="PAPERS_TYPE"
+            width="200px"
+            placeholder="请选择证件类型"
+          />
+        </div>
+        <p class="content-text">
+          证件号码:
+          <FieldItem
+            v-model="contractForm.partyCIdCard"
+            :is-text-mode="isTextMode"
+            width="220px"
+            placeholder="请输入"
+          />
+          &nbsp;&nbsp;联系方式:
+          <FieldItem
+            v-model="contractForm.partyCPhone"
+            :is-text-mode="isTextMode"
+            width="160px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          住所(址):
+          <FieldItem
+            v-model="contractForm.partyCAddress"
+            :is-text-mode="isTextMode"
+            width="280px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          户籍所在地:
+          <FieldItem
+            v-model="contractForm.partyCHomeAddr"
+            :is-text-mode="isTextMode"
+            width="260px"
+            placeholder="请输入"
+          />
+          邮编:
+          <FieldItem
+            v-model="contractForm.partyCZip"
+            :is-text-mode="isTextMode"
+            width="100px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          工作单位:
+          <FieldItem
+            v-model="contractForm.partyCWorkUnit"
+            :is-text-mode="isTextMode"
+            width="280px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          通信地址:
+          <FieldItem
+            v-model="contractForm.partyCCommAddr"
+            :is-text-mode="isTextMode"
+            width="280px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text" style="margin-top: 14px; font-size: 13px">
+          (若乙方属于限制民事行为能力或者无民事行为能力的入住老年人,须由监护人签字确认)
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第4页:鉴于 + 第一条 ========== -->
+    <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">4</span>
+      </div>
+      <div class="page-content">
+        <h3 class="subsection-title">鉴于:</h3>
+        <p class="content-text">
+          1、甲方是依法成立的养老机构,能够提供个人生活照料、康复护理、精神慰藉、文化娱乐等养老服务;
+        </p>
+        <p class="content-text">
+          2、乙方和丙方经实地考察甲方,自愿决定乙方入住甲方开办的养老机构,接受甲方提供的专业养老服务,并向甲方支付相应费用;
+        </p>
+        <p class="content-text">
+          3、乙方授权丙方作为乙方在紧急情况下的代理人、联系人,代为处理乙方在本合同项下的相关事务,丙方同意接受乙方授权并作为乙方履行本合同义务的保证人。
+        </p>
+        <p class="content-text">
+          4、接收条件:乙方保证无精神病,无传染性疾病,无吸毒嗜好,无自杀、自残、攻击他人等危害自身、他人和公共安全的精神性障碍或缺陷,并且适应集体生活;
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;为了营造温馨、舒适、安全的生活环境,满足老年人"老有所养、老有所乐"的需要,切实保障老年人的合法权益,同时明确各自的权利义务,甲、乙、丙三方根据《中华人民共和国民法典》《中华人民共和国老年人权益保障法》《广东省养老服务条例》《广州市养老服务条例》和《养老机构管理办法》等有关法律、法规的规定,本着平等、自愿、公平、诚实守信的原则,经友好协商,就甲方为乙方提供养老服务事宜达成一致,签订本合同。
+        </p>
+
+        <h2 class="section-title">第一条&nbsp;&nbsp;服务内容</h2>
+        <p class="content-text">
+          1.甲方按照约定向乙方提供生活照料、康复护理、精神慰藉、文化娱乐等服务。甲方提供的服务应当符合法律法规规章和国家强制性标准《养老机构服务安全基本规范》要求,并积极适用行业和地方标准。
+        </p>
+        <p class="content-text">
+          2.甲方应依据广州市老年人照护需求综合评估规范,对乙方进行照护需求等级评估,根据评估结果和乙方提供的《体检报告》,经与乙方或丙方商定后,确定乙方照护等级,并由甲方按照约定的《护理等级与服务项目》(附件)为乙方提供相应服务。
+        </p>
+        <p class="content-text">
+          2.1根据乙方提供的《体检报告》、《入住登记表》(见本合同附件)及甲方对乙方进行护理等级首评,确定乙方护理级别为:
+          <FieldItem
+            v-model="contractForm.nurseLevelName"
+            :is-text-mode="isTextMode"
+            width="180px"
+            placeholder="请输入"
+          />
+          ,甲方向乙方提供的护理等级服务项目详见本合同附件《护理等级与服务项目》。
+        </p>
+        <p class="content-text">
+          2.2因老年人护理等级评估涉及到乙方的日常生活、精神状态、感知觉与沟通、社会参与等方面的评估,甲方为乙方进行护理等级复评,如复评与首评的护理等级一致,则按照首评护理等级服务项目进行收费和服务;如果复评与首评的护理等级不一致,则按照复评结果调整护理等级服务项目,并调整服务项目的收费和服务内容,甲方应通知乙方、丙方签订书面补充协议进行护理等级变更。
+        </p>
+        <p class="content-text">
+          2.3因老年人的身体机能处在不断的变化中,每入住半年或根据老年人身体变化需要,甲方会对乙方护理等级进行动态评估,如护理等级有调整,按照新的护理等级服务项目进行收费和服务,并签订书面补充协议。
+        </p>
+        <p class="content-text">
+          3.在本合同履行过程中,乙方或丙方如果选择《护理等级与服务项目》以外的其他服务项目,经当事人协商一致后另行签署书面补充协议确定。
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第5页:第二条 服务地点及设施 ========== -->
+    <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">5</span>
+      </div>
+      <div class="page-content">
+        <h2 class="section-title">第二条&nbsp;&nbsp;服务地点及设施</h2>
+        <div class="content-text">
+          1.经协商,确定本合同期限为
+          <FieldItem
+            v-model="contractForm.contractMonths"
+            :is-text-mode="true"
+            width="60px"
+            placeholder="12"
+          />
+          个月,自
+          <FieldItem
+            v-model="contractForm.startDate"
+            :is-text-mode="isTextMode"
+            type="date"
+            width="180px"
+            placeholder="请选择日期"
+          />
+          起至
+          <FieldItem
+            v-model="contractForm.endDate"
+            :is-text-mode="isTextMode"
+            type="date"
+            width="180px"
+            placeholder="请选择日期"
+          />
+          止。
+        </div>
+        <p class="content-text">
+          2.甲方为乙方提供养老服务的地点为:
+          <FieldItem
+            v-model="contractForm.servicePlace"
+            :is-text-mode="isTextMode"
+            width="260px"
+            placeholder="请输入"
+          />
+        </p>
+        <div class="content-text">
+          3.乙方或丙方为乙方选择入住的房间类型为:
+          <span v-if="!isTextMode" style="display: inline-block; vertical-align: middle">
+            <el-select v-model="contractForm.roomType" placeholder="请选择" style="width: 180px">
+              <el-option
+                v-for="item in roomTypeOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </span>
+          <span v-else class="fill-text">{{ contractForm.roomType || '' }}</span>
+        </div>
+        <p class="content-text">
+          4.乙方或丙方为乙方选择的具体房间为:
+          <FieldItem
+            v-model="contractForm.roomNo"
+            :is-text-mode="isTextMode"
+            width="120px"
+            placeholder="请输入"
+          />
+          。
+        </p>
+        <p class="content-text">
+          5.乙方或丙方基于正当理由要求调整房间的,甲方在条件许可的范围内应尽量满足。若因房间变化,需要相应调整费用的,应由各方协商一致书面确认后调整,如各方不能达成一致意见书面确认,则仍依本合同约定房间履行。
+        </p>
+        <p class="content-text">
+          6.甲方提供的服务设施除了住宿的房屋,还包括房间内生活起居必要的基础设施及其他公共设施。
+        </p>
+
+        <h2 class="section-title">第三条&nbsp;&nbsp;收费标准及费用支付方式</h2>
+        <p class="content-text">
+          1.甲方的收费标准和调整应遵守养老机构服务收费管理的相关规定,不得违规收取大额预付、向服务对象兜售保健品,不得以许诺还本付息或者给予其他投资回报、虚假夸大宣传、承诺明显低于市场价入住、折扣返利等与事实不符的条件诱导乙方或丙方交纳费用。
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第6页:第三条 收费标准及费用明细 ========== -->
+    <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">6</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          2.甲方提供的各种服务项目的收费标准和收费依据应在养老机构内公共区域显著位置进行公示,并以公共区域或网络方式(养老机构网站、政府部门有关网站等)进行线上公示,服务项目及其收费标准应作为本合同附件。
+        </p>
+        <p class="content-text">
+          3.根据本合同第一条、第二条乙方选择的房间、照护等级及服务项目,各方共同确认,乙方入住甲方需支付的养老服务费用具体如下:
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;(1)养老服务费用为:
+          <FieldItem
+            v-model="contractForm.totalFee"
+            :is-text-mode="isTextMode"
+            width="100px"
+            placeholder="0"
+          />
+          元/月。
+        </p>
+        <p class="content-text"> &nbsp;&nbsp;&nbsp;&nbsp;其中: </p>
+        <p v-for="item in monthlyExpensesList" :key="item.id" class="content-text">
+          {{ item.itemCategoryName || item.itemName }}:
+          <FieldItem
+            v-model="item.actualAmount"
+            :is-text-mode="isTextMode"
+            width="120px"
+            placeholder="0"
+          />
+          元/月;
+        </p>
+        <p class="content-text"> 其他费用: </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;(1)水电费:超出床位费包含的每人每月
+          <FieldItem
+            v-model="contractForm.freeElectric"
+            :is-text-mode="isTextMode"
+            width="80px"
+            placeholder="0"
+          />
+          千瓦时电和
+          <FieldItem
+            v-model="contractForm.freeWater"
+            :is-text-mode="isTextMode"
+            width="80px"
+            placeholder="0"
+          />
+          立方冷水的免费额度后,超出部分按实际支出进行对应房型具体入住床数进行均摊收取,超出部分收费标准为:热水
+          <FieldItem
+            v-model="contractForm.hotWaterFee"
+            :is-text-mode="isTextMode"
+            width="80px"
+            placeholder="0"
+          />
+          元/立方;冷水
+          <FieldItem
+            v-model="contractForm.coldWaterFee"
+            :is-text-mode="isTextMode"
+            width="80px"
+            placeholder="0"
+          />
+          元/立方;电
+          <FieldItem
+            v-model="contractForm.electricFee"
+            :is-text-mode="isTextMode"
+            width="80px"
+            placeholder="0"
+          />
+          元/千瓦时;
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          出现合同中止或终止情形的,扣除实际入住天数产生的费用后予以退款。
+        </p>
+        <p class="content-text"> &nbsp;&nbsp;(2)一次性收取的费用(如有请填写)。 </p>
+      </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) }}
+          <FieldItem
+            v-model="item.actualAmount"
+            :is-text-mode="isTextMode"
+            width="100px"
+            placeholder="0"
+          />
+          元。
+          <template v-if="isDepositFee(item)">
+            出现合同中止情形的,予以全额退还(
+            <el-radio-group
+              style="margin-left: 4mm"
+              v-if="!isTextMode"
+              v-model="contractForm.depositInterestType"
+              size="small"
+            >
+              <el-radio label="0">押金不计利息</el-radio>
+              <el-radio label="1">押金计利息</el-radio>
+            </el-radio-group>
+            <template v-else>
+              <span v-if="contractForm.depositInterestType === '0'"
+                >☑押金不计利息&nbsp;&nbsp;□押金计利息</span
+              >
+              <span v-else>□押金不计利息&nbsp;&nbsp;☑押金计利息</span>
+            </template>
+            <template v-if="contractForm.depositInterestType === '1'">
+              ,计息标准为:
+              <FieldItem
+                v-model="contractForm.depositInterest"
+                :is-text-mode="isTextMode"
+                width="160px"
+                placeholder="无"
+              />
+              &nbsp;&nbsp;
+            </template>
+            )。
+          </template>
+        </div>
+        <p v-if="!oneTimeExpensesList.length" class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;无。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;合同期限内出现押金不足时,乙方或丙方应在接到甲方通知之日起5日内补足。涉及退款的,在出现合同中止或终止情形后,双方进行结算,经双方确认无误之日起15个工作日内将资金退给付款方。
+        </p>
+        <p class="content-text"> 4.乙方应支付的阶段性费用及支付方式如下: </p>
+        <div v-for="item in stageExpensesList" :key="item.id" class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;{{ displayExpenseName(item) }}:
+          <template v-if="item.isFreeGift == 1">
+            赠送开始时间
+            <FieldItem
+              v-model="item.freeStartTime"
+              :is-text-mode="isTextMode"
+              type="date"
+              width="160px"
+              placeholder="请选择日期"
+            />
+            ,赠送结束时间
+            <FieldItem
+              v-model="item.freeEndTime"
+              :is-text-mode="isTextMode"
+              type="date"
+              width="160px"
+              placeholder="请选择日期"
+            />
+            ;
+          </template>
+          <template v-else>
+            费用总额
+            <FieldItem
+              v-model="item.totalAmount"
+              :is-text-mode="isTextMode"
+              width="100px"
+              placeholder="0"
+            />
+            元,分
+            <FieldItem
+              v-model="item.hirePurchaseNumber"
+              :is-text-mode="isTextMode"
+              width="60px"
+              placeholder="0"
+            />
+            期支付,每期
+            <FieldItem
+              v-model="item.hirePurchaseAmount"
+              :is-text-mode="isTextMode"
+              width="100px"
+              placeholder="0"
+            />
+            元;
+          </template>
+        </div>
+        <p v-if="!stageExpensesList.length" class="content-text"> &nbsp;&nbsp;&nbsp;&nbsp;无。 </p>
+      </div>
+    </div>
+
+    <!-- ========== 第8页:第三条 账户信息及后续 + 第四条 甲方权利及义务 ========== -->
+    <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">8</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text"> 5.甲方指定的收款账户信息如下: </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;户名:
+          <FieldItem
+            v-model="contractForm.partyAAccountName"
+            :is-text-mode="isTextMode"
+            width="260px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;开户银行:
+          <FieldItem
+            v-model="contractForm.partyABank"
+            :is-text-mode="isTextMode"
+            width="260px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;账号:
+          <FieldItem
+            v-model="contractForm.partyAAccount"
+            :is-text-mode="isTextMode"
+            width="280px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text"> 6.乙方或丙方指定的付款账户信息如下: </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;户名:
+          <FieldItem
+            v-model="contractForm.partyCAccountName"
+            :is-text-mode="isTextMode"
+            width="260px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;开户银行:
+          <FieldItem
+            v-model="contractForm.partyCBank"
+            :is-text-mode="isTextMode"
+            width="260px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;账号:
+          <FieldItem
+            v-model="contractForm.partyCAccount"
+            :is-text-mode="isTextMode"
+            width="280px"
+            placeholder="请输入"
+          />
+        </p>
+        <p class="content-text">
+          7.乙方接受甲方除本合同约定外的其他服务项目的,应根据甲方公示的收费标准和补充合同的约定交纳费用。
+        </p>
+        <p class="content-text">
+          8.甲方每月向乙方或丙方提供《个人费用明细表》,乙方或丙方应签字确认。乙方或丙方如有异议,可在收到《个人费用明细表》后7日内书面提出,甲方应做出书面说明。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;对于双方无争议费用金额应按照本合同约定时间支付,乙方或丙方不得以异议费用为由拒绝支付有关费用。
+        </p>
+        <p class="content-text"> 9.乙方、丙方共同承担向甲方支付本合同约定价款的义务。 </p>
+        <p class="content-text"> 10.甲方在收到款项后应向付款人开具等额的合法收费发票。 </p>
+        <h2 class="section-title">第四条&nbsp;&nbsp;甲方权利及义务</h2>
+        <h3 class="subsection-title">1.甲方权利</h3>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.1&nbsp;有权按照本合同约定收取相关费用。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.2&nbsp;制订、修改并在养老机构公示管理制度,并按照公开的管理制度对乙方进行管理。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.3&nbsp;为了乙方的健康和安全,乙方出现紧急情况时,有权在通知
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第10页:第四条甲方权利义务继续 + 甲方义务 ========== -->
+    <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">
+        <p class="content-text">
+          乙方或丙方同意的同时,采取必要的处置措施,包括但不限于转送医疗机构,由此产生的费用由乙方或丙方承担。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.4&nbsp;如乙方的身体状况、生活自理能力出现变化,由甲方根据对乙方护理等级评价另行确定护理等级,相关费用随之进行调整,如一周联系不上乙方,甲方有权根据乙方所需服务项目的变化情况在押金中扣除,不足部分甲方有权要求乙方和丙方支付所产生变化的费用,由乙方和丙方按甲方核定的标准支付。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.5&nbsp;乙方入住后因精神、情绪、性格、生活习惯等原因不适宜院内生活的,经甲方努力,仍无改善的,为维护乙方及院内其他老人的权利,甲方有权要求丙方在两天内为乙方办理退院或转院手续,丙方必须积极配合,做好安抚工作,对此甲方无需承担任何责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.6&nbsp;如乙方患病需要去医院治疗的,由乙方亲人送医,有权紧急处置,所涉及的各项费用由乙方和丙方承担。如乙方需甲方提供住院期间陪护服务的,相关费用由乙方和丙方承担,具体陪护事宜由当事人协商一致后另行签署书面协议确定。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.7&nbsp;有权依照本合同约定及法律规定解除合同。
+        </p>
+
+        <h3 class="subsection-title" style="margin-top: 14px">2.甲方义务</h3>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.1&nbsp;甲方应是依法成立的养老机构,应履行养老机构备案承诺,按照建筑、消防、食品安全、医疗卫生、特种设备等法律、法规和强制性标准及服务安全相关规范要求开展服务活动,确保按约定向乙方提供符合服务质量标准的养老服务;建立各类安全、疫情防控等应急预案,并应定期对应急预案进行演练。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.2&nbsp;应当提供符合乙方住宿条件的居住用房,并配备适合乙方安全保护要求的设施、设备及用具,定期对乙方的活动场所和物品进行消毒
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第11页:第四条甲方义务继续 ========== -->
+    <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">10</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          和清洗;甲方提供的饮食应当符合食品安全要求、适宜乙方食用、有利于乙方营养平衡和身体健康。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.3&nbsp;应根据登记类型、经营性质、设施设备条件、管理水平、服务质量、照料护理等级等因素合理确定服务项目收费标准,调整收费标准时应遵守国家、省、广州和广州市价格管理的有关规定。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.4&nbsp;应保证从事医疗、康复、消防等服务人员符合资质要求,保证养老护理人员接受专业技能培训,并定期组织工作人员进行职业道德教育和业务培训,能够满足岗位职责要求。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.5&nbsp;在提供服务过程中,甲方及其工作人员应尊重乙方、尽力合理地保障乙方的人格尊严和人身、财产安全,并接受乙方、丙方的合理建议和监督。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.6&nbsp;应当根据需要为乙方提供情绪疏导、心理咨询、危机干预等精神慰藉服务;应当开展适合老年人的文化、教育、体育、娱乐活动,丰富老年人的精神文化生活。甲方开展文化、教育、体育、娱乐活动时,应当为乙方提供必要的安全防护措施。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.7&nbsp;定期组织所在地的医疗机构为乙方开展体检并建立个人健康档案。妥善保存乙方的入住登记表、体检报告等健康资料以及日常经费开支情况等个人信息。应当建立各类信息资料的保管、归档和保密制度,除向乙方、丙方和其他有权部门(公安局、检察院、法院、纪委监察、养老服务行业主管部门因办案、监督、检查需要)提供查阅、允许复制外,不得对外透露。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.8&nbsp;发现乙方为疑似传染病病人或者精神障碍患者时,应依照传染病防治、精神卫生等相关法律法规的规定处理,及时向附近的疾病预防控制机构或者医疗机构报告,配合实施卫生处理、隔离等预防控制措施,
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第12页:甲方义务继续 + 第五条 ========== -->
+    <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">11</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          并及时通知丙方。乙方需要外出就医的,甲方应及时告知丙方并由有相关义务的丙方亲自携带乙方就诊,丙方确实未能亲自携带乙方就诊的,应通过委托办理等方式作出妥善安排。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.9&nbsp;应当为乙方家庭成员看望或者问候老年人提供便利,为乙方联系家庭成员提供帮助;但不得影响甲方对于乙方正常服务运营或执行政府部门规定的疫情防控等管理要求,否则甲方有权拒绝。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.10&nbsp;在发生公共卫生事件等特殊情况下,甲方应贯彻执行政府部门的防控政策规定,积极落实防控措施,并向乙方或丙方做好解释工作。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.11&nbsp;甲方暂停、终止服务的,应当在暂停或终止服务60日前,书面通知乙方或丙方,并向社会公告;将入住老年人的安置方案书面告知甲方所在地的区级民政部门。在解散清算前,甲方应当依法妥善安置乙方。如乙方或丙方有意与其他养老机构签订服务协议的,甲方应当积极为乙方联系与甲方具有同等资质和服务水平的养老服务机构,努力促进双方建立合同;如乙方或丙方解除或终止服务协议的,甲方应当退还乙方或丙方剩余未消费或合同约定的有关费用。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.12&nbsp;当乙方出现紧急情况时,应及时联系和通知丙方。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.13&nbsp;在甲方服务期间,经鉴定乙方正常死亡的,甲方应及时与丙方取得联系。无法与丙方取得联系的且机构内不具备遗体保存条件,可严格按照规定要求使用《广州市养老机构死亡报告书》并对接殡仪馆,妥善保存遗体。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.14&nbsp;乙方符合长期护理保险等申报条件的,甲方应积极为其申请。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.15&nbsp;乙方入住养老机构、请假外出、终止合同离院和去世,甲方应及时在广州市为老服务综合平台填报有关信息。
+        </p>
+
+        <h2 class="section-title">第五条&nbsp;&nbsp;乙方权利及义务</h2>
+      </div>
+    </div>
+
+    <!-- ========== 第13页:乙方权利及义务 ========== -->
+    <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">12</span>
+      </div>
+      <div class="page-content">
+        <h3 class="subsection-title">1.乙方的权利</h3>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.1&nbsp;享有隐私权,人格尊严和人身、财产安全不受非法侵害的权利。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.2&nbsp;有权按照约定的服务项目获得甲方提供的符合服务标准的养老服务,对甲方的服务有批评建议的权利。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.3&nbsp;对自身的健康状况、费用支出、入院记录等有知情权,有权查阅、复印甲方为其建立的个人档案。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.4&nbsp;有权了解提供服务的人员是否经过专业培训,是否具备相应资质,有权要求甲方更换未经专业培训或不具备相应资质或提供服务不合格的人员。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.5&nbsp;在突发疾病的情况下乙方有权获得及时、必要的医疗帮助。
+        </p>
+
+        <h3 class="subsection-title" style="margin-top: 14px">2.乙方的义务</h3>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.1&nbsp;应当按照约定自行或与丙方共同支付养老服务费及相关费用。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.2&nbsp;应当按照约定提供相关的体检报告,如实告知甲方本人的健康状况、药品使用情况及过往病史等信息,并如实填写《入住登记表》。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.3&nbsp;应当配合甲方做好持续评估及确认照护等级;配合甲方定期参加体检。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.4&nbsp;应当与其他入住老年人和谐相处。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.5&nbsp;在接收甲方提供的养老服务期间,因疾病进行诊疗时,应在治疗期间遵守医嘱,配合治疗。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.6&nbsp;应当服从甲方管理,遵守甲方的规章制度,维护养老机构正常服务秩序,爱护甲方提供的各项服务设施,入住期间损坏甲方设施设备的,乙方或丙方应当予以赔偿。损坏有关服务设施的赔偿价格可与甲方协商约定。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.7&nbsp;对于甲方提供的其他符合合同约定、法律规定的养老服务,乙
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第14页:乙方义务继续 + 第六条 ========== -->
+    <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">13</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text"> 方应予配合甲方的服务工作。 </p>
+
+        <h2 class="section-title">第六条&nbsp;&nbsp;丙方权利及义务</h2>
+        <h3 class="subsection-title">1.丙方的权利</h3>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.1&nbsp;对乙方有探视权,但不得影响甲方对乙方的正常服务管理和执行政府规定的疫情防控等管理要求。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.2&nbsp;对乙方的健康状况、享受服务情况、费用支出、入院记录等有知情权,有权查阅、复印甲方为乙方建立的个人档案。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.3&nbsp;有权了解提供服务的人员是否经过专业培训,是否具备相应资质,有权要求甲方更换未经专业培训或不具备相应资质或提供服务不合格的人员;有权对甲方的服务提出批评建议。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.4&nbsp;遇紧急情况时,包括但不限于乙方走失、身体健康状况出现紧急情况时,有权及时从甲方得到相关信息。
+        </p>
+
+        <h3 class="subsection-title" style="margin-top: 14px">2.丙方的义务</h3>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.1&nbsp;乙方入住前,丙方要如实向甲方反映乙方的情况,如脾气秉性、家庭成员、既往病史、健康状况和药品使用情况等,协助乙方如实填写《入住登记表》。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.2&nbsp;劝导乙方入住后自觉遵守养老机构的规章制度,接受管理,爱护甲方提供的各项服务设施。乙方违反本合同约定或甲方制定的规章制度,造成甲方损失或第三人人身、财产损害的,乙方需承担赔偿责任,负有付款义务或需连带责任的丙方应当承担有关赔偿责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.3&nbsp;应劝导乙方与其他入住老年人和谐相处,并经常与乙方沟通,保持联络,满足乙方的精神需求。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.4&nbsp;应劝导乙方在接收甲方提供的养老服务期间,因疾病进行诊疗时,应在治疗期间遵守医嘱,配合治疗。乙方需外出就医的,负有相关
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第15页:丙方义务继续 + 第七条 + 第八条 ========== -->
+    <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">14</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          义务的丙方应当及时携乙方到医院就诊,并向甲方如实告知乙方的就医情况。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.5&nbsp;按时足额向甲方支付约定的养老服务费、保证金及相关费用。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.6&nbsp;丙方的家庭及单位地址、联系方式变更时,应及时通知甲方。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.7&nbsp;及时协助甲方处理乙方出现的紧急情况。当甲方按照合同约定处理时,负有付款义务或连带责任的丙方应当及时足额支付由此产生的费用。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.8&nbsp;乙方在养老机构去世的,丙方应及时进行善后处理并解决费用问题。
+        </p>
+
+        <h2 class="section-title">第七条&nbsp;&nbsp;合同的续签</h2>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.合同期满前
+          <FieldItem
+            v-model="contractForm.renewNoticeDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="30"
+          />
+          日,乙方或丙方可向养老机构申请续签合同。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.续签的养老服务合同内容应当由甲方、乙方和丙方协商确定。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;3.如果乙方或丙方未在合同期限届满前
+          <FieldItem
+            v-model="contractForm.renewNoticeDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="30"
+          />
+          日提出续签合同,或者乙方或丙方虽在合同期限届满前
+          <FieldItem
+            v-model="contractForm.renewNoticeDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="30"
+          />
+          日提出续签合同申请,但各方未就合同续签达成一致,乙方应于合同到期后
+          <FieldItem
+            v-model="contractForm.moveOutDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="3"
+          />
+          日内搬离甲方,办理离院手续并结清所有费用。
+        </p>
+
+        <h2 class="section-title">第八条&nbsp;&nbsp;合同的变更和解除</h2>
+        <h3 class="subsection-title">1.合同的变更</h3>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.1&nbsp;根据乙方健康状况的变化以及护理等级的评估结果,乙方、丙方可以要求甲方变更服务方案,甲方亦可以提出变更服务方案,并以书面形式通知乙方及丙方。任何一方要求变更服务方案的,需经甲方、乙方、丙方三方协商一致,签署补充协议。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;若甲方提出变更服务方案,乙方或丙方收到甲方变更服务方案的书面通知后
+          <FieldItem
+            v-model="contractForm.changeConfirmDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="7"
+          />
+          日内既不确认又不提出异议,但乙方实际接受甲方提供的相
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第16页:合同变更继续 + 合同解除 ========== -->
+    <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">15</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          应服务的,视为甲、乙、丙三方就合同约定的服务项目的变更达成一致,乙方或丙方有义务按照新的服务项目支付相应的服务费用。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;若乙方或者丙方提出变更方案,甲方应在收到其变更服务方案的要求后
+          <FieldItem
+            v-model="contractForm.priceObjDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="30"
+          />
+          日内会同乙方或者丙方进行研究确定,变更方案符合有关规定和实际情况的,甲方应予以采纳。经沟通未能达成一致意见的,甲方有义务应向乙方或丙方解释不采纳其变更方案的理由和依据,乙方或丙方仍不能接受的,可向属地民政部门反映或向司法部门起诉。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;如果根据乙方健康状况的变化以及护理等级的评估结果,不调整服务项目将导致乙方的健康安全无法保障的,甲方提出变更的服务方案后,乙方或丙方既不同意,也不接受实际服务的,甲方、乙方或丙方均有权解除本合同。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;当食品材料市场价格发生重大变化,致使甲方服务成本急剧上升(单项价格变动幅度超过
+          <FieldItem
+            v-model="contractForm.priceThreshold"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="6"
+          />
+          %时),甲方可适当调整伙食费收费标准,将价格调整的通知在调价前
+          <FieldItem
+            v-model="contractForm.priceAdjustNoticeDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="30"
+          />
+          日以书面形式通知乙方及丙方,并签订补充合同。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;乙方或丙方对价格调整有异议的,可在收到通知后
+          <FieldItem
+            v-model="contractForm.priceObjDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="15"
+          />
+          日内以书面形式提出解除合同;乙方或丙方要求继续按照原收费标准履行合同的,甲方有权提出解除合同。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;乙方或丙方收到通知后
+          <FieldItem
+            v-model="contractForm.priceConfirmDays"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="15"
+          />
+          日内不以书面形式提出异议,但拒绝根据调整后的价格支付相关费用的,甲方有权解除合同并按照原收费标准收取已提供服务的费用。
+        </p>
+
+        <h3 class="subsection-title" style="margin-top: 14px">2.合同的解除</h3>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.1&nbsp;除本合同另有约定外,下列情况下,乙方或丙方可以单方解除本合同,并无需承担违约责任:
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (1)甲方提供的服务不符合合同约定,经乙方或丙方提出,30日内不改正的;
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (2)因甲方或甲方工作人员的严重过错造成乙方人身或重大财产损害的;
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (3)乙方因疾病或其他个人原因离院的,但乙方或丙方不提出解除本合同而要求保留床位或房间的除外;乙方因疾病需要长期住院治疗(凭7天内住院证明)或去世解除合同的,免收违约金;
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (4)履行合同过程中,乙方或丙方提前30日书面通知甲方并结清服务费用的;
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (5)乙方首次入住15日内不适应居住环境或管理方式的,乙方可以单方解除本合同,并无需承担违约责任。
+        </p>
+
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.2&nbsp;除本合同另有约定外,下列情况下,甲方可以单方解除本合同,并无需承担违约责任:
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (1)乙方或丙方无无故拖欠各项费用超过15日,经甲方书面催告后7日内仍不交纳的,甲方有权解除合同,并书面通知乙方搬出养老机构。乙方在甲方发出书面解除合同通知后7日内仍不搬出的,甲方有权提起诉讼,请求法院确认合同解除。乙方和丙方除应支付拖欠的服务费用,诉讼期间的服务费用以外,还应每天支付应付未付费用金额的1%违约金,并负担甲方由此产生的一切费用(包括但不限于诉讼费、甲方聘请律师的实际支出、搬出费用)等。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (2)乙方严重违反甲方的规章制度,造成甲方难以履行对乙方的养老服务,或造成其他入住老人伤害或存在可能造成他人伤害危险的。需对有关事实进行甄别别的,可提请属地民政部门或委托第三方协助认定。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (3)乙方或丙方隐瞒乙方健康状况,或者乙方患有须隔离治疗的
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第18页:合同解除继续 + 第九条违约责任 ========== -->
+    <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">17</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text"> 传染性疾病或者患有精神疾病等其他不适宜在机构内集中生活的。 </p>
+        <p class="content-text" style="padding-left: 2em">
+          (4)发生不可抗力致甲方不能履行合同的。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (5)甲方因丧失养老机构执业资格等原因暂停、终止服务的。甲方应当于暂停或者终止服务60日前向实施许可或者备案的属地民政部门提交老年人安置方案,经批准后方可解除养老机构服务合同。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (6)乙方连续请假外出超过
+          <FieldItem
+            v-model="contractForm.leaveDays"
+            :is-text-mode="isTextMode"
+            width="60px"
+            placeholder="60"
+          />
+          天(限期不得少于30天)。请假期间,因病情严重需要医治或疫情防控等管理要求,乙方无法返院或甲方不具备返院条件的情形除外。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (7)丙方与甲方中断联系达到30天的,甲方有权选择单方解除合同。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.3&nbsp;除本合同另有约定外,下列情况下,乙方提前终止合同的,按照以下约定执行:
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;如乙方提前解除合同(除因疾病需长期住院治疗、去世解除合同外),须提前30天书面向甲方提出申请,经甲方批准后方可办理离院手续,乙方应按照本月实际享受服务天数结算本月床位费、护理费、膳食费、管理费、水电费等费用,并按照附件《服务项目收费标准》中乙方所定房型向甲方缴纳一个月床位费的违约金。
+        </p>
+
+        <h2 class="section-title">第九条&nbsp;&nbsp;违约责任</h2>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.因甲方及其工作人员的过错,损害乙方人身或财产权利的,由甲方承担赔偿责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.甲方服务人员资质不合格、没有按约定提供服务或者提供的服务不合格,造成乙方人身或财产损失的,甲方应当承担赔偿责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;3.甲方或其工作人员侵犯乙方、丙方对甲方提供的养老服务的知情权的,乙方和丙方有权要求甲方改正,造成损失的甲方应承担赔偿责任。
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第19页:违约责任继续 ========== -->
+    <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">18</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;4.如果乙方或丙方无故拖欠各项费用超过15日,经甲方发出催告通知后7日内仍不交纳的,甲方有权解除合同,书面通知乙方和丙方,要求乙方出院。如果乙方在甲方发出解除合同通知后7日内仍不出院,甲方有权强制要求乙方出院或者送回乙方或丙方住所。此种情况下解除合同,乙方及丙方除应支付拖欠的费用外,还应每天支付应付未付费用金额的1%违约金,并负担甲方由此产生的一切费用(包括但不限于诉讼费、甲方聘请律师的实际支出、搬出费用)等;
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;5.乙方或丙方未将乙方健康状况、用药情况及过往病史如实告知甲方,造成甲方在提供服务过程中护理失当的,由乙方或丙方承担相应的后果。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;6.乙方需外出就医的,甲方履行告知义务,乙方拒绝外出就医或丙方拒绝及时携乙方到医院就诊而造成的后果,由乙、丙方自行承担。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;7.甲方没有过错,因乙方原因造成其自身损害的,由乙方、丙方自行承担全部后果和责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;8.因乙方原因造成甲方或第三人人身或财产损失的,乙方、丙方应承担赔偿责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;9.签订养老服务合同后,乙方未按照合同约定时间入住的,按照以下约定办理:因紧急住院治疗无法按期办理且向公办养老机构提出由医疗机构出具的诊断结论的,由公办养老机构适当延长其资格核验、办理入住手续期限。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;10.本合同提前终止或服务期满的,乙方逾期搬离甲方养老机构的,按乙方在服务期满前一个月的养老服务费用标准的1.5倍按日计算养老服务费用,直至办理完毕离院手续并搬离甲方养老机构之日止。
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第20页:违约责任继续 + 第十条通知与送达 + 第十一条陈述与保证 ========== -->
+    <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">19</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;11.甲方按本合同约定应承担赔偿责任的,赔偿限额以甲方实际收费为限。
+        </p>
+
+        <h2 class="section-title">第十条&nbsp;&nbsp;通知与送达</h2>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.在本合同首页中所标明的甲方、乙方和丙方的地址和联系方式为各方各自有效的通讯地址和联系方式。一方变更通讯地址和联络方式应及时通知其他各方。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.以下情形,视为送达,但受送达人有证据证明其因客观原因未实际接收到通知的除外:
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          以特快专递形式发送,已经签收的,以签收日为送达日;未签收的,同城自发送之日起2日视为文件已经送达,异地5日视为送达,境外15日视为送达;以手机短信发送的,发送成功即视为送达;电子邮件自发出后进入收件方邮箱服务器视为送达;传真发送自对方传真机接收视为送达。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          因受送达人通讯地址或其他相关信息错误、不详或发生变更未及时通知其他各方造成无法送达的,由受送达人自行承担相关后果。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;3.乙方入住甲方期间,有关本合同的履行事宜甲方应以书面或数据电文形式通知乙方或丙方,由乙方或丙方确认签收;乙方或丙方拒绝的,书面通知在第三方见证下送至收件人地址的视为已通知或已送达,数据电文进入收件人接收系统的视为已通知或已送达。
+        </p>
+
+        <h2 class="section-title">第十一条&nbsp;&nbsp;陈述与保证</h2>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.甲方保证为依照法律、行政法规设立并依法登记的养老机构,具有提供本合同约定的养老服务的资格和能力。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.乙方或丙方保证乙方不属于患有精神病、甲类或乙类传染性疾病等不符合入住养老机构疾病的老年人。
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第21页:陈述与保证继续 + 第十二条特别约定 ========== -->
+    <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">20</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;3.乙方或丙方保证向甲方提供乙方在本协议签署前1个月内在甲方所在地二级甲等以上医院进行体检的《体检报告》(体检项目包括:精神健康状况、传染性疾病及养老机构要求的其他体检项目等)(作为本合同附件)。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;4.乙方或丙方保证向甲方提供的乙方或丙方共同签字的《入住登记表》(作为本协议附件)是真实的,没有任何虚假或隐瞒。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;5.丙方保证履行本合同履行过程的联系人,接收甲方的通知,如涉及诉讼、仲裁或其他法律程序的,保证作为相关机构法律文书的接收人,甲方或相关机构向乙方或保证人所列明的地址、联系方式等送达相关文书的,均视为有效送达。
+        </p>
+
+        <h2 class="section-title">第十二条&nbsp;&nbsp;特别约定</h2>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.甲方仅提供与合同约定护理等级相符的相关服务,对于超出护理等级的看护、注意义务,甲方将依据现实情况、乙方身体状况尽可能的提供帮扶、协助,但不表示甲方愿意接受超出合同约定的范围的约束;甲方不是专业的医疗机构,对乙方进行的常规体检不代表甲方对乙方真实身体状况的了解,也不能代表甲方对乙方身体状况的确认,一切以专业的医疗机构及医护人员的判断为准。
+        </p>
+        <p class="content-text"> &nbsp;&nbsp;&nbsp;&nbsp;2.突发疾病或出现事故等紧急情况的处理 </p>
+        <p class="content-text" style="padding-left: 2em">
+          (1)乙方在入住期间突发疾病或身体伤害事故,甲方应及时通知丙方,及时联系120等医疗急救机构;如需到医疗机构急救,甲方应派人陪送至医疗机构。甲方不能及时联系上丙方的,应尽早与本合同附件确定的其他联系人取得联系并通报情况。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (2)甲方具有医疗资质的,在乙方生命垂危等紧急情况下应尽到合理诊疗义务,费用由乙方和丙方承担。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (3)因乙方发生紧急情况产生的费用急救费用、治疗费用、住院押金等均由乙方和丙方负担。甲方因此垫付费用的,乙方或丙方应按照甲方要求的时间内清偿。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (4)为保证入住长者的生活环境,甲方暂未设有临终关怀服务,当乙方生命垂危时,丙方应全力配合甲方将乙方送医院进行抢救;若乙方或丙方任何一方不予配合,甲方有权将乙方送往就近医院抢救并扣除乙方入住时缴纳人民币
+          <FieldItem
+            v-model="contractForm.depositAmt1"
+            :is-text-mode="isTextMode"
+            width="120px"
+            placeholder="0"
+          />
+          元(大写金额:
+          <FieldItem
+            v-model="contractForm.depositAmtCn1"
+            :is-text-mode="isTextMode"
+            width="200px"
+            placeholder="零元整"
+          />
+          )的押金,救护费用不足部分由乙方及丙方承担;
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          (5)若乙方在甲方养老院突然去世,丙方须全力配合甲方将乙方以医疗救护的方式将乙方送往就近医院;若丙方不予配合,甲方有权扣除乙方入住时缴纳人民币
+          <FieldItem
+            v-model="contractForm.depositAmt2"
+            :is-text-mode="isTextMode"
+            width="120px"
+            placeholder="0"
+          />
+          元(大写金额:
+          <FieldItem
+            v-model="contractForm.depositAmtCn2"
+            :is-text-mode="isTextMode"
+            width="200px"
+            placeholder="零元整"
+          />
+          )的押金,费用不足部分由丙方承担。
+        </p>
+        <p class="content-text"> &nbsp;&nbsp;&nbsp;&nbsp;3.乙方去世的善后服务及相关费用 </p>
+        <p class="content-text" style="padding-left: 2em">
+          乙方在甲方服务期间去世的,甲方应及时与丙方取得联系,丙方负责善后处理并承担相关费用。无法与丙方取得联系的,应及时联系殡仪馆,妥善保存遗体,发生的费用由丙方承担。
+        </p>
+        <p class="content-text"> &nbsp;&nbsp;&nbsp;&nbsp;4.甲方与丙方联系中断 </p>
+        <p class="content-text" style="padding-left: 2em">
+          因丙方提供的联系地址、方式不准确或不详细或变更后未及时通知甲方,或其他客观原因致使甲方无法与丙方及时联系,连续达30天则视为联系中断。甲方与乙方协商后,可以重新确定联系人。联系中断不免除丙方在本合同项下的责任。
+        </p>
+        <p class="content-text" style="padding-left: 2em">
+          因乙方、丙方原因导致联系中断的,如乙方仍有其他直系亲属的,则甲方有权自行联系其他直系亲属协商重新确定联系人或解除合同关系,无其他直系亲属或无其他亲属愿意承担乙方相关费用的,则甲方有
+        </p>
+      </div>
+    </div>
+
+    <!-- ========== 第23页:特别约定继续 + 第十三条争议解决 ========== -->
+    <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">22</span>
+      </div>
+      <div class="page-content">
+        <p class="content-text">
+          权自行联系相关政府部门或其他机构解决处理有关乙方的托养事宜,因此而产生的相关费用,甲方有权向乙方或丙方追偿。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;5.非因甲方故意或重大过失的原因造成乙方人身、财产损害的,甲方不承担责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;乙方入住后若发生根据体检报告所反映出的一系列疾病、并发症或突发性疾病导致死亡,与甲方无关;
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;由于乙方属高龄及有疾病的长者,易发生意外,入住期间非因甲方原因发生骨折、心脏骤停、脑梗、脑溢血、呛咳、肺部感染等疾病导致死亡与甲方无关;
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;乙方入住后,经甲方诊断有疾病且书面通知乙方前往三甲及以上的医院进行治疗的,乙方应及时前往医院就医;若乙方或丙方不予配合,乙方发生任何意外,由乙方和丙方承担全部责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;6.乙方具有完全民事行为能力,但拒绝接收甲方提供服务,造成其自身人身、财产损害的,由乙方自行承担后果。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;7.本合同关于乙方和丙方权利义务的约定,并不免除对乙方有法定赡养义务的其他人员的法定责任。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;8.因不可抗力导致本合同无法继续履行的、受到不可抗力影响的一方应在不可抗力情形发生后及时通知合同其他相关方,本合同可依法解除,合同各方不承担解除合同的责任。丙方应及时接回并妥善安置乙方。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;9.甲方破产、停业、转让:甲方需提前30天通知乙方和丙方,并协助丙方将乙方转至其他养老机构托养或送回住所;
+        </p>
+
+        <h2 class="section-title">第十三条&nbsp;&nbsp;争议解决方式</h2>
+        <template v-if="!isTextMode">
+          <p class="content-text">
+            &nbsp;&nbsp;&nbsp;&nbsp;本合同在履行过程中发生争议,当事人尽量协商解决。协商不成的,当事人可以选择下列第
+            <el-radio-group
+              v-model="contractForm.disputeMode"
+              size="small"
+              style="display: inline-flex; vertical-align: middle; margin: 0 4px"
+            >
+              <el-radio label="1">1</el-radio>
+              <el-radio label="2">2</el-radio>
+            </el-radio-group>
+            种方式解决:
+          </p>
+          <p class="content-text"> &nbsp;&nbsp;&nbsp;&nbsp;1.向仲裁机构申请仲裁。 </p>
+          <p class="content-text"> &nbsp;&nbsp;&nbsp;&nbsp;2.向有管辖权的人民法院提起诉讼。 </p>
+        </template>
+        <template v-else>
+          <p class="content-text">
+            &nbsp;&nbsp;&nbsp;&nbsp;本合同在履行过程中发生争议,当事人尽量协商解决。协商不成的,当事人可以选择下列第
+            <span
+              style="
+                display: inline-block;
+                min-width: 30px;
+                text-align: center;
+                border-bottom: 1px solid #333;
+              "
+            >
+              {{ contractForm.disputeMode || '2' }}
+            </span>
+            种方式解决:
+          </p>
+          <p class="content-text">
+            &nbsp;&nbsp;&nbsp;&nbsp;{{ contractForm.disputeMode === '1' ? '☑' : '□' }}
+            1.向仲裁机构申请仲裁。
+          </p>
+          <p class="content-text">
+            &nbsp;&nbsp;&nbsp;&nbsp;{{ contractForm.disputeMode === '2' ? '☑' : '□' }}
+            2.向有管辖权的人民法院提起诉讼。
+          </p>
+        </template>
+      </div>
+    </div>
+
+    <!-- ========== 第24页:第十四条合同生效及附件 ========== -->
+    <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">23</span>
+      </div>
+      <div class="page-content">
+        <h2 class="section-title">第十四条&nbsp;&nbsp;合同生效及附件</h2>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;本合同一式【
+          <FieldItem
+            v-model="contractForm.copyCount"
+            :is-text-mode="isTextMode"
+            width="60px"
+            placeholder="叁"
+          />
+          】份,甲方执【
+          <FieldItem
+            v-model="contractForm.partyACopy"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="壹"
+          />
+          】份,乙方执【
+          <FieldItem
+            v-model="contractForm.partyBCopy"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="壹"
+          />
+          】份,乙方监护人执【
+          <FieldItem
+            v-model="contractForm.partyCCopy"
+            :is-text-mode="isTextMode"
+            width="40px"
+            placeholder="壹"
+          />
+          】份,自各方签字或盖章之日起生效。
+        </p>
+
+        <p class="content-text" style="margin-top: 16px">
+          &nbsp;&nbsp;&nbsp;&nbsp;1.下列文件为本合同附件,与本合同具有同等法律效力:
+        </p>
+        <template v-for="(item, index) in page24AttachmentItems" :key="item.no">
+          <p class="content-text" style="padding-left: 2em">
+            附件{{ toChineseNumber(index + 1) }}:{{ item.title }}
+          </p>
+          <p v-if="item.subTitle" class="content-text" style="padding-left: 3em; font-size: 13px">
+            {{ item.subTitle }}
+          </p>
+        </template>
+      </div>
+    </div>
+
+    <!-- ========== 第25页:附件继续 + 签署页 ========== -->
+    <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">24</span>
+      </div>
+      <div class="page-content">
+        <template v-for="(item, index) in page25AttachmentItems" :key="item.no">
+          <p class="content-text" style="padding-left: 2em">
+            附件{{ toChineseNumber(page24AttachmentItems.length + index + 1) }}:{{ item.title }}
+          </p>
+          <p v-if="item.subTitle" class="content-text" style="padding-left: 3em; font-size: 13px">
+            {{ item.subTitle }}
+          </p>
+        </template>
+
+        <p class="content-text" style="margin-top: 12px">
+          &nbsp;&nbsp;&nbsp;&nbsp;2.本合同附件系本合同不可分割的组成部分,与本合同具有同等法律效力。
+        </p>
+        <p class="content-text">
+          &nbsp;&nbsp;&nbsp;&nbsp;3.本合同附件是本合同的组成部分,与合同正文具有同等法律效力。
+        </p>
+
+        <p class="content-text" style="text-align: center; margin-top: 30px; font-size: 14px">
+          (本文以下无正文,为合同签署页)
+        </p>
+
+        <div style="margin-top: 30px; font-size: 14px; line-height: 2.2">
+          <p>
+            甲方(盖章):
+            <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 style="margin-top: 6px">
+            日期:
+            <FieldItem
+              v-model="contractForm.partyADate"
+              :is-text-mode="isTextMode"
+              type="date"
+              width="200px"
+              placeholder="请选择日期"
+            />
+          </div>
+          <div style="margin-top: 20px">
+            乙方(签字):
+            <SignatureItem
+              :elder-id="props.recordRow.elderId"
+              v-model="contractForm.partyBSign"
+              :is-text-mode="isTextMode"
+              :width="260"
+              :height="80"
+              placeholder="(签字处)"
+              title="乙方签字"
+            />
+          </div>
+          <div style="margin-top: 6px">
+            日期:
+            <FieldItem
+              v-model="contractForm.partyBDate"
+              :is-text-mode="isTextMode"
+              type="date"
+              width="200px"
+              placeholder="请选择日期"
+            />
+          </div>
+          <div style="margin-top: 20px">
+            丙方(签字/盖章):
+            <SignatureItem
+              :elder-id="props.recordRow.elderId"
+              v-model="contractForm.partyCSign"
+              :is-text-mode="isTextMode"
+              :width="260"
+              :height="80"
+              placeholder="(签字/盖章处)"
+              title="丙方签字"
+            />
+          </div>
+          <div style="margin-top: 6px">
+            日期:
+            <FieldItem
+              v-model="contractForm.partyCDate"
+              :is-text-mode="isTextMode"
+              type="date"
+              width="200px"
+              placeholder="请选择日期"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.contract-body {
+  width: 100%;
+  padding: 0;
+  background: #f5f5f5;
+}
+
+.a4-page {
+  width: 210mm;
+  min-height: auto;
+  margin: 4mm auto;
+  padding: 10mm 14mm;
+  background: #fff;
+  box-shadow: 0 0 8px rgba(0, 0, 0, 0.12);
+  position: relative;
+  box-sizing: border-box;
+}
+
+/* 封面页保留完整 A4 高度 */
+.a4-page.cover-a4 {
+  min-height: 297mm;
+}
+
+/* 非封面页隐藏页眉(logo+页码) */
+.a4-page:not(.cover-a4) .page-header {
+  display: none;
+}
+
+.page-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding-bottom: 6px;
+  border-bottom: 1.5px solid #333;
+  margin-bottom: 16px;
+}
+
+.logo-line {
+  display: flex;
+  align-items: center;
+}
+
+.logo-circle {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  background: #2b7c4e;
+  color: #fff;
+  font-size: 14px;
+  font-weight: bold;
+  margin-right: 8px;
+}
+
+.logo-text {
+  font-size: 16px;
+  font-weight: bold;
+  color: #333;
+}
+
+.page-no-right {
+  font-size: 12px;
+  color: #666;
+}
+
+.page-content {
+  font-size: 14px;
+  line-height: 1.9;
+  color: #333;
+}
+
+.cover-page {
+  text-align: center;
+  padding-top: 30mm;
+}
+
+.cover-fields {
+  text-align: left;
+  margin: 0 auto;
+  width: 100%;
+}
+
+.cover-fields .label {
+  display: inline-block;
+  min-width: 80px;
+  font-size: 14px;
+}
+
+.doc-title {
+  margin-top: 50mm;
+  font-size: 32px;
+  font-weight: bold;
+  letter-spacing: 4px;
+  color: #222;
+}
+
+.cover-issuer {
+  margin-top: 60mm;
+  font-size: 16px;
+  line-height: 2;
+  text-align: center;
+}
+
+.section-title {
+  font-size: 18px;
+  font-weight: bold;
+  text-align: center;
+  margin: 20px 0 14px 0;
+  color: #222;
+}
+
+.subsection-title {
+  font-size: 15px;
+  font-weight: bold;
+  margin: 12px 0 6px 0;
+  color: #222;
+}
+
+.content-text {
+  font-size: 14px;
+  line-height: 1.9;
+  margin: 4px 0;
+  text-indent: 0;
+  text-align: left;
+  color: #333;
+}
+
+@media print {
+  .contract-body {
+    background: #fff;
+    margin: 0;
+    padding: 0;
+    width: 210mm;
+  }
+
+  /* 封面页:填满一整页(@page margin 16mm,可打印区域高度 = 297-32=265mm) */
+  .a4-page.cover-a4 {
+    width: 210mm !important;
+    min-height: 265mm !important;
+    margin: 0 !important;
+    padding: 0 !important;
+    background: #fff !important;
+    box-shadow: none !important;
+    box-sizing: border-box !important;
+    page-break-after: always;
+    break-after: page;
+  }
+
+  /* 其他页:保留屏幕内边距,由 @page margin 控制物理边距 */
+  .a4-page:not(.cover-a4) {
+    width: 210mm !important;
+    min-height: auto !important;
+    margin: 0 !important;
+    padding: 0 !important;
+    background: #fff !important;
+    box-shadow: none !important;
+    box-sizing: border-box !important;
+    page-break-after: auto;
+    break-after: auto;
+  }
+
+  .a4-page:last-child {
+    page-break-after: auto;
+    break-after: auto;
+  }
+
+  /* 注意:@page 规则统一在 ContractManageForm.vue 中声明,避免多组件冲突 */
+}
+</style>

+ 37 - 5
src/views/elderly/fee/comprehensive-setting/index.vue

@@ -168,7 +168,7 @@ const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 const formRef = ref()
 const configList:any = ref([]) // 配置列表
-const list = ref([
+const list = ref<any[]>([
   {
     title: '机构配置',
     children: [
@@ -419,6 +419,24 @@ const list = ref([
         prop: 'contract',
         tgType: true,
         title: '合同模块配置'
+      },
+      {
+        configName: '合同区域设置',
+        desc: '设置电子合同的默认合同区域,创建新合同时默认使用该区域',
+        type: 'select',
+        placeholder: '请选择',
+        list: [
+          { label: '广州地区合同', value: '广州地区合同' },
+          { label: '湖北地区合同', value: '湖北地区合同' },
+
+        ],
+        value: '广州地区合同',
+        id: '',
+        label: '请选择合同区域',
+        prop: 'contract-area',
+        tgType: true,
+        title: '合同模块配置',
+        value2Field: true
       }
     ]
   },
@@ -441,7 +459,7 @@ const list = ref([
     ]
   },
 ])
-const currItem = ref({}) // 当前处理的项
+const currItem = ref<any>({}) // 当前处理的项
 const handleEdit = async (c) => {
   currItem.value = c
   if(!c.tgType){
@@ -451,7 +469,21 @@ const handleEdit = async (c) => {
       formRef.value.validateField(c.prop)
       return
     }
-    const res = await updateBusinessParamsConfig(c)
+    // 构造干净的更新参数,合同区域使用 value2 字段
+    const payload: any = {
+      id: c.id,
+      title: c.title,
+      configName: c.configName,
+      description: c.desc,
+      label: c.label,
+      placeholder: c.placeholder,
+      prop: c.prop,
+      type: c.type,
+      appendText: c.appendText,
+      value: c.value2Field ? '' : c.value,
+      value2: c.value2Field ? c.value : undefined
+    }
+    const res = await updateBusinessParamsConfig(payload)
     if(res){
       c.tgType = true
       message.success(t('common.updateSuccess'))
@@ -500,7 +532,7 @@ const getList = async () => {
           }else{
             if(child.configName == r.configName){
               child.id = r.id
-              child.value = r.value
+              child.value = child.value2Field ? r.value2 : r.value
               child.title = r.title
               child.desc = r.description
             }
@@ -663,4 +695,4 @@ onMounted(()=>{
     }
   }
 }
-</style>
+</style>