tabs组件优化
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user