|
@@ -9,40 +9,64 @@
|
|
|
<div class="exit">
|
|
|
<el-button icon="el-icon-close" @click="goBack">退出预览</el-button>
|
|
|
</div>
|
|
|
- <div v-for="(data, i) in coursewareDataList" :key="`data-${i}`" class="content">
|
|
|
- <span class="content-title">
|
|
|
- <SvgIcon icon-class="menu-2" size="24" />
|
|
|
- <template v-for="(item, m) in menuList">
|
|
|
- <span :key="m">{{ item }}</span>
|
|
|
- <span v-if="i < menuList.length - 1" :key="`separator-${m}`" class="separator">/</span>
|
|
|
- </template>
|
|
|
- </span>
|
|
|
- <div
|
|
|
- class="courserware"
|
|
|
- :style="[
|
|
|
- {
|
|
|
- backgroundImage: data.background_image_url ? `url(${data.background_image_url})` : '',
|
|
|
- backgroundSize: data.background_image_url
|
|
|
- ? `${data.background_position.width}% ${data.background_position.height}%`
|
|
|
- : '',
|
|
|
- backgroundPosition: data.background_image_url
|
|
|
- ? `${data.background_position.left}% ${data.background_position.top}%`
|
|
|
- : '',
|
|
|
- },
|
|
|
- ]"
|
|
|
- ></div>
|
|
|
- </div>
|
|
|
+ <template v-for="(data, index) in coursewareDataList">
|
|
|
+ <div v-if="data.hasOwnProperty('row_list')" :key="`data-${index}`" class="content">
|
|
|
+ <span class="content-title">
|
|
|
+ <SvgIcon icon-class="menu-2" size="24" />
|
|
|
+ <template v-for="(item, m) in menuList">
|
|
|
+ <span :key="m">{{ item }}</span>
|
|
|
+ <span v-if="index < menuList.length - 1" :key="`separator-${m}`" class="separator">/</span>
|
|
|
+ </template>
|
|
|
+ </span>
|
|
|
+ <!-- 课件 -->
|
|
|
+ <div
|
|
|
+ class="courserware"
|
|
|
+ :style="[
|
|
|
+ {
|
|
|
+ backgroundImage: data.background_image_url ? `url(${data.background_image_url})` : '',
|
|
|
+ backgroundSize: data.background_image_url
|
|
|
+ ? `${data.background_position.width}% ${data.background_position.height}%`
|
|
|
+ : '',
|
|
|
+ backgroundPosition: data.background_image_url
|
|
|
+ ? `${data.background_position.left}% ${data.background_position.top}%`
|
|
|
+ : '',
|
|
|
+ },
|
|
|
+ ]"
|
|
|
+ >
|
|
|
+ <template v-for="(row, i) in data.row_list">
|
|
|
+ <div :key="i" class="row" :style="getMultipleColStyle(index, i)">
|
|
|
+ <!-- 列 -->
|
|
|
+ <template v-for="(col, j) in row.col_list">
|
|
|
+ <div :key="j" :class="['col', `col-${i}-${j}`]" :style="computedColStyle(col)">
|
|
|
+ <!-- 网格 -->
|
|
|
+ <template v-for="(grid, k) in col.grid_list">
|
|
|
+ <component
|
|
|
+ :is="previewComponentMap[grid.type]"
|
|
|
+ :id="grid.id"
|
|
|
+ ref="preview"
|
|
|
+ :key="k"
|
|
|
+ :courseware_id="data.courseware_id"
|
|
|
+ :class="[grid.id]"
|
|
|
+ :style="{
|
|
|
+ gridArea: grid.grid_area,
|
|
|
+ height: grid.height,
|
|
|
+ }"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import {
|
|
|
- GetCoursewareContent,
|
|
|
- GetBookChapterStruct,
|
|
|
- GetCoursewareList_Chapter,
|
|
|
- GetCoursewareComponentContent_View,
|
|
|
-} from '@/api/book';
|
|
|
+import { GetCoursewareContent, GetBookChapterStruct, GetCoursewareList_Chapter } from '@/api/book';
|
|
|
+import { previewComponentMap } from './components/common/data';
|
|
|
|
|
|
import CatalogueTree from '@/views/book/components/catalogueTree.vue';
|
|
|
|
|
@@ -63,6 +87,7 @@ export default {
|
|
|
book_id: this.$route.params.book_id,
|
|
|
chapter_id,
|
|
|
curChapterId: chapter_id,
|
|
|
+ previewComponentMap,
|
|
|
nodes: [],
|
|
|
curPosition: [],
|
|
|
courseware_list: [],
|
|
@@ -77,21 +102,11 @@ export default {
|
|
|
created() {
|
|
|
GetBookChapterStruct({ book_id: this.book_id, node_deep_mode: 0 }).then(({ nodes }) => {
|
|
|
this.nodes = nodes ?? [];
|
|
|
- this.setCurPosition(this.chapter_id);
|
|
|
+ if (this.chapter_id) this.setCurPosition(this.chapter_id);
|
|
|
});
|
|
|
- this.getCoursewareList_Chapter(this.chapter_id);
|
|
|
- this.getCoursewareComponentContent_View();
|
|
|
+ if (this.chapter_id) this.getCoursewareList_Chapter(this.chapter_id);
|
|
|
},
|
|
|
methods: {
|
|
|
- // 获取课件数据
|
|
|
- getCoursewareComponentContent_View() {
|
|
|
- GetCoursewareComponentContent_View({ courseware_id: this.coursewareId, component_id: this.componentId }).then(
|
|
|
- ({ content }) => {
|
|
|
- // if (content) this.file_list = JSON.parse(content).file_list;
|
|
|
- },
|
|
|
- );
|
|
|
- },
|
|
|
-
|
|
|
goBack() {
|
|
|
this.$router.push(`/chapter?chapter_id=${this.chapter_id}&book_id=${this.book_id}`);
|
|
|
},
|
|
@@ -132,14 +147,17 @@ export default {
|
|
|
});
|
|
|
},
|
|
|
async getCoursewareContent() {
|
|
|
- Promise.all(
|
|
|
+ this.coursewareDataList = await Promise.all(
|
|
|
this.courseware_list.map(async ({ courseware_id }) => {
|
|
|
const { content } = await GetCoursewareContent({ id: courseware_id });
|
|
|
- return content ? JSON.parse(content) : {};
|
|
|
+ if (content) {
|
|
|
+ let _content = JSON.parse(content);
|
|
|
+ _content.courseware_id = courseware_id;
|
|
|
+ return _content;
|
|
|
+ }
|
|
|
+ return {};
|
|
|
}),
|
|
|
- ).then((coursewareDataList) => {
|
|
|
- this.coursewareDataList = coursewareDataList;
|
|
|
- });
|
|
|
+ );
|
|
|
},
|
|
|
getNodeName(index) {
|
|
|
let node = this.nodes;
|
|
@@ -151,6 +169,101 @@ export default {
|
|
|
getCatalogueName() {
|
|
|
return this.curPosition.map((item, index) => this.getNodeName(index)).join(' / ');
|
|
|
},
|
|
|
+ getMultipleColStyle(index, i) {
|
|
|
+ let row = this.coursewareDataList[index].row_list[i];
|
|
|
+ let col = row.col_list;
|
|
|
+ if (col.length <= 1) {
|
|
|
+ return {
|
|
|
+ gridTemplateColumns: '100%',
|
|
|
+ };
|
|
|
+ }
|
|
|
+ let str = row.width_list
|
|
|
+ .map((item) => {
|
|
|
+ return `calc(${item} - ${(16 * (row.width_list.length - 1)) / row.width_list.length}px)`;
|
|
|
+ })
|
|
|
+ .join(' 16px ');
|
|
|
+ let gridTemplateColumns = `${str}`;
|
|
|
+
|
|
|
+ return {
|
|
|
+ gridAutoFlow: 'column',
|
|
|
+ gridTemplateColumns,
|
|
|
+ gridTemplateRows: 'auto',
|
|
|
+ };
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 分割整数为多个 1的倍数
|
|
|
+ * @param {number} num
|
|
|
+ * @param {number} parts
|
|
|
+ */
|
|
|
+ splitInteger(num, parts) {
|
|
|
+ let base = Math.floor(num / parts);
|
|
|
+ let arr = Array(parts).fill(base);
|
|
|
+ let remainder = num - base * parts;
|
|
|
+ for (let i = 0; remainder > 0; i = (i + 1) % parts) {
|
|
|
+ arr[i] += 1;
|
|
|
+ remainder -= 1;
|
|
|
+ }
|
|
|
+ return arr;
|
|
|
+ },
|
|
|
+ computedColStyle(col) {
|
|
|
+ const grid = col.grid_list;
|
|
|
+
|
|
|
+ let maxCol = 0; // 最大列数
|
|
|
+ let rowList = new Map();
|
|
|
+ grid.forEach(({ row }) => {
|
|
|
+ rowList.set(row, (rowList.get(row) || 0) + 1);
|
|
|
+ });
|
|
|
+ let curMaxRow = 0; // 当前数量最大 row 的值
|
|
|
+ rowList.forEach((value, key) => {
|
|
|
+ if (value > maxCol) {
|
|
|
+ maxCol = value;
|
|
|
+ curMaxRow = key;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 计算 grid_template_areas
|
|
|
+ let gridTemplateAreas = '';
|
|
|
+ let gridArr = [];
|
|
|
+ grid.forEach(({ grid_area, row }) => {
|
|
|
+ if (!gridArr[row - 1]) {
|
|
|
+ gridArr[row - 1] = [];
|
|
|
+ }
|
|
|
+ if (curMaxRow === row) {
|
|
|
+ gridArr[row - 1].push(`${grid_area}`);
|
|
|
+ } else {
|
|
|
+ let filter = grid.filter((item) => item.row === row);
|
|
|
+ let find = filter.findIndex((item) => item.grid_area === grid_area);
|
|
|
+ let needNum = (maxCol - filter.length) * 3; // 需要的数量
|
|
|
+
|
|
|
+ let str = '';
|
|
|
+ if (filter.length === 1) {
|
|
|
+ str = ` ${grid_area} `.repeat(needNum + 1);
|
|
|
+ } else {
|
|
|
+ let arr = this.splitInteger(needNum, filter.length);
|
|
|
+ str = arr[find] === 0 ? ` ${grid_area} ` : ` ${grid_area} `.repeat(arr[find] + 1);
|
|
|
+ }
|
|
|
+ gridArr[row - 1].push(`${str}`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ gridArr.forEach((item) => {
|
|
|
+ gridTemplateAreas += `'${item.join(' ')}' `;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 计算 grid_template_columns
|
|
|
+ let gridTemplateColumns = '';
|
|
|
+ let rowOneNum = grid.filter((item) => item.row === 1).length;
|
|
|
+ grid.forEach((item) => {
|
|
|
+ if (item.row === 1) {
|
|
|
+ gridTemplateColumns += `calc(${item.width} - ${((rowOneNum - 1) * 16) / rowOneNum}px) `;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ width: col.width,
|
|
|
+ gridTemplateAreas,
|
|
|
+ gridTemplateColumns,
|
|
|
+ gridTemplateRows: `${grid.map(({ height }) => height).join(' ')}`,
|
|
|
+ };
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
@@ -193,9 +306,12 @@ export default {
|
|
|
.content-wrapper {
|
|
|
flex: 1;
|
|
|
padding: 24px 60px;
|
|
|
+ overflow: auto;
|
|
|
background: url('~@/assets/mask_group.png') repeat 0 0;
|
|
|
|
|
|
.exit {
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
|
|
|
@@ -234,23 +350,19 @@ export default {
|
|
|
row-gap: 6px;
|
|
|
width: 100%;
|
|
|
min-height: 500px;
|
|
|
+ padding: 24px;
|
|
|
background-color: #fff;
|
|
|
background-repeat: no-repeat;
|
|
|
border-bottom-right-radius: 12px;
|
|
|
border-bottom-left-radius: 12px;
|
|
|
- }
|
|
|
-
|
|
|
- .navigation {
|
|
|
- margin: -10px 0 0 -24px;
|
|
|
|
|
|
- &-label {
|
|
|
- padding: 18px 24px;
|
|
|
- color: #fff;
|
|
|
- background-color: #f44444;
|
|
|
- border-radius: 16px 0;
|
|
|
+ .row {
|
|
|
+ display: grid;
|
|
|
+ row-gap: 16px;
|
|
|
|
|
|
- .svg-icon {
|
|
|
- margin: 0 22px 0 1px;
|
|
|
+ .col {
|
|
|
+ display: grid;
|
|
|
+ gap: 16px;
|
|
|
}
|
|
|
}
|
|
|
}
|