Parcourir la source

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

xiongxing il y a 4 semaines
Parent
commit
f34e7d40c3
27 fichiers modifiés avec 2130 ajouts et 4076 suppressions
  1. 0 3496
      public/pdf.worker.mjs
  2. 392 0
      scripts/add-export-to-nine-precautions-v2.js
  3. 383 0
      scripts/add-export-to-nine-precautions.js
  4. 60 0
      scripts/cleanup-nine-precautions-export.js
  5. 27 0
      scripts/remove-batch-dialog.js
  6. 3 1
      src/components/UploadFile/src/useUpload.ts
  7. 74 45
      src/views/elderly/apply/nine-precautions/MMSE/index.vue
  8. 74 16
      src/views/elderly/apply/nine-precautions/anti-entertainment/index.vue
  9. 70 33
      src/views/elderly/apply/nine-precautions/asphyxiation-by-choking/index.vue
  10. 70 59
      src/views/elderly/apply/nine-precautions/attack/index.vue
  11. 71 59
      src/views/elderly/apply/nine-precautions/commit-suicide/index.vue
  12. 74 62
      src/views/elderly/apply/nine-precautions/communication/index.vue
  13. 74 33
      src/views/elderly/apply/nine-precautions/daily-life/index.vue
  14. 74 33
      src/views/elderly/apply/nine-precautions/empyrosis/index.vue
  15. 74 33
      src/views/elderly/apply/nine-precautions/equilibrium/index.vue
  16. 74 33
      src/views/elderly/apply/nine-precautions/fall-down/index.vue
  17. 74 33
      src/views/elderly/apply/nine-precautions/fall-prevention-measures/index.vue
  18. 79 4
      src/views/elderly/apply/nine-precautions/nutritional-risk/index.vue
  19. 74 33
      src/views/elderly/apply/nine-precautions/pressure-sores/index.vue
  20. 29 12
      src/views/elderly/apply/nine-precautions/risk-disclosure-statement/index.vue
  21. 74 33
      src/views/elderly/apply/nine-precautions/wander-away/index.vue
  22. 31 7
      src/views/elderly/contracts/ContractManageForm.vue
  23. 50 35
      src/views/elderly/contracts/components/ContractBody.vue
  24. 91 2
      src/views/elderly/contracts/components/DocumentAttachmentBody.vue
  25. 25 9
      src/views/elderly/contracts/components/RoomFacilitiesEquipmentBody.vue
  26. 6 3
      src/views/elderly/elder/family-appointment/time-setting/index.vue
  27. 3 2
      vite.config.ts

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 3496
public/pdf.worker.mjs


+ 392 - 0
scripts/add-export-to-nine-precautions-v2.js

