|
|
@@ -646,6 +646,10 @@ export default {
|
|
|
await Promise.all(comps.map((item) => item.saveCoursewareComponentContent()));
|
|
|
}
|
|
|
|
|
|
+ // 组件内容已按组件自身 id 保存到当前课件,清理仅用于从模板课件取内容的临时标记 oldId,
|
|
|
+ // 否则该课件之后再次被当作模板使用时组件会按陈旧的 oldId 请求而取到空内容
|
|
|
+ this.clearGridOldId();
|
|
|
+
|
|
|
// 再收集并保存页面结构
|
|
|
let component_id_list = this.data.row_list.flatMap((row) =>
|
|
|
row.col_list.flatMap((col) => col.grid_list.map((grid) => grid.id)),
|
|
|
@@ -1579,7 +1583,7 @@ export default {
|
|
|
|
|
|
// 获取子组件
|
|
|
findChildComponentByKey(key) {
|
|
|
- return this.$refs.component.find((child) => child.$vnode.key === key);
|
|
|
+ return (this.$refs.component || []).find((child) => child.$vnode.key === key);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
@@ -1768,11 +1772,15 @@ export default {
|
|
|
* @param {Array} param.backgroundList - 组件背景列表
|
|
|
*/
|
|
|
async loadTemplateData_CreateCanvas({ data, content_group_row_list, backgroundList }) {
|
|
|
- this.data = data || {
|
|
|
- row_list: [],
|
|
|
- };
|
|
|
- this.content_group_row_list = content_group_row_list || [];
|
|
|
- await this.insertComponentBackground(data.row_list, backgroundList, 'id');
|
|
|
+ // 深拷贝:避免与「选择模板」弹窗缓存的模板数据共享引用(否则画布改动会污染模板数据)
|
|
|
+ const templateData = _.cloneDeep(data) || { row_list: [] };
|
|
|
+ if (!Array.isArray(templateData.row_list)) templateData.row_list = [];
|
|
|
+ this.data = templateData;
|
|
|
+ // 分组行列表同样深拷贝:归一化时会直接改写其中的 is_pre_same_group
|
|
|
+ this.content_group_row_list = _.cloneDeep(content_group_row_list) || [];
|
|
|
+ // 清空模板数据中残留的 oldId,避免按陈旧的来源组件 id 取到错误内容
|
|
|
+ this.clearGridOldId(this.data.row_list);
|
|
|
+ await this.insertComponentBackground(this.data.row_list, backgroundList, 'id');
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
@@ -1784,22 +1792,29 @@ export default {
|
|
|
*/
|
|
|
async insertTemplateData_CreateCanvas({ row_list = [], content_group_row_list = [], backgroundList = [] }) {
|
|
|
let contentGroupRowList = JSON.parse(JSON.stringify(content_group_row_list));
|
|
|
+ // 插入的内容保持独立分组,不并入插入位置上方的分组(模板数据异常时兜底)
|
|
|
+ if (contentGroupRowList.length > 0) contentGroupRowList[0].is_pre_same_group = false;
|
|
|
|
|
|
- let rowList = row_list.map((row) => {
|
|
|
+ // 深拷贝后再改写 id:直接改写会污染「选择模板」弹窗缓存的模板数据,
|
|
|
+ // 导致同一模板连续插入两次时把同一批对象重复放进 row_list(重复 key / 重复组件 id / oldId 被覆盖)
|
|
|
+ let rowList = _.cloneDeep(row_list).map((row) => {
|
|
|
const oldRowID = row.row_id;
|
|
|
const newRowID = `R${getRandomNumber(6, true)}`;
|
|
|
row.row_id = newRowID;
|
|
|
// 更新内容分组行列表中的 row_id
|
|
|
- for (let idx = 0; idx < contentGroupRowList.length; idx++) {
|
|
|
- if (contentGroupRowList[idx].row_id === oldRowID) {
|
|
|
- contentGroupRowList[idx] = { ...contentGroupRowList[idx], row_id: newRowID };
|
|
|
+ if (oldRowID) {
|
|
|
+ for (let idx = 0; idx < contentGroupRowList.length; idx++) {
|
|
|
+ if (contentGroupRowList[idx].row_id === oldRowID) {
|
|
|
+ contentGroupRowList[idx] = { ...contentGroupRowList[idx], row_id: newRowID };
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- row.col_list = row.col_list.map((col) => {
|
|
|
+ row.col_list = (row.col_list || []).map((col) => {
|
|
|
col.col_id = `C${getRandomNumber(8, true)}`;
|
|
|
|
|
|
- col.grid_list = col.grid_list.map((grid) => {
|
|
|
+ col.grid_list = (col.grid_list || []).map((grid) => {
|
|
|
+ // oldId 用于子组件从模板课件取组件内容(temporaryCoursewareID + oldId)
|
|
|
grid.oldId = grid.id;
|
|
|
grid.id = this.generateUniqueGridId();
|
|
|
grid.grid_area = `L${getRandomNumber(6, true)}`;
|
|
|
@@ -1812,22 +1827,52 @@ export default {
|
|
|
});
|
|
|
|
|
|
const curId = this.getCurSettingId();
|
|
|
- // 如果无选中组件,则插入到最后
|
|
|
- if (!curId) {
|
|
|
+ if (curId) {
|
|
|
+ // 插入到当前选中组件后面
|
|
|
+ const attrs = this.findChildComponentByKey(`grid-${curId}`)?.$attrs;
|
|
|
+ if (!attrs) return;
|
|
|
+ const i = Number(attrs['data-row']);
|
|
|
+ this.data.row_list.splice(i + 1, 0, ...rowList);
|
|
|
+ this.content_group_row_list.splice(i + 1, 0, ...contentGroupRowList);
|
|
|
+ // 断开插入内容之后那一行的分组,避免模板内容被并入原有分组(与「插入行」的处理保持一致)
|
|
|
+ this.breakGroupFrom(i + 1 + contentGroupRowList.length);
|
|
|
+ } else {
|
|
|
+ // 无选中组件,插入到最后
|
|
|
this.data.row_list.push(...rowList);
|
|
|
this.content_group_row_list.push(...contentGroupRowList);
|
|
|
- await this.insertComponentBackground(rowList, backgroundList);
|
|
|
- return;
|
|
|
}
|
|
|
- // 插入到当前选中组件后面
|
|
|
- const attrs = this.findChildComponentByKey(`grid-${curId}`)?.$attrs;
|
|
|
- if (!attrs) return;
|
|
|
- const i = Number(attrs['data-row']);
|
|
|
- this.data.row_list.splice(i + 1, 0, ...rowList);
|
|
|
- this.content_group_row_list.splice(i + 1, 0, ...contentGroupRowList);
|
|
|
+
|
|
|
await this.insertComponentBackground(rowList, backgroundList);
|
|
|
},
|
|
|
/**
|
|
|
+ * 清除组件上仅用于「从模板课件取内容」的临时标记 oldId
|
|
|
+ * 保存时组件内容已按组件自身 id 写入当前课件,若继续保留 oldId,
|
|
|
+ * 该课件之后再次被当作模板使用时组件会按陈旧的 oldId 请求而取到空内容
|
|
|
+ * @param {Array} row_list - 行列表,默认当前画布的行列表
|
|
|
+ */
|
|
|
+ clearGridOldId(row_list = this.data.row_list) {
|
|
|
+ (row_list || []).forEach((row) => {
|
|
|
+ (row.col_list || []).forEach((col) => {
|
|
|
+ (col.grid_list || []).forEach((grid) => {
|
|
|
+ delete grid.oldId;
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 断开指定下标行与其上一行的分组关系(分组线、边框颜色、保存时的分组都会随之更新)
|
|
|
+ * @param {number} startIndex - 起始下标
|
|
|
+ */
|
|
|
+ breakGroupFrom(startIndex) {
|
|
|
+ for (let i = startIndex; i >= 0 && i < this.content_group_row_list.length; i++) {
|
|
|
+ if (this.content_group_row_list[i].is_pre_same_group) {
|
|
|
+ this.content_group_row_list[i].is_pre_same_group = false;
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
* 插入组件背景
|
|
|
* @param {Array} row_list - 行列表
|
|
|
* @param {Array} backgroundList - 组件背景列表
|
|
|
@@ -1843,7 +1888,8 @@ export default {
|
|
|
const bg = background?.background;
|
|
|
|
|
|
if (bg) {
|
|
|
- this.findChildComponentByKey(`grid-${grid.id}`).background = bg;
|
|
|
+ const component = this.findChildComponentByKey(`grid-${grid.id}`);
|
|
|
+ if (component) component.background = bg;
|
|
|
}
|
|
|
});
|
|
|
});
|