Jelajahi Sumber

适宜技术智能开方

张田田 1 Minggu lalu
induk
melakukan
7b409673fe

+ 9 - 0
src/api/diagnosis.js

@@ -480,6 +480,15 @@ export function getRecipePriview(data) {
     })
 }
 
+// 专家/协定方转为开方查询接口
+export function getRecipeByBasis(data) {    
+    return request({
+        url: `/test/outpatient/changeStAccordPre`,
+        method: 'post',
+        data
+    })
+}
+
 // 获取中药制剂 包装单位 
 export function getBzdw(params) {
     return request({

+ 112 - 44
src/components/ui/suitMadePadTech.vue

@@ -37,58 +37,83 @@
             <div class="Rp-title">Rp:</div>
             <div class="Rp-detail">
                 <!-- 项目名称 -->
-                <div class="Rp-option flex flex-col-top flex-row-left" v-if="recipeData.itemName">
+                <div class="Rp-option flex flex-col-top flex-row-left" v-if="recipeData.technologyType">
                     <div class="option-name">项目名称:</div>
-                    <div class="option-right flex flex-wrap">{{recipeData.itemName}}</div>
+                    <div class="option-right flex flex-wrap">{{recipeData.technologyType}}</div>
                 </div>
-                <!-- 穴位(带数量) -->
-                <div class="Rp-option flex flex-col-top flex-row-left" v-if="recipeData.prescriptiontechnologydetailVos && recipeData.prescriptiontechnologydetailVos.length">
+                <div class="Rp-option flex flex-col-top flex-row-left" v-if="hasDetailData('detailPoint')">
                     <div class="option-name">穴位:</div>
                     <div class="option-right flex flex-wrap">
-                        <div class="Rp-item" v-for="(item,index) in recipeData.prescriptiontechnologydetailVos"
-                            :key="index">{{item.pointname}}<span v-if="item.num">{{item.num}}</span></div>
+                        <template v-for="(treatItem, treatIndex) in recipeData.treatmentList">
+                            <div v-for="(point, pointIndex) in treatItem.detailPoint" :key="'point-'+treatIndex+'-'+pointIndex" class="Rp-item">
+                                {{point.name}}<span v-if="point.num">{{point.num}}</span>
+                            </div>
+                        </template>
                     </div>
                 </div>
-                <!-- 经络 -->
-                <div class="Rp-option flex flex-col-top flex-row-left" v-if="recipeData.meridian">
+                <!-- 经络 - 从 treatmentList 中获取 -->
+                <div class="Rp-option flex flex-col-top flex-row-left" v-if="hasDetailData('detailMeridian')">
                     <div class="option-name">经络:</div>
-                    <div class="option-right flex flex-wrap">{{recipeData.meridian}}</div>
-                </div>
-                <!-- 数量 / 治疗次数 / 频次(同一行,数量作为行标签,与上面各行对齐) -->
-                <div class="Rp-option flex flex-col-top flex-row-left" v-if="recipeData.singleQty || recipeData.treatNum || recipeData.frequency">
-                    <div class="option-name">数量:</div>
                     <div class="option-right flex flex-wrap">
-                        <span class="Rp-item" v-if="recipeData.singleQty">{{recipeData.singleQty}}{{recipeData.pricingUnit}}</span>
-                        <span class="Rp-item" v-if="recipeData.treatNum">治疗次数:{{recipeData.treatNum}}次</span>
-                        <span class="Rp-item" v-if="recipeData.frequency">频次:{{recipeData.frequency}}</span>
+                        <template v-for="(treatItem, treatIndex) in recipeData.treatmentList">
+                            <div v-for="(item, itemIndex) in treatItem.detailMeridian" :key="'meridian-'+treatIndex+'-'+itemIndex" class="Rp-item">
+                                {{item.name}}<span v-if="item.num">{{item.num}}</span>
+                            </div>
+                        </template>
                     </div>
                 </div>
-                <!-- 配穴指南 -->
-                <div class="Rp-option flex flex-col-top flex-row-left" v-if="recipeData.pointMatchGuide">
-                    <div class="option-name">配穴指南:</div>
-                    <div class="option-right flex flex-wrap">{{recipeData.pointMatchGuide}}</div>
+                <div class="Rp-option flex flex-col-top flex-row-left" v-if="hasDetailData('detailEarPoint')">
+                    <div class="option-name">耳穴:</div>
+                    <div class="option-right flex flex-wrap">
+                        <template v-for="(treatItem, treatIndex) in recipeData.treatmentList">
+                            <div v-for="(item, itemIndex) in treatItem.detailEarPoint" :key="'earpoint-'+treatIndex+'-'+itemIndex" class="Rp-item">
+                                {{item.name}}<span v-if="item.num">{{item.num}}</span>
+                            </div>
+                        </template>
+                    </div>
                 </div>
-                <!-- 操作指南 -->
-                <div class="Rp-option flex flex-col-top flex-row-left" v-if="recipeData.useExplain">
-                    <div class="option-name">操作指南:</div>
-                    <div class="option-right flex flex-wrap">{{recipeData.useExplain}}</div>
+                <div class="Rp-option flex flex-col-top flex-row-left" v-if="hasDetailData('detailBodyPart')">
+                    <div class="option-name">部位:</div>
+                    <div class="option-right flex flex-wrap">
+                        <template v-for="(treatItem, treatIndex) in recipeData.treatmentList">
+                            <div v-for="(item, itemIndex) in treatItem.detailBodyPart" :key="'bodypart-'+treatIndex+'-'+itemIndex" class="Rp-item">
+                                {{item.name}}<span v-if="item.num">{{item.num}}</span>
+                            </div>
+                        </template>
+                    </div>
                 </div>
-
-                <!-- 旧字段保留注释(原件 suitMadePad.vue 未动)
-                <div class="Rp-option flex flex-col-top flex-row-left">
-                    <div class="option-name">类型:</div>
-                    <div class="option-right flex flex-wrap">{{recipeData.technologyType}}</div>
+                <div class="Rp-option flex flex-col-top flex-row-left" v-if="hasDetailData('detailOther')">
+                    <div class="option-name">其他详情:</div>
+                    <div class="option-right flex flex-wrap">
+                        <template v-for="(treatItem, treatIndex) in recipeData.treatmentList">
+                            <div v-for="(item, itemIndex) in treatItem.detailOther" :key="'other-'+treatIndex+'-'+itemIndex" class="Rp-item">
+                                {{item.name}}<span v-if="item.num">{{item.num}}</span>
+                            </div>
+                        </template>
+                    </div>
                 </div>
-                <div class="Rp-option flex flex-col-top flex-row-left">
-                    <div class="option-name">次数:</div>
-                    <div class="option-right flex flex-wrap">{{recipeData.num}}</div>
+                <div class="Rp-option flex flex-col-top flex-row-left" v-if="hasTreatmentInfo()">
+                    <div class="option-right treatment-info-row">
+                        <template v-for="(treatItem, treatIndex) in recipeData.treatmentList">
+                            <div class="treatment-info-item" :key="'qty-'+treatIndex" v-if="treatItem.singleQty">
+                                <span class="treatment-label">数量:</span>
+                                <span class="treatment-value">{{treatItem.singleQty}}{{treatItem.basisStitutionsnondrug && treatItem.basisStitutionsnondrug.pricingUnit || ''}}</span>
+                            </div>
+                            <div class="treatment-info-item" :key="'treat-'+treatIndex" v-if="treatItem.treatNum">
+                                <span class="treatment-label">治疗次数:</span>
+                                <span class="treatment-value">{{treatItem.treatNum}}次</span>
+                            </div>
+                            <div class="treatment-info-item" :key="'freq-'+treatIndex" v-if="treatItem.frequency">
+                                <span class="treatment-label">频次:</span>
+                                <span class="treatment-value">{{treatItem.frequency}}</span>
+                            </div>
+                        </template>
+                    </div>
                 </div>
-                -->
-            </div>
-            <div class="Rp-other">
-
-                <div style="text-align:right;" v-if="recipeData.entrust">
-                    {{recipeData.entrust}}
+                <!-- 嘱托 -->
+                <div class="Rp-option flex flex-col-top flex-row-left" v-if="recipeData.entrust">
+                    <div class="option-name">嘱托:</div>
+                    <div class="option-right flex flex-wrap">{{recipeData.entrust}}</div>
                 </div>
             </div>
         </div>
@@ -131,6 +156,27 @@
                     return {}
                 }
             }
+        },
+        methods: {
+            // 检查 treatmentList 中是否有指定类型的详情数据
+            hasDetailData(detailType) {
+                if (!this.recipeData.treatmentList || !this.recipeData.treatmentList.length) {
+                    return false;
+                }
+                return this.recipeData.treatmentList.some(item => {
+                    const detail = item[detailType];
+                    return detail && Array.isArray(detail) && detail.length > 0;
+                });
+            },
+            // 检查 treatmentList 中是否有数量、治疗次数、频次信息
+            hasTreatmentInfo() {
+                if (!this.recipeData.treatmentList || !this.recipeData.treatmentList.length) {
+                    return false;
+                }
+                return this.recipeData.treatmentList.some(item => {
+                    return item.singleQty || item.treatNum || item.frequency;
+                });
+            }
         }
     }
 </script>
