CoursewarePreview.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <template>
  2. <div
  3. class="courserware"
  4. :style="[
  5. {
  6. backgroundImage: data.background_image_url ? `url(${data.background_image_url})` : '',
  7. backgroundSize: data.background_image_url
  8. ? `${data.background_position.width}% ${data.background_position.height}%`
  9. : '',
  10. backgroundPosition: data.background_image_url
  11. ? `${data.background_position.left}% ${data.background_position.top}%`
  12. : '',
  13. },
  14. ]"
  15. >
  16. <template v-for="(row, i) in data.row_list">
  17. <div :key="i" class="row" :style="getMultipleColStyle(i)">
  18. <!-- 列 -->
  19. <template v-for="(col, j) in row.col_list">
  20. <div :key="j" :class="['col', `col-${i}-${j}`]" :style="computedColStyle(col)">
  21. <!-- 网格 -->
  22. <template v-for="(grid, k) in col.grid_list">
  23. <component
  24. :is="previewComponentList[grid.type]"
  25. :id="grid.id"
  26. ref="preview"
  27. :key="k"
  28. :courseware-id="data.courseware_id"
  29. :class="[grid.id]"
  30. :style="{
  31. gridArea: grid.grid_area,
  32. height: grid.height,
  33. }"
  34. />
  35. </template>
  36. </div>
  37. </template>
  38. </div>
  39. </template>
  40. </div>
  41. </template>
  42. <script>
  43. import { previewComponentList } from '@/views/book/courseware/data/bookType';
  44. import { GetBook } from '@/api/book';
  45. export default {
  46. name: 'CoursewarePreview',
  47. provide() {
  48. return {
  49. getDragStatus: () => false,
  50. bookInfo: this.bookInfo,
  51. };
  52. },
  53. props: {
  54. data: {
  55. type: Object,
  56. default: () => ({}),
  57. },
  58. },
  59. data() {
  60. return {
  61. previewComponentList,
  62. bookInfo: {
  63. theme_color: '',
  64. },
  65. };
  66. },
  67. created() {
  68. GetBook({ id: this.$route.query.book_id }).then(({ theme_color }) => {
  69. this.bookInfo.theme_color = theme_color;
  70. });
  71. },
  72. methods: {
  73. getMultipleColStyle(i) {
  74. let row = this.data.row_list[i];
  75. let col = row.col_list;
  76. if (col.length <= 1) {
  77. return {
  78. gridTemplateColumns: '100fr',
  79. };
  80. }
  81. let gridTemplateColumns = row.width_list.join(' ');
  82. return {
  83. gridAutoFlow: 'column',
  84. gridTemplateColumns,
  85. gridTemplateRows: 'auto',
  86. };
  87. },
  88. /**
  89. * 分割整数为多个 1的倍数
  90. * @param {number} num
  91. * @param {number} parts
  92. */
  93. splitInteger(num, parts) {
  94. let base = Math.floor(num / parts);
  95. let arr = Array(parts).fill(base);
  96. let remainder = num - base * parts;
  97. for (let i = 0; remainder > 0; i = (i + 1) % parts) {
  98. arr[i] += 1;
  99. remainder -= 1;
  100. }
  101. return arr;
  102. },
  103. computedColStyle(col) {
  104. const grid = col.grid_list;
  105. let maxCol = 0; // 最大列数
  106. let rowList = new Map();
  107. grid.forEach(({ row }) => {
  108. rowList.set(row, (rowList.get(row) || 0) + 1);
  109. });
  110. let curMaxRow = 0; // 当前数量最大 row 的值
  111. rowList.forEach((value, key) => {
  112. if (value > maxCol) {
  113. maxCol = value;
  114. curMaxRow = key;
  115. }
  116. });
  117. // 计算 grid_template_areas
  118. let gridTemplateAreas = '';
  119. let gridArr = [];
  120. grid.forEach(({ grid_area, row }) => {
  121. if (!gridArr[row - 1]) {
  122. gridArr[row - 1] = [];
  123. }
  124. if (curMaxRow === row) {
  125. gridArr[row - 1].push(`${grid_area}`);
  126. } else {
  127. let filter = grid.filter((item) => item.row === row);
  128. let find = filter.findIndex((item) => item.grid_area === grid_area);
  129. let needNum = maxCol - filter.length; // 需要的数量
  130. let str = '';
  131. if (filter.length === 1) {
  132. str = ` ${grid_area} `.repeat(needNum + 1);
  133. } else {
  134. let arr = this.splitInteger(needNum, filter.length);
  135. str = arr[find] === 0 ? ` ${grid_area} ` : ` ${grid_area} `.repeat(arr[find] + 1);
  136. }
  137. gridArr[row - 1].push(`${str}`);
  138. }
  139. });
  140. gridArr.forEach((item) => {
  141. gridTemplateAreas += `'${item.join(' ')}' `;
  142. });
  143. // 计算 grid_template_columns
  144. let gridTemplateColumns = '';
  145. let max = { row: 0, num: 0 };
  146. grid.forEach(({ row }) => {
  147. // 计算出 row 的哪个值最多
  148. let len = grid.filter((item) => item.row === row).length;
  149. if (max.num < len) {
  150. max.num = len;
  151. max.row = row;
  152. }
  153. });
  154. grid.forEach((item) => {
  155. if (item.row === max.row) {
  156. gridTemplateColumns += `${item.width} `;
  157. }
  158. });
  159. // 计算 grid_template_rows
  160. let gridTemplateRows = '';
  161. // 将 grid 按照 row 分组
  162. let gridMap = new Map();
  163. grid.forEach((item) => {
  164. if (!gridMap.has(item.row)) {
  165. gridMap.set(item.row, []);
  166. }
  167. gridMap.get(item.row).push(item.height);
  168. });
  169. gridMap.forEach((value) => {
  170. if (value.length === 1) {
  171. gridTemplateRows += `${value[0]} `;
  172. } else {
  173. let isAllAuto = value.every((item) => item === 'auto'); // 是否全是 auto
  174. gridTemplateRows += isAllAuto ? 'auto ' : `max(${value.join(', ')}) `;
  175. }
  176. });
  177. return {
  178. width: col.width,
  179. gridTemplateAreas,
  180. gridTemplateColumns,
  181. gridTemplateRows,
  182. };
  183. },
  184. },
  185. };
  186. </script>
  187. <style lang="scss" scoped>
  188. .courserware {
  189. display: flex;
  190. flex-direction: column;
  191. row-gap: 6px;
  192. width: $courseware-width;
  193. min-height: 500px;
  194. padding: 24px;
  195. background-color: #fff;
  196. background-repeat: no-repeat;
  197. border-bottom-right-radius: 12px;
  198. border-bottom-left-radius: 12px;
  199. .row {
  200. display: grid;
  201. gap: 16px;
  202. .col {
  203. display: grid;
  204. gap: 16px;
  205. overflow: hidden;
  206. }
  207. }
  208. }
  209. </style>