PubSelect.vue 18 KB

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