@@ -0,0 +1,392 @@
+const fs = require('fs')
+const path = require('path')
+const { execSync } = require('child_process')
+
+const baseDir = path.resolve(__dirname, '../src/views/elderly/apply/nine-precautions')
+
+const configs = [
+  {
+    dir: 'MMSE',
+    pageApi: 'mmseGetPage',
+    title: 'MMSE认知评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'info'
+  },
+  {
+    dir: 'anti-entertainment',
+    pageApi: 'entertainmentPage',
+    title: '防文娱活动意外评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'asphyxiation-by-choking',
+    pageApi: 'asphyxiationPage',
+    title: '防噎食评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'attack',
+    pageApi: 'attackRiskPage',
+    title: '攻击风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'info'
+  },
+  {
+    dir: 'commit-suicide',
+    pageApi: 'ngasrPage',
+    title: '自伤自杀风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'info'
+  },
+  {
+    dir: 'communication',
+    pageApi: 'perceptionPage',
+    title: '感知沟通评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'info'
+  },
+  {
+    dir: 'daily-life',
+    pageApi: 'dailyLifePage',
+    title: '日常生活活动能力评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '结果等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'result'
+  },
+  {
+    dir: 'empyrosis',
+    pageApi: 'burnPreventionPage',
+    title: '防烫伤评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'equilibrium',
+    pageApi: 'equilibriumPage',
+    title: '平衡能力评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'fall-down',
+    pageApi: 'fallDownPage',
+    title: '跌倒风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'fall-prevention-measures',
+    pageApi: 'fallPreventionPage',
+    title: '防坠床评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'pressure-sores',
+    pageApi: 'pressureSoresPage',
+    title: '防压疮评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'nutritional-risk',
+    pageApi: 'nutritionalRiskPage',
+    title: '营养风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '量表总分' },
+      { key: 'riskLevelText', title: '评估结果' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'result'
+  },
+  {
+    dir: 'wander-away',
+    pageApi: 'wanderAwayPage',
+    title: '防走失风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  }
+]
+
+function buildExportFunction(config) {
+  const { pageApi, title, columns, riskMode } = config
+  const headersStr = JSON.stringify(columns, null, 6)
+    .replace(/"/g, "'")
+    .replace(/\n      /g, '\n      ')
+
+  let riskLevelProcess = ''
+  if (riskMode === 'info') {
+    riskLevelProcess = `const riskInfo = getRiskLevelInfo(item.assessData)
+      row.riskLevelText = riskInfo.text || '-'`
+  } else if (riskMode === 'text') {
+    riskLevelProcess = `row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'`
+  } else if (riskMode === 'result') {
+    riskLevelProcess = `row.riskLevelText = getResultLevelText(item.riskLevel) || '-'`
+  }
+
+  return `// 打开导出弹窗
+const handleImportCard = async () => {
+  exportLoading.value = true
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await ${pageApi}(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      ${riskLevelProcess}
+      return row
+    })
+
+    const headers = ${headersStr}
+
+    exportWithExpandedObjectArrays(processedData, headers, \`${title}_\${new Date().getTime()}.xlsx\`, '${title}')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
+}
+`
+}
+
+// 从 git 读取原始文件
+function readOriginal(relativePath) {
+  return execSync(`git show HEAD:${relativePath}`, {
+    cwd: path.resolve(__dirname, '..'),
+    encoding: 'utf-8'
+  })
+}
+
+function removeBlockByRegex(content, regex) {
+  const match = content.match(regex)
+  if (!match) return content
+  const start = match.index
+  let depth = 0
+  let end = start
+  for (let i = start; i < content.length; i++) {
+    if (content[i] === '{') depth++
+    if (content[i] === '}') {
+      depth--
+      if (depth === 0) {
+        end = i + 1
+        break
+      }
+    }
+  }
+  let before = content.slice(0, start)
+  let after = content.slice(end)
+  // 去掉后面多余的换行
+  if (after.startsWith('\n')) after = after.slice(1)
+  if (after.startsWith('\n')) after = after.slice(1)
+  return before + after
+}
+
+function processFile(config) {
+  const relativePath = `src/views/elderly/apply/nine-precautions/${config.dir}/index.vue`
+  const filePath = path.resolve(__dirname, '..', relativePath)
+  let content = readOriginal(relativePath)
+
+  // 1. 添加 ButtonImport 导入
+  const buttonAddImport = "import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'"
+  if (content.includes(buttonAddImport)) {
+    content = content.replace(
+      buttonAddImport,
+      `${buttonAddImport}\nimport ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'`
+    )
+  } else {
+    // nutritional-risk 没有 ButtonAdd import,ButtonAdd 是全局注册的
+    content = content.replace(
+      '<script setup lang="ts">',
+      '<script setup lang="ts">\nimport ButtonImport from \'@/components/ButtonImport/src/ButtonImport.vue\''
+    )
+  }
+
+  // 2. 添加 exportWithExpandedObjectArrays 导入
+  const apiImportMatch = content.match(/import \{[^}]+\} from '@\/api\/social-work'/)
+  if (apiImportMatch) {
+    const insertPos = apiImportMatch.index + apiImportMatch[0].length
+    content = content.slice(0, insertPos) + "\nimport { exportWithExpandedObjectArrays } from '@/utils/excel-export'" + content.slice(insertPos)
+  } else {
+    content = content.replace(
+      '<script setup lang="ts">',
+      '<script setup lang="ts">\nimport { exportWithExpandedObjectArrays } from \'@/utils/excel-export\''
+    )
+  }
+
+  // 3. 添加导出按钮
+  content = content.replace(
+    /<ButtonAdd @click="openForm\(undefined\)"\s*\/>/g,
+    '<ButtonAdd @click="openForm(undefined)" />\n      <ButtonImport @click="handleImportCard" />'
+  )
+  // 移除旧的注释导入按钮
+  content = content.replace(/\s*<!--\s*<ButtonImport[^>]*>\s*-->\s*/g, '\n')
+
+  // 4. 移除 BatchExportDialog
+  content = content.replace(
+    /\s*<!-- 通用批量导出弹窗 -->\s*<BatchExportDialog[\s\S]*?<\/BatchExportDialog>/,
+    ''
+  )
+
+  // 5. 移除旧的 handleImportCard / handleBatchExport / handleExport 空壳函数
+  content = removeBlockByRegex(
+    content,
+    /\/\/ 打开导出弹窗\s*const handleImportCard = async \(\) => \{/
+  )
+  content = removeBlockByRegex(
+    content,
+    /\/\/ 处理批量导出\s*const handleBatchExport = async \(batch: number, count: number\) => \{/
+  )
+  content = removeBlockByRegex(
+    content,
+    /const handleExport = \(\) => \{/
+  )
+
+  // 6. 精简状态管理为只保留 exportLoading
+  content = content.replace(
+    /\n\/\/ 状态管理\s*const showBatchExport = ref\(false\)\s*const exportConfig = ref\(\{[\s\S]*?description: \[\] as string\[\]\s*\}\)\s*const exportLoading = ref\(false\)\s*/,
+    '\nconst exportLoading = ref(false)\n'
+  )
+
+  // 7. 插入新的 handleImportCard 函数
+  const exportFunc = buildExportFunction(config)
+  const queryFormRefPattern = /const queryFormRef = ref\(\)\s*\/\/ 搜索的表单/
+  if (queryFormRefPattern.test(content)) {
+    content = content.replace(queryFormRefPattern, `const queryFormRef = ref() // 搜索的表单\n\n${exportFunc}`)
+  } else {
+    content = content.replace(
+      /const queryFormRef = ref\(\)\s*$/m,
+      `const queryFormRef = ref()\n\n${exportFunc}`
+    )
+  }
+
+  fs.writeFileSync(filePath, content, 'utf-8')
+  console.log(`已处理:${filePath}`)
+}
+
+configs.forEach(processFile)

+ 383 - 0
scripts/add-export-to-nine-precautions.js

@@ -0,0 +1,383 @@
+const fs = require('fs')
+const path = require('path')
+
+const baseDir = path.resolve(__dirname, '../src/views/elderly/apply/nine-precautions')
+
+const configs = [
+  {
+    dir: 'MMSE',
+    pageApi: 'mmseGetPage',
+    title: 'MMSE认知评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'info'
+  },
+  {
+    dir: 'anti-entertainment',
+    pageApi: 'entertainmentPage',
+    title: '防文娱活动意外评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'asphyxiation-by-choking',
+    pageApi: 'asphyxiationPage',
+    title: '防噎食评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'attack',
+    pageApi: 'attackRiskPage',
+    title: '攻击风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'info'
+  },
+  {
+    dir: 'commit-suicide',
+    pageApi: 'ngasrPage',
+    title: '自伤自杀风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'info'
+  },
+  {
+    dir: 'communication',
+    pageApi: 'perceptionPage',
+    title: '感知沟通评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'info'
+  },
+  {
+    dir: 'daily-life',
+    pageApi: 'dailyLifePage',
+    title: '日常生活活动能力评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '结果等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'result'
+  },
+  {
+    dir: 'empyrosis',
+    pageApi: 'burnPreventionPage',
+    title: '防烫伤评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'equilibrium',
+    pageApi: 'equilibriumPage',
+    title: '平衡能力评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'fall-down',
+    pageApi: 'fallDownPage',
+    title: '跌倒风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'fall-prevention-measures',
+    pageApi: 'fallPreventionPage',
+    title: '防坠床评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'pressure-sores',
+    pageApi: 'pressureSoresPage',
+    title: '防压疮评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  },
+  {
+    dir: 'nutritional-risk',
+    pageApi: 'nutritionalRiskPage',
+    title: '营养风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '量表总分' },
+      { key: 'riskLevelText', title: '评估结果' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'result'
+  },
+  {
+    dir: 'wander-away',
+    pageApi: 'wanderAwayPage',
+    title: '防走失风险评估',
+    columns: [
+      { key: 'orgName', title: '机构名称' },
+      { key: 'elderName', title: '长者姓名' },
+      { key: 'assessor', title: '评估人' },
+      { key: 'assessDate', title: '记录日期' },
+      { key: 'assessScore', title: '评估总得分' },
+      { key: 'riskLevelText', title: '风险等级' },
+      { key: 'creator', title: '记录人' }
+    ],
+    riskMode: 'text'
+  }
+]
+
+function buildExportFunction(config) {
+  const { pageApi, title, columns, riskMode } = config
+  const headersStr = JSON.stringify(columns, null, 6).replace(/"/g, "'")
+
+  let riskLevelProcess = ''
+  if (riskMode === 'info') {
+    riskLevelProcess = `const riskInfo = getRiskLevelInfo(item.assessData)
+      row.riskLevelText = riskInfo.text || '-'`
+  } else if (riskMode === 'text') {
+    riskLevelProcess = `row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'`
+  } else if (riskMode === 'result') {
+    riskLevelProcess = `row.riskLevelText = getResultLevelText(item.riskLevel) || '-'`
+  }
+
+  return `
+// 打开导出弹窗
+const handleImportCard = async () => {
+  exportLoading.value = true
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await ${pageApi}(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      ${riskLevelProcess}
+      return row
+    })
+
+    const headers = ${headersStr}
+
+    exportWithExpandedObjectArrays(processedData, headers, \`${title}_\${new Date().getTime()}.xlsx\`, '${title}')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
+}
+`
+}
+
+function removeBlock(content, startRegex, endMarker) {
+  const startMatch = content.match(startRegex)
+  if (!startMatch) return content
+  const startIndex = startMatch.index
+  let depth = 0
+  let endIndex = startIndex
+  for (let i = startIndex; i < content.length; i++) {
+    if (content[i] === '{') depth++
+    if (content[i] === '}') {
+      depth--
+      if (depth === 0) {
+        endIndex = i + 1
+        break
+      }
+    }
+  }
+  // 包含到 endMarker 之前或之后的换行
+  let before = content.slice(0, startIndex)
+  let after = content.slice(endIndex)
+  if (after.startsWith('\n')) after = after.slice(1)
+  return before + after
+}
+
+function processFile(config) {
+  const filePath = path.join(baseDir, config.dir, 'index.vue')
+  if (!fs.existsSync(filePath)) {
+    console.log(`跳过:${filePath} 不存在`)
+    return
+  }
+
+  let content = fs.readFileSync(filePath, 'utf-8')
+
+  // 1. 添加 ButtonImport 导入(如果还没有)
+  if (!content.includes("import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'")) {
+    content = content.replace(
+      "import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'",
+      "import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'\nimport ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'"
+    )
+  }
+
+  // 2. 添加 exportWithExpandedObjectArrays 导入
+  if (!content.includes("import { exportWithExpandedObjectArrays } from '@/utils/excel-export'")) {
+    const apiImportMatch = content.match(/import \{[^}]+\} from '@\/api\/social-work'/)
+    if (apiImportMatch) {
+      const insertPos = apiImportMatch.index + apiImportMatch[0].length
+      content = content.slice(0, insertPos) + "\nimport { exportWithExpandedObjectArrays } from '@/utils/excel-export'" + content.slice(insertPos)
+    } else {
+      content = content.replace(
+        '<script setup lang="ts">',
+        '<script setup lang="ts">\nimport { exportWithExpandedObjectArrays } from \'@/utils/excel-export\''
+      )
+    }
+  }
+
+  // 3. 添加导出按钮(紧跟 ButtonAdd 之后,并移除原有的注释导入按钮)
+  content = content.replace(
+    /<ButtonAdd @click="openForm\(undefined\)"\s*\/>/g,
+    '<ButtonAdd @click="openForm(undefined)" />\n      <ButtonImport @click="handleImportCard" />'
+  )
+  // 移除旧的注释按钮行
+  content = content.replace(/\s*<!--\s*<ButtonImport[^>]*>\s*-->\s*/g, '\n')
+
+  // 4. 移除 BatchExportDialog 组件
+  content = content.replace(
+    /\s*<!-- 通用批量导出弹窗 -->\s*<BatchExportDialog[\s\S]*?<\/BatchExportDialog>/,
+    ''
+  )
+
+  // 5. 移除已存在的 handleImportCard / handleBatchExport / handleExport 空壳函数
+  content = content.replace(
+    /\/\/ 打开导出弹窗\s*const handleImportCard = async \(\) => \{[\s\S]*?\}\s*/,
+    ''
+  )
+  content = removeBlock(
+    content,
+    /\/\/ 处理批量导出\s*const handleBatchExport = async \(batch: number, count: number\) => \{/,
+    ''
+  )
+  content = removeBlock(
+    content,
+    /const handleExport = \(\) => \{/,
+    ''
+  )
+
+  // 6. 精简状态管理为只保留 exportLoading
+  content = content.replace(
+    /\n\/\/ 状态管理\s*const showBatchExport = ref\(false\)\s*const exportConfig = ref\(\{[\s\S]*?description: \[\] as string\[\]\s*\}\)\s*const exportLoading = ref\(false\)\s*/,
+    '\nconst exportLoading = ref(false)\n'
+  )
+
+  // 7. 插入新的 handleImportCard 函数
+  const exportFunc = buildExportFunction(config)
+  // 优先在 queryFormRef 定义后插入
+  const queryFormRefPattern = /const queryFormRef = ref\(\)\s*\/\/ 搜索的表单/
+  if (queryFormRefPattern.test(content)) {
+    content = content.replace(queryFormRefPattern, `const queryFormRef = ref() // 搜索的表单\n${exportFunc}`)
+  } else {
+    content = content.replace(
+      /const queryFormRef = ref\(\)\s*$/m,
+      `const queryFormRef = ref()\n${exportFunc}`
+    )
+  }
+
+  fs.writeFileSync(filePath, content, 'utf-8')
+  console.log(`已处理:${filePath}`)
+}
+
+configs.forEach(processFile)

+ 60 - 0
scripts/cleanup-nine-precautions-export.js

@@ -0,0 +1,60 @@
+const fs = require('fs')
+const path = require('path')
+
+const baseDir = path.resolve(__dirname, '../src/views/elderly/apply/nine-precautions')
+const dirs = fs.readdirSync(baseDir).filter(d => fs.statSync(path.join(baseDir, d)).isDirectory())
+
+dirs.forEach(dir => {
+  const filePath = path.join(baseDir, dir, 'index.vue')
+  if (!fs.existsSync(filePath)) return
+  let content = fs.readFileSync(filePath, 'utf-8')
+  let modified = false
+
+  // 1. 移除 BatchExportDialog 组件(支持有无注释前缀)
+  const batchDialogRegex = /(\s*<!-- 通用批量导出弹窗 -->\s*)?<BatchExportDialog[\s\S]*?<\/BatchExportDialog>/
+  if (batchDialogRegex.test(content)) {
+    content = content.replace(batchDialogRegex, '')
+    modified = true
+  }
+
+  // 2. 修复 ButtonAdd 后未自动导入 ButtonImport 的情况( nutritional-risk 等)
+  if (content.includes('<ButtonImport') && !content.includes("import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'")) {
+    // 在 script 标签后的第一行 import 处插入
+    content = content.replace(
+      '<script setup lang="ts">',
+      '<script setup lang="ts">\nimport ButtonImport from \'@/components/ButtonImport/src/ButtonImport.vue\''
+    )
+    modified = true
+  }
+
+  // 3. 移除旧的空壳 handleImportCard / handleBatchExport 残留
+  const oldHandleRegex = /\/\/ 打开导出弹窗\s*const handleImportCard = async \(\) => \{[\s\S]*?\}\s*/
+  if (oldHandleRegex.test(content)) {
+    content = content.replace(oldHandleRegex, '')
+    modified = true
+  }
+
+  // 4. 整理 headers 缩进:将 6 空格缩进的单引号 key/title 改为 2 空格
+  content = content.replace(/\n            'key': /g, "\n      'key': ")
+  content = content.replace(/\n            'title': /g, "\n      'title': ")
+
+  // 5. 修正 div 闭合标签缩进:将 ButtonImport 后的 </div> 单独一行并正确缩进
+  content = content.replace(
+    /(<ButtonImport @click="handleImportCard" \/>)\n      <!--      <el-button @click="inputH" type="success">.*<\/el-button>-->\n<\/div>/g,
+    '$1\n    </div>'
+  )
+
+  // 兜底:把 "-->\n</div>" 替换为 "-->\n    </div>"
+  content = content.replace(/-->\n<\/div>/g, '-->\n    </div>')
+
+  // 6. 将 exportData.map 中的 const row = { ... } 改为 const row: any = { ... }
+  content = content.replace(
+    /const processedData = exportData\.map\(\(item\) => \{\n      const row = \{/g,
+    'const processedData = exportData.map((item) => {\n      const row: any = {'
+  )
+
+  if (modified || content !== fs.readFileSync(filePath, 'utf-8')) {
+    fs.writeFileSync(filePath, content, 'utf-8')
+    console.log(`已清理:${filePath}`)
+  }
+})

+ 27 - 0
scripts/remove-batch-dialog.js

@@ -0,0 +1,27 @@
+const fs = require('fs')
+const path = require('path')
+
+const baseDir = path.resolve(__dirname, '../src/views/elderly/apply/nine-precautions')
+const dirs = fs.readdirSync(baseDir).filter(d => fs.statSync(path.join(baseDir, d)).isDirectory())
+
+dirs.forEach(dir => {
+  const filePath = path.join(baseDir, dir, 'index.vue')
+  if (!fs.existsSync(filePath)) return
+  let content = fs.readFileSync(filePath, 'utf-8')
+  const original = content
+
+  // 移除 BatchExportDialog 组件:可能是自闭合或成对标签
+  content = content.replace(
+    /\s*<!--[^>]*批量导出[^>]*-->\s*<BatchExportDialog[\s\S]*?\/>/,
+    ''
+  )
+  content = content.replace(
+    /\s*<BatchExportDialog[\s\S]*?\/>/,
+    ''
+  )
+
+  if (content !== original) {
+    fs.writeFileSync(filePath, content, 'utf-8')
+    console.log(`已移除 BatchExportDialog:${filePath}`)
+  }
+})

+ 3 - 1
src/components/UploadFile/src/useUpload.ts

@@ -203,7 +203,9 @@ export const pdfFileToImageFiles = async (
   const { scale = 2, quality = 0.92 } = options
   const pdfjsLib = await import('pdfjs-dist')
   const pdfjs: any = pdfjsLib
-  pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorkerUrl
+  // 用版本号做 query 参数防缓存:文件名固定(兼容云端 nginx 配置),
+  // 但 URL 随 pdfjs 版本变化,避免主库升级后浏览器命中旧版本 worker 缓存导致版本不匹配
+  pdfjs.GlobalWorkerOptions.workerSrc = `${pdfjsWorkerUrl}?v=${pdfjs.version}`
 
   const arrayBuffer = await fileToArrayBuffer(file)
   const pdfDocument = await pdfjs.getDocument({ data: arrayBuffer }).promise

+ 74 - 45
src/views/elderly/apply/nine-precautions/MMSE/index.vue

@@ -82,9 +82,9 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
       <!--      <el-button @click="inputH" type="success"><Icon icon="fa:cloud-upload" :size="16" class="mr-1"/>导入</el-button>-->
-      <!--      <ButtonImport @click="handleImportCard"  />-->
-    </div>
+</div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
         <template #default="scope">
@@ -193,10 +193,12 @@
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { getRiskLevelInfo } from '@/utils/risk-assessment'
 import { useUserStore } from '@/store/modules/user'
 import Import from '@/components/ImportFile/index.vue'
 import { mmseDelete, mmseGetPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 import { ref } from 'vue'
 import { getBuildList } from '@/api/system/badManage'
@@ -209,20 +211,7 @@ const importRef = ref()
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -235,41 +224,81 @@ let queryParams = reactive({
 })
 const queryFormRef = ref() // 搜索的表单
 
-const inputH = () => {
-  importRef.value.open(queryParams.tenantIds[0])
-}
 // 打开导出弹窗
 const handleImportCard = async () => {
-  // showBatchExport.value = true
-}
-
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
   exportLoading.value = true
-  console.log(batch, count)
-  // try {
-  //   let queryParams = {
-  //     pageNo: batch,
-  //     pageSize: count,
-  //     tenantId: userStore.orgTenantId[0]
-  //   }
-  //   const list = await careRecordsPage(queryParams)
-  //   if (list.length <= 0) {
-  //     message.error('暂无数据可以导出!')
-  //     return
-  //   }
-  //   const headers = [
-  //     { key: 'organizationName', title: '机构名称' },
-  //     { key: 'visitName', title: '姓名' },
-  //     { key: 'visitPhone', title: '手机号' },
-  //     { key: 'visitDate', title: '预约时间' },
-  //     { key: 'accompanyCount', title: '陪同人数' },
-  //     { key: 'reason', title: '理由' }
-  //   ]
-  //   exportWithExpandedObjectArrays(list, headers, `医疗护理记录${formatToDateTime()}.xlsx`, '医疗护理记录')
-  // } catch (_) {}
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await mmseGetPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      const riskInfo = getRiskLevelInfo(item.assessData)
+      row.riskLevelText = riskInfo.text || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `MMSE认知评估_${new Date().getTime()}.xlsx`, 'MMSE认知评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
+
+const inputH = () => {
+  importRef.value.open(queryParams.tenantIds[0])
+}
 /** 查询列表 */
 const getList = async () => {
   loading.value = true

+ 74 - 16
src/views/elderly/apply/nine-precautions/anti-entertainment/index.vue

@@ -77,6 +77,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -179,6 +180,7 @@
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import {
@@ -187,6 +189,7 @@ import {
   fallDownDelete,
   fallDownPage
 } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 import { getBuildList } from '@/api/system/badManage'
 import { ref } from 'vue'
@@ -198,20 +201,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -225,10 +215,78 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await entertainmentPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'assessScore',
+            'title': '评估总得分'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `防文娱活动意外评估_${new Date().getTime()}.xlsx`, '防文娱活动意外评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 70 - 33
src/views/elderly/apply/nine-precautions/asphyxiation-by-choking/index.vue

@@ -51,6 +51,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -140,31 +141,16 @@
   </ContentWrap>
 
   <AddForm ref="formRef" @success="getList" />
-
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
 </template>
 
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import { asphyxiationDelete, asphyxiationPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 
 const message = useMessage()
@@ -174,20 +160,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -199,10 +172,74 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await asphyxiationPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `防噎食评估_${new Date().getTime()}.xlsx`, '防噎食评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 70 - 59
src/views/elderly/apply/nine-precautions/attack/index.vue

@@ -82,9 +82,9 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
       <!--      <el-button @click="inputH" type="success"><Icon icon="fa:cloud-upload" :size="16" class="mr-1"/>导入</el-button>-->
-      <!--      <ButtonImport @click="handleImportCard"  />-->
-    </div>
+</div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
         <template #default="scope">
@@ -177,23 +177,6 @@
 
   <AddForm ref="formRef" @success="getList" />
 
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
-
   <Import
     ref="importRef"
     @success="getList"
@@ -216,6 +199,7 @@ import { formatTimestamp, getCurrentMonthRange } from '@/utils/dateUtil'
 import Import from '@/components/ImportFile/index.vue'
 import { restraintCreatePage, restraintDelete } from '@/api/elderly/nursing/keep-fit'
 import { attackRiskDelete, attackRiskPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { getRiskLevelInfo } from '@/utils/risk-assessment'
 import { findLabelById } from '@/utils/dict'
 import { ref } from 'vue'
@@ -229,20 +213,7 @@ const importRef = ref()
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -258,36 +229,76 @@ const queryFormRef = ref() // 搜索的表单
 
 // 打开导出弹窗
 const handleImportCard = async () => {
-  // showBatchExport.value = true
-}
-
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
   exportLoading.value = true
-  console.log(batch, count)
-  // try {
-  //   let queryParams = {
-  //     pageNo: batch,
-  //     pageSize: count,
-  //     tenantId: userStore.orgTenantId[0]
-  //   }
-  //   const list = await careRecordsPage(queryParams)
-  //   if (list.length <= 0) {
-  //     message.error('暂无数据可以导出!')
-  //     return
-  //   }
-  //   const headers = [
-  //     { key: 'organizationName', title: '机构名称' },
-  //     { key: 'visitName', title: '姓名' },
-  //     { key: 'visitPhone', title: '手机号' },
-  //     { key: 'visitDate', title: '预约时间' },
-  //     { key: 'accompanyCount', title: '陪同人数' },
-  //     { key: 'reason', title: '理由' }
-  //   ]
-  //   exportWithExpandedObjectArrays(list, headers, `医疗护理记录${formatToDateTime()}.xlsx`, '医疗护理记录')
-  // } catch (_) {}
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await attackRiskPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      const riskInfo = getRiskLevelInfo(item.assessData)
+      row.riskLevelText = riskInfo.text || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `攻击风险评估_${new Date().getTime()}.xlsx`, '攻击风险评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
+
 /** 查询列表 */
 const getList = async () => {
   loading.value = true

+ 71 - 59
src/views/elderly/apply/nine-precautions/commit-suicide/index.vue

@@ -56,9 +56,9 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
       <!--      <el-button @click="inputH" type="success"><Icon icon="fa:cloud-upload" :size="16" class="mr-1"/>导入</el-button>-->
-      <!--      <ButtonImport @click="handleImportCard"  />-->
-    </div>
+</div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
         <template #default="scope">
@@ -151,23 +151,6 @@
 
   <AddForm ref="formRef" @success="getList" />
 
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
-
   <Import
     ref="importRef"
     @success="getList"
@@ -184,9 +167,11 @@
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import Import from '@/components/ImportFile/index.vue'
 import { ngasrDelete, ngasrPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { getRiskLevelInfo } from '@/utils/risk-assessment'
 import { findLabelById } from '@/utils/dict'
 const message = useMessage() // 消息弹窗
@@ -198,20 +183,7 @@ const importRef = ref()
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -225,36 +197,76 @@ const queryFormRef = ref() // 搜索的表单
 
 // 打开导出弹窗
 const handleImportCard = async () => {
-  // showBatchExport.value = true
-}
-
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
   exportLoading.value = true
-  console.log(batch, count)
-  // try {
-  //   let queryParams = {
-  //     pageNo: batch,
-  //     pageSize: count,
-  //     tenantId: userStore.orgTenantId[0]
-  //   }
-  //   const list = await careRecordsPage(queryParams)
-  //   if (list.length <= 0) {
-  //     message.error('暂无数据可以导出!')
-  //     return
-  //   }
-  //   const headers = [
-  //     { key: 'organizationName', title: '机构名称' },
-  //     { key: 'visitName', title: '姓名' },
-  //     { key: 'visitPhone', title: '手机号' },
-  //     { key: 'visitDate', title: '预约时间' },
-  //     { key: 'accompanyCount', title: '陪同人数' },
-  //     { key: 'reason', title: '理由' }
-  //   ]
-  //   exportWithExpandedObjectArrays(list, headers, `医疗护理记录${formatToDateTime()}.xlsx`, '医疗护理记录')
-  // } catch (_) {}
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await ngasrPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      const riskInfo = getRiskLevelInfo(item.assessData)
+      row.riskLevelText = riskInfo.text || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `自伤自杀风险评估_${new Date().getTime()}.xlsx`, '自伤自杀风险评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
+
 /** 查询列表 */
 const getList = async () => {
   loading.value = true

+ 74 - 62
src/views/elderly/apply/nine-precautions/communication/index.vue

@@ -82,9 +82,9 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
       <!--      <el-button @click="inputH" type="success"><Icon icon="fa:cloud-upload" :size="16" class="mr-1"/>导入</el-button>-->
-      <!--      <ButtonImport @click="handleImportCard"  />-->
-    </div>
+</div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
         <template #default="scope">
@@ -177,23 +177,6 @@
 
   <AddForm ref="formRef" @success="getList" />
 
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
-
   <Import
     ref="importRef"
     @success="getList"
@@ -210,10 +193,12 @@
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { getRiskLevelInfo } from '@/utils/risk-assessment'
 import { useUserStore } from '@/store/modules/user'
 import Import from '@/components/ImportFile/index.vue'
 import { perceptionDelete, perceptionPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 import { getBuildList } from '@/api/system/badManage'
 import { ref } from 'vue'
@@ -226,20 +211,7 @@ const importRef = ref()
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -252,41 +224,81 @@ let queryParams = reactive({
 })
 const queryFormRef = ref() // 搜索的表单
 
-const inputH = () => {
-  importRef.value.open(queryParams.tenantIds[0])
-}
 // 打开导出弹窗
 const handleImportCard = async () => {
-  // showBatchExport.value = true
-}
-
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
   exportLoading.value = true
-  console.log(batch, count)
-  // try {
-  //   let queryParams = {
-  //     pageNo: batch,
-  //     pageSize: count,
-  //     tenantId: userStore.orgTenantId[0]
-  //   }
-  //   const list = await careRecordsPage(queryParams)
-  //   if (list.length <= 0) {
-  //     message.error('暂无数据可以导出!')
-  //     return
-  //   }
-  //   const headers = [
-  //     { key: 'organizationName', title: '机构名称' },
-  //     { key: 'visitName', title: '姓名' },
-  //     { key: 'visitPhone', title: '手机号' },
-  //     { key: 'visitDate', title: '预约时间' },
-  //     { key: 'accompanyCount', title: '陪同人数' },
-  //     { key: 'reason', title: '理由' }
-  //   ]
-  //   exportWithExpandedObjectArrays(list, headers, `医疗护理记录${formatToDateTime()}.xlsx`, '医疗护理记录')
-  // } catch (_) {}
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await perceptionPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      const riskInfo = getRiskLevelInfo(item.assessData)
+      row.riskLevelText = riskInfo.text || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `感知沟通评估_${new Date().getTime()}.xlsx`, '感知沟通评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
+
+const inputH = () => {
+  importRef.value.open(queryParams.tenantIds[0])
+}
 /** 查询列表 */
 const getList = async () => {
   loading.value = true

+ 74 - 33
src/views/elderly/apply/nine-precautions/daily-life/index.vue

@@ -51,6 +51,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -148,31 +149,16 @@
   </ContentWrap>
 
   <AddForm ref="formRef" @success="getList" />
-
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
 </template>
 
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import { dailyLifeDelete, dailyLifePage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 
 const message = useMessage()
@@ -182,20 +168,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -207,10 +180,78 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await dailyLifePage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getResultLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'assessScore',
+            'title': '评估总得分'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '结果等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `日常生活活动能力评估_${new Date().getTime()}.xlsx`, '日常生活活动能力评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 74 - 33
src/views/elderly/apply/nine-precautions/empyrosis/index.vue

@@ -51,6 +51,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -148,31 +149,16 @@
   </ContentWrap>
 
   <AddForm ref="formRef" @success="getList" />
-
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
 </template>
 
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import { burnPreventionDelete, burnPreventionPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 
 const message = useMessage()
@@ -182,20 +168,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -207,10 +180,78 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await burnPreventionPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'assessScore',
+            'title': '评估总得分'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `防烫伤评估_${new Date().getTime()}.xlsx`, '防烫伤评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 74 - 33
src/views/elderly/apply/nine-precautions/equilibrium/index.vue

@@ -51,6 +51,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -148,31 +149,16 @@
   </ContentWrap>
 
   <AddForm ref="formRef" @success="getList" />
-
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
 </template>
 
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import { equilibriumDelete, equilibriumPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 
 const message = useMessage()
@@ -182,20 +168,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -207,10 +180,78 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await equilibriumPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'assessScore',
+            'title': '评估总得分'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `平衡能力评估_${new Date().getTime()}.xlsx`, '平衡能力评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 74 - 33
src/views/elderly/apply/nine-precautions/fall-down/index.vue

@@ -51,6 +51,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -148,31 +149,16 @@
   </ContentWrap>
 
   <AddForm ref="formRef" @success="getList" />
-
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
 </template>
 
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import { fallDownDelete, fallDownPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 
 const message = useMessage()
@@ -182,20 +168,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -207,10 +180,78 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await fallDownPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'assessScore',
+            'title': '评估总得分'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `跌倒风险评估_${new Date().getTime()}.xlsx`, '跌倒风险评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 74 - 33
src/views/elderly/apply/nine-precautions/fall-prevention-measures/index.vue

@@ -51,6 +51,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -148,31 +149,16 @@
   </ContentWrap>
 
   <AddForm ref="formRef" @success="getList" />
-
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
 </template>
 
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import { fallPreventionDelete, fallPreventionPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 
 const message = useMessage()
@@ -182,20 +168,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -207,10 +180,78 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await fallPreventionPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'assessScore',
+            'title': '评估总得分'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `防坠床评估_${new Date().getTime()}.xlsx`, '防坠床评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 79 - 4
src/views/elderly/apply/nine-precautions/nutritional-risk/index.vue

@@ -1,7 +1,9 @@
 <script setup lang="ts">
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { onMounted, ref, reactive } from 'vue'
 import { ContentWrap } from '@/components/ContentWrap'
 import { nutritionalRiskPage, nutritionalRiskDelete } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import AddForm from './AddForm.vue'
 import { useUserStore } from '@/store/modules/user'
 import { tableHeaderColor } from '@/utils/table'
@@ -28,6 +30,82 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
+const exportLoading = ref(false)
+
+// 打开导出弹窗
+const handleImportCard = async () => {
+  exportLoading.value = true
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await nutritionalRiskPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getResultLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'assessScore',
+            'title': '量表总分'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '评估结果'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `营养风险评估_${new Date().getTime()}.xlsx`, '营养风险评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
+}
+
 /** 查询列表 */
 const getList = async () => {
   loading.value = true
@@ -84,10 +162,6 @@ const openClose = async (row: any) => {
   }
 }
 
-const handleExport = () => {
-  message.info('导出功能开发中')
-}
-
 const getResultLevelType = (level: string) => {
   const typeMap: Record<string, string> = {
     good: 'success',
@@ -201,6 +275,7 @@ onMounted(async () => {
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">

+ 74 - 33
src/views/elderly/apply/nine-precautions/pressure-sores/index.vue

@@ -51,6 +51,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -148,31 +149,16 @@
   </ContentWrap>
 
   <AddForm ref="formRef" @success="getList" />
-
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
 </template>
 
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import { pressureSoresDelete, pressureSoresPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 
 const message = useMessage()
@@ -182,20 +168,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -207,10 +180,78 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await pressureSoresPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'assessScore',
+            'title': '评估总得分'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `防压疮评估_${new Date().getTime()}.xlsx`, '防压疮评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 29 - 12
src/views/elderly/apply/nine-precautions/risk-disclosure-statement/index.vue

@@ -48,9 +48,7 @@
         <el-button type="primary" @click="handleAdd">
           <Icon icon="ep:plus" class="mr-5px" /> 新增
         </el-button>
-        <el-button type="success" @click="handleExport">
-          <Icon icon="ep:upload" class="mr-5px" /> 导出
-        </el-button>
+        <ButtonImport @click="handleImportCard" />
       </template>
     </TabBarBtn>
 
@@ -242,6 +240,7 @@ import AttackForm from '@/views/elderly/apply/nine-precautions/attack/AddForm.vu
 import AntiEntertainmentForm from '@/views/elderly/apply/nine-precautions/anti-entertainment/AddForm.vue'
 import DailyLifeForm from '@/views/elderly/apply/nine-precautions/daily-life/AddForm.vue'
 import NutritionalRiskForm from '@/views/elderly/apply/nine-precautions/nutritional-risk/AddForm.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { formatToDateTime } from '@/utils/dateUtil'
 import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
@@ -381,16 +380,31 @@ const getRiskLevelText = (riskLevel: string) => {
   }
 }
 
-// 导出
-const handleExport = async () => {
+const exportLoading = ref(false)
+
+// 打开导出弹窗
+const handleImportCard = async () => {
+  exportLoading.value = true
   try {
-    if (!list.value || (list.value as any[]).length <= 0) {
-      message.error('暂无数据可以导出!')
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      floorName: queryParams.floorName,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await getSafetyRiskNoticePage(queryP)
+    const exportList = (data.list || []).map((item: any) => ({
+      ...item,
+      riskData: parseRiskData(item)
+    }))
+
+    if (exportList.length === 0) {
+      message.warning('暂无数据可导出')
       return
     }
 
-    // 预处理数据:解析 riskData 中各风险字段并映射为中文
-    const exportList = (list.value as any[]).map((row, index) => {
+    const processedData = exportList.map((row: any, index: number) => {
       const rd = row.riskData || {}
       return {
         index: index + 1,
@@ -436,14 +450,17 @@ const handleExport = async () => {
     ]
 
     exportWithExpandedObjectArrays(
-      exportList,
+      processedData,
       headers,
-      `安全风险告知书${formatToDateTime()}.xlsx`,
+      `安全风险告知书_${new Date().getTime()}.xlsx`,
       '安全风险告知书'
     )
+    message.success('导出成功')
   } catch (error) {
     console.error('导出失败:', error)
-    message.error('导出失败!')
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
   }
 }
 

+ 74 - 33
src/views/elderly/apply/nine-precautions/wander-away/index.vue

@@ -51,6 +51,7 @@
   <ContentWrap>
     <div class="mb-10px">
       <ButtonAdd @click="openForm(undefined)" />
+      <ButtonImport @click="handleImportCard" />
     </div>
     <el-table v-loading="loading" :data="list" :header-cell-style="tableHeaderColor">
       <el-table-column header-align="center" align="center" label="序号" width="60">
@@ -148,31 +149,16 @@
   </ContentWrap>
 
   <AddForm ref="formRef" @success="getList" />
-
-  <!-- 通用批量导出弹窗 -->
-  <BatchExportDialog
-    :show="showBatchExport"
-    :title="exportConfig.title"
-    :loading="exportLoading"
-    :batch-min="exportConfig.batchMin"
-    :batch-max="exportConfig.batchMax"
-    :count-min="exportConfig.countMin"
-    :count-max="exportConfig.countMax"
-    :default-batch="exportConfig.defaultBatch"
-    :default-count="exportConfig.defaultCount"
-    :description="exportConfig.description"
-    @update:show="showBatchExport = $event"
-    @confirm="handleBatchExport"
-    @cancel="showBatchExport = false"
-  />
 </template>
 
 <script setup lang="ts">
 import AddForm from './AddForm.vue'
 import ButtonAdd from '@/components/ButtonAdd/src/ButtonAdd.vue'
+import ButtonImport from '@/components/ButtonImport/src/ButtonImport.vue'
 import { useUserStore } from '@/store/modules/user'
 import { getCurrentMonthRange } from '@/utils/dateUtil'
 import { wanderAwayDelete, wanderAwayPage } from '@/api/social-work'
+import { exportWithExpandedObjectArrays } from '@/utils/excel-export'
 import { findLabelById } from '@/utils/dict'
 
 const message = useMessage()
@@ -182,20 +168,7 @@ const loading = ref(true)
 const total = ref(0)
 const list = ref([])
 
-// 状态管理
-const showBatchExport = ref(false)
-const exportConfig = ref({
-  title: '',
-  batchMin: 1,
-  batchMax: 999,
-  countMin: 1,
-  countMax: 200,
-  defaultBatch: 1,
-  defaultCount: 200,
-  description: [] as string[]
-})
 const exportLoading = ref(false)
-
 let queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -207,10 +180,78 @@ let queryParams = reactive({
 })
 const queryFormRef = ref()
 
-// 处理批量导出
-const handleBatchExport = async (batch: number, count: number) => {
+// 打开导出弹窗
+const handleImportCard = async () => {
   exportLoading.value = true
-  console.log(batch, count)
+  try {
+    const queryP = {
+      pageNo: 1,
+      pageSize: 9999,
+      elderName: queryParams.elderName,
+      assessor: queryParams.assessor,
+      assessDate: queryParams.assessDate,
+      tenantIds: queryParams.tenantIds
+    }
+    const data = await wanderAwayPage(queryP)
+    const exportData = data.list || []
+
+    if (exportData.length === 0) {
+      message.warning('暂无数据可导出')
+      return
+    }
+
+    const processedData = exportData.map((item) => {
+      const row: any = {
+        orgName: findLabelById(userStore.getOrgTenant.options, item.tenantId) || '',
+        elderName: item.elderName || '',
+        assessor: item.assessor || '',
+        assessDate: item.assessDate || '',
+        assessScore: item.assessScore ?? '',
+        creator: item.creator || ''
+      }
+      row.riskLevelText = getRiskLevelText(item.riskLevel) || '-'
+      return row
+    })
+
+    const headers = [
+      {
+            'key': 'orgName',
+            'title': '机构名称'
+      },
+      {
+            'key': 'elderName',
+            'title': '长者姓名'
+      },
+      {
+            'key': 'assessor',
+            'title': '评估人'
+      },
+      {
+            'key': 'assessDate',
+            'title': '记录日期'
+      },
+      {
+            'key': 'assessScore',
+            'title': '评估总得分'
+      },
+      {
+            'key': 'riskLevelText',
+            'title': '风险等级'
+      },
+      {
+            'key': 'creator',
+            'title': '记录人'
+      }
+]
+
+    exportWithExpandedObjectArrays(processedData, headers, `防走失风险评估_${new Date().getTime()}.xlsx`, '防走失风险评估')
+    message.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    message.error('导出失败,请重试')
+  } finally {
+    exportLoading.value = false
+  }
 }
 
 /** 查询列表 */

+ 31 - 7
src/views/elderly/contracts/ContractManageForm.vue

@@ -463,6 +463,12 @@ const toggleTextMode = () => {
 }
 
 const openAttachmentSelector = (attach: any) => {
+  if (attach.no == 3) {
+    const key = `attach_${attach.no}`
+    attachments[key] = { title: attach.title }
+    return
+  }
+
   selectorVisible.value = {
     show: true,
     current: `attach_${attach.no}`,
@@ -474,17 +480,17 @@ const openAttachmentSelector = (attach: any) => {
 const handleAttachmentDelete = (attach: any) => {
   const key = `attach_${attach.no}`
   // 固定内容附件(3=入住须知)删除后恢复默认展示
-  if (attach.no === 3) {
-    attachments[key] = { title: attach.title }
-  } else {
-    attachments[key] = null
-  }
+  // if (attach.no === 3) {
+  //   attachments[key] = { title: attach.title }
+  // } else {
+  attachments[key] = null
+  // }
   message.success(`已删除:${attach.title}`)
 }
 
 const handleAttachmentSelect = async (row: any) => {
   const key = selectorVisible.value.current
-  console.log('KEY值:', key, row, attachments)
+  //console.log('KEY值:', key, row, attachments)
   if (key) {
     const getDetail = attachmentDetailMap[key]
     let fullData = row
@@ -969,8 +975,26 @@ const renderAttachmentContent = (key: string) => {
     page-break-after: auto;
     break-after: auto;
   }
+  /* 附件容器与根元素宽度策略对齐合同主体 .a4-page(210mm),
+     解除 max-width:100% / width:100% 对父容器宽度的依赖,
+     避免 Teleport 打印容器 width:auto 计算偏小导致附件右侧留白 */
+  .print-container .print-attachment {
+    width: 210mm !important;
+    max-width: none !important;
+    margin: 0 !important;
+    padding: 0 !important;
+    box-sizing: border-box !important;
+    /* 每个附件强制另起一页:合同主体与附件、附件与附件之间都分页,
+       避免附件与前序内容挤在同一页 */
+    page-break-before: always;
+    break-before: page;
+  }
   .print-container .print-attachment .mgb {
-    padding-bottom: 30px !important;
+    width: 210mm !important;
+    max-width: none !important;
+    padding: 0 0 30px !important;
+    margin: 0 !important;
+    box-sizing: border-box !important;
   }
 
   /* 封面页保留完整 A4 高度并强制分页(可打印区域 265mm,@page margin 16mm) */

+ 50 - 35
src/views/elderly/contracts/components/ContractBody.vue

@@ -216,11 +216,8 @@ const calcMonthsBetween = (startStr: string, endStr: string): number | null => {
   const start = parseChineseDate(startStr)
   const end = parseChineseDate(endStr)
   if (!start || !end || end < start) return null
-  let months = (end.getFullYear() - start.getFullYear()) * 12 + (end.getMonth() - start.getMonth())
-  if (end.getDate() < start.getDate()) {
-    months--
-  }
-  return Math.max(0, months)
+  // 直接按"年月差"计算整月数,末尾差几天不影响(如 2026-08-15 → 2028-08-14 = 24 个月)
+  return (end.getFullYear() - start.getFullYear()) * 12 + (end.getMonth() - start.getMonth())
 }
 
 const isIdCardType = (papersType: any): boolean => {
@@ -363,13 +360,22 @@ const fillContractForm = (data: any) => {
   }
 
   contractForm.monthlyExpenses = data.monthlyExpenses || []
-  contractForm.oneTimeExpenses = data.oneTimeExpenses || []
+  //contractForm.oneTimeExpenses = data.oneTimeExpenses || []
   contractForm.stageExpenses = data.stageExpenses || []
-
+  //天河颐养院需要过滤掉‘一次性设施费’
   const oneTime = data.oneTimeExpenses || []
-  const deposit = findItem(oneTime, '押金')
-  if (deposit) {
-    const depositAmt = Number(deposit.actualAmount || deposit.amount || 0)
+  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)
@@ -377,7 +383,7 @@ const fillContractForm = (data: any) => {
     contractForm.depositAmtCn1 = numToChinese(depositAmt)
     contractForm.depositAmt2 = String(depositAmt)
     contractForm.depositAmtCn2 = numToChinese(depositAmt)
-    contractForm.depositType = deposit.itemName || ''
+    contractForm.depositType = firstItem.itemName || ''
   }
 
   const relative = (data.relativesList && data.relativesList[0]) || {}
@@ -453,11 +459,23 @@ const fetchContractData = async (row: any) => {
     //console.log('合同信息接口:', JSON.parse(res.contractInfo))
     if (res) {
       contractFormUpdate.value = res
-     // console.log('接口获取合同信息:', contractFormUpdate.value.contractInfo)
+      // 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)
           }
@@ -471,9 +489,8 @@ const fetchContractData = async (row: any) => {
           //console.log('config', config, key)
           let id = undefined
           try {
-             id = contractForm.attachments[key].id
-          }catch (e) {
-          }
+            id = contractForm.attachments[key].id
+          } catch (e) {}
           //console.log('id', id)
           if (id) {
             detailPromises.push(
@@ -482,7 +499,6 @@ const fetchContractData = async (row: any) => {
                 .then((detail) => {
                   //console.log('获取详情', detail)
                   attachmentsMap[key] = JSON.parse(detail.content)
-
                 })
                 .catch((err) => {
                   console.error(`获取附件详情失败: ${key}`, err)
@@ -504,6 +520,8 @@ const fetchContractData = async (row: any) => {
         try {
           const checkInRes = await getCheckInDetailByContractId(row.id)
           if (checkInRes) {
+            if (checkInRes) {
+            }
             fillContractForm(checkInRes)
           }
           contractForm.roomNo = contractFormUpdate.value.bedName
@@ -748,9 +766,7 @@ const selectedAttachmentItems = computed(() => {
 })
 
 const page24AttachmentItems = computed(() => selectedAttachmentItems.value.slice(0, 14))
-const page25AttachmentItems = computed(() =>
-  selectedAttachmentItems.value.slice(14)
-)
+const page25AttachmentItems = computed(() => selectedAttachmentItems.value.slice(14))
 
 const contractFormUpdate = ref({})
 
@@ -767,12 +783,10 @@ const saveContract = async () => {
             const data = JSON.parse(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)
@@ -1204,7 +1218,7 @@ watch(
           1.经协商,确定本合同期限为
           <FieldItem
             v-model="contractForm.contractMonths"
-            :is-text-mode="isTextMode"
+            :is-text-mode="true"
             width="60px"
             placeholder="12"
           />
@@ -2194,16 +2208,25 @@ watch(
         <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">
+            <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.向仲裁机构申请仲裁。
+            &nbsp;&nbsp;&nbsp;&nbsp;{{ contractForm.disputeMode === '1' ? '☑' : '□' }}
+            1.向仲裁机构申请仲裁。
           </p>
           <p class="content-text">
-            &nbsp;&nbsp;&nbsp;&nbsp;{{ contractForm.disputeMode === '2' ? '☑' : '□' }} 2.向有管辖权的人民法院提起诉讼。
+            &nbsp;&nbsp;&nbsp;&nbsp;{{ contractForm.disputeMode === '2' ? '☑' : '□' }}
+            2.向有管辖权的人民法院提起诉讼。
           </p>
         </template>
       </div>
@@ -2259,11 +2282,7 @@ watch(
           <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"
-          >
+          <p v-if="item.subTitle" class="content-text" style="padding-left: 3em; font-size: 13px">
             {{ item.subTitle }}
           </p>
         </template>
@@ -2284,11 +2303,7 @@ watch(
           <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"
-          >
+          <p v-if="item.subTitle" class="content-text" style="padding-left: 3em; font-size: 13px">
             {{ item.subTitle }}
           </p>
         </template>

+ 91 - 2
src/views/elderly/contracts/components/DocumentAttachmentBody.vue

@@ -30,14 +30,49 @@ const form = reactive<{ images: string[] }>({
   images: []
 })
 
+// 打印模式下背景图 div 需要的每张图片原始尺寸
+const imageSizes = ref<{ width: number; height: number }[]>([])
+
+const calcImageSize = (url: string): Promise<{ width: number; height: number }> => {
+  return new Promise((resolve) => {
+    const img = new Image()
+    img.onload = () => {
+      resolve({ width: img.naturalWidth, height: img.naturalHeight })
+    }
+    img.onerror = () => {
+      resolve({ width: 0, height: 0 })
+    }
+    img.src = url
+  })
+}
+
+const updateImageSizes = async (images: string[]) => {
+  if (!images || images.length === 0) {
+    imageSizes.value = []
+    return
+  }
+  const sizes = await Promise.all(images.map(calcImageSize))
+  imageSizes.value = sizes
+}
+
+// 计算打印时背景图 div 应有的高度(容器宽度按 210mm,background-size: contain)
+const getPrintImageHeight = (idx: number): string => {
+  const size = imageSizes.value[idx]
+  if (!size || !size.width || !size.height) return 'auto'
+  const heightMm = (size.height / size.width) * 210
+  return `${heightMm}mm`
+}
+
 watch(
   () => props.modelValue,
   (val) => {
     if (!val) return
     if (Array.isArray(val.images)) {
       form.images = [...val.images]
+      updateImageSizes(form.images)
     } else {
       form.images = []
+      imageSizes.value = []
     }
   },
   { immediate: true, deep: true }
@@ -83,7 +118,7 @@ const handleFileChange = async (e: Event) => {
         }
       } catch (error) {
         console.error('PDF 解析失败', error)
-        message.error(`PDF 解析失败:${file.name}`)
+        message.error(`PDF 解析失败:${file.name}-${error}`)
       }
     } else {
       await uploadSingleFile(file)
@@ -139,11 +174,22 @@ defineExpose({ form })
     <!-- 文本/打印模式:仅展示图片 -->
     <div v-else class="preview-section">
       <div v-if="form.images && form.images.length > 0" class="image-preview-list">
+        <!-- 屏幕预览仍用 img -->
         <img
           v-for="(img, idx) in form.images"
           :key="idx"
           :src="img"
-          class="preview-img"
+          class="preview-img screen-only"
+        />
+        <!-- 打印时用背景图 div,可被浏览器正常分页截断,避免整图被推到下一页产生空白页 -->
+        <div
+          v-for="(img, idx) in form.images"
+          :key="`print-${idx}`"
+          class="print-img"
+          :style="{
+            backgroundImage: `url(${img})`,
+            height: getPrintImageHeight(idx)
+          }"
         />
       </div>
       <div v-else class="empty-box">
@@ -279,6 +325,15 @@ defineExpose({ form })
     box-sizing: border-box;
   }
 
+  /* 打印专用背景图 div,默认屏幕隐藏 */
+  .print-img {
+    display: none;
+    width: 100%;
+    background-repeat: no-repeat;
+    background-position: top center;
+    background-size: contain;
+  }
+
   .empty-box {
     width: 100%;
     min-height: 400px;
@@ -288,4 +343,38 @@ defineExpose({ form })
     color: #999;
   }
 }
+
+/* 打印时:用背景图 div 替代 img,避免替换元素无法被分页截断导致的空白页问题 */
+@media print {
+  .preview-section .image-preview-list {
+    display: block !important;
+    gap: 0 !important;
+  }
+
+  /* 屏幕预览的 img 在打印时隐藏 */
+  .preview-section .preview-img.screen-only {
+    display: none !important;
+  }
+
+  /* 打印专用 div:把图片作为背景图铺满,浏览器可以正常在 div 中间分页截断,
+     从而不会出现整图被推到下一页、标题单独占一页的空白页 */
+  .preview-section .print-img {
+    display: block !important;
+    width: 100%;
+    /* 高度由 JS 动态计算,这里先给最小高度占位,避免背景图为空时 div 高度为 0 */
+    min-height: 50mm;
+    background-repeat: no-repeat;
+    background-position: top center;
+    background-size: contain;
+    page-break-inside: auto;
+    break-inside: auto;
+    break-before: auto;
+    break-after: auto;
+    /* 关键:强制浏览器在打印时渲染背景图,否则 Chrome/Edge 打印预览默认不显示背景图形,
+       会导致图片整体消失(即使 div 高度已正确计算) */
+    -webkit-print-color-adjust: exact !important;
+    print-color-adjust: exact !important;
+    color-adjust: exact !important;
+  }
+}
 </style>

+ 25 - 9
src/views/elderly/contracts/components/RoomFacilitiesEquipmentBody.vue

@@ -256,8 +256,8 @@ defineExpose({ form })
             <SignatureItem
               :model-value="form.elderSign"
               :is-text-mode="isTextMode"
-              width="200"
-              height="80"
+              :width="200"
+              :height="80"
               placeholder="(签字处)"
               title="入住老人签字"
               @update:model-value="(v: any) => { form.elderSign = v; updateForm() }"
@@ -336,7 +336,7 @@ defineExpose({ form })
 
 .table-header {
   display: flex;
-  border-bottom: 1px solid #333;
+
 
   .header-left,
   .header-right {
@@ -359,17 +359,12 @@ defineExpose({ form })
 
 .tables-row {
   display: flex;
-  border-bottom: 1px solid #333;
 
   .half-table {
     flex: 1;
     border-collapse: collapse;
     width: 50%;
 
-    &:first-child {
-      border-right: 1px solid #333;
-    }
-
     th,
     td {
       border: 1px solid #333;
@@ -383,6 +378,27 @@ defineExpose({ form })
       background: #fff;
     }
 
+    // 第一个表格第一列去掉左边框:由 .main-table-wrapper 的左边框提供,避免重叠
+    &:first-child {
+      th:first-child,
+      td:first-child {
+        border-left: 0;
+      }
+    }
+
+    // 第二个表格第一列去掉左边框(中间线由第一个表格最后一列的右边框提供),
+    // 最后一列去掉右边框(由 .main-table-wrapper 的右边框提供),避免重叠
+    &:last-child {
+      th:first-child,
+      td:first-child {
+        border-left: 0;
+      }
+      th:last-child,
+      td:last-child {
+        border-right: 0;
+      }
+    }
+
     .col-no {
       width: 40px;
     }
@@ -449,7 +465,7 @@ defineExpose({ form })
 .date-row-wrapper {
   display: flex;
   align-items: center;
-  justify-content: center;
+  justify-content: flex-end;
   padding: 10px 12px;
   gap: 8px;
 

+ 6 - 3
src/views/elderly/elder/family-appointment/time-setting/index.vue

@@ -35,7 +35,7 @@
                 </el-radio-group>
               </el-form-item>
 
-              <el-form-item label="开始预约日" prop="startDay">
+              <el-form-item v-show="false" label="开始预约日" prop="startDay">
                 <el-select
                   v-model="formData.startDay"
                   placeholder="请选择"
@@ -60,7 +60,7 @@
                   <el-option label="未来15天" :value="15" />
                 </el-select>
               </el-form-item>
-              <el-form-item label="提前预约天数" prop="advanceDays">
+              <el-form-item label="提前预约" prop="advanceDays">
                 <el-input-number
                   v-model="formData.advanceDays"
                   :min="1"
@@ -68,8 +68,11 @@
                   style="width: 100%"
                   :disabled="isDisabled"
                 >
+                  <template #prefix>
+                    <span>可提前</span>
+                  </template>
                   <template #suffix>
-                    <span>天</span>
+                    <span>天预约</span>
                   </template>
                 </el-input-number>
               </el-form-item>

+ 3 - 2
vite.config.ts

@@ -89,7 +89,8 @@ export default ({command, mode}: ConfigEnv): UserConfig => {
             rollupOptions: {
                 output: {
                   chunkFileNames: (chunkInfo) => {
-                      // 只要 chunk 名字包含 pdf.worker,就直接抛到根目录并命名为 pdf.worker.js
+                      // pdf.worker 保持固定文件名,云端 nginx 通常针对该路径配置了 .mjs 的 MIME;
+                      // 改名会导致 module worker MIME 校验失败。缓存问题通过 URL query 参数解决(见 useUpload.ts)
                       if (chunkInfo.name && chunkInfo.name.includes('pdf.worker')) {
                         return 'pdf.worker.js';
                       }
@@ -97,7 +98,7 @@ export default ({command, mode}: ConfigEnv): UserConfig => {
                     },
                     entryFileNames: 'assets/js/[name]-[hash].js',
                     assetFileNames: (chunkInfo) => {
-                      // public 目录下的 pdf worker 保持原文件名,否则 pdfjs 找不到 worker
+                      // pdf.worker 保持固定文件名,避免云端 nginx 对新文件名不匹配 MIME 规则
                       if (chunkInfo.name && chunkInfo.name.includes('pdf.worker')) {
                         return 'pdf.worker.mjs'
                       }

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff