Эх сурвалжийг харах

Merge branch 'feature/task-244' into develop

cc12458 6 сар өмнө
parent
commit
a02dbfd6de

+ 25 - 1
src/api/business.js

@@ -242,7 +242,31 @@ export function addOrUpdateDrug(data) {
         data
     })
 };
-
+export function getDrugMap(pid) {
+    const group = (array, level = 0) => {
+        if (!Array.isArray(array) || !array.length) return level > 1 ? void 0 : [];
+        return array.map(item => {
+            const children = group(item.children, level + 1);
+            return children ? {
+                value: item.pid,
+                label: item.name,
+                children, leaf: false,
+            } : {
+                value: item.pid,
+                label: item.name,
+                leaf: true,
+            };
+        });
+    };
+    return request({url: `/basis/stitutionsdrugMgr/getDrugCatalogueInfo/${pid}`, method: 'get'}).then((res) => {
+        if (res.ResultCode !== 0) throw {message: res.ResultInfo};
+        const data = res.Data;
+        return {
+            pid: data.pid,
+            groupInfo: group(JSON.parse(data.groupInfo)),
+        };
+    });
+}
 // 获取药品映射详情
 export function getDrugMapList(data) {
     return request({

+ 6 - 2
src/components/Propup.vue

@@ -13,14 +13,14 @@
         <span>{{title}}</span>
         <div @click="closePropup()">+</div>
       </div>
-      <div class="popup-container" v-if="showBody">
+      <div class="popup-container" v-if="showBody" v-loading="loading">
         <slot name="body"></slot>
         <div class="btns flex-center" v-if="showBtns">
           <div class="confim flex-center" @click="confim()" v-if="confimText">{{confimText}}</div>
           <div class="cancle flex-center" @click="cancle()" v-if="!hideCancleButton" :style="cancleStyle">{{cancleText}}</div>
         </div>
       </div>
-      <div v-else>
+      <div v-else v-loading="loading">
         <slot name="body"></slot>
         <div class="btns flex-center" v-if="showBtns">
           <div class="confim flex-center" @click="confim()" v-if="confimText">{{confimText}}</div>
@@ -37,6 +37,10 @@ export default {
       type: Boolean,
       default: true
     },
+    loading: {
+      type: Boolean,
+      default: false
+    },
     title: {
       type: String,
       default: "添加信息"

+ 207 - 240
src/views/business/DrugList.vue

@@ -9,12 +9,8 @@
         <div class="screening-item flex-vertical-center-l">
           <span>医共体名称:</span>
           <div class="input">
-            <el-select
-              size="mini"
-              v-model="doctorBody"
-              placeholder="请选择"
-              @change="getMedSelect(doctorBody)"
-            >
+            <el-select size="mini" placeholder="请选择"
+                       v-model="searchData.ygtid" @change="searchData.cascader = [];getCascaderB($event)">
               <el-option
                 :label="item.name"
                 :value="item.pid"
@@ -25,41 +21,24 @@
           </div>
         </div>
         <div class="screening-item flex-vertical-center-l">
-          <span>医疗机构名称:</span>
+          <span>医疗机构 / 科室名称:</span>
           <div class="input">
-            <el-select
-              size="mini"
-              v-model="medName"
-              placeholder="请选择"
-              @change="getDepartSelect(medName)"
-            >
-              <el-option
-                :label="item.name"
-                :value="item.pid"
-                v-for="(item,index) in medSelectList"
-                :key="index"
-              ></el-option>
-            </el-select>
-          </div>
-        </div>
-        <div class="screening-item flex-vertical-center-l">
-          <span>科室名称:</span>
-          <div class="input">
-            <el-select size="mini" v-model="departName" placeholder="请选择" clearable>
-              <el-option
-                :label="item.name"
-                :value="item.pid"
-                v-for="(item,index) in departSelect"
-                :key="index"
-              ></el-option>
-            </el-select>
+            <el-cascader v-if="searchData.ygtid" style="width: 100%" size="mini" clearable
+                         :props="{ ...cascaderProp, checkStrictly: true }" :options="cascaderList"
+                         v-model="searchData.cascader" @change="lazyLoadMethod"
+            />
+            <div v-else class="el-select el-select--mini">
+              <div class="el-input el-input--mini el-input--suffix">
+                <input class="el-input__inner" type="text" readonly="readonly" autocomplete="off" placeholder="请选择">
+              </div>
+            </div>
           </div>
         </div>
 
         <el-button type="primary" size="mini" @click="search()">搜索</el-button>
         <el-button type="warning" size="mini" @click="clearFilter()">清空</el-button>
 
-        <el-button type="primary" size="mini" @click="addData" v-if="showAdd">新增</el-button>
+        <el-button type="primary" size="mini" @click="openEditDialog()" v-if="showAdd">新增</el-button>
         <!-- <el-button type="danger" size="mini" v-if="showMapAuto" @click="autoMap(null)">自动映射</el-button> -->
       </div>
     </div>
@@ -82,12 +61,8 @@
               <div class="flex-center operation" slot-scope="scope">
                 <!-- <div class="flex-center" style="margin-right:20px;" v-if="showAdd" @click="add(scope)">
                 新增</div>-->
-                <div class="flex-center" v-if="showEdit" @click="edit(scope)">修改</div>
-                <div
-                  class="flex-center bg-yellow"
-                  v-if="showMap"
-                  @click="$router.push({path:'/index/drugmaplist?id='+scope.row.ygtid})"
-                >映射管理</div>
+                <div class="flex-center" v-if="showEdit" @click="openEditDialog(scope.row)">修改</div>
+                <div class="flex-center bg-yellow" v-if="showMap" @click="openMapPage(scope.row)">映射管理</div>
                 <div class="flex-center bg-red" v-if="showMapAuto" @click="autoMap(scope)">自动映射</div>
                 <div class="flex-center bg-yellow" v-if="showImport">
                   导入
@@ -117,9 +92,10 @@
 
     <popup
       distanceTop="5vh"
-      :showDialog="showDialog"
-      @cancle="showDialog=false"
-      @confim="submit()"
+      :showDialog="showEditDialog"
+      :loading="editLoading"
+      @cancle="showEditDialog=false"
+      @confim="submitEditData()"
       title="药品目录管理"
     >
       <div class="flex-center" slot="body">
@@ -128,30 +104,13 @@
             <span>*</span>
             <div class="name">医共体:</div>
             <div class="input">
-              <el-select v-model="ygt" placeholder="请选择医共体" @change="getMedSelect1(ygt)">
-                <el-option
-                  :label="item.name"
-                  :value="item.pid"
-                  v-for="(item,index) in list1"
-                  :key="index"
-                ></el-option>
-              </el-select>
-            </div>
-          </div>
-          <div class="form-item flex flex-col-center">
-            <span style="opacity:0;">*</span>
-            <div class="name">医疗机构:</div>
-            <div class="input">
-              <el-select
-                clearable
-                v-model="yljg"
-                placeholder="请选择"
-                @change="getDepartSelect1(yljg)"
+              <el-select style="width: 100%" placeholder="请选择医共体"
+                         v-model="editData.ygtid" @change="editData.cascader = [];getCascaderB($event)"
               >
                 <el-option
                   :label="item.name"
                   :value="item.pid"
-                  v-for="(item,index) in list2"
+                  v-for="(item,index) in doctorBodyList"
                   :key="index"
                 ></el-option>
               </el-select>
@@ -159,25 +118,31 @@
           </div>
           <div class="form-item flex flex-col-center">
             <span style="opacity:0;">*</span>
-            <div class="name">科室:</div>
+            <div class="name">医疗机构 / 科室:</div>
             <div class="input">
-              <el-select clearable v-model="ks" placeholder="请选择">
-                <el-option
-                  :label="item.name"
-                  :value="item.pid"
-                  v-for="(item,index) in list3"
-                  :key="index"
-                ></el-option>
-              </el-select>
+              <el-cascader v-if="editCascaderListLoaded" style="width: 100%" clearable collapse-tags
+                           :props="{ multiple: true, }" :options="cascaderList"
+                           v-model="editData.cascader"
+              />
+              <el-cascader v-else-if="editData.ygtid" style="width: 100%" clearable collapse-tags
+                           :props="{ ...cascaderProp, multiple: true, }"
+                           v-model="editData.cascader" @change="lazyLoadMethod"
+              />
+              <div v-else class="el-select" style="width: 100%;">
+                <div class="el-input el-input--suffix">
+                  <input type="text" readonly="readonly" autocomplete="off" placeholder="请选择"
+                         class="el-input__inner">
+                </div>
+              </div>
             </div>
           </div>
           <div class="form-item flex flex-col-center">
             <span>*</span>
             <div class="name">类型:</div>
             <div class="input">
-              <el-select v-model="type" placeholder="请选择类型">
-                <el-option label="中心药房" :value="0"></el-option>
-                <el-option label="HIS" :value="1"></el-option>
+              <el-select style="width: 100%" v-model="editData.type" placeholder="请选择类型">
+                <el-option label="中心药房" value="0"></el-option>
+                <el-option label="HIS" value="1"></el-option>
               </el-select>
             </div>
           </div>
@@ -185,14 +150,14 @@
             <span>*</span>
             <div class="name">药品目录名称:</div>
             <div class="input">
-              <el-input v-model="name" placeholder="请输入"></el-input>
+              <el-input v-model="editData.name" placeholder="请输入"></el-input>
             </div>
           </div>
           <div class="form-item flex-plane-center-l">
             <span>*</span>
             <div class="name">药品目录描述:</div>
             <div class="input">
-              <el-input type="textarea" v-model="desc" placeholder="请输入"></el-input>
+              <el-input type="textarea" v-model="editData.describe" placeholder="请输入"></el-input>
             </div>
           </div>
         </div>
@@ -212,93 +177,172 @@ import {
 
 import { fileImport } from "@/api/upload.js";
 import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
-import { doctorBodySelect } from "@/api/city.js";
 import {
   getDoctorBodySelect,
   getMedSelect,
   getDepartSelect
 } from "@/api/system.js";
+
+let cache = new Map();
 export default {
   components: {
     popup
   },
   data() {
     return {
-      departName: "", // 科室
-      doctorBody: "", // 医共体
-      medName: "", // 医疗机构
-      yigt: "", // 医工体
-      medSelectList: [],
-      doctorBodyList: [],
-      departSelect: [],
+      searchData: {
+        ygtid: '',
+        cascader: [],
+      },
       tableData: [],
       page: 1,
       limit: 10,
       total: 0,
 
       // 新增 表单字段
-      desc: "", // 药品目录描述
-      ygt: "",
-      name: "",
-      type: "",
-      yljg: "",
-      ks: "",
-
+      showEditDialog: false,
+      editLoading: false,
+      editData: {
+        ygtid: '',
+        cascader: [],
+      },
+      editCascaderListLoaded: false,
       showAdd: true,
       showImport: true,
       showMapAuto: true,
       showEdit: true,
       showMap: true,
-      showDialog: false,
 
       pid: "",
       nowPid: "",
 
-      list1: [],
-      list2: [],
-      list3: []
+      // 医共体
+      doctorBodyList: [],
+      // 机构 / 科室
+      cascaderList: [],
+      cascaderProp: {
+        lazy: true,
+        lazyLoad: (node, resolve) => {
+          if (Array.isArray(node.children) && node.children.length > 0) resolve();
+          else switch (node.level) {
+            case 0:
+              /* 编辑表单没有添加 :options="cascaderList" */
+              /* el bug 直接选择子选项 不能选中  */
+              return this.editData.ygtid && this.getCascaderB(this.editData.ygtid).then(resolve);
+            case 1:
+              return this.getCascaderC(node.value).then(resolve);
+            case 2:
+              resolve();
+          }
+        },
+      },
     };
   },
   created() {
-    this.getDoctorBodySelect();
-    this.getDoctorBodySelect1();
+    this.getCascaderA();
     this.getDrugList();
     this.getDrugBM();
     this.nowPid = this.getuserinfo.organizationid;
   },
+  destroyed() { cache.clear(); },
   methods: {
-    addData() {
-      this.desc = "";
-      this.name = "";
-      this.ygt = "";
-      this.type = "";
-      this.showDialog = true;
+    lazyLoadMethod(value) {
+      if (Array.isArray(value) && value.length === 1) {
+        const parent = this.cascaderList.find(item => item.value === value[0]);
+        if (parent && !parent.leaf && !parent.children.length) this.cascaderProp.lazyLoad({
+          value: value[0],
+          level: 1,
+        }, () => void 0);
+      }
     },
-    edit(scope) {
-      this.pid = scope.row.pid;
-      this.desc = scope.row.describe ? scope.row.describe : "";
-      this.name = scope.row.name;
-      this.type = Number(scope.row.type);
-      this.ygt = scope.row.ygtid;
-      this.showDialog = true;
-      this.yljg = scope.row.stitutionsId;
-      this.ks = scope.row.departmentidSelsource;
-
-      this.getMedSelect1(this.ygt, "auto");
-      this.getDepartSelect1(this.yljg, "auto");
+    openMapPage(row) {
+      this.$router.push({path: `/index/drugmaplist?pid=${row.pid}`});
+    },
+    async openEditDialog(row = {}) {
+      this.editData = {
+        pid: row.pid,
+        describe: row.describe || '',
+        name: row.name || '',
+        type: row.type,
+        ygtid: row.ygtid || this.searchData.ygtid,
+        cascader: row.stitutionsId || !this.searchData.cascader.length ? [] : [this.searchData.cascader],
+      };
+      this.editCascaderListLoaded = this.editData.cascader.length > 0 || !!row.stitutionsId;
+      this.showEditDialog = true;
+      if (this.editCascaderListLoaded) {
+        this.editLoading = true;
+        if (this.editData.ygtid) await this.getCascaderB(this.editData.ygtid);
+        const list = await Promise.all(this.cascaderList.map(item => this.getCascaderC(item.value))).then(() => this.cascaderList);
+        if (row.stitutionsId) {
+          const cascader = [];
+          const stitutionsId = (row.stitutionsId || '').split(',').filter(Boolean);
+          const departmentidSelsource = (row.departmentidSelsource || '').split(',').filter(Boolean);
+          for (const s of stitutionsId) {
+            try {
+              const nodes = list.find(item => item.value === s).children.map(node => node.value);
+              let i = 0;
+              let has = 0;
+              do {
+                const d = departmentidSelsource[i];
+                if (nodes.includes(d)) {
+                  has = cascader.push([s, d]);
+                  departmentidSelsource.splice(i, 1);
+                } else if (d) i += 1;
+              } while (departmentidSelsource.length < i);
+              if (!has) cascader.push(...nodes.map(d => [s, d]));
+            } catch (e) { }
+          }
+          this.editData.cascader = [...cascader];
+        }
+        this.editLoading = false;
+      }
+    },
+    async submitEditData() {
+      const {cascader = [], ...params} = this.editData;
+      const stitutionsId = new Set();
+      const departmentidSelsource = new Set();
+      if (cascader.length) {
+        for (const [s, d] of cascader) {
+          stitutionsId.add(s);
+          departmentidSelsource.add(d);
+        }
+      }
+      params.stitutionsId = [...stitutionsId].join(',');
+      params.departmentidSelsource = [...departmentidSelsource].join(',');
+      // 构造 医共体 / 机构 / 科室 树
+      params.groupInfo = [{
+        pid: params.ygtid,
+        name: this.doctorBodyList.find(item => item.pid === params.ygtid).name,
+        children: [],
+      }];
+      if (stitutionsId.size) {
+        const group = params.groupInfo[0].children;
+        for (const s of stitutionsId) {
+          const item1 = this.cascaderList.find(item => item.value === s);
+          if (!item1) continue;
+          const length = group.push({pid: item1.value, name: item1.label, children: []});
+          if (item1.leaf || !Array.isArray(item1.children) || !item1.children.length) continue;
+          for (const d of departmentidSelsource) {
+            const item2 = item1.children.find(item => item.value === d);
+            if (!item2) continue;
+            group[length - 1].children.push({pid: item2.value, name: item2.label, children: []});
+            departmentidSelsource.delete(d);
+          }
+        }
+      }
+      params.groupInfo = JSON.stringify(params.groupInfo);
+      const res = await (params.pid ? updateDrugDesc(params) : addDrugList(params));
+      if (res.ResultCode == 0) {
+        this.$message.success(params.pid ? '操作成功' : '添加成功');
+        this.showEditDialog = false;
+        await this.getDrugList();
+      }
     },
     add(scope) {
       this.$router.push({
         path: "/index/drugmaplist?id=" + scope.row.pid
       });
     },
-    submit() {
-      if (!this.pid) {
-        this._addDrugList();
-        return;
-      }
-      this.updateDrugDesc();
-    },
     sizeC(e) {
       this.page = e;
       this.getDrugList();
@@ -309,11 +353,11 @@ export default {
     },
     // 清空搜索条件
     clearFilter() {
-      this.yigt = "";
-      this.doctorBody = "";
-      this.departName = "";
-      this.medName = "";
-      this.medSelectList = [];
+      this.searchData = {
+        ygtid: '',
+        cascader: [],
+      };
+      this.cascaderList = [];
       this.getDrugList();
     },
     doctorBodyC() {
@@ -326,98 +370,43 @@ export default {
       formData.append("file", e.target.files[0]);
       this.fileImport(formData);
     },
-    // 新增药品目录
-    async _addDrugList() {
-      let params = {
-        describe: this.desc,
-        name: this.name,
-        type: this.type,
-        ygtid: this.ygt,
-        departmentidSelsource: this.ks,
-        stitutionsId: this.yljg
-      };
-      let res = await addDrugList(params);
-      if (res.ResultCode == 0) {
-        this.$message.success("添加成功");
-        this.showDialog = false;
-        this.getDrugList();
-      }
-    },
     // 获取医共体选择器数据
-    async getDoctorBodySelect() {
-      let res = await getDoctorBodySelect();
-      if (res.ResultCode == 0) {
+    async getCascaderA() {
+      const res = await getDoctorBodySelect();
+      if (res && +res.ResultCode === 0) {
         this.doctorBodyList = res.Data;
       }
     },
-    // 获取医疗机构选择器
-    async getMedSelect(id, type = "change") {
-      let params = {
-        organizationId: id
-      };
-      let res = await getMedSelect(params);
-      if (res.ResultCode == 0) {
-        this.medSelectList = res.Data;
-        if (type == "change") {
-          this.medName = "";
-          this.departName = "";
-        }
-      }
-    },
-    // 获取科室选择器
-    async getDepartSelect(id, type = "change") {
-      let res = await getDepartSelect({
-        // institutionId: this.getuserinfo.sititutionid
-        institutionId: id
-      });
-      if (res.ResultCode == 0) {
-        this.departSelect = res.Data;
-        if (type == "change") {
-          this.departName = "";
-        }
-      }
-    },
-
-    // 获取医共体选择器数据
-    async getDoctorBodySelect1() {
-      let res = await getDoctorBodySelect();
-      if (res.ResultCode == 0) {
-        this.list1 = res.Data;
-      }
-    },
-    // 获取医疗机构选择器
-    async getMedSelect1(id, type = "change") {
-      let params = {
-        organizationId: id
-      };
-      let res = await getMedSelect(params);
-      if (res.ResultCode == 0) {
-        this.list2 = res.Data;
-        if (type == "change") {
-          this.yljg = "";
-          this.ks = "";
-        }
-      }
+    async getCascaderB(organizationId) {
+      const nodes = cache.has(organizationId) ? cache.get(organizationId) : await getMedSelect({organizationId}).then(res => res && +res.ResultCode === 0
+          ? res.Data.map(item => ({
+            children: [], leaf: false,
+            label: item.name, value: item.pid,
+          }))
+          : [],
+      ).catch(() => []);
+
+      cache.set(organizationId, nodes);
+      this.cascaderList = nodes;
+      return nodes;
     },
-    // 获取科室选择器
-    async getDepartSelect1(id, type = "change") {
-      let res = await getDepartSelect({
-        // institutionId: this.getuserinfo.sititutionid
-        institutionId: id
-      });
-      if (res.ResultCode == 0) {
-        this.list3 = res.Data;
-        if (type == "change") {
-          this.ks = "";
-        }
-      }
-    },
-    // 获取医共体选择器数据
-    async doctorBodySelect() {
-      let res = await doctorBodySelect();
-      if (res.ResultCode == 0) {
-        this.doctorBody = res.Data;
+    async getCascaderC(institutionId) {
+      const parent = this.cascaderList.find(item => item.value === institutionId);
+      if (parent && (parent.leaf || parent.children.length)) return parent.children || [];
+
+      const nodes = await getDepartSelect({institutionId}).then(res => res && +res.ResultCode === 0
+          ? res.Data.map(item => ({
+            leaf: true,
+            label: item.name, value: item.pid,
+          }))
+          : [],
+      ).catch(() => []);
+
+      if (parent) {
+        parent.children = nodes;
+        if (!nodes.length) parent.leaf = true;
       }
+      return nodes;
     },
     // 获取药品列表
     async getDrugList() {
@@ -427,9 +416,9 @@ export default {
         // jgmc: this.yigt
         // ygtid: this.yigt,
 
-        departmentidSelsource: this.departName,
-        ygtid: this.doctorBody,
-        stitutionsId: this.medName
+        ygtid: this.searchData.ygtid,
+        stitutionsId: this.searchData.cascader[0],
+        departmentidSelsource: this.searchData.cascader[1],
       };
       let res = await getDrugList(params);
       if (res.ResultCode == 0) {
@@ -452,28 +441,6 @@ export default {
       this.showImport = res.Data.indexOf("edit") != -1;
       this.showMapAuto = res.Data.indexOf("del") != -1;
     },
-
-    /// 修改药品目录描述
-    async updateDrugDesc() {
-      let res = await updateDrugDesc({
-        describe: this.desc,
-        name: this.name,
-        type: this.type,
-        ygtid: this.ygt,
-        pid: this.pid,
-        departmentidSelsource: this.ks,
-        stitutionsId: this.yljg
-      });
-      if (res.ResultCode == 0) {
-        this.$message({
-          type: "success",
-          message: "操作成功",
-          showClose: true
-        });
-        this.showDialog = false;
-        this.getDrugList();
-      }
-    },
     // 自动映射
     async autoMap(scope) {
       // console.log(scope, '一共提')
@@ -703,7 +670,7 @@ export default {
     }
 
     .name {
-      width: 100px;
+      width: 120px;
     }
 
     .input {

+ 274 - 97
src/views/business/DrugMapList.vue

@@ -6,30 +6,57 @@
         <img src="~@/assets/filters.png" alt />
       </div>
       <div class="screening-form flex-vertical-center-l flex-wrap">
+        <div class="screening-item flex-vertical-center-l">
+          <span>医共体名称:</span>
+          <div class="input">
+            <el-select size="mini" placeholder="请选择" :clearable="doctorBodyList.length > 1"
+                       v-model="searchData.orgId" @change="searchData.cascader = [];getCascaderB($event)">
+              <el-option v-for="(item) in doctorBodyList" :key="item.value"
+                         :label="item.label" :value="item.value"
+              />
+            </el-select>
+          </div>
+        </div>
+        <div class="screening-item flex-vertical-center-l">
+          <span v-if="cascaderProp.level === 2">医疗机构 / 科室名称:</span>
+          <span v-if="cascaderProp.level === 1">医疗机构:</span>
+          <div class="input">
+            <el-cascader v-if="searchData.orgId" style="width: 100%" size="mini" clearable collapse-tags
+                         :props="cascaderProp" :options="cascaderList" filterable :show-all-levels="false"
+                         v-model="searchData.cascader"
+            />
+            <div v-else class="el-select el-select--mini">
+              <div class="el-input el-input--mini el-input--suffix">
+                <input class="el-input__inner" type="text" readonly="readonly" autocomplete="off" placeholder="请选择">
+              </div>
+            </div>
+          </div>
+        </div>
+
         <div class="screening-item flex-vertical-center-l">
           <span>映射状态:</span>
           <div class="input">
-            <el-select size="mini" placeholder="请选择" v-model="isMap">
+            <el-select size="mini" placeholder="请选择" v-model="searchData.isMapping" clearable>
               <el-option :value="0" label="未映射"></el-option>
               <el-option :value="1" label="已映射"></el-option>
             </el-select>
           </div>
         </div>
         <div class="screening-item flex-vertical-center-l">
-          <span>平台药品名称:</span>
+          <span>机构药品:</span>
           <div class="input">
-            <el-input size="mini" placeholder="请输入药品名称" v-model="yigt"></el-input>
+            <el-input size="mini" placeholder="请输入药品名称" v-model="searchData.matName" @keydown.enter.native="search()"></el-input>
           </div>
         </div>
 
         <el-button type="primary" size="mini" @click="search()">搜索</el-button>
-        <el-button type="warning" size="mini" @click="clearFilter()">清空</el-button>
-        <el-button
-          type="primary"
-          size="mini"
-          @click="$router.push({path:'/index/drugmap?pid='+$route.query.id+'&isMapping='+isMap})"
-        >新增</el-button>
-        <el-button type="warning" size="mini" @click="$router.back()">返回</el-button>
+        <el-button size="mini" @click="clearFilter()">清空</el-button>
+        <el-button size="mini" @click="$router.back()">返回</el-button>
+        <template v-if="editing">
+          <el-button type="warning" size="mini" @click="saveEdit()">保存</el-button>
+          <el-button size="mini" @click="stopEdit()">取消</el-button>
+        </template>
+        <el-button v-else type="success" size="mini" @click="startEdit()">编辑</el-button>
       </div>
     </div>
 
@@ -37,62 +64,56 @@
     <div class="table">
       <div class="today-table">
         <div class="table-container">
-          <el-table :data="tableData" stripe style="width: 100%" border height="100%">
-            <el-table-column prop="id" label="序号" width="100"></el-table-column>
-            <el-table-column label="平台药品">
-              <el-table-column prop="name" label="药品名称"></el-table-column>
-              <el-table-column prop="dw" label="单位"></el-table-column>
-              <!-- <el-table-column prop="drugRemark" label="药品描述">
-              </el-table-column>-->
+          <el-table :data="tableData" v-loading="loading" stripe style="width: 100%" border height="100%"
+                    @select="selectEditRow($event)" @select-all="selectEditRow">
+            <!--<el-table-column prop="id" label="序号" width="100"></el-table-column>-->
+            <el-table-column type="selection" width="55"></el-table-column>
+            <el-table-column label="医共体" prop="orgDrugs.appName" width="200" align="center"></el-table-column>
+            <el-table-column label="医疗机构" prop="orgDrugs.jgmc" align="center"></el-table-column>
+            <el-table-column label="机构药品">
+              <el-table-column label="名称" prop="orgDrugs.name" align="center"></el-table-column>
+              <el-table-column label="规格" prop="orgDrugs.gg" width="200" align="center"></el-table-column>
+              <el-table-column label="单位" prop="orgDrugs.dw" width="200" align="center"></el-table-column>
             </el-table-column>
-            <el-table-column label="第三方药品">
-              <el-table-column prop="name" label="药品名称">
-                <template slot-scope="scope">
-                  <div class="hisName">
-                    <span
-                      v-for="(item,index) in scope.row.orgDrugs"
-                      :key="index"
-                    >{{item.name}}{{index==scope.row.orgDrugs.length-1?'':'/'}}</span>
-                  </div>
-                </template>
-              </el-table-column>
-              <el-table-column prop="type" label="规格">
+            <el-table-column label="映射状态" width="200" align="center">
+              <template slot-scope="scope">
+                <el-tag v-if="scope.row.orgDrugs.isMapping === 1" type="success" size="mini">已映射</el-tag>
+                <el-tag v-else type="danger" size="mini">未映射</el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="系统药品">
+              <el-table-column label="名称" align="center">
                 <template slot-scope="scope">
-                  <div>
-                    <span
-                      v-for="(item,index) in scope.row.orgDrugs"
-                      :key="index"
-                    >{{item.gg}}{{index==scope.row.orgDrugs.length-1?'':'/'}}</span>
-                  </div>
+                  <el-select v-if="editing" size="mini" clearable
+                             :loading="editData[scope.$index].loading" :placeholder="editData[scope.$index].placeholder"
+                             filterable remote :remote-method="matSearchRemoteMethod"
+                             v-model="editData[scope.$index].matDrugId" @change="updateEditRow(scope.$index, $event)"
+                             @focus="focusEditRow(scope.$index)"
+                  >
+                    <el-option v-for="option in editData[scope.$index].options" :key="option.value"
+                               :label="option.label" :value="option.value"
+                    />
+                  </el-select>
+                  <div v-else>{{ scope.row.name }}</div>
                 </template>
               </el-table-column>
-              <el-table-column prop="drugRemark" label="单位">
+              <el-table-column label="单位" width="200" align="center">
                 <template slot-scope="scope">
-                  <div>
-                    <span
-                      v-for="(item,index) in scope.row.orgDrugs"
-                      :key="index"
-                    >{{item.dw}}{{index==scope.row.orgDrugs.length-1?'':'/'}}</span>
-                  </div>
+                  <el-input v-if="editing" size="mini" v-model="editData[scope.$index].matDrugDw"></el-input>
+                  <div v-else>{{ scope.row.dw }}</div>
                 </template>
               </el-table-column>
             </el-table-column>
-            <el-table-column label="操作">
-              <template slot-scope="scope">
-                <div class="flex-center operation">
-                  <div
-                    class="flex-center"
-                    @click="$router.push({path:'/index/drugmap?id='+scope.row
-                                    .matDrugId+'&pid='+$route.query.id+'&isMapping='+isMap})"
-                  >编辑</div>
-                  <!-- <div class="flex-center bg-yellow">删除
-                  </div>-->
-                </div>
-              </template>
-            </el-table-column>
           </el-table>
         </div>
         <div class="flex-vertical-center-r today-page">
+          <div>
+            <template v-if="!loading">
+              <span>机构药品:共<el-tag type="info" size="mini" style="margin: 0 4px;">{{ statistics.total }}</el-tag>味,</span>
+              <span>已映射<el-tag type="success" size="mini" style="margin: 0 4px;">{{ statistics.isMapping }}</el-tag>味,</span>
+              <span>未映射<el-tag type="danger" size="mini" style="margin: 0 4px;">{{ statistics.noMapping }}</el-tag>味</span>
+            </template>
+          </div>
           <el-pagination
             background
             layout=" prev, pager, next, jumper, total"
@@ -106,39 +127,107 @@
   </div>
 </template>
 <script>
-import popup from "@/components/Propup.vue";
-import { getDrugMapList, getDrugBM } from "@/api/business.js";
-import { doctorBodySelect } from "@/api/city.js";
-import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
+import popup from '@/components/Propup.vue';
+import {addOrUpdateDrug, getDrugMap, getDrugMapList, searchMyDrug} from '@/api/business.js';
+import {getMedSelect} from '@/api/system';
+import {mapGetters} from 'vuex';
+
+const TAG = -1;
+let cache = new Map();
+let skipWatch = false;
 export default {
   components: {
     popup
   },
   data() {
     return {
-      doctorBody: [], // 医共体选择器数据
-      yigt: "", // 医工体
+      searchData: {
+        pid: '',
+        orgId: '',
+        cascader: [],
+      },
+      doctorBodyList: [], // 医共体选择器数据
+      cascaderList: [],
+      cascaderProp: {
+        level: 1,
+        multiple: true,
+        checkStrictly: true,
+      },
+      loading: false,
       tableData: [],
+      statistics: {},
       page: 1,
       limit: 10,
       total: 0,
-      isMap: 1
+
+      editing: false,
+      editIndex: -1,
+      editData: [],
+      selected: [],
     };
   },
-  created() {
-    this.getDrugMapList();
+  watch: {
+    'searchData.cascader'(value = [], oldValue = []) {
+      if (skipWatch) skipWatch = false;
+      else {
+        skipWatch = true;
+        const vHas = value.some(item => item[0] === TAG);
+        const oHas = oldValue.some(item => item[0] === TAG);
+        if (vHas === oHas) {
+          const _value = value.filter(item => item[0] !== TAG);
+          if (_value.length === this.cascaderList.length - 1) {
+            this.searchData.cascader = [[TAG], ...value];
+          } else {
+            this.searchData.cascader = _value;
+          }
+        } else if (vHas) {
+          this.searchData.cascader = this.cascaderList.map(item => [item.value]);
+        } else {
+          this.searchData.cascader = [];
+        }
+      }
+    },
   },
   beforeRouteEnter(to, from, next) {
-    // 在渲染该组件的对应路由被 confirm 前调用
-    // 不!能!获取组件实例 `this`
-    // 因为当守卫执行前,组件实例还没被创建
-    // 可以通过传一个回调给 next 来访问组件实例
-    next(vm => {
-      // 通过 `vm` 访问组件实例
-      vm.getDrugMapList();
-    });
+    next(vm => vm.load());
   },
+  created() { this.load(); },
+  destroyed() { cache.clear(); },
   methods: {
+    async load() {
+      this.searchData.pid = this.$route.query.pid;
+      const loading = this.$loading({lock: true, text: '加载中...', spinner: 'el-icon-loading'});
+      try {
+        const {groupInfo} = await getDrugMap(this.searchData.pid);
+        for (const {value, children} of groupInfo) cache.set(value, children);
+        this.doctorBodyList = groupInfo;
+        await this.clearFilter();
+      } catch (e) {
+        this.$message.error(e.message);
+        this.$router.back();
+      }
+      loading.close();
+    },
+    async getCascaderB(id) {
+      let list = cache.get(id);
+      if (!Array.isArray(list) || !list.length) {
+        list = await getMedSelect({organizationId: id}).then(res => res && +res.ResultCode === 0
+            ? res.Data.map(item => ({
+              children: [], leaf: false,
+              label: item.name, value: item.pid,
+            }))
+            : [],
+        ).catch(() => []);
+        cache.set(id, list);
+      }
+
+      if (this.cascaderProp.level === 1) {
+        this.cascaderList = list.map(({children, ...item}) => Object.assign(item, {leaf: true}));
+        this.cascaderList.unshift({value: TAG, label: '全选'});
+      } else if (this.cascaderProp.level === 2) {
+        this.cascaderList = list;
+      }
+    },
     sizeC(e) {
       this.page = e;
       this.getDrugMapList();
@@ -148,35 +237,119 @@ export default {
       this.getDrugMapList();
     },
     // 清空搜索条件
-    clearFilter() {
-      this.yigt = "";
-      this.getDrugMapList();
-    },
-    doctorBodyC() {
-      // this.page = 1
-      // this.getDrugList()
+    async clearFilter() {
+      this.searchData = {pid: this.$route.query.pid, orgId: '', cascader: []};
+      if (this.doctorBodyList.length === 1) {
+        this.searchData.orgId = this.doctorBodyList[0].value;
+        await this.getCascaderB(this.searchData.orgId);
+      }
+      this.getDrugMapList().then();
     },
-
     // 获取药品列表
     async getDrugMapList() {
-      let params = {
-        page: this.page,
-        limit: this.limit,
-        isMapping: this.isMap,
-        // orgId: this.getuserinfo.organizationid,
-        matName: this.yigt,
-        orgId: this.$route.query.id
-      };
-      let res = await getDrugMapList(params);
-      if (res.ResultCode == 0) {
-        this.tableData = res.Data.Items;
-        this.total = res.Data.TotalRecordCount;
-        this.tableData.filter((item, index) => {
-          item.id = index + 1;
-          item.type = "his";
-          return item;
-        });
+      this.stopEdit();
+      this.selected = [];
+      this.loading = true;
+      try {
+        const {cascader, ...searchData} = this.searchData;
+        let params = {page: this.page, limit: this.limit, ...searchData};
+        const stitutionsId = cascader.length ? cascader : this.cascaderList.map(item => [item.value]);
+        params.stitutionsIds = stitutionsId.map(item => item[0]).filter(item => item !== TAG).join(',');
+        let res = await getDrugMapList(params);
+        if (res.ResultCode == 0) {
+          this.tableData = res.Data.Items.map(item => Object.assign(item, {id: `${item.orgDrugs.appId}.${item.orgDrugs.jgdm}.${item.orgDrugs.drugId}`}));
+          this.total = res.Data.TotalRecordCount;
+          this.statistics = res.Data.count;
+        } else throw {message: res.ResultInfo};
+      } catch (e) {
+        this.$message.error(e.message);
+      }
+      this.loading = false;
+    },
+    startEdit() {
+      this.editing = true;
+      this.editData = this.tableData.map(item => {
+        return {
+          id: item.id,
+          orgId: item.orgDrugs.appId,
+          jgDrugId: item.orgDrugs.drugId,
+          jgDrugName: item.orgDrugs.name,
+          matDrugId: item.matDrugId,
+          matDrugName: item.name,
+          matDrugDw: item.dw,
+
+          loading: false,
+          placeholder: item.name || '请输入药品名称搜索',
+          options: item.matDrugId ? [{value: item.matDrugId, label: item.name, dw: item.dw}] : [],
+        };
+      });
+    },
+    stopEdit() {
+      this.editing = false;
+      this.editData = [];
+    },
+    async saveEdit() {
+      try {
+        const data = [];
+        for (const {orgId, jgDrugId, matDrugId, matDrugName, matDrugDw} of this.editData) {
+          if (matDrugId && !matDrugDw) throw `请补充完整系统药品单位`;
+          data.push({orgId, jgDrugId, matDrugId, matDrugName, matDrugDw, isMapping: matDrugId ? 1 : 0});
+        }
+        await addOrUpdateDrug(data).then(res => { if (res.ResultCode !== 0) throw {message: res.ResultInfo};});
+        this.getDrugMapList().then();
+      } catch (e) {
+        if (typeof e === 'string') this.$message.warning(e);
+        else this.$message.error(e.message);
+      }
+    },
+    selectEditRow(selection, row) {
+      this.selected = selection.map(item => item.id);
+      if (this.editing && selection.length > 1) this.syncEditRow(row);
+    },
+    focusEditRow(index, name = '') {
+      this.editIndex = index;
+      const item = this.editData[index];
+      if (!item.loading && !item.options.length) {
+        if (!name) {try {name = (item.matDrugName || item.jgDrugName).match(/[\u4E00-\u9FFF]+/g)[0];} catch (e) {name = '';}}
+        this.matSearchRemoteMethod(name, index).then(options => { if (!options.length) this.matSearchRemoteMethod(' ', index); });
+      }
+    },
+    syncEditRow(row) {
+      const selection = this.selected.map(id => this.editData.find(item => item.id === id));
+      if (row == null) row = selection.find(item => item.matDrugId);
+      if (row == null) return;
+      for (const item of selection) {
+        item.matDrugId = row.matDrugId;
+        item.matDrugName = row.matDrugName;
+        item.matDrugDw = row.matDrugDw;
+        item.options = row.options.map(item => Object.assign({}, item));
       }
+    },
+    updateEditRow(index, value) {
+      const item = this.editData[index];
+      if (value) {
+        const option = item.options.find(item => item.value === value);
+        item.matDrugName = option.label;
+        item.matDrugDw = option.dw;
+      } else {
+        item.matDrugName = '';
+        item.matDrugDw = '';
+      }
+      if (this.selected.includes(item.id)) this.syncEditRow(item);
+    },
+    async matSearchRemoteMethod(name, index) {
+      if (index == null) index = this.editIndex;
+      const item = this.editData[index];
+      if (!name) item.options = item.matDrugId ? [{value: item.matDrugId, label: item.name}] : [];
+      else {
+        item.loading = true;
+        item.options = await searchMyDrug({name: name.trim()}).then(res => {
+          if (res.ResultCode === 0)
+            return res.Data.map(item => ({value: item.drugId, label: item.name, dw: item.dw}));
+        }).catch(() => []);
+        item.loading = false;
+      }
+      return item.options;
     }
   },
 
@@ -196,6 +369,10 @@ export default {
   margin-top: 10px;
   height: 72vh;
 
+  .flex-vertical-center-r {
+    justify-content: space-between;
+  }
+
   .table-btns {
     margin-bottom: 13px;