AddTermSet.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. <style lang="less" scoped>
  2. // @import "../../less/admin.less";
  3. #AddRuleContent {
  4. width: 100%;
  5. min-width: 1000px;
  6. padding: 20px;
  7. padding-top: 50px;
  8. padding-bottom: 0;
  9. box-sizing: border-box;
  10. .form {
  11. width: 100%;
  12. }
  13. .remark {
  14. font-size: 14px;
  15. color: #606266;
  16. position: relative;
  17. left: 34px;
  18. top: -10px;
  19. padding-right: 30px;
  20. }
  21. .left_header {
  22. height: 40px;
  23. display: flex;
  24. justify-content: space-between;
  25. .tips {
  26. margin-top: 15px;
  27. }
  28. .inp {
  29. width: 150px;
  30. /deep/.el-input__inner {
  31. height: 30px;
  32. margin-top: 10px;
  33. }
  34. }
  35. }
  36. .right_header {
  37. display: flex;
  38. }
  39. .table_form {
  40. width: 100%;
  41. box-sizing: border-box;
  42. background: #fff;
  43. padding: 20px;
  44. padding-bottom: 0;
  45. display: flex;
  46. flex-wrap: wrap;
  47. }
  48. .table_content {
  49. margin-top: 10px;
  50. overflow: hidden;
  51. .table_left {
  52. width: 45%;
  53. float: left;
  54. margin-right: 10px;
  55. background: #ffffff;
  56. padding: 0 2%;
  57. .left_box {
  58. margin: 30px 0;
  59. overflow: hidden;
  60. min-height: calc(100vh - 410px)
  61. }
  62. .tabs {
  63. max-width: 100%;
  64. min-width: 100%;
  65. }
  66. .form_btn {
  67. display: flex;
  68. justify-content: flex-end;
  69. padding-bottom: 15px;
  70. }
  71. }
  72. .table_right {
  73. width: 45%;
  74. float: right;
  75. background: #ffffff;
  76. padding: 0 2%;
  77. .right_box {
  78. margin: 30px 0;
  79. overflow: hidden;
  80. min-height: calc(100vh - 410px)
  81. }
  82. .tabs {
  83. max-width: 100%;
  84. min-width: 100%;
  85. }
  86. .inp {
  87. width: 100px;
  88. /deep/.el-input__inner {
  89. height: 30px;
  90. margin-top: 10px;
  91. }
  92. }
  93. .inps {
  94. margin-right: 10px;
  95. }
  96. .form_btn {
  97. display: flex;
  98. justify-content: space-between;
  99. padding-bottom: 15px;
  100. }
  101. }
  102. }
  103. /deep/.el-select-dropdown__item.hover,
  104. .el-select-dropdown__item:hover {
  105. color: #48c5d7;
  106. }
  107. /deep/ .el-form--inline .el-form-item__label {
  108. font-size: 14px;
  109. color: #606266;
  110. }
  111. /deep/ .el-input--mini .el-input__inner,
  112. .el-select {
  113. width: 100%;
  114. font-size: 14px;
  115. }
  116. /deep/ .el-form-item.is-success .el-input__inner,
  117. .el-form-item.is-success .el-textarea__inner {
  118. border-color: #c9c9c9 !important;
  119. }
  120. /deep/ .el-form-item.is-success .el-textarea__inner {
  121. border-color: #c9c9c9 !important;
  122. }
  123. /deep/ .el-form-item.is-success .el-textarea__inner {
  124. border-color: #c9c9c9 !important;
  125. }
  126. /deep/ .el-table th.gutter {
  127. display: table-cell !important;
  128. }
  129. }
  130. .test_box {
  131. min-height: 300px;
  132. max-height: 300px;
  133. outline: 0;
  134. border: 1px solid #dcdfe6;
  135. font-size: 14px;
  136. line-height: 1.5;
  137. word-wrap: break-word;
  138. overflow-x: hidden;
  139. overflow-y: auto;
  140. border-radius: 4px;
  141. margin-top: 6px;
  142. padding: 10px 15px;
  143. }
  144. </style>
  145. <style scoped>
  146. </style>
  147. <template>
  148. <div>
  149. <crumbs :title="title" :param="$route.params" linkTo="TermSet"></crumbs>
  150. <div id="AddRuleContent">
  151. <div class="table_form">
  152. <el-form
  153. size="mini"
  154. :inline="true"
  155. class="demo-form-inline form"
  156. :model="form"
  157. :rules="rules"
  158. >
  159. <el-form-item label-width="130px" label="术语集合类型:" prop="collectionLibType">
  160. <el-select
  161. v-model="form.collectionLibType"
  162. placeholder="请选择"
  163. @change="getConceptLibType"
  164. :disabled="sign==2?true:false"
  165. :title="form.collectionLibName"
  166. >
  167. <el-option
  168. v-for="item in ruleTypeList"
  169. :key="item.val"
  170. :label="item.name"
  171. :value="item.val"
  172. ></el-option>
  173. </el-select>
  174. </el-form-item>
  175. <!-- 规则术语类型: -->
  176. <el-form-item label-width="130px" label="术语集合名称:" prop="collectionLibName">
  177. <el-select
  178. clearable
  179. remote
  180. filterable
  181. v-model.trim="form.collectionLibName"
  182. placeholder="请输入"
  183. :remote-method="searchLibName"
  184. @change="getCollectionLib"
  185. :disabled="sign==2?true:false"
  186. value-key="conceptId"
  187. :title="form.collectionLibName"
  188. >
  189. <el-option
  190. v-for="item in ruleTermTypeList"
  191. :key="item.conceptId"
  192. :label="item.conceptName"
  193. :value="item.conceptName"
  194. ></el-option>
  195. </el-select>
  196. </el-form-item>
  197. </el-form>
  198. <div class="remark">说明:{{form.collectionRemark}}</div>
  199. </div>
  200. <div class="table_content" v-if="onshow">
  201. <div class="table_left">
  202. <div class="left_header">
  203. <h5 class="tips">关联的术语({{form.concepts.length}})</h5>
  204. <div style="display:flex">
  205. <el-input v-model="searchtext" @input="searchList" placeholder="关键词" class="inp"></el-input>
  206. <span style="display:flex;align-items: center;margin:0 5px">-</span>
  207. <el-input v-model="searchtext2" @input="searchList" placeholder="关键词" class="inp"></el-input>
  208. </div>
  209. </div>
  210. <div class="left_box">
  211. <el-table
  212. :data="leftList"
  213. border
  214. style="min-height: 200px"
  215. height="calc(100vh - 393px)"
  216. class="tabs"
  217. :header-row-style="{height:'40px'}"
  218. :header-cell-style="{height:'40px',background:'#f7f7f7'}"
  219. >
  220. <el-table-column prop="conceptLibName" :show-overflow-tooltip="true" label="术语名称"></el-table-column>
  221. <el-table-column label="操作">
  222. <template slot-scope="scope">
  223. <el-button
  224. type="text"
  225. size="small"
  226. class="delete"
  227. @click="showDelDialog(scope.row)"
  228. >移除</el-button>
  229. </template>
  230. </el-table-column>
  231. </el-table>
  232. </div>
  233. <div class="form_btn">
  234. <el-button type="primary" size="medium " @click="saveSet">确定</el-button>
  235. </div>
  236. </div>
  237. <div class="table_right">
  238. <div class="right_header">
  239. <el-select
  240. v-model="formInline.logicalOperator"
  241. class="inp inps"
  242. @change="searchConcept"
  243. >
  244. <el-option label="and" value="0"></el-option>
  245. <el-option label="or" value="1"></el-option>
  246. </el-select>
  247. <el-input
  248. v-model="formInline.name1"
  249. @input="searchConcept"
  250. placeholder="关键词"
  251. class="inp"
  252. ></el-input>
  253. <span style="display:flex;align-items: center;margin:0 5px">-</span>
  254. <el-input
  255. v-model="formInline.name2"
  256. @input="searchConcept"
  257. placeholder="关键词"
  258. class="inp"
  259. ></el-input>
  260. <span style="display:flex;align-items: center;margin:0 5px">-</span>
  261. <el-input
  262. v-model="formInline.name3"
  263. @input="searchConcept"
  264. placeholder="关键词"
  265. class="inp"
  266. ></el-input>
  267. </div>
  268. <div class="right_box">
  269. <el-table
  270. :data="conceptList"
  271. border
  272. style="min-height: 200px"
  273. height="calc(100vh - 393px)"
  274. class="tabs"
  275. @row-click="btn"
  276. :header-row-style="{height:'40px'}"
  277. :header-cell-style="{height:'40px',background:'#f7f7f7'}"
  278. @selection-change="handleSelectionChange"
  279. >
  280. <el-table-column type="selection"></el-table-column>
  281. <el-table-column prop="conceptName" :show-overflow-tooltip="true" label="术语名称"></el-table-column>
  282. </el-table>
  283. </div>
  284. <div class="form_btn">
  285. <el-button size="medium " @click="add" icon="el-icon-caret-left">添加</el-button>
  286. <el-button size="medium " @click="dialogVisible = true">文本批量添加</el-button>
  287. </div>
  288. </div>
  289. </div>
  290. </div>
  291. <el-dialog
  292. :title="'请输入要添加到关联的标准术语(每行一个)'+'共'+len+'行'"
  293. :visible.sync="dialogVisible"
  294. width="30%"
  295. :close-on-click-modal="false"
  296. :showClose="false"
  297. >
  298. <div
  299. class="test_box"
  300. contenteditable="true"
  301. ref="msg"
  302. style="white-space: pre-wrap"
  303. @input="handleInput"
  304. ></div>
  305. <span slot="footer" class="dialog-footer">
  306. <el-button @click="collectcancel">保存并关闭</el-button>
  307. <el-button type="primary" @click="collectionMatch">确 定</el-button>
  308. </span>
  309. </el-dialog>
  310. </div>
  311. </template>
  312. <script type="text/javascript">
  313. import api from '@api/knowledgeLib.js';
  314. import AddNewRuleTable from './AddNewRuleTable';
  315. import axios from 'axios';
  316. export default {
  317. name: 'AddRule',
  318. data() {
  319. return {
  320. title: '术语集合内容维护-添加',
  321. formInline: {
  322. logicalOperator: '0',
  323. name1: '',
  324. name2: '',
  325. name3: ''
  326. },
  327. innerText: '',
  328. ruleTypeList: [],
  329. ruleTermTypeList: [],
  330. conceptList: [],
  331. conceptText: '',
  332. excludedConceptIds: [],
  333. type: [],
  334. leftList: [],
  335. multipleSelection: [],
  336. sign: 1,
  337. searchtext: '',
  338. searchtext2: '',
  339. dialogVisible: false,
  340. form: {
  341. collectionLibType: '',
  342. collectionLibName: '',
  343. concepts: [],
  344. conceptLibType: '',
  345. collectionRemark: '',
  346. collectionId: ''
  347. },
  348. whether: false,
  349. editCount: -1, // 页面会否被编辑 >0被编辑 =0 未编辑
  350. startCount: -1,
  351. isSaveSuccess: false, // 是否保存成功
  352. timeout: null,
  353. rules: {
  354. collectionLibType: [
  355. { required: true, message: '请选择术语集合类型', trigger: 'change' }
  356. ],
  357. collectionLibName: [
  358. { required: true, message: '请选择术语集合名称', trigger: 'change' }
  359. ]
  360. },
  361. Math: 88,
  362. English: 77,
  363. chemistry: 99
  364. };
  365. },
  366. created() {
  367. this.getDict();
  368. const param = this.$route.params;
  369. let info = param.data;
  370. if (info) {
  371. this.title = '术语集合内容维护-' + '修改';
  372. this.form.collectionLibType = JSON.stringify(info.collectionLibType);
  373. this.form.collectionLibName = info.collectionLibName;
  374. this.form.concepts = info.concepts;
  375. this.form.conceptLibType = info.concepts[0].conceptLibType;
  376. this.form.collectionId = info.collectionId;
  377. this.form.collectionRemark = info.collectionRemark;
  378. this.leftList = info.concepts;
  379. this.sign = 2;
  380. this.$nextTick(() => {
  381. this.getIds(this.form.concepts);
  382. this.getTreeSearchList();
  383. });
  384. }
  385. setTimeout(() => {
  386. this.startCount = this.editCount;
  387. }, 500);
  388. },
  389. methods: {
  390. handleInput(event) {
  391. let text = event.target.innerText;
  392. this.innerText = text.replace(/(^\s*)|(\s*$)/g, '');
  393. },
  394. collectcancel() {
  395. this.dialogVisible = false;
  396. },
  397. cancelRequest() {
  398. if (typeof this.source === 'function') {
  399. this.source('终止请求');
  400. }
  401. },
  402. getDict() {
  403. api
  404. .zskgetDict()
  405. .then(res => {
  406. if (res.data.code == '0') {
  407. const data = res.data.data;
  408. this.ruleTypeList = data[63];
  409. this.type = data[61];
  410. }
  411. })
  412. .catch(error => {
  413. console.log(error);
  414. });
  415. },
  416. //过滤集合id
  417. getIds(arr) {
  418. arr.forEach((item, index) => {
  419. this.excludedConceptIds.push(item.conceptId);
  420. });
  421. },
  422. //获取术语集合名称
  423. searchLibName(val) {
  424. api
  425. .getSearchConcept({
  426. excludedConceptIds: [0],
  427. libType: this.form.collectionLibType,
  428. name: val
  429. })
  430. .then(res => {
  431. if (res.data.code == '0') {
  432. const data = res.data.data;
  433. this.ruleTermTypeList = data;
  434. }
  435. })
  436. .catch(error => {
  437. console.log(error);
  438. });
  439. },
  440. searchList() {
  441. let concepts, val;
  442. if (
  443. (this.searchtext != '' && this.searchtext2 == '') ||
  444. (this.searchtext == '' && this.searchtext2 != '')
  445. ) {
  446. concepts = JSON.parse(JSON.stringify(this.form.concepts));
  447. val = this.searchtext != '' ? this.searchtext : this.searchtext2;
  448. } else if (this.searchtext != '' && this.searchtext2 != '') {
  449. concepts = JSON.parse(JSON.stringify(this.leftList));
  450. val = this.searchtext2;
  451. } else if (this.searchtext == '' && this.searchtext2 == '') {
  452. this.leftList = JSON.parse(JSON.stringify(this.form.concepts));
  453. return;
  454. }
  455. let str = '.*' + val + '.*';
  456. let reg = new RegExp(str);
  457. let arr = [];
  458. //通过附加信息查询
  459. for (var i = 0; i < concepts.length; i++) {
  460. if (reg.test(concepts[i].conceptLibName)) {
  461. arr.push(concepts[i]);
  462. }
  463. }
  464. this.leftList = arr;
  465. },
  466. getCollectionLib(newValue) {
  467. this.ruleTermTypeList.forEach(item => {
  468. if (newValue == item.conceptName) {
  469. // this.form.collectionLibName = item.conceptName;
  470. this.form.collectionId = item.conceptId;
  471. this.form.collectionRemark = item.remark;
  472. }
  473. });
  474. },
  475. // 基础术语
  476. searchConcept(e) {
  477. if (this.timeout) {
  478. clearTimeout(this.timeout);
  479. }
  480. this.timeout = setTimeout(() => {
  481. this.getTreeSearchList();
  482. }, 800);
  483. },
  484. async getTreeSearchList() {
  485. this.whether = true;
  486. const params = {
  487. libType: this.form.conceptLibType,
  488. names: [
  489. this.formInline.name1,
  490. this.formInline.name2,
  491. this.formInline.name3
  492. ],
  493. excludedConceptIds: this.excludedConceptIds,
  494. logicalOperator: this.formInline.logicalOperator
  495. };
  496. const data = await api.searchCollectionConceptVO(params);
  497. if (data.data.code == '0') {
  498. this.conceptList = data.data.data;
  499. this.whether = false;
  500. }
  501. },
  502. btn(row) {
  503. if (this.whether) {
  504. return;
  505. }
  506. let concepts = {
  507. conceptId: row.conceptId,
  508. conceptLibType: row.libType,
  509. conceptLibName: row.conceptName
  510. };
  511. this.excludedConceptIds.push(row.conceptId);
  512. this.form.concepts.push(concepts);
  513. this.leftList = this.form.concepts;
  514. this.conceptList = [];
  515. this.searchtext = '';
  516. this.searchtext2 = '';
  517. this.$nextTick(() => {
  518. setTimeout(() => {
  519. this.getTreeSearchList();
  520. }, 150);
  521. });
  522. },
  523. handleSelectionChange(val) {
  524. this.multipleSelection = val;
  525. },
  526. add() {
  527. if (this.multipleSelection.length == 0) {
  528. this.$message({
  529. message: '数据不能为空',
  530. type: 'error'
  531. });
  532. return;
  533. }
  534. this.processing(this.multipleSelection);
  535. this.searchtext = '';
  536. this.searchtext2 = '';
  537. },
  538. //去重
  539. unique(arr) {
  540. let obj = {};
  541. arr = arr.reduce(function(item, next) {
  542. obj[next.conceptId]
  543. ? ''
  544. : (obj[next.conceptId] = true && item.push(next));
  545. return item;
  546. }, []);
  547. return arr;
  548. },
  549. //处理数据
  550. processing(arr) {
  551. if (this.whether) {
  552. return;
  553. }
  554. arr.forEach(it => {
  555. let concepts = {
  556. conceptId: it.conceptId,
  557. conceptLibType: it.libType ? it.libType : it.conceptLibType,
  558. conceptLibName: it.conceptName ? it.conceptName : it.conceptLibName
  559. };
  560. this.excludedConceptIds.push(it.conceptId);
  561. this.form.concepts.push(concepts);
  562. });
  563. this.form.concepts = this.unique(this.form.concepts);
  564. this.leftList = this.form.concepts;
  565. this.conceptList = [];
  566. this.multipleSelection = [];
  567. this.$nextTick(() => {
  568. setTimeout(() => {
  569. this.getTreeSearchList();
  570. }, 150);
  571. });
  572. },
  573. // 切换术语类型
  574. getConceptLibType() {
  575. this.type.forEach(it => {
  576. let id = it.val.split('-');
  577. if (this.form.collectionLibType == id[0]) {
  578. this.form.conceptLibType = id[2];
  579. }
  580. });
  581. this.clearData();
  582. },
  583. // 移除术语
  584. showDelDialog(row) {
  585. if (this.searchtext == '' && this.searchtext2 == '') {
  586. this.form.concepts.forEach((item, index) => {
  587. if (item.conceptId == row.conceptId) {
  588. this.form.concepts.splice(index, 1);
  589. this.excludedConceptIds.splice(index, 1);
  590. }
  591. });
  592. } else {
  593. this.leftList.forEach((item, index) => {
  594. if (item.conceptId == row.conceptId) {
  595. this.leftList.splice(index, 1);
  596. }
  597. });
  598. this.form.concepts.forEach((item, index) => {
  599. if (item.conceptId == row.conceptId) {
  600. this.form.concepts.splice(index, 1);
  601. this.excludedConceptIds.splice(index, 1);
  602. }
  603. });
  604. }
  605. this.getTreeSearchList();
  606. },
  607. saveSet() {
  608. let params = {
  609. ...this.form,
  610. relationId: 0
  611. };
  612. api.saveOrUpdateRecord(params).then(res => {
  613. if (res.data.code == 0) {
  614. this.$message({
  615. message: '操作成功',
  616. type: 'success'
  617. });
  618. this.isSaveSuccess = true;
  619. this.$router.push({
  620. name: 'TermSet',
  621. params: Object.assign({}, this.$route.params, { currentPage: 1 })
  622. });
  623. } else {
  624. this.$message({
  625. message: res.data.msg,
  626. type: 'warning'
  627. });
  628. }
  629. });
  630. },
  631. collectionMatch() {
  632. if (this.innerText.length == 0) {
  633. this.$message({
  634. message: '术语名称不能为空',
  635. type: 'error'
  636. });
  637. return;
  638. }
  639. let params = {
  640. conceptLibNames: this.innerText,
  641. conceptLibType: this.form.conceptLibType
  642. };
  643. api
  644. .collectionMatch(params)
  645. .then(res => {
  646. if (res.data.code == '0') {
  647. const data = res.data.data;
  648. let text = '';
  649. if (data.unMatchList.length > 0) {
  650. data.unMatchList.forEach(it => {
  651. text += it.conceptLibName + '\n';
  652. });
  653. this.$message({
  654. message: '列表中存在非标准术语',
  655. type: 'error'
  656. });
  657. }
  658. if (data.matchList.length > 0) {
  659. this.processing(data.matchList);
  660. if (data.unMatchList.length == 0) {
  661. this.dialogVisible = false;
  662. }
  663. }
  664. this.$refs.msg.innerHTML = text;
  665. this.innerText = text;
  666. }
  667. })
  668. .catch(error => {
  669. console.log(error);
  670. });
  671. },
  672. clearData() {
  673. this.form.collectionLibName = '';
  674. this.conceptText = '';
  675. this.ruleTermTypeList = [];
  676. this.form.concepts = [];
  677. this.getTreeSearchList();
  678. }
  679. },
  680. watch: {
  681. form: {
  682. handler(newName, oldName) {
  683. this.editCount++;
  684. },
  685. deep: true,
  686. immediate: true
  687. }
  688. },
  689. beforeRouteLeave(to, from, next) {
  690. if (
  691. this.startCount !== this.editCount &&
  692. this.form.concepts.length > 0 &&
  693. !this.isSaveSuccess
  694. ) {
  695. this.$alert('还有未保存的内容,确定要退出当前页面吗?', '提示', {
  696. confirmButtonText: '确定',
  697. // cancelButtonText: '取消',
  698. // cancelButtonClass: 'leaveBtn',
  699. // customClass: 'leaveBox',
  700. type: 'warning'
  701. })
  702. .then(() => {
  703. next();
  704. })
  705. .catch(() => {});
  706. } else {
  707. next();
  708. }
  709. },
  710. computed: {
  711. onshow() {
  712. return (
  713. this.form.collectionLibType != '' && this.form.collectionLibName != ''
  714. );
  715. },
  716. len() {
  717. let arr = this.innerText.split('\n');
  718. let len = 0;
  719. arr.forEach(it => {
  720. if (it != '') {
  721. len++;
  722. }
  723. });
  724. return len;
  725. }
  726. }
  727. };
  728. </script>