瀏覽代碼

床头卡跳转

chenjun 1 月之前
父節點
當前提交
5ee233e28e

+ 28 - 0
.workbuddy/memory/2026-08-20.md

@@ -0,0 +1,28 @@
+# 2026-08-20 工作记录
+
+## Detail.vue 床头卡跳转后关闭失效(keep-alive + el-dialog 动画打断)
+
+### 现象
+- 用户点床头卡 → 弹窗内"跳转到编辑页" → router.push 跳走 → 用户返回 → 再点床头卡能开 → 但点"关闭预览"关不掉,console 里 `handleDialogClose` 的 `console.log('床头卡弹窗已关闭')` 照常打出。
+
+### 根因
+- 路由 `elderly/elder-file/detail/:id` 的 `meta.noCache = false`(`src/router/modules/remaining.ts:135`),Detail 页被 `<keep-alive>` 缓存。
+- `BedCardModal` 的 `handleCloseE` 同步执行 `visible.value = false`(触发 el-dialog 关闭动画,约 300ms)后立即 `emit('edit')`,父级 `handleEdit` 立刻 `router.push(...)`,路由切换(deactivate)**打断**了 el-dialog 正在进行的关闭动画。
+- el-dialog 内部动画状态卡死:v-model 已经是 false,但 dialog 实例不再响应后续 `modelValue -> false` 的关闭动作(但 `emit('close')` 是同步触发,所以 log 照打)。这就是「log 出来但弹窗没关」的来源。
+
+### 修复
+- 在 `src/views/elderly/elder/elder-file/Detail.vue` 的 `handleEdit` 中:先 `dialogVisible.value = false` 显式触发关闭,再 `setTimeout(..., 350)` 等关闭动画走完,再 `router.push`。
+- 注意:不能依赖 `handleCloseE` 自己去关,因为它和 `router.push` 几乎同帧,动画照样被打断。必须由父级在跳转前给动画留出 300+ ms。
+
+### 验证
+- ESLint:0 errors(仅 1 个历史 warning)
+
+### 后续可考虑(暂未做)
+- `BedCardModal` 的 `visible = ref(props.modelValue)` + 两个 watch 的模式本身就是脆弱的双向同步,容易在不同生命周期/keep-alive 场景下出现 desync。根治方案是改成 computed:
+  ```ts
+  const visible = computed({ get: () => props.modelValue, set: v => emit('update:modelValue', v) })
+  ```
+  这是个共享组件,改造影响面较大,等真出现其他 desync 再统一改。
+
+### 文件
+- 修改:`src/views/elderly/elder/elder-file/Detail.vue`(`handleEdit`)

+ 9 - 1
src/components/BedCardModal/index.vue

@@ -27,6 +27,7 @@
         <el-button @click="handleImport" type="warning" style="margin-left: auto"
           >导出床头卡</el-button
         >
+        <el-button @click="handleCloseE" style="margin-left: 30px">跳转到编辑页</el-button>
         <el-button @click="handleClose" style="margin-left: 30px">{{ closeText }}</el-button>
         <slot name="footer-extra"></slot>
       </div>
@@ -67,6 +68,7 @@ const emit = defineEmits<{
   'update:modelValue': [value: boolean]
   close: []
   importCard: []
+  edit: []
 }>()
 
 // 床头卡组件引用
@@ -141,7 +143,7 @@ const updatePatientData = async (data) => {
         eId: sourceData.id || sourceData.qr?.eId || '',
         tId: sourceData.tenantId || sourceData.qr?.tId || ''
       },
-      updateTime: sourceData.updateTime||''
+      updateTime: sourceData.updateTime || ''
     }
     console.log('DATA', data)
 
@@ -181,6 +183,12 @@ const handleClose = () => {
   emit('close')
 }
 
