改善生成代码逻辑,覆盖各种情况,改用asyncMode存储promise状态

This commit is contained in:
fofolee 2025-01-26 12:05:56 +08:00
parent 208a6a08d9
commit 365964fc02
22 changed files with 387 additions and 237 deletions

View File

@ -155,27 +155,37 @@ export default defineComponent({
}, },
methods: { methods: {
handleOutputVariableUpdate(result) { handleOutputVariableUpdate(result) {
const { outputVariable, mode, functionInfo } = result; const { outputVariable, asyncMode, callbackFunc } = result;
if (outputVariable.name || outputVariable.details) { if (outputVariable.name || outputVariable.details) {
this.localCommand.outputVariable = { ...outputVariable }; this.localCommand.outputVariable = { ...outputVariable };
} else {
delete this.localCommand.outputVariable;
}
if (asyncMode) {
this.localCommand.asyncMode = asyncMode;
// callbackFunc // callbackFunc
if (mode === "callback") { if (callbackFunc) {
this.localCommand.callbackFunc = functionInfo.name; this.localCommand.callbackFunc = callbackFunc;
let params = [];
if (outputVariable?.name) {
params.push(outputVariable.name);
}
if (outputVariable?.details) {
params.push(...Object.values(outputVariable.details));
}
this.$emit("add-command", {
command: {
name: callbackFunc,
params,
silent: true,
},
type: "function",
});
} else { } else {
delete this.localCommand.callbackFunc; delete this.localCommand.callbackFunc;
} }
//
if (mode === "callback" && functionInfo) {
this.$emit("add-command", {
command: functionInfo,
type: "function",
});
}
} else {
delete this.localCommand.outputVariable;
delete this.localCommand.callbackFunc;
} }
}, },
runCommand() { runCommand() {

View File

@ -63,7 +63,6 @@ import ComposerCard from "./ComposerCard.vue";
import ChainStyles from "./flow/ChainStyles.vue"; import ChainStyles from "./flow/ChainStyles.vue";
import DropArea from "./flow/DropArea.vue"; import DropArea from "./flow/DropArea.vue";
import { findCommandByValue } from "js/composer/composerConfig"; import { findCommandByValue } from "js/composer/composerConfig";
import { processVariable } from "js/composer/variableManager";
// //
let commandsBeforeDrag = []; let commandsBeforeDrag = [];

View File

@ -252,19 +252,9 @@ export default defineComponent({
}); });
} }
//
if (options.localVars && options.localVars.length > 0) {
options.localVars.forEach((varInfo) => {
newFlow.customVariables.push({
name: varInfo.name,
type: "var",
value: varInfo.value,
});
});
}
this.subFlows.push(newFlow); this.subFlows.push(newFlow);
if (options.params || options.localVars) {
if (options.silent) {
return; return;
} }
@ -281,12 +271,17 @@ export default defineComponent({
} }
}, },
updateSubFlow(index, payload) { updateSubFlow(index, payload) {
const { params, localVars } = payload; const { params } = payload;
const newParams = params.map((param) => ({
name: param,
type: "param",
}));
const localVars = this.subFlows[index].customVariables.filter(
(v) => v.type === "var"
);
//
this.subFlows[index].customVariables = [ this.subFlows[index].customVariables = [
...params.map((param) => ({ ...newParams,
name: param,
type: "param",
})),
...localVars, ...localVars,
]; ];
}, },
@ -355,7 +350,6 @@ export default defineComponent({
"icon", "icon",
"width", "width",
"placeholder", "placeholder",
"isAsync",
"summary", "summary",
"type", "type",
]; ];

View File

@ -15,9 +15,9 @@
@click="showOutputEditor = true" @click="showOutputEditor = true"
> >
<q-tooltip> <q-tooltip>
<div class="text-body2">配置命令输出变量</div> <div class="text-body2">输出配置</div>
<div class="text-caption text-grey-5"> <div class="text-caption text-grey-5">
将命令的输出保存为变量以供后续使用 配置输出变量是否等待执行完毕等
</div> </div>
</q-tooltip> </q-tooltip>
</q-icon> </q-icon>

View File

