NonDrugMapList.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. <template>
  2. <div class="druglist">
  3. <!-- 顶部筛选 -->
  4. <div class="screening">
  5. <div class="screening-title flex-vertical-center-l">
  6. <img src="~@/assets/filters.png" alt />
  7. </div>
  8. <div class="screening-form flex-vertical-center-l flex-wrap">
  9. <div class="screening-item flex-vertical-center-l">
  10. <span>映射状态:</span>
  11. <div class="input">
  12. <el-select
  13. size="mini"
  14. placeholder="全部"
  15. v-model="searchData.isMapping"
  16. clearable
  17. >
  18. <el-option :value="0" label="未映射"></el-option>
  19. <el-option :value="1" label="已映射"></el-option>
  20. </el-select>
  21. </div>
  22. </div>
  23. <div class="screening-item flex-vertical-center-l">
  24. <span>平台非药物疗法:</span>
  25. <div class="input">
  26. <el-input
  27. size="mini"
  28. placeholder="请输入二级分类名称"
  29. v-model="searchData.secondName"
  30. @keydown.enter.native="search()"
  31. clearable
  32. ></el-input>
  33. </div>
  34. </div>
  35. <el-button type="primary" size="mini" @click="search()">搜索</el-button>
  36. <el-button type="warning" size="mini" @click="clearFilter()"
  37. >清空</el-button
  38. >
  39. <div style="width: 60px;"></div>
  40. <el-button type="warning" size="mini" @click="$router.back()"
  41. >返回</el-button
  42. >
  43. <el-button type="primary" size="mini" @click="autoMap"
  44. >自动映射</el-button
  45. >
  46. <el-button type="danger" size="mini" @click="clearMap"
  47. >清空映射</el-button
  48. >
  49. </div>
  50. </div>
  51. <!-- 底部表格数据 -->
  52. <div class="table">
  53. <div class="today-table">
  54. <div class="table-container">
  55. <el-table
  56. :data="tableData"
  57. v-loading="loading"
  58. stripe
  59. style="width: 100%"
  60. border
  61. height="100%"
  62. :header-cell-style="headerCellStyle"
  63. >
  64. <el-table-column
  65. type="index"
  66. label="序号"
  67. width="60"
  68. align="center"
  69. :index="indexMethod"
  70. ></el-table-column>
  71. <el-table-column label="平台非药物疗法">
  72. <el-table-column
  73. label="一级分类"
  74. prop="firstLevel"
  75. align="center"
  76. >
  77. <template slot-scope="scope">
  78. <span
  79. :style="{
  80. color: String(scope.row.isMapping) !== '1' ? 'red' : '',
  81. }"
  82. >{{ scope.row.firstLevel || "-" }}</span
  83. >
  84. </template>
  85. </el-table-column>
  86. <el-table-column
  87. label="二级分类"
  88. prop="secondLevel"
  89. align="center"
  90. >
  91. <template slot-scope="scope">
  92. <span
  93. :style="{
  94. color: String(scope.row.isMapping) !== '1' ? 'red' : '',
  95. }"
  96. >{{ scope.row.secondLevel || "-" }}</span
  97. >
  98. </template>
  99. </el-table-column>
  100. </el-table-column>
  101. <el-table-column label="第三方非药物疗法">
  102. <el-table-column label="项目名称" align="center">
  103. <template slot-scope="scope">
  104. <el-select
  105. v-if="activeEditIndex === scope.$index"
  106. size="mini"
  107. :loading="editData[scope.$index].loading"
  108. :placeholder="editData[scope.$index].placeholder"
  109. filterable
  110. remote
  111. :remote-method="matSearchRemoteMethod"
  112. v-model="editData[scope.$index].matDrugId"
  113. @change="onSelectChange(scope.$index, $event)"
  114. @focus="focusEditRow(scope.$index)"
  115. @visible-change="onVisibleChange(scope.$index, $event)"
  116. >
  117. <el-option
  118. v-for="option in editData[scope.$index].options"
  119. :key="option.value"
  120. :label="option.label"
  121. :value="option.value"
  122. />
  123. </el-select>
  124. <div
  125. v-else
  126. class="clickable-name"
  127. @click="activateEdit(scope.$index)"
  128. >
  129. {{
  130. editData[scope.$index]
  131. ? editData[scope.$index].displayName || "-"
  132. : "-"
  133. }}
  134. </div>
  135. </template>
  136. </el-table-column>
  137. <el-table-column label="编码" width="150" align="center">
  138. <template slot-scope="scope">
  139. <div>{{ scope.row.itemCode || "-" }}</div>
  140. </template>
  141. </el-table-column>
  142. <el-table-column label="计价单位" width="100" align="center">
  143. <template slot-scope="scope">
  144. <div>{{ scope.row.pricingUnit || "-" }}</div>
  145. </template>
  146. </el-table-column>
  147. <el-table-column label="价格" width="100" align="center">
  148. <template slot-scope="scope">
  149. <div>{{ scope.row.price || "-" }}</div>
  150. </template>
  151. </el-table-column>
  152. </el-table-column>
  153. </el-table>
  154. </div>
  155. <div class="flex-vertical-center-r today-page">
  156. <div></div>
  157. <el-pagination
  158. background
  159. layout=" prev, pager, next, jumper, total"
  160. :total="total"
  161. :page-size="limit"
  162. @current-change="sizeC($event)"
  163. ></el-pagination>
  164. </div>
  165. </div>
  166. </div>
  167. </div>
  168. </template>
  169. <script>
  170. import popup from "@/components/Propup.vue";
  171. import {
  172. getNondrugMapList,
  173. autoMapNondrug,
  174. clearMapNondrug,
  175. materialQuery,
  176. manualMapping,
  177. } from "@/api/nonDrug.js";
  178. import { mapGetters } from "vuex";
  179. export default {
  180. components: {
  181. popup,
  182. },
  183. data() {
  184. return {
  185. searchData: {
  186. pid: "",
  187. appId: "",
  188. deptId: "",
  189. institutionCode: "",
  190. isMapping: "",
  191. secondName: "",
  192. },
  193. loading: false,
  194. tableData: [],
  195. page: 1,
  196. limit: 10,
  197. total: 0,
  198. editIndex: -1,
  199. activeEditIndex: -1,
  200. editData: [],
  201. editOriginalMatDrugId: "",
  202. changeHandled: false,
  203. };
  204. },
  205. activated() {
  206. this.load();
  207. },
  208. methods: {
  209. async load() {
  210. this.activeEditIndex = -1;
  211. this.searchData = {
  212. pid: this.$route.query.pid || "",
  213. appId: this.$route.query.ygtid || "",
  214. deptId: this.$route.query.departmentidSelsource || "",
  215. institutionCode: this.$route.query.stitutionsId || "",
  216. isMapping: "",
  217. secondName: "",
  218. };
  219. this.page = 1;
  220. await this.getList();
  221. },
  222. sizeC(e) {
  223. this.page = e;
  224. this.getList();
  225. },
  226. search() {
  227. this.page = 1;
  228. this.getList();
  229. },
  230. async clearFilter() {
  231. this.searchData = {
  232. pid: this.$route.query.pid || "",
  233. appId: this.$route.query.ygtid || "",
  234. deptId: this.$route.query.departmentidSelsource || "",
  235. institutionCode: this.$route.query.stitutionsId || "",
  236. isMapping: "",
  237. secondName: "",
  238. };
  239. this.page = 1;
  240. this.getList();
  241. },
  242. async getList() {
  243. this.loading = true;
  244. try {
  245. const {
  246. appId,
  247. deptId,
  248. institutionCode,
  249. isMapping,
  250. secondName,
  251. } = this.searchData;
  252. let params = {
  253. appId,
  254. deptId,
  255. institutionCode,
  256. isMapping,
  257. secondName,
  258. pageNum: this.page,
  259. pageSize: this.limit,
  260. };
  261. let res = await getNondrugMapList(params);
  262. if (res.ResultCode == 0) {
  263. const data = res.Data || {};
  264. this.tableData = data.Items || [];
  265. this.total = data.TotalRecordCount || 0;
  266. } else throw { message: res.ResultInfo };
  267. this.initEditData();
  268. } catch (e) {
  269. this.$message.error(e.message);
  270. }
  271. this.loading = false;
  272. },
  273. initEditData() {
  274. this.editData = this.tableData.map((item) => {
  275. const isMapped = String(item.isMapping) === "1";
  276. const displayName = isMapped ? item.itemName || "-" : "-";
  277. return {
  278. id: item.id,
  279. matDrugId: isMapped ? item.id : "",
  280. matDrugName: item.itemName || "",
  281. matDrugDw: item.pricingUnit || "",
  282. displayName,
  283. loading: false,
  284. placeholder: displayName !== "-" ? displayName : "请输入项目名称搜索",
  285. options: isMapped
  286. ? [{ value: item.id, label: item.itemName, dw: item.pricingUnit }]
  287. : [],
  288. };
  289. });
  290. },
  291. focusEditRow(index) {
  292. this.editIndex = index;
  293. const item = this.editData[index];
  294. let name = "";
  295. if (item.matDrugName) {
  296. try {
  297. name = item.matDrugName.match(/[\u4E00-\u9FFF]+/g)[0];
  298. } catch (e) {
  299. name = "";
  300. }
  301. }
  302. this.matSearchRemoteMethod(name || " ", index);
  303. },
  304. activateEdit(index) {
  305. this.activeEditIndex = index;
  306. this.editOriginalMatDrugId = this.editData[index].matDrugId;
  307. this.changeHandled = false;
  308. },
  309. async onSelectChange(index, value) {
  310. this.changeHandled = true;
  311. this.updateEditRow(index, value);
  312. await this.doManualMapping(index);
  313. this.activeEditIndex = -1;
  314. },
  315. onVisibleChange(index, visible) {
  316. if (visible) return;
  317. if (this.changeHandled) return;
  318. if (this.editData[index].matDrugId !== this.editOriginalMatDrugId) {
  319. this.doManualMapping(index);
  320. }
  321. this.activeEditIndex = -1;
  322. },
  323. async doManualMapping(index) {
  324. try {
  325. const row = this.tableData[index];
  326. const item = this.editData[index];
  327. let params = {
  328. deptId: this.searchData.deptId,
  329. firstName: row.firstLevel || "",
  330. organizationid: this.searchData.appId,
  331. platformClassifyId: row.id || "",
  332. secondName: row.secondLevel || "",
  333. sititutionNondrugId: item.matDrugId || "",
  334. sititutionid: this.searchData.institutionCode,
  335. };
  336. const loading = this.$loading({
  337. lock: true,
  338. text: "正在映射",
  339. spinner: "el-icon-loading",
  340. background: "rgba(0, 0, 0, 0.7)",
  341. });
  342. const res = await manualMapping(params).catch((err) => {
  343. loading.close();
  344. });
  345. if (res.ResultCode == 0) {
  346. loading.close();
  347. this.$message.success("映射保存成功");
  348. await this.getList();
  349. }
  350. } catch (e) {
  351. this.$message.error(e.message);
  352. }
  353. },
  354. updateEditRow(index, value) {
  355. const item = this.editData[index];
  356. if (value) {
  357. const option = item.options.find((o) => o.value === value);
  358. item.displayName = option.label;
  359. item.matDrugName = option.label;
  360. item.matDrugDw = option.dw || "";
  361. } else {
  362. item.displayName = "-";
  363. item.matDrugName = "";
  364. item.matDrugDw = "";
  365. }
  366. },
  367. async matSearchRemoteMethod(name, index) {
  368. if (index == null) index = this.editIndex;
  369. const item = this.editData[index];
  370. if (!name) {
  371. item.options = item.matDrugId
  372. ? [{ value: item.matDrugId, label: item.matDrugName }]
  373. : [];
  374. } else {
  375. item.loading = true;
  376. item.options = await materialQuery({
  377. name: name.trim(),
  378. appId: this.searchData.appId,
  379. deptId: this.searchData.deptId,
  380. institutionCode: this.searchData.institutionCode,
  381. })
  382. .then((res) => {
  383. if (res.ResultCode === 0)
  384. return (res.Data || []).map((d) => ({
  385. value: d.pid,
  386. label: d.itemName || d.name,
  387. dw: d.pricingUnit || d.dw,
  388. }));
  389. return [];
  390. })
  391. .catch(() => []);
  392. item.loading = false;
  393. }
  394. return item.options;
  395. },
  396. // 自动映射
  397. autoMap() {
  398. this.$confirm("确认自动映射所有未映射的非药物疗法?", "提示", {
  399. confirmButtonText: "确定",
  400. cancelButtonText: "取消",
  401. type: "warning",
  402. })
  403. .then(async () => {
  404. try {
  405. const res = await autoMapNondrug({
  406. basisNondrugcatalogueId: this.searchData.pid,
  407. });
  408. if (res.ResultCode == 0) {
  409. this.$message.success("自动映射成功");
  410. this.getList();
  411. }
  412. } catch (e) {
  413. this.$message.error(e.message);
  414. }
  415. })
  416. .catch(() => {});
  417. },
  418. // 清空映射
  419. clearMap() {
  420. this.$confirm("确认清空本列表的全部映射关系吗?", "提示", {
  421. confirmButtonText: "确认",
  422. cancelButtonText: "取消",
  423. type: "warning",
  424. })
  425. .then(async () => {
  426. try {
  427. const res = await clearMapNondrug({
  428. basisNondrugcatalogueId: this.searchData.pid,
  429. });
  430. if (res.ResultCode == 0) {
  431. this.$message.success("清空映射成功");
  432. this.getList();
  433. }
  434. } catch (e) {
  435. this.$message.error(e.message);
  436. }
  437. })
  438. .catch(() => {});
  439. },
  440. indexMethod(index) {
  441. return (this.page - 1) * this.limit + index + 1;
  442. },
  443. headerCellStyle({ rowIndex, columnIndex }) {
  444. if (rowIndex === 0) {
  445. // 序号列
  446. if (columnIndex === 0) return { backgroundColor: "#f3fffb" };
  447. // 平台非药物疗法
  448. if (columnIndex === 1) return { backgroundColor: "#efe1c7" };
  449. // 第三方非药物疗法
  450. if (columnIndex === 2) return { backgroundColor: "#c7efef" };
  451. }
  452. if (rowIndex === 1) return { backgroundColor: "#c7efef" };
  453. return {};
  454. },
  455. },
  456. computed: {
  457. ...mapGetters(["getuserinfo"]),
  458. },
  459. };
  460. </script>
  461. <style lang="scss" scoped>
  462. @import "../../style/common.scss";
  463. @import "../../style/base.scss";
  464. .table {
  465. padding: 5px 5px;
  466. background: #ffffff;
  467. border-radius: 5px;
  468. margin-top: 10px;
  469. height: 72vh;
  470. .flex-vertical-center-r {
  471. justify-content: space-between;
  472. }
  473. .table-container {
  474. height: 90%;
  475. }
  476. .today-table {
  477. height: 100%;
  478. }
  479. }
  480. .clickable-name {
  481. cursor: pointer;
  482. min-height: 28px;
  483. line-height: 28px;
  484. }
  485. .today-table::v-deep .el-table .cell {
  486. text-align: center;
  487. }
  488. </style>
  489. <style lang="scss" scoped>
  490. @media screen and (min-width: 1681px) and (max-width: 1920px) {
  491. .table {
  492. height: 82vh;
  493. .table-container {
  494. height: 94%;
  495. }
  496. }
  497. .today-table::v-deep .el-table td {
  498. padding: 18px 0;
  499. }
  500. .today-table::v-deep .el-table th {
  501. padding: 18px 0;
  502. }
  503. }
  504. @media screen and (min-width: 1601px) and (max-width: 1680px) {
  505. .table {
  506. height: 81vh;
  507. .table-container {
  508. height: 94%;
  509. }
  510. }
  511. .today-table::v-deep .el-table td {
  512. padding: 18px 0;
  513. }
  514. .today-table::v-deep .el-table th {
  515. padding: 18px 0;
  516. }
  517. }
  518. @media screen and (min-width: 1361px) and (max-width: 1600px) {
  519. .table {
  520. height: 73vh;
  521. .table-container {
  522. height: 90%;
  523. }
  524. }
  525. .today-table::v-deep .el-table td {
  526. padding: 5px 0;
  527. }
  528. .today-table::v-deep .el-table th {
  529. padding: 5px 0;
  530. }
  531. }
  532. @media screen and(min-width:1281px) and (max-width: 1360px) {
  533. .table {
  534. height: 74vh;
  535. .table-container {
  536. height: 90%;
  537. }
  538. }
  539. .today-table::v-deep .el-table td {
  540. padding: 5px 0;
  541. }
  542. .today-table::v-deep .el-table th {
  543. padding: 5px 0;
  544. }
  545. }
  546. </style>