+// 关闭弹窗
+const handleCloseE = () => {
+  visible.value = false
+  emit('edit')
+}
+
 //
 const handleImport = () => {
   emit('importCard')

+ 5 - 5
src/views/elderly/contracts/components/CheckInRegistrationBody.vue

@@ -875,18 +875,18 @@ const onInlineInput = (key: keyof CheckInRegistrationForm, e: Event) => {
         </td>
       </tr>
 
-      <!-- 签名区域:签章(2) + 乙方(2) + 签名(3) = 7列 -->
+      <!-- 签名区域:签章(2) + 甲方(2) + 签名(3) = 7列 -->
       <tr>
         <td class="lbl" rowspan="2" colspan="2">签章</td>
-        <td colspan="2">乙方(入住人/监护人)签章:</td>
+        <td colspan="2">甲方(机构负责人)签章:</td>
         <td colspan="3">
-          <SignatureItem v-model="form.partyBSign" :is-text-mode="isTextMode" />
+          <SignatureItem v-model="form.partyCSign" :is-text-mode="isTextMode" />
         </td>
       </tr>
       <tr>
-        <td colspan="2">丙方(机构负责人)签章:</td>
+        <td colspan="2">乙方(入住人/监护人)签章:</td>
         <td colspan="3">
-          <SignatureItem v-model="form.partyCSign" :is-text-mode="isTextMode" />
+          <SignatureItem v-model="form.partyBSign" :is-text-mode="isTextMode" />
         </td>
       </tr>
       <tr>

+ 18 - 0
src/views/elderly/elder/elder-file/Detail.vue

@@ -128,6 +128,7 @@
     @import-card="importCardFun"
     :title="'床头卡预览'"
     :width="'1080px'"
+    @edit="handleEdit"
     @close="handleDialogClose"
   />
   <!-- 分享卡弹窗组件 -->
@@ -150,6 +151,8 @@
     :width="'600px'"
     @close="handleDialogClose"
   />
+
+  <Form ref="formRefE" @success="getElderInfoById(idE)" />
 </template>
 <script setup lang="ts">
 import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
@@ -179,8 +182,10 @@ import { formatTime } from '@/utils'
 
 import { getElderHealthRecordById } from '@/api/elderly/elder/health-record'
 import { getDictLabel, DICT_TYPE } from '@/utils/dict'
+import Form from '@/views/elderly/elder/health-record/Form.vue'
 defineOptions({ name: 'ElderFileDetail' })
 const formRef = ref() // 表单 Ref
+const formRefE = ref() // 表单 Ref
 const bed = ref() // 表单 Ref
 const dataForm = ref<{
   elderName?: string
@@ -281,8 +286,10 @@ const routeArr = [
 
 const route = useRoute()
 const healthRecord = ref({})
+let idE = undefined
 onMounted(async () => {
   const { id } = route.params
+  idE = id
   activeName.value = 1
   // 获取长者详情
   try {
@@ -342,6 +349,17 @@ const showCardDoor = () => {
 const handleDialogClose = () => {
   console.log('床头卡弹窗已关闭')
 }
+const handleEdit = () => {
+  // 先显式关闭床头卡弹窗,再等关闭动画结束(约 300ms)后再跳转。
+  // 否则 el-dialog 的关闭动画会被 <keep-alive> 的路由切换打断,
+  // 弹窗内部动画状态会卡住,导致返回后再点关闭预览关不掉(log 仍会打)。
+  dialogVisible.value = false
+  setTimeout(() => {
+    router.push({
+      path: '/trend-charts/health-record'
+    })
+  }, 350)
+}
 
 const importCardFun = () => {
   importCard(healthRecord.value, dataForm.value)

+ 1 - 0
src/views/elderly/elder/health-record/Form.vue

@@ -1025,6 +1025,7 @@ const {
 const open = async (row, elderId, detail) => {
   dialogVisible.value = true
   isDetail.value = detail
+  console.log(row,elderId,detail)
   if (row.id) {
     try {
       const res = await getElderHealthRecordById(elderId)