@ -14,8 +14,16 @@
</template> </template>
</q-input> </q-input>
</div> </div>
<div v-if="hasNestedFields(currentOutputs)"> <div v-if="currentOutputs?.structure">
<q-badge color="primary" class="q-ma-sm q-pa-xs">详细输出</q-badge> <div class="row items-center">
<q-badge color="primary" class="q-ma-sm q-pa-xs">详细输出</q-badge>
<div
v-if="Array.isArray(currentOutputs.structure)"
class="text-caption text-grey-5"
>
数组中第一个元素
</div>
</div>
<q-scroll-area <q-scroll-area
style="height: 200px" style="height: 200px"
:thumb-style="{ :thumb-style="{
@ -23,61 +31,124 @@
}" }"
> >
<div class="detail-output column q-col-gutter-sm q-px-sm"> <div class="detail-output column q-col-gutter-sm q-px-sm">
<div v-for="(output, key) in detailOutputs" :key="key"> <!-- 处理数组类型的structure -->
<!-- 如果是嵌套对象 --> <template v-if="Array.isArray(currentOutputs.structure)">
<div v-if="hasNestedFields(output)"> <div
<BorderLabel :label="output.label || key" :model-value="false"> v-for="(output, key) in currentOutputs.structure[0]"
<div class="column q-col-gutter-sm"> :key="key"
<div >
v-for="(subOutput, subKey) in getNestedFields(output)" <!-- 如果是嵌套对象 -->
:key="subKey" <div v-if="hasNestedFields(output)">
> <BorderLabel
<div class="output-item"> :label="output.label || key"
<q-input :model-value="false"
v-model="outputVars[`${key}.${subKey}`]" >
filled <div class="column q-col-gutter-sm">
dense <div
autofocus v-for="(subOutput, subKey) in getNestedFields(output)"
class="col" :key="subKey"
:placeholder="subOutput.placeholder" >
> <div class="output-item">
<template v-slot:prepend> <q-input
<div class="variable-label"> v-model="outputVars[`[0].${key}.${subKey}`]"
{{ subOutput.label }} filled
</div> dense
</template> autofocus
</q-input> class="col"
:placeholder="subOutput.placeholder"
>
<template v-slot:prepend>
<div class="variable-label">
{{ subOutput.label }}
</div>
</template>
</q-input>
</div>
</div> </div>
</div> </div>
</div> </BorderLabel>
</BorderLabel> </div>
<!-- 如果是普通字段 -->
<div v-else class="output-item">
<q-input
v-model="outputVars[`[0].${key}`]"
filled
dense
class="col"
:placeholder="output.placeholder"
autofocus
>
<template v-slot:prepend>
<div class="variable-label">{{ output.label }}</div>
</template>
</q-input>
</div>
</div> </div>
<!-- 如果是普通字段 --> </template>
<div v-else class="output-item"> <!-- 处理对象类型的structure -->
<q-input <template v-else>
v-model="outputVars[key]" <div
filled v-for="(output, key) in currentOutputs?.structure"
dense :key="key"
class="col" >
:placeholder="output.placeholder" <!-- 如果是嵌套对象 -->
autofocus <div v-if="hasNestedFields(output)">
> <BorderLabel
<template v-slot:prepend> :label="output.label || key"
<div class="variable-label">{{ output.label }}</div> :model-value="false"
</template> >
</q-input> <div class="column q-col-gutter-sm">
<div
v-for="(subOutput, subKey) in getNestedFields(output)"
:key="subKey"
>
<div class="output-item">
<q-input
v-model="outputVars[`${key}.${subKey}`]"
filled
dense
autofocus
class="col"
:placeholder="subOutput.placeholder"
>
<template v-slot:prepend>
<div class="variable-label">
{{ subOutput.label }}
</div>
</template>
</q-input>
</div>
</div>
</div>
</BorderLabel>
</div>
<!-- 如果是普通字段 -->
<div v-else class="output-item">
<q-input
v-model="outputVars[key]"
filled
dense
class="col"
:placeholder="output.placeholder"
autofocus
>
<template v-slot:prepend>
<div class="variable-label">{{ output.label }}</div>
</template>
</q-input>
</div>
</div> </div>
</div> </template>
</div> </div>
</q-scroll-area> </q-scroll-area>
</div> </div>
<div v-if="isAsyncCommand"> <div v-if="!!asyncMode">
<q-badge color="primary" class="q-ma-sm q-pa-xs">输出模式</q-badge> <q-badge color="primary" class="q-ma-sm q-pa-xs">运行模式</q-badge>
<div class="row q-col-gutter-sm q-px-sm"> <div class="row q-col-gutter-sm q-px-sm">
<q-select <q-select
v-model="outputMode" v-model="asyncMode"
:options="outputModeOptions" :options="asyncModeOptions"
filled filled
dense dense
autofocus autofocus
@ -92,10 +163,11 @@
dense dense
autofocus autofocus
class="col-8" class="col-8"
v-if="outputMode === 'callback'" v-if="asyncMode === 'then'"
placeholder="新函数名则自动创建"
> >
<template v-slot:prepend> <template v-slot:prepend>
<div class="variable-label">回调函数</div> <div class="variable-label">回调函数</div>
</template> </template>
</q-input> </q-input>
</div> </div>
@ -147,64 +219,74 @@ export default defineComponent({
commandName() { commandName() {
return this.currentSubCommand.label || this.command.label; return this.currentSubCommand.label || this.command.label;
}, },
isAsyncCommand() {
return this.currentSubCommand.isAsync || this.command.isAsync;
},
currentOutputs() { currentOutputs() {
return this.currentSubCommand.outputs || this.command.outputs; return this.currentSubCommand.outputs || this.command.outputs;
}, },
detailOutputs() {
let outputs = { ...this.currentOutputs };
delete outputs.label;
delete outputs.placeholder;
return outputs;
},
}, },
data() { data() {
return { return {
simpleOutputVar: "", simpleOutputVar: "",
outputVars: {}, outputVars: {},
outputMode: "wait", asyncMode: "await",
outputModeOptions: [ callbackFunc: "",
asyncModeOptions: [
{ {
label: "等待运行完毕", label: "等待运行完毕",
value: "wait", value: "await",
}, },
{ {
label: "输出到回调函数", label: "不等待运行完毕",
value: "callback", value: "then",
}, },
], ],
callbackFunc: "",
}; };
}, },
watch: { watch: {
"command.outputVariable": { "command.outputVariable": {
immediate: true, immediate: true,
deep: true, deep: true,
handler(outputVariable) { handler(newValue) {
this.initOutputVars(outputVariable); this.initOutputVars(newValue);
},
},
"command.asyncMode": {
immediate: true,
handler(newValue) {
this.asyncMode = newValue;
}, },
}, },
"command.callbackFunc": { "command.callbackFunc": {
immediate: true, immediate: true,
handler(callbackFunc) { handler(newValue) {
if (callbackFunc) { this.callbackFunc = newValue;
this.outputMode = "callback";
this.callbackFunc = callbackFunc;
} else {
this.outputMode = "wait";
}
}, },
}, },
}, },
methods: { methods: {
hasNestedFields(output) { hasNestedFields(output) {
console.log(output); if (!output) return false;
return Object.keys(output).some( return Object.keys(output).some(
(key) => key !== "label" && key !== "placeholder" (key) => key !== "label" && key !== "placeholder"
); );
}, },
/**
* 只处理一层嵌套手动在配置文件中控制outputs结构不要太复杂
* 第二层嵌套只嵌套对象不嵌套数组
* 最复杂的情况
* outputs: {
* label: "测试",
* structure: [
* {
* position: { label: "位置", {
* x: { label: "X坐标" },
* y: { label: "Y坐标" }
* }
* }
* ]
* }
*
*
*/
getNestedFields(output) { getNestedFields(output) {
const fields = {}; const fields = {};
Object.entries(output).forEach(([key, value]) => { Object.entries(output).forEach(([key, value]) => {
@ -243,25 +325,17 @@ export default defineComponent({
} }
// //
const result = { let result = {
outputVariable, outputVariable,
mode: this.outputMode,
}; };
// // async
if (this.outputMode === "callback" && this.callbackFunc) { if (this.asyncMode) {
// result.asyncMode = this.asyncMode;
result.functionInfo = { //
name: this.callbackFunc, if (this.asyncMode === "then" && this.callbackFunc) {
params: [outputVariable.name], result.callbackFunc = this.callbackFunc;
localVars: outputVariable.details }
? Object.entries(outputVariable.details).map(([path, varName]) => ({
name: varName,
type: "var",
value: `${outputVariable.name}.${path}`,
}))
: [],
};
} }
this.$emit("confirm", result); this.$emit("confirm", result);

View File

@ -133,7 +133,7 @@ export const audioCommands = {
value: "quickcomposer.audio.media.play", value: "quickcomposer.audio.media.play",
label: "音频播放", label: "音频播放",
icon: "music_note", icon: "music_note",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.audio.media.play", value: "quickcomposer.audio.media.play",
@ -175,7 +175,7 @@ export const audioCommands = {
value: "quickcomposer.audio.record", value: "quickcomposer.audio.record",
label: "音频录制", label: "音频录制",
icon: "mic", icon: "mic",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "录制时长(ms)", label: "录制时长(ms)",
@ -211,7 +211,7 @@ export const audioCommands = {
{ {
value: "quickcomposer.audio.media.beep", value: "quickcomposer.audio.media.beep",
label: "系统音效", label: "系统音效",
isAsync: true, asyncMode: "await",
icon: "notifications_active", icon: "notifications_active",
config: [ config: [
{ {
@ -238,7 +238,7 @@ export const audioCommands = {
value: "quickcomposer.audio.media.analyze", value: "quickcomposer.audio.media.analyze",
label: "音频信息", label: "音频信息",
icon: "analytics", icon: "analytics",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "音频文件", label: "音频文件",

View File

@ -36,7 +36,7 @@ export const browserCommands = {
value: "quickcomposer.browser.startClient", value: "quickcomposer.browser.startClient",
label: "浏览器实例管理", label: "浏览器实例管理",
icon: "launch", icon: "launch",
isAsync: true, asyncMode: "await",
config: [], config: [],
subCommands: [ subCommands: [
{ {
@ -168,7 +168,7 @@ export const browserCommands = {
value: "quickcomposer.browser.getUrl", value: "quickcomposer.browser.getUrl",
label: "获取/设置网址", label: "获取/设置网址",
icon: "link", icon: "link",
isAsync: true, asyncMode: "await",
config: [tabConfig], config: [tabConfig],
subCommands: [ subCommands: [
{ {
@ -196,7 +196,7 @@ export const browserCommands = {
value: "quickcomposer.browser.getTabs", value: "quickcomposer.browser.getTabs",
label: "标签操作", label: "标签操作",
icon: "tab", icon: "tab",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.browser.getTabs", value: "quickcomposer.browser.getTabs",
@ -240,7 +240,7 @@ export const browserCommands = {
value: "quickcomposer.browser.captureScreenshot", value: "quickcomposer.browser.captureScreenshot",
label: "捕获截图", label: "捕获截图",
icon: "screenshot", icon: "screenshot",
isAsync: true, asyncMode: "await",
config: [ config: [
tabConfig, tabConfig,
{ {
@ -305,7 +305,7 @@ export const browserCommands = {
value: "quickcomposer.browser.executeScript", value: "quickcomposer.browser.executeScript",
label: "执行脚本", label: "执行脚本",
icon: "code", icon: "code",
isAsync: true, asyncMode: "await",
config: [ config: [
tabConfig, tabConfig,
{ {
@ -328,7 +328,7 @@ export const browserCommands = {
value: "quickcomposer.browser.injectRemoteScript", value: "quickcomposer.browser.injectRemoteScript",
label: "注入脚本/样式", label: "注入脚本/样式",
icon: "style", icon: "style",
isAsync: true, asyncMode: "await",
config: [tabConfig], config: [tabConfig],
subCommands: [ subCommands: [
{ {
@ -396,7 +396,7 @@ export const browserCommands = {
value: "quickcomposer.browser.setCookie", value: "quickcomposer.browser.setCookie",
label: "Cookie操作", label: "Cookie操作",
icon: "cookie", icon: "cookie",
isAsync: true, asyncMode: "await",
config: [tabConfig], config: [tabConfig],
subCommands: [ subCommands: [
{ {
@ -486,7 +486,7 @@ export const browserCommands = {
value: "quickcomposer.browser.clickElement", value: "quickcomposer.browser.clickElement",
label: "元素操作", label: "元素操作",
icon: "web", icon: "web",
isAsync: true, asyncMode: "await",
config: [ config: [
tabConfig, tabConfig,
{ {
@ -591,7 +591,7 @@ export const browserCommands = {
value: "quickcomposer.browser.scrollTo", value: "quickcomposer.browser.scrollTo",
label: "滚动及页面尺寸", label: "滚动及页面尺寸",
icon: "open_in_full", icon: "open_in_full",
isAsync: true, asyncMode: "await",
config: [tabConfig], config: [tabConfig],
subCommands: [ subCommands: [
{ {
@ -631,8 +631,8 @@ export const browserCommands = {
value: "quickcomposer.browser.network.setRequestInterception", value: "quickcomposer.browser.network.setRequestInterception",
label: "修改请求/响应", label: "修改请求/响应",
icon: "network", icon: "network",
isAsync: true, asyncMode: "await",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.browser.network.setRequestInterception", value: "quickcomposer.browser.network.setRequestInterception",
@ -753,7 +753,7 @@ export const browserCommands = {
value: "quickcomposer.browser.device.setDevice", value: "quickcomposer.browser.device.setDevice",
label: "设备模拟", label: "设备模拟",
icon: "devices", icon: "devices",
isAsync: true, asyncMode: "await",
config: [tabConfig], config: [tabConfig],
subCommands: [ subCommands: [
{ {

View File

@ -709,7 +709,7 @@ export const dataCommands = {
label: "数据压缩解压", label: "数据压缩解压",
component: "ZlibEditor", component: "ZlibEditor",
icon: "compress", icon: "compress",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "quickcomposer.data.htmlParser", value: "quickcomposer.data.htmlParser",

View File

@ -7,7 +7,7 @@ export const fileCommands = {
value: "quickcomposer.file.operation", value: "quickcomposer.file.operation",
label: "文件/文件夹操作", label: "文件/文件夹操作",
component: "FileOperationEditor", component: "FileOperationEditor",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "utools.shellOpenItem", value: "utools.shellOpenItem",
@ -67,7 +67,7 @@ export const fileCommands = {
value: "quickcomposer.file.archive", value: "quickcomposer.file.archive",
label: "文件归档", label: "文件归档",
icon: "archive", icon: "archive",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "操作类型", label: "操作类型",

View File

@ -25,7 +25,7 @@ export const imageCommands = {
value: "quickcomposer.image.analyze", value: "quickcomposer.image.analyze",
label: "图片信息", label: "图片信息",
icon: "analytics", icon: "analytics",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "图片文件", label: "图片文件",
@ -54,7 +54,7 @@ export const imageCommands = {
value: "quickcomposer.image.resize", value: "quickcomposer.image.resize",
label: "调整大小", label: "调整大小",
icon: "aspect_ratio", icon: "aspect_ratio",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "输入文件", label: "输入文件",
@ -140,7 +140,7 @@ export const imageCommands = {
value: "quickcomposer.image.rotate", value: "quickcomposer.image.rotate",
label: "旋转图片", label: "旋转图片",
icon: "rotate_right", icon: "rotate_right",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "输入文件", label: "输入文件",
@ -207,7 +207,7 @@ export const imageCommands = {
value: "quickcomposer.image.crop", value: "quickcomposer.image.crop",
label: "裁剪图片", label: "裁剪图片",
icon: "crop", icon: "crop",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "输入文件", label: "输入文件",
@ -302,7 +302,7 @@ export const imageCommands = {
value: "quickcomposer.image.watermark", value: "quickcomposer.image.watermark",
label: "添加水印", label: "添加水印",
icon: "format_color_text", icon: "format_color_text",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "输入文件", label: "输入文件",
@ -409,7 +409,7 @@ export const imageCommands = {
value: "quickcomposer.image.convert", value: "quickcomposer.image.convert",
label: "格式转换", label: "格式转换",
icon: "transform", icon: "transform",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "输入文件", label: "输入文件",

View File

@ -7,7 +7,7 @@ export const macosCommands = {
value: "quickcomposer.macos.app.getFrontmost", value: "quickcomposer.macos.app.getFrontmost",
label: "应用及窗口控制", label: "应用及窗口控制",
icon: "apps", icon: "apps",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.macos.app.getFrontmost", value: "quickcomposer.macos.app.getFrontmost",
@ -15,29 +15,32 @@ export const macosCommands = {
icon: "front_hand", icon: "front_hand",
outputs: { outputs: {
label: "前台应用信息", label: "前台应用信息",
name: { label: "应用名称" }, structure: {
displayedName: { label: "应用显示名称" }, name: { label: "应用名称" },
path: { label: "应用路径" }, displayedName: { label: "应用显示名称" },
version: { label: "应用版本" }, path: { label: "应用路径" },
pid: { label: "应用进程ID" }, version: { label: "应用版本" },
backgroundOnly: { label: "是否后台运行" }, pid: { label: "应用进程ID" },
visible: { label: "是否可见" }, backgroundOnly: { label: "是否后台运行" },
frontmost: { label: "是否前台运行" }, visible: { label: "是否可见" },
window: { frontmost: { label: "是否前台运行" },
label: "窗口信息", window: {
name: { label: "窗口名称" }, label: "窗口信息",
title: { label: "窗口标题" }, name: { label: "窗口名称" },
index: { label: "窗口索引" }, title: { label: "窗口标题" },
position: { index: { label: "窗口索引" },
label: "窗口位置", position: {
placeholder: "数组, 第一个元素是 x 坐标,第二个元素是 y 坐标", label: "窗口位置",
placeholder:
"数组, 第一个元素是 x 坐标,第二个元素是 y 坐标",
},
size: {
label: "窗口大小",
placeholder: "数组, 第一个元素是宽度,第二个元素是高度",
},
minimized: { label: "是否最小化" },
fullscreen: { label: "是否全屏" },
}, },
size: {
label: "窗口大小",
placeholder: "数组, 第一个元素是宽度,第二个元素是高度",
},
minimized: { label: "是否最小化" },
fullscreen: { label: "是否全屏" },
}, },
}, },
}, },
@ -164,7 +167,7 @@ export const macosCommands = {
value: "quickcomposer.macos.system.setVolume", value: "quickcomposer.macos.system.setVolume",
label: "系统管理", label: "系统管理",
icon: "settings", icon: "settings",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.macos.system.setVolume", value: "quickcomposer.macos.system.setVolume",
@ -284,7 +287,7 @@ export const macosCommands = {
value: "quickcomposer.macos.finder.getSelection", value: "quickcomposer.macos.finder.getSelection",
label: "访达管理", label: "访达管理",
icon: "folder", icon: "folder",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.macos.finder.getSelection", value: "quickcomposer.macos.finder.getSelection",

View File

@ -26,14 +26,14 @@ export const networkCommands = {
icon: "public", icon: "public",
}, },
], ],
isAsync: true, asyncMode: "await",
}, },
{ {
value: "ubrowser", value: "ubrowser",
label: "ubrowser浏览器操作", label: "ubrowser浏览器操作",
config: [], config: [],
component: "UBrowserEditor", component: "UBrowserEditor",
isAsync: true, asyncMode: "await",
icon: "public", icon: "public",
}, },
{ {
@ -41,7 +41,7 @@ export const networkCommands = {
label: "HTTP请求(Axios)", label: "HTTP请求(Axios)",
config: [], config: [],
component: "AxiosConfigEditor", component: "AxiosConfigEditor",
isAsync: true, asyncMode: "await",
icon: "http", icon: "http",
}, },
{ {
@ -246,7 +246,7 @@ export const networkCommands = {
value: "quickcomposer.network.dns.lookupHost", value: "quickcomposer.network.dns.lookupHost",
label: "DNS操作", label: "DNS操作",
icon: "dns", icon: "dns",
isAsync: true, asyncMode: "await",
config: [], config: [],
subCommands: [ subCommands: [
{ {
@ -389,7 +389,7 @@ export const networkCommands = {
value: "quickcommand.downloadFile", value: "quickcommand.downloadFile",
label: "下载文件", label: "下载文件",
icon: "file_download", icon: "file_download",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "文件URL", label: "文件URL",
@ -411,7 +411,7 @@ export const networkCommands = {
value: "quickcommand.uploadFile", value: "quickcommand.uploadFile",
label: "上传文件", label: "上传文件",
icon: "file_upload", icon: "file_upload",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "上传接口地址", label: "上传接口地址",

View File

@ -24,7 +24,7 @@ export const scriptCommands = {
label: "运行脚本", label: "运行脚本",
component: "ScriptEditor", component: "ScriptEditor",
desc: "运行各种编程语言的代码", desc: "运行各种编程语言的代码",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "return", value: "return",

View File

@ -216,19 +216,19 @@ export const simulateCommands = {
label: "屏幕找图", label: "屏幕找图",
component: "ImageSearchEditor", component: "ImageSearchEditor",
config: [], config: [],
isAsync: true, asyncMode: "await",
}, },
{ {
value: "quickcomposer.simulate.screenColorPick", value: "quickcomposer.simulate.screenColorPick",
label: "屏幕取色", label: "屏幕取色",
icon: "colorize", icon: "colorize",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "quickcomposer.simulate.captureScreen", value: "quickcomposer.simulate.captureScreen",
label: "屏幕截图", label: "屏幕截图",
icon: "screenshot_monitor", icon: "screenshot_monitor",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "截图范围", label: "截图范围",

View File

@ -6,31 +6,31 @@ export const statusCommands = {
value: "utools.readCurrentFolderPath", value: "utools.readCurrentFolderPath",
label: "获取当前文件管理器路径", label: "获取当前文件管理器路径",
icon: "folder", icon: "folder",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "utools.readCurrentBrowserUrl", value: "utools.readCurrentBrowserUrl",
label: "获取当前浏览器地址", label: "获取当前浏览器地址",
icon: "language", icon: "language",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "quickcomposer.status.getSelectedText", value: "quickcomposer.status.getSelectedText",
label: "获取选中文本", label: "获取选中文本",
icon: "text_fields", icon: "text_fields",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "quickcomposer.status.getSelectedImage", value: "quickcomposer.status.getSelectedImage",
label: "获取选中的图片", label: "获取选中的图片",
icon: "image", icon: "image",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "quickcomposer.status.getSelectedFiles", value: "quickcomposer.status.getSelectedFiles",
label: "获取选中的文件", label: "获取选中的文件",
icon: "file_present", icon: "file_present",
isAsync: true, asyncMode: "await",
}, },
], ],
}; };

View File

@ -105,7 +105,7 @@ export const systemCommands = {
label: "执行系统命令", label: "执行系统命令",
component: "SystemCommandEditor", component: "SystemCommandEditor",
icon: "terminal", icon: "terminal",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "utools.getPath", value: "utools.getPath",

View File

@ -111,7 +111,7 @@ export const uiCommands = {
{ {
value: "quickcommand.showMessageBox", value: "quickcommand.showMessageBox",
label: "消息提示", label: "消息提示",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "提示内容", label: "提示内容",
@ -168,7 +168,7 @@ export const uiCommands = {
{ {
value: "quickcommand.showConfirmBox", value: "quickcommand.showConfirmBox",
label: "确认框", label: "确认框",
isAsync: true, asyncMode: "await",
outputs: { outputs: {
label: "是否确认", label: "是否确认",
}, },
@ -219,7 +219,7 @@ export const uiCommands = {
{ {
value: "quickcommand.showButtonBox", value: "quickcommand.showButtonBox",
label: "按钮组", label: "按钮组",
isAsync: true, asyncMode: "await",
width: 12, width: 12,
config: [ config: [
{ {
@ -254,7 +254,7 @@ export const uiCommands = {
{ {
value: "quickcommand.showInputBox", value: "quickcommand.showInputBox",
label: "输入框", label: "输入框",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "输入框", label: "输入框",
@ -293,12 +293,12 @@ export const uiCommands = {
value: "quickcommand.showSelectList", value: "quickcommand.showSelectList",
label: "选择列表", label: "选择列表",
component: "SelectListEditor", component: "SelectListEditor",
isAsync: true, asyncMode: "await",
}, },
{ {
value: "quickcommand.showTextArea", value: "quickcommand.showTextArea",
label: "文本框", label: "文本框",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "文本框占位符", label: "文本框占位符",
@ -329,7 +329,7 @@ export const uiCommands = {
{ {
value: "quickcommand.showSystemWaitButton", value: "quickcommand.showSystemWaitButton",
label: "等待操作按钮", label: "等待操作按钮",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
component: "OptionEditor", component: "OptionEditor",

View File

@ -199,7 +199,7 @@ export const windowsCommands = {
value: "quickcomposer.windows.window.getWindowInfo", value: "quickcomposer.windows.window.getWindowInfo",
label: "搜索/选择窗口", label: "搜索/选择窗口",
icon: "window", icon: "window",
isAsync: true, asyncMode: "await",
config: [], config: [],
subCommands: [ subCommands: [
{ {
@ -207,6 +207,22 @@ export const windowsCommands = {
value: "quickcomposer.windows.window.getWindowInfo", value: "quickcomposer.windows.window.getWindowInfo",
label: "搜索窗口", label: "搜索窗口",
icon: "search", icon: "search",
outputs: {
label: "窗口信息(数组)",
structure: [
{
handle: { label: "窗口句柄" },
title: { label: "窗口标题" },
class: { label: "窗口类名" },
x: { label: "窗口X坐标" },
y: { label: "窗口Y坐标" },
width: { label: "窗口宽度" },
height: { label: "窗口高度" },
processName: { label: "窗口进程名" },
processPath: { label: "窗口进程路径" },
},
],
},
}, },
{ {
value: "quickcomposer.windows.automation.inspect", value: "quickcomposer.windows.automation.inspect",
@ -381,14 +397,14 @@ export const windowsCommands = {
], ],
}, },
], ],
isAsync: true, asyncMode: "await",
}, },
// automation // automation
{ {
value: "quickcomposer.windows.automation.click", value: "quickcomposer.windows.automation.click",
label: "界面自动化", label: "界面自动化",
icon: "smart_button", icon: "smart_button",
isAsync: true, asyncMode: "await",
config: searchElementConfig, config: searchElementConfig,
subCommands: [ subCommands: [
{ {
@ -611,7 +627,7 @@ export const windowsCommands = {
value: "quickcomposer.windows.sendmessage.listControls", value: "quickcomposer.windows.sendmessage.listControls",
label: "发送控制消息", label: "发送控制消息",
icon: "smart_button", icon: "smart_button",
isAsync: true, asyncMode: "await",
config: windowHandleConfig, config: windowHandleConfig,
subCommands: [ subCommands: [
{ {
@ -804,7 +820,7 @@ export const windowsCommands = {
value: "quickcomposer.windows.monitor.watchClipboard", value: "quickcomposer.windows.monitor.watchClipboard",
label: "剪贴板/文件监控", label: "剪贴板/文件监控",
icon: "monitor_heart", icon: "monitor_heart",
isAsync: true, asyncMode: "await",
showLoading: true, showLoading: true,
subCommands: [ subCommands: [
{ {
@ -866,7 +882,7 @@ export const windowsCommands = {
value: "quickcomposer.windows.process.listProcesses", value: "quickcomposer.windows.process.listProcesses",
label: "进程管理", label: "进程管理",
icon: "memory", icon: "memory",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.windows.process.listProcesses", value: "quickcomposer.windows.process.listProcesses",
@ -928,7 +944,7 @@ export const windowsCommands = {
value: "quickcomposer.windows.registry.listKeys", value: "quickcomposer.windows.registry.listKeys",
label: "注册表管理", label: "注册表管理",
icon: "settings", icon: "settings",
isAsync: true, asyncMode: "await",
config: [ config: [
{ {
label: "注册表路径", label: "注册表路径",
@ -1053,7 +1069,7 @@ export const windowsCommands = {
value: "quickcomposer.windows.service.listServices", value: "quickcomposer.windows.service.listServices",
label: "服务管理", label: "服务管理",
icon: "miscellaneous_services", icon: "miscellaneous_services",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.windows.service.listServices", value: "quickcomposer.windows.service.listServices",
@ -1095,7 +1111,7 @@ export const windowsCommands = {
value: "quickcomposer.windows.software.listSoftware", value: "quickcomposer.windows.software.listSoftware",
label: "软件管理", label: "软件管理",
icon: "apps", icon: "apps",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.windows.software.listSoftware", value: "quickcomposer.windows.software.listSoftware",
@ -1124,7 +1140,7 @@ export const windowsCommands = {
value: "quickcomposer.windows.utils.setWallpaper", value: "quickcomposer.windows.utils.setWallpaper",
label: "系统工具", label: "系统工具",
icon: "build", icon: "build",
isAsync: true, asyncMode: "await",
subCommands: [ subCommands: [
{ {
value: "quickcomposer.windows.utils.setWallpaper", value: "quickcomposer.windows.utils.setWallpaper",

View File

@ -103,7 +103,7 @@ const commonComponentGuide = {
}, },
optionalFields: { optionalFields: {
desc: "命令描述", desc: "命令描述",
isAsync: "是否异步命令", asyncMode: "async模式可选值为await/then",
icon: "命令图标", icon: "命令图标",
}, },
}, },

View File

@ -270,7 +270,7 @@ const customComponentGuide = {
}, },
optionalFields: { optionalFields: {
desc: "命令描述", desc: "命令描述",
isAsync: "是否异步命令", asyncMode: "async模式可选值为await/then",
isControlFlow: "是否控制流命令", isControlFlow: "是否控制流命令",
}, },
}, },

View File

@ -1,10 +1,28 @@
export function generateCode(flow) { export function generateCode(flow) {
let usedVarNames = {};
// 获取变量赋值代码,如果变量已经存在,则直接赋值,否则声明并赋值
const getVarAssignCode = (varName, varValue, funcName) => {
if (!usedVarNames[funcName]) {
usedVarNames[funcName] = [];
}
if (usedVarNames[funcName].includes(varName)) {
return `${varName} = ${varValue};`;
}
usedVarNames[funcName].push(varName);
return `let ${varName} = ${varValue};`;
};
const getVarByPath = (name, path) => {
return `${name}${path.startsWith("[") ? "" : "."}${path}`;
};
const { commands, name, label, customVariables = [] } = flow; const { commands, name, label, customVariables = [] } = flow;
const params = customVariables.filter((v) => v.type === "param") || []; const params = customVariables.filter((v) => v.type === "param") || [];
const manualVars = customVariables.filter((v) => v.type === "var") || []; const manualVars = customVariables.filter((v) => v.type === "var") || [];
// 检查是否包含异步函数 // 检查是否包含异步函数
const hasAsyncFunction = commands.some((cmd) => cmd.isAsync); const hasAsyncFunction = commands.some((cmd) => cmd.asyncMode);
let code = []; let code = [];
const funcName = name || "func_" + new Date().getTime(); const funcName = name || "func_" + new Date().getTime();
@ -17,9 +35,13 @@ export function generateCode(flow) {
.join(", ")}) {` .join(", ")}) {`
); );
code.push(manualVars.map((v) => ` let ${v.name} = ${v.value};`).join("\n"));
const indent = " "; const indent = " ";
// 局部变量赋值
manualVars.forEach((v) => {
code.push(indent + getVarAssignCode(v.name, v.value, flow.name));
});
commands.forEach((cmd) => { commands.forEach((cmd) => {
// 跳过禁用的命令 // 跳过禁用的命令
if (cmd.disabled) return; if (cmd.disabled) return;
@ -29,36 +51,71 @@ export function generateCode(flow) {
// 处理输出变量 // 处理输出变量
if (cmd.outputVariable) { if (cmd.outputVariable) {
const { name, details } = cmd.outputVariable; const { name, details } = cmd.outputVariable;
if (cmd.isAsync) { if (cmd.asyncMode === "then") {
// 使用回调函数模式
if (cmd.callbackFunc) { if (cmd.callbackFunc) {
// 使用回调函数模式 // 如果回调函数存在,则使用回调函数模式,否则保持原样
cmdCode = `${cmdCode}.then(${cmd.callbackFunc})`; if (!details) {
} else { cmdCode = `${cmdCode}.then(${cmd.callbackFunc})`;
// 使用 await 模式 } else {
cmdCode = `const ${name} = await ${cmdCode}`; // 如果输出变量有详细变量,则需要为每个变量赋值
code.push(indent + cmdCode); const promiseName = name || "result";
// 处理详细变量
if (details) { const extractVarCode = Object.entries(details)
Object.entries(details).forEach(([path, varName]) => { .map(
code.push(`${indent}let ${varName} = ${name}.${path};`); ([path, varName]) =>
}); `let ${varName} = ${getVarByPath(promiseName, path)}`
)
.join("\n");
const funcName = cmd.callbackFunc;
const funcParams =
(name ? `${name},` : "") + Object.values(details).join(",");
cmdCode = `${cmdCode}.then((${promiseName})=>{
${extractVarCode}
${funcName}(${funcParams})
})`;
} }
return;
} }
} else { code.push(indent + cmdCode);
cmdCode = `const ${name} = ${cmdCode}`; } else if (cmd.asyncMode === "await") {
// 使用 await 模式
const promiseName = name || "result";
cmdCode = getVarAssignCode(promiseName, `await ${cmdCode}`);
code.push(indent + cmdCode); code.push(indent + cmdCode);
// 处理详细变量 // 处理详细变量
if (details) { if (details) {
Object.entries(details).forEach(([path, varName]) => { Object.entries(details).forEach(([path, varName]) => {
code.push(`${indent}let ${varName} = ${name}.${path};`); code.push(
`${indent}${getVarAssignCode(
varName,
getVarByPath(promiseName, path)
)}`
);
});
}
} else {
// 非Async命令
cmdCode = getVarAssignCode(name, `${cmdCode}`);
code.push(indent + cmdCode);
// 处理详细变量
if (details) {
Object.entries(details).forEach(([path, varName]) => {
code.push(
`${indent}${getVarAssignCode(varName, getVarByPath(name, path))}`
);
}); });
} }
return; return;
} }
} else {
if (cmd.asyncMode === "await") {
cmdCode = `await ${cmdCode}`;
}
code.push(indent + cmdCode);
} }
code.push(indent + cmdCode);
}); });
code.push("}"); // Close the function code.push("}"); // Close the function

View File

@ -7,12 +7,7 @@ import { validateVariableName } from "js/common/variableValidator";
*/ */
function generateRandomSuffix(varCount, withPrefix = true) { function generateRandomSuffix(varCount, withPrefix = true) {
// 根据变量数量决定后缀长度 // 根据变量数量决定后缀长度
let length = 1; // 默认1位 let length = varCount > 100 ? 3 : 2;
if (varCount >= 100) {
length = 3;
} else if (varCount >= 10) {
length = 2;
}
return ( return (
(withPrefix ? "_" : "") + (withPrefix ? "_" : "") +
@ -100,7 +95,9 @@ export function processVariable({ value, existingVars, baseName = "var" }) {
isValid: true, isValid: true,
processedValue: processedVar, processedValue: processedVar,
warning: warning:
processedVar !== value ? `输入值非法,已被修改为: ${processedVar}` : null, processedVar !== value
? `输入值非法,已被修改为: ${processedVar}`
: null,
}; };
} }