mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-28 20:02:44 +08:00
新增子流程功能,可以添加子流程,方便后续作为函数调用
This commit is contained in:
parent
2728c5783f
commit
e0208eb119
@ -9,12 +9,9 @@
|
|||||||
|
|
||||||
<!-- 右侧命令流程 -->
|
<!-- 右侧命令流程 -->
|
||||||
<div class="col command-section">
|
<div class="col command-section">
|
||||||
<ComposerFlow
|
<FlowTabs
|
||||||
v-model="commandFlow"
|
|
||||||
:generate-code="generateFlowCode"
|
|
||||||
:show-close-button="showCloseButton"
|
|
||||||
@add-command="addCommand"
|
|
||||||
@action="handleComposer"
|
@action="handleComposer"
|
||||||
|
:show-close-button="showCloseButton"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -27,19 +24,15 @@
|
|||||||
<script>
|
<script>
|
||||||
import { defineComponent, provide, ref } from "vue";
|
import { defineComponent, provide, ref } from "vue";
|
||||||
import ComposerList from "./ComposerList.vue";
|
import ComposerList from "./ComposerList.vue";
|
||||||
import ComposerFlow from "./ComposerFlow.vue";
|
import FlowTabs from "./FlowTabs.vue";
|
||||||
import {
|
import { availableCommands } from "js/composer/composerConfig";
|
||||||
availableCommands,
|
|
||||||
findCommandByValue,
|
|
||||||
} from "js/composer/composerConfig";
|
|
||||||
import { generateCode } from "js/composer/generateCode";
|
|
||||||
import { parseVariables } from "js/composer/variableManager";
|
import { parseVariables } from "js/composer/variableManager";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "CommandComposer",
|
name: "CommandComposer",
|
||||||
components: {
|
components: {
|
||||||
ComposerList,
|
ComposerList,
|
||||||
ComposerFlow,
|
FlowTabs,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const commandFlow = ref([]);
|
const commandFlow = ref([]);
|
||||||
@ -94,65 +87,9 @@ export default defineComponent({
|
|||||||
outputVariable: null,
|
outputVariable: null,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
generateFlowCode() {
|
handleComposer(type, code) {
|
||||||
return generateCode(this.commandFlow);
|
// 直接转发事件和代码
|
||||||
},
|
this.$emit("use-composer", { type, code });
|
||||||
handleComposer(type, flow) {
|
|
||||||
switch (type) {
|
|
||||||
case "save":
|
|
||||||
return this.saveFlow();
|
|
||||||
case "load":
|
|
||||||
return this.loadFlow();
|
|
||||||
case "run":
|
|
||||||
return this.runFlow(flow);
|
|
||||||
default:
|
|
||||||
return this.$emit("use-composer", {
|
|
||||||
type,
|
|
||||||
code: this.generateFlowCode(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 传入临时flow说明是运行单独的命令,否则是运行整个命令流
|
|
||||||
runFlow(flow) {
|
|
||||||
this.hasCommandNeedLoading = this.findCommandNeedLoading(flow);
|
|
||||||
const code = generateCode(flow || this.commandFlow);
|
|
||||||
this.$emit("use-composer", { type: "run", code });
|
|
||||||
if (!code.includes("console.log")) quickcommand.showMessageBox("已运行");
|
|
||||||
},
|
|
||||||
saveFlow() {
|
|
||||||
const flow = window.lodashM.cloneDeep(this.commandFlow);
|
|
||||||
const uselessProps = [
|
|
||||||
"config",
|
|
||||||
"code",
|
|
||||||
"label",
|
|
||||||
"component",
|
|
||||||
"subCommands",
|
|
||||||
"options",
|
|
||||||
"defaultValue",
|
|
||||||
"icon",
|
|
||||||
"width",
|
|
||||||
"placeholder",
|
|
||||||
];
|
|
||||||
// 移除不必要属性
|
|
||||||
flow.forEach((cmd) => {
|
|
||||||
for (const props of uselessProps) {
|
|
||||||
delete cmd[props];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
localStorage.setItem("quickcomposer.flow", JSON.stringify(flow));
|
|
||||||
quickcommand.showMessageBox("保存成功");
|
|
||||||
},
|
|
||||||
loadFlow() {
|
|
||||||
const savedFlow = localStorage.getItem("quickcomposer.flow");
|
|
||||||
if (!savedFlow) return;
|
|
||||||
this.commandFlow = JSON.parse(savedFlow).map((cmd) => {
|
|
||||||
// 获取完整命令
|
|
||||||
const command = findCommandByValue(cmd.value);
|
|
||||||
return {
|
|
||||||
...command,
|
|
||||||
...cmd,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
findCommandNeedLoading(flow) {
|
findCommandNeedLoading(flow) {
|
||||||
// 暂时只在运行单独命令时显示载入界面,因为运行整个命令流时,如果不打印输出,是无法判断什么时候运行结束的,
|
// 暂时只在运行单独命令时显示载入界面,因为运行整个命令流时,如果不打印输出,是无法判断什么时候运行结束的,
|
||||||
|
@ -1,19 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="composer-flow">
|
<div class="composer-flow">
|
||||||
<ChainStyles ref="chainStyles" :commands="commands" />
|
<ChainStyles ref="chainStyles" :commands="commands" />
|
||||||
<div class="section-header flow-header">
|
|
||||||
<div class="flow-title">
|
|
||||||
<q-icon name="timeline" size="20px" class="q-mx-sm text-primary" />
|
|
||||||
<span class="text-subtitle1">命令流程</span>
|
|
||||||
</div>
|
|
||||||
<ComposerButtons
|
|
||||||
:generate-code="generateCode"
|
|
||||||
:is-all-collapsed="isAllCollapsed"
|
|
||||||
:show-close-button="showCloseButton"
|
|
||||||
@action="handleAction"
|
|
||||||
class="flex-grow"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<q-scroll-area class="command-scroll">
|
<q-scroll-area class="command-scroll">
|
||||||
<div
|
<div
|
||||||
@ -73,7 +60,6 @@
|
|||||||
import { defineComponent, inject } from "vue";
|
import { defineComponent, inject } from "vue";
|
||||||
import draggable from "vuedraggable";
|
import draggable from "vuedraggable";
|
||||||
import ComposerCard from "./ComposerCard.vue";
|
import ComposerCard from "./ComposerCard.vue";
|
||||||
import ComposerButtons from "./flow/ComposerButtons.vue";
|
|
||||||
import ChainStyles from "./flow/ChainStyles.vue";
|
import ChainStyles from "./flow/ChainStyles.vue";
|
||||||
import EmptyFlow from "./flow/EmptyFlow.vue";
|
import EmptyFlow from "./flow/EmptyFlow.vue";
|
||||||
import DropArea from "./flow/DropArea.vue";
|
import DropArea from "./flow/DropArea.vue";
|
||||||
@ -88,7 +74,6 @@ export default defineComponent({
|
|||||||
components: {
|
components: {
|
||||||
draggable,
|
draggable,
|
||||||
ComposerCard,
|
ComposerCard,
|
||||||
ComposerButtons,
|
|
||||||
ChainStyles,
|
ChainStyles,
|
||||||
EmptyFlow,
|
EmptyFlow,
|
||||||
DropArea,
|
DropArea,
|
||||||
@ -118,7 +103,6 @@ export default defineComponent({
|
|||||||
dragIndex: -1,
|
dragIndex: -1,
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
draggedCommand: null,
|
draggedCommand: null,
|
||||||
isAllCollapsed: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -363,13 +347,16 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
handleRunCommand(command) {
|
handleRunCommand(command) {
|
||||||
// 创建一个临时的命令流程
|
// 创建一个临时的命令流程
|
||||||
const tempFlow = [
|
const tempFlow = {
|
||||||
command,
|
name: "main",
|
||||||
{
|
commands: [
|
||||||
//没有输出,则不打印
|
command,
|
||||||
code: `if(${command.outputVariable}!==undefined){console.log(${command.outputVariable})}`,
|
{
|
||||||
},
|
//没有输出,则不打印
|
||||||
];
|
code: `if(${command.outputVariable}!==undefined){console.log(${command.outputVariable})}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
// 触发运行事件
|
// 触发运行事件
|
||||||
this.$emit("action", "run", tempFlow);
|
this.$emit("action", "run", tempFlow);
|
||||||
},
|
},
|
||||||
@ -497,46 +484,20 @@ export default defineComponent({
|
|||||||
this.$emit("update:modelValue", newCommands);
|
this.$emit("update:modelValue", newCommands);
|
||||||
},
|
},
|
||||||
collapseAll() {
|
collapseAll() {
|
||||||
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,
|
|
||||||
isCollapsed: true,
|
|
||||||
};
|
|
||||||
// 跳过这个链中的所有命令
|
|
||||||
i = endIndex + 1;
|
|
||||||
} else if (!cmd.chainId) {
|
|
||||||
// 如果是普通命令,设置为折叠状态
|
|
||||||
newCommands[i] = {
|
|
||||||
...cmd,
|
|
||||||
isCollapsed: true,
|
|
||||||
};
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
// 如果是链中的其他命令,跳过
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$emit("update:modelValue", newCommands);
|
|
||||||
this.isAllCollapsed = true;
|
|
||||||
},
|
|
||||||
expandAll() {
|
|
||||||
const newCommands = this.commands.map((cmd) => ({
|
const newCommands = this.commands.map((cmd) => ({
|
||||||
...cmd,
|
...cmd,
|
||||||
isCollapsed: false, // 所有命令都设置为展开状态
|
isCollapsed: true,
|
||||||
|
}));
|
||||||
|
this.$emit("update:modelValue", newCommands);
|
||||||
|
},
|
||||||
|
expandAll() {
|
||||||
|
// 遍历所有命令,展开状态
|
||||||
|
const newCommands = this.commands.map((cmd) => ({
|
||||||
|
...cmd,
|
||||||
|
isCollapsed: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.$emit("update:modelValue", newCommands);
|
this.$emit("update:modelValue", newCommands);
|
||||||
this.isAllCollapsed = false;
|
|
||||||
},
|
},
|
||||||
// 检查链式命令的顺序
|
// 检查链式命令的顺序
|
||||||
checkChainOrders(commands, chainId) {
|
checkChainOrders(commands, chainId) {
|
||||||
@ -618,22 +579,6 @@ export default defineComponent({
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-header {
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding: 0 8px;
|
|
||||||
height: 30px;
|
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flow-title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-grow {
|
.flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
367
src/components/composer/FlowTabs.vue
Normal file
367
src/components/composer/FlowTabs.vue
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flow-tabs">
|
||||||
|
<div class="tabs-header">
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="tabs-container">
|
||||||
|
<!-- main 作为固定按钮 -->
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
:color="activeTab === 'main' ? 'primary' : 'grey'"
|
||||||
|
label="main"
|
||||||
|
class="main-btn"
|
||||||
|
@click="activeTab = 'main'"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 其他流程标签可滚动 -->
|
||||||
|
<q-tabs
|
||||||
|
v-model="activeTab"
|
||||||
|
dense
|
||||||
|
class="text-grey"
|
||||||
|
active-color="primary"
|
||||||
|
indicator-color="primary"
|
||||||
|
align="left"
|
||||||
|
narrow-indicator
|
||||||
|
>
|
||||||
|
<template v-for="flow in nonMainFlows" :key="flow.id">
|
||||||
|
<q-tab :name="flow.id" class="flow-tab">
|
||||||
|
<div class="flow-tab-content">
|
||||||
|
<q-input
|
||||||
|
v-model="flow.name"
|
||||||
|
dense
|
||||||
|
borderless
|
||||||
|
class="flow-name-input"
|
||||||
|
@keydown.space.prevent
|
||||||
|
@blur="validateFlowName(flow)"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
round
|
||||||
|
icon="close"
|
||||||
|
size="xs"
|
||||||
|
@click.stop="removeFlow(flow)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-tab>
|
||||||
|
</template>
|
||||||
|
</q-tabs>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
round
|
||||||
|
icon="add"
|
||||||
|
size="sm"
|
||||||
|
class="q-ml-sm add-btn"
|
||||||
|
@click="addFlow"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ComposerButtons
|
||||||
|
:generate-code="generateAllFlowCode"
|
||||||
|
:is-all-collapsed="isAllCollapsed"
|
||||||
|
:show-close-button="showCloseButton"
|
||||||
|
@action="handleAction"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flow-container">
|
||||||
|
<ComposerFlow
|
||||||
|
v-for="flow in flows"
|
||||||
|
v-show="activeTab === flow.id"
|
||||||
|
:key="flow.id"
|
||||||
|
v-model="flow.commands"
|
||||||
|
:generate-code="() => generateFlowCode(flow)"
|
||||||
|
:show-close-button="flows.length > 1"
|
||||||
|
@action="(type, payload) => handleFlowAction(type, payload, flow)"
|
||||||
|
ref="flowRefs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import ComposerFlow from "./ComposerFlow.vue";
|
||||||
|
import ComposerButtons from "./flow/ComposerButtons.vue";
|
||||||
|
import { generateCode } from "js/composer/generateCode";
|
||||||
|
import { findCommandByValue } from "js/composer/composerConfig";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "FlowTabs",
|
||||||
|
components: {
|
||||||
|
ComposerFlow,
|
||||||
|
ComposerButtons,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
showCloseButton: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
flows: [
|
||||||
|
{
|
||||||
|
id: "main",
|
||||||
|
name: "main",
|
||||||
|
commands: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
activeTab: "main",
|
||||||
|
isAllCollapsed: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
nonMainFlows() {
|
||||||
|
return this.flows.filter((f) => f.id !== "main");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addFlow() {
|
||||||
|
const id = `flow_${this.$root.getUniqueId()}`;
|
||||||
|
const name = `flow${this.flows.length}`;
|
||||||
|
this.flows.push({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
commands: [],
|
||||||
|
});
|
||||||
|
this.activeTab = id;
|
||||||
|
this.$nextTick(this.updateWidths);
|
||||||
|
},
|
||||||
|
removeFlow(flow) {
|
||||||
|
const index = this.flows.findIndex((f) => f.id === flow.id);
|
||||||
|
if (index > -1 && flow.id !== "main") {
|
||||||
|
this.flows.splice(index, 1);
|
||||||
|
this.activeTab = this.flows[0].id;
|
||||||
|
this.$nextTick(this.updateWidths);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
validateFlowName(flow) {
|
||||||
|
if (flow.id === "main") return;
|
||||||
|
// 移除空格并确保名字唯一
|
||||||
|
let newName = flow.name.replace(/\s+/g, "_");
|
||||||
|
let counter = 1;
|
||||||
|
const baseName = newName;
|
||||||
|
|
||||||
|
while (this.flows.some((f) => f.id !== flow.id && f.name === newName)) {
|
||||||
|
newName = `${baseName}_${counter++}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
flow.name = newName;
|
||||||
|
},
|
||||||
|
generateFlowCode(flow) {
|
||||||
|
return generateCode(flow.commands, flow.name);
|
||||||
|
},
|
||||||
|
generateAllFlowCode() {
|
||||||
|
// 生成所有flow的代码
|
||||||
|
return this.flows.map((flow) => this.generateFlowCode(flow)).join("\n\n");
|
||||||
|
},
|
||||||
|
handleFlowAction(type, payload, flow) {
|
||||||
|
if (type === "close") {
|
||||||
|
const index = this.flows.findIndex((f) => f.id === flow.id);
|
||||||
|
if (index > -1 && this.flows.length > 1) {
|
||||||
|
this.flows.splice(index, 1);
|
||||||
|
this.activeTab = this.flows[0].id;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.handleAction(type, payload);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleAction(type, payload) {
|
||||||
|
switch (type) {
|
||||||
|
case "save":
|
||||||
|
this.saveFlows();
|
||||||
|
break;
|
||||||
|
case "load":
|
||||||
|
this.loadFlows();
|
||||||
|
break;
|
||||||
|
case "run":
|
||||||
|
this.runFlows(payload);
|
||||||
|
break;
|
||||||
|
case "collapseAll":
|
||||||
|
this.collapseAll();
|
||||||
|
break;
|
||||||
|
case "expandAll":
|
||||||
|
this.expandAll();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.$emit("action", type, this.generateAllFlowCode());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
saveFlows() {
|
||||||
|
const flowsData = this.flows.map((flow) => ({
|
||||||
|
id: flow.id,
|
||||||
|
name: flow.name,
|
||||||
|
commands: flow.commands.map((cmd) => {
|
||||||
|
const cmdCopy = { ...cmd };
|
||||||
|
// 移除不必要的属性
|
||||||
|
const uselessProps = [
|
||||||
|
"config",
|
||||||
|
"code",
|
||||||
|
"label",
|
||||||
|
"component",
|
||||||
|
"subCommands",
|
||||||
|
"options",
|
||||||
|
"defaultValue",
|
||||||
|
"icon",
|
||||||
|
"width",
|
||||||
|
"placeholder",
|
||||||
|
];
|
||||||
|
uselessProps.forEach((prop) => delete cmdCopy[prop]);
|
||||||
|
return cmdCopy;
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
localStorage.setItem("quickcomposer.flows", JSON.stringify(flowsData));
|
||||||
|
quickcommand.showMessageBox("保存成功");
|
||||||
|
},
|
||||||
|
loadFlows() {
|
||||||
|
const savedFlows = localStorage.getItem("quickcomposer.flows");
|
||||||
|
if (!savedFlows) return;
|
||||||
|
|
||||||
|
const flowsData = JSON.parse(savedFlows);
|
||||||
|
this.flows = flowsData.map((flow) => ({
|
||||||
|
...flow,
|
||||||
|
commands: flow.commands.map((cmd) => {
|
||||||
|
const command = findCommandByValue(cmd.value);
|
||||||
|
return {
|
||||||
|
...command,
|
||||||
|
...cmd,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
this.activeTab = this.flows[0].id;
|
||||||
|
},
|
||||||
|
runFlows(flow) {
|
||||||
|
const code = flow
|
||||||
|
? this.generateFlowCode(flow)
|
||||||
|
: this.generateAllFlowCode();
|
||||||
|
this.$emit("action", "run", code);
|
||||||
|
if (!code.includes("console.log")) {
|
||||||
|
quickcommand.showMessageBox("已运行");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collapseAll() {
|
||||||
|
this.$refs.flowRefs.forEach((flow) => {
|
||||||
|
if (flow.collapseAll) flow.collapseAll();
|
||||||
|
});
|
||||||
|
this.isAllCollapsed = true;
|
||||||
|
},
|
||||||
|
expandAll() {
|
||||||
|
this.$refs.flowRefs.forEach((flow) => {
|
||||||
|
if (flow.expandAll) flow.expandAll();
|
||||||
|
});
|
||||||
|
this.isAllCollapsed = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.flow-tabs {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-header {
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 28px;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 限制在当前组件内的tabs样式 */
|
||||||
|
.tabs-container :deep(.q-tabs) {
|
||||||
|
flex: 1;
|
||||||
|
height: 28px;
|
||||||
|
min-height: 28px;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
margin-left: 4px; /* 与 main 按钮保持间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏滚动条 */
|
||||||
|
.tabs-container :deep(.q-tabs)::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-container :deep(.q-tab) {
|
||||||
|
min-height: 28px;
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-container :deep(.q-tab__content) {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-tab {
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-tab-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-name-input {
|
||||||
|
max-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-name-input :deep(.q-field__native) {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加按钮样式 */
|
||||||
|
.tabs-container .q-btn {
|
||||||
|
height: 28px;
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 28px;
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-container {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body--dark .tabs-header {
|
||||||
|
border-bottom-color: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-btn {
|
||||||
|
height: 28px;
|
||||||
|
min-height: 28px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-right: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="composer-buttons">
|
<div class="composer-buttons">
|
||||||
<div class="left-buttons">
|
<div class="right-buttons">
|
||||||
<q-btn
|
<q-btn
|
||||||
:icon="isAllCollapsed ? 'unfold_more' : 'unfold_less'"
|
:icon="isAllCollapsed ? 'unfold_more' : 'unfold_less'"
|
||||||
dense
|
dense
|
||||||
@ -11,9 +11,7 @@
|
|||||||
>
|
>
|
||||||
<q-tooltip>{{ isAllCollapsed ? "展开所有" : "折叠所有" }}</q-tooltip>
|
<q-tooltip>{{ isAllCollapsed ? "展开所有" : "折叠所有" }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</div>
|
<q-separator vertical />
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<q-btn
|
<q-btn
|
||||||
@click="$q.dark.toggle()"
|
@click="$q.dark.toggle()"
|
||||||
:icon="$q.dark.isActive ? 'dark_mode' : 'light_mode'"
|
:icon="$q.dark.isActive ? 'dark_mode' : 'light_mode'"
|
||||||
@ -135,24 +133,25 @@ export default defineComponent({
|
|||||||
.composer-buttons {
|
.composer-buttons {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
height: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-buttons,
|
|
||||||
.right-buttons {
|
.right-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.composer-buttons > div > .q-btn {
|
.right-buttons .q-btn {
|
||||||
|
height: 28px;
|
||||||
|
min-height: 28px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.composer-buttons > div > .q-btn:hover {
|
.right-buttons .q-btn:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
color: var(--q-primary);
|
color: var(--q-primary);
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
export function generateCode(commandFlow) {
|
export function generateCode(commandFlow, functionName = null) {
|
||||||
// 检查是否包含异步函数
|
// 检查是否包含异步函数
|
||||||
const hasAsyncFunction = commandFlow.some((cmd) => cmd.isAsync);
|
const hasAsyncFunction = commandFlow.some((cmd) => cmd.isAsync);
|
||||||
|
|
||||||
let code = hasAsyncFunction ? ["async function run() {"] : [];
|
let code = [];
|
||||||
const indent = hasAsyncFunction ? " " : "";
|
const funcName = functionName || "run";
|
||||||
|
|
||||||
|
// 生成函数声明
|
||||||
|
code.push(`${hasAsyncFunction ? "async " : ""}function ${funcName}() {`);
|
||||||
|
|
||||||
|
const indent = " ";
|
||||||
|
|
||||||
commandFlow.forEach((cmd) => {
|
commandFlow.forEach((cmd) => {
|
||||||
// 跳过禁用的命令
|
// 跳过禁用的命令
|
||||||
@ -20,9 +25,11 @@ export function generateCode(commandFlow) {
|
|||||||
code.push(line);
|
code.push(line);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hasAsyncFunction) {
|
code.push("}"); // Close the function
|
||||||
code.push("}"); // Close the async function
|
|
||||||
code.push("run();"); // Call the function
|
// 如果是主函数,则自动执行
|
||||||
|
if (functionName === "main") {
|
||||||
|
code.push("\nmain();"); // Call the main function
|
||||||
}
|
}
|
||||||
|
|
||||||
return code.join("\n");
|
return code.join("\n");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user