可视化编排的命令卡片支持禁用,复制,快速打印

This commit is contained in:
fofolee 2025-01-21 01:20:03 +08:00
parent b026b484f7
commit 7a224be9f4
19 changed files with 320 additions and 44 deletions

View File

@ -123,7 +123,7 @@ export default defineComponent({
const flow = window.lodashM.cloneDeep(this.commandFlow);
const uselessProps = [
"config",
"argvs",
"code",
"label",
"component",
"subCommands",

View File

@ -6,6 +6,25 @@
}"
v-bind="$attrs"
>
<!-- 禁用遮罩层 -->
<div
v-if="localCommand.disabled"
class="disabled-overlay"
:class="{
showToggleBtn: canToggleDisable,
}"
@click.stop="handleToggleDisable"
>
<div
class="enable-btn-wrapper row items-center text-primary"
:style="{
fontSize: localCommand.isCollapsed ? '12px' : '16px',
}"
>
<q-icon name="layers" class="q-mr-sm" />
<div>点击启用</div>
</div>
</div>
<q-card class="command-item">
<q-card-section
class="card-section"
@ -20,6 +39,9 @@
@toggle-collapse="handleToggleCollapse"
@run="runCommand"
@remove="$emit('remove')"
@copy="handleCopy"
@toggle-disable="handleToggleDisable"
@add-print="handleAddPrint"
>
<!-- 控制流程组件直接把组件放在head中 -->
<template v-if="localCommand.isControlFlow">
@ -74,6 +96,7 @@ import MultiParams from "components/composer/MultiParams.vue";
import CommandHead from "components/composer/card/CommandHead.vue";
import * as CardComponents from "js/composer/cardComponents";
import { processVariable } from "js/composer/variableManager";
import { newVarInputVal } from "js/composer/varInputValManager";
import ControlCommand from "components/composer/control/ControlCommand.vue";
export default defineComponent({
@ -95,7 +118,15 @@ export default defineComponent({
required: true,
},
},
emits: ["remove", "run", "addBranch", "toggle-collapse", "update:modelValue"],
emits: [
"remove",
"run",
"addBranch",
"toggle-collapse",
"update:modelValue",
"add-command",
"toggle-disable",
],
computed: {
localCommand: {
get() {
@ -105,18 +136,15 @@ export default defineComponent({
this.$emit("update:modelValue", value);
},
},
showRunBtn() {
return !this.command.isControlFlow;
},
showOutputBtn() {
return !this.command.isControlFlow;
},
isLastCommandInChain() {
if (!this.command.commandChain) return false;
isFirstCommandInChain() {
if (!this.localCommand.commandChain) return false;
return (
this.command.commandType === this.command.commandChain?.slice(-1)[0]
this.localCommand.commandType === this.localCommand.commandChain?.[0]
);
},
canToggleDisable() {
return !this.localCommand.isControlFlow || this.isFirstCommandInChain;
},
},
setup(props) {
const getCurrentVariables = inject("getCurrentVariables");
@ -171,6 +199,68 @@ export default defineComponent({
this.localCommand.isCollapsed = !this.localCommand.isCollapsed;
}
},
handleCopy() {
if (this.localCommand.isControlFlow && this.localCommand.chainId) {
//
this.$emit("add-command", {
command: this.localCommand,
type: "chain",
});
} else {
//
const copiedCommand = window.lodashM.cloneDeep(this.localCommand);
delete copiedCommand.id;
delete copiedCommand.chainId;
delete copiedCommand.commandType;
this.$emit("add-command", {
command: copiedCommand,
type: "single",
});
}
},
handleToggleDisable() {
if (!this.canToggleDisable) return;
if (this.localCommand.isControlFlow && this.localCommand.chainId) {
console.log(
"handleToggleDisable card",
this.localCommand.isControlFlow,
this.localCommand.chainId
);
//
this.$emit("toggle-disable", {
chainId: this.localCommand.chainId,
disabled: !this.localCommand.disabled,
});
} else {
//
this.localCommand.disabled = !this.localCommand.disabled;
}
},
handleAddPrint() {
//
if (!this.localCommand.outputVariable) {
this.localCommand.outputVariable = `temp_${parseInt(
new Date().getTime() / 1000
)}`;
this.localCommand.saveOutput = true;
}
const printCommand = {
value: "console.log",
label: "显示消息",
config: [
{
label: "要打印的消息文本",
component: "VariableInput",
icon: "info",
},
],
argvs: [newVarInputVal("var", this.localCommand.outputVariable)],
};
this.$emit("add-command", {
command: printCommand,
type: "single",
});
},
},
});
</script>
@ -268,4 +358,71 @@ export default defineComponent({
.command-item :deep(.condition-type-btn) {
margin-left: -8px;
}
/* 禁用状态样式 */
.composer-card.disabled {
position: relative;
}
/* 禁用遮罩层 */
.disabled-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(1px);
border: 1px dashed rgba(0, 0, 0, 0.2);
z-index: 10;
border-radius: inherit;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer !important;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.body--dark .disabled-overlay {
background: rgba(0, 0, 0, 0.05);
border-color: rgba(255, 255, 255, 0.15);
}
/* 斜纹背景 */
.disabled-overlay::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: repeating-linear-gradient(
-45deg,
rgba(0, 0, 0, 0.02),
rgba(0, 0, 0, 0.02) 10px,
rgba(0, 0, 0, 0.04) 10px,
rgba(0, 0, 0, 0.04) 20px
);
border-radius: inherit;
pointer-events: none;
}
.enable-btn-wrapper {
opacity: 0;
transform: scale(0.9);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
cursor: pointer !important;
}
.disabled-overlay.showToggleBtn:hover .enable-btn-wrapper {
opacity: 1;
transform: scale(1);
}
.disabled-overlay.showToggleBtn:hover {
backdrop-filter: blur(0.5px);
border-color: transparent;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
</style>

View File

@ -55,6 +55,8 @@
@run="handleRunCommand"
@add-branch="addBranch"
@toggle-collapse="(event) => handleControlFlowCollapse(event)"
@add-command="(event) => handleAddCommand(event, index)"
@toggle-disable="handleToggleDisable"
/>
</div>
</transition>
@ -435,6 +437,62 @@ export default defineComponent({
this.$emit("action", action, payload);
}
},
getChainCommands(chainId) {
const startIndex = this.commands.findIndex(
(cmd) => cmd.chainId === chainId
);
const endIndex = this.commands.findLastIndex(
(cmd) => cmd.chainId === chainId
);
return {
chainCommands: this.commands.slice(startIndex, endIndex + 1),
startIndex,
endIndex,
};
},
copyChainCommands(chainCommands) {
// chainId
const newChainId = this.$root.getUniqueId();
//
const newChainCommands = [];
chainCommands.forEach((cmd) => {
const copiedCommand = window.lodashM.cloneDeep(cmd);
copiedCommand.id = this.$root.getUniqueId();
if (copiedCommand.chainId) copiedCommand.chainId = newChainId;
newChainCommands.push(copiedCommand);
});
return newChainCommands;
},
handleAddCommand({ command, type }, index) {
if (type === "chain") {
//
const { chainCommands, endIndex } = this.getChainCommands(
command.chainId
);
const newChainCommands = this.copyChainCommands(chainCommands);
const newCommands = [...this.commands];
newCommands.splice(endIndex + 1, 0, ...newChainCommands);
this.$emit("update:modelValue", newCommands);
} else {
//
const newCommand = {
...command,
id: this.$root.getUniqueId(),
};
const newCommands = [...this.commands];
newCommands.splice(index + 1, 0, newCommand);
this.$emit("update:modelValue", newCommands);
}
},
handleToggleDisable({ chainId, disabled }) {
console.log("handleToggleDisable", chainId, disabled);
const { chainCommands } = this.getChainCommands(chainId);
//
const newCommands = chainCommands.map((cmd) => {
return { ...cmd, disabled };
});
this.$emit("update:modelValue", newCommands);
},
collapseAll() {
const newCommands = this.commands.map((cmd) => ({
...cmd,

View File

@ -199,8 +199,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.funcName, this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(this.funcName, argvs);
}
},
});

View File

@ -54,6 +54,50 @@
<q-tooltip>单独运行此命令并打印输出</q-tooltip>
</q-icon>
<!-- 更多操作按钮 -->
<q-icon
name="more_vert"
class="more-btn"
v-if="!isControlFlow || isFirstCommandInChain"
>
<q-menu>
<q-list style="min-width: 150px">
<q-item clickable v-close-popup @click="$emit('copy')">
<q-item-section avatar>
<q-icon name="content_copy" />
</q-item-section>
<q-item-section>复制命令</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="$emit('toggle-disable')"
x
>
<q-item-section avatar>
<q-icon :name="command.disabled ? 'check_circle' : 'block'" />
</q-item-section>
<q-item-section>{{
command.disabled ? "启用命令" : "禁用命令"
}}</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="$emit('add-print')"
v-if="!isControlFlow"
>
<q-item-section avatar>
<q-icon name="chat" />
</q-item-section>
<q-item-section>打印输出</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-icon>
<q-icon
name="close"
@click="$emit('remove')"
@ -109,6 +153,9 @@ export default {
"run",
"remove",
"toggle-collapse",
"copy",
"toggle-disable",
"add-print",
],
methods: {
handleBlur() {
@ -167,7 +214,8 @@ export default {
/* 按钮样式 */
.output-btn,
.run-btn,
.remove-btn {
.remove-btn,
.more-btn {
font-size: 18px;
min-height: 25px;
cursor: pointer;
@ -178,7 +226,8 @@ export default {
.output-btn:hover,
.run-btn:hover,
.remove-btn:hover {
.remove-btn:hover,
.more-btn:hover {
opacity: 1;
transform: scale(1.1) translateY(-1px);
transition: all 0.3s ease;

View File

@ -317,9 +317,9 @@ export default defineComponent({
},
},
mounted() {
// argvs code
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -350,8 +350,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -300,8 +300,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -274,8 +274,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -675,8 +675,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -493,8 +493,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -249,8 +249,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -705,11 +705,12 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.code && !this.modelValue.argvs) {
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.$emit("update:modelValue", {
...this.modelValue,
argvs: this.defaultArgvs,
code: this.generateCode(this.defaultArgvs),
argvs,
code: this.generateCode(argvs),
});
}
},

View File

@ -678,8 +678,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.code && !this.modelValue.argvs) {
this.updateValue();
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateValue(argvs);
}
},
});

View File

@ -271,8 +271,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -388,8 +388,9 @@ export default defineComponent({
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.updateModelValue(argvs);
}
},
});

View File

@ -104,7 +104,6 @@ export const imageCommands = {
width: 6,
min: 1,
step: 10,
defaultValue: "",
},
{
label: "高度(像素)",
@ -113,7 +112,6 @@ export const imageCommands = {
width: 6,
min: 1,
step: 10,
defaultValue: "",
},
{
label: "保持宽高比",

View File

@ -172,11 +172,12 @@ const customComponentGuide = {
description: "组件初始化时的处理",
implementation: `
// 如果没有 argvs 和 code使用默认值初始化
if (!this.modelValue.argvs && !this.modelValue.code) {
const argvs = this.modelValue.argvs || this.defaultArgvs;
if (!this.modelValue.code) {
this.$emit("update:modelValue", {
...this.modelValue,
argvs: this.defaultArgvs,
code: this.generateCode(this.defaultArgvs)
argvs,
code: this.generateCode(argvs),
});
}
`,

View File

@ -6,6 +6,8 @@ export function generateCode(commandFlow) {
const indent = hasAsyncFunction ? " " : "";
commandFlow.forEach((cmd) => {
// 跳过禁用的命令
if (cmd.disabled) return;
if (!cmd.code) return;
let line = indent;