PubSelect.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. <template>
  2. <div class="single-container" @click="hideQas">
  3. <el-form>
  4. <div class="operation-row">
  5. <el-checkbox-group size="small">
  6. <el-checkbox-button
  7. :label="0"
  8. v-if="type!=8&&type!=10"
  9. :disabled="disableBtn"
  10. @change="handlePlaceholder(0)"
  11. >文字输入框占位符</el-checkbox-button>
  12. </el-checkbox-group>
  13. <el-checkbox-group size="small">
  14. <el-checkbox-button
  15. :label="0"
  16. v-if="type!=8&&type!=10"
  17. :disabled="disableBtn"
  18. @change="handlePlaceholder(1)"
  19. >数字输入框占位符</el-checkbox-button>
  20. </el-checkbox-group>
  21. <el-checkbox-group size="small" v-if="type==2" v-model="checkedExc">
  22. <el-checkbox-button :label="0" @change="handleExclu">互斥项</el-checkbox-button>
  23. </el-checkbox-group>
  24. <el-button type="danger" size="small" class="del" @click="delRow">删除</el-button>
  25. </div>
  26. <div class="main-area" v-if="type!=3">
  27. <el-col class="col-title">
  28. <span>
  29. <i>*</i>填写单医生界面展示标准内容
  30. </span>
  31. <span>填写单患者界面展示通俗内容</span>
  32. </el-col>
  33. <!-- <p class="static-tip" v-if="type==8">默认展示有/无</p> -->
  34. <el-col v-for="(it,i) in rows" :key="i">
  35. <div class="inps">
  36. <el-input
  37. v-model="rows[i].name"
  38. v-bind:class="{select:focusOn==i}"
  39. @focus="selectRow(i,'name')"
  40. ref="inputName"
  41. @input="HandleInputName(i, rows[i].name,true)"
  42. @blur="emitValues"
  43. ></el-input>
  44. <el-input
  45. v-model="rows[i].description"
  46. v-bind:class="{select:focusOn==i}"
  47. @focus="selectRow(i,'description')"
  48. ref="inputDesc"
  49. @input="HandleInputName(i, rows[i].description)"
  50. @blur="emitValues"
  51. ></el-input>
  52. </div>
  53. <el-tag v-if="it.exclusion" type="info" size="mini">互斥项</el-tag>
  54. <span :class="tagActive===i?'tag-active el-tag--mini el-tag el-tag--info':'el-tag--mini el-tag el-tag--info'" v-if="it.exclusionCon" @click="getConnectedQas($event,it.subQuestion,i)">已关联</span>
  55. </el-col>
  56. <el-button @click="addRow">+</el-button>
  57. <div class="bottomPartMid bottomPartMidss">
  58. <p>
  59. <span class="el-icon-arrow-up" @click="orderUpDown(-1)"></span>
  60. </p>
  61. <p>
  62. <span class="el-icon-arrow-down" @click="orderUpDown(1)"></span>
  63. </p>
  64. </div>
  65. <div class="connected-qas" @click.stop v-if="showQas.length>0">
  66. <p style="margin-bottom: 10px;">关联的问题:</p>
  67. <p v-for="(qa,i) in showQas">{{i+1}}. {{qa.name}}</p>
  68. </div>
  69. </div>
  70. <div class="main-area sigle-row" v-if="type==3">
  71. <el-col v-for="(it,i) in rows" :key="i">
  72. <div class="inps">
  73. <el-input
  74. v-model="rows[i].name"
  75. v-bind:class="{'red':noHolder.indexOf(i)!==-1, 'select':focusOn==i}"
  76. @focus="selectRow(i,'name')"
  77. ref="inputName"
  78. @input="HandleInputName(i, rows[i].name,true)"
  79. @blur="emitValues(i)"
  80. ></el-input>
  81. </div>
  82. <el-tag v-if="it.exclusion" type="info" size="mini">互斥项</el-tag>
  83. </el-col>
  84. <el-button @click="addRow" class="little">+</el-button>
  85. <div class="bottomPartMid bottomPartMidss">
  86. <p>
  87. <span class="el-icon-arrow-up" @click="orderUpDown(-1)"></span>
  88. </p>
  89. <p>
  90. <span class="el-icon-arrow-down" @click="orderUpDown(1)"></span>
  91. </p>
  92. </div>
  93. </div>
  94. <div v-if="(type==1||type==2)&&hasPool" class="bottomPartLeft">
  95. <p class="poolTitle">标签池</p>
  96. <div class="pool">
  97. <el-input placeholder="请输入搜索内容" v-model="searchVal">
  98. <i slot="prefix" class="el-input__icon el-icon-search"></i>
  99. </el-input>
  100. <ul class="tagList tagPool">
  101. <li
  102. v-for="(item, index) in leftTagsList"
  103. class="tagItem"
  104. :key="item.id"
  105. :title="'[ '+item.tagName+' ]('+sex[item.sexType]+(item.required?'、必':'')+')'"
  106. :style="getStyle(item)?styles:null"
  107. @click="selectLeftTag(item, index, $event)"
  108. >
  109. <p class="ellipsis">
  110. <span class="tagName">{{item.tagName}}</span>
  111. <span>({{sex[item.sexType]}}{{item.required?'、必':''}}{{item.flag==1?'、时间':''}}{{item.flag==2?'、诱因':''}}{{item.flag==3?'、伴随':''}})</span>
  112. </p>
  113. </li>
  114. </ul>
  115. <el-checkbox-group size="small" v-model="checkedCon" class="connect">
  116. <el-checkbox-button
  117. :label="0"
  118. v-if="type==1||type==2"
  119. @change="handleExcluCon"
  120. >{{checkedCon?'取消关联':'添加关联'}}</el-checkbox-button>
  121. </el-checkbox-group>
  122. </div>
  123. </div>
  124. </el-form>
  125. </div>
  126. </template>
  127. <style lang="less">
  128. @import "../../less/common.less";
  129. .tag-active{
  130. background: #ccc;
  131. }
  132. .main-area {
  133. position: relative;
  134. .connected-qas{
  135. width:190px;
  136. height:200px;
  137. background: #fff;
  138. position: absolute;
  139. top:29px;
  140. right: -150px;
  141. border:1px #ccc solid;
  142. padding:5px;
  143. }
  144. .bottomPartMid {
  145. position: absolute;
  146. top: 29px;
  147. right: -50px;
  148. }
  149. }
  150. .main-area .static-tip {
  151. border: 1px solid #dcdfe6;
  152. height: 38px;
  153. width: 130px;
  154. position: absolute;
  155. top: 29px;
  156. left: -130px;
  157. line-height: 38px;
  158. text-align: center;
  159. }
  160. .main-area .el-col .el-input.red .el-input__inner {
  161. border-color: red;
  162. }
  163. .el-checkbox-button--small .el-checkbox-button__inner {
  164. font-size: 14px;
  165. }
  166. .el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner {
  167. border-color: @disableColor;
  168. border-left-color: @disableColor;
  169. color: @disableColor;
  170. }
  171. .el-checkbox-button:last-child .el-checkbox-button__inner {
  172. border-radius: 3px;
  173. border-color: @adminBase;
  174. color: @adminBase;
  175. margin-right: 15px;
  176. }
  177. .el-checkbox-button.is-checked:first-child .el-checkbox-button__inner {
  178. background-color: @adminBase;
  179. border-left-color: @adminBase;
  180. color: #fff;
  181. }
  182. .el-checkbox-group {
  183. display: inline-block;
  184. }
  185. .operation-row {
  186. margin-left: 150px;
  187. /*text-align: right;*/
  188. .del {
  189. margin-left: 150px;
  190. }
  191. .tip {
  192. color: #48c5d7;
  193. }
  194. }
  195. .main-area {
  196. width: 80%;
  197. min-width: 400px;
  198. margin: 20px 150px 20px 124px;
  199. &.sigle-row {
  200. width: 60%;
  201. margin: 20px 150px 20px 30%;
  202. .bottomPartMid {
  203. top: 0;
  204. right: 5%;
  205. }
  206. }
  207. .inps {
  208. display: inline-block;
  209. width: calc(100% - 60px);
  210. }
  211. .el-tag {
  212. margin-left: 10px;
  213. }
  214. .col-title {
  215. margin-bottom: 10px;
  216. span {
  217. display: inline-block;
  218. width: calc(50% - 30px);
  219. font-size: 12px;
  220. i {
  221. color: #f56c6c;
  222. margin-right: 3px;
  223. }
  224. }
  225. }
  226. .el-col .el-input {
  227. width: 50%;
  228. display: inline-block;
  229. .el-input__inner {
  230. border-radius: 0;
  231. }
  232. &.select {
  233. input {
  234. border-color: @adminBase;
  235. }
  236. }
  237. }
  238. .el-button {
  239. width: calc(100% - 60px);
  240. border-radius: 0;
  241. &.little {
  242. width: calc(50% - 30px);
  243. }
  244. }
  245. }
  246. </style>
  247. <script>
  248. import utils from "@api/utils.js";
  249. import api from "@api/preTreat.js";
  250. import Vue from "vue";
  251. //单行数据
  252. const initRow = { orderNo: 0, name: "", description: "", exclusion: 0 };
  253. const initRows = utils.getInitRow(initRow, 4);
  254. export default {
  255. props: ["type", "options", "ascription", "sexType","hasId","hasPool"],
  256. data() {
  257. return {
  258. rows: [...initRows],
  259. selectIndex: -1,
  260. checkedExc: false,
  261. checkedCon: false,
  262. focusOn: -1, //聚焦的行index
  263. focusName: "name", //是否聚焦医生界面输入框
  264. disableBtn: false, //占位符是否禁用
  265. noHolder: "", //是否有占位符-仅多列使用
  266. msgTimer: null, //占位符必填提示延时
  267. searchVal: "",
  268. leftTagsList: [],
  269. selectLeftTagsList:[],
  270. tagActive:-1,
  271. connectedQas:{},
  272. showQas:[],
  273. styles: {
  274. background: "#eae7e7"
  275. },
  276. sex: {
  277. 1: "男",
  278. 2: "女",
  279. 3: "通"
  280. }
  281. };
  282. },
  283. mounted() {
  284. const { options } = this.$props;
  285. if (options) {
  286. const arr = options.filter(it => {
  287. if(it.subQuestion){
  288. it.exclusionCon = 1
  289. }
  290. return it.name;
  291. });
  292. this.rows = arr.length == 0 ? utils.getInitRow(initRow, 4) : arr;
  293. this.$emit("pushValues", arr);
  294. } else {
  295. this.initData();
  296. }
  297. if(this.type==1||this.type==2){
  298. this.searchTagList();
  299. }
  300. },
  301. watch: {
  302. searchVal(newVal, preVal) {
  303. this.searchTagList();
  304. },
  305. focusOn(newVal) {
  306. this.selectIndex = newVal
  307. this.checkedExc = this.rows[newVal].exclusion === 1;
  308. this.checkedCon = this.rows[newVal].exclusionCon === 1;
  309. this.searchTagList()
  310. },
  311. /*type() {
  312. this.initData();
  313. },*/
  314. sexType() {
  315. this.initData();
  316. }
  317. },
  318. methods: {
  319. getConnectedQas(e,ids,n){
  320. e.stopPropagation();
  321. if(this.tagActive===n){
  322. this.hideQas()
  323. return;
  324. }
  325. this.tagActive=n;
  326. const idArr=ids.split(",");
  327. let idsA = [],qa={};
  328. this.showQas=[];
  329. idArr.map((it)=>{
  330. qa=this.connectedQas[it];
  331. if(!qa){
  332. idsA.push(it);
  333. }else{
  334. this.showQas.push(qa);
  335. }
  336. });
  337. if(idsA.length===0){
  338. return;
  339. }
  340. const param = {
  341. age:'',
  342. ids:idsA,
  343. sexType:this.sexType
  344. };
  345. api.getByIds(param).then((res)=>{
  346. if(res.data.code=='0'){
  347. this.connectedQas=Object.assign({},this.connectedQas,res.data.data);
  348. idsA.map((q)=>{
  349. this.showQas.push(this.connectedQas[q]);
  350. });
  351. }
  352. });
  353. },
  354. hideQas(){
  355. this.tagActive=-1;
  356. this.showQas =[]
  357. },
  358. selectLeftTag(tag) {
  359. const hasTag = this.isHasTag(tag, this.selectLeftTagsList);
  360. if (hasTag) {
  361. this.selectLeftTagsList = this.selectLeftTagsList.filter(
  362. item => item.id !== tag.id
  363. );
  364. } else {
  365. this.selectLeftTagsList.push(tag);
  366. }
  367. },
  368. isHasTag(item, arr) {
  369. for (let i = 0; i < arr.length; i++) {
  370. if (arr[i].id === item.id) {
  371. return true;
  372. }
  373. }
  374. return false;
  375. },
  376. getStyle(item) {
  377. //左侧选中状态
  378. return this.isHasTag(item, this.selectLeftTagsList);
  379. },
  380. searchTagList() {
  381. let ids = []
  382. this.rows.map((it, x) => {
  383. if (it.subQuestion&&this.selectIndex===x) {
  384. ids=ids.concat(it.subQuestion.split(','))
  385. }
  386. });
  387. if(this.hasId!=''){
  388. ids.push(this.hasId)
  389. }
  390. let param = {
  391. tagName: this.searchVal.trim(),
  392. type: this.ascription,
  393. notIds: ids,
  394. noSubQuestion:1,
  395. notControlType: ['8','4'], //组合填写单或非诊疗情况模版不能添加图片上传
  396. sexType: this.sexType,
  397. tagType: ["1"] //qaType=2:组合填写单,qaType=3模板
  398. };
  399. api.questionSearch(param).then(res => {
  400. if (res.data.code === "0") {
  401. this.leftTagsList = res.data.data;
  402. this.selectLeftTagsList = [];
  403. // this.selectRightTagsList = [];
  404. }
  405. });
  406. },
  407. initData() {
  408. this.rows = [...utils.getInitRow(initRow, 4)];
  409. },
  410. addRow() {
  411. if(this.type == 3){
  412. if(this.rows.length>5){
  413. this.$message({
  414. message: "多列填写类型最多添加6个选项",
  415. type: "warning",
  416. showClose: true
  417. });
  418. return
  419. }
  420. }
  421. this.rows.push(Object.assign({}, initRow, { orderNo: this.rows.length }));
  422. },
  423. selectRow(index, name) {
  424. this.focusOn = index;
  425. this.focusName = name;
  426. const placeReg = /(\$\{number_\S*?\})|(\$\{input_\S*?\})/g;
  427. if (placeReg.test(this.rows[index][name])) {
  428. this.disableBtn = true;
  429. return;
  430. }
  431. this.disableBtn = false;
  432. },
  433. orderUpDown(i) {
  434. const item = this.rows[this.focusOn]; //要调整位置的行
  435. const inx = this.focusOn;
  436. if (
  437. inx === -1 ||
  438. (inx === 0 && i === -1) ||
  439. (inx === this.rows.length - 1 && i === 1)
  440. ) {
  441. return;
  442. }
  443. this.focusOn = inx + i;
  444. this.rows.splice(inx, 1);
  445. this.rows.splice(inx + i, 0, item);
  446. },
  447. handlePlaceholder(type) {
  448. //占位符类型,type=0文本输入框,type=1数字输入框,type=2关联问题
  449. const i = this.focusOn;
  450. clearTimeout(this.msgTimer);
  451. if (i == -1) {
  452. this.$message({
  453. message: "请先选中要操作的行",
  454. type: "warning",
  455. showClose: true
  456. });
  457. return;
  458. }
  459. const maps = {
  460. 0: "${input_其他(点击输入)}",
  461. 1: "${number_其他(点击输入)}"
  462. };
  463. const key = this.focusName;
  464. this.noHolder = this.noHolder.replace("," + i, "");
  465. this.rows[i].name = this.rows[i].name + maps[type];
  466. if (this.type != "3") {
  467. this.rows[i].description = this.rows[i].description + maps[type];
  468. }
  469. this.disableBtn = true;
  470. },
  471. handleExcluCon(){
  472. const i = this.focusOn;
  473. if (i == -1) {
  474. this.$message({
  475. message: "请先选中要操作的行",
  476. type: "warning",
  477. showClose: true
  478. });
  479. this.checkedCon = false
  480. return;
  481. }
  482. if(this.selectLeftTagsList.length==0&&this.rows[i].exclusionCon!=1){
  483. this.$message({
  484. message: "请选择标签池选项",
  485. type: "warning",
  486. showClose: true
  487. });
  488. this.checkedCon = false
  489. return;
  490. }
  491. if (this.rows[i].exclusionCon&&this.rows[i].exclusionCon === 1) {
  492. this.rows[i].exclusionCon = 0;
  493. this.rows[i].subQuestion = '';
  494. this.rows.map((it, x) => {
  495. if (x === i) {
  496. this.selectLeftTagsList = [];
  497. it.subQuestion = '';
  498. }
  499. });
  500. this.searchTagList()
  501. return;
  502. }
  503. this.rows.map((it, x) => {
  504. if (x === i) {
  505. let ids = []
  506. this.selectLeftTagsList.map((part)=>{
  507. ids.push(part.id)
  508. })
  509. this.selectLeftTagsList = [];
  510. it.exclusionCon = 1;
  511. it.subQuestion = ids.join(',');
  512. }
  513. });
  514. this.searchTagList()
  515. },
  516. handleExclu() {
  517. const i = this.focusOn;
  518. if (i == -1) {
  519. this.$message({
  520. message: "请先选中要操作的行",
  521. type: "warning",
  522. showClose: true
  523. });
  524. return;
  525. }
  526. if (this.rows[i].exclusion === 1) {
  527. this.rows[i].exclusion = 0;
  528. return;
  529. }
  530. this.rows.map((it, x) => {
  531. if (x === i) {
  532. it.exclusion = 1;
  533. }
  534. // else{
  535. // it.exclusion = 0;
  536. // }
  537. });
  538. },
  539. emitValues(i) {
  540. if (typeof i === "number") {
  541. const reg = /(\$\{number_\S*?\})|(\$\{input_\S*?\})/g;
  542. const name = this.rows[i].name;
  543. if (name && !reg.test(name)) {
  544. this.noHolder =
  545. this.noHolder.indexOf(i) != -1
  546. ? this.noHolder
  547. : this.noHolder + "," + i;
  548. const that = this;
  549. this.msgTimer = setTimeout(function() {
  550. that.$message({
  551. message: "请添加数字输入框或者文本输入框",
  552. type: "warning",
  553. showClose: true
  554. });
  555. }, 500);
  556. this.$emit("pushValues", this.rows);
  557. return;
  558. }
  559. this.noHolder = this.noHolder.replace("," + i, "");
  560. }
  561. const items = this.rows;
  562. this.$emit("pushValues", items);
  563. },
  564. HandleInputName(i, name, isName) {
  565. const reg = /(\$\{number_\S*?\})|(\$\{input_\S*?\})/g;
  566. const pureName = name.replace(reg, "");
  567. const hasPlace = reg.test(name);
  568. if (hasPlace && this.disableBtn == false) {
  569. this.disableBtn = true;
  570. } else if (!hasPlace && this.disableBtn == true) {
  571. this.rows[i][isName ? "description" : "name"] = this.rows[i][
  572. isName ? "description" : "name"
  573. ].replace(reg, "");
  574. this.disableBtn = false;
  575. }
  576. if (pureName.length > 30) {
  577. this.$message({
  578. message: "最多输入30个字",
  579. type: "warning",
  580. showClose: true
  581. });
  582. return;
  583. }
  584. },
  585. delRow() {
  586. if (this.focusOn == -1) {
  587. this.$message({
  588. message: "请先选择要删除的行",
  589. type: "warning",
  590. showClose: true
  591. });
  592. return;
  593. }
  594. this.$alert("确定要删除该行吗?", "提示", {
  595. confirmButtonText: "确定",
  596. type: "warning"
  597. })
  598. .then(() => {
  599. this.rows.splice(this.focusOn, 1);
  600. this.focusOn = -1;
  601. this.emitValues();
  602. })
  603. .catch(() => {});
  604. }
  605. }
  606. };
  607. </script>
  608. <style lang="less" scoped>
  609. .attributeBox {
  610. position: absolute;
  611. right: -100px;
  612. top: 2px;
  613. }
  614. .tagItem {
  615. position: relative;
  616. line-height: 30px;
  617. cursor: pointer;
  618. padding: 0 10px;
  619. }
  620. .operationPool {
  621. position: relative;
  622. width: 60%;
  623. min-height: 300px;
  624. padding: 10px 0;
  625. }
  626. .tagName {
  627. margin-right: 10px;
  628. }
  629. .tagName:before {
  630. content: "[";
  631. }
  632. .tagName::after {
  633. content: "]";
  634. }
  635. .bottomPartLeft {
  636. width: 50%;
  637. box-sizing: border-box;
  638. margin: 20px 150px 20px 124px;
  639. margin: 20px 150px 20px 70px;
  640. }
  641. .main-area{
  642. margin: 20px 150px 20px 70px;
  643. }
  644. .operation-row{
  645. margin-left: 80px;
  646. text-align: left;
  647. }
  648. .operation-row .del{
  649. float: right;
  650. }
  651. .poolTitle {
  652. // border-bottom: 1px solid @icssBorder;
  653. box-sizing: border-box;
  654. margin-bottom: 20px;
  655. }
  656. .pool {
  657. // border:1px solid @icssBorder;
  658. }
  659. .search {
  660. width: 100%;
  661. border-bottom: 1px solid #c0c4cc;
  662. box-sizing: border-box;
  663. height: 30px;
  664. }
  665. .tagList {
  666. border: 1px solid #c0c4cc;
  667. }
  668. .tagPool {
  669. height: 300px;
  670. overflow-y: auto;
  671. }
  672. .NoiseTemplateWrapper .btn {
  673. margin-top: 250px !important;
  674. }
  675. .bottomPartLeft {
  676. min-height: 250px;
  677. }
  678. .main-area .inps,.main-area .el-button {
  679. width:calc(100% - 120px)
  680. }
  681. .el-checkbox-group.connect {
  682. position: absolute;
  683. right: -150px;
  684. top: 0;
  685. }
  686. .pool {
  687. position: relative;
  688. }
  689. </style>