PubSelect.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. <template>
  2. <div class="single-container">
  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(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" 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" 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: 40%;
  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"],
  256. data() {
  257. return {
  258. rows: [...initRows],
  259. checkedExc: false,
  260. checkedCon: false,
  261. focusOn: -1, //聚焦的行index
  262. focusName: "name", //是否聚焦医生界面输入框
  263. disableBtn: false, //占位符是否禁用
  264. noHolder: "", //是否有占位符-仅多列使用
  265. msgTimer: null, //占位符必填提示延时
  266. searchVal: "",
  267. leftTagsList: [],
  268. selectLeftTagsList:[],
  269. tagActive:-1,
  270. connectedQas:{},
  271. showQas:[],
  272. styles: {
  273. background: "#eae7e7"
  274. },
  275. sex: {
  276. 1: "男",
  277. 2: "女",
  278. 3: "通"
  279. }
  280. };
  281. },
  282. mounted() {
  283. const { options } = this.$props;
  284. if (options) {
  285. const arr = options.filter(it => {
  286. if(it.subQuestion){
  287. it.exclusionCon = 1
  288. }
  289. return it.name;
  290. });
  291. this.rows = arr.length == 0 ? utils.getInitRow(initRow, 4) : arr;
  292. this.$emit("pushValues", arr);
  293. } else {
  294. this.initData();
  295. }
  296. if(this.type==1||this.type==2){
  297. this.searchTagList();
  298. }
  299. },
  300. watch: {
  301. searchVal(newVal, preVal) {
  302. this.searchTagList();
  303. },
  304. focusOn(newVal) {
  305. this.checkedExc = this.rows[newVal].exclusion === 1;
  306. this.checkedCon = this.rows[newVal].exclusionCon === 1;
  307. },
  308. /*type() {
  309. this.initData();
  310. },*/
  311. sexType() {
  312. this.initData();
  313. }
  314. },
  315. methods: {
  316. getConnectedQas(ids,n){
  317. if(this.tagActive===n){
  318. this.tagActive=-1;
  319. this.showQas=[];
  320. return;
  321. }
  322. this.tagActive=n;
  323. const idArr=ids.split(",");
  324. let idsA = [],qa={};
  325. this.showQas=[];
  326. idArr.map((it)=>{
  327. qa=this.connectedQas[it];
  328. if(!qa){
  329. idsA.push(it);
  330. }else{
  331. this.showQas.push(qa);
  332. }
  333. });
  334. if(idsA.length===0){
  335. return;
  336. }
  337. const param = {
  338. age:'',
  339. ids:idsA,
  340. sexType:this.sexType
  341. };
  342. api.getByIds(param).then((res)=>{
  343. if(res.data.code=='0'){
  344. this.connectedQas=Object.assign({},this.connectedQas,res.data.data);
  345. idsA.map((q)=>{
  346. this.showQas.push(this.connectedQas[q]);
  347. });
  348. }
  349. });
  350. },
  351. selectLeftTag(tag) {
  352. const hasTag = this.isHasTag(tag, this.selectLeftTagsList);
  353. if (hasTag) {
  354. this.selectLeftTagsList = this.selectLeftTagsList.filter(
  355. item => item.id !== tag.id
  356. );
  357. } else {
  358. this.selectLeftTagsList.push(tag);
  359. }
  360. },
  361. isHasTag(item, arr) {
  362. for (let i = 0; i < arr.length; i++) {
  363. if (arr[i].id === item.id) {
  364. return true;
  365. }
  366. }
  367. return false;
  368. },
  369. getStyle(item) {
  370. //左侧选中状态
  371. return this.isHasTag(item, this.selectLeftTagsList);
  372. },
  373. searchTagList() {
  374. let ids = []
  375. this.rows.map((it, x) => {
  376. if (it.subQuestion) {
  377. ids=ids.concat(it.subQuestion.split(','))
  378. }
  379. });
  380. let param = {
  381. tagName: this.searchVal.trim(),
  382. type: this.ascription,
  383. notIds: ids,
  384. notControlType: ['8'], //组合填写单或非诊疗情况模版不能添加图片上传
  385. sexType: this.sexType,
  386. tagType: ["1"] //qaType=2:组合填写单,qaType=3模板
  387. };
  388. api.questionSearch(param).then(res => {
  389. if (res.data.code === "0") {
  390. this.leftTagsList = res.data.data;
  391. this.selectLeftTagsList = [];
  392. // this.selectRightTagsList = [];
  393. }
  394. });
  395. },
  396. initData() {
  397. this.rows = [...utils.getInitRow(initRow, 4)];
  398. },
  399. addRow() {
  400. this.rows.push(Object.assign({}, initRow, { orderNo: this.rows.length }));
  401. },
  402. selectRow(index, name) {
  403. this.focusOn = index;
  404. this.focusName = name;
  405. const placeReg = /(\$\{number_\S*?\})|(\$\{input_\S*?\})/g;
  406. if (placeReg.test(this.rows[index][name])) {
  407. this.disableBtn = true;
  408. return;
  409. }
  410. this.disableBtn = false;
  411. },
  412. orderUpDown(i) {
  413. const item = this.rows[this.focusOn]; //要调整位置的行
  414. const inx = this.focusOn;
  415. if (
  416. inx === -1 ||
  417. (inx === 0 && i === -1) ||
  418. (inx === this.rows.length - 1 && i === 1)
  419. ) {
  420. return;
  421. }
  422. this.focusOn = inx + i;
  423. this.rows.splice(inx, 1);
  424. this.rows.splice(inx + i, 0, item);
  425. },
  426. handlePlaceholder(type) {
  427. //占位符类型,type=0文本输入框,type=1数字输入框,type=2关联问题
  428. const i = this.focusOn;
  429. clearTimeout(this.msgTimer);
  430. if (i == -1) {
  431. this.$message({
  432. message: "请先选中要操作的行",
  433. type: "warning",
  434. showClose: true
  435. });
  436. return;
  437. }
  438. const maps = {
  439. 0: "${input_其他(点击输入)}",
  440. 1: "${number_其他(点击输入)}"
  441. };
  442. const key = this.focusName;
  443. this.noHolder = this.noHolder.replace("," + i, "");
  444. this.rows[i].name = this.rows[i].name + maps[type];
  445. if (this.type != "3") {
  446. this.rows[i].description = this.rows[i].description + maps[type];
  447. }
  448. this.disableBtn = true;
  449. },
  450. handleExcluCon(){
  451. const i = this.focusOn;
  452. if (i == -1) {
  453. this.$message({
  454. message: "请先选中要操作的行",
  455. type: "warning",
  456. showClose: true
  457. });
  458. this.checkedCon = false
  459. return;
  460. }
  461. if(this.selectLeftTagsList.length==0&&this.rows[i].exclusionCon!=1){
  462. this.$message({
  463. message: "请选择标签池选项",
  464. type: "warning",
  465. showClose: true
  466. });
  467. this.checkedCon = false
  468. return;
  469. }
  470. if (this.rows[i].exclusionCon&&this.rows[i].exclusionCon === 1) {
  471. this.rows[i].exclusionCon = 0;
  472. this.rows[i].subQuestion = '';
  473. this.rows.map((it, x) => {
  474. if (x === i) {
  475. this.selectLeftTagsList = [];
  476. it.subQuestion = '';
  477. }
  478. });
  479. this.searchTagList()
  480. return;
  481. }
  482. this.rows.map((it, x) => {
  483. if (x === i) {
  484. let ids = []
  485. this.selectLeftTagsList.map((part)=>{
  486. ids.push(part.id)
  487. })
  488. this.selectLeftTagsList = [];
  489. it.exclusionCon = 1;
  490. it.subQuestion = ids.join(',');
  491. }
  492. });
  493. this.searchTagList()
  494. },
  495. handleExclu() {
  496. const i = this.focusOn;
  497. if (i == -1) {
  498. this.$message({
  499. message: "请先选中要操作的行",
  500. type: "warning",
  501. showClose: true
  502. });
  503. return;
  504. }
  505. if (this.rows[i].exclusion === 1) {
  506. this.rows[i].exclusion = 0;
  507. return;
  508. }
  509. this.rows.map((it, x) => {
  510. if (x === i) {
  511. it.exclusion = 1;
  512. }
  513. // else{
  514. // it.exclusion = 0;
  515. // }
  516. });
  517. },
  518. emitValues(i) {
  519. if (typeof i === "number") {
  520. const reg = /(\$\{number_\S*?\})|(\$\{input_\S*?\})/g;
  521. const name = this.rows[i].name;
  522. if (name && !reg.test(name)) {
  523. this.noHolder =
  524. this.noHolder.indexOf(i) != -1
  525. ? this.noHolder
  526. : this.noHolder + "," + i;
  527. const that = this;
  528. this.msgTimer = setTimeout(function() {
  529. that.$message({
  530. message: "请添加数字输入框或者文本输入框",
  531. type: "warning",
  532. showClose: true
  533. });
  534. }, 500);
  535. this.$emit("pushValues", this.rows);
  536. return;
  537. }
  538. this.noHolder = this.noHolder.replace("," + i, "");
  539. }
  540. const items = this.rows;
  541. this.$emit("pushValues", items);
  542. },
  543. HandleInputName(i, name, isName) {
  544. const reg = /(\$\{number_\S*?\})|(\$\{input_\S*?\})/g;
  545. const pureName = name.replace(reg, "");
  546. const hasPlace = reg.test(name);
  547. if (hasPlace && this.disableBtn == false) {
  548. this.disableBtn = true;
  549. } else if (!hasPlace && this.disableBtn == true) {
  550. this.rows[i][isName ? "description" : "name"] = this.rows[i][
  551. isName ? "description" : "name"
  552. ].replace(reg, "");
  553. this.disableBtn = false;
  554. }
  555. if (pureName.length > 30) {
  556. this.$message({
  557. message: "最多输入30个字",
  558. type: "warning",
  559. showClose: true
  560. });
  561. return;
  562. }
  563. },
  564. delRow() {
  565. if (this.focusOn == -1) {
  566. this.$message({
  567. message: "请先选择要删除的行",
  568. type: "warning",
  569. showClose: true
  570. });
  571. return;
  572. }
  573. this.$alert("确定要删除该行吗?", "提示", {
  574. confirmButtonText: "确定",
  575. type: "warning"
  576. })
  577. .then(() => {
  578. this.rows.splice(this.focusOn, 1);
  579. this.focusOn = -1;
  580. this.emitValues();
  581. })
  582. .catch(() => {});
  583. }
  584. }
  585. };
  586. </script>
  587. <style lang="less" scoped>
  588. .attributeBox {
  589. position: absolute;
  590. right: -100px;
  591. top: 2px;
  592. }
  593. .tagItem {
  594. position: relative;
  595. line-height: 30px;
  596. cursor: pointer;
  597. padding: 0 10px;
  598. }
  599. .operationPool {
  600. position: relative;
  601. width: 60%;
  602. min-height: 300px;
  603. padding: 10px 0;
  604. }
  605. .tagName {
  606. margin-right: 10px;
  607. }
  608. .tagName:before {
  609. content: "[";
  610. }
  611. .tagName::after {
  612. content: "]";
  613. }
  614. .bottomPartLeft {
  615. width: 50%;
  616. box-sizing: border-box;
  617. margin: 20px 150px 20px 124px;
  618. margin: 20px 150px 20px 70px;
  619. }
  620. .main-area{
  621. margin: 20px 150px 20px 70px;
  622. }
  623. .operation-row{
  624. margin-left: 80px;
  625. text-align: left;
  626. }
  627. .operation-row .del{
  628. float: right;
  629. }
  630. .poolTitle {
  631. // border-bottom: 1px solid @icssBorder;
  632. box-sizing: border-box;
  633. margin-bottom: 20px;
  634. }
  635. .pool {
  636. // border:1px solid @icssBorder;
  637. }
  638. .search {
  639. width: 100%;
  640. border-bottom: 1px solid #c0c4cc;
  641. box-sizing: border-box;
  642. height: 30px;
  643. }
  644. .tagList {
  645. border: 1px solid #c0c4cc;
  646. }
  647. .tagPool {
  648. height: 300px;
  649. overflow-y: auto;
  650. }
  651. .NoiseTemplateWrapper .btn {
  652. margin-top: 250px !important;
  653. }
  654. .bottomPartLeft {
  655. min-height: 250px;
  656. }
  657. .main-area .inps,.main-area .el-button {
  658. width:calc(100% - 120px)
  659. }
  660. .el-checkbox-group.connect {
  661. position: absolute;
  662. right: -150px;
  663. top: 0;
  664. }
  665. .pool {
  666. position: relative;
  667. }
  668. </style>