ConfigurableTable.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. <template>
  2. <div class="config-table">
  3. <table
  4. :style="{
  5. 'box-shadow': `${
  6. curQue.isShadow ? '4px 4px 4px rgba(0, 0, 0, 0.3)' : ''
  7. }`,
  8. border: `${curQue.marginHighlight ? '1.1px solid #949494' : ''}`,
  9. }"
  10. >
  11. <colgroup>
  12. <col
  13. v-for="(col, i) in curQue.tableData.colsConfig.width"
  14. :key="`col-${i}`"
  15. :style="{ width: `${col.val}px` }"
  16. />
  17. </colgroup>
  18. <caption v-if="curQue.isTitle">
  19. {{
  20. curQue.title
  21. }}
  22. </caption>
  23. <thead>
  24. <tr
  25. v-for="({ content }, i) in curQue.tableData.headers"
  26. :key="`thead-${i}`"
  27. :style="{
  28. 'background-color': `${curQue.headerBgColor}`,
  29. }"
  30. >
  31. <template v-for="({ text, colspan, rowspan }, j) in content">
  32. <th
  33. v-if="thIsShow(i, j)"
  34. :key="`th-${i}-${j}`"
  35. :colspan="colspan"
  36. :rowspan="rowspan"
  37. >
  38. {{ text }}
  39. </th>
  40. </template>
  41. </tr>
  42. </thead>
  43. <tbody
  44. :style="{
  45. 'text-align': `${curQue.textAlign}`,
  46. }"
  47. >
  48. <tr v-for="(row, i) in curQue.tableData.body" :key="`tr-${i}`">
  49. <template v-for="(col, j) in row.content">
  50. <td
  51. v-if="tdIsShow(i, j)"
  52. :key="`td-${i}-${j}`"
  53. :colspan="col.colspan"
  54. :rowspan="col.rowspan"
  55. :class="[{ underline: col.isUnderline }]"
  56. :style="{ 'background-color': `${col.background}` }"
  57. >
  58. <div class="cell-wrap">
  59. <template v-if="col.type === 'content'">
  60. <span v-if="col.text.length > 0" class="content">
  61. {{ col.text }}
  62. </span>
  63. <template v-else>
  64. <el-input
  65. v-model="col.answer"
  66. type="textarea"
  67. :placeholder="`${isAnswerMode ? '' : '输入'}`"
  68. :disabled="isAnswerMode"
  69. :autosize="{ minRows: 1, maxRows: 6 }"
  70. @input="enterAnswer(i, j, $event)"
  71. />
  72. </template>
  73. </template>
  74. <div v-else-if="col.type === 'preContent'" class="preContent">
  75. <span>{{ col.prefix }}</span>
  76. <template v-if="col.text.length > 0">
  77. {{ col.text }}
  78. </template>
  79. <template v-else>
  80. <el-input
  81. v-model="col.answer"
  82. type="textarea"
  83. :placeholder="`${isAnswerMode ? '' : '输入'}`"
  84. :disabled="isAnswerMode"
  85. :autosize="{ minRows: 1, maxRows: 6 }"
  86. @input="enterAnswer(i, j, $event)"
  87. />
  88. </template>
  89. </div>
  90. <div
  91. v-else-if="
  92. col.type === 'pinyin' || col.type === 'twoAnnotation'
  93. "
  94. class="sentence"
  95. :style="pinyinStyle"
  96. >
  97. <div>
  98. <span
  99. v-for="({ pinyin, chs }, k) in col.sentence_data
  100. .wordsList"
  101. :key="`${
  102. curQue.pinyinPosition === 'top' ||
  103. curQue.pinyinPosition === 'left'
  104. ? 'pinyin'
  105. : 'chs'
  106. }-${k}`"
  107. :class="[
  108. `${
  109. curQue.pinyinPosition === 'top' ||
  110. curQue.pinyinPosition === 'left'
  111. ? 'pinyin'
  112. : 'chs'
  113. }`,
  114. ]"
  115. >
  116. {{
  117. curQue.pinyinPosition === "top" ||
  118. curQue.pinyinPosition == "left"
  119. ? pinyin
  120. : chs
  121. }}
  122. </span>
  123. <span
  124. v-if="
  125. col.type === 'twoAnnotation' &&
  126. (curQue.pinyinPosition === 'right' ||
  127. curQue.pinyinPosition === 'bottom')
  128. "
  129. class="english"
  130. >
  131. ({{ col.text }})
  132. </span>
  133. </div>
  134. <div>
  135. <span
  136. v-for="({ pinyin, chs }, k) in col.sentence_data
  137. .wordsList"
  138. :key="`${
  139. curQue.pinyinPosition === 'top' ||
  140. curQue.pinyinPosition === 'left'
  141. ? 'chs'
  142. : 'pinyin'
  143. }-${k}`"
  144. :class="[
  145. `${
  146. curQue.pinyinPosition === 'top' ||
  147. curQue.pinyinPosition === 'left'
  148. ? 'chs'
  149. : 'pinyin'
  150. }`,
  151. ]"
  152. >
  153. {{
  154. curQue.pinyinPosition === "top" ||
  155. curQue.pinyinPosition == "left"
  156. ? chs
  157. : pinyin
  158. }}
  159. </span>
  160. <span
  161. v-if="
  162. col.type === 'twoAnnotation' &&
  163. (curQue.pinyinPosition === 'top' ||
  164. curQue.pinyinPosition === 'left')
  165. "
  166. class="english"
  167. >
  168. ({{ col.text }})
  169. </span>
  170. </div>
  171. </div>
  172. <div v-else-if="col.type === 'prePinyin'" class="pre-pinyin">
  173. <span>{{ col.prefix }}</span>
  174. <div
  175. class="right-pinyin"
  176. :style="{
  177. 'grid-template-columns': `repeat(${col.sentence_data.wordsList.length}, auto)`,
  178. }"
  179. >
  180. <span
  181. v-for="({ pinyin }, k) in col.sentence_data.wordsList"
  182. :key="`pre-pinyin-${k}`"
  183. class="pinyin"
  184. >
  185. {{ pinyin }}
  186. </span>
  187. <span
  188. v-for="({ pinyin, chs }, k) in col.sentence_data
  189. .wordsList"
  190. :key="`pre-chs-${k}`"
  191. class="chs"
  192. >
  193. {{ chs }}
  194. </span>
  195. </div>
  196. </div>
  197. <CrossTick v-if="col.isCross" />
  198. </div>
  199. </td>
  200. </template>
  201. </tr>
  202. </tbody>
  203. </table>
  204. </div>
  205. </template>
  206. <script>
  207. import CrossTick from "./HeaderSparate/CrossTick.vue";
  208. export default {
  209. components: { CrossTick },
  210. props: {
  211. curQue: {
  212. type: Object,
  213. required: true,
  214. },
  215. themeColor: {
  216. type: String,
  217. required: true,
  218. },
  219. },
  220. data() {
  221. return {
  222. isAnswerMode: false,
  223. };
  224. },
  225. computed: {
  226. pinyinStyle() {
  227. let pyPos = this.curQue.pinyinPosition;
  228. if (pyPos === "left") {
  229. return {
  230. "column-gap": "16px",
  231. };
  232. }
  233. if (pyPos === "top") {
  234. return {
  235. "flex-direction": "column",
  236. };
  237. }
  238. if (pyPos === "right") {
  239. return {
  240. "column-gap": "16px",
  241. };
  242. }
  243. if (pyPos === "bottom") {
  244. return {
  245. "flex-direction": "column",
  246. };
  247. }
  248. },
  249. },
  250. created() {
  251. const Bookanswer = this.curQue.Bookanswer;
  252. if (Bookanswer) {
  253. this.isAnswerMode = true;
  254. for (const key in Bookanswer) {
  255. let { col, row, value } = Bookanswer[key];
  256. this.curQue.tableData.body[col].content[row].answer = value;
  257. }
  258. } else {
  259. this.$set(this.curQue, "Bookanswer", {});
  260. }
  261. },
  262. methods: {
  263. enterAnswer(i, j, value) {
  264. this.curQue.Bookanswer[`${i}-${j}`] = {
  265. col: i,
  266. row: j,
  267. value,
  268. };
  269. },
  270. // th 是否生成
  271. thIsShow(i, j) {
  272. let headers = this.curQue.tableData.headers;
  273. let col = 1;
  274. let colIndex = headers[i].content.findIndex(({ colspan }, index) => {
  275. if (index > j) return false;
  276. let num = colspan === undefined ? 1 : Number(colspan);
  277. if (num > 1) {
  278. col = num;
  279. return false;
  280. }
  281. if (index === j && col > 1) return true;
  282. if (col > 0) col -= 1;
  283. return false;
  284. });
  285. let row = 1;
  286. let rowIndex = headers.findIndex((item, index) => {
  287. let rowspan = item.content[j].rowspan;
  288. let num = rowspan === undefined ? 1 : Number(rowspan);
  289. if (num > 1) {
  290. row = num;
  291. return false;
  292. }
  293. if (index === i && row > 1) return true;
  294. if (row > 0) row -= 1;
  295. return false;
  296. });
  297. return colIndex === -1 && rowIndex === -1;
  298. },
  299. // rowspan colspan 控制td是否生成
  300. tdIsShow(i, j) {
  301. let body = this.curQue.tableData.body;
  302. let col = 1;
  303. let colIndex = body[i].content.findIndex(({ colspan }, index) => {
  304. if (index > j) return false;
  305. let num = colspan === undefined ? 1 : Number(colspan);
  306. if (num > 1) {
  307. col = num;
  308. return false;
  309. }
  310. if (index === j && col > 1) return true;
  311. if (col > 0) col -= 1;
  312. return false;
  313. });
  314. let row = 1;
  315. let rowIndex = body.findIndex((item, index) => {
  316. let rowspan = item.content[j].rowspan;
  317. let num = rowspan === undefined ? 1 : Number(rowspan);
  318. if (num > 1) {
  319. row = num;
  320. return false;
  321. }
  322. if (index === i && row > 1) return true;
  323. if (row > 0) row -= 1;
  324. return false;
  325. });
  326. return colIndex === -1 && rowIndex === -1;
  327. },
  328. },
  329. };
  330. </script>
  331. <style lang="scss" scoped>
  332. .config-table {
  333. width: 100%;
  334. margin-bottom: 16px;
  335. table {
  336. table-layout: fixed;
  337. font-size: 16px;
  338. color: #404040;
  339. border-collapse: collapse;
  340. caption {
  341. font-size: 20px;
  342. color: #000;
  343. font-weight: bold;
  344. line-height: 1.95;
  345. }
  346. th {
  347. font-family: "FZJCGFKTK", "GB-PINYINOK-B", "robot";
  348. }
  349. th,
  350. td {
  351. font-weight: normal;
  352. border: 1px solid #e6e6e6;
  353. padding: 8px 12px;
  354. }
  355. .thead-merge {
  356. display: flex;
  357. justify-content: space-evenly;
  358. }
  359. .preContent {
  360. font-family: "FZJCGFKTK", "GB-PINYINOK-B", "robot";
  361. display: flex;
  362. align-items: center;
  363. ::v-deep .el-textarea__inner {
  364. padding-top: 2px;
  365. }
  366. }
  367. td {
  368. // min-height: 51px;
  369. // height: 51px;
  370. .cell-wrap {
  371. display: flex;
  372. align-items: center;
  373. justify-content: space-between;
  374. .content {
  375. font-family: "FZJCGFKTK", "GB-PINYINOK-B", "robot";
  376. }
  377. }
  378. .content {
  379. font-family: "FZJCGFKTK", "GB-PINYINOK-B", "robot";
  380. }
  381. .sentence {
  382. display: flex;
  383. .english {
  384. font-family: "robot";
  385. opacity: 0.6;
  386. }
  387. }
  388. .pinyin {
  389. font-family: "GB-PINYINOK-B";
  390. opacity: 0.6;
  391. }
  392. .chs {
  393. font-family: "FZJCGFKTK";
  394. }
  395. // 下划线
  396. &.underline {
  397. text-decoration: underline;
  398. }
  399. // 前缀 + 拼音
  400. .pre-pinyin {
  401. display: flex;
  402. align-items: flex-end;
  403. .right-pinyin {
  404. margin-left: 4px;
  405. column-gap: 2px;
  406. text-align: center;
  407. display: grid;
  408. }
  409. }
  410. }
  411. }
  412. }
  413. </style>