Bläddra i källkod

2.4 中医诊疗→智能开方页,新增 舌象分析

cc12458 1 år sedan
förälder
incheckning
e6d01b1c58

+ 3 - 3
package-lock.json

@@ -4601,9 +4601,9 @@
       "dev": true
     },
     "element-ui": {
-      "version": "2.15.1",
-      "resolved": "https://registry.npmmirror.com/element-ui/-/element-ui-2.15.1.tgz",
-      "integrity": "sha512-TqlScAKGH97XndSScUDeEHIzL1x7yg7DvQdKPEOUdiDcyIz3y3FJJBlpHYaJT96FOn1xpIcUZb+I2FJeU9EcrQ==",
+      "version": "2.15.14",
+      "resolved": "https://registry.npmmirror.com/element-ui/-/element-ui-2.15.14.tgz",
+      "integrity": "sha512-2v9fHL0ZGINotOlRIAJD5YuVB8V7WKxrE9Qy7dXhRipa035+kF7WuU/z+tEmLVPBcJ0zt8mOu1DKpWcVzBK8IA==",
       "requires": {
         "async-validator": "~1.8.1",
         "babel-helper-vue-jsx-merge-props": "^2.0.0",

+ 1 - 1
package.json

@@ -11,7 +11,7 @@
     "axios": "^0.21.1",
     "core-js": "^3.6.5",
     "echarts": "^4.8.0",
-    "element-ui": "^2.15.1",
+    "element-ui": "^2.15.14",
     "vue": "^2.6.11",
     "vue-print-nb": "^1.7.4",
     "vue-router": "^3.2.0",

+ 16 - 0
src/api/diagnosis.js

@@ -1,4 +1,5 @@
 import request from '@/utils/request.js'
+import {fromTongueAndFaceAnalysisModel} from "@/model/tongue-analysis,model";
 
 // 获取就诊病人信息
 export function getPatiiensMsg(data) {
@@ -440,4 +441,19 @@ export function getMaxMinDoaseNumber(data) {
         method: 'post',
         data
     })
+}
+
+export function getTongueAndFaceAnalysis(data) {
+    return request({
+        url: '/outpatient/electronicmedicalrecordMgr/getTongueFaceAnalysisResult',
+        method: 'post',
+        data,
+        params: {recordsId: data.recordsId},
+    }).then(res => {
+        if (res.ResultCode == 0) {
+            return res.Data = fromTongueAndFaceAnalysisModel(res.Data), res;
+        } else {
+            throw res
+        }
+    })
 }

+ 61 - 0
src/model/tongue-analysis,model.js

@@ -0,0 +1,61 @@
+/**
+ * 解析舌象异常数据
+ * @param {{title: string; cover: string; descriptions: string[]; tags: string[];}[]} exception
+ * @param {{actualList: Record<string, any>[]}} [data]
+ * @return {string}
+ */
+function fromReportTongueExceptionData(exception, data) {
+    if (data == null || !Array.isArray(data.actualList)) return '';
+    return data.actualList.map(item => {
+        if (!item) return '';
+        let title = item.actualValue || '';
+        const suffix = item.contrast || 's';
+        if (suffix !== 's') {
+            title += ` (${suffix || ''}) `;
+            exception.push({
+                title, cover: item.splitImage,
+                descriptions: [
+                    item.features ? `【特征】${item.features}` : '',
+                    item.clinicalSignificance ? `【临床意义】${item.clinicalSignificance}` : '',
+                ].filter(Boolean),
+                tags: item.attrs ?? [],
+            });
+        }
+        return title;
+    }).join('<br>');
+}
+
+/**
+ * 解析舌面象数据
+ * @param {Record<string, any>} data
+ */
+export function fromTongueAndFaceAnalysisModel(data) {
+    if (data == null || typeof data !== 'object') data = {};
+    const tongueException = [];
+    const fromTongueException = fromReportTongueExceptionData.bind(null, tongueException);
+    const fromTongueValue = (data) => data && typeof data === 'object' ? data.standardValue || '' : '';
+
+    return {
+        tongueTable: {
+            column: ['舌象维度', '检测结果', '标准值'],
+            data: [
+                ['舌色', fromTongueException(data.tongueColor), fromTongueValue(data.tongueColor)],
+                ['苔色', fromTongueException(data.tongueCoatingColor), fromTongueValue(data.tongueCoatingColor)],
+                ['舌形', fromTongueException(data.tongueShape), fromTongueValue(data.tongueShape)],
+                ['苔质', fromTongueException(data.tongueCoating), fromTongueValue(data.tongueCoating)],
+                ['津液', fromTongueException(data.bodyFluid), fromTongueValue(data.bodyFluid)],
+                ['舌下', fromTongueException(data.sublingualVein), fromTongueValue(data.sublingualVein)],
+            ],
+        },
+        tongueException,
+        tongueAnalysis: {
+            ['结果']: data.tongueAnalysisResult,
+            ['舌上']: data.upImg,
+            ['舌下']: data.downImg,
+        },
+        faceAnalysis: {
+            ['结果']: data.faceAnalysisResult,
+            ['面象']: data.faceImg,
+        },
+    }
+}

+ 39 - 0
src/views/diagnosis/Prescribing.vue

@@ -314,6 +314,7 @@
         <!-- 右侧按钮 -->
         <div class="flex-vertical-center-r flex-wrap">
           <el-button size="mini" @click="openUnifyPrescPrec" type="primary">统建处方</el-button>
+          <el-button size="mini" :loading="tongueAndFaceLoading" :disabled="!tongueAndFaceAnalysis" @click="openTongueAndFaceAnalysis" type="primary">舌象分析</el-button>
           <el-button
             size="mini"
             type="primary"
@@ -1070,6 +1071,20 @@
       </div>
     </Popup>
 
+    <!-- 查询舌象分析 页面768 -->
+    <Popup
+        :showDialog="showTongueAnalysis"
+        @cancle="showTongueAnalysis=false"
+        title="分析详情"
+        :showBtns="false"
+        width="700px"
+        distanceTop="5vh"
+    >
+      <div slot="body">
+        <TongueAnalysis :dataset="tongueAndFaceAnalysis"></TongueAnalysis>
+      </div>
+    </Popup>
+
     <!-- 安全合理用药弹窗 -->
     <!-- 查询协定方 方剂 页面768 -->
     <Popup
@@ -1122,11 +1137,13 @@ import TCMDiagnosis from "../../components/TCMDiagnosis.vue";
 import doctorCase from "./components/doctorCase.vue";
 import prescription from "./components/prescription.vue";
 import UnifyPrescription from "./components/prescription-unify.vue";
+import TongueAnalysis from "./components/tongue-analysis.vue";
 import safeDrug from "./components/safeDrug.vue";
 import medAdress from "./components/medAddress.vue";
 import medAdressNew from "./components/medAddressNew.vue";
 import {
   getPatiensBasisM,
+  getTongueAndFaceAnalysis,
   addRecipe,
   getRecipeShowData,
   getRecipeDataByid,
@@ -1173,6 +1190,7 @@ export default {
     submitRecipe,
     prescription,
     UnifyPrescription,
+    TongueAnalysis,
     doctorCase,
     safeDrug,
     medAdress,
@@ -1180,6 +1198,10 @@ export default {
   },
   data() {
     return {
+      tongueAndFaceLoading: false, // 舌面象加载
+      tongueAndFaceAnalysis: null, // 舌面象数据
+      showTongueAnalysis: false, // 舌象分析弹窗
+
       showPriview: false, // 展示预览数据
       showDialog: false, // 方剂详情
       showDrug: false, // 药品详情
@@ -1342,6 +1364,7 @@ export default {
 
     if (this.getPatiensInfo.pid) {
       this.getPatiensBasisM();
+      this.getPatientBasisTongueAndFaceAnalysis();
     }
   },
   mounted() {
@@ -3158,6 +3181,22 @@ export default {
         // }
       }
     },
+    async openTongueAndFaceAnalysis() {
+      if (!this.tongueAndFaceAnalysis) await this.getPatientBasisTongueAndFaceAnalysis()
+      if (this.tongueAndFaceAnalysis) this.showTongueAnalysis = true;
+    },
+    // 获取病人 舌面象数据
+    async getPatientBasisTongueAndFaceAnalysis() {
+      this.tongueAndFaceLoading = true;
+      try {
+        let res = await getTongueAndFaceAnalysis({
+          recordsId: this.getPatiensInfo ? this.getPatiensInfo.pid : ""
+          // recordsId: '8ed63872-6d1f-4fe6-b170-4d36e677a744',
+        });
+        this.tongueAndFaceAnalysis = res.Data && (res.Data.tongueAnalysis.结果 || res.Data.faceAnalysis.结果) ? res.Data : null;
+      } catch (e) {}
+      this.tongueAndFaceLoading = false;
+    },
     // 获取处方预览数据
     async _getRecipePriview(zhongyao, zhongchengyao, technology) {
       const loading = this.$loading({

+ 179 - 0
src/views/diagnosis/components/tongue-analysis.vue

@@ -0,0 +1,179 @@
+<template>
+  <!-- 舌象分析详情 -->
+  <div class="tongue-analysis">
+    <template v-if="dataset && (dataset.tongueAnalysis.结果 || dataset.faceAnalysis.结果)">
+      <template v-if="dataset.tongueAnalysis && dataset.tongueAnalysis.结果">
+        <el-card class="tongue-exception-wrapper" v-if="showException">
+          <div slot="header" class="card-header-container">
+            <span>异常舌象分析</span>
+            <el-button size="small" type="primary" plain style="float: right;" @click="showException=false">
+              舌象分析
+            </el-button>
+          </div>
+          <div class="card-body-container">
+            <el-card v-for="item in dataset.tongueException" :key="item.title" class="inner" size="small">
+              <div class="card__title">{{ item.title }}</div>
+              <div class="card__content">
+                <div style="display: flex;">
+                  <el-image :src="item.cover" lazy fit="scale-down" :preview-src-list="[item.cover]"></el-image>
+                  <div>
+                    <el-tag v-for="value in item.tags" :key="value" type="danger">{{ value }}</el-tag>
+                  </div>
+                </div>
+                <p class="my-2 text-grey" v-for="value in item.descriptions" :key="value">{{ value }}</p>
+              </div>
+            </el-card>
+          </div>
+        </el-card>
+        <el-card v-else>
+          <div slot="header" class="card-header-container">
+            <span>舌象分析</span>
+            <el-button
+                v-if="dataset.tongueException && dataset.tongueException.length"
+                size="small" type="danger" plain style="float: right;" @click="showException=true">
+              异常舌象分析
+            </el-button>
+          </div>
+          <div class="card-body-container">
+            <el-table v-if="dataset.tongueTable" class="result-wrapper" :data="dataset.tongueTable.data" border
+                      size="small">
+              <el-table-column
+                  v-for="(col, index) in dataset.tongueTable.column" :key="col"
+                  :prop="index + ''" :label="col" align="center"
+              >
+                <template v-slot="{row, column}">
+                  <div v-html="row[index]"></div>
+                </template>
+              </el-table-column>
+            </el-table>
+            <div v-else class="result-wrapper">{{ dataset.tongueAnalysis.结果 }}</div>
+            <div class="picture-wrapper">
+              <el-image :src="dataset.tongueAnalysis.舌上" lazy fit="scale-down"
+                        :preview-src-list="preview"></el-image>
+              <el-image :src="dataset.tongueAnalysis.舌下" lazy fit="scale-down"
+                        :preview-src-list="preview"></el-image>
+            </div>
+          </div>
+        </el-card>
+      </template>
+      <el-card v-if="dataset.faceAnalysis && dataset.faceAnalysis.结果">
+        <div slot="header" class="card-header-container">
+          <span>面象分析</span>
+        </div>
+        <div class="card-body-container">
+          <div class="result-wrapper">{{ dataset.faceAnalysis.结果 }}</div>
+          <div class="picture-wrapper">
+            <el-image :src="dataset.faceAnalysis.面象" lazy fit="scale-down" :preview-src-list="preview"></el-image>
+          </div>
+        </div>
+      </el-card>
+    </template>
+    <el-empty v-else-if="!loading" description="暂无数据"></el-empty>
+  </div>
+</template>
+<script>
+import {getTongueAndFaceAnalysis} from "@/api/diagnosis.js";
+
+export default {
+  props: {
+    dataset: {
+      type: Object,
+      default() { return null; }
+    }
+  },
+  data() {
+    return {
+      showException: false
+    };
+  },
+  computed: {
+    preview: function () {
+      return [
+        this.dataset.tongueAnalysis.舌上,
+        this.dataset.tongueAnalysis.舌下,
+        this.dataset.faceAnalysis.面象,
+      ].filter(Boolean);
+    }
+  },
+};
+</script>
+<style lang="scss" scoped>
+.tongue-analysis {
+  .el-card:not(.inner) {
+    margin: 24px 0;
+
+    &:first-of-type { margin-top: 0 }
+
+    &:last-of-type { margin-bottom: 0 }
+
+    &.tongue-exception-wrapper {
+      .card-body-container {
+        display: grid;
+        grid-template-rows: repeat(1, minmax(0, 1fr));
+        grid-template-columns: repeat(2, minmax(0, 1fr));
+        gap: 12px;
+      }
+
+      .card__title {
+        padding: 6px 12px;
+        color: #F56C6C;
+      }
+
+      .card__content {
+        padding: 6px 12px 12px;
+      }
+
+      .el-image {
+        width: 100px;
+        height: 100px;
+        margin-right: 12px;
+        margin-bottom: 12px;
+      }
+
+      .inner ::v-deep .el-card__body {
+        padding: 0;
+      }
+
+      p {
+        line-height: 1.75;
+
+        &:not(:last-of-type) { margin-bottom: 8px; }
+      }
+    }
+  }
+
+  .card-header-container {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 100%;
+  }
+
+  .card-body-container {
+    display: flex;
+
+    .result-wrapper {
+      flex: auto;
+    }
+
+    .picture-wrapper {
+      flex: none;
+      display: flex;
+      flex-direction: column;
+      justify-content: space-evenly;
+      margin-left: 12px;
+      max-width: 100px;
+
+      .el-image {
+        width: 100px;
+        height: 100px;
+      }
+    }
+  }
+
+  ::v-deep .el-card__header {
+    padding: 0 20px;
+    height: 56px;
+  }
+}
+</style>