补全条件分支、异常处理、条件循环、遍历对象四个控制流程

This commit is contained in:
fofolee 2025-01-02 13:16:23 +08:00
parent db3d2428c8
commit 51e6e91ee1
10 changed files with 1005 additions and 59 deletions

View File

@ -28,6 +28,7 @@
:command="command" :command="command"
v-bind="command.componentProps || {}" v-bind="command.componentProps || {}"
:type="command.commandType" :type="command.commandType"
class="control-component"
@addBranch="(chainInfo) => $emit('addBranch', chainInfo)" @addBranch="(chainInfo) => $emit('addBranch', chainInfo)"
/> />
</template> </template>
@ -67,11 +68,12 @@
</template> </template>
<script> <script>
import { defineComponent, inject, defineAsyncComponent } from "vue"; import { defineComponent, inject } from "vue";
import { validateVariableName } from "js/common/variableValidator"; import { validateVariableName } from "js/common/variableValidator";
import VariableInput from "components/composer/ui/VariableInput.vue"; import VariableInput from "./ui/VariableInput.vue";
import MultiParamInput from "components/composer/ui/MultiParamInput.vue"; import MultiParamInput from "./ui/MultiParamInput.vue";
import CommandHead from "components/composer/card/CommandHead.vue"; import CommandHead from "./card/CommandHead.vue";
import * as CardComponents from "js/composer/cardComponents";
export default defineComponent({ export default defineComponent({
name: "ComposerCard", name: "ComposerCard",
@ -79,33 +81,7 @@ export default defineComponent({
VariableInput, VariableInput,
MultiParamInput, MultiParamInput,
CommandHead, CommandHead,
KeyEditor: defineAsyncComponent(() => ...CardComponents,
import("components/composer/ui/KeyEditor.vue")
),
UBrowserEditor: defineAsyncComponent(() =>
import("components/composer/ubrowser/UBrowserEditor.vue")
),
AxiosConfigEditor: defineAsyncComponent(() =>
import("components/composer/http/AxiosConfigEditor.vue")
),
SymmetricCryptoEditor: defineAsyncComponent(() =>
import("components/composer/crypto/SymmetricCryptoEditor.vue")
),
AsymmetricCryptoEditor: defineAsyncComponent(() =>
import("components/composer/crypto/AsymmetricCryptoEditor.vue")
),
FunctionSelector: defineAsyncComponent(() =>
import("components/composer/ui/FunctionSelector.vue")
),
RegexEditor: defineAsyncComponent(() =>
import("components/composer/regex/RegexEditor.vue")
),
ConditionalJudgment: defineAsyncComponent(() =>
import("components/composer/control/ConditionalJudgment.vue")
),
LoopControl: defineAsyncComponent(() =>
import("components/composer/control/LoopControl.vue")
),
}, },
props: { props: {
command: { command: {
@ -323,6 +299,14 @@ export default defineComponent({
position: relative; position: relative;
} }
/* 控制流程组件样式 */
.control-component {
flex: 1;
display: flex;
align-items: center;
width: 100%;
}
.composer-card, .composer-card,
.composer-card::before, .composer-card::before,
.composer-card .command-item { .composer-card .command-item {

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="conditional-judgment"> <div class="conditional-judgment-wrapper">
<div class="row items-end no-wrap"> <div class="conditional-judgment">
<!-- 类型标签 --> <!-- 类型标签 -->
<div class="control-type-label"> <div class="control-type-label">
<template v-if="type === 'if'">如果</template> <template v-if="type === 'if'">如果</template>
@ -8,14 +8,26 @@
<template v-else>结束</template> <template v-else>结束</template>
</div> </div>
<!-- 条件输入区域 -->
<div class="condition-settings">
<template v-if="showCondition">
<ControlInput
v-model="conditionLocal"
label="条件"
placeholder="表达式"
class="condition-input"
/>
</template>
</div>
<!-- if类型显示添加按钮 --> <!-- if类型显示添加按钮 -->
<q-btn <q-btn
v-if="type === 'if'" v-if="type === 'if'"
flat flat
dense dense
size="sm"
icon="add" icon="add"
class="control-btn q-mx-xs" size="sm"
class="control-btn"
@click=" @click="
$emit('addBranch', { $emit('addBranch', {
chainId: command.chainId, chainId: command.chainId,
@ -33,20 +45,11 @@
dense dense
size="sm" size="sm"
:icon="showCondition ? 'remove' : 'add'" :icon="showCondition ? 'remove' : 'add'"
class="control-btn q-mx-xs" class="control-btn"
@click="toggleCondition" @click="toggleCondition"
> >
<q-tooltip>{{ showCondition ? "隐藏条件" : "显示条件" }}</q-tooltip> <q-tooltip>{{ showCondition ? "隐藏条件" : "显示条件" }}</q-tooltip>
</q-btn> </q-btn>
<!-- 条件输入框 -->
<ControlInput
v-if="showCondition"
v-model="conditionLocal"
label="条件"
placeholder="表达式"
class="condition-input"
/>
</div> </div>
</div> </div>
</template> </template>
@ -159,24 +162,43 @@ export default defineComponent({
</script> </script>
<style scoped> <style scoped>
.conditional-judgment-wrapper {
width: 100%;
display: flex;
}
.conditional-judgment {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
}
.control-type-label { .control-type-label {
font-size: 13px; font-size: 13px;
font-weight: 500;
white-space: nowrap; white-space: nowrap;
opacity: 0.9; opacity: 0.9;
user-select: none; user-select: none;
} }
.condition-settings {
display: flex;
gap: 4px;
flex: 1;
min-width: 0;
}
.condition-input { .condition-input {
flex: 1; flex: 1;
transition: all 0.3s ease; min-width: 0;
} }
.control-btn { .control-btn {
width: 21px; width: 21px;
height: 21px; height: 21px;
min-height: 21px;
opacity: 0.7; opacity: 0.7;
transition: all 0.2s ease; flex-shrink: 0;
} }
.control-btn:hover { .control-btn:hover {

View File

@ -2,7 +2,7 @@
<div class="loop-control-wrapper" v-bind="$attrs"> <div class="loop-control-wrapper" v-bind="$attrs">
<div class="loop-control row items-center no-wrap"> <div class="loop-control row items-center no-wrap">
<!-- 类型标签和按钮区域 --> <!-- 类型标签和按钮区域 -->
<div class="control-type-label q-mr-sm"> <div class="control-type-label">
<template v-if="type === 'forEach'">开始</template> <template v-if="type === 'forEach'">开始</template>
<template v-else-if="type === 'continue'">继续</template> <template v-else-if="type === 'continue'">继续</template>
<template v-else-if="type === 'break'">终止</template> <template v-else-if="type === 'break'">终止</template>
@ -38,7 +38,7 @@
dropdown-icon="add" dropdown-icon="add"
no-icon-animation no-icon-animation
size="sm" size="sm"
class="control-btn q-ml-sm" class="control-btn"
> >
<q-list> <q-list>
<q-item <q-item
@ -128,12 +128,6 @@ export default defineComponent({
}, },
}, },
watch: { watch: {
type: {
immediate: true,
handler(val) {
console.log("ForEachControl type:", val);
},
},
modelValue: { modelValue: {
immediate: true, immediate: true,
handler(val) { handler(val) {
@ -179,11 +173,14 @@ export default defineComponent({
<style scoped> <style scoped>
.loop-control-wrapper { .loop-control-wrapper {
width: 100%; width: 100%;
display: flex;
} }
.loop-control { .loop-control {
width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px;
} }
.control-type-label { .control-type-label {
@ -198,6 +195,7 @@ export default defineComponent({
width: 21px; width: 21px;
height: 21px; height: 21px;
opacity: 0.7; opacity: 0.7;
flex-shrink: 0;
} }
.control-btn:hover { .control-btn:hover {
@ -209,6 +207,7 @@ export default defineComponent({
display: flex; display: flex;
gap: 4px; gap: 4px;
flex: 1; flex: 1;
min-width: 0;
} }
.loop-input { .loop-input {

View File

@ -0,0 +1,235 @@
<template>
<div class="loop-control-wrapper" v-bind="$attrs">
<div class="loop-control row items-center no-wrap">
<!-- 类型标签和按钮区域 -->
<div class="control-type-label">
<template v-if="type === 'forIn'">开始</template>
<template v-else-if="type === 'continue'">继续</template>
<template v-else-if="type === 'break'">终止</template>
<template v-else>结束</template>
</div>
<!-- 遍历设置区域 -->
<div v-if="type === 'forIn'" class="loop-settings">
<ControlInput
v-model="keyVar"
label="键名"
:is-variable="true"
class="loop-input"
/>
<ControlInput
v-model="valueVar"
label="值"
:is-variable="true"
class="loop-input"
/>
<ControlInput
v-model="objectVar"
label="对象"
class="loop-input object-input"
/>
</div>
<!-- 只在循环开始时显示添加按钮 -->
<q-btn-dropdown
v-if="type === 'forIn'"
flat
dense
dropdown-icon="add"
no-icon-animation
size="sm"
class="control-btn"
>
<q-list>
<q-item
clickable
v-close-popup
@click="
$emit('addBranch', {
chainId: command.chainId,
commandType: 'continue',
})
"
>
<q-item-section>
<q-item-label>添加继续循环</q-item-label>
</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="
$emit('addBranch', {
chainId: command.chainId,
commandType: 'break',
})
"
>
<q-item-section>
<q-item-label>添加终止循环</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import ControlInput from "../ui/ControlInput.vue";
export default defineComponent({
name: "ForInControl",
components: {
ControlInput,
},
inheritAttrs: false,
props: {
modelValue: String,
command: Object,
type: {
type: String,
required: true,
validator: (value) =>
["forIn", "continue", "break", "end"].includes(value),
},
},
emits: ["update:modelValue", "addBranch"],
data() {
return {
keyVar: "key",
valueVar: "value",
objectVar: "obj",
};
},
created() {
if (!this.modelValue) {
this.updateValue();
}
},
computed: {
generatedCode() {
switch (this.type) {
case "forIn":
const key = this.keyVar || "key";
const value = this.valueVar || "value";
const obj = this.objectVar || "obj";
return `for(const ${key} in ${obj}){const ${value}=${obj}[${key}];`;
case "continue":
return "continue;";
case "break":
return "break;";
case "end":
return "}";
default:
return "";
}
},
},
watch: {
type: {
immediate: true,
handler(val) {
console.log("ForInControl type:", val);
},
},
modelValue: {
immediate: true,
handler(val) {
if (val) {
this.parseCodeString(val);
}
},
},
keyVar() {
this.updateValue();
},
valueVar() {
this.updateValue();
},
objectVar() {
this.updateValue();
},
},
methods: {
updateValue() {
this.$emit("update:modelValue", this.generatedCode);
},
parseCodeString(val) {
try {
if (this.type === "forIn") {
const match = val.match(
/^for\(const\s+(\w+)\s+in\s+(\w+|\$\{.+\})\){const\s+(\w+)=.*$/
);
if (match) {
this.keyVar = match[1];
this.objectVar = match[2];
this.valueVar = match[3];
}
}
} catch (e) {
console.error("Failed to parse code string:", e);
}
},
},
});
</script>
<style scoped>
.loop-control-wrapper {
width: 100%;
display: flex;
}
.loop-control {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
}
.control-type-label {
font-size: 13px;
font-weight: 500;
white-space: nowrap;
opacity: 0.9;
user-select: none;
}
.control-btn {
width: 21px;
height: 21px;
opacity: 0.7;
flex-shrink: 0;
}
.control-btn:hover {
opacity: 1;
transform: scale(1.1);
}
.loop-settings {
display: flex;
gap: 4px;
flex: 1;
min-width: 0;
}
.loop-input {
width: 80px;
}
.object-input {
width: 120px;
}
/* 暗色模式适配 */
.body--dark .control-btn {
color: rgba(255, 255, 255, 0.7);
}
.body--dark .control-btn:hover {
color: var(--q-primary);
}
</style>

View File

@ -2,7 +2,7 @@
<div class="loop-control-wrapper" v-bind="$attrs"> <div class="loop-control-wrapper" v-bind="$attrs">
<div class="loop-control row items-center no-wrap"> <div class="loop-control row items-center no-wrap">
<!-- 类型标签和按钮区域 --> <!-- 类型标签和按钮区域 -->
<div class="control-type-label q-mr-sm"> <div class="control-type-label">
<template v-if="type === 'loop'">开始</template> <template v-if="type === 'loop'">开始</template>
<template v-else-if="type === 'continue'">继续</template> <template v-else-if="type === 'continue'">继续</template>
<template v-else-if="type === 'break'">终止</template> <template v-else-if="type === 'break'">终止</template>
@ -30,7 +30,7 @@
dropdown-icon="add" dropdown-icon="add"
no-icon-animation no-icon-animation
size="sm" size="sm"
class="control-btn q-ml-sm" class="control-btn"
> >
<q-list> <q-list>
<q-item <q-item
@ -171,11 +171,14 @@ export default defineComponent({
<style scoped> <style scoped>
.loop-control-wrapper { .loop-control-wrapper {
width: 100%; width: 100%;
display: flex;
} }
.loop-control { .loop-control {
width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px;
} }
.control-type-label { .control-type-label {
@ -190,6 +193,7 @@ export default defineComponent({
width: 21px; width: 21px;
height: 21px; height: 21px;
opacity: 0.7; opacity: 0.7;
flex-shrink: 0;
} }
.control-btn:hover { .control-btn:hover {
@ -201,6 +205,7 @@ export default defineComponent({
display: flex; display: flex;
gap: 4px; gap: 4px;
flex: 1; flex: 1;
min-width: 0;
} }
.loop-input { .loop-input {

View File

@ -0,0 +1,219 @@
<template>
<div class="switch-control-wrapper">
<div class="switch-control">
<!-- 类型标签 -->
<div class="control-type-label">
<template v-if="type === 'switch'">选择</template>
<template v-else-if="type === 'case'">匹配</template>
<template v-else-if="type === 'default'">默认</template>
<template v-else>结束</template>
</div>
<!-- 条件输入区域 -->
<div class="switch-settings">
<template v-if="type === 'switch'">
<ControlInput
v-model="expression"
label="变量"
placeholder="变量或表达式"
class="switch-input"
/>
</template>
<template v-else-if="type === 'case'">
<ControlInput
v-model="value"
label="值"
placeholder="匹配值"
class="switch-input"
/>
</template>
</div>
<!-- 只在switch开始时显示添加按钮 -->
<q-btn-dropdown
v-if="type === 'switch'"
flat
dense
dropdown-icon="add"
no-icon-animation
size="sm"
class="control-btn"
>
<q-list>
<q-item
clickable
v-close-popup
@click="
$emit('addBranch', {
chainId: command.chainId,
commandType: 'case',
})
"
>
<q-item-section>
<q-item-label>添加匹配分支</q-item-label>
</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="
$emit('addBranch', {
chainId: command.chainId,
commandType: 'default',
})
"
>
<q-item-section>
<q-item-label>添加默认分支</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import ControlInput from "../ui/ControlInput.vue";
export default defineComponent({
name: "SwitchControl",
components: {
ControlInput,
},
inheritAttrs: false,
props: {
modelValue: String,
command: Object,
type: {
type: String,
required: true,
validator: (value) =>
["switch", "case", "default", "end"].includes(value),
},
},
emits: ["update:modelValue", "addBranch"],
data() {
return {
expression: "",
value: "",
};
},
created() {
if (!this.modelValue) {
this.updateValue();
}
},
computed: {
generatedCode() {
switch (this.type) {
case "switch":
return `switch(${this.expression || "value"}){`;
case "case":
return `case ${this.value}:`;
case "default":
return "default:";
case "end":
return "}";
default:
return "";
}
},
},
watch: {
modelValue: {
immediate: true,
handler(val) {
if (val) {
this.parseCodeString(val);
}
},
},
expression() {
this.updateValue();
},
value() {
this.updateValue();
},
},
methods: {
updateValue() {
this.$emit("update:modelValue", this.generatedCode);
},
parseCodeString(val) {
try {
if (this.type === "switch") {
const match = val.match(/^switch\((.*)\){$/);
if (match) {
this.expression = match[1];
}
} else if (this.type === "case") {
const match = val.match(/^case\s+(.*):$/);
if (match) {
this.value = match[1];
}
}
} catch (e) {
console.error("Failed to parse code string:", e);
}
},
},
});
</script>
<style scoped>
.switch-control-wrapper {
width: 100%;
display: flex;
}
.switch-control {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
}
.control-type-label {
font-size: 13px;
font-weight: 500;
white-space: nowrap;
opacity: 0.9;
user-select: none;
}
.control-btn {
width: 21px;
height: 21px;
opacity: 0.7;
flex-shrink: 0;
}
.control-btn:hover {
opacity: 1;
transform: scale(1.1);
}
.switch-settings {
display: flex;
gap: 4px;
flex: 1;
min-width: 0;
}
.switch-input {
flex: 1;
min-width: 0;
}
/* 暗色模式适配 */
.body--dark .control-btn {
color: rgba(255, 255, 255, 0.7);
}
.body--dark .control-btn:hover {
color: var(--q-primary);
}
</style>

View File

@ -0,0 +1,201 @@
<template>
<div class="try-catch-wrapper">
<div class="try-catch">
<!-- 类型标签 -->
<div class="control-type-label">
<template v-if="type === 'try'">尝试</template>
<template v-else-if="type === 'catch'">捕获</template>
<template v-else-if="type === 'finally'">最后</template>
<template v-else>结束</template>
</div>
<!-- 错误变量输入区域 -->
<div class="try-catch-settings">
<template v-if="type === 'catch'">
<ControlInput
v-model="errorVar"
label="错误"
placeholder="错误变量名"
class="error-input"
/>
</template>
</div>
<!-- 只在try开始时显示添加按钮 -->
<q-btn-dropdown
v-if="type === 'try'"
flat
dense
dropdown-icon="add"
no-icon-animation
size="sm"
class="control-btn"
>
<q-list>
<q-item
clickable
v-close-popup
@click="
$emit('addBranch', {
chainId: command.chainId,
commandType: 'catch',
})
"
>
<q-item-section>
<q-item-label>添加捕获分支</q-item-label>
</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="
$emit('addBranch', {
chainId: command.chainId,
commandType: 'finally',
})
"
>
<q-item-section>
<q-item-label>添加最后分支</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import ControlInput from "../ui/ControlInput.vue";
export default defineComponent({
name: "TryCatchControl",
components: {
ControlInput,
},
inheritAttrs: false,
props: {
modelValue: String,
command: Object,
type: {
type: String,
required: true,
validator: (value) => ["try", "catch", "finally", "end"].includes(value),
},
},
emits: ["update:modelValue", "addBranch"],
data() {
return {
errorVar: "error",
};
},
created() {
if (!this.modelValue) {
this.updateValue();
}
},
computed: {
generatedCode() {
switch (this.type) {
case "try":
return "try{";
case "catch":
return `}catch(${this.errorVar}){`;
case "finally":
return "}finally{";
case "end":
return "}";
default:
return "";
}
},
},
watch: {
modelValue: {
immediate: true,
handler(val) {
if (val) {
this.parseCodeString(val);
}
},
},
errorVar() {
this.updateValue();
},
},
methods: {
updateValue() {
this.$emit("update:modelValue", this.generatedCode);
},
parseCodeString(val) {
try {
if (this.type === "catch") {
const match = val.match(/^}catch\((.*)\){$/);
if (match) {
this.errorVar = match[1];
}
}
} catch (e) {
console.error("Failed to parse code string:", e);
}
},
},
});
</script>
<style scoped>
.try-catch-wrapper {
width: 100%;
display: flex;
}
.try-catch {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
}
.control-type-label {
font-size: 13px;
font-weight: 500;
white-space: nowrap;
opacity: 0.9;
user-select: none;
}
.control-btn {
width: 21px;
height: 21px;
opacity: 0.7;
flex-shrink: 0;
}
.control-btn:hover {
opacity: 1;
transform: scale(1.1);
}
.try-catch-settings {
display: flex;
gap: 4px;
flex: 1;
min-width: 0;
}
.error-input {
flex: 1;
min-width: 0;
}
/* 暗色模式适配 */
.body--dark .control-btn {
color: rgba(255, 255, 255, 0.7);
}
.body--dark .control-btn:hover {
color: var(--q-primary);
}
</style>

View File

@ -0,0 +1,202 @@
<template>
<div class="loop-control-wrapper">
<div class="loop-control">
<!-- 类型标签 -->
<div class="control-type-label">
<template v-if="type === 'while'">满足</template>
<template v-else-if="type === 'continue'">继续</template>
<template v-else-if="type === 'break'">终止</template>
<template v-else>结束</template>
</div>
<!-- 循环条件区域 -->
<div class="loop-settings">
<template v-if="type === 'while'">
<ControlInput
v-model="condition"
label="条件"
placeholder="表达式"
class="condition-input"
/>
</template>
</div>
<!-- 只在循环开始时显示添加按钮 -->
<q-btn-dropdown
v-if="type === 'while'"
flat
dense
dropdown-icon="add"
no-icon-animation
size="sm"
class="control-btn"
>
<q-list>
<q-item
clickable
v-close-popup
@click="
$emit('addBranch', {
chainId: command.chainId,
commandType: 'continue',
})
"
>
<q-item-section>
<q-item-label>添加继续循环</q-item-label>
</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="
$emit('addBranch', {
chainId: command.chainId,
commandType: 'break',
})
"
>
<q-item-section>
<q-item-label>添加终止循环</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import ControlInput from "../ui/ControlInput.vue";
export default defineComponent({
name: "WhileControl",
components: {
ControlInput,
},
inheritAttrs: false,
props: {
modelValue: String,
command: Object,
type: {
type: String,
required: true,
validator: (value) =>
["while", "continue", "break", "end"].includes(value),
},
},
emits: ["update:modelValue", "addBranch"],
data() {
return {
condition: "true",
};
},
created() {
if (!this.modelValue) {
this.updateValue();
}
},
computed: {
generatedCode() {
switch (this.type) {
case "while":
return `while(${this.condition}){`;
case "continue":
return "continue;";
case "break":
return "break;";
case "end":
return "}";
default:
return "";
}
},
},
watch: {
modelValue: {
immediate: true,
handler(val) {
if (val) {
this.parseCodeString(val);
}
},
},
condition() {
this.updateValue();
},
},
methods: {
updateValue() {
this.$emit("update:modelValue", this.generatedCode);
},
parseCodeString(val) {
try {
if (this.type === "while") {
const match = val.match(/^while\((.*)\){$/);
if (match) {
this.condition = match[1];
}
}
} catch (e) {
console.error("Failed to parse code string:", e);
}
},
},
});
</script>
<style scoped>
.loop-control-wrapper {
width: 100%;
display: flex;
}
.loop-control {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
}
.control-type-label {
font-size: 13px;
font-weight: 500;
white-space: nowrap;
opacity: 0.9;
user-select: none;
}
.control-btn {
width: 21px;
height: 21px;
opacity: 0.7;
flex-shrink: 0;
}
.control-btn:hover {
opacity: 1;
transform: scale(1.1);
}
.loop-settings {
display: flex;
gap: 4px;
flex: 1;
min-width: 0;
}
.condition-input {
flex: 1;
min-width: 0;
}
/* 暗色模式适配 */
.body--dark .control-btn {
color: rgba(255, 255, 255, 0.7);
}
.body--dark .control-btn:hover {
color: var(--q-primary);
}
</style>

View File

@ -0,0 +1,51 @@
import { defineAsyncComponent } from "vue";
// UI Components
export const KeyEditor = defineAsyncComponent(() =>
import("components/composer/ui/KeyEditor.vue")
);
export const FunctionSelector = defineAsyncComponent(() =>
import("components/composer/ui/FunctionSelector.vue")
);
// Control Flow Components
export const ConditionalJudgment = defineAsyncComponent(() =>
import("components/composer/control/ConditionalJudgment.vue")
);
export const LoopControl = defineAsyncComponent(() =>
import("components/composer/control/LoopControl.vue")
);
export const ForEachControl = defineAsyncComponent(() =>
import("components/composer/control/ForEachControl.vue")
);
export const ForInControl = defineAsyncComponent(() =>
import("components/composer/control/ForInControl.vue")
);
export const WhileControl = defineAsyncComponent(() =>
import("components/composer/control/WhileControl.vue")
);
export const SwitchControl = defineAsyncComponent(() =>
import("components/composer/control/SwitchControl.vue")
);
export const TryCatchControl = defineAsyncComponent(() =>
import("components/composer/control/TryCatchControl.vue")
);
// Editor Components
export const UBrowserEditor = defineAsyncComponent(() =>
import("components/composer/ubrowser/UBrowserEditor.vue")
);
export const AxiosConfigEditor = defineAsyncComponent(() =>
import("components/composer/http/AxiosConfigEditor.vue")
);
export const RegexEditor = defineAsyncComponent(() =>
import("components/composer/regex/RegexEditor.vue")
);
// Crypto Components
export const SymmetricCryptoEditor = defineAsyncComponent(() =>
import("components/composer/crypto/SymmetricCryptoEditor.vue")
);
export const AsymmetricCryptoEditor = defineAsyncComponent(() =>
import("components/composer/crypto/AsymmetricCryptoEditor.vue")
);

View File

@ -11,7 +11,7 @@ export const controlCommands = {
}, },
{ {
value: "loop", value: "loop",
label: "循环", label: "循环执行",
component: "LoopControl", component: "LoopControl",
isControlFlow: true, isControlFlow: true,
commandChain: ["loop", "end"], commandChain: ["loop", "end"],
@ -23,5 +23,33 @@ export const controlCommands = {
isControlFlow: true, isControlFlow: true,
commandChain: ["forEach", "end"], commandChain: ["forEach", "end"],
}, },
{
value: "forIn",
label: "遍历对象",
component: "ForInControl",
isControlFlow: true,
commandChain: ["forIn", "end"],
},
{
value: "while",
label: "条件循环",
component: "WhileControl",
isControlFlow: true,
commandChain: ["while", "end"],
},
{
value: "switch",
label: "条件分支",
component: "SwitchControl",
isControlFlow: true,
commandChain: ["switch", "case", "end"],
},
{
value: "tryCatch",
label: "异常处理",
component: "TryCatchControl",
isControlFlow: true,
commandChain: ["try", "catch", "end"],
},
], ],
}; };