فهرست منبع

开放页面适宜技术增加医派协定方和协定方

张田田 2 هفته پیش
والد
کامیت
b5519720ef

+ 119 - 35
src/components/ui/outpatientRecords.vue

@@ -163,33 +163,83 @@
                             <span>适宜技术处方</span>
                             <el-button type="primary" size="mini" v-if="syjszf">转方</el-button>
                         </div>
-                        <!-- 适宜技术穴位 -->
-                        <div class="flex flex-col-top flex-row-left syjs-option">
-                            <div>穴位:</div>
-                            <div class="syjs-right flex flex-row-left flex-wrap">
-                                <div class="syjs-item" v-for="(item1,index1) in item.prescriptiontechnologydetailVos"
-                                    :key="index1">{{item1.pointname}}</div>
-                            </div>
-                        </div>
-
-                        <div class="flex flex-col-top flex-row-left syjs-option">
-                            <div>类型:</div>
-                            <div class="syjs-right flex flex-row-left flex-wrap">
-                                {{item.technologyTypeName}}
-                            </div>
-                        </div>
-
-                        <div class="flex flex-col-top flex-row-left syjs-option">
-                            <div>次数:</div>
-                            <div class="syjs-right flex flex-row-left flex-wrap">
-                                {{item.num}}
-                            </div>
-                        </div>
-
-                        <div class="flex flex-col-top flex-row-left syjs-option">
-                            <div>嘱托:</div>
-                            <div class="syjs-right flex flex-row-left flex-wrap">
-                                {{item.command}}
+                        <!-- Rp 区:参考 suitMadePad 处方笺 -->
+                        <div class="syjs-rp">
+                            <div class="syjs-rp-detail">
+                                <!-- 类型 -->
+                                <div class="syjs-rp-option flex flex-col-top flex-row-left" v-if="item.technologyTypeName">
+                                    <div class="option-name">类型:</div>
+                                    <div class="option-right flex flex-wrap">{{item.technologyTypeName}}</div>
+                                </div>
+                                <!-- 穴位 -->
+                                <div class="syjs-rp-option flex flex-col-top flex-row-left" v-if="hasSyjsDetail(item, 'detailPoint')">
+                                    <div class="option-name">穴位:</div>
+                                    <div class="option-right flex flex-wrap">
+                                        <template v-for="(treatItem, ti) in (item.treatmentList || [])">
+                                            <div class="syjs-rp-item" v-for="(point, pi) in (treatItem.detailPoint || [])" :key="'syjs-point-'+index+'-'+ti+'-'+pi">
+                                                {{point.name}}<span v-if="point.num">{{point.num}}</span>
+                                            </div>
+                                        </template>
+                                    </div>
+                                </div>
+                                <!-- 经络 -->
+                                <div class="syjs-rp-option flex flex-col-top flex-row-left" v-if="hasSyjsDetail(item, 'detailMeridian')">
+                                    <div class="option-name">经络:</div>
+                                    <div class="option-right flex flex-wrap">
+                                        <template v-for="(treatItem, ti) in (item.treatmentList || [])">
+                                            <div class="syjs-rp-item" v-for="(meridian, mi) in (treatItem.detailMeridian || [])" :key="'syjs-meridian-'+index+'-'+ti+'-'+mi">
+                                                {{meridian.name}}<span v-if="meridian.num">{{meridian.num}}</span>
+                                            </div>
+                                        </template>
+                                    </div>
+                                </div>
+                                <!-- 耳穴 -->
+                                <div class="syjs-rp-option flex flex-col-top flex-row-left" v-if="hasSyjsDetail(item, 'detailEarPoint')">
+                                    <div class="option-name">耳穴:</div>
+                                    <div class="option-right flex flex-wrap">
+                                        <template v-for="(treatItem, ti) in (item.treatmentList || [])">
+                                            <div class="syjs-rp-item" v-for="(ear, ei) in (treatItem.detailEarPoint || [])" :key="'syjs-ear-'+index+'-'+ti+'-'+ei">
+                                                {{ear.name}}<span v-if="ear.num">{{ear.num}}</span>
+                                            </div>
+                                        </template>
+                                    </div>
+                                </div>
+                                <!-- 部位 -->
+                                <div class="syjs-rp-option flex flex-col-top flex-row-left" v-if="hasSyjsDetail(item, 'detailBodyPart')">
+                                    <div class="option-name">部位:</div>
+                                    <div class="option-right flex flex-wrap">
+                                        <template v-for="(treatItem, ti) in (item.treatmentList || [])">
+                                            <div class="syjs-rp-item" v-for="(part, bi) in (treatItem.detailBodyPart || [])" :key="'syjs-body-'+index+'-'+ti+'-'+bi">
+                                                {{part.name}}<span v-if="part.num">{{part.num}}</span>
+                                            </div>
+                                        </template>
+                                    </div>
+                                </div>
+                                <!-- 其他详情 -->
+                                <div class="syjs-rp-option flex flex-col-top flex-row-left" v-if="hasSyjsDetail(item, 'detailOther')">
+                                    <div class="option-name">其他详情:</div>
+                                    <div class="option-right flex flex-wrap">
+                                        <template v-for="(treatItem, ti) in (item.treatmentList || [])">
+                                            <div class="syjs-rp-item" v-for="(other, oi) in (treatItem.detailOther || [])" :key="'syjs-other-'+index+'-'+ti+'-'+oi">
+                                                {{other.name}}<span v-if="other.num">{{other.num}}</span>
+                                            </div>
+                                        </template>
+                                    </div>
+                                </div>
+                                <!-- 次数 -->
+                                <div class="syjs-rp-option flex flex-col-top flex-row-left" v-if="hasSyjsTreatNum(item)">
+                                    <div class="option-name">次数:</div>
+                                    <div class="option-right flex flex-wrap">
+                                        <template v-for="(treatItem, ti) in (item.treatmentList || [])">
+                                            <span class="syjs-rp-item" v-if="treatItem.treatNum" :key="'syjs-treatnum-'+index+'-'+ti">{{treatItem.treatNum}}次</span>
+                                        </template>
+                                    </div>
+                                </div>
+                                <!-- 嘱托 -->
+                                <div class="syjs-rp-option flex flex-col-top flex-row-left" v-if="item.command">
+                                    <div class="option-name">嘱托:</div>
+                                    <div class="option-right flex flex-wrap">{{item.command}}</div>
+                                </div>
                             </div>
                         </div>
                     </div>
