|
@@ -22,7 +22,7 @@
|
|
|
|
|
|
<div class="create-middle">
|
|
|
<div class="create-operation">
|
|
|
- <el-button><SvgIcon icon-class="background-img" />背景图</el-button>
|
|
|
+ <el-button @click="showSetBackground"><SvgIcon icon-class="background-img" />背景图</el-button>
|
|
|
<el-button><SvgIcon icon-class="template" />模板</el-button>
|
|
|
<el-button class="exit-edit">
|
|
|
<span><i class="el-icon-close"></i> 退出编辑</span>
|
|
@@ -36,59 +36,30 @@
|
|
|
</el-button>
|
|
|
</div>
|
|
|
|
|
|
- <main ref="canvas" class="canvas">
|
|
|
- <span class="drag-line" data-row="-1"></span>
|
|
|
- <div v-for="(row, i) in data.row_list" :key="i" class="row">
|
|
|
- <div
|
|
|
- v-for="(col, j) in row.col_list"
|
|
|
- :key="j"
|
|
|
- class="col"
|
|
|
- :style="{
|
|
|
- width: col.width,
|
|
|
- gridTemplateAreas: col.grid_template_areas,
|
|
|
- gridTemplateColumns: col.grid_template_columns,
|
|
|
- gridTemplateRows: col.grid_template_rows,
|
|
|
- }"
|
|
|
- >
|
|
|
- <template v-for="(grid, k) in col.grid_list">
|
|
|
- <span
|
|
|
- v-if="k === 0"
|
|
|
- :key="`start-${k}`"
|
|
|
- class="drag-vertical-line"
|
|
|
- :data-row="i"
|
|
|
- :data-col="j"
|
|
|
- :data-grid="k"
|
|
|
- ></span>
|
|
|
- <component
|
|
|
- :is="componentList[grid.type]"
|
|
|
- :id="grid.id"
|
|
|
- ref="component"
|
|
|
- :key="k"
|
|
|
- :style="{ gridArea: grid.grid_area }"
|
|
|
- @showSetting="showSetting"
|
|
|
- />
|
|
|
- <span :key="`end-${k}`" class="drag-vertical-line" :data-row="i" :data-col="j" :data-grid="k + 1"></span>
|
|
|
- </template>
|
|
|
- </div>
|
|
|
- <span class="drag-line" :data-row="i"></span>
|
|
|
- </div>
|
|
|
- </main>
|
|
|
+ <CreateCanvas ref="createCanvas" @showSetting="showSetting" />
|
|
|
</div>
|
|
|
|
|
|
<div class="create-right">
|
|
|
<div class="setting-tittle">设置</div>
|
|
|
<component :is="componentSettingList[curSettingType]" ref="setting" />
|
|
|
</div>
|
|
|
+
|
|
|
+ <SelectBackground :visible.sync="visible" @setBackgroundImage="setBackgroundImage" />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { bookTypeOption, componentList, componentSettingList } from '../data/bookType';
|
|
|
-import { getRandomNumber } from '@/utils/index';
|
|
|
-import { SaveCoursewareContent, GetCoursewareContent } from '@/api/book';
|
|
|
+import { bookTypeOption, componentSettingList } from '../data/bookType';
|
|
|
+
|
|
|
+import CreateCanvas from './components/createCanvas.vue';
|
|
|
+import SelectBackground from './components/SelectBackground.vue';
|
|
|
|
|
|
export default {
|
|
|
name: 'CreatePage',
|
|
|
+ components: {
|
|
|
+ CreateCanvas,
|
|
|
+ SelectBackground,
|
|
|
+ },
|
|
|
provide() {
|
|
|
return {
|
|
|
getCurSettingId: () => this.curSettingId,
|
|
@@ -102,97 +73,26 @@ export default {
|
|
|
courseware_id: this.$route.params.courseware_id,
|
|
|
book_id,
|
|
|
chapter_id,
|
|
|
- data: {
|
|
|
- background_image_url: '',
|
|
|
- background_position: {
|
|
|
- x: 0,
|
|
|
- y: 0,
|
|
|
- width: 100,
|
|
|
- height: 100,
|
|
|
- },
|
|
|
- // 组件列表
|
|
|
- row_list: [],
|
|
|
- },
|
|
|
curSettingType: '',
|
|
|
curSettingId: '',
|
|
|
- curType: 'divider',
|
|
|
- componentList,
|
|
|
componentSettingList,
|
|
|
bookTypeOption,
|
|
|
- curRow: -2,
|
|
|
- curCol: -1,
|
|
|
- curGrid: -1,
|
|
|
- enterCanvas: false, // 是否进入画布
|
|
|
- // 拖拽状态
|
|
|
- drag: {
|
|
|
- clientX: 0,
|
|
|
- clientY: 0,
|
|
|
- dragging: false,
|
|
|
- },
|
|
|
+ visible: false,
|
|
|
};
|
|
|
},
|
|
|
- watch: {
|
|
|
- drag: {
|
|
|
- handler(val) {
|
|
|
- if (val.dragging) {
|
|
|
- const dragging = document.querySelector('.dragging');
|
|
|
- dragging.style.left = `${val.clientX}px`;
|
|
|
- dragging.style.top = `${val.clientY}px`;
|
|
|
- }
|
|
|
- },
|
|
|
- deep: true,
|
|
|
- },
|
|
|
- enterCanvas: {
|
|
|
- handler(val) {
|
|
|
- if (val) return;
|
|
|
- const dragLineList = document.querySelectorAll('.drag-line');
|
|
|
- dragLineList.forEach((item) => {
|
|
|
- item.style.opacity = 0;
|
|
|
- });
|
|
|
- this.curRow = -2;
|
|
|
- const dragVerticalLineList = document.querySelectorAll('.drag-vertical-line');
|
|
|
- dragVerticalLineList.forEach((item) => {
|
|
|
- item.style.opacity = 0;
|
|
|
- });
|
|
|
- this.curCol = -1;
|
|
|
- this.curGrid = -1;
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- created() {
|
|
|
- GetCoursewareContent({ id: this.courseware_id }).then(({ content }) => {
|
|
|
- if (content) this.data = JSON.parse(content);
|
|
|
- });
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- document.addEventListener('mousemove', this.dragMove);
|
|
|
- document.addEventListener('mouseup', this.dragEnd);
|
|
|
- },
|
|
|
- beforeDestroy() {
|
|
|
- document.removeEventListener('mousemove', this.dragMove);
|
|
|
- document.removeEventListener('mouseup', this.dragEnd);
|
|
|
- },
|
|
|
+
|
|
|
methods: {
|
|
|
back() {
|
|
|
this.$router.push({ path: '/chapter', query: { chapter_id: this.chapter_id, book_id: this.book_id } });
|
|
|
},
|
|
|
+ dragStart(event, type) {
|
|
|
+ this.$refs.createCanvas.dragStart(event, type);
|
|
|
+ },
|
|
|
saveCoursewareContent() {
|
|
|
- let component_id_list = this.data.row_list.flatMap((row) =>
|
|
|
- row.col_list.flatMap((col) => col.grid_list.map((grid) => grid.id)),
|
|
|
- );
|
|
|
-
|
|
|
- this.$refs.component.forEach((item) => {
|
|
|
- item.saveCoursewareComponentContent();
|
|
|
- });
|
|
|
-
|
|
|
- SaveCoursewareContent({
|
|
|
- id: this.courseware_id,
|
|
|
- category: 'NEW',
|
|
|
- content: JSON.stringify(this.data),
|
|
|
- component_id_list,
|
|
|
- }).then(() => {
|
|
|
- this.$message.success('保存成功');
|
|
|
- });
|
|
|
+ this.$refs.createCanvas.saveCoursewareContent();
|
|
|
+ },
|
|
|
+ showSetBackground() {
|
|
|
+ this.visible = true;
|
|
|
},
|
|
|
/**
|
|
|
* 显示设置
|
|
@@ -206,184 +106,8 @@ export default {
|
|
|
this.$refs.setting.setSetting(setting);
|
|
|
});
|
|
|
},
|
|
|
- /**
|
|
|
- * 拖拽开始
|
|
|
- * 用点击模拟拖拽
|
|
|
- * @param {MouseEvent} event
|
|
|
- * @param {string} type
|
|
|
- */
|
|
|
- dragStart(event, type) {
|
|
|
- // 获取鼠标位置
|
|
|
- const { clientX, clientY } = event;
|
|
|
- document.body.style.userSelect = 'none'; // 禁止选中文本
|
|
|
- this.drag.dragging = true;
|
|
|
- this.curType = type;
|
|
|
- // 在鼠标位置创建一个拖拽元素
|
|
|
- const dragging = document.createElement('div');
|
|
|
- dragging.className = 'dragging';
|
|
|
- this.drag.clientX = clientX;
|
|
|
- this.drag.clientY = clientY;
|
|
|
- document.body.appendChild(dragging);
|
|
|
- },
|
|
|
- /**
|
|
|
- * 鼠标移动
|
|
|
- */
|
|
|
- dragMove(event) {
|
|
|
- if (!this.drag.dragging) return;
|
|
|
-
|
|
|
- const { clientX, clientY } = event;
|
|
|
- this.drag.clientX = clientX;
|
|
|
- this.drag.clientY = clientY;
|
|
|
-
|
|
|
- let { isInsideCanvas } = this.getMarginDifferences();
|
|
|
-
|
|
|
- this.enterCanvas = isInsideCanvas;
|
|
|
- if (!isInsideCanvas) return;
|
|
|
-
|
|
|
- this.showRecentLine(clientX, clientY);
|
|
|
- },
|
|
|
- /**
|
|
|
- * 显示最近的线
|
|
|
- * @param {number} clientX
|
|
|
- * @param {number} clientY
|
|
|
- */
|
|
|
- showRecentLine(clientX, clientY) {
|
|
|
- const dragLineList = document.querySelectorAll('.drag-line'); // 获取所有的横线
|
|
|
- const dragVerticalLineList = document.querySelectorAll('.drag-vertical-line'); // 获取所有的竖线
|
|
|
- let minDistance = Infinity;
|
|
|
- let minIndex = -1;
|
|
|
- const list = [...dragLineList, ...dragVerticalLineList];
|
|
|
-
|
|
|
- list.forEach((item, index) => {
|
|
|
- const rect = item.getBoundingClientRect();
|
|
|
- const distance = Math.sqrt(
|
|
|
- Math.pow(clientX - rect.left - rect.width / 2, 2) + Math.pow(clientY - rect.top - rect.height / 2, 2),
|
|
|
- );
|
|
|
- if (distance < minDistance) {
|
|
|
- minDistance = distance;
|
|
|
- minIndex = index;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- list.forEach((item, index) => {
|
|
|
- if (index === minIndex) {
|
|
|
- this.curRow = Number(item.getAttribute('data-row'));
|
|
|
- this.curCol = Number(item.getAttribute('data-col') || -1);
|
|
|
- this.curGrid = Number(item.getAttribute('data-grid') || -1);
|
|
|
-
|
|
|
- item.style.opacity = 1;
|
|
|
- } else {
|
|
|
- item.style.opacity = 0;
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 鼠标松开
|
|
|
- */
|
|
|
- dragEnd() {
|
|
|
- document.body.style.userSelect = 'auto';
|
|
|
- const dragging = document.querySelector('.dragging');
|
|
|
- if (dragging) {
|
|
|
- document.body.removeChild(dragging);
|
|
|
- this.drag.dragging = false;
|
|
|
- }
|
|
|
-
|
|
|
- if (this.enterCanvas) {
|
|
|
- if (this.curRow >= -1 && this.curCol <= -1) {
|
|
|
- this.data.row_list.splice(this.curRow + 1, 0, this.calculateRowInsertedObject());
|
|
|
- }
|
|
|
- if (this.curRow >= -1 && this.curCol > -1 && this.curGrid > -1) {
|
|
|
- this.calculateColObject();
|
|
|
- }
|
|
|
- }
|
|
|
- this.enterCanvas = false;
|
|
|
- },
|
|
|
- /**
|
|
|
- * 计算列插入的对象
|
|
|
- */
|
|
|
- calculateColObject() {
|
|
|
- let num = 0; // 计算当前行之前的所有 grid_list 的数量
|
|
|
- for (let i = 0; i <= this.curRow; i++) {
|
|
|
- this.data.row_list[i]?.col_list.forEach((item) => {
|
|
|
- num += item.grid_list.length;
|
|
|
- });
|
|
|
- }
|
|
|
- const id = getRandomNumber(12);
|
|
|
- const letter = String.fromCharCode(65 + num);
|
|
|
- let col = this.data.row_list[this.curRow].col_list[this.curCol];
|
|
|
-
|
|
|
- col.grid_list.splice(this.curGrid, 0, {
|
|
|
- id,
|
|
|
- grid_area: letter,
|
|
|
- type: this.curType,
|
|
|
- });
|
|
|
-
|
|
|
- let grid_template_columns = '0';
|
|
|
- col.grid_list.forEach((item, i) => {
|
|
|
- if (i === col.grid_list.length - 1) grid_template_columns += ' auto 0';
|
|
|
- else grid_template_columns += ' auto 16px';
|
|
|
- });
|
|
|
- col.grid_template_columns = grid_template_columns;
|
|
|
-
|
|
|
- let grid_template_areas = '.';
|
|
|
- col.grid_list.forEach(({ grid_area }) => {
|
|
|
- grid_template_areas += ` ${grid_area} .`;
|
|
|
- });
|
|
|
- col.grid_template_areas = `"${grid_template_areas}"`;
|
|
|
- },
|
|
|
- /**
|
|
|
- * 计算行插入的对象
|
|
|
- */
|
|
|
- calculateRowInsertedObject() {
|
|
|
- let num = 0; // 计算当前行之前的所有 grid_list 的数量
|
|
|
- for (let i = 0; i <= this.curRow; i++) {
|
|
|
- this.data.row_list[i]?.col_list.forEach((item) => {
|
|
|
- num += item.grid_list.length;
|
|
|
- });
|
|
|
- }
|
|
|
- const id = getRandomNumber(12);
|
|
|
- const letter = String.fromCharCode(65 + num);
|
|
|
-
|
|
|
- return {
|
|
|
- col_list: [
|
|
|
- {
|
|
|
- width: '100%',
|
|
|
- grid_template_areas: `'. ${letter} .'`,
|
|
|
- grid_template_columns: '0 auto 0',
|
|
|
- grid_template_rows: 'auto',
|
|
|
- grid_list: [
|
|
|
- {
|
|
|
- id,
|
|
|
- grid_area: letter,
|
|
|
- type: this.curType,
|
|
|
- },
|
|
|
- ],
|
|
|
- },
|
|
|
- ],
|
|
|
- };
|
|
|
- },
|
|
|
- /**
|
|
|
- * 获取拖拽元素和画布的边距差值
|
|
|
- * @returns {object} { leftMarginDifference, topMarginDifference, isInsideCanvas }
|
|
|
- * leftMarginDifference: 拖拽元素和画布左边距差值
|
|
|
- * topMarginDifference: 拖拽元素和画布上边距差值
|
|
|
- * isInsideCanvas: 是否在画布内
|
|
|
- */
|
|
|
- getMarginDifferences() {
|
|
|
- const rect1 = document.querySelector('.dragging').getBoundingClientRect();
|
|
|
- const rect2 = this.$refs.canvas.getBoundingClientRect();
|
|
|
-
|
|
|
- const leftMarginDifference = rect1.left - rect2.left + 128;
|
|
|
- const topMarginDifference = rect1.top - rect2.top + 72;
|
|
|
-
|
|
|
- let isInsideCanvas =
|
|
|
- leftMarginDifference > 0 &&
|
|
|
- leftMarginDifference < rect2.width &&
|
|
|
- topMarginDifference > 0 &&
|
|
|
- topMarginDifference < rect2.height;
|
|
|
-
|
|
|
- return { leftMarginDifference, topMarginDifference, isInsideCanvas };
|
|
|
+ setBackgroundImage(...data) {
|
|
|
+ this.$refs.createCanvas.setBackgroundImage(...data);
|
|
|
},
|
|
|
},
|
|
|
};
|
|
@@ -491,57 +215,6 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- .canvas {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- row-gap: 6px;
|
|
|
- width: 100%;
|
|
|
- min-height: calc(100% - 56px);
|
|
|
- padding: 24px;
|
|
|
- background-color: #fff;
|
|
|
- border-radius: 4px;
|
|
|
-
|
|
|
- .row {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- row-gap: 6px;
|
|
|
-
|
|
|
- .col {
|
|
|
- display: grid;
|
|
|
-
|
|
|
- .drag-vertical-line:first-child {
|
|
|
- left: -8px;
|
|
|
- }
|
|
|
-
|
|
|
- .drag-vertical-line:not(:first-child, :last-child) {
|
|
|
- left: 6px;
|
|
|
- }
|
|
|
-
|
|
|
- .drag-vertical-line:last-child {
|
|
|
- right: -4px;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .drag-line {
|
|
|
- width: calc(100% - 16px);
|
|
|
- height: 4px;
|
|
|
- margin: 0 8px;
|
|
|
- background-color: #379fff;
|
|
|
- border-radius: 4px;
|
|
|
- opacity: 0;
|
|
|
- }
|
|
|
-
|
|
|
- .drag-vertical-line {
|
|
|
- position: relative;
|
|
|
- width: 4px;
|
|
|
- height: 100%;
|
|
|
- background-color: #379fff;
|
|
|
- border-radius: 4px;
|
|
|
- opacity: 0;
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
&-right {
|
|
@@ -559,17 +232,6 @@ export default {
|
|
|
</style>
|
|
|
|
|
|
<style lang="scss">
|
|
|
-.dragging {
|
|
|
- position: fixed;
|
|
|
- z-index: 999;
|
|
|
- width: 320px;
|
|
|
- height: 180px;
|
|
|
- background-color: #eaf5ff;
|
|
|
- border: 1px solid #b5dbff;
|
|
|
- border-radius: 4px;
|
|
|
- transform: translate(-40%, -40%);
|
|
|
-}
|
|
|
-
|
|
|
.save-popover {
|
|
|
width: 100px;
|
|
|
min-width: 100px;
|