@@ -141,14 +187,14 @@
         max-width: 420px;
         margin: 0 auto;
         width: 100%;
-        // height: 609px;
-        height: 560px; // 1280 下
-        overflow: auto;
+        height: 609px;
+        // height: 560px; // 1280 下
+        overflow-y: auto;
+        overflow-x: hidden;
         padding: 5px;
         box-sizing: border-box;
         background: #fff;
         // border: 1px solid red;
-        overflow: hidden;
 
         header {
 
@@ -240,14 +286,15 @@
 
                 .option-name {
                     display: block;
-                    width: 72px;
+                    // width: 72px;
                     flex-shrink: 0;
                     white-space: nowrap;
-                    text-align: right;
+                    text-align: left;
                 }
 
                 .option-right {
                     flex: 1;
+                    text-align: left;
                 }
             }
 
@@ -261,6 +308,27 @@
 
             }
 
+            // 数量、治疗次数、频次同一行均匀排列
+            .treatment-info-row {
+                display: flex;
+                justify-content: space-between;
+                width: 100%;
+
+                .treatment-info-item {
+                    flex: 1;
+                    display: flex;
+                    align-items: center;
+
+                    .treatment-label {
+                        white-space: nowrap;
+                    }
+
+                    .treatment-value {
+                        flex: 1;
+                    }
+                }
+            }
+
             &-other {
                 font-size: 13px;
                 padding: 0 10px 0 44px;

+ 16 - 3
src/store/modules/drug.js

@@ -1,14 +1,27 @@
 export default {
   namespaced: true,
   state: {
-    drugsInfo: sessionStorage.getItem('drugsInfo') ? JSON.parse(sessionStorage.getItem('drugsInfo')) : {}, // 病人信息
+    drugsInfo: (() => {
+      try {
+        const raw = sessionStorage.getItem('drugsInfo');
+        if (!raw || raw === 'undefined') return {};
+        return JSON.parse(raw) || {};
+      } catch (e) {
+        return {};
+      }
+    })(), // 病人信息
+    //  drugsInfo: sessionStorage.getItem('drugsInfo') ? JSON.parse(sessionStorage.getItem('drugsInfo')) : {}, // 病人信息
     recipeId: sessionStorage.getItem('recipeId'),
   },
   mutations: {
     setDrugsInfo(state, data) {
+      const safe = data == null ? {} : data;
+      sessionStorage.setItem('drugsInfo', JSON.stringify(safe))
+      state.drugsInfo = safe
 
-      sessionStorage.setItem('drugsInfo', JSON.stringify(data))
-      state.drugsInfo = data
+
+      //  sessionStorage.setItem('drugsInfo', JSON.stringify(data))
+      // state.drugsInfo = data
     },
     setRecipeId(state, id) {
       sessionStorage.setItem('recipeId', id)

+ 1 - 1
src/views/business/Recipe.vue

@@ -312,7 +312,7 @@
 import Propup from "@/components/Propup.vue";
 import chinesepad from "@/components/ui/chineseMedicinePad.vue";
 import chineseMadepad from "@/components/ui/chineseMadePad.vue";
-import suitPad from "@/components/ui/suitMadePad.vue";
+import suitPad from "@/components/ui/suitMadePadTech.vue";
 import {
   getRecipeList,
   changeRecipeS,

+ 160 - 116
src/views/business/components/AcupointTable.vue

@@ -1,19 +1,22 @@
 <template>
   <div class="recipe-acupoint-wrapper">
     <!-- 处方 tab + 按钮同一行 -->
-    <div class="prescription-header">
-      <div class="prescription-tabs" v-if="prescriptions.length">
+    <div class="prescription-header flex-vertical-between">
+      <div class="table-label flex-vertical-center-l">
         <div
-          class="tab-item"
-          :class="{ active: activeIndex === index }"
+          class="label-item flex-center"
           v-for="(item, index) in prescriptions"
           :key="index"
-          @click="switchTab(index)"
         >
           <el-tooltip :content="item.itemName" placement="top" :open-delay="300">
-            <span class="tab-name">{{ item.itemName }}</span>
+            <span
+              :class="{ l_active: activeIndex === index }"
+              @click="switchTab(index)"
+            >{{ item.itemName }}</span>
           </el-tooltip>
-          <span class="tab-close" @click.stop="removePrescription(index)">×</span>
+          <div
+            @click.stop="removePrescription(index)"
+          >X</div>
         </div>
       </div>
       <div class="top-btns">
@@ -113,6 +116,7 @@
           <el-checkbox-group
             v-model="innerDetailTypes"
             size="mini"
+            :disabled="isLocked"
             @change="onDetailTypesChange"
           >
             <el-checkbox label="穴位">穴位</el-checkbox>
@@ -160,6 +164,7 @@
                       filterable
                       :filter-method="getFilterMethod(detailType)"
                       placeholder="请选择"
+                      :disabled="isLocked"
                       @change="onItemChange($event, scope, detailType)"
                       @focus="searchByType('', detailType)"
                     >
@@ -175,6 +180,7 @@
                       size="mini"
                       v-model="scope.row.name"
                       placeholder="请输入"
+                      :disabled="isLocked"
                       @change="onDetailInput(scope, detailType)"
                     ></el-input>
                   </template>
@@ -187,6 +193,7 @@
                       :min="1"
                       :controls="false"
                       style="width: 100%"
+                      :disabled="isLocked"
                     ></el-input-number>
                   </template>
                 </el-table-column>
@@ -196,6 +203,7 @@
                       size="mini"
                       v-model="scope.row.remark"
                       placeholder="请输入"
+                      :disabled="isLocked"
                     ></el-input>
                   </template>
                 </el-table-column>
@@ -222,12 +230,14 @@
                       <img
                         src="~@/assets/add.png"
                         alt
-                        @click="addDetailRow(scope, detailType)"
+                        :class="{ 'operate-disabled': isLocked }"
+                        @click="!isLocked && addDetailRow(scope, detailType)"
                       />
                       <img
                         src="~@/assets/delete1.png"
                         alt
-                        @click="deleteDetailRow(scope, detailType)"
+                        :class="{ 'operate-disabled': isDeleteDisabled(scope.row, detailType) }"
+                        @click="!isDeleteDisabled(scope.row, detailType) && deleteDetailRow(scope, detailType)"
                       />
                       <img
                         v-if="
@@ -267,6 +277,7 @@
                       filterable
                       :filter-method="getFilterMethod(detailType)"
                       placeholder="请选择"
+                      :disabled="isLocked"
                       @change="onItemChange($event, scope, detailType)"
                       @focus="searchByType('', detailType)"
                     >
@@ -282,6 +293,7 @@
                       size="mini"
                       v-model="scope.row.name"
                       placeholder="请输入"
+                      :disabled="isLocked"
                       @change="onDetailInput(scope, detailType)"
                     ></el-input>
                   </template>
@@ -294,6 +306,7 @@
                       :min="1"
                       :controls="false"
                       style="width: 100%"
+                      :disabled="isLocked"
                     ></el-input-number>
                   </template>
                 </el-table-column>
@@ -303,6 +316,7 @@
                       size="mini"
                       v-model="scope.row.remark"
                       placeholder="请输入"
+                      :disabled="isLocked"
                     ></el-input>
                   </template>
                 </el-table-column>
@@ -329,12 +343,14 @@
                       <img
                         src="~@/assets/add.png"
                         alt
-                        @click="addDetailRow(scope, detailType)"
+                        :class="{ 'operate-disabled': isLocked }"
+                        @click="!isLocked && addDetailRow(scope, detailType)"
                       />
                       <img
                         src="~@/assets/delete1.png"
                         alt
-                        @click="deleteDetailRow(scope, detailType)"
+                        :class="{ 'operate-disabled': isDeleteDisabled(scope.row, detailType) }"
+                        @click="!isDeleteDisabled(scope.row, detailType) && deleteDetailRow(scope, detailType)"
                       />
                       <img
                         v-if="
@@ -374,6 +390,7 @@
                   v-model="pointMatchGuide"
                   type="textarea"
                   auto-size="{ minRows: 1, maxRows: 4 }"
+                  :disabled="isLocked"
                   @input="emitStatistics"
                 ></el-input>
               </div>
@@ -390,6 +407,7 @@
                   v-model="operationGuide"
                   type="textarea"
                   auto-size="{ minRows: 1, maxRows: 4 }"
+                  :disabled="isLocked"
                   @input="emitStatistics"
                 ></el-input>
               </div>
@@ -397,6 +415,7 @@
             <div
               class="item flex-vertical-center-l"
               style="align-items: flex-start;"
+              v-if="showEntrust"
             >
               <span><span style="opacity:0">*</span> 嘱托:</span>
               <div style="flex: 1;">
@@ -406,6 +425,7 @@
                   v-model="command"
                   type="textarea"
                   auto-size="{ minRows: 1, maxRows: 2 }"
+                  :disabled="isLocked"
                   @input="emitStatistics"
                 ></el-input>
               </div>
@@ -427,24 +447,26 @@
                 <span class="stat-unit">{{ currentPricingUnit }}</span>
               </div>
               <div class="stat-field flex-vertical-center-l">
-                <span>治疗次数:</span>
+                <span><span v-if="requiredTreatFields" style="color: red">*</span> 治疗次数:</span>
                 <el-input-number
                   size="mini"
                   v-model="treatCount"
                   :min="0"
                   :controls="false"
                   style="width: 60px"
+                  :disabled="isLocked"
                   @change="updatePrice"
                 ></el-input-number>
               </div>
               <div class="stat-field flex-vertical-center-l">
-                <span>频次:</span>
+                <span><span v-if="requiredTreatFields" style="color: red">*</span> 频次:</span>
                 <el-input-number
                   size="mini"
                   v-model="frequency"
                   :min="0"
                   :controls="false"
                   style="width: 60px"
+                  :disabled="isLocked"
                   @change="emitStatistics"
                   placeholder="请输入"
                 ></el-input-number>
@@ -455,6 +477,7 @@
                   :min="0"
                   :controls="false"
                   style="width: 60px"
+                  :disabled="isLocked"
                   @change="emitStatistics"
                   placeholder="请输入"
                 ></el-input-number>
@@ -464,30 +487,30 @@
           </div>
         </div>
       </div>
+    </div>
 
-      <!-- 底部金额 -->
-      <div class="table-b-bottom flex-vertical-between">
-        <div class="t-b-b-left flex-vertical-center-l flex-wrap">
-          <div class="t-b-l-item">
-            单次金额:<span>{{ singlePrice || "0.00" }}元</span>
-          </div>
-          <div class="t-b-l-item">
-            疗程金额:<span>{{ coursePrice || "0.00" }}元</span>
-          </div>
-          <div class="t-b-l-item">
-            协定方总金额:<span>{{ totalPrice || "0.00" }}元</span>
-          </div>
+    <!-- 底部金额 - 固定在最底部 -->
+    <div class="table-b-bottom flex-vertical-between">
+      <div class="t-b-b-left flex-vertical-center-l flex-wrap">
+        <div class="t-b-l-item">
+          单次金额:<span>{{ singlePrice || "0.00" }}元</span>
         </div>
-        <div class="t-b-b-right flex-vertical-center-r">
-          <el-button
-            type="primary"
-            size="mini"
-            :loading="saveLoading"
-            @click="handleSave"
-            >保存</el-button
-          >
+        <div class="t-b-l-item">
+          疗程金额:<span>{{ coursePrice || "0.00" }}元</span>
+        </div>
+        <div class="t-b-l-item" v-if="showAgreementTotal">
+          协定方总金额:<span>{{ totalPrice || "0.00" }}元</span>
         </div>
       </div>
+      <div class="t-b-b-right flex-vertical-center-r">
+        <el-button
+          type="primary"
+          size="mini"
+          :loading="saveLoading"
+          @click="handleSave"
+          >保存</el-button
+        >
+      </div>
     </div>
 
     <!-- 查看详情弹窗 -->
@@ -688,10 +711,26 @@ export default {
       type: Boolean,
       default: false,
     },
+    showEntrust: {
+      type: Boolean,
+      default: false,
+    },
+    showAgreementTotal: {
+      type: Boolean,
+      default: true,
+    },
     unitPrice: {
       type: Number,
       default: 0,
     },
+    ownerType: {
+      type: String,
+      default: "",
+    },
+    requiredTreatFields: {
+      type: Boolean,
+      default: false,
+    },
   },
   data() {
     return {
@@ -1316,6 +1355,15 @@ export default {
       this.searchByType("", detailType);
     },
     isDeleteDisabled(row, detailType) {
+      // 当 isLocked 为 true 时(isUpdate === "0"),限制删除操作
+      if (this.isLocked) {
+        // 穴位:主穴不可删除,配穴可以删除
+        if (detailType === '穴位') {
+          return row.mainType === '1'; // 主穴不可删除
+        }
+        // 耳穴、经络、部位、其他详情:全部不可删除
+        return true;
+      }
       return false;
     },
     deleteDetailRow(scope, detailType) {
@@ -1432,11 +1480,25 @@ export default {
         this.$message.warning("请输入单次数量");
         return false;
       }
+      // 当 requiredTreatFields 为 true 时,验证治疗次数和频次必填
+      if (this.requiredTreatFields) {
+        if (!this.treatCount || this.treatCount <= 0) {
+          this.$message.warning("请输入治疗次数");
+          return false;
+        }
+        if (!this.frequency || this.frequency <= 0) {
+          this.$message.warning("请输入频次");
+          return false;
+        }
+        if (!this.frequencyUnit || this.frequencyUnit <= 0) {
+          this.$message.warning("请输入频次次数");
+          return false;
+        }
+      }
       return true;
     },
     handleSave() {
-      // [临时调试] 调预览弹窗样式:暂时跳过校验,保证点保存一定触发 emit(原逻辑保留为注释)
-      // if (!this.validate()) return;
+      if (!this.validate()) return;
       this.saveLoading = true;
       const treatmentList = this.buildTreatmentList();
       const firstP = this.prescriptions[0] || {};
@@ -1696,13 +1758,57 @@ export default {
 
 <style lang="scss" scoped>
 .recipe-acupoint-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
   // tab + 按钮同一行
   .prescription-header {
     display: flex;
     align-items: center;
     justify-content: space-between;
-    margin-bottom: 6px;
+    border-bottom: 2px solid #dedede;
+    padding: 0px 0;
     flex-shrink: 0;
+
+    .table-label {
+      display: flex;
+      align-items: center;
+
+      .label-item {
+        cursor: pointer;
+        min-width: 104px;
+        max-width: 220px;
+        border-right: 2px solid #eaeaea;
+        display: flex;
+        align-items: center;
+        padding: 0 8px;
+
+        span {
+          font-size: 14px;
+          font-family: PingFang SC;
+          font-weight: 400;
+          color: #666666;
+          margin-left: 8px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+
+        div {
+          color: #666;
+          font-size: 16px;
+          margin-left: 8px;
+          margin-top: 1px;
+          font-weight: 600;
+          flex-shrink: 0;
+        }
+
+        .l_active {
+          color: #5386f6;
+        }
+      }
+    }
   }
 
   .top-btns {
@@ -1710,72 +1816,20 @@ export default {
     flex-shrink: 0;
     margin-left: auto;
   }
-}
 
-// 处方 tab 列表
-.prescription-tabs {
-  display: flex;
-  flex-shrink: 0;
-  overflow-x: auto;
-  white-space: nowrap;
-
-  .tab-item {
-    position: relative;
-    display: flex;
-    align-items: center;
-    padding: 8px 20px;
+  // 底部金额 - 固定在最底部
+  .table-b-bottom {
     flex-shrink: 0;
-    font-size: 14px;
-    color: #666;
-    background: #f5f7fa;
-    border-radius: 4px;
-    cursor: pointer;
-    margin-right: 6px;
-    transition: all 0.25s;
-
-    &:hover {
-      color: #5386f6;
-      background: #e8eefb;
-    }
-
-    &.active {
-      background: #5386f6;
-      color: #fff;
-
-      &:hover {
-        background: #4078f0;
-      }
-
-      .tab-close {
-        color: rgba(255, 255, 255, 0.7);
-
-        &:hover {
-          color: #fff;
-          background: rgba(255, 255, 255, 0.2);
-        }
-      }
-    }
-
-    .tab-name {
-      max-width: 200px;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-    }
+    padding: 10px;
+    border-top: 2px solid #dedede;
+    background: #fff;
 
-    .tab-close {
-      margin-left: 8px;
-      width: 16px;
-      height: 16px;
-      line-height: 16px;
-      text-align: center;
-      border-radius: 50%;
+    .t-b-l-item {
       font-size: 14px;
-      color: #999;
-      transition: all 0.2s;
+      color: #333;
+      margin-right: 20px;
 
-      &:hover {
-        background: rgba(0, 0, 0, 0.1);
+      span {
         color: #ff6245;
       }
     }
@@ -1787,6 +1841,8 @@ export default {
   padding: 7px 0 0;
   display: flex;
   flex-direction: column;
+  flex: 1;
+  min-height: 0;
 
   // 工具栏
   .table-toolbar {
@@ -1810,7 +1866,7 @@ export default {
   .table-container {
     padding: 0 5px;
     flex: 1;
-    min-height: 0;
+    min-height: 100px;
     overflow: auto;
   }
 
@@ -1903,6 +1959,12 @@ export default {
 
     img {
       width: 16px;
+      cursor: pointer;
+    }
+
+    .operate-disabled {
+      opacity: 0.4;
+      cursor: not-allowed;
     }
   }
 }
@@ -1928,24 +1990,6 @@ export default {
   height: 33px !important;
 }
 
-// 底部金额
-.table-b-bottom {
-  flex-shrink: 0;
-  padding: 10px;
-  border-top: 2px solid #dedede;
-  margin-top: 5px;
-
-  .t-b-l-item {
-    font-size: 14px;
-    color: #333;
-    margin-right: 20px;
-
-    span {
-      color: #ff6245;
-    }
-  }
-}
-
 // 详情弹窗样式(scoped 内)
 .drug-body {
   padding: 10px;

+ 449 - 249
src/views/diagnosis/Prescribing.vue

@@ -292,18 +292,40 @@
               <el-input
                 size="mini"
                 disabled
-                :value="patiensMsg.maindiagnosis.diagnosis || ''"
+                :value="westernDiag"
               ></el-input>
             </div>
           </div>
           <div class="his-item" v-if="container_i == 2">
             <div class="name">建议诊断:</div>
             <div class="value">
-              <el-input
-                size="mini"
-                disabled
-               :value="patiensMsg.maindiagnosis.diagnosis || ''"
-              ></el-input>
+              <div class="western-disease-input-wrapper" @click="$refs.suggestDiagAutocomplete && $refs.suggestDiagAutocomplete.focus()">
+                <el-tag
+                  v-for="code in suggestDiag"
+                  :key="code"
+                  size="mini"
+                  closable
+                  @close="removeWesternDisease(code)"
+                >{{ westernDiseaseNameMap[code] || code }}</el-tag>
+                <el-autocomplete
+                  ref="suggestDiagAutocomplete"
+                  size="mini"
+                  v-model="westernDiseaseSearch"
+                  :fetch-suggestions="queryWesternDisease"
+                  value-key="westname"
+                  :placeholder="suggestDiag.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>
             </div>
           </div>
         </div>
@@ -453,6 +475,11 @@
           ref="suitScience"
           :showEditable="false"
           :showGuide="true"
+          :showEntrust="true"
+          :showAgreementTotal="false"
+          :useIsUpdateLock="true"
+          :ownerType="'2'"
+          :requiredTreatFields="true"
           @save="submitRecipe1()"
         />
       </div>
@@ -1103,7 +1130,8 @@ import {
   recipeIsPay,
   getPreNumber,
   getRecipePriview,
-  getMaxMinDoaseNumber
+  getMaxMinDoaseNumber,
+  getRecipeByBasis
 } from "@/api/diagnosis.js";
 import { numberToUpperCase } from "@/utils/format.js";
 import { addRecipeFrom } from "@/api/dataAnalysis.js";
@@ -1117,7 +1145,8 @@ import {
   changeAndJoin,
   getPreDetal,
   getAcupointD,
-  getMedDetail
+  getMedDetail,
+  getXDiseaseName
 } from "@/api/knowledge.js";
 import {
   legacyDeduceIllnessPrescriptionMethod,
@@ -1299,7 +1328,7 @@ export default {
         },
         {
           id: '2',
-          businesstype: '3',
+          businesstype: '7', // 适宜技术 businesstype 由 '3' 改为 '7'
           name: "适宜技术处方",
           check: false,
           hide: true,
@@ -1309,6 +1338,15 @@ export default {
       patiensMsg: {}, // 患者信息
       patientMsgPreviewImages: [], // 患者信息预览图片
       dianosisMsg: [], // 诊断信息
+      westernDiag: '', // 西医主诊断(接口返回,只读)
+      suggestDiag: [], // 建议诊断(用户可编辑,多选)
+      // 西医诊断搜索相关
+      westernDiseaseOptions: [],
+      westernDiseaseNameMap: {},
+      westernDiseaseSearch: '',
+      westernDiseasePage: 1,
+      westernDiseaseHasMore: true,
+      westernDiseaseLoading: false,
 
       ops: {
         vuescroll: {},
@@ -1444,14 +1482,17 @@ export default {
     },
     _updateContentTabs(value) {
       if (!value) return;
-      console.log('log:更新类别-开始', value, this.$el);
       const tabs = value.split(',');
       for (const id of tabs) {
         const index = this.contentTabs.findIndex(item => item.id === id);
         if (index !== -1) this.$set(this.contentTabs, index, {...this.contentTabs[index], hide: false});
         this._hackUpdateContentTab(id);
       }
-      console.log('log:更新类别-完成', this.contentTabs.map(item => `${item.id}: ${item.hide}`).join(','));
+      // 设置 container_i 为第一个可见的 tab
+      const firstVisible = this.contentTabs.findIndex(tab => !tab.hide);
+      if (firstVisible !== -1) {
+        this.container_i = firstVisible;
+      }
     },
 
     // 中医诊断推导点击
@@ -1532,6 +1573,7 @@ export default {
         contentTabs: this.contentTabs,
         container_i: this.container_i,
         rRecomendR: this.rRecomendR,
+        suggestDiag: this.suggestDiag,
         child1: {
           recipe_tabs: child1.recipe_tabs,
           recipe_tabs_c: child1.recipe_tabs_c
@@ -1605,6 +1647,7 @@ export default {
       this.contentTabs = storageData.contentTabs;
       this.container_i = storageData.container_i;
       this.rRecomendR = Array.isArray(storageData.rRecomendR) ? storageData.rRecomendR : [];
+      this.suggestDiag = Array.isArray(storageData.suggestDiag) ? storageData.suggestDiag : [];
       // child1.getSelectType("剂型", 0);
       // child1.getSelectType("处方用法");
       // child1.getSelectType("中药服药时间");
@@ -1683,7 +1726,6 @@ export default {
     },
     // 手风琴 更改
     activeChange(e) {
-      console.log(e, "手风琴该表");
 
       // if (this.activeNames == e) return;
       if (e) {
@@ -1812,7 +1854,6 @@ export default {
         });
         return false;
       }
-      console.log(recipeAlert, "recipeAlert");
       // let data2 = children[1]
       // let data3 = children[2]
       let zhongPrescriptionVo = [];
@@ -1821,9 +1862,9 @@ export default {
         medAdressData = this.$refs.medAdress.form;
       }
 
-      console.group("debug:20250558")
+      // console.group("debug:20250558")
       data1.recipe_tabs.forEach((item, index) => {
-        console.log("填写值", item.bottom_form.radio)
+        // console.log("填写值", item.bottom_form.radio)
         let obj = {
           seqn: index + 1,
           province:
@@ -1875,7 +1916,7 @@ export default {
           // preId: this.$route.query.recipeID ? this.$route.query.recipeID : ""
           preId: item.preId || "",
         };
-        console.log("保存值", obj.isdelivery)
+        // console.log("保存值", obj.isdelivery)
         item.totalTableD.forEach(item1 => {
           if (item1.name && item1.color != "red") {
             let obj1 = {
@@ -2018,77 +2059,91 @@ export default {
     },
     // 处理适宜剂数处方提交数据
     dealRecipe3(data1) {
-      let isAutoCheck = data1.isAutoCheck;
-      if (!data1.tableData4.filter(item => item.name).length) {
-        this.$message.error({ message: '请完善适宜技术处方穴位信息', showClose: true });
-        return {};
+      try {
+      // 新版 AcupointTable 组件
+      const acupointTable = this.$refs.suitScience;
+      if (!acupointTable) {
+        this.$message.error({ message: '适宜技术处方组件未加载', showClose: true });
+        return [];
       }
-      let hasDrugMsg = [];
-      data1.tableData4.forEach((item, index) => {
-        if (!item.name && index != data1.tableData4.length - 1) {
-          hasDrugMsg.push(index + 1);
-        }
-      });
 
-      if (hasDrugMsg.length > 0) {
-        // this.$message.error(
-        //   "请完善适宜技术处方穴位相关信息(序号:" + hasDrugMsg.join(",") + ")"
-        // );
-        return false;
+      // 校验:至少有一个处方
+      if (!acupointTable.prescriptions || acupointTable.prescriptions.length === 0) {
+        this.$message.error({ message: '请先新增适宜技术处方', showClose: true });
+        return [];
       }
 
-      if (!data1.bottom_form.doseNum1) {
-        this.$message.error({
-          message: "请完善适宜技术处方次数信息",
-          showClose: false,
-          type: "error"
-        });
-        return false;
+      // 校验操作指南
+      const hasOperationGuide = acupointTable.prescriptions.every((_, index) => {
+        const d = acupointTable.prescriptionDataMap[index];
+        return d && d.operationGuide && d.operationGuide.trim();
+      });
+      if (!hasOperationGuide) {
+        this.$message.error({ message: '请完善适宜技术处方操作指南', showClose: true });
+        return [];
       }
 
-      if (!data1.bottom_form.doseType1) {
-        this.$message.error({
-          message: "请完善适宜技术处方类型信息",
-          showClose: false,
-          type: "error"
-        });
-        return false;
+      // 校验单次数量
+      const hasSingleCount = acupointTable.prescriptions.every((_, index) => {
+        const d = acupointTable.prescriptionDataMap[index];
+        return d && d.singleCount > 0;
+      });
+      if (!hasSingleCount) {
+        this.$message.error({ message: '请完善适宜技术处方单次数量', showClose: true });
+        return [];
       }
 
-      let obj = {
-        command: data1.bottom_form.zhutuo,
-        num: Number(data1.bottom_form.doseNum1),
-        technologyType: data1.bottom_form.doseType1,
-        type: 2,
-        useexplain: data1.bottom_form.caozuo,
-        // preId: this.$route.query.recipeID ? this.$route.query.recipeID : "",
-        preId: data1.preId || "",
-        detail: []
-      };
+      // 已支付则跳过
+      if (acupointTable.paystate == 1) {
+        return [];
+      }
 
-      data1.tableData4.forEach(item => {
-        if (item.name) {
-          let obj1 = {
-            pointid: item.acuid,
-            pointname: item.acuname,
-            price: data1.bottom_form.doseType,
-            seqn: item.id,
-            preDetailId: this.getEditPreNo(),
-          };
-          obj.detail.push(obj1);
-        }
+      // 获取治疗列表(每个prescription对应一个治疗项)
+      const treatmentList = acupointTable.buildTreatmentList();
+      if (!treatmentList || treatmentList.length === 0) {
+        this.$message.error({ message: '请完善适宜技术处方信息', showClose: true });
+        return [];
+      }
+
+      // 为每个prescription创建独立的项目对象
+      // sourceId和accordPid都传recordid(患者pid)
+      const recordid = this.getPatiensInfo.pid || "";
+
+      const result = acupointTable.prescriptions.map((p, index) => {
+        const treatmentItem = treatmentList[index];
+        const d = acupointTable.prescriptionDataMap[index] || {};
+
+        // 计算该项目的总金额
+        const singleAmount = parseFloat(d.singlePrice) || 0;
+        const treatCount = d.treatCount || 0;
+        const projectTotal = singleAmount * treatCount;
+
+        return {
+          accordPid: recordid,
+          num: treatCount,
+          thisRecipePrice: singleAmount,
+          totalAmount: projectTotal,
+          command: d.command || "",
+          useexplain: d.operationGuide || "",
+          type: "2",
+          sourceId: recordid,
+          sourceType: "2",
+          suggestDiag: Array.isArray(this.suggestDiag) ? this.suggestDiag.join(',') : (this.suggestDiag || ""),
+          westernDiag: this.westernDiag || "",
+          treatmentList: [treatmentItem],
+        };
       });
-      if (data1.isMyMade) {
+
+      if (acupointTable.isMyMade) {
         this.addRecipeFrom("3");
       }
-      // if ((data1.isPay || data1.prescribed == 1) && isAutoCheck == 0) {
-      //   return {};
-      // }
-      // && isAutoCheck == 1
-      if (data1.paystate == 1) {
-        return {};
+
+      return result;
+      } catch (error) {
+        console.error('dealRecipe3异常:', error);
+        this.$message.error({ message: '处理适宜技术处方数据时发生错误', showClose: true });
+        return [];
       }
-      return obj;
     },
     // 获取数据 赋值给 中药处方
     assignRecipe1(data, loading) {
@@ -2440,56 +2495,78 @@ export default {
     // 获取数据 赋值给 适宜技术处方
     assignRecipe3(data, loading) {
       setTimeout(() => {
-        let children = this.$children.filter(item => {
-          return (
-            item.name == "中药处方" ||
-            item.name == "中药制剂" ||
-            item.name == "适宜技术处方"
-          );
-        });
-        let data1 = children[2];
-        let isAutoCheck = data1.isAutoCheck;
-        data1.preId = data.preId ? data.preId : "";
-        data1.bottom_form.doseNum1 = data.num;
-        data1.bottom_form.doseType1 = data.technologyType;
-        data1.bottom_form.zhutuo = data.command;
-        data1.bottom_form.caozuo = data.useexplain;
+        const acupointTable = this.$refs.suitScience;
+        if (!acupointTable) {
+          loading.close();
+          return;
+        }
 
-        data1.allMoney = data.allprice;
-        data1.nowMoney = data.thisRecipePrice;
+        // 兼容数组和对象两种格式,处理数组时合并所有treatmentList
+        const dataArray = Array.isArray(data) ? data : [data];
+        if (!dataArray.length) {
+          loading.close();
+          return;
+        }
 
-        if (!!this.getEditPreNo()) {
-          if (data.revierwstate == 1) {
-            data1.prescribed = 0; // 是否已开方 0否 1是
-            data1.paystate = 0;
+        // 使用第一个数据作为基础处方信息
+        const techData = dataArray[0];
+
+        // 存储处方级字段,提交时需要用到
+        console.log('适宜技术处方赋值数据', techData);
+        acupointTable._prescriptionMeta = {
+          preId: techData.preId || "",
+          technologyType: techData.technologyType || "",
+          num: techData.num || 0,
+          allprice: techData.allprice || 0,
+          thisRecipePrice: techData.thisRecipePrice || 0,
+          totalAmount: techData.totalAmount || 0,
+          prescribed: techData.prescribed || 0,
+          paystate: techData.paystate || 0,
+          revierwstate: techData.revierwstate || 0,
+          command: techData.command || "",
+          useexplain: techData.useexplain || "",
+          sourceType: techData.sourceType || "",
+          westernDiag: techData.westernDiag || "",
+        };
+
+        // 处方状态
+        if (this.getEditPreNo()) {
+          if (techData.revierwstate == 1) {
+            acupointTable.prescribed = 0;
+            acupointTable.paystate = 0;
           } else {
-            data1.prescribed = data.prescribed; // 是否已开方 0否 1是
-            data1.paystate = data.paystate;
+            acupointTable.prescribed = techData.prescribed || 0;
+            acupointTable.paystate = techData.paystate || 0;
           }
         } else {
-          data1.prescribed = data.prescribed; // 是否已开方 0否 1是
-          data1.paystate = data.paystate;
+          acupointTable.prescribed = techData.prescribed || 0;
+          acupointTable.paystate = techData.paystate || 0;
         }
 
-        let arr = [];
-        data.detail.forEach((item, index) => {
-          let obj = {
-            id: item.sqen,
-            name: item.pointname,
-            acuname: item.pointname,
-            acuid: item.pointid
-          };
+        // 西医主诊断(只读,接口返回)和建议诊断(用户输入)
+        this.westernDiag = techData.westernDiag || '';
+        // 建议诊断(多选,从接口返回)
+        if (techData.suggestDiag) {
+          this.suggestDiag = typeof techData.suggestDiag === 'string'
+            ? techData.suggestDiag.split(',').filter(Boolean)
+            : Array.isArray(techData.suggestDiag) ? techData.suggestDiag : [];
+        }
 
-          arr.push(obj);
-        });
+        // 合并所有数据中的treatmentList
+        const mergedTreatmentList = dataArray.reduce((acc, item) => {
+          if (item.treatmentList && Array.isArray(item.treatmentList)) {
+            acc.push(...item.treatmentList);
+          }
+          return acc;
+        }, []);
 
-        arr.filter((item, index) => {
-          return (item.id = index + 1);
-        });
+        // 使用 loadFromServerData 加载合并后的治疗列表数据
+        if (mergedTreatmentList.length > 0) {
+          acupointTable.loadFromServerData(mergedTreatmentList);
+        }
 
-        data1.tableData4 = arr;
         loading.close();
-      }, 1000);
+      }, 500);
     },
     // 协定方数据转方 赋值给中药处方
     agreeAssignToTCM(data, loading, request = true) {
@@ -2625,117 +2702,9 @@ export default {
     },
     // 提交中药处方
     async submitRecipe1() {
-      // ============================================================
-      // [临时调试] 后端 getRecipePriview 接口数据结构待确认,
-      // 先跳过校验/组装/网络,直接用 mock 数据弹出预览弹窗,仅用于调样式。
-      // 原有保存逻辑(含 dealRecipe3 等)全部保留在下方未删除;
-      // 接口确认后把 DEBUG_PREVIEW_POPUP 改为 false(或删除本 if 块)即可恢复。
-      // ============================================================
-      const DEBUG_PREVIEW_POPUP = true; // 调试完改为 false
-      if (DEBUG_PREVIEW_POPUP) {
-        // mock 条形码(SVG 数据 URI,仅用于占位调样式)
-        const barcodeSvg = `<svg xmlns='http://www.w3.org/2000/svg' width='160' height='48'><rect width='160' height='48' fill='white'/><g fill='black'><rect x='4' y='4' width='2' height='40'/><rect x='8' y='4' width='1' height='40'/><rect x='11' y='4' width='3' height='40'/><rect x='16' y='4' width='1' height='40'/><rect x='19' y='4' width='2' height='40'/><rect x='23' y='4' width='4' height='40'/><rect x='29' y='4' width='1' height='40'/><rect x='32' y='4' width='2' height='40'/><rect x='36' y='4' width='1' height='40'/><rect x='39' y='4' width='3' height='40'/><rect x='44' y='4' width='2' height='40'/><rect x='48' y='4' width='1' height='40'/><rect x='51' y='4' width='2' height='40'/><rect x='55' y='4' width='3' height='40'/><rect x='60' y='4' width='1' height='40'/><rect x='63' y='4' width='2' height='40'/><rect x='67' y='4' width='4' height='40'/><rect x='73' y='4' width='1' height='40'/><rect x='76' y='4' width='2' height='40'/><rect x='80' y='4' width='1' height='40'/><rect x='83' y='4' width='3' height='40'/><rect x='88' y='4' width='2' height='40'/><rect x='92' y='4' width='1' height='40'/><rect x='95' y='4' width='2' height='40'/><rect x='99' y='4' width='3' height='40'/><rect x='104' y='4' width='1' height='40'/><rect x='107' y='4' width='2' height='40'/><rect x='111' y='4' width='1' height='40'/><rect x='114' y='4' width='4' height='40'/><rect x='120' y='4' width='2' height='40'/><rect x='124' y='4' width='1' height='40'/><rect x='127' y='4' width='3' height='40'/><rect x='132' y='4' width='2' height='40'/><rect x='136' y='4' width='1' height='40'/><rect x='139' y='4' width='2' height='40'/><rect x='143' y='4' width='3' height='40'/><rect x='148' y='4' width='1' height='40'/></g></svg>`;
-        const techPatient = {
-          name: "张三", sex: "男", age: "30岁", clinic: "中医科",
-          clinicalDiagnosis: "示例临床诊断", prescriptionTime: "2026-06-12 10:00",
-          phone: "138****0000",
-          prescriber: "开方医生", reviewer: "审核", dispatcher: "调配",
-          checker: "核对", dispenser: "发药"
-        };
-        const techBarcode = "data:image/svg+xml," + encodeURIComponent(barcodeSvg);
-        this.priviewData = {
-          shiyijishuFormVos: [
-            {
-              ...techPatient, barcode: techBarcode, pid: "DEBUG-001",
-              itemName: "内科失眠推拿治疗", // 项目名称
-              prescriptiontechnologydetailVos: [
-                { pointname: "大椎", num: 1 },
-                { pointname: "肺俞", num: 2 },
-                { pointname: "风池", num: 2 }
-              ],
-              meridian: "膀胱经", // 经络
-              singleQty: 6, pricingUnit: "部位", // 数量
-              treatNum: 7, // 治疗次数
-              frequency: "1天1次", // 频次
-              pointMatchGuide: "示例配穴指南:以局部穴位为主,配合循经取穴",
-              useExplain: "示例操作指南:患者仰卧位,常规消毒后进针,得气后留针20分钟",
-              entrust: "注意保暖,避免吹风、洗澡", // 嘱托
-              amountOfMedicine: 20, lumpSum: 20
-            },
-            {
-              ...techPatient, barcode: techBarcode, pid: "DEBUG-002",
-              itemName: "普通针刺(快速针)",
-              prescriptiontechnologydetailVos: [
-                { pointname: "合谷", num: 1 },
-                { pointname: "足三里", num: 2 }
-              ],
-              meridian: "阳明胃经",
-              singleQty: 10, pricingUnit: "次",
-              treatNum: 5,
-              frequency: "2天1次",
-              pointMatchGuide: "示例配穴指南:循经取穴,局部与远端配合",
-              useExplain: "示例操作指南:常规消毒,快速进针,得气后行平补平泻手法",
-              entrust: "针刺后请按压片刻,避免出血",
-              amountOfMedicine: 30, lumpSum: 30
-            },
-            {
-              ...techPatient, barcode: techBarcode, pid: "DEBUG-003",
-              itemName: "拔罐疗法(电)",
-              prescriptiontechnologydetailVos: [
-                { pointname: "肩井", num: 1 },
-                { pointname: "天宗", num: 1 }
-              ],
-              meridian: "小肠经",
-              singleQty: 4, pricingUnit: "部位",
-              treatNum: 3,
-              frequency: "1天1次",
-              pointMatchGuide: "示例配穴指南:以痛点及周围肌肉为主",
-              useExplain: "示例操作指南:清洁皮肤,扣罐后接电针仪,留罐10分钟",
-              entrust: "拔罐后避免吹风、洗澡",
-              amountOfMedicine: 40, lumpSum: 40
-            }
-          ],
-          // 左侧 患者信息 + 就诊信息(submitRecipe 的 msg 来源)
-          prescriptionVo: {
-            patient: {
-              name: "张三",
-              sex: "男",
-              age: "30",
-              idcard: "110101199001011234",
-              phone: "138****0000"
-            },
-            outpatientRecords: {
-              recordstime: "2026-06-12 10:00",
-              departmentName: "中医科"
-            },
-            mainDiagnosis: {
-              namemedicine: "示例中医诊断",
-              treatment: "示例治法"
-            },
-            secondDiagnosis: [
-              { namemedicine: "示例其他中医诊断", diagnosis: "" },
-              { namemedicine: "", diagnosis: "示例西医诊断" }
-            ],
-            electronicmedicalrecord: {
-              chiefcomplaint: "示例主诉内容",
-              historypresent: "示例现病史内容",
-              pasthistory: "示例既往史内容",
-              fourmedicine: "示例中医四诊内容",
-              physicalexamination: "示例体格检查内容",
-              supplementaryexamination: "示例辅助检查内容",
-              image1: ""
-            }
-          }
-        };
-        this.showPriview = true;
-        this.saving = false;
-        this.$refs.suitScience && this.$refs.suitScience.saveDone();
-        return;
-      }
-      // ==================== [临时调试结束] ====================
-
       const cancel = (id) => {
         this.saving = false;
+        this.$refs.suitScience && this.$refs.suitScience.saveDone();
         if (id) this.container_i = this.contentTabs.findIndex(tab => tab.id === id);
       }
 
@@ -2809,12 +2778,16 @@ export default {
           '2': {
             if (+child.paystate === 1) continue;
             technologyPrescriptionVo = this.dealRecipe3(child);
-            if (!technologyPrescriptionVo || !Object.keys(technologyPrescriptionVo).length) return cancel(tab.id);
+            if (!technologyPrescriptionVo || !technologyPrescriptionVo.length) return cancel(tab.id);
             break;
           }
         }
       }
 
+      console.log("【处方保存数据】中药处方:", JSON.stringify(zhongPrescriptionVo, null, 2));
+      console.log("【处方保存数据】中药制剂:", JSON.stringify(chengPrescriptionVo, null, 2));
+      console.log("【处方保存数据】适宜技术:", JSON.stringify(technologyPrescriptionVo, null, 2));
+
       await this._getRecipePriview(
           zhongPrescriptionVo,
           chengPrescriptionVo,
@@ -2881,12 +2854,155 @@ export default {
         case '2': this.isTuiDaoSuit = false; break;
       }
     },
+    // ========== 西医诊断搜索(分页) ==========
+    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 selectedCodes = Array.isArray(this.suggestDiag)
+            ? this.suggestDiag
+            : [];
+          const resultCodes = new Set(list.map((i) => i.westcode));
+          const preserved = selectedCodes
+            .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;
+      }
+    },
+    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;
+      }
+    },
+    onWesternDiseaseVisible(show) {
+      if (!show) {
+        const wrap = document.querySelector(
+          ".western-disease-input-wrapper .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-input-wrapper .el-scrollbar__wrap",
+        );
+        if (wrap) {
+          wrap.addEventListener(
+            "scroll",
+            (this._wdScroll = () => {
+              if (
+                wrap.scrollTop + wrap.clientHeight >=
+                wrap.scrollHeight - 10
+              ) {
+                this.loadMoreWesternDisease();
+              }
+            }),
+          );
+        }
+      });
+    },
+    async queryWesternDisease(queryString, cb) {
+      await this.searchWesternDisease(queryString);
+      if (this.westernDiseaseOptions.length > 0) {
+        const selectedCodes = Array.isArray(this.suggestDiag) ? this.suggestDiag : [];
+        const options = this.westernDiseaseOptions.map(item => ({
+          ...item,
+          _disabled: selectedCodes.includes(item.westcode),
+        }));
+        cb(options);
+      } else {
+        cb([{ westname: "暂无数据", _disabled: true }]);
+      }
+    },
+    onWesternDiseaseSelect(item) {
+      if (item._disabled) {
+        this.$nextTick(() => {
+          this.westernDiseaseSearch = "";
+        });
+        return;
+      }
+      if (!item || !item.westcode) return;
+      if (!Array.isArray(this.suggestDiag)) {
+        this.suggestDiag = [];
+      }
+      if (!this.suggestDiag.includes(item.westcode)) {
+        this.suggestDiag.push(item.westcode);
+        this.westernDiseaseNameMap[item.westcode] = item.westname;
+      }
+      this.westernDiseaseSearch = "";
+    },
+    removeWesternDisease(code) {
+      if (!Array.isArray(this.suggestDiag)) return;
+      this.suggestDiag = this.suggestDiag.filter((c) => c !== code);
+    },
     // 顶部tab 改变
     async changeContainer(item, type) {
       this.container_i = type;
       item.check = true;
-      // if (item.id === '1') return;
-      // if (this.contentTabs[type].color == 'red') {
+      
+      // 切换到适宜技术tab时,重置标志位以允许重新获取数据
+      if (type === 2) {
+        this.isTuiDaoSuit = false;
+      }
+      
       await this.inferRecipe(3, item.businesstype);
 
       const child = this.$children.find(child => child.name === item.name);
@@ -2896,21 +3012,6 @@ export default {
       } else if (item.id === '2') {
         try { this.tjRecipeId = child.recipeId; } catch (e) { this.tjRecipeId = "" }
       }
-      // }
-
-      // if (type == 2) {
-      //   if (!this.isTuiDaoSuit) {
-      //     this.isTuiDaoSuit = true
-      //     this.inferRecipe()
-      //   }
-      // }
-
-      // if (type == 0) {
-      //   if (!this.isTuiDaoZy) {
-      //     this.isTuiDaoZy = true
-      //     this.inferRecipe()
-      //   }
-      // }
     },
     checked(item1) {
       this.contentTabs.forEach(item => {
@@ -3378,7 +3479,7 @@ export default {
       });
       let params = {
         recordid: this.getPatiensInfo.pid,
-        technology: technology,
+        technologies: technology,
         zhongchengyao: zhongchengyao,
         zhongyao: zhongyao
       };
@@ -3630,7 +3731,7 @@ export default {
 
       if (type != 4 && businesstype == null) {
         businesstype =
-          this.container_i == 0 ? "1" : this.container_i == 2 ? "3" : "1";
+          this.container_i == 0 ? "1" : this.container_i == 2 ? "7" : "1"; // 适宜技术由 '3' 改为 '7'
       }
 
       let params = {
@@ -3727,7 +3828,7 @@ export default {
           return;
         }
 
-        setTimeout(() => {
+        setTimeout(async() => {
           if (
             // this.$route.query.infer &&
             // this.$route.query.infer == "true" &&
@@ -3749,16 +3850,30 @@ export default {
               this.isTuiDaoZy = true;
             }
           } else if (this.container_i == 2) {
-            //  && child2.tableData4.length == 1
-            let info
             if (arr2.length > 0) {
-              this.setDrugsInfo(arr2[0].items);
-              this.setRecipeId(arr2[0].acupreid);
-              info = arr2[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',
+                });
+                if (recipeRes.ResultCode === 0 && recipeRes.Data) {
+                  this.assignRecipe3(recipeRes.Data, loading3);
+                } else {
+                  loading3.close();
+                }
+              } catch (e) {
+                loading3.close();
+              }
             }
 
             this.addRecipeFrom("4", 2);
-            this.suitChnageOrJoin('', info);
             if (type == 3) {
               this.isTuiDaoSuit = true;
             }
@@ -4688,6 +4803,8 @@ export default {
     .center-table {
       border: 2px solid #dedede;
       padding: 0px 0 0;
+      height: 100%;
+      overflow: hidden;
       // min-height: 680px;
       // position: relative;
 
@@ -5457,6 +5574,88 @@ export default {
 </style>
 <style lang="scss" scoped>
 @import "../../style/media/diagnosis/prescribing.scss";
+
+/* 西医诊断搜索样式 - scoped 穿透 */
+.prescribing ::v-deep .his-item .value:has(.western-disease-input-wrapper) {
+  width: auto;
+  min-width: 200px;
+  flex: 1;
+}
+
+.prescribing ::v-deep .western-disease-input-wrapper {
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 2px 4px;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  min-height: 28px;
+  cursor: text;
+
+  .el-tag {
+    margin: 2px 4px 2px 0;
+    max-width: 200px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .el-autocomplete {
+    flex: 1;
+    min-width: 80px;
+  }
+
+  .el-input {
+    border: none !important;
+    background: transparent !important;
+  }
+
+  .el-input__wrapper {
+    border: none !important;
+    background: transparent !important;
+    box-shadow: none !important;
+    padding: 0 !important;
+  }
+
+  .el-input__inner {
+    border: none !important;
+    padding: 0 4px;
+    height: 24px;
+    line-height: 24px;
+    background: transparent !important;
+    box-shadow: none !important;
+  }
+
+  .el-input__suffix {
+    display: flex;
+    align-items: center;
+  }
+
+  &:hover {
+    border-color: #c0c4cc;
+  }
+
+  &:focus-within {
+    border-color: #409eff;
+  }
+
+  &.view-mode {
+    cursor: default;
+    background: #f5f7fa;
+
+    .el-tag {
+      background-color: #f0f2f5;
+      border-color: #e4e7ed;
+      color: #909399;
+    }
+  }
+}
+
+.autocomplete-disabled {
+  color: #999 !important;
+  cursor: not-allowed !important;
+  pointer-events: none;
+}
+
 </style>
 <style lang="scss">
 .reasonable-safe-medicines-wrapper {
@@ -5522,4 +5721,5 @@ export default {
     padding-bottom: 8px;
   }
 }
+
 </style>

+ 5 - 4
src/views/diagnosis/components/submitRecipeTech.vue

@@ -288,7 +288,7 @@
                 :key="index"
                 placement="top"
                 :open-delay="300"
-                :content="item.recipeType==1 ? ('中药处方'+(index+1)) : (item.recipeType==2 ? '中药制剂处方' : (item.itemName||'适宜技术处方'))"
+                :content="item.recipeType==1 ? ('中药处方'+(index+1)) : (item.recipeType==2 ? '中药制剂处方' : (item.technologyType||'适宜技术处方'))"
               >
                 <div
                   :class="['tabs-item',recipeItem.pid==item.pid?'tabs-active':'']"
@@ -296,7 +296,7 @@
                 >
                   <span class="tabs-text" v-if="item.recipeType==1">中药处方{{index+1}}</span>
                   <span class="tabs-text" v-if="item.recipeType==2">中药制剂处方</span>
-                  <span class="tabs-text" v-if="item.recipeType==3">{{item.itemName || '适宜技术处方'}}</span>
+                  <span class="tabs-text" v-if="item.recipeType==3">{{item.technologyType || '适宜技术处方'}}</span>
                   <img src="~@/assets/new-icon/close.png" alt @click.self="deleteItem(index)" />
                 </div>
               </el-tooltip>
@@ -603,7 +603,8 @@ export default {
       });
       let params = {
         recordid: this.getPatiensInfo.pid,
-        technology: technology,
+        // technology: technology,
+        technologies: technology,
         zhongchengyao: zhongchengyao,
         zhongyao: zhongyao
       };
@@ -854,7 +855,7 @@ export default {
   .tabs-item {
     cursor: pointer;
     min-width: 105px;
-    max-width: 140px;
+    max-width: 180px;
     flex-shrink: 0;
     padding: 2px 5px;
     font-size: 14px;