添加整体拖拽控制流程的功能,优化命令折叠展开功能

This commit is contained in:
fofolee 2025-01-21 16:36:14 +08:00
parent 7d67ef9ae6
commit 020eb2fb06

View File

@ -54,7 +54,7 @@
@remove="removeCommand(index)" @remove="removeCommand(index)"
@run="handleRunCommand" @run="handleRunCommand"
@add-branch="addBranch" @add-branch="addBranch"
@toggle-collapse="(event) => handleControlFlowCollapse(event)" @toggle-collapse="(event) => handleChainCollapse(event)"
@add-command="(event) => handleAddCommand(event, index)" @add-command="(event) => handleAddCommand(event, index)"
@toggle-chain-disable="handleToggleChainDisable" @toggle-chain-disable="handleToggleChainDisable"
/> />
@ -80,6 +80,9 @@ import DropArea from "./flow/DropArea.vue";
import { findCommandByValue } from "js/composer/composerConfig"; import { findCommandByValue } from "js/composer/composerConfig";
import { processVariable } from "js/composer/variableManager"; import { processVariable } from "js/composer/variableManager";
//
let commandsBeforeDrag = [];
export default defineComponent({ export default defineComponent({
name: "ComposerFlow", name: "ComposerFlow",
components: { components: {
@ -115,7 +118,6 @@ export default defineComponent({
dragIndex: -1, dragIndex: -1,
isDragging: false, isDragging: false,
draggedCommand: null, draggedCommand: null,
collapsedRanges: [],
isAllCollapsed: false, isAllCollapsed: false,
}; };
}, },
@ -136,37 +138,72 @@ export default defineComponent({
getPlaceholder(element, index) { getPlaceholder(element, index) {
return element.desc; return element.desc;
}, },
//
onDragStart(event) { onDragStart(event) {
//
commandsBeforeDrag = [...this.commands];
this.isDragging = true; this.isDragging = true;
//
this.draggedCommand = this.commands[event.oldIndex]; this.draggedCommand = this.commands[event.oldIndex];
//
if (this.isFirstCommandInChain(this.draggedCommand)) {
this.handleChainCollapse({
chainId: this.draggedCommand.chainId,
isCollapsed: false,
});
}
}, },
//
onDragEnd() { onDragEnd() {
this.isDragging = false; this.isDragging = false;
this.dragIndex = -1; this.dragIndex = -1;
this.draggedCommand = null; this.draggedCommand = null;
commandsBeforeDrag = [];
}, },
//
onDragChange(event) { onDragChange(event) {
const oldCommands = [...commandsBeforeDrag];
let newCommands = [...this.commands]; let newCommands = [...this.commands];
if (event.moved || event.added) {
//
const isValidOrder = this.checkAllChainOrders(newCommands);
if (!isValidOrder) {
//
if (event.moved) { if (event.moved) {
const { oldIndex, newIndex } = event.moved; const { oldIndex, newIndex } = event.moved;
const [item] = newCommands.splice(newIndex, 1); const draggedCommand = oldCommands[oldIndex];
newCommands.splice(oldIndex, 0, item);
} else if (event.added) { //
const { newIndex } = event.added; let adjustedNewIndex = newIndex;
newCommands.splice(newIndex, 1); for (let i = 0; i < newCommands.length; i++) {
const cmd = newCommands[i];
if (cmd?.chainId && cmd.isCollapsed) {
const { startIndex, endIndex } = this.getChainIndex(
cmd.chainId,
newCommands
);
//
if (newIndex > startIndex && newIndex <= endIndex) {
adjustedNewIndex = endIndex + 1;
break;
} }
} }
} }
if (draggedCommand.chainId) {
newCommands = this.handleChainCommandDrag(
draggedCommand,
oldCommands,
adjustedNewIndex
);
} else {
//
newCommands = oldCommands.filter(
(cmd) => cmd.id !== draggedCommand.id
);
newCommands.splice(adjustedNewIndex, 0, draggedCommand);
}
}
this.$emit("update:modelValue", newCommands); this.$emit("update:modelValue", newCommands);
}, },
//
onDragOver(event) { onDragOver(event) {
if (!this.isDragging) { if (!this.isDragging) {
const items = this.$el.querySelectorAll(".flow-item"); const items = this.$el.querySelectorAll(".flow-item");
@ -175,8 +212,14 @@ export default defineComponent({
// //
let closestIndex = -1; let closestIndex = -1;
let minDistance = Infinity; let minDistance = Infinity;
let lastVisibleIndex = -1;
items.forEach((item, index) => { items.forEach((item, index) => {
//
if (item.classList.contains("collapsed-chain-hidden")) {
return;
}
const itemRect = item.getBoundingClientRect(); const itemRect = item.getBoundingClientRect();
const itemCenter = itemRect.top + itemRect.height / 2; const itemCenter = itemRect.top + itemRect.height / 2;
const distance = Math.abs(mouseY - itemCenter); const distance = Math.abs(mouseY - itemCenter);
@ -185,50 +228,44 @@ export default defineComponent({
minDistance = distance; minDistance = distance;
closestIndex = index; closestIndex = index;
} }
lastVisibleIndex = index;
}); });
// //
const lastItem = items[items.length - 1]; if (closestIndex !== -1) {
if (lastItem && mouseY > lastItem.getBoundingClientRect().bottom) { const command = this.commands[closestIndex];
if (command?.chainId && command.isCollapsed) {
//
const { endIndex } = this.getChainIndex(command.chainId);
//
const closestItem = items[closestIndex];
const itemRect = closestItem.getBoundingClientRect();
const itemCenter = itemRect.top + itemRect.height / 2;
if (mouseY > itemCenter) {
closestIndex = endIndex + 1;
}
}
}
//
const lastVisibleItem = items[lastVisibleIndex];
if (
lastVisibleItem &&
mouseY > lastVisibleItem.getBoundingClientRect().bottom
) {
closestIndex = this.commands.length; closestIndex = this.commands.length;
} }
this.dragIndex = closestIndex; this.dragIndex = closestIndex;
} }
}, },
//
onDragLeave() { onDragLeave() {
if (!this.isDragging) { if (!this.isDragging) {
this.dragIndex = -1; this.dragIndex = -1;
} }
}, },
checkAllChainOrders(commands) { //
// chainId
const chainGroups = commands.reduce((groups, cmd) => {
if (cmd.chainId) {
if (!groups[cmd.chainId]) {
groups[cmd.chainId] = [];
}
groups[cmd.chainId].push(cmd);
}
return groups;
}, {});
// true
if (Object.keys(chainGroups).length === 0) return true;
//
return Object.values(chainGroups).every((chainCommands) => {
const commandChain = chainCommands[0].commandChain;
const firstCommand = chainCommands[0];
const lastCommand = chainCommands[chainCommands.length - 1];
// chainchainCommands
if (firstCommand.commandType !== commandChain[0]) return false;
// chainCommands
if (lastCommand.commandType !== commandChain[commandChain.length - 1])
return false;
return true;
});
},
onDrop(event) { onDrop(event) {
try { try {
const actionData = event.dataTransfer.getData("action"); const actionData = event.dataTransfer.getData("action");
@ -304,11 +341,11 @@ export default defineComponent({
removeCommand(index) { removeCommand(index) {
const command = this.commands[index]; const command = this.commands[index];
// //
if (this.isFirstCommandInChain(command)) { if (this.isFirstCommandInChain(command)) {
// //
quickcommand quickcommand
.showButtonBox(["全部删除", "保留内部命令", "手抖👋🏻"]) .showButtonBox(["全部删除", "保留内部命令", "手抖👋"])
.then(({ id }) => { .then(({ id }) => {
if (id !== 0 && id !== 1) return; if (id !== 0 && id !== 1) return;
const chainId = command.chainId; const chainId = command.chainId;
@ -320,7 +357,7 @@ export default defineComponent({
); );
}); });
} else { } else {
// //
this.removeRangeCommand(index); this.removeRangeCommand(index);
} }
}, },
@ -344,6 +381,7 @@ export default defineComponent({
(cmd) => cmd.chainId === chainId && cmd.commandType === commandType (cmd) => cmd.chainId === chainId && cmd.commandType === commandType
); );
}, },
//
addBranch({ chainId, commandType, value }) { addBranch({ chainId, commandType, value }) {
if (this.findUniqueBranch(chainId, commandType)) if (this.findUniqueBranch(chainId, commandType))
return quickcommand.showMessageBox("该分支仅允许存在一个", "warning"); return quickcommand.showMessageBox("该分支仅允许存在一个", "warning");
@ -364,56 +402,37 @@ export default defineComponent({
this.$emit("update:modelValue", newCommands); this.$emit("update:modelValue", newCommands);
} }
}, },
handleControlFlowCollapse(event) { //
const chainId = event.chainId;
const isCollapsed = !event.isCollapsed; //
if (!chainId) return;
// commandschainIdindex
const { startIndex, endIndex } = this.getChainIndex(chainId);
if (startIndex === -1 || endIndex === -1) return;
//
const newCommands = [...this.commands];
newCommands[startIndex] = {
...newCommands[startIndex],
isCollapsed,
};
this.$emit("update:modelValue", newCommands);
if (isCollapsed) {
//
this.collapsedRanges.push({
chainId,
start: startIndex,
end: endIndex,
});
} else {
//
const existingRangeIndex = this.collapsedRanges.findIndex(
(range) => range.chainId === chainId
);
if (existingRangeIndex !== -1) {
this.collapsedRanges.splice(existingRangeIndex, 1);
}
}
},
getCollapsedChainClass(index) { getCollapsedChainClass(index) {
// index const command = this.commands[index];
const matchingRanges = this.collapsedRanges.filter(
(range) => index >= range.start && index <= range.end //
for (let i = index - 1; i >= 0; i--) {
const prevCommand = this.commands[i];
if (!prevCommand?.chainId) continue;
//
const { startIndex, endIndex } = this.getChainIndex(
prevCommand.chainId
); );
if (!matchingRanges.length) return {}; if (i === startIndex && prevCommand.isCollapsed) {
// //
const isAnyMiddleEnd = matchingRanges.some( if (index > startIndex && index <= endIndex) {
(range) => index > range.start && index <= range.end return { "collapsed-chain-hidden": true };
); }
// hidden }
return isAnyMiddleEnd }
? { "collapsed-chain-hidden": true }
: { "collapsed-chain-start": true }; //
if (
command?.chainId &&
this.isFirstCommandInChain(command) &&
command.isCollapsed
) {
return { "collapsed-chain-start": true };
}
return {};
}, },
handleAction(action, payload) { handleAction(action, payload) {
if (action === "collapseAll") { if (action === "collapseAll") {
@ -424,13 +443,9 @@ export default defineComponent({
this.$emit("action", action, payload); this.$emit("action", action, payload);
} }
}, },
getChainIndex(chainId) { getChainIndex(chainId, commands = this.commands) {
const startIndex = this.commands.findIndex( const startIndex = commands.findIndex((cmd) => cmd.chainId === chainId);
(cmd) => cmd.chainId === chainId const endIndex = commands.findLastIndex((cmd) => cmd.chainId === chainId);
);
const endIndex = this.commands.findLastIndex(
(cmd) => cmd.chainId === chainId
);
return { startIndex, endIndex }; return { startIndex, endIndex };
}, },
copyCommands(commands) { copyCommands(commands) {
@ -467,10 +482,12 @@ export default defineComponent({
} }
}, },
handleToggleChainDisable({ chainId, disabled }) { handleToggleChainDisable({ chainId, disabled }) {
// Chain //
this.handleControlFlowCollapse({ chainId, isCollapsed: !disabled }); if (disabled) {
this.handleChainCollapse({ chainId, isCollapsed: false });
}
const { startIndex, endIndex } = this.getChainIndex(chainId); const { startIndex, endIndex } = this.getChainIndex(chainId);
//
const newCommands = [...this.commands]; const newCommands = [...this.commands];
newCommands.forEach((cmd, idx) => { newCommands.forEach((cmd, idx) => {
if (idx >= startIndex && idx <= endIndex) { if (idx >= startIndex && idx <= endIndex) {
@ -480,21 +497,115 @@ export default defineComponent({
this.$emit("update:modelValue", newCommands); this.$emit("update:modelValue", newCommands);
}, },
collapseAll() { collapseAll() {
const newCommands = this.commands.map((cmd) => ({ const newCommands = [...this.commands];
let i = 0;
while (i < newCommands.length) {
const cmd = newCommands[i];
if (cmd.chainId && this.isFirstCommandInChain(cmd)) {
//
const { endIndex } = this.getChainIndex(cmd.chainId);
//
newCommands[i] = {
...cmd, ...cmd,
isCollapsed: true, isCollapsed: true,
})); };
//
i = endIndex + 1;
} else if (!cmd.chainId) {
//
newCommands[i] = {
...cmd,
isCollapsed: true,
};
i++;
} else {
//
i++;
}
}
this.$emit("update:modelValue", newCommands); this.$emit("update:modelValue", newCommands);
this.isAllCollapsed = true; this.isAllCollapsed = true;
}, },
expandAll() { expandAll() {
const newCommands = this.commands.map((cmd) => ({ const newCommands = this.commands.map((cmd) => ({
...cmd, ...cmd,
isCollapsed: false, isCollapsed: false, //
})); }));
this.$emit("update:modelValue", newCommands); this.$emit("update:modelValue", newCommands);
this.isAllCollapsed = false; this.isAllCollapsed = false;
}, },
//
checkChainOrders(commands, chainId) {
//
const { startIndex, endIndex } = this.getChainIndex(chainId, commands);
// true
if (startIndex === -1 || endIndex === -1) return true;
//
const chainCommands = commands.slice(startIndex, endIndex + 1);
const commandChain = chainCommands[0].commandChain;
const firstCommand = chainCommands[0];
const lastCommand = chainCommands[chainCommands.length - 1];
// chainCommands
if (firstCommand.commandType !== commandChain[0]) return false;
// chainCommands
if (lastCommand.commandType !== commandChain[commandChain.length - 1])
return false;
return true;
},
//
handleChainCommandDrag(draggedCommand, oldCommands, newIndex) {
let newCommands = [...this.commands];
if (this.isFirstCommandInChain(draggedCommand)) {
const { startIndex, endIndex } = this.getChainIndex(
draggedCommand.chainId,
oldCommands
);
const chainCommands = oldCommands.slice(startIndex, endIndex + 1);
newCommands = oldCommands.filter(
(cmd) => !chainCommands.some((chainCmd) => chainCmd.id === cmd.id)
);
newCommands.splice(newIndex, 0, ...chainCommands);
} else {
//
const isValidOrder = this.checkChainOrders(
newCommands,
draggedCommand.chainId
);
if (!isValidOrder) {
newCommands = [...oldCommands];
}
}
return newCommands;
},
//
handleChainCollapse(event) {
const chainId = event.chainId;
const isCollapsed = !event.isCollapsed; //
if (!chainId) return;
// commandschainIdindex
const { startIndex } = this.getChainIndex(chainId);
if (startIndex === -1) return;
//
const newCommands = [...this.commands];
newCommands[startIndex] = {
...newCommands[startIndex],
isCollapsed,
};
this.$emit("update:modelValue", newCommands);
},
}, },
}); });
</script> </script>