AddForm.vue 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. <template>
  2. <el-drawer v-model="dialogVisible" :title="title" size="90%" :before-close="handleClosed">
  3. <div class="assessment-form">
  4. <div class="form-header">
  5. <el-form :model="dataForm" :rules="rules" ref="formRef" label-width="80px">
  6. <el-row :gutter="20">
  7. <el-col :span="6">
  8. <el-form-item label="姓名" prop="elderName">
  9. <SelectElder
  10. v-model="dataForm.elderId"
  11. ref="selectElderRef" :tId="dataForm.tenantId" @elder="elderUp" :disabled="isDetail"
  12. />
  13. </el-form-item>
  14. </el-col>
  15. <el-col :span="6">
  16. <el-form-item label="年龄">
  17. <el-input v-model="dataForm.elderAge" disabled />
  18. </el-form-item>
  19. </el-col>
  20. <el-col :span="6">
  21. <el-form-item label="性别">
  22. <el-input v-model="dataForm.elderSex" disabled />
  23. </el-form-item>
  24. </el-col>
  25. <el-col :span="6">
  26. <el-form-item label="房号/床号">
  27. <el-input v-model="dataForm.bedName" disabled />
  28. </el-form-item>
  29. </el-col>
  30. </el-row>
  31. </el-form>
  32. </div>
  33. <!-- 评估表 -->
  34. <div class="risk-factors-section">
  35. <div class="section-title">文娱活动风险评估表</div>
  36. <div class="table-wrapper">
  37. <table class="assessment-table">
  38. <thead>
  39. <tr>
  40. <th class="col-factor">评估项目</th>
  41. <th class="col-standard">评估内容及评分标准</th>
  42. <th class="col-score">得分</th>
  43. </tr>
  44. </thead>
  45. <tbody>
  46. <!-- 身体健康状况基础疾病 -->
  47. <tr>
  48. <td class="col-factor" rowspan="4">身体健康状况基础疾病</td>
  49. <td class="col-standard">
  50. <el-radio-group v-model="form.assessment.scores[0]" :disabled="isDetail" @change="calculateTotal">
  51. <el-radio :label="7">两项疾病以上(>2项)=2分+不适合=5分</el-radio>
  52. <el-radio :label="1">两项疾病以下(≤2项)=1分+适合=0分</el-radio>
  53. <el-radio :label="4">两项疾病以上(>2项)2分+身体适合0分=2分</el-radio>
  54. <el-radio :label="6">两项疾病以下(≤2项)1分+身体不适合5分=6分</el-radio>
  55. </el-radio-group>
  56. </td>
  57. <td class="col-score" rowspan="4">{{ form.assessment.scores[0] ?? '-' }}</td>
  58. </tr>
  59. <tr></tr>
  60. <tr></tr>
  61. <tr></tr>
  62. <!-- 跌倒风险与行动能力 -->
  63. <tr>
  64. <td class="col-factor" rowspan="3">跌倒风险与行动能力</td>
  65. <td class="col-standard">
  66. <el-radio-group v-model="form.assessment.scores[1]" :disabled="isDetail" @change="calculateTotal">
  67. <el-radio :label="8">高风险=5分+完全依赖=3分</el-radio>
  68. <el-radio :label="3">中风险=1分+需要协助=2分</el-radio>
  69. <el-radio :label="0">低风险=0分+正常=0分</el-radio>
  70. </el-radio-group>
  71. </td>
  72. <td class="col-score" rowspan="3">{{ form.assessment.scores[1] ?? '-' }}</td>
  73. </tr>
  74. <tr></tr>
  75. <tr></tr>
  76. <!-- 走失风险与认知能力 -->
  77. <tr>
  78. <td class="col-factor" rowspan="3">走失风险与认知能力</td>
  79. <td class="col-standard">
  80. <el-radio-group v-model="form.assessment.scores[2]" :disabled="isDetail" @change="calculateTotal">
  81. <el-radio :label="8">高风险=5分+确诊认知功能障碍=3分</el-radio>
  82. <el-radio :label="3">中风险=1分+疑似认知功能障碍=2分</el-radio>
  83. <el-radio :label="0">低风险=0分+无认知功能障碍=0分</el-radio>
  84. </el-radio-group>
  85. </td>
  86. <td class="col-score" rowspan="3">{{ form.assessment.scores[2] ?? '-' }}</td>
  87. </tr>
  88. <tr></tr>
  89. <tr></tr>
  90. <!-- 心理健康状况 -->
  91. <tr>
  92. <td class="col-factor" rowspan="3">心理健康状况</td>
  93. <td class="col-standard">
  94. <el-radio-group v-model="form.assessment.scores[3]" :disabled="isDetail" @change="calculateTotal">
  95. <el-radio :label="6">状况很差=3分+抑郁=3分</el-radio>
  96. <el-radio :label="3">状况较差=1分+冷漠=2分</el-radio>
  97. <el-radio :label="0">状况良好(正常)=0</el-radio>
  98. </el-radio-group>
  99. </td>
  100. <td class="col-score" rowspan="3">{{ form.assessment.scores[3] ?? '-' }}</td>
  101. </tr>
  102. <tr></tr>
  103. <tr></tr>
  104. <!-- 他伤及自伤风险 -->
  105. <tr>
  106. <td class="col-factor">他伤及自伤风险</td>
  107. <td class="col-standard">
  108. <el-radio-group v-model="form.assessment.scores[4]" :disabled="isDetail" @change="calculateTotal">
  109. <el-radio :label="0">轻度风险=0</el-radio>
  110. <el-radio :label="1">中度风险=1</el-radio>
  111. <el-radio :label="5">重度风险=5</el-radio>
  112. </el-radio-group>
  113. </td>
  114. <td class="col-score">{{ form.assessment.scores[4] ?? '-' }}</td>
  115. </tr>
  116. <!-- 参加活动老年人之间是否发生过矛盾冲突 -->
  117. <tr>
  118. <td class="col-factor">参加活动老年人之间是否发生过矛盾冲突</td>
  119. <td class="col-standard">
  120. <el-radio-group v-model="form.assessment.scores[5]" :disabled="isDetail" @change="calculateTotal">
  121. <el-radio :label="3">是=3</el-radio>
  122. <el-radio :label="0">否=0</el-radio>
  123. </el-radio-group>
  124. </td>
  125. <td class="col-score">{{ form.assessment.scores[5] ?? '-' }}</td>
  126. </tr>
  127. <!-- 评估总分 -->
  128. <tr>
  129. <td class="col-factor" colspan="2" style="text-align: center; font-weight: bold;">评估总分</td>
  130. <td class="col-score">{{ form.assessment.totalScore }}</td>
  131. </tr>
  132. <!-- 综合风险评级 -->
  133. <tr>
  134. <td class="col-factor" colspan="2" style="text-align: center; font-weight: bold;">综合风险评级</td>
  135. <td class="col-score">{{ getRiskText(form.riskLevel) }}</td>
  136. </tr>
  137. </tbody>
  138. </table>
  139. </div>
  140. <!-- 评价标准 -->
  141. <div class="evaluation-standard">
  142. <div class="standard-title">评价标准:</div>
  143. <div class="standard-content">
  144. 0分为无风险;≤7分为低风险;8-11分为中风险;≥12分为高风险。
  145. </div>
  146. </div>
  147. <!-- 备注 -->
  148. <div class="remarks-section">
  149. <div class="remarks-title">备注:</div>
  150. <div class="remarks-content">
  151. <div class="remark-item">1、制定适合不同风险等级的老年人活动,并做好风险防范措施;</div>
  152. <div class="remark-item">2、选择安全的文娱活动场所,地面应要防滑、平整,墙壁边角和家具边应做好防护处理;</div>
  153. <div class="remark-item">3、准确评估老年人的活动耐受力,忌做刺激性强的、运动强度高的活动;</div>
  154. <div class="remark-item">4、文娱活动时间不宜过长,建议1小时以内为宜;</div>
  155. <div class="remark-item">5、参加活动时,必须要有工作人员陪同。</div>
  156. </div>
  157. </div>
  158. <!-- 风险程度判断 -->
  159. <div class="risk-level-section">
  160. <div class="risk-level-title">风险程度判断:</div>
  161. <div class="risk-level-options">
  162. <div class="risk-option" :class="{ active: form.riskLevel === 'none' }">
  163. <el-radio v-model="form.riskLevel" label="none" :disabled="isDetail">
  164. 无风险:0分
  165. </el-radio>
  166. </div>
  167. <div class="risk-option" :class="{ active: form.riskLevel === 'low' }">
  168. <el-radio v-model="form.riskLevel" label="low" :disabled="isDetail">
  169. 低风险:I级
  170. </el-radio>
  171. </div>
  172. <div class="risk-option" :class="{ active: form.riskLevel === 'medium' }">
  173. <el-radio v-model="form.riskLevel" label="medium" :disabled="isDetail">
  174. 中风险:II级
  175. </el-radio>
  176. </div>
  177. <div class="risk-option" :class="{ active: form.riskLevel === 'high' }">
  178. <el-radio v-model="form.riskLevel" label="high" :disabled="isDetail">
  179. 高风险:III级、IV级
  180. </el-radio>
  181. </div>
  182. <div class="risk-option score-display">
  183. <span class="score-label">评估总得分:</span>
  184. <span class="score-value">{{ form.assessment.totalScore }} 分</span>
  185. </div>
  186. </div>
  187. </div>
  188. <!-- 评估记录 -->
  189. <div class="assessment-records">
  190. <div class="record-section">
  191. <div class="record-header">评估记录</div>
  192. <el-row :gutter="20">
  193. <el-col :span="12">
  194. <el-form-item label="评估人">
  195. <el-input v-model="form.assessment.assessor" placeholder="请输入评估人" :disabled="isDetail" />
  196. </el-form-item>
  197. </el-col>
  198. <el-col :span="12">
  199. <el-form-item label="评估日期">
  200. <el-date-picker
  201. v-model="form.assessment.assessDate"
  202. type="date"
  203. placeholder="选择日期"
  204. value-format="YYYY-MM-DD"
  205. :disabled="isDetail"
  206. style="width: 100%"
  207. />
  208. </el-form-item>
  209. </el-col>
  210. </el-row>
  211. </div>
  212. </div>
  213. </div>
  214. </div>
  215. <template #footer>
  216. <el-button @click="handleClosed">关闭</el-button>
  217. <el-button v-if="isDetail" type="success" @click="handleExport">打印</el-button>
  218. <el-button
  219. style="margin-left: 22px;margin-right: 30px" v-loading="formLoading" type="primary"
  220. v-show="!isDetail" @click="submitForm">确定</el-button>
  221. </template>
  222. </el-drawer>
  223. </template>
  224. <script lang="ts" setup>
  225. import { computed, ref, reactive } from 'vue'
  226. import dayjs from 'dayjs'
  227. import { useUserStore } from '@/store/modules/user'
  228. import {
  229. entertainmentCreate, entertainmentGetById, entertainmentUpdate,
  230. fallDownPage, wanderAwayPage, ngasrPage,
  231. } from "@/api/social-work";
  232. const message = useMessage()
  233. const userStore = useUserStore()
  234. const { t } = useI18n()
  235. const title = ref('')
  236. const dialogVisible = ref(false)
  237. const formRef = ref()
  238. const selectElderRef = ref()
  239. const isDetail = ref(false)
  240. const formLoading = ref(false)
  241. let dataForm = ref({
  242. id: undefined,
  243. elderName: '',
  244. elderSex: '',
  245. elderAge: '',
  246. bedName: '',
  247. elderId: '',
  248. tenantId: undefined
  249. })
  250. const elderUp = async (e: any) => {
  251. console.log(e)
  252. dataForm.value.elderName = e.elderName
  253. dataForm.value.elderId = e.id
  254. dataForm.value.elderSex = e.elderSex === 1 ? '男' : '女'
  255. dataForm.value.bedName = e.bedName || ''
  256. dataForm.value.elderAge = e.elderAge
  257. // 新增模式下,自动查询长者的跌倒/走失/他伤自伤风险评估,并自动选中对应值
  258. if (!isDetail.value && e.id) {
  259. await loadElderRiskData(e.id)
  260. }
  261. }
  262. // 从最新一条评估记录中解析 riskLevel
  263. const parseRiskLevel = (record: any): string => {
  264. if (!record) return ''
  265. // 优先取顶层 riskLevel
  266. if (record.riskLevel) return record.riskLevel
  267. // 其次尝试从 assessData 中解析
  268. if (record.assessData) {
  269. try {
  270. const assessData = JSON.parse(record.assessData)
  271. if (assessData.riskLevel) return assessData.riskLevel
  272. } catch (err) {
  273. // ignore
  274. }
  275. }
  276. return ''
  277. }
  278. // 根据评估日期或创建时间获取最新一条记录
  279. const getLatestRecord = (list: any[]): any => {
  280. if (!list || list.length === 0) return null
  281. const sorted = [...list].sort((a, b) => {
  282. const dateA = a.assessDate || a.createdAt || ''
  283. const dateB = b.assessDate || b.createdAt || ''
  284. return new Date(dateB).getTime() - new Date(dateA).getTime()
  285. })
  286. return sorted[0]
  287. }
  288. // 加载长者风险数据:跌倒风险、走失风险、他伤自伤风险
  289. const loadElderRiskData = async (elderId: string) => {
  290. try {
  291. const params = { pageNo: 1, pageSize: 100, elderId: elderId }
  292. // 1. 查询跌倒风险评估
  293. try {
  294. const res = await fallDownPage(params)
  295. if (res && res.list && res.list.length > 0) {
  296. const latest = getLatestRecord(res.list)
  297. const riskLevel = parseRiskLevel(latest)
  298. if (riskLevel === 'high') {
  299. form.assessment.scores[1] = 8
  300. } else if (riskLevel === 'medium') {
  301. form.assessment.scores[1] = 3
  302. } else {
  303. form.assessment.scores[1] = 0
  304. }
  305. }
  306. } catch (err) {
  307. console.error('获取跌倒风险评估失败', err)
  308. }
  309. // 2. 查询走失风险评估
  310. try {
  311. const res = await wanderAwayPage(params)
  312. if (res && res.list && res.list.length > 0) {
  313. const latest = getLatestRecord(res.list)
  314. const riskLevel = parseRiskLevel(latest)
  315. if (riskLevel === 'high') {
  316. form.assessment.scores[2] = 8
  317. } else if (riskLevel === 'medium') {
  318. form.assessment.scores[2] = 3
  319. } else {
  320. form.assessment.scores[2] = 0
  321. }
  322. }
  323. } catch (err) {
  324. console.error('获取走失风险评估失败', err)
  325. }
  326. // 3. 查询他伤自伤风险评估(NGASR)
  327. try {
  328. const res = await ngasrPage(params)
  329. if (res && res.list && res.list.length > 0) {
  330. const latest = getLatestRecord(res.list)
  331. const riskLevel = parseRiskLevel(latest)
  332. if (riskLevel === 'high') {
  333. form.assessment.scores[4] = 5
  334. } else if (riskLevel === 'medium') {
  335. form.assessment.scores[4] = 1
  336. } else {
  337. form.assessment.scores[4] = 0
  338. }
  339. }
  340. } catch (err) {
  341. console.error('获取他伤自伤风险评估失败', err)
  342. }
  343. // 重新计算总分和风险等级
  344. calculateTotal()
  345. } catch (e) {
  346. console.error('获取风险数据失败', e)
  347. }
  348. }
  349. // 表单数据
  350. const form = reactive({
  351. assessment: {
  352. assessDate: '',
  353. assessor: '',
  354. scores: new Array(6).fill(0),
  355. totalScore: 0
  356. },
  357. riskLevel: ''
  358. })
  359. // 计算总得分
  360. const calculateTotal = () => {
  361. const scores = form.assessment.scores
  362. const total = scores.reduce((sum, score) => sum + (score || 0), 0)
  363. form.assessment.totalScore = total
  364. // 自动判断风险等级 (0分为无风险,≤7分为低风险;8-11分为中风险;≥12分为高风险)
  365. if (total === 0) {
  366. form.riskLevel = 'none'
  367. } else if (total <= 7) {
  368. form.riskLevel = 'low'
  369. } else if (total >= 8 && total <= 11) {
  370. form.riskLevel = 'medium'
  371. } else if (total >= 12) {
  372. form.riskLevel = 'high'
  373. }
  374. }
  375. // 获取风险等级文本
  376. const getRiskText = (riskLevel: string) => {
  377. switch (riskLevel) {
  378. case 'none': return '无风险'
  379. case 'low': return '低风险'
  380. case 'medium': return '中风险'
  381. case 'high': return '高风险'
  382. default: return '-'
  383. }
  384. }
  385. // 获取风险等级标签类型
  386. const getRiskTagType = (riskLevel: string) => {
  387. switch (riskLevel) {
  388. case 'none': return 'info'
  389. case 'low': return 'success'
  390. case 'medium': return 'warning'
  391. case 'high': return 'danger'
  392. default: return ''
  393. }
  394. }
  395. /** 将表单数据序列化为 JSON 对象 */
  396. const serializeFormData = () => {
  397. return {
  398. assessment: {
  399. assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : '',
  400. assessor: form.assessment.assessor || '',
  401. scores: form.assessment.scores || [],
  402. totalScore: form.assessment.totalScore || 0
  403. },
  404. riskLevel: form.riskLevel
  405. }
  406. }
  407. /** 将 JSON 对象反序列化为表单数据 */
  408. const deserializeFormData = (formData: Record<string, any>) => {
  409. if (!formData) return
  410. if (formData.assessment) {
  411. form.assessment.assessDate = formData.assessment.assessDate || ''
  412. form.assessment.assessor = formData.assessment.assessor || ''
  413. form.assessment.scores = formData.assessment.scores || new Array(6).fill(0)
  414. form.assessment.totalScore = formData.assessment.totalScore || 0
  415. }
  416. form.riskLevel = formData.riskLevel || ''
  417. }
  418. /** 重置表单数据 */
  419. const resetForm = () => {
  420. dataForm.value = {
  421. id: undefined,
  422. elderName: '',
  423. elderSex: '',
  424. elderAge: '',
  425. bedName: '',
  426. elderId: '',
  427. tenantId: undefined
  428. }
  429. formRef.value?.resetFields()
  430. form.assessment = {
  431. assessDate: '',
  432. assessor: '',
  433. scores: new Array(6).fill(0),
  434. totalScore: 0
  435. }
  436. form.riskLevel = ''
  437. }
  438. /** 打开弹窗 */
  439. const open = async (tenantId: any, id?: any, detail: boolean = false) => {
  440. resetForm()
  441. dialogVisible.value = true
  442. dataForm.value.id = id || undefined
  443. dataForm.value.tenantId = tenantId
  444. isDetail.value = detail
  445. if (id) {
  446. title.value = "编辑-防文娱意外评估表"
  447. await loadData(id)
  448. } else {
  449. title.value = "新增-防文娱意外评估表"
  450. }
  451. }
  452. /** 加载评估数据 */
  453. const loadData = async (id: number) => {
  454. try {
  455. const res = await entertainmentGetById(id)
  456. if (res) {
  457. dataForm.value.elderName = res.elderName || ''
  458. dataForm.value.elderId = res.elderId || ''
  459. dataForm.value.elderSex = res.elderSex || ''
  460. dataForm.value.bedName = res.bedName || ''
  461. dataForm.value.elderAge = res.elderAge || ''
  462. await selectElderRef.value.upData(res.elderName, res.elderId)
  463. // 优先从独立字段获取评估人和评估日期
  464. if (res.assessor) {
  465. form.assessment.assessor = res.assessor
  466. }
  467. if (res.assessDate) {
  468. form.assessment.assessDate = res.assessDate
  469. }
  470. if (res.assessData) {
  471. const formData = JSON.parse(res.assessData)
  472. deserializeFormData(formData)
  473. // assessData中的assessor和assessDate会覆盖独立字段的值(如果存在)
  474. }
  475. }
  476. } catch (error) {
  477. message.error('加载评估数据失败')
  478. }
  479. }
  480. defineExpose({ open })
  481. const emit = defineEmits(['success'])
  482. /** 提交表单 */
  483. const submitForm = async () => {
  484. if (!dataForm.value.elderId) {
  485. message.error('请选择长者')
  486. return
  487. }
  488. formLoading.value = true
  489. try {
  490. const formData = serializeFormData()
  491. const payload = {
  492. id: dataForm.value.id,
  493. elderId: dataForm.value.elderId,
  494. tenantId: dataForm.value.tenantId,
  495. elderName: dataForm.value.elderName,
  496. elderSex: dataForm.value.elderSex,
  497. elderAge: dataForm.value.elderAge,
  498. bedName: dataForm.value.bedName,
  499. assessData: JSON.stringify(formData),
  500. riskLevel: form.riskLevel,
  501. assessScore: form.assessment.totalScore || 0,
  502. assessor: form.assessment.assessor,
  503. assessDate: form.assessment.assessDate ? dayjs(form.assessment.assessDate).format('YYYY-MM-DD') : ''
  504. }
  505. if (dataForm.value.id) {
  506. await entertainmentUpdate(payload)
  507. message.success(t('common.updateSuccess'))
  508. } else {
  509. await entertainmentCreate(payload)
  510. message.success(t('common.createSuccess'))
  511. }
  512. dialogVisible.value = false
  513. emit('success')
  514. } catch (error) {
  515. message.error('提交失败')
  516. } finally {
  517. formLoading.value = false
  518. }
  519. }
  520. /** 关闭弹窗 */
  521. const handleClosed = () => {
  522. dialogVisible.value = false
  523. }
  524. /** 导出/打印 */
  525. const handleExport = () => {
  526. // 创建打印窗口
  527. const printWindow = window.open('', '_blank')
  528. if (!printWindow) {
  529. message.error('请允许弹出窗口')
  530. return
  531. }
  532. // 评估项目数据
  533. const assessmentItems = [
  534. {
  535. factor: '身体健康状况基础疾病',
  536. options: [
  537. { label: '两项疾病以上(>2项)=2分+不适合=5分', value: 5 },
  538. { label: '两项疾病以下(≤2项)=1分+适合=0分', value: 1 },
  539. { label: '两项疾病以上(>2项)2分+身体适合0分=2分', value: 2 },
  540. { label: '两项疾病以下(≤2项)1分+身体不适合5分=6分', value: 6 }
  541. ],
  542. score: form.assessment.scores[0]
  543. },
  544. {
  545. factor: '跌倒风险与行动能力',
  546. options: [
  547. { label: '高风险=5分+完全依赖=3分', value: 8 },
  548. { label: '中风险=1分+需要协助=2分', value: 3 },
  549. { label: '低风险=0分+正常=0分', value: 0 }
  550. ],
  551. score: form.assessment.scores[1]
  552. },
  553. {
  554. factor: '走失风险与认知能力',
  555. options: [
  556. { label: '高风险=5分+确诊认知功能障碍=3分', value: 8 },
  557. { label: '中风险=1分+疑似认知功能障碍=2分', value: 3 },
  558. { label: '低风险=0分+无认知功能障碍=0分', value: 0 }
  559. ],
  560. score: form.assessment.scores[2]
  561. },
  562. {
  563. factor: '心理健康状况',
  564. options: [
  565. { label: '状况很差=3分+抑郁=3分', value: 6 },
  566. { label: '状况较差=1分+冷漠=2分', value: 3 },
  567. { label: '状况良好(正常)=0', value: 0 }
  568. ],
  569. score: form.assessment.scores[3]
  570. },
  571. {
  572. factor: '他伤及自伤风险',
  573. options: [
  574. { label: '轻度风险=0', value: 0 },
  575. { label: '中度风险=1', value: 1 },
  576. { label: '重度风险=5', value: 5 }
  577. ],
  578. score: form.assessment.scores[4]
  579. },
  580. {
  581. factor: '参加活动老年人之间是否发生过矛盾冲突',
  582. options: [
  583. { label: '是=3', value: 3 },
  584. { label: '否=0', value: 0 }
  585. ],
  586. score: form.assessment.scores[5]
  587. }
  588. ]
  589. // 构建打印内容
  590. const tenantName = userStore.getTenantName || '' // 当前登录的机构名称
  591. const printContent = `
  592. <!DOCTYPE html>
  593. <html>
  594. <head>
  595. <meta charset="UTF-8">
  596. <title>防文娱活动意外评估表 - ${dataForm.value.elderName || ''}</title>
  597. <style>
  598. @media print {
  599. @page { size: A4 portrait; margin: 15mm; }
  600. }
  601. body {
  602. font-family: 'SimSun', 'Microsoft YaHei', serif;
  603. font-size: 10pt;
  604. line-height: 1.4;
  605. color: #333;
  606. }
  607. .header {
  608. text-align: center;
  609. margin-bottom: 15px;
  610. border-bottom: 2px solid #333;
  611. padding-bottom: 10px;
  612. }
  613. .header h1 {
  614. font-size: 16pt;
  615. margin: 0;
  616. letter-spacing: 2px;
  617. }
  618. .info-section {
  619. margin-bottom: 15px;
  620. padding: 10px;
  621. border: 1px solid #999;
  622. background: #fafafa;
  623. }
  624. .info-row {
  625. display: flex;
  626. flex-wrap: wrap;
  627. gap: 20px;
  628. }
  629. .info-item {
  630. display: flex;
  631. align-items: center;
  632. }
  633. .info-item .label {
  634. font-weight: bold;
  635. margin-right: 8px;
  636. color: #555;
  637. }
  638. .info-item .value {
  639. border-bottom: 1px solid #333;
  640. min-width: 80px;
  641. padding: 0 5px;
  642. text-align: center;
  643. }
  644. .assessment-table {
  645. width: 100%;
  646. border-collapse: collapse;
  647. margin-bottom: 15px;
  648. }
  649. .assessment-table th, .assessment-table td {
  650. border: 1px solid #333;
  651. padding: 8px;
  652. text-align: left;
  653. vertical-align: top;
  654. }
  655. .assessment-table th {
  656. background: #e8e8e8;
  657. font-weight: bold;
  658. text-align: center;
  659. }
  660. .assessment-table .col-factor {
  661. width: 15%;
  662. text-align: center;
  663. font-weight: bold;
  664. background: #f5f5f5;
  665. }
  666. .assessment-table .col-standard {
  667. width: 70%;
  668. }
  669. .assessment-table .col-score {
  670. width: 15%;
  671. text-align: center;
  672. font-weight: bold;
  673. }
  674. .risk-judgment-section {
  675. margin: 15px 0;
  676. padding: 10px;
  677. border: 1px solid #999;
  678. }
  679. .risk-judgment-title {
  680. font-weight: bold;
  681. margin-bottom: 10px;
  682. }
  683. .risk-options {
  684. display: flex;
  685. flex-wrap: wrap;
  686. gap: 15px;
  687. }
  688. .risk-option {
  689. display: inline-block;
  690. }
  691. .record-section {
  692. margin: 15px 0;
  693. padding: 10px;
  694. border: 1px solid #999;
  695. }
  696. .record-title {
  697. font-weight: bold;
  698. margin-bottom: 10px;
  699. border-bottom: 1px solid #ccc;
  700. padding-bottom: 5px;
  701. }
  702. .record-row {
  703. display: flex;
  704. gap: 30px;
  705. margin-bottom: 8px;
  706. }
  707. .record-item {
  708. display: flex;
  709. align-items: center;
  710. }
  711. .record-item .label {
  712. font-weight: bold;
  713. margin-right: 8px;
  714. }
  715. .record-item .value {
  716. border-bottom: 1px solid #333;
  717. min-width: 180px;
  718. padding: 0 5px;
  719. text-align: center;
  720. }
  721. .score-value {
  722. color: #d9534f;
  723. font-weight: bold;
  724. font-size: 14pt;
  725. }
  726. .prevention-section {
  727. margin: 15px 0;
  728. border: 1px solid #999;
  729. }
  730. .prevention-title {
  731. font-weight: bold;
  732. background: #e8e8e8;
  733. padding: 8px 12px;
  734. border-bottom: 1px solid #999;
  735. }
  736. .prevention-content {
  737. padding: 10px 12px;
  738. }
  739. .prevention-item {
  740. margin-bottom: 8px;
  741. font-size: 10pt;
  742. }
  743. </style>
  744. </head>
  745. <body>
  746. <div class="tenant-name" style="text-align: end;width: 100%;font-size: 16px; font-weight: bold; margin-bottom: 10px;">${tenantName}</div>
  747. <div class="header">
  748. <h1>防文娱活动意外评估表</h1>
  749. </div>
  750. <div class="info-section">
  751. <div class="info-row">
  752. <div class="info-item">
  753. <span class="label">长者姓名:</span>
  754. <span class="value">${dataForm.value.elderName || ''}</span>
  755. </div>
  756. <div class="info-item">
  757. <span class="label">性别:</span>
  758. <span class="value">${dataForm.value.elderSex || ''}</span>
  759. </div>
  760. <div class="info-item">
  761. <span class="label">年龄:</span>
  762. <span class="value">${dataForm.value.elderAge || ''}</span>
  763. </div>
  764. <div class="info-item">
  765. <span class="label">房号/床号:</span>
  766. <span class="value">${dataForm.value.bedName || ''}</span>
  767. </div>
  768. </div>
  769. </div>
  770. <!-- 危险因素评估表 -->
  771. <table class="assessment-table">
  772. <thead>
  773. <tr>
  774. <th class="col-factor">危险因素</th>
  775. <th class="col-standard">评估标准(分)</th>
  776. <th class="col-score">得分</th>
  777. </tr>
  778. </thead>
  779. <tbody>
  780. ${assessmentItems.map(item => `
  781. <tr>
  782. <td class="col-factor">${item.factor}</td>
  783. <td class="col-standard">
  784. ${item.options.map(opt => `${item.score === opt.value ? '☑' : '☐'} ${opt.label}=${opt.value}`).join('&nbsp;&nbsp;&nbsp;&nbsp;')}
  785. </td>
  786. <td class="col-score">${item.score}</td>
  787. </tr>
  788. `).join('')}
  789. </tbody>
  790. </table>
  791. <!-- 评价标准 -->
  792. <div class="evaluation-standard-section">
  793. <div class="evaluation-title">评价标准:0分为无风险;≤7分为低风险;8-11分为中风险;≥12分为高风险。</div>
  794. </div>
  795. <!-- 备注 -->
  796. <div class="remarks-section">
  797. <div class="remarks-title">备注:</div>
  798. <div class="remarks-content">
  799. <div class="remark-item">1、制定适合不同风险等级的老年人活动,并做好风险防范措施;</div>
  800. <div class="remark-item">2、选择安全的文娱活动场所,地面应要防滑、平整,墙壁边角和家具边应做好防护处理;</div>
  801. <div class="remark-item">3、准确评估老年人的活动耐受力,忌做刺激性强的、运动强度高的活动;</div>
  802. <div class="remark-item">4、文娱活动时间不宜过长,建议1小时以内为宜;</div>
  803. <div class="remark-item">5、参加活动时,必须要有工作人员陪同。</div>
  804. </div>
  805. </div>
  806. <!-- 风险程度判断 -->
  807. <div class="risk-judgment-section">
  808. <div class="risk-judgment-title">风险程度判断:</div>
  809. <div class="risk-options">
  810. <span class="risk-option">${form.riskLevel === 'none' ? '☑' : '☐'} 无风险:0分</span>
  811. <span class="risk-option">${form.riskLevel === 'low' ? '☑' : '☐'} 低风险:I级</span>
  812. <span class="risk-option">${form.riskLevel === 'medium' ? '☑' : '☐'} 中风险:II级</span>
  813. <span class="risk-option">${form.riskLevel === 'high' ? '☑' : '☐'} 高风险:III级、IV级</span>
  814. <span class="risk-option score-display"><strong>评估总得分:${form.assessment.totalScore} 分</strong></span>
  815. </div>
  816. </div>
  817. <!-- 评估记录 -->
  818. <div class="record-section">
  819. <div class="record-title">评估记录</div>
  820. <div class="record-row">
  821. <div class="record-item">
  822. <span class="label">评估人签名:</span>
  823. <span class="value">${form.assessment.assessor || ''}</span>
  824. </div>
  825. <div class="record-item">
  826. <span class="label">评估日期:</span>
  827. <span class="value">${form.assessment.assessDate || ''}</span>
  828. </div>
  829. </div>
  830. </div>
  831. </body>
  832. </html>
  833. `
  834. // 写入内容并打印
  835. printWindow.document.write(printContent)
  836. printWindow.document.close()
  837. // 延迟打印,确保样式加载完成
  838. setTimeout(() => {
  839. printWindow.print()
  840. }, 500)
  841. }
  842. const rules = {
  843. elderName: [{ required: true, message: '请选择长者', trigger: 'change' }]
  844. }
  845. </script>
  846. <style scoped lang="scss">
  847. .assessment-form {
  848. padding: 0 20px;
  849. .form-header {
  850. margin-bottom: 20px;
  851. }
  852. .risk-factors-section {
  853. margin-bottom: 20px;
  854. .section-title {
  855. font-size: 16px;
  856. font-weight: bold;
  857. margin-bottom: 15px;
  858. color: #333;
  859. border-left: 4px solid #409eff;
  860. padding-left: 10px;
  861. }
  862. .table-wrapper {
  863. border: 1px solid #f0f0f0;
  864. border-radius: 4px;
  865. overflow: hidden;
  866. }
  867. .assessment-table {
  868. width: 100%;
  869. border-collapse: collapse;
  870. th, td {
  871. padding: 12px;
  872. border: 1px solid #e4e7ed;
  873. }
  874. thead {
  875. background-color: #f5f7fa;
  876. font-weight: bold;
  877. th {
  878. border-bottom: 1px solid #f0f0f0;
  879. }
  880. }
  881. tbody {
  882. tr:last-child {
  883. td {
  884. border-bottom: none;
  885. }
  886. }
  887. }
  888. .col-factor {
  889. width: 20%;
  890. text-align: center;
  891. font-weight: bold;
  892. border-right: 1px solid #e4e7ed;
  893. }
  894. .col-standard {
  895. width: 65%;
  896. text-align: left;
  897. border-right: 1px solid #e4e7ed;
  898. .el-radio-group {
  899. display: flex;
  900. flex-wrap: wrap;
  901. gap: 20px;
  902. .el-radio {
  903. margin-right: 0;
  904. height: 24px;
  905. }
  906. }
  907. &.empty-row {
  908. padding: 4px;
  909. }
  910. }
  911. .col-score {
  912. width: 15%;
  913. text-align: center;
  914. font-weight: bold;
  915. color: #409eff;
  916. font-size: 16px;
  917. }
  918. }
  919. .evaluation-standard {
  920. margin-top: 15px;
  921. padding: 15px;
  922. background-color: #f5f7fa;
  923. border-radius: 4px;
  924. border: 1px solid #e4e7ed;
  925. .standard-title {
  926. font-weight: bold;
  927. margin-bottom: 5px;
  928. }
  929. .standard-content {
  930. color: #606266;
  931. }
  932. }
  933. .remarks-section {
  934. margin-top: 15px;
  935. padding: 15px;
  936. background-color: #fff;
  937. border: 1px solid #e4e7ed;
  938. border-radius: 4px;
  939. .remarks-title {
  940. font-weight: bold;
  941. margin-bottom: 10px;
  942. color: #333;
  943. }
  944. .remarks-content {
  945. .remark-item {
  946. margin-bottom: 5px;
  947. color: #606266;
  948. line-height: 1.6;
  949. }
  950. }
  951. }
  952. .risk-level-section {
  953. margin-top: 20px;
  954. padding: 15px;
  955. background-color: #f5f7fa;
  956. border: 1px solid #e4e7ed;
  957. border-radius: 4px;
  958. .risk-level-title {
  959. font-size: 14px;
  960. font-weight: bold;
  961. margin-bottom: 10px;
  962. color: #333;
  963. }
  964. .risk-level-options {
  965. display: flex;
  966. flex-wrap: wrap;
  967. gap: 30px;
  968. align-items: center;
  969. .risk-option {
  970. .el-radio {
  971. margin-right: 0;
  972. }
  973. &.score-display {
  974. margin-left: auto;
  975. display: flex;
  976. align-items: center;
  977. gap: 8px;
  978. .score-label {
  979. font-weight: bold;
  980. color: #333;
  981. }
  982. .score-value {
  983. font-size: 18px;
  984. font-weight: bold;
  985. color: #409eff;
  986. }
  987. }
  988. }
  989. }
  990. }
  991. }
  992. .assessment-records {
  993. margin-top: 20px;
  994. .record-section {
  995. margin-bottom: 20px;
  996. padding: 15px;
  997. border: 1px solid #e4e7ed;
  998. border-radius: 4px;
  999. .record-header {
  1000. font-size: 14px;
  1001. font-weight: bold;
  1002. margin-bottom: 15px;
  1003. color: #409eff;
  1004. border-bottom: 1px solid #e4e7ed;
  1005. padding-bottom: 10px;
  1006. }
  1007. .score-text {
  1008. font-size: 16px;
  1009. font-weight: bold;
  1010. color: #409eff;
  1011. }
  1012. }
  1013. }
  1014. .prevention-section {
  1015. margin-top: 20px;
  1016. .section-title {
  1017. font-size: 16px;
  1018. font-weight: bold;
  1019. margin-bottom: 15px;
  1020. color: #333;
  1021. border-left: 4px solid #409eff;
  1022. padding-left: 10px;
  1023. }
  1024. .prevention-group {
  1025. display: flex;
  1026. flex-direction: column;
  1027. gap: 10px;
  1028. .el-checkbox {
  1029. margin-bottom: 10px;
  1030. margin-right: 20px;
  1031. }
  1032. }
  1033. }
  1034. .evaluation-standard-section {
  1035. margin-top: 20px;
  1036. padding: 15px;
  1037. background-color: #f5f7fa;
  1038. border: 1px solid #e4e7ed;
  1039. border-radius: 4px;
  1040. .evaluation-title {
  1041. font-weight: bold;
  1042. color: #333;
  1043. }
  1044. }
  1045. .remarks-section {
  1046. margin-top: 20px;
  1047. padding: 15px;
  1048. background-color: #fff;
  1049. border: 1px solid #e4e7ed;
  1050. border-radius: 4px;
  1051. .remarks-title {
  1052. font-size: 16px;
  1053. font-weight: bold;
  1054. margin-bottom: 15px;
  1055. color: #333;
  1056. border-left: 4px solid #409eff;
  1057. padding-left: 10px;
  1058. }
  1059. .remarks-content {
  1060. .remark-item {
  1061. margin-bottom: 8px;
  1062. color: #606266;
  1063. line-height: 1.6;
  1064. }
  1065. }
  1066. }
  1067. .el-checkbox {
  1068. margin-bottom: 10px;
  1069. margin-right: 20px;
  1070. }
  1071. }
  1072. .api-params-section {
  1073. margin-top: 30px;
  1074. padding: 20px;
  1075. background-color: #f5f7fa;
  1076. border: 1px solid #e4e7ed;
  1077. border-radius: 4px;
  1078. .section-title {
  1079. font-size: 16px;
  1080. font-weight: bold;
  1081. margin-bottom: 15px;
  1082. color: #333;
  1083. border-left: 4px solid #67c23a;
  1084. padding-left: 10px;
  1085. }
  1086. .risk-rules {
  1087. margin-top: 15px;
  1088. padding: 10px;
  1089. background-color: #fff;
  1090. border-radius: 4px;
  1091. .rules-title {
  1092. font-weight: bold;
  1093. margin-bottom: 10px;
  1094. color: #606266;
  1095. }
  1096. .rule-tag {
  1097. margin-right: 10px;
  1098. margin-bottom: 5px;
  1099. }
  1100. }
  1101. }
  1102. </style>