AddForm.vue 36 KB

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