Table.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. <!-- -->
  2. <template>
  3. <div class="Big-Book-table" v-if="curQue">
  4. <div class="Big-Book-Single-content">
  5. <div class="adult-book-input-item">
  6. <span class="adult-book-lable">标题:</span>   
  7. <el-input
  8. type="textarea"
  9. class="adult-book-input"
  10. :autosize="{ minRows: 2 }"
  11. placeholder="请输入标题"
  12. v-model="curQue.title"
  13. @blur="curQue.title = curQue.title.trim()"
  14. ></el-input>
  15. </div>
  16. <div
  17. class="Big-Book-main"
  18. style="border-bottom: 1px #ccc solid; margin-bottom: 20px"
  19. >
  20. <div class="adult-book-input-item">
  21. <span class="adult-book-lable">表头:</span>
  22. <el-radio-group v-model="curQue.isHeader" @change="changeHeader"
  23. >     
  24. <el-radio :label="true">有</el-radio>
  25. <el-radio :label="false">无</el-radio>
  26. </el-radio-group>
  27. </div>
  28. <template v-if="curQue.isHeader">
  29. <div
  30. class="adult-book-input-item"
  31. v-for="(item, i) in curQue.headerList"
  32. :key="i"
  33. >
  34. <span class="adult-book-lable">表头{{ i + 1 }}:</span>           
  35.  <el-input
  36. type="textarea"
  37. placeholder="请输入内容"
  38. v-model="item.con"
  39. class="adult-book-input"
  40. :autosize="{ minRows: 2 }"
  41. @blur="item.con = item.con.trim()"
  42. ></el-input>
  43. <img
  44. @click="deleteHeader(i)"
  45. class="close"
  46. src="../../../assets/adult/del-close.png"
  47. alt=""
  48. />
  49. </div>
  50. <div class="addoption" @click="addHeader">添加表头</div>
  51. </template>
  52. <table style="table-layout: fixed">
  53. <tr v-if="curQue.headerList.length > 0 && curQue.isHeader">
  54. <th
  55. :class="'th' + heai"
  56. v-for="(item, heai) in curQue.headerList"
  57. :key="heai + 'header'"
  58. >
  59. {{ item.con }}
  60. </th>
  61. </tr>
  62. <tr v-for="(item, rowi) in curQue.option" :key="rowi + 'row'">
  63. <td
  64. :class="'td' + coli"
  65. v-for="(it, coli) in item"
  66. :key="coli + 'col'"
  67. >
  68. <el-button
  69. v-if="!it.ByMerge"
  70. size="small"
  71. @click="editTd(rowi, coli)"
  72. >编辑</el-button
  73. >
  74. <!-- <el-button
  75. size="small"
  76. type="primary"
  77. @click="removeTd(rowi, coli)"
  78. >删除</el-button
  79. > -->
  80. <!-- <template v-if="coli == item.length - 1"> 删除列 </template> -->
  81. <div>
  82. <el-button
  83. style="position: absolute; top: 50px; left: 15px"
  84. size="mini"
  85. v-if="rowi == curQue.option.length - 1"
  86. @click="removeCol(coli)"
  87. >删除列</el-button
  88. >
  89. </div>
  90. </td>
  91. <el-button size="small" @click="removeRow(rowi)">删除行</el-button>
  92. </tr>
  93. </table>
  94. <div class="add">
  95. <div class="addoption" @click="addRow">增加行</div>
  96. <div class="addoption" v-if="!curQue.isHeader" @click="addCol">
  97. 增加列
  98. </div>
  99. </div>
  100. <div class="adult-book-input-item">
  101. <span class="adult-book-lable">提示标题:</span>           
  102. <el-input
  103. type="textarea"
  104. class="adult-book-input"
  105. :autosize="{ minRows: 2 }"
  106. placeholder="请输入提示标题"
  107. v-model="curQue.hintTitle"
  108. @blur="curQue.hintTitle = curQue.hintTitle.trim()"
  109. ></el-input>
  110. </div>
  111. <div
  112. v-for="(item, htindex) in curQue.hintOtion"
  113. :key="'hint' + htindex"
  114. >
  115. <div class="adult-book-input-item">
  116. <span class="adult-book-lable">提示选项:</span>           
  117. <el-input
  118. type="textarea"
  119. class="adult-book-input"
  120. :autosize="{ minRows: 2 }"
  121. placeholder="请输入提示内容"
  122. v-model="item.con"
  123. @blur="item.con = item.con.trim()"
  124. ></el-input>
  125. <img
  126. @click="deleteHint(htindex)"
  127. class="close"
  128. src="../../../assets/adult/del-close.png"
  129. alt=""
  130. />
  131. </div>
  132. <div class="adult-book-input-item">
  133. <span class="adult-book-lable">选项拼音:</span>           
  134. <el-input
  135. type="textarea"
  136. class="adult-book-input"
  137. :autosize="{ minRows: 2 }"
  138. placeholder="请输入选项拼音"
  139. v-model="item.pinyin"
  140. @blur="item.pinyin = item.pinyin.trim()"
  141. ></el-input>
  142. <el-button @click="getPinyin(item)">生成拼音</el-button>
  143. </div>
  144. </div>
  145. <div class="addoption" @click="addHint">添加选项</div>
  146. </div>
  147. </div>
  148. <el-dialog
  149. title="编辑内容"
  150. :visible.sync="dialogVisible"
  151. width="30%"
  152. :before-close="handleClose"
  153. destroy-on-close
  154. >
  155. <template v-if="data">
  156. <div class="adult-book-input-item">
  157. <span class="adult-book-lable">内容:</span>
  158. <el-input
  159. type="textarea"
  160. class="adult-book-input"
  161. :autosize="{ minRows: 2 }"
  162. placeholder="请输入内容"
  163. v-model="data.con"
  164. @blur="data.con = data.con.trim()"
  165. ></el-input>
  166. </div>
  167. <!-- <div
  168. class="Big-Book-con"
  169. v-for="(item, i) in data.answerList"
  170. :key="i + 'answer'"
  171. >
  172. <span>答案:</span>           
  173. <el-input
  174. style="width: 300px"
  175. type="textarea"
  176. autosize
  177. placeholder="请输入答案"
  178. v-model="item.answer"
  179. @blur="item.answer = item.answer.trim()"
  180. ></el-input>
  181. <img
  182. @click="deleteAnswer(data, i)"
  183. class="close"
  184. src="../../../assets/adult/del-close.png"
  185. alt=""
  186. />
  187. </div>
  188. <div class="addoption" @click="addAnswer(data)">增加答案</div>
  189. <div class="Big-Book-con">
  190. <span>合并单元格:</span>      
  191. <el-radio-group
  192. v-model="data.MergeDirection"
  193. @change="changeMergeDirection"
  194. >     
  195. <el-radio label="bottom">向下合并</el-radio>
  196. <el-radio label="right">向右合并</el-radio>
  197. <el-radio label="false">不合并</el-radio>
  198. </el-radio-group>
  199. </div>
  200. <div class="Big-Book-con">
  201. <span>是否需要录音:</span>           
  202. <el-radio v-model="data.isRecord" :label="true">是</el-radio>
  203. <el-radio v-model="data.isRecord" :label="false">否</el-radio>
  204. </div>
  205. <div
  206. class="Big-Book-con"
  207. v-if="mergeList.length > 0 && data.MergeDirection != 'false'"
  208. >
  209. <span>合并数量:</span>
  210. <el-select
  211. placeholder="请选择"
  212. v-model="data.mergeNumber"
  213. @change="changemMergeNumber"
  214. >
  215. <el-option
  216. v-for="item in mergeList"
  217. :key="item + 'a'"
  218. :value="item"
  219. >
  220. </el-option>
  221. </el-select>
  222. </div>
  223. <div class="Big-Book-mp3" v-if="data">
  224. <span>音频:</span>
  225. <Upload
  226. :changeFillId="changeMp3"
  227. :datafileList="data.mp3_list"
  228. :filleNumber="mp3Number"
  229. :uploadType="'mp3'"
  230. />
  231. </div> -->
  232. </template>
  233. <span slot="footer" class="dialog-footer">
  234. <el-button @click="handleClose">取 消</el-button>
  235. <el-button type="primary" @click="save">保 存</el-button>
  236. </span>
  237. </el-dialog>
  238. </div>
  239. </template>
  240. <script>
  241. import Upload from "../common/Upload.vue";
  242. export default {
  243. name: "table",
  244. props: ["curQue", "fn_data", "changeCurQue"],
  245. components: { Upload },
  246. data() {
  247. return {
  248. form: {
  249. stem: {
  250. con: "",
  251. pinyin: "",
  252. english: "",
  253. highlight: "",
  254. underline: "",
  255. img_url: [],
  256. mp3_url: [],
  257. },
  258. },
  259. dialogVisible: false,
  260. data: null,
  261. rowIndex: null,
  262. colIndex: null,
  263. mp3Number: 1,
  264. mergeList: [],
  265. currentOption: null,
  266. data_structure: {
  267. type: "table",
  268. name: "表格",
  269. title: "",
  270. isHeader: false,
  271. headerList: [
  272. {
  273. con: "",
  274. },
  275. ],
  276. option: [
  277. [
  278. {
  279. img_list: [],
  280. mp3_list: [],
  281. answerList: [
  282. {
  283. answer: "",
  284. },
  285. ],
  286. con: "",
  287. MergeDirection: "false", //合并方向
  288. isRecord: false,
  289. ByMerge: false, //是否被合并
  290. },
  291. ],
  292. ],
  293. img_list: [],
  294. hintTitle: "",
  295. hintOtion: [
  296. {
  297. con: "",
  298. pinyin: "",
  299. },
  300. ],
  301. },
  302. };
  303. },
  304. computed: {},
  305. watch: {},
  306. //方法集合
  307. methods: {
  308. // 点击生成拼音
  309. getPinyin(item) {
  310. let bool = false;
  311. let value = "";
  312. if (item.con == "") {
  313. this.$message.warning("请先输入内容,再生成拼音");
  314. bool = true;
  315. } else {
  316. value = item.con;
  317. }
  318. if (bool) {
  319. return;
  320. }
  321. let result = pinyinUtil.getPinyin(value);
  322. item.pinyin = result;
  323. this.$forceUpdate()
  324. },
  325. // 删除提示选项
  326. deleteHint(index) {
  327. if (this.curQue.hintOtion.length <= 1) {
  328. this.$message.warning("至少要保留一个选项");
  329. return;
  330. }
  331. this.curQue.hintOtion.splice(index, 1);
  332. },
  333. // 增加提示选项
  334. addHint() {
  335. let obj = JSON.parse(JSON.stringify(this.data_structure.hintOtion[0]));
  336. this.curQue.hintOtion.push(obj);
  337. },
  338. // 修改表头时清空option否则引发bug
  339. changeHeader(val) {
  340. let obj = JSON.parse(JSON.stringify(this.data_structure.option));
  341. this.curQue.option = obj;
  342. },
  343. // 选择合并方向或者不合并
  344. changeMergeDirection(val) {
  345. if (val == "bottom") {
  346. let num = this.currentOption.length - 1 - this.rowIndex;
  347. for (let i = 1; i <= num; i++) {
  348. this.mergeList.push(i);
  349. }
  350. }
  351. if (val == "false") {
  352. let currentTd = this.curQue.option[this.rowIndex][this.colIndex];
  353. if (currentTd.MergeDirection == "bottom") {
  354. this.currentOption.forEach((item, row) => {
  355. item.forEach((it, col) => {
  356. if (
  357. col == this.colIndex &&
  358. row > this.rowIndex &&
  359. row <= this.rowIndex + currentTd.mergeNumber
  360. ) {
  361. it.ByMerge = false;
  362. }
  363. });
  364. });
  365. }
  366. }
  367. },
  368. // 选择合并数量
  369. changemMergeNumber(val) {
  370. this.currentOption.forEach((item, row) => {
  371. item.forEach((it, col) => {
  372. if (
  373. col == this.colIndex &&
  374. row > this.rowIndex &&
  375. row <= this.rowIndex + val
  376. ) {
  377. it.ByMerge = true;
  378. }
  379. });
  380. });
  381. },
  382. // 上传音频
  383. changeMp3(fileList) {
  384. const articleImgList = JSON.parse(JSON.stringify(fileList));
  385. const articleImgRes = [];
  386. articleImgList.forEach((item) => {
  387. if (item.response) {
  388. const obj = {
  389. name: item.name,
  390. url: item.response.file_info_list[0].file_url,
  391. id: "[FID##" + item.response.file_info_list[0].file_id + "##FID]",
  392. media_duration: item.response.file_info_list[0].media_duration, //音频时长
  393. };
  394. articleImgRes.push(obj);
  395. }
  396. });
  397. this.data.mp3_list = JSON.parse(JSON.stringify(articleImgRes));
  398. },
  399. // 删除答案
  400. deleteAnswer(data, index) {
  401. if (data.answerList.length <= 1) {
  402. this.$message.warning("至少要保留1个答案");
  403. return;
  404. }
  405. data.answerList.splice(index, 1);
  406. },
  407. // 增加答案
  408. addAnswer(data) {
  409. let type = this.curQue.type;
  410. let cur_fn_data_arr = this.fn_data.filter((item) => item.type == type);
  411. let cur_fn_data = JSON.parse(JSON.stringify(cur_fn_data_arr[0]));
  412. let obj = cur_fn_data.data_structure.option[0][0].answerList[0];
  413. data.answerList.push(obj);
  414. },
  415. // 删除行
  416. removeRow(index) {
  417. if (this.curQue.option.length <= 1) {
  418. this.$message.warning("至少要保留一行");
  419. return;
  420. }
  421. this.curQue.option.forEach((item, i) => {
  422. if (i == index) {
  423. this.curQue.option.splice(i, 1);
  424. }
  425. });
  426. },
  427. // 删除列
  428. removeCol(index) {
  429. if (this.curQue.option[0].length <= 1) {
  430. this.$message.warning("至少要保留一格");
  431. return;
  432. }
  433. this.curQue.option.forEach((item) => {
  434. item.forEach((it, i) => {
  435. if (i == index) {
  436. item.splice(i, 1);
  437. }
  438. });
  439. });
  440. this.curQue.headerList.forEach((item, i) => {
  441. if (i == index) {
  442. this.curQue.headerList.splice(i, 1);
  443. }
  444. });
  445. },
  446. // 删除td
  447. removeTd(rowi, coli) {
  448. console.log(rowi, coli);
  449. },
  450. // 编辑td
  451. editTd(rowi, coli) {
  452. this.rowIndex = rowi;
  453. this.colIndex = coli;
  454. this.data = JSON.parse(JSON.stringify(this.curQue.option[rowi][coli]));
  455. this.dialogVisible = true;
  456. this.currentOption = null;
  457. this.currentOption = JSON.parse(JSON.stringify(this.curQue.option));
  458. if (this.data.MergeDirection == "false") {
  459. this.mergeList = [];
  460. }
  461. },
  462. // 保存
  463. save() {
  464. this.curQue.option = JSON.parse(JSON.stringify(this.currentOption));
  465. this.curQue.option[this.rowIndex][this.colIndex] = JSON.parse(
  466. JSON.stringify(this.data)
  467. );
  468. this.dialogVisible = false;
  469. },
  470. // 增加行
  471. addRow() {
  472. let obj = JSON.parse(JSON.stringify(this.data_structure.option[0][0]));
  473. let arr = [];
  474. for (let i = 0; i < this.curQue.option[0].length; i++) {
  475. arr.push(obj);
  476. }
  477. this.curQue.option.push(arr);
  478. },
  479. // 增加列
  480. addCol() {
  481. let obj = JSON.parse(JSON.stringify(this.data_structure.option[0][0]));
  482. this.curQue.option.forEach((item, i) => {
  483. item.push(obj);
  484. });
  485. },
  486. // 删除其中一个选项
  487. deleteHeader(index) {
  488. if (this.curQue.headerList.length <= 1) {
  489. this.$message.warning("至少要保留一个表头");
  490. return;
  491. }
  492. this.curQue.headerList.splice(index, 1);
  493. this.curQue.option.forEach((item) => {
  494. item.splice(index, 1);
  495. });
  496. },
  497. //添加一个表头
  498. addHeader() {
  499. let optionobj = JSON.parse(
  500. JSON.stringify(this.data_structure.headerList[0])
  501. );
  502. this.curQue.headerList.push(optionobj);
  503. this.curQue.option.forEach((item) => {
  504. item.push(optionobj);
  505. });
  506. setTimeout(() => {
  507. this.changeTh();
  508. }, 100);
  509. },
  510. // 关闭弹窗并清空数据
  511. handleClose() {
  512. this.dialogVisible = false;
  513. this.data = null;
  514. },
  515. },
  516. //生命周期 - 创建完成(可以访问当前this实例)
  517. created() {
  518. if (!this.curQue) {
  519. this.changeCurQue(this.data_structure);
  520. }
  521. },
  522. //生命周期 - 挂载完成(可以访问DOM元素)
  523. mounted() {},
  524. beforeCreate() {}, //生命周期 - 创建之前
  525. beforeMount() {}, //生命周期 - 挂载之前
  526. beforeUpdate() {}, //生命周期 - 更新之前
  527. updated() {}, //生命周期 - 更新之后
  528. beforeDestroy() {}, //生命周期 - 销毁之前
  529. destroyed() {}, //生命周期 - 销毁完成
  530. activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
  531. };
  532. </script>
  533. <style lang='scss' scope>
  534. //@import url(); 引入公共css类
  535. .Big-Book-table {
  536. &-content {
  537. &.m {
  538. display: flex;
  539. justify-content: flex-start;
  540. align-items: flex-start;
  541. }
  542. .Big-Book-title {
  543. font-size: 16px;
  544. line-height: 40px;
  545. color: #000;
  546. margin-right: 15px;
  547. }
  548. }
  549. .Big-Book-main {
  550. > div {
  551. margin-bottom: 10px;
  552. &.Big-Book-pinyin {
  553. display: flex;
  554. justify-content: flex-start;
  555. align-items: center;
  556. }
  557. }
  558. }
  559. .addoption {
  560. width: 150px;
  561. height: 40px;
  562. left: 40px;
  563. top: 304px;
  564. background: #f3f3f3;
  565. border: 1px dashed rgba(0, 0, 0, 0.15);
  566. box-sizing: border-box;
  567. border-radius: 4px;
  568. text-align: center;
  569. line-height: 40px;
  570. cursor: pointer;
  571. margin-right: 20px;
  572. }
  573. .Big-Book-divide {
  574. > div {
  575. width: 100%;
  576. }
  577. .answerList {
  578. > div {
  579. margin-top: 16px;
  580. display: flex;
  581. align-items: center;
  582. > :nth-child(1) {
  583. display: inline-block;
  584. width: 100px;
  585. margin-right: 10px;
  586. word-break: break-all;
  587. }
  588. .checkbox-group {
  589. > span {
  590. display: inline-block;
  591. margin-left: 29px;
  592. }
  593. }
  594. }
  595. }
  596. }
  597. .Big-Book-con {
  598. display: flex;
  599. align-items: center;
  600. margin: 15px 0;
  601. img {
  602. width: 24px;
  603. height: 24px;
  604. cursor: pointer;
  605. }
  606. }
  607. .Big-Book-mp3 {
  608. display: flex;
  609. }
  610. .add {
  611. display: flex;
  612. margin-top: 50px;
  613. }
  614. table {
  615. tr {
  616. th {
  617. min-width: 100px;
  618. max-width: 100px;
  619. min-height: 40px;
  620. max-height: 40px;
  621. border: 1px solid black;
  622. text-align: center;
  623. padding: 5px;
  624. word-break: break-all;
  625. overflow: hidden;
  626. text-overflow: ellipsis;
  627. }
  628. td {
  629. min-width: 100px;
  630. max-width: 100px;
  631. height: 42px;
  632. border: 1px solid black;
  633. text-align: center;
  634. padding: 5px;
  635. word-break: break-all;
  636. position: relative;
  637. }
  638. display: flex;
  639. align-items: center;
  640. }
  641. }
  642. }
  643. </style>