index.vue 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. <template>
  2. <div class="p-2">
  3. <div v-show="type === 'list'">
  4. <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
  5. <div v-show="showSearch" class="mb-[10px]">
  6. <el-card shadow="hover">
  7. <el-form ref="queryFormRef" :model="queryParams" :inline="true">
  8. <el-form-item>
  9. <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  10. </el-form-item>
  11. <el-form-item label="看诊类型">
  12. <el-select v-model="queryParams.type" class="spec-unit-select">
  13. <el-option v-for="dict in treatment_user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
  14. </el-select>
  15. </el-form-item>
  16. <el-form-item>
  17. <el-input v-model="queryParams.searchValue" placeholder="医生姓名/门诊号/住院号" style="width: 240px; " clearable />
  18. </el-form-item>
  19. <el-form-item>
  20. <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
  21. <el-button icon="Refresh" @click="resetQuery">重置</el-button>
  22. </el-form-item>
  23. </el-form>
  24. </el-card>
  25. </div>
  26. </transition>
  27. <el-card shadow="never">
  28. <template #header>
  29. <el-row :gutter="10" class="mb8">
  30. <el-col :span="1.5">
  31. <el-button type="primary" @click="handleAdd">新增营养诊断</el-button>
  32. </el-col>
  33. <el-col :span="1.5">
  34. <el-button disabled>打印已选病历</el-button>
  35. </el-col>
  36. <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
  37. </el-row>
  38. </template>
  39. <el-table v-loading="loading" border :data="diagnosisList" @selection-change="handleSelectionChange">
  40. <el-table-column type="selection" width="55" align="center" />
  41. <el-table-column label="时间" align="center" prop="createTime" />
  42. <el-table-column label="诊断依据" align="center" prop="diagnosisBasis">
  43. <template #default="scope">
  44. <span>{{getDictLabel(treatment_user_type ,scope.row.diagnosisBasis )|| '--' }}</span>
  45. </template>
  46. </el-table-column>
  47. <el-table-column label="看诊类型" align="center" prop="type">
  48. <template #default="scope">
  49. <span>{{getDictLabel(treatment_user_type ,scope.row.type )|| '--' }}</span>
  50. </template>
  51. </el-table-column>
  52. <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
  53. <el-table-column label="营养诊断" align="center" prop="diagnosisLabelStr" width="350" />
  54. <el-table-column label="诊断医生" align="center" prop="createByUser" />
  55. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  56. <template #default="scope">
  57. <el-tooltip content="详情" placement="top">
  58. <el-button link type="primary" icon="Edit" @click="handleDetail(scope.row)">详情</el-button>
  59. </el-tooltip>
  60. <el-tooltip content="删除" placement="top">
  61. <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
  62. </el-tooltip>
  63. </template>
  64. </el-table-column>
  65. </el-table>
  66. <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
  67. </el-card>
  68. </div>
  69. <div v-show="type === 'addForm'">
  70. <el-row :gutter="20">
  71. <el-col :span="20">
  72. <el-form ref="diagnosisFormRef" :model="form" :rules="rules" label-width="120px">
  73. <el-form-item label="营养诊断:" prop="diagnosisLableId">
  74. <el-select v-model="form.labelList" multiple placeholder="请选择" style="width: 100%;" :disabled="true" @click="labelDialogVisible = true" class="custom-label-select">
  75. <el-option v-for="item in labelOptions" :key="item.labelId" :label="item.labelName" :value="item.labelId">
  76. <el-tag type="info" size="small">{{ item.labelName }}</el-tag>
  77. </el-option>
  78. </el-select>
  79. </el-form-item>
  80. <el-form-item label="营养诊断依据:" prop="diagnosisBasisId">
  81. <div class="diagnosis-basis-list">
  82. <div v-if="diagnosisBasisList.length > 0">
  83. <div v-for="(item, index) in diagnosisBasisList" :key="item.id" class="basis-item">
  84. <el-input v-model="item.content" type="textarea" :rows="item.content.split('\n').length + 1" readonly resize="none" />
  85. <el-button type="danger" @click="removeBasisItem(index)">删除</el-button>
  86. </div>
  87. </div>
  88. <div v-else>
  89. <div class="basis-item">
  90. <el-input placeholder="请选择营养筛查/评估结果" readonly resize="none" />
  91. </div>
  92. </div>
  93. </div>
  94. </el-form-item>
  95. <el-form-item label="营养会诊结论:">
  96. <div class="consultation-toolbar">
  97. <el-button type="danger" plain @click="clearContent">清空记录</el-button>
  98. <el-button @click="showTemplateDialog = true">导入模板</el-button>
  99. </div>
  100. </el-form-item>
  101. <el-form-item>
  102. <Editor v-model="form.consultantResult" placeholder="请输入内容..." style="min-height: 200px; width: 100%;" />
  103. </el-form-item>
  104. <el-form-item label="营养医嘱:" prop="medicalOrder">
  105. <el-input v-model="form.medicalOrder" type="textarea" :rows="5" placeholder="请输入" clearable />
  106. </el-form-item>
  107. </el-form>
  108. </el-col>
  109. <!-- 营养筛查和评估的选择项 -->
  110. <el-col :span="4">
  111. <div class="screen-eval-card">
  112. <div>
  113. <div class="card-title">营养筛查/评估</div>
  114. <span style="font-size: 12px;">(点击添加下列筛查结果增加诊断依据)</span>
  115. <div style="border-bottom: 2px solid #ccc;margin-top: 10px;width: 100%;"></div>
  116. <div>
  117. <span style="margin-top: 15px;">时间:</span>
  118. <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" style="width: 70%;margin-top: 10px;"></el-date-picker>
  119. </div>
  120. </div>
  121. <div v-for="item in screenEvalList" :key="item.id" class="screen-eval-item">
  122. <div class="eval-content">
  123. <div v-if="item.type === 'evaluation'">
  124. <div>评估时间:{{ item.date }}</div>
  125. <div>营养评估类型:{{ item.evalType }}</div>
  126. <div v-for="(v, i) in item.energyArr" :key="i">{{ v }}</div>
  127. <div>{{ item.suggestion }}</div>
  128. </div>
  129. <div v-else>
  130. <div>筛查时间:{{ item.date }}</div>
  131. <div>营养筛查方法:{{ item.method }}</div>
  132. <div>营养风险总评分:{{ item.score }}</div>
  133. <div>筛查结论:{{ item.conclusion }}</div>
  134. </div>
  135. </div>
  136. <div class="eval-button">
  137. <el-button type="success" size="small" @click="addToDiagnosisBasis(item)">
  138. 【添加至诊断依据】
  139. </el-button>
  140. </div>
  141. </div>
  142. </div>
  143. </el-col>
  144. </el-row>
  145. <LabelDialog v-model="labelDialogVisible" :initial-selected-labels="labelOptions || []" @confirm="onLabelConfirm" />
  146. <ConsultantTemplateDialog v-model:visible="showTemplateDialog" @select="onTemplateSelect" />
  147. <div class="footter-low" style="text-align: center; margin-top: 100px">
  148. <el-button @click="handleCancel">取 消</el-button>
  149. <el-button :loading="buttonLoading" type="primary" @click="submitForm">提 交</el-button>
  150. </div>
  151. </div>
  152. <!-- 详情弹窗始终挂载在最外层div内 -->
  153. <detail-dialog v-model="showDetailDialog" :detail="currentDetail" />
  154. </div>
  155. </template>
  156. <script setup name="Diagnosis" lang="ts">
  157. import { listDiagnosis, getDiagnosis, delDiagnosis, addDiagnosis, updateDiagnosis } from '@/api/patients/diagnosis';
  158. import { DiagnosisVO, DiagnosisQuery, DiagnosisForm } from '@/api/patients/diagnosis/types';
  159. import { getTreatmentUser as fetchTreatmentUser } from '@/api/workbench/treatmentUser';
  160. import LabelDialog from '@/views/warehouse/nutriProduct/labelDialog.vue';
  161. import { getDiseaseLabel } from '@/api/system/diseaseLabel'; // 新增: 导入获取标签详情API
  162. import { listEvaluation } from '@/api/patients/evaluation';
  163. import { EvaluationVO, EvaluationQuery, EvaluationForm } from '@/api/patients/evaluation/types';
  164. import { listScreening } from '@/api/patients/screening';
  165. import { ScreeningVO, ScreeningQuery, ScreeningForm } from '@/api/patients/screening/types';
  166. import DetailDialog from './detailDialog.vue';
  167. import { watch } from 'vue';
  168. const emit = defineEmits(['change'])
  169. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  170. const ConsultantTemplateDialog = defineAsyncComponent(() => import('./consultantTemplateDialog.vue'));
  171. const { treatment_user_type } = toRefs < any > (proxy ?.useDict('treatment_user_type'));
  172. const diagnosisBasisList = ref < DiagnosisBasisItem[] > ([]);
  173. const newBasisItem = ref('');
  174. const diagnosisList = ref < DiagnosisVO[] > ([]);
  175. const buttonLoading = ref(false);
  176. const loading = ref(true);
  177. const showSearch = ref(true);
  178. const ids = ref < Array < string | number >> ([]);
  179. const single = ref(true);
  180. const multiple = ref(true);
  181. const total = ref(0);
  182. const type = ref('list');
  183. const labelDialogVisible = ref(false);
  184. const labelOptions = ref < any[] > ([]); // 新增: 用于存储可选标签对象
  185. const showDetailDialog = ref(false);
  186. const currentDetail = ref({});
  187. const queryFormRef = ref < ElFormInstance > ();
  188. const diagnosisFormRef = ref < ElFormInstance > ();
  189. const showTemplateDialog = ref(false);
  190. const diagnosisBasisStr = ref('');
  191. const dialog = reactive < DialogOption > ({
  192. visible: false,
  193. title: ''
  194. });
  195. interface DiagnosisBasisItem {
  196. id: string; // 用于防重
  197. content: string; // 用于显示
  198. }
  199. // 声明接收的 props
  200. const props = defineProps({
  201. patientInfo: {
  202. type: Object,
  203. required: true,
  204. default: () => ({
  205. id: '',
  206. name: '',
  207. age: '',
  208. gender: ''
  209. })
  210. }
  211. });
  212. const initFormData: DiagnosisForm = {
  213. id: undefined,
  214. labelList: [],
  215. type: props.patientInfo ?.type,
  216. deptId: props.patientInfo ?.deptId,
  217. treatmentUserId: props.patientInfo ?.id,
  218. consultantTemplateId: undefined,
  219. diagnosisLableId: undefined,
  220. diagnosisBasisId: undefined,
  221. medicalOrder: undefined,
  222. consultantResult: undefined,
  223. consultantResultStr: undefined,
  224. }
  225. const data = reactive < PageData < DiagnosisForm,
  226. DiagnosisQuery >> ({
  227. form: { ...initFormData },
  228. queryParams: {
  229. pageNum: 1,
  230. pageSize: 10,
  231. visitType: undefined,
  232. treatmentUserId: props.patientInfo ?.id,
  233. dateRange: undefined,
  234. searchValue: undefined,
  235. params: {}
  236. },
  237. rules: {
  238. diagnosisLableId: [
  239. { required: false, message: "营养诊断不能为空", trigger: ['blur', 'change'] }
  240. ],
  241. medicalOrder: [
  242. { required: true, message: "医嘱不能为空", trigger: "blur" }
  243. ],
  244. }
  245. });
  246. const { queryParams, form, rules } = toRefs(data);
  247. // 监听患者ID变化,自动同步到表单和查询参数
  248. watch(
  249. () => props.patientInfo.id,
  250. (newId) => {
  251. form.value.treatmentUserId = newId;
  252. queryParams.value.treatmentUserId = newId;
  253. }, { immediate: true }
  254. );
  255. // 添加筛查/评估结果
  256. const addToDiagnosisBasis = (item: any) => {
  257. // 1. 检查是否已添加(基于ID)
  258. const isAlreadyAdded = diagnosisBasisList.value.some(
  259. entry => entry.id === item.id
  260. );
  261. if (isAlreadyAdded) {
  262. ElMessage.warning('该条目已添加至诊断依据!');
  263. return;
  264. }
  265. // 2. 拼接 diagnosisBasisId(分号分隔)
  266. if (item.id) {
  267. const currentIds = form.value.diagnosisBasisId ?
  268. form.value.diagnosisBasisId.split(';').map(id => id.trim()).filter(Boolean) : [];
  269. if (!currentIds.includes(item.id)) {
  270. form.value.diagnosisBasisId = currentIds.length > 0 ?
  271. `${form.value.diagnosisBasisId};${item.id}` :
  272. item.id;
  273. }
  274. }
  275. // 3. 生成显示内容(不包含ID)
  276. let content = '';
  277. if (item.type === 'evaluation') {
  278. content = `
  279. 评估时间:${item.date}
  280. 营养评估类型:${item.evalType}
  281. ${item.energyArr?.join('\n') || ''}
  282. ${item.suggestion}
  283. `.trim();
  284. } else {
  285. content = `
  286. 筛查时间:${item.date}
  287. 营养筛查方法:${item.method}
  288. 营养风险总评分:${item.score}
  289. 筛查结论:${item.conclusion}
  290. `.trim();
  291. }
  292. // 4. 存储到列表
  293. diagnosisBasisList.value.push({
  294. id: item.id,
  295. content: content
  296. });
  297. };
  298. const removeBasisItem = (index: number) => {
  299. // 获取要删除的项目
  300. const itemToRemove = diagnosisBasisList.value[index];
  301. if (itemToRemove && itemToRemove.id) {
  302. // 从 diagnosisBasisId 中移除对应的ID
  303. const diagnosisBasisIdStr = form.value.diagnosisBasisId ? String(form.value.diagnosisBasisId) : '';
  304. const currentIds = diagnosisBasisIdStr ?
  305. diagnosisBasisIdStr.split(';').map((id: string) => id.trim()).filter(Boolean) : [];
  306. // 过滤掉要删除的ID
  307. const updatedIds = currentIds.filter((id: string) => id !== String(itemToRemove.id));
  308. // 更新 diagnosisBasisId
  309. form.value.diagnosisBasisId = updatedIds.length > 0 ? updatedIds.join(';') : undefined;
  310. }
  311. // 从显示列表中删除项目
  312. diagnosisBasisList.value.splice(index, 1);
  313. };
  314. /** 查询营养诊断列表 */
  315. const getList = async () => {
  316. loading.value = true;
  317. try {
  318. const res = await listDiagnosis(queryParams.value);
  319. diagnosisList.value = res.rows || [];
  320. total.value = res.total || 0;
  321. } catch (error) {
  322. proxy ?.$modal.msgError('获取列表失败');
  323. diagnosisList.value = [];
  324. }
  325. loading.value = false;
  326. }
  327. /** 取消按钮 */
  328. const cancel = () => {
  329. reset();
  330. dialog.visible = false;
  331. }
  332. // 标签确认回调
  333. function onLabelConfirm(selectedLabels: Array < { labelId: string | number;labelName: string } > ) {
  334. form.value.labelList = selectedLabels.map(l => l.labelId); // 只存labelId
  335. labelOptions.value = selectedLabels; // 用于el-option展示labelName
  336. }
  337. const onTemplateSelect = async (data) => {
  338. form.value.consultantTemplateId = data.id;
  339. let templateContent = data.template;
  340. console.log(JSON.stringify(data));
  341. if (!templateContent) return;
  342. try {
  343. // 获取患者详细信息
  344. const res = await fetchTreatmentUser(props.patientInfo ?.id);
  345. const patientDetail = res.data as any || {};
  346. form.value.consultantTemplateId = data.id;
  347. // 替换模板中的占位符
  348. let processedContent = templateContent;
  349. // 定义替换规则(根据实际字段进行调整)
  350. const replacements = {
  351. 'purpose': patientDetail.type == 1 ? '住院' : '门诊' || '',
  352. 'height': patientDetail.height || '',
  353. 'weight': patientDetail.weight || '',
  354. 'bmi': patientDetail.bmi || '',
  355. 'alb': patientDetail.alb || '',
  356. 'hgb': patientDetail.hgb || '',
  357. 'nrs2002Score': patientDetail.nrs2002Score || '',
  358. 'nrs2002Conclusion': patientDetail.nrs2002Conclusion || '',
  359. 'beforeAlb': patientDetail.beforeAlb || '',
  360. 'way': patientDetail.way || '',
  361. 'glimResult': patientDetail.glimResult || '',
  362. 'lossWeight': patientDetail.lossWeight || '',
  363. 'totalCalories': patientDetail.totalCalories || '',
  364. 'totalProtein': patientDetail.totalProtein || '',
  365. 'lossWeightRate': patientDetail.lossWeightRate || '',
  366. 'totalFood24retrospectProtein': patientDetail.totalFood24retrospectProtein || '',
  367. 'totalFood24retrospectCalories': patientDetail.totalFood24retrospectCalories || '',
  368. // 可以根据需要添加更多替换规则
  369. };
  370. // 执行替换
  371. for (const [key, value] of Object.entries(replacements)) {
  372. const placeholder = '${' + key + '}';
  373. console.log(`Replacing ${placeholder} with ${value}`);
  374. processedContent = processedContent.split(placeholder).join(value);
  375. }
  376. // 将处理后的内容赋值给表单
  377. form.value.consultantResult = processedContent;
  378. } catch (error) {
  379. console.error('获取患者详情失败:', error);
  380. proxy ?.$modal.msgError('获取患者详情失败');
  381. // 如果获取详情失败,仍然使用原始模板
  382. form.value.consultantResult = templateContent;
  383. }
  384. };
  385. /** 表单重置 */
  386. const reset = () => {
  387. form.value = {
  388. ...initFormData,
  389. treatmentUserId: props.patientInfo ?.id // 用最新id
  390. };
  391. diagnosisFormRef.value ?.resetFields();
  392. }
  393. /** 搜索按钮操作 */
  394. const handleQuery = () => {
  395. queryParams.value.pageNum = 1;
  396. getList();
  397. }
  398. /** 重置按钮操作 */
  399. const resetQuery = () => {
  400. queryFormRef.value ?.resetFields();
  401. queryParams.value.dateRange = undefined;
  402. queryParams.value.type = undefined;
  403. queryParams.value.searchValue = undefined;
  404. queryParams.value.pageNum = 1;
  405. queryParams.value.pageSize = 10;
  406. handleQuery();
  407. }
  408. // 字典label工具
  409. function getDictLabel(dictList: any[], value: string) {
  410. if (!dictList || !Array.isArray(dictList)) return value || '--';
  411. const found = dictList.find(item => item.value === value);
  412. return found ? found.label : value || '--';
  413. }
  414. /** 多选框选中数据 */
  415. const handleSelectionChange = (selection: DiagnosisVO[]) => {
  416. ids.value = selection.map(item => item.id);
  417. single.value = selection.length != 1;
  418. multiple.value = !selection.length;
  419. }
  420. /** 新增按钮操作 */
  421. const handleAdd = () => {
  422. reset();
  423. type.value = 'addForm';
  424. form.value.treatmentUserId = props.patientInfo ?.id;
  425. }
  426. const handleCancel = () => {
  427. type.value = 'list';
  428. };
  429. const clearContent = () => {
  430. form.value.consultantResult = '';
  431. }
  432. /** 修改按钮操作 */
  433. const handleUpdate = async (row ? : DiagnosisVO) => {
  434. reset();
  435. const _id = row ?.id || ids.value[0]
  436. const res = await getDiagnosis(_id);
  437. Object.assign(form.value, res.data);
  438. // 适配labelList为labelId数组时,需获取完整标签对象
  439. if (Array.isArray(form.value.labelList) && form.value.labelList.length > 0 && typeof form.value.labelList[0] !== 'object') {
  440. // 批量获取标签详情
  441. const labelIds = form.value.labelList;
  442. const labelDetailPromises = labelIds.map(id => getDiseaseLabel(id).then(r => r.data));
  443. labelOptions.value = await Promise.all(labelDetailPromises);
  444. } else {
  445. labelOptions.value = form.value.labelList || [];
  446. }
  447. dialog.visible = true;
  448. dialog.title = "修改营养诊断";
  449. }
  450. /** 提交按钮 */
  451. const submitForm = () => {
  452. diagnosisFormRef.value ?.validate(async (valid: boolean) => {
  453. if (valid) {
  454. buttonLoading.value = true;
  455. if (form.value.id) {
  456. form.value.consultantResultStr = window.btoa(encodeURIComponent(form.value.consultantResult))
  457. await updateDiagnosis(form.value).finally(() => buttonLoading.value = false);
  458. } else {
  459. form.value.consultantResultStr = window.btoa(encodeURIComponent(form.value.consultantResult))
  460. await addDiagnosis(form.value).finally(() => buttonLoading.value = false);
  461. }
  462. proxy ?.$modal.msgSuccess("操作成功");
  463. dialog.visible = false;
  464. await getList();
  465. type.value = 'list';
  466. }
  467. });
  468. }
  469. /** 删除按钮操作 */
  470. const handleDelete = async (row ? : DiagnosisVO) => {
  471. const _ids = row ?.id || ids.value;
  472. await proxy ?.$modal.confirm('是否确认删除营养诊断编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
  473. await delDiagnosis(_ids);
  474. proxy ?.$modal.msgSuccess("删除成功");
  475. await getList();
  476. }
  477. const handleDetail = (row: any) => {
  478. currentDetail.value = row as any;
  479. currentDetail.value.consultantResult = stripHtml((currentDetail.value as any).consultantResult);
  480. showDetailDialog.value = true;
  481. };
  482. function stripHtml(html) {
  483. const div = document.createElement('div');
  484. div.innerHTML = html;
  485. return div.textContent || div.innerText || '';
  486. }
  487. const screenEvalDateRange = ref < any[] > ([]);
  488. const screenEvalList = ref < any[] > ([]);
  489. const fetchScreenEvalList = async () => {
  490. // 获取评估
  491. const evalRes = await listEvaluation({
  492. patientId: props.patientInfo ?.id,
  493. dateRange: screenEvalDateRange.value
  494. });
  495. // 获取筛查
  496. const screeningRes = await listScreening({
  497. patientId: props.patientInfo ?.id,
  498. dateRange: screenEvalDateRange.value
  499. });
  500. // 组装成统一格式
  501. const evalList = (evalRes.rows || []).map(row => {
  502. // 解析content字段,获取建议和热量摄入
  503. let suggestion = '';
  504. let energyArr = [];
  505. try {
  506. if (row.content) {
  507. const contentObj = typeof row.content === 'string' ? JSON.parse(row.content) : row.content;
  508. // 建议
  509. if (contentObj.suggestion) suggestion = contentObj.suggestion;
  510. // 热量摄入
  511. if (contentObj.energyIntakeList && Array.isArray(contentObj.energyIntakeList)) {
  512. energyArr = contentObj.energyIntakeList.map(e => `${e.date}热量摄入:${e.value}kcal/d`);
  513. }
  514. }
  515. } catch (e) {}
  516. return {
  517. id: row.id,
  518. type: 'evaluation',
  519. date: formatDate(row.evaluationTime || row.screeningTime || row.createTime),
  520. evalType: row.configName,
  521. energyArr,
  522. suggestion: suggestion || row.suggestion || row.remark || '',
  523. };
  524. });
  525. const screeningList = (screeningRes.rows || []).map(row => {
  526. // 解析content字段,获取结论
  527. let conclusion = '';
  528. try {
  529. if (row.content) {
  530. const contentObj = typeof row.content === 'string' ? JSON.parse(row.content) : row.content;
  531. if (contentObj.conclusion) conclusion = contentObj.conclusion;
  532. }
  533. } catch (e) {}
  534. return {
  535. id: row.id,
  536. type: 'screening',
  537. date: formatDate(row.screeningTime || row.createTime),
  538. method: row.configName,
  539. score: row.screeningScore,
  540. conclusion: conclusion || row.screeningConclusion || '',
  541. };
  542. });
  543. screenEvalList.value = [...evalList, ...screeningList];
  544. };
  545. const formatDate = (dateStr) => {
  546. if (!dateStr) return '';
  547. const date = new Date(dateStr);
  548. const year = date.getFullYear();
  549. const month = String(date.getMonth() + 1).padStart(2, '0');
  550. const day = String(date.getDate()).padStart(2, '0');
  551. return `${year}-${month}-${day}`;
  552. };
  553. onMounted(() => {
  554. getList();
  555. fetchScreenEvalList();
  556. });
  557. </script>
  558. <style lang="scss" scoped>
  559. .screen-eval-card {
  560. margin-bottom: 10px;
  561. background: #fff;
  562. }
  563. .card-title {
  564. font-weight: bold;
  565. font-size: 16px;
  566. margin-bottom: 8px;
  567. padding: 10px;
  568. }
  569. .card-tip {
  570. color: #999;
  571. font-size: 12px;
  572. margin-left: 8px;
  573. }
  574. .screen-eval-item {
  575. background: #f4f4f4;
  576. border-radius: 6px;
  577. padding: 10px 12px;
  578. margin-bottom: 10px;
  579. box-shadow: 0 1px 2px #eee;
  580. display: flex;
  581. justify-content: space-between;
  582. align-items: flex-start;
  583. }
  584. .eval-content {
  585. flex: 1;
  586. font-size: 14px;
  587. color: #333;
  588. line-height: 1.7;
  589. }
  590. .diagnosis-basis-list {
  591. margin-bottom: 10px;
  592. }
  593. .basis-item {
  594. display: flex;
  595. align-items: flex-start;
  596. /* 顶部对齐 */
  597. margin-bottom: 10px;
  598. width: 65vw;
  599. }
  600. .basis-item .el-textarea {
  601. flex: 1;
  602. margin-right: 8px;
  603. }
  604. /* 确保文本换行 */
  605. .el-textarea__inner {
  606. white-space: pre-line;
  607. }
  608. .screen-eval-item {
  609. display: flex;
  610. flex-direction: column;
  611. margin-bottom: 16px;
  612. padding: 12px;
  613. background: #f9f9f9;
  614. border-radius: 4px;
  615. }
  616. .eval-content div {
  617. margin-bottom: 4px;
  618. line-height: 1.5;
  619. }
  620. .eval-button {
  621. margin-top: 8px;
  622. text-align: right;
  623. }
  624. @media (max-width: 768px) {
  625. .eval-button .el-button {
  626. width: 100%;
  627. }
  628. }
  629. .eval-button .el-button:hover {
  630. opacity: 0.8;
  631. }
  632. .footter-low {
  633. position: fixed;
  634. z-index: 99;
  635. bottom: 0;
  636. left: calc(var(--left-menu-max-width) + var(--app-content-padding));
  637. right: 0;
  638. height: 90px;
  639. display: flex;
  640. justify-content: center;
  641. align-items: center;
  642. background: #fff;
  643. box-shadow: 0 -3px 6px 1px #6c6d6f26;
  644. width: 90vw;
  645. margin-right: 10px;
  646. .el-button {
  647. margin-top: 30px;
  648. min-width: 120px;
  649. height: 44px;
  650. padding: 0 24px;
  651. }
  652. }
  653. </style>