|
|
@@ -372,120 +372,113 @@ export default {
|
|
|
* @returns {Object} 列的样式对象
|
|
|
*/
|
|
|
computedColStyle(col) {
|
|
|
- const grid = col.grid_list;
|
|
|
+ const grid = col.grid_list || [];
|
|
|
+ if (grid.length === 0) {
|
|
|
+ return {
|
|
|
+ width: col.width,
|
|
|
+ gridTemplateAreas: '',
|
|
|
+ gridTemplateColumns: '',
|
|
|
+ gridTemplateRows: '',
|
|
|
+ };
|
|
|
+ }
|
|
|
|
|
|
- let maxCol = 0; // 最大列数
|
|
|
- let rowList = new Map();
|
|
|
- grid.forEach(({ row }) => {
|
|
|
- rowList.set(row, (rowList.get(row) || 0) + 1);
|
|
|
+ // 先按 row 分组,避免后续重复 filter 扫描
|
|
|
+ const rowMap = new Map();
|
|
|
+ grid.forEach((item) => {
|
|
|
+ if (!rowMap.has(item.row)) {
|
|
|
+ rowMap.set(item.row, []);
|
|
|
+ }
|
|
|
+ rowMap.get(item.row).push(item);
|
|
|
});
|
|
|
- let curMaxRow = 0; // 当前数量最大 row 的值
|
|
|
- rowList.forEach((value, key) => {
|
|
|
- if (value > maxCol) {
|
|
|
- maxCol = value;
|
|
|
- curMaxRow = key;
|
|
|
+
|
|
|
+ let maxCol = 0;
|
|
|
+ let curMaxRow = 0;
|
|
|
+ rowMap.forEach((items, row) => {
|
|
|
+ if (items.length > maxCol) {
|
|
|
+ maxCol = items.length;
|
|
|
+ curMaxRow = row;
|
|
|
}
|
|
|
});
|
|
|
+
|
|
|
// 计算 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}`);
|
|
|
+ rowMap.forEach((items, row) => {
|
|
|
+ let rowAreas = [];
|
|
|
+ if (row === curMaxRow) {
|
|
|
+ rowAreas = items.map((item) => item.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; // 需要的数量
|
|
|
-
|
|
|
- let str = '';
|
|
|
- if (filter.length === 1) {
|
|
|
- str = ` ${grid_area} `.repeat(needNum + 1);
|
|
|
+ const needNum = maxCol - items.length;
|
|
|
+ if (items.length === 1) {
|
|
|
+ rowAreas = Array(needNum + 1).fill(items[0].grid_area);
|
|
|
} else {
|
|
|
- let arr = this.splitInteger(needNum, filter.length);
|
|
|
- str = arr[find] === 0 ? ` ${grid_area} ` : ` ${grid_area} `.repeat(arr[find] + 1);
|
|
|
+ const splitArr = this.splitInteger(needNum, items.length);
|
|
|
+ rowAreas = items.flatMap((item, index) => Array(splitArr[index] + 1).fill(item.grid_area));
|
|
|
}
|
|
|
- gridArr[row - 1].push(`${str}`);
|
|
|
}
|
|
|
- });
|
|
|
- gridArr.forEach((item) => {
|
|
|
- gridTemplateAreas += `'${item.join(' ')}' `;
|
|
|
+ gridTemplateAreas += `'${rowAreas.join(' ')}' `;
|
|
|
});
|
|
|
|
|
|
// 计算 grid_template_columns
|
|
|
- let gridTemplateColumns = '';
|
|
|
- let max = { row: 0, num: 0 };
|
|
|
- grid.forEach(({ row }) => {
|
|
|
- // 计算出 row 的哪个值最多
|
|
|
- let len = grid.filter((item) => item.row === row).length;
|
|
|
- if (max.num < len) {
|
|
|
- max.num = len;
|
|
|
- max.row = row;
|
|
|
- }
|
|
|
- });
|
|
|
- grid.forEach((item) => {
|
|
|
- if (item.row === max.row) {
|
|
|
- gridTemplateColumns += `${item.width} `;
|
|
|
- }
|
|
|
- });
|
|
|
+ const maxRowItems = rowMap.get(curMaxRow) || [];
|
|
|
+ const gridTemplateColumns = maxRowItems.length ? `${maxRowItems.map((item) => item.width).join(' ')} ` : '';
|
|
|
|
|
|
// 计算 grid_template_rows
|
|
|
- let gridTemplateRows = '';
|
|
|
- // 将 grid 按照 row 分组
|
|
|
- let gridMap = new Map();
|
|
|
- grid.forEach((item) => {
|
|
|
- if (!gridMap.has(item.row)) {
|
|
|
- gridMap.set(item.row, []);
|
|
|
+ const previewById = new Map();
|
|
|
+ (this.$refs.preview || []).forEach((child) => {
|
|
|
+ const id = child?.$el?.dataset?.id;
|
|
|
+ if (id) {
|
|
|
+ previewById.set(id, child);
|
|
|
}
|
|
|
- gridMap.get(item.row).push({ height: item.height, id: item.id });
|
|
|
});
|
|
|
+ const hasOperationById = (id) => {
|
|
|
+ const component = previewById.get(id);
|
|
|
+ return Boolean(component && component.$el.querySelector('.operation'));
|
|
|
+ };
|
|
|
+ const toNumberHeight = (height) => {
|
|
|
+ const num = Number(String(height).replace('px', ''));
|
|
|
+ return Number.isFinite(num) ? num : NaN;
|
|
|
+ };
|
|
|
|
|
|
- gridMap.forEach((value) => {
|
|
|
- if (value.length === 1) {
|
|
|
- const component = this.$refs.preview?.find(
|
|
|
- (child) => child.$el && child.$el.dataset && child.$el.dataset.id === value[0].id,
|
|
|
- );
|
|
|
+ let gridTemplateRows = '';
|
|
|
+ rowMap.forEach((items) => {
|
|
|
+ if (items.length === 1) {
|
|
|
+ const current = items[0];
|
|
|
+ if (current.height === 'auto') {
|
|
|
+ gridTemplateRows += 'auto ';
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let baseHeight = toNumberHeight(current.height);
|
|
|
+ if (Number.isNaN(baseHeight)) {
|
|
|
+ gridTemplateRows += `${current.height} `;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (hasOperationById(current.id)) {
|
|
|
+ baseHeight += 48;
|
|
|
+ }
|
|
|
+ gridTemplateRows += `${baseHeight}px `;
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- const hasOperation = component && component.$el.querySelector('.operation') !== null; // 判断是否有操作按钮
|
|
|
- let height = hasOperation ? `${Number(value[0].height.replace('px', '')) + 48}px` : value[0].height;
|
|
|
+ const nonAutoItems = items.filter((item) => item.height !== 'auto');
|
|
|
+ if (nonAutoItems.length === 0) {
|
|
|
+ gridTemplateRows += 'auto ';
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- gridTemplateRows += `${height} `;
|
|
|
- } else {
|
|
|
- let isAllAuto = value.every((item) => item.height === 'auto'); // 是否全是 auto
|
|
|
- if (!isAllAuto) {
|
|
|
- // 判断 value 中height 最大的组件是那个,不包括 auto 的组件
|
|
|
- let maxHeight = 0;
|
|
|
- let maxId = '';
|
|
|
- value.forEach((item) => {
|
|
|
- if (item.height !== 'auto') {
|
|
|
- const heightNum = Number(item.height.replace('px', ''));
|
|
|
- if (heightNum > maxHeight) {
|
|
|
- maxHeight = heightNum;
|
|
|
- maxId = item.id;
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- // 判断最高组件是否有操作按钮
|
|
|
- const component = this.$refs.preview?.find(
|
|
|
- (child) => child.$el && child.$el.dataset && child.$el.dataset.id === maxId,
|
|
|
- );
|
|
|
- const hasOperation = component && component.$el.querySelector('.operation') !== null; // 判断是否有操作按钮
|
|
|
- if (hasOperation) {
|
|
|
- maxHeight += 48;
|
|
|
- }
|
|
|
- // 将 maxId 的 height 设置为 maxHeight
|
|
|
- value.forEach((item) => {
|
|
|
- if (item.id === maxId) {
|
|
|
- item.height = `${maxHeight}px`;
|
|
|
- }
|
|
|
- });
|
|
|
+ let maxItem = null;
|
|
|
+ let maxHeight = 0;
|
|
|
+ nonAutoItems.forEach((item) => {
|
|
|
+ const current = toNumberHeight(item.height);
|
|
|
+ if (!Number.isNaN(current) && current > maxHeight) {
|
|
|
+ maxHeight = current;
|
|
|
+ maxItem = item;
|
|
|
}
|
|
|
- gridTemplateRows += isAllAuto
|
|
|
- ? 'auto '
|
|
|
- : `${Math.max(...value.map((item) => Number(item.height.replace('px', ''))))}px `;
|
|
|
+ });
|
|
|
+
|
|
|
+ if (maxItem && hasOperationById(maxItem.id)) {
|
|
|
+ maxHeight += 48;
|
|
|
}
|
|
|
+ gridTemplateRows += `${maxHeight}px `;
|
|
|
});
|
|
|
|
|
|
return {
|
|
|
@@ -507,30 +500,6 @@ export default {
|
|
|
background: back,
|
|
|
} = this.background || {};
|
|
|
|
|
|
- const hasNoRows = !Array.isArray(this.data?.row_list) || this.data.row_list.length === 0; // 判断是否没有行
|
|
|
- const projectCover = this.project?.cover_image_file_url || '';
|
|
|
-
|
|
|
- // 优先在空行时使用背景图或项目封面
|
|
|
- if (hasNoRows) {
|
|
|
- const backgroundImage = hasNoRows ? bcImgUrl || projectCover : bcImgUrl;
|
|
|
-
|
|
|
- // 保护性读取位置/大小值,避免 undefined 导致字符串 "undefined%"
|
|
|
- const widthPct = typeof pos.width === 'undefined' ? '' : pos.width;
|
|
|
- const heightPct = typeof pos.height === 'undefined' ? '' : pos.height;
|
|
|
- const leftPct = typeof pos.left === 'undefined' ? '' : pos.left;
|
|
|
- const topPct = typeof pos.top === 'undefined' ? '' : pos.top;
|
|
|
-
|
|
|
- const hasBcImg = Boolean(bcImgUrl);
|
|
|
- const backgroundSize = hasBcImg ? `${widthPct}% ${heightPct}%` : hasNoRows ? 'contain' : '';
|
|
|
- const backgroundPosition = hasBcImg ? `${leftPct}% ${topPct}%` : hasNoRows ? 'center' : '';
|
|
|
-
|
|
|
- return {
|
|
|
- backgroundImage: backgroundImage ? `url(${backgroundImage})` : '',
|
|
|
- backgroundSize,
|
|
|
- backgroundPosition,
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
let canvasStyle = {
|
|
|
backgroundSize: bcImgUrl ? `${pos.width}% ${pos.height}%` : '',
|
|
|
backgroundPosition: bcImgUrl ? `${pos.left}% ${pos.top}%` : '',
|
|
|
@@ -961,9 +930,6 @@ export default {
|
|
|
if (!_offset) _offset = 0;
|
|
|
const element = document.querySelector(`div[data-id="${dataId}"]`);
|
|
|
if (element) {
|
|
|
- const elementPosition = element.getBoundingClientRect().top + window.pageYOffset;
|
|
|
- const offsetPosition = elementPosition - _offset;
|
|
|
-
|
|
|
element.scrollIntoView({
|
|
|
behavior: 'smooth', // 滚动行为:'auto' | 'smooth'
|
|
|
block: 'center', // 垂直对齐:'start' | 'center' | 'end' | 'nearest'
|