@@ -242,6 +292,19 @@
             console.log(this.$route, 'route')
         },
         methods: {
+            // 检查适宜技术某类详情(穴位/经络/耳穴/部位/其他)是否有数据
+            hasSyjsDetail(item, detailType) {
+                if (!item || !item.treatmentList || !item.treatmentList.length) return false;
+                return item.treatmentList.some((t) => {
+                    const d = t[detailType];
+                    return Array.isArray(d) && d.length > 0;
+                });
+            },
+            // 检查适宜技术是否有治疗次数
+            hasSyjsTreatNum(item) {
+                if (!item || !item.treatmentList || !item.treatmentList.length) return false;
+                return item.treatmentList.some((t) => t.treatNum);
+            },
             // 中药转方
             zyTurn(item) {
                 console.log(this.$route, '页面路由')
@@ -386,16 +449,37 @@
                 flex: 0 0 20%;
             }
 
-            .syjs-right {
-                flex: 1;
-            }
+            // 适宜技术 Rp 区(参考 suitMadePad 处方笺)
+            .syjs-rp {
+                margin-top: 5px;
+                padding-left: 10px;
 
-            .syjs-item {
-                flex: 0 0 14%;
-            }
+                .syjs-rp-detail {
+                    font-size: 14px;
+                }
 
-            .syjs-option {
-                margin-bottom: 10px;
+                .syjs-rp-option {
+                    margin-bottom: 8px;
+                    padding-left: 20px;
+
+                    .option-name {
+                        flex-shrink: 0;
+                        white-space: nowrap;
+                    }
+
+                    .option-right {
+                        flex: 1;
+                    }
+                }
+
+                .syjs-rp-item {
+                    margin-right: 12px;
+                    margin-bottom: 4px;
+
+                    span {
+                        margin-left: 2px;
+                    }
+                }
             }
 
 

+ 12 - 0
src/utils/minix/prescribing.js

@@ -9,6 +9,8 @@ export default {
             showCase: false, // 参考医案弹窗
             showUnifyPresc: false, // 统建处方弹窗
             showPresc: false, // 方剂 协定方弹窗
+            showSuitUnifyPresc: false, // 统建处方弹窗副本(适宜技术-医派协定方按钮,可独立修改)
+            showSuitPresc: false, // 统建处方弹窗副本(适宜技术-协定方按钮,可独立修改)
             showSafeD: false, // 安全合理用药
             isShrink: false, // 是否是收缩状态
 
@@ -92,6 +94,16 @@ export default {
             this.showUnifyPresc = true
             addRecipeFrom({ type: 2 }).catch();
         },
+        // 适宜技术-医派协定方按钮 打开独立副本弹窗
+        openSuitUnifyPresc() {
+            this.showSuitUnifyPresc = true
+            addRecipeFrom({ type: 2 }).catch();
+        },
+        // 适宜技术-协定方按钮 打开独立副本弹窗
+        openSuitPresc() {
+            this.showSuitPresc = true
+            addRecipeFrom({ type: 2 }).catch();
+        },
         opensafeD() {
             this.showSafeD = true
         },

+ 83 - 21
src/views/diagnosis/Prescribing.vue

@@ -361,6 +361,7 @@
         </div>
         <!-- 右侧按钮 -->
         <div class="flex-vertical-center-r flex-wrap">
+          <el-button v-if="container_i == 2 && unifyPrescriptionTitle" size="mini" style="margin-right: 10px;" @click="openSuitUnifyPresc" type="primary">医派协定方</el-button>
           <AiEModal v-if="AI_MODEL_URL" :url="AI_MODEL_URL" title="e生大模型">
             <template #default="{ handle }">
               <el-button size="mini" style="margin-right: 10px;" @click="handle" type="primary">e生大模型</el-button>
@@ -373,6 +374,7 @@
             type="primary"
             @click="handleReplenish"
           >{{ innerWidth > 768 ? '补充中医电子病历' :'补充病历' }}</el-button>
+          <el-button v-if="container_i == 2" size="mini" @click="openSuitPresc" type="primary">协定方</el-button>
           <el-button size="mini" @click="openDCase" v-if="showPrec && isShrink">参考医案</el-button>
           <el-button v-if="showPrec" size="mini" @click="openPrec" type="primary">协定方/方剂</el-button>
           <el-popover
@@ -1056,6 +1058,34 @@
       </div>
     </Popup>
 
+    <!-- 查询医派协定方(适宜技术-医派协定方按钮,独立副本)页面768 -->
+    <Popup
+      :showDialog="showSuitUnifyPresc"
+      @cancle="showSuitUnifyPresc=false"
+      title="查询医派协定方"
+      :showBtns="false"
+      width="78%"
+      distanceTop="5vh"
+    >
+      <div slot="body">
+        <PrescriptionUnifySuit></PrescriptionUnifySuit>
+      </div>
+    </Popup>
+
+    <!-- 查询协定方(适宜技术-协定方按钮,独立副本)页面768 -->
+    <Popup
+      :showDialog="showSuitPresc"
+      @cancle="showSuitPresc=false"
+      title="查询协定方"
+      :showBtns="false"
+      width="78%"
+      distanceTop="5vh"
+    >
+      <div slot="body">
+        <PrescriptionSuit></PrescriptionSuit>
+      </div>
+    </Popup>
+
     <!-- 查询舌象分析 页面768 -->
     <Popup
         :showDialog="showTongueAnalysis"
@@ -1122,6 +1152,8 @@ 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 PrescriptionUnifySuit from "./components/prescription-unify-suit.vue";
+import PrescriptionSuit from "./components/prescription-suit.vue";
 import TongueAnalysis from "./components/tongue-analysis.vue";
 import safeDrug from "./components/safeDrug.vue";
 import medAdress from "./components/medAddress.vue";
@@ -1196,6 +1228,8 @@ export default {
     submitRecipe,
     prescription,
     UnifyPrescription,
+    PrescriptionUnifySuit,
+    PrescriptionSuit,
     TongueAnalysis,
     doctorCase,
     safeDrug,
@@ -1228,6 +1262,7 @@ export default {
       isTuiDaoZy: false, // 中药处方是否推导过
       raDoseShow: false,
       tjRecipeId: "", // 当前选中推荐 方剂的 id
+      suitActiveSafety: [], // 适宜技术右侧「安全合理检测」项目(传给 SuitTechSidePanel :safetyItems)
 
       isMyMade: true, // 是否是自拟处方
 
@@ -1410,10 +1445,13 @@ export default {
     this._processRouteQuery();
   },
   beforeRouteLeave(to, from, next) {
+    console.log('query===处方页面跳转', to.path);
     if (to.path == "/index/recipe") {
+      console.log('清缓存', to.path);
       sessionStorage.removeItem("prescr" + this.getPatiensInfo.pid);
       next();
     } else {
+      console.log('存缓存', to.path);   
       this._setDataToStorage(next);
     }
   },
@@ -1454,6 +1492,8 @@ export default {
     // 处理路由参数
     async _processRouteQuery() {
       const query = this.$route.query || {};
+      console.log('query======', sessionStorage.getItem("prescr" + this.getPatiensInfo.pid));
+      console.log('query.recipeID && query.kjType === "kj-fj"', query.recipeID, query.kjType === "kj-fj");
       // 暂存处方数据(不含药品)
       if (sessionStorage.getItem("prescr" + this.getPatiensInfo.pid)) await this._showDataFromStorage(true);
 
@@ -1585,6 +1625,10 @@ export default {
       let child2 = children[1];
       let child3 = children[2];
 
+      // 适宜技术:存前先把当前活动处方页的编辑同步进 prescriptionDataMap,
+      // 否则缓存的 map 会漏当前页(镜像 detailTables 没存回 map),切页/提交时丢编辑
+      if (child3 && child3.saveCurrentTabData) child3.saveCurrentTabData();
+
       let obj = {
         contentTabs: this.contentTabs,
         container_i: this.container_i,
@@ -1648,7 +1692,11 @@ export default {
         this.isTuiDaoZy = true;
       }
 
-      if (storageData.child3.tableData4.length > 1) {
+      // [原逻辑·保留] 适宜技术迁移到 AcupointTable 后 $data 无 tableData4 字段,
+      // 改用 prescriptions 判断是否推导过,并兼容旧缓存(tableData4)+ 判空避免 undefined.length 崩溃
+      // if (storageData.child3.tableData4.length > 1) {
+      const suitPres = storageData.child3.prescriptions;
+      if ((suitPres && suitPres.length > 0) || (storageData.child3.tableData4 && storageData.child3.tableData4.length > 1)) {
         this.isTuiDaoSuit = true;
       }
 
@@ -3027,7 +3075,9 @@ export default {
       if (item.id === '0') {
         try { this.tjRecipeId = child.recipe_tabs[child.recipe_tabs_c].id; } catch (e) { this.tjRecipeId = "" }
       } else if (item.id === '2') {
-        try { this.tjRecipeId = child.recipeId; } catch (e) { this.tjRecipeId = "" }
+        // [原逻辑·保留] AcupointTable 无 recipeId 字段,child.recipeId 为 undefined,
+        // 覆盖会清空 inferRecipe 已设的适宜技术默认高亮(pres[0]),故不再覆盖
+        // try { this.tjRecipeId = child.recipeId; } catch (e) { this.tjRecipeId = "" }
       }
     },
     checked(item1) {
@@ -3813,6 +3863,15 @@ export default {
         }
         this.rRecomendR = arr2;
 
+        // 适宜技术:SuitTechSidePanel 面板只显示 pres(showType==0),默认高亮其第一项
+        // (通用 arr2[0] 可能是专家经验 expList、面板不显示,故适宜技术覆盖为 pres[0])
+        if (this.container_i == 2) {
+          const presList = (res.data.schemes && res.data.schemes[0] && res.data.schemes[0].pres) || [];
+          if (presList.length > 0) {
+            this.tjRecipeId = presList[0].preid || presList[0].pid || presList[0].acupreid;
+          }
+        }
+
         if (this.$route.query.type != "tuidao" && type == 1) return;
         if (type === 3) {
           try { if (this.contentTabs[this.container_i].id === '0' && this.isTuiDaoZy) return; } catch (e) {}
@@ -3867,30 +3926,33 @@ export default {
               this.isTuiDaoZy = true;
             }
           } else if (this.container_i == 2) {
-            if (arr2.length > 0) {
-              const loading3 = this.$loading({
-                lock: true,
-                text: '正在获取适宜技术处方数据',
-                spinner: 'el-icon-loading',
-                background: 'rgba(0, 0, 0, 0.7)',
-              });
-              try {
-                const recipeRes = await getRecipeByBasis({
-                  sourcePid: arr2[0].pid,
-                  recordId: this.getPatiensInfo.pid || undefined,
-                  sourceType: 'localExpert',
+            // 仅推导(type=1/2)时拉取推荐方案并填入;切 tab(type=3)不拉接口、不埋点,
+            // 保留用户上次编辑/缓存(AcupointTable 是 v-show 常驻,prescriptions 切 tab 本就不丢)
+            if (type !== 3) {
+              if (arr2.length > 0) {
+                const loading3 = this.$loading({
+                  lock: true,
+                  text: '正在获取适宜技术处方数据',
+                  spinner: 'el-icon-loading',
+                  background: 'rgba(0, 0, 0, 0.7)',
                 });
-                if (recipeRes.ResultCode === 0 && recipeRes.Data) {
-                  this.assignRecipe3(recipeRes.Data, loading3);
-                } else {
+                try {
+                  const recipeRes = await getRecipeByBasis({
+                    sourcePid: arr2[0].pid,
+                    recordId: this.getPatiensInfo.pid || undefined,
+                    sourceType: 'localExpert',
+                  });
+                  if (recipeRes.ResultCode === 0 && recipeRes.Data) {
+                    this.assignRecipe3(recipeRes.Data, loading3);
+                  } else {
+                    loading3.close();
+                  }
+                } catch (e) {
                   loading3.close();
                 }
-              } catch (e) {
-                loading3.close();
               }
+              this.addRecipeFrom("4", 2);
             }
-
-            this.addRecipeFrom("4", 2);
             if (type == 3) {
               this.isTuiDaoSuit = true;
             }

+ 474 - 0
src/views/diagnosis/components/prescription-suit.vue

@@ -0,0 +1,474 @@
+<template>
+  <!-- 查询协定方(适宜技术-协定方按钮) -->
+  <div class="prescription">
+    <!-- 搜索条件 -->
+    <div class="top-filter">
+      <el-form label-position="right" label-width="80px" :model="form" inline>
+        <el-form-item label="方名">
+          <el-input v-model="form.name" size="mini" placeholder="请输入"></el-input>
+        </el-form-item>
+        <!-- 中医病名:el-input + el-popover 自定义列表(参考 SuitableTech.vue) -->
+        <el-form-item label="中医病名">
+          <el-popover placement="bottom" width="180" trigger="focus" :close-delay="100">
+            <el-input
+              size="mini"
+              slot="reference"
+              :placeholder="form.disName || '中医病名'"
+              v-model="diseaseKey"
+              ref="zybmInput"
+              @input="getDiseaseList(diseaseKey)"
+              @focus="handleFocusDisease"
+              @keydown.enter.native="handleEnterDisease"
+            >
+              <div slot="suffix" class="suffix">
+                <i class="el-icon-arrow-down" v-if="!diseaseKey"></i>
+                <i class="el-icon-circle-close" v-else @click="clearDisease"></i>
+              </div>
+            </el-input>
+            <ul class="option-list">
+              <li
+                v-for="item in diseaseList"
+                :key="item.$uid"
+                :class="{ active: form.disName === item.$name }"
+                @click="handleSelectDisease(item)"
+              >{{ item.$name }}</li>
+            </ul>
+          </el-popover>
+        </el-form-item>
+        <!-- 西医诊断:el-tag + el-autocomplete(参考 SuitableTech.vue) -->
+        <el-form-item label="西医诊断">
+          <div class="western-disease-input-wrapper" @click="$refs.wdAutocomplete && $refs.wdAutocomplete.focus()">
+            <el-tag
+              v-for="code in westernCodes"
+              :key="code"
+              size="mini"
+              closable
+              @close="removeWesternDisease(code)"
+            >{{ westernDiseaseNameMap[code] || code }}</el-tag>
+            <el-autocomplete
+              ref="wdAutocomplete"
+              size="mini"
+              popper-class="western-disease-select"
+              v-model="westernDiseaseSearch"
+              :fetch-suggestions="queryWesternDisease"
+              value-key="westname"
+              :placeholder="westernCodes.length ? '' : '请搜索选择'"
+              clearable
+              :trigger-on-focus="true"
+              @select="onWesternDiseaseSelect"
+              @visible-change="onWesternDiseaseVisible"
+            >
+              <template slot-scope="{ item }">
+                <div :class="{ 'autocomplete-disabled': item._disabled }">
+                  {{ item.westname }}
+                </div>
+              </template>
+            </el-autocomplete>
+          </div>
+        </el-form-item>
+      </el-form>
+      <el-button size="mini" type="primary" @click="searchDis">搜索</el-button>
+      <el-button size="mini" type="warning" @click="clearDis">重置</el-button>
+    </div>
+    <!-- 表格数据展示 -->
+    <div class="table">
+      <el-table :data="tableData1" border style="width: 100%">
+        <el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
+        <el-table-column prop="name" label="方名" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="effect" label="功效与适应症" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="drugInformation" label="涵盖项目" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="provenance" label="处方出处" align="center" width="150" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="address" label="操作" width="80" align="center">
+          <template slot-scope="scope">
+            <el-button size="mini" type="primary" @click="handleAgree(scope)">转方</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <!-- 分页数据 -->
+    <div class="paging">
+      <el-pagination
+        @current-change="handleCurrentChange"
+        :current-page="currentPage"
+        :page-size="10"
+        :total="total"
+        background
+        layout=" prev, pager, next, jumper"
+      ></el-pagination>
+    </div>
+  </div>
+</template>
+<script>
+import { getAccordDetail } from "@/api/diagnosis.js";
+import { getSuitableTechList } from "@/api/technology.js";
+import { getDiseaseListMethod } from "@/request/api";
+import { getXDiseaseName } from "@/api/knowledge.js";
+
+export default {
+  data() {
+    return {
+      // 中医病名
+      diseaseList: [],
+      diseaseKey: "", // 输入框搜索关键字
+      // 西医诊断
+      westernDiseaseSearch: "", // autocomplete 搜索关键字
+      westernDiseaseOptions: [], // autocomplete 选项列表
+      westernDiseaseNameMap: {}, // { westcode: westname }
+      westernCodes: [], // 已选中的 westcode 数组
+      westernDiseasePage: 1, // 分页页码
+      westernDiseaseHasMore: true, // 是否还有更多
+      westernDiseaseLoading: false, // 加载中
+      // 表单
+      form: {
+        name: "", // 方名
+        disName: "", // 中医病名
+        westernCode: "", // 西医诊断码(逗号分隔)
+      },
+      tableData1: [],
+      currentPage: 1,
+      total: 0
+    };
+  },
+  created() {
+    this.clearDis();
+  },
+  methods: {
+    resetForm() {
+      this.form = {
+        name: "", // 方名
+        disName: "", // 中医病名
+        westernCode: "", // 西医诊断码
+      };
+      this.diseaseKey = "";
+      this.diseaseList = [];
+      this.westernDiseaseSearch = "";
+      this.westernDiseaseOptions = [];
+      this.westernDiseaseNameMap = {};
+      this.westernCodes = [];
+    },
+    clearDis() {
+      this.currentPage = 1;
+      this.resetForm();
+      this.getAgreeRecipe();
+    },
+    handleCurrentChange(e) {
+      this.currentPage = e;
+      this.getAgreeRecipe();
+    },
+    searchDis() {
+      this.currentPage = 1;
+      this.getAgreeRecipe();
+    },
+
+    // ==================== 中医病名(参考 SuitableTech.vue) ====================
+    async getDiseaseList(keyword = '') {
+      const { list } = await getDiseaseListMethod(1, 9999, { keyword }).catch(() => ({ total: 0, list: [] }));
+      this.diseaseList = list;
+    },
+    // focus 时若列表为空则加载全部(参考 SuitableTech.vue handleFocus('bm'))
+    handleFocusDisease() {
+      if (this.diseaseList.length === 0) this.getDiseaseList(this.diseaseKey);
+    },
+    handleSelectDisease(item) {
+      this.form.disName = item.$name;
+      this.diseaseKey = item.$name;
+      this.$refs.zybmInput && this.$refs.zybmInput.blur();
+    },
+    clearDisease() {
+      this.form.disName = "";
+      this.diseaseKey = "";
+      this.diseaseList = [];
+    },
+    handleEnterDisease() {
+      if (this.diseaseList.length) {
+        this.handleSelectDisease(this.diseaseList[0]);
+      }
+    },
+
+    // ==================== 西医诊断(参考 SuitableTech.vue) ====================
+    async queryWesternDisease(queryString, cb) {
+      await this.searchWesternDisease(queryString);
+      if (this.westernDiseaseOptions.length > 0) {
+        cb(this.westernDiseaseOptions);
+      } else {
+        cb([{ westname: "暂无数据", _disabled: true }]);
+      }
+    },
+    async searchWesternDisease(query) {
+      this.westernDiseasePage = 1;
+      this.westernDiseaseHasMore = true;
+      this._wdQuery = query || "";
+      this.westernDiseaseLoading = true;
+      try {
+        const pinyin = /^[A-Za-z]+$/g;
+        const serchtype = query && pinyin.test(query) ? "1" : "";
+        const res = await getXDiseaseName({
+          pageid: 1,
+          pagesize: 200,
+          keyword: query || "",
+          serchtype,
+        });
+        if (res.code == 0) {
+          const list = res.data?.wests || [];
+          // 保留已选中但不在搜索结果中的选项
+          const resultCodes = new Set(list.map(i => i.westcode));
+          const preserved = this.westernCodes
+            .filter(code => !resultCodes.has(code))
+            .map(code => ({
+              westcode: code,
+              westname: this.westernDiseaseNameMap[code] || code,
+            }));
+          this.westernDiseaseOptions = [...preserved, ...list];
+          this.westernDiseaseHasMore = list.length >= 200;
+          list.forEach(item => {
+            if (item.westcode && item.westname) {
+              this.westernDiseaseNameMap[item.westcode] = item.westname;
+            }
+          });
+        }
+      } catch (e) {
+        console.error("搜索西医诊断失败", e);
+      } finally {
+        this.westernDiseaseLoading = false;
+      }
+    },
+    // 滚动到底加载更多(参考 SuitableTech.vue loadMoreWesternDisease)
+    async loadMoreWesternDisease() {
+      if (this.westernDiseaseLoading || !this.westernDiseaseHasMore) return;
+      this.westernDiseasePage++;
+      this.westernDiseaseLoading = true;
+      try {
+        const query = this._wdQuery || "";
+        const pinyin = /^[A-Za-z]+$/g;
+        const serchtype = query && pinyin.test(query) ? "1" : "";
+        const res = await getXDiseaseName({
+          pageid: this.westernDiseasePage,
+          pagesize: 200,
+          keyword: query,
+          serchtype,
+        });
+        if (res.code == 0) {
+          const list = res.data?.wests || [];
+          this.westernDiseaseOptions = this.westernDiseaseOptions.concat(list);
+          this.westernDiseaseHasMore = list.length >= 200;
+          list.forEach(item => {
+            if (item.westcode && item.westname) {
+              this.westernDiseaseNameMap[item.westcode] = item.westname;
+            }
+          });
+        }
+      } catch (e) {
+        console.error("加载更多西医诊断失败", e);
+      } finally {
+        this.westernDiseaseLoading = false;
+      }
+    },
+    // 下拉显隐:首次打开加载 + 绑定滚动加载更多(参考 SuitableTech.vue onWesternDiseaseVisible)
+    onWesternDiseaseVisible(show) {
+      if (!show) {
+        const wrap = document.querySelector(".western-disease-select .el-scrollbar__wrap");
+        if (wrap && this._wdScroll) wrap.removeEventListener("scroll", this._wdScroll);
+        return;
+      }
+      if (this.westernDiseaseOptions.length === 0) this.searchWesternDisease("");
+      this.$nextTick(() => {
+        const wrap = document.querySelector(".western-disease-select .el-scrollbar__wrap");
+        if (wrap) {
+          wrap.addEventListener("scroll", (this._wdScroll = () => {
+            if (wrap.scrollHeight - wrap.scrollTop <= wrap.clientHeight + 5) {
+              this.loadMoreWesternDisease();
+            }
+          }));
+        }
+      });
+    },
+    onWesternDiseaseSelect(item) {
+      if (item._disabled) {
+        this.$nextTick(() => { this.westernDiseaseSearch = ""; });
+        return;
+      }
+      const code = String(item.westcode);
+      if (!this.westernCodes.includes(code)) {
+        this.westernCodes.push(code);
+        this.westernDiseaseNameMap[code] = item.westname;
+        this.updateWesternCode();
+      }
+      this.westernDiseaseSearch = "";
+      this.$nextTick(() => { this.searchWesternDisease(""); });
+    },
+    removeWesternDisease(code) {
+      this.westernCodes = this.westernCodes.filter(c => c !== code);
+      this.updateWesternCode();
+    },
+    updateWesternCode() {
+      this.form.westernCode = this.westernCodes.join(",");
+    },
+
+    // ==================== 列表与转方 ====================
+    // 协定方转方
+    handleAgree(scope) {
+      this.getAccordDetail(scope.row.preId);
+    },
+    //获取协定方列表(使用适宜技术列表接口,status=0, purposeType=1)
+    async getAgreeRecipe() {
+      let params = {
+        status: 0,
+        purposeType: 1,
+        name: this.form.name || undefined,
+        disName: this.form.disName || undefined,
+        westernCode: this.form.westernCode || undefined,
+        pageNum: this.currentPage,
+        pageSize: 10
+      };
+      let res = await getSuitableTechList(params);
+      if (res.ResultCode == 0) {
+        this.total = res.Data?.totalRecordCount || 0;
+        this.tableData1 = res.Data?.Items || [];
+      }
+    },
+    //   获取协定方详情(转方)
+    async getAccordDetail(id) {
+      let res = await getAccordDetail({
+        pid: id
+      });
+      if (res.ResultCode == 0) {
+        const recipe = { ...res.Data, medicine: res.Data.preStiDetails, __RecipeFrom__: '2' }
+        this.$parent.$parent.$parent.transposition(recipe);
+        if (res.Data.diseaseid) {
+          this.$parent.$parent.$parent.$refs.TCM.setParams({
+            namemedicine: res.Data.diseasename,
+            disid: res.Data.diseaseid,
+            symptomid: res.Data.symptomid,
+            syndrometypes: res.Data.symptomname,
+            treatment: res.Data.treatment
+          });
+
+          setTimeout(() => {
+            this.$parent.$parent.$parent.tcmClick(false);
+          }, 200);
+        }
+      }
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.top-filter {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  margin-bottom: 10px;
+}
+
+.top-filter {
+  ::v-deep {
+    .el-input__inner {
+      width: 150px;
+    }
+
+    .el-form--inline .el-form-item {
+      margin-bottom: 0;
+    }
+  }
+}
+
+// 西医诊断多选 wrapper(外观对齐中医病名 el-input:同宽 150px / 同高 28px / 同边框)
+.western-disease-input-wrapper {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  width: 150px;
+  min-height: 28px;
+  box-sizing: border-box;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 0 8px;
+  cursor: text;
+
+  .el-tag {
+    margin: 2px 4px 2px 0;
+    max-width: 120px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .el-autocomplete {
+    flex: 1;
+    min-width: 60px;
+
+    ::v-deep .el-input__inner {
+      border: none !important;
+      padding: 0;
+      height: 28px;
+      line-height: 28px;
+      width: 100%;
+      background: transparent;
+    }
+  }
+
+  &:hover {
+    border-color: #c0c4cc;
+  }
+
+  &:focus-within {
+    border-color: #409eff;
+  }
+}
+
+// autocomplete 暂无数据项置灰(参考 SuitableTech.vue)
+.autocomplete-disabled {
+  color: #999 !important;
+  cursor: not-allowed !important;
+  pointer-events: none;
+}
+
+// input suffix 图标(参考 SuitableTech.vue)
+.suffix {
+  height: 100%;
+  padding-right: 5px;
+  display: flex;
+  align-items: center;
+
+  i {
+    cursor: pointer;
+    color: #c0c4cc;
+  }
+
+  i:hover {
+    color: #909399;
+  }
+}
+
+// 下拉选项列表(中医病名 popover 内,参考 SuitableTech.vue)
+.option-list {
+  margin: -12px -12px;
+  max-height: 300px;
+  overflow: auto;
+  padding: 0;
+  list-style: none;
+
+  li {
+    padding: 8px 12px;
+    box-sizing: border-box;
+    width: 100%;
+    font-size: 14px;
+    color: #606266;
+    font-weight: 500;
+    cursor: pointer;
+
+    &:hover {
+      background: #f5f7fa;
+    }
+  }
+
+  .active {
+    color: #5386f6;
+  }
+}
+
+.paging {
+  margin-top: 10px;
+  display: flex;
+  justify-content: center;
+}
+</style>

+ 193 - 0
src/views/diagnosis/components/prescription-unify-suit.vue

@@ -0,0 +1,193 @@
+<template>
+  <!-- 查询医派协定方(适宜技术-医派协定方按钮) -->
+  <div class="prescription">
+    <!-- 搜索条件 -->
+    <div class="top-filter">
+      <el-form label-position="right" label-width="70px" :model="form" inline>
+        <el-form-item label="方名">
+          <el-input v-model="form.name" size="small" placeholder="请输入"></el-input>
+        </el-form-item>
+        <el-form-item label="医派">
+          <el-select v-model="form.sectCategory" @change="getHospitalDepartment(form.sectCategory)"
+                     placeholder="请选择" size="small" clearable>
+            <el-option v-for="item in hospitalCategory" :key="item.id" :label="item.name" :value="item.id"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="科室">
+          <el-select v-model="form.sectDept"
+                     placeholder="请选择" size="small" clearable>
+            <el-option v-for="item in hospitalDepartment" :key="item.id" :label="item.name" :value="item.id"></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <el-button size="small" type="primary" @click="searchDis">搜索</el-button>
+      <el-button size="small" type="warning" @click="clearDis">重置</el-button>
+    </div>
+    <!-- 表格数据展示 -->
+    <div class="table">
+      <!-- 统建处方(医派协定方)表格 -->
+      <el-table :data="tableData1" border style="width: 100%">
+        <el-table-column prop="sectCategory" label="医派" align="center" width="120" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="sectDept" label="科室" align="center" width="120" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="name" label="方名" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="effect" label="功效与适用症" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="drugInformation" label="涵盖项目" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="provenance" label="处方出处" align="center" width="150" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="address" label="操作" width="80" align="center">
+          <template slot-scope="scope">
+            <el-button size="mini" type="primary" @click="handleAgree(scope)">转方</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <!-- 分页数据 -->
+    <div class="paging">
+      <el-pagination
+        @current-change="handleCurrentChange"
+        :current-page="currentPage"
+        :page-size="10"
+        :total="total"
+        background
+        layout=" prev, pager, next, jumper"
+      ></el-pagination>
+    </div>
+  </div>
+</template>
+<script>
+import { getEffectQuery } from "@/api/knowledge.js";
+import { getAccordDetail } from "@/api/diagnosis.js";
+import { getSuitableTechList } from "@/api/technology.js";
+import { getHospitalCategory, getHospitalDepartment } from "@/api/city";
+
+export default {
+  data() {
+    return {
+      hospitalCategory: [],
+      hospitalDepartment: [],
+
+      form: {
+        name: "", // 方名
+        sectCategory: '', // 医派
+        sectDept: '', // 科室
+      },
+      tableData1: [],
+      currentPage: 1,
+      total: 0
+    };
+  },
+  created() {
+    this.getEffectQuery();
+    this.clearDis();
+  },
+  methods: {
+    async getHospitalCategory() {
+      this.hospitalCategory = await getHospitalCategory();
+    },
+    async getHospitalDepartment() {
+      this.hospitalDepartment = await getHospitalDepartment({hospital: this.form.sectCategory || ''});
+      if (!this.hospitalDepartment.find(item => item.id === this.form.sectDept)) this.form.sectDept = '';
+    },
+    resetForm() {
+      this.form = {
+        sectCategory: '', // 医派
+        sectDept: '', // 科室
+        name: "" // 方名
+      };
+    },
+    clearDis() {
+      this.currentPage = 1;
+      this.resetForm();
+      this.getHospitalCategory().then(() => this.getHospitalDepartment());
+      this.getAgreeRecipe();
+    },
+    handleCurrentChange(e) {
+      this.currentPage = e;
+      this.getAgreeRecipe();
+    },
+    searchDis() {
+      this.currentPage = 1;
+      this.getAgreeRecipe();
+    },
+    // 协定方转方
+    handleAgree(scope) {
+      this.getAccordDetail(scope.row.preId);
+    },
+    // 获取方剂分类
+    async getEffectQuery() {
+      let res = await getEffectQuery({
+        effecttype: "1",
+        effictId: ""
+      });
+      if (res.code == 0) {
+        // 预留:方剂分类
+      }
+    },
+    //获取医派协定方列表(使用适宜技术列表接口,status=0, purposeType=0)
+    async getAgreeRecipe() {
+      let params = {
+        status: 0,
+        purposeType: 0,
+        sectCategory: this.form.sectCategory || undefined,
+        sectDept: this.form.sectDept || undefined,
+        name: this.form.name || undefined,
+        pageNum: this.currentPage,
+        pageSize: 10
+      };
+      let res = await getSuitableTechList(params);
+      if (res.ResultCode == 0) {
+        this.total = res.Data?.totalRecordCount || 0;
+        this.tableData1 = res.Data?.Items || [];
+      }
+    },
+    //   获取协定方详情(转方)
+    async getAccordDetail(id) {
+      let res = await getAccordDetail({
+        pid: id
+      });
+      if (res.ResultCode == 0) {
+        const recipe = { ...res.Data, medicine: res.Data.preStiDetails, __RecipeFrom__: '2' }
+        this.$parent.$parent.$parent.transposition(recipe);
+        if (res.Data.diseaseid) {
+          this.$parent.$parent.$parent.$refs.TCM.setParams({
+            namemedicine: res.Data.diseasename,
+            disid: res.Data.diseaseid,
+            symptomid: res.Data.symptomid,
+            syndrometypes: res.Data.symptomname,
+            treatment: res.Data.treatment
+          });
+
+          setTimeout(() => {
+            this.$parent.$parent.$parent.tcmClick(false);
+          }, 200);
+        }
+      }
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.top-filter {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  margin-bottom: 10px;
+}
+
+.top-filter {
+  ::v-deep {
+    .el-input__inner {
+      width: 150px;
+    }
+
+    .el-form--inline .el-form-item {
+      margin-bottom: 0;
+    }
+  }
+}
+
+.paging {
+  margin-top: 10px;
+  display: flex;
+  justify-content: center;
+}
+</style>

+ 1 - 0
src/views/diagnosis/components/submitRecipe.vue

@@ -601,6 +601,7 @@ export default {
         spinner: "el-icon-loading",
         background: "rgba(0, 0, 0, 0.7)"
       });
+      console.log('addRecipe params:提交处方', this.getPatiensInfo.pid, technology, zhongchengyao, zhongyao);
       let params = {
         recordid: this.getPatiensInfo.pid,
         // technology: technology,

+ 1 - 1
src/views/patients/TodayPatients.vue

@@ -292,7 +292,7 @@ export default {
       // if (scope.row.sex == '男') {
       this.setPatients(scope.row);
       this.seeDoctor(this.scope);
-
+console.log(this.$route.query, "this.$route.query",scope);
       if (this.$route.query && this.$route.query.isBack == "true") {
         this.$router.back();
       } else {