tabs组件优化

This commit is contained in:
Erin66
2026-02-11 00:01:20 +08:00
parent 996d0a5ba5
commit da7d02474f
3 changed files with 201 additions and 139 deletions

View File

@@ -319,6 +319,26 @@
:widget-params-config="widgetParamsConfig"
@onChanged="(val) => widgetValueChanged('setup', val)"
/>
<!-- 如果当前选中的是 Tabs 内部子组件,在配置表单底部显示删除按钮 -->
<div
v-if="innerWidgetSelected"
style="text-align: right; margin-top: 12px;"
>
<el-popconfirm
title="确定删除该子组件吗?"
@onConfirm="deleteInnerWidget"
@confirm="deleteInnerWidget"
>
<el-button
slot="reference"
type="danger"
size="mini"
plain
>
删除该子组件
</el-button>
</el-popconfirm>
</div>
</el-tab-pane>
<el-tab-pane
v-if="isNotNull(widgetOptions.data)"
@@ -695,9 +715,9 @@ export default {
const rootIndex = payload.rootWidgetIndex;
const widget = this.widgets[rootIndex];
if (!widget || !widget.value || !widget.value.position) return;
// 选中 Tabs 组件本身,触发蓝色点框和右侧配置
this.innerWidgetSelected = null;
this.widgetIndex = rootIndex;
this.setOptionsOnClickWidget(rootIndex);
this.widgetsClickFocus(rootIndex);
const evt = payload.event;
const workbenchRect = document.getElementById('workbench') && document.getElementById('workbench').getBoundingClientRect();
if (!workbenchRect) return;
@@ -774,12 +794,58 @@ export default {
*/
setOptionsOnClickInnerWidget(payload) {
if (!payload) return;
const { rootWidgetIndex, tabIndex, childIndex, widget } = payload;
console.log('setOptionsOnClickInnerWidget payload:', payload);
const { rootWidgetIndex, tabIndex, childIndex } = payload;
const rootIndex = typeof rootWidgetIndex === "number" ? rootWidgetIndex : 0;
const rootWidget = this.widgets[rootIndex];
if (!rootWidget || !rootWidget.value || !rootWidget.value.setup) return;
if (!rootWidget || !rootWidget.value) return;
// 记录当前选中的内部子组件路径
// 1. 兼容两种存储位置value.setup.tabsList / options.setup 里的 tabsList
const setupObj = rootWidget.value.setup || {};
let tabsList = setupObj.tabsList;
if (!tabsList || !tabsList.length) {
const setupArr = rootWidget.options && rootWidget.options.setup ? rootWidget.options.setup : [];
const tabsItem = setupArr.find(it => it.name === "tabsList");
if (tabsItem && Array.isArray(tabsItem.value)) {
tabsList = tabsItem.value;
}
}
tabsList = tabsList || [];
const targetTab = tabsList[tabIndex];
if (!targetTab || !targetTab.children || !targetTab.children[childIndex]) {
console.warn("Tabs 子组件未找到:", { rootIndex, tabIndex, childIndex, tabsList });
return;
}
let childWidget = targetTab.children[childIndex];
// 2. 确保子组件有 options老数据里可能只有 type + value
if (!childWidget.options) {
try {
const tool = getToolByCode(childWidget.type);
if (tool && tool.options) {
childWidget.options = this.deepClone(tool.options);
} else {
console.warn("未找到子组件 options 配置:", childWidget.type);
}
} catch (e) {
console.error("为子组件补全 options 失败:", e);
}
}
// 3. 用实际 position 回填到 options.position 中,保证坐标表单显示正确
if (childWidget.options && Array.isArray(childWidget.options.position)) {
const pos = (childWidget.value && childWidget.value.position) ? childWidget.value.position : {};
childWidget.options.position.forEach((el) => {
if (pos.hasOwnProperty(el.name)) {
el.value = pos[el.name];
}
});
}
// 4. 记录当前选中的内部子组件路径 & 切换右侧到子组件配置
this.innerWidgetSelected = {
rootWidgetIndex: rootIndex,
tabIndex,
@@ -789,51 +855,53 @@ export default {
this.widgetIndex = rootIndex;
this.activeName = "first";
// 找到真正的子组件对象
const tabsList = (rootWidget.value.setup && rootWidget.value.setup.tabsList) || [];
this.widgetOptions = this.deepClone(childWidget.options || {});
},
/**
* 删除当前选中的 Tabs 内部子组件
*/
deleteInnerWidget() {
if (!this.innerWidgetSelected) return;
const { rootWidgetIndex, tabIndex, childIndex } = this.innerWidgetSelected;
const rootWidget = this.widgets[rootWidgetIndex];
if (!rootWidget || !rootWidget.value) return;
// 永远只操作“真实绑定”的数据rootWidget.value.setup.tabsList
if (!rootWidget.value.setup) {
this.$set(rootWidget.value, "setup", {});
}
if (!Array.isArray(rootWidget.value.setup.tabsList)) {
this.$set(rootWidget.value.setup, "tabsList", []);
}
const tabsList = rootWidget.value.setup.tabsList;
const targetTab = tabsList[tabIndex];
if (!targetTab || !targetTab.children || !targetTab.children[childIndex]) {
return;
}
const childWidget = widget || targetTab.children[childIndex];
if (!targetTab || !targetTab.children || !targetTab.children.length) return;
// 用实际 position 值回填到 options.position 中,保证坐标表单显示正确
if (childWidget.options && Array.isArray(childWidget.options.position)) {
const pos = childWidget.value && childWidget.value.position ? childWidget.value.position : {};
childWidget.options.position.forEach((el) => {
if (pos.hasOwnProperty(el.name)) {
el.value = pos[el.name];
}
});
}
targetTab.children.splice(childIndex, 1);
this.widgetOptions = this.deepClone(childWidget.options);
// 同步回 rootWidget 的 setup / options
rootWidget.value.setup.tabsList = tabsList;
const setupArr = rootWidget.options && rootWidget.options.setup ? rootWidget.options.setup : [];
setupArr.forEach((item) => {
if (item.name === "tabsList") {
item.value = tabsList;
}
});
// 清空内部选中状态,并回到 Tabs 本身配置
this.innerWidgetSelected = null;
this.widgetIndex = rootWidgetIndex;
this.widgetOptions = this.deepClone(rootWidget.options || {});
this.activeName = "first";
},
widgetsClick(event,index) {
console.log("widgetsClick");
// 如果点击发生在 Tabs 组件内部的子组件上,优先选中内部组件
if (event && event.target && event.target.closest) {
const tabChildWrapper = event.target.closest(".tab-child-wrapper");
const tabsRootEl = event.target.closest(".widget-tabs");
if (tabChildWrapper && tabsRootEl) {
const tabIndexAttr = tabChildWrapper.getAttribute("data-tab-index");
const childIndexAttr = tabChildWrapper.getAttribute("data-child-index");
const tabIndex = Number(tabIndexAttr);
const childIndex = Number(childIndexAttr);
if (!isNaN(tabIndex) && !isNaN(childIndex)) {
this.setOptionsOnClickInnerWidget({
rootWidgetIndex: index,
tabIndex,
childIndex,
});
return;
}
}
// 如果只是点击在 Tabs 内容区的空白处,则交给 Tabs 自己内部处理,避免整个 Tabs 组件被选中
const tabContentEl = event.target.closest(".tab-content");
if (tabContentEl && tabsRootEl) {
return;
}
// 如果 Tabs 组件内部点击由 widgetTabs 自己处理,这里只负责选中 Tabs 整体
const rootWidget = this.widgets[index];
if (rootWidget && rootWidget.type === "widget-tabs") {
this.widgetsClickFocus(index);
return;
}
//判断是否按住了Ctrl按钮表示Ctrl多选
let _this = this;