新增遍历数组

This commit is contained in:
fofolee 2025-01-02 12:10:01 +08:00
parent 15ad67a753
commit db3d2428c8
5 changed files with 321 additions and 55 deletions

View File

@ -40,12 +40,11 @@
</q-btn>
<!-- 条件输入框 -->
<q-input
<ControlInput
v-if="showCondition"
v-model="conditionLocal"
dense
borderless
placeholder="输入条件表达式"
label="条件"
placeholder="表达式"
class="condition-input"
/>
</div>
@ -54,9 +53,13 @@
<script>
import { defineComponent } from "vue";
import ControlInput from "../ui/ControlInput.vue";
export default defineComponent({
name: "ConditionalJudgment",
components: {
ControlInput,
},
props: {
modelValue: String,
command: Object,
@ -168,15 +171,6 @@ export default defineComponent({
transition: all 0.3s ease;
}
.condition-input :deep(.q-field__control),
.condition-input :deep(.q-field__native) {
padding: 1px;
height: 21px !important;
min-height: 21px;
border-radius: 4px;
font-size: 13px;
}
.control-btn {
width: 21px;
height: 21px;

View File

@ -0,0 +1,230 @@
<template>
<div class="loop-control-wrapper" v-bind="$attrs">
<div class="loop-control row items-center no-wrap">
<!-- 类型标签和按钮区域 -->
<div class="control-type-label q-mr-sm">
<template v-if="type === 'forEach'">开始</template>
<template v-else-if="type === 'continue'">继续</template>
<template v-else-if="type === 'break'">终止</template>
<template v-else>结束</template>
</div>
<!-- 遍历设置区域 -->
<div v-if="type === 'forEach'" class="loop-settings">
<ControlInput
v-model="itemVar"
label="元素"
:is-variable="true"
class="loop-input"
/>
<ControlInput
v-model="indexVar"
label="索引"
:is-variable="true"
class="loop-input"
/>
<ControlInput
v-model="arrayVar"
label="数组"
class="loop-input array-input"
/>
</div>
<!-- 只在循环开始时显示添加按钮 -->
<q-btn-dropdown
v-if="type === 'forEach'"
flat
dense
dropdown-icon="add"
no-icon-animation
size="sm"
class="control-btn q-ml-sm"
>
<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: "ForEachControl",
components: {
ControlInput,
},
inheritAttrs: false,
props: {
modelValue: String,
command: Object,
type: {
type: String,
required: true,
validator: (value) =>
["forEach", "continue", "break", "end"].includes(value),
},
},
emits: ["update:modelValue", "addBranch"],
data() {
return {
itemVar: "item",
indexVar: "index",
arrayVar: "array",
};
},
created() {
if (!this.modelValue) {
this.updateValue();
}
},
computed: {
generatedCode() {
switch (this.type) {
case "forEach":
const item = this.itemVar || "item";
const index = this.indexVar || "index";
const array = this.arrayVar || "array";
return `for(let [${index}, ${item}] of ${array}.entries()){`;
case "continue":
return "continue;";
case "break":
return "break;";
case "end":
return "}";
default:
return "";
}
},
},
watch: {
type: {
immediate: true,
handler(val) {
console.log("ForEachControl type:", val);
},
},
modelValue: {
immediate: true,
handler(val) {
if (val) {
this.parseCodeString(val);
}
},
},
itemVar() {
this.updateValue();
},
indexVar() {
this.updateValue();
},
arrayVar() {
this.updateValue();
},
},
methods: {
updateValue() {
this.$emit("update:modelValue", this.generatedCode);
},
parseCodeString(val) {
try {
if (this.type === "forEach") {
const match = val.match(
/^for\(let\s+\[(\w+),\s*(\w+)\]\s+of\s+(\w+|\$\{.+\})\.entries\(\)\){$/
);
if (match) {
this.indexVar = match[1];
this.itemVar = match[2];
this.arrayVar = match[3];
}
}
} catch (e) {
console.error("Failed to parse code string:", e);
}
},
},
});
</script>
<style scoped>
.loop-control-wrapper {
width: 100%;
}
.loop-control {
display: flex;
align-items: center;
}
.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;
}
.control-btn:hover {
opacity: 1;
transform: scale(1.1);
}
.loop-settings {
display: flex;
gap: 4px;
flex: 1;
}
.loop-input {
width: 80px;
}
.array-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

@ -1,14 +1,27 @@
<template>
<div class="loop-control-wrapper" v-bind="$attrs">
<div class="loop-control row">
<div class="loop-control row items-center no-wrap">
<!-- 类型标签和按钮区域 -->
<div class="control-type-label">
<div class="control-type-label q-mr-sm">
<template v-if="type === 'loop'">开始</template>
<template v-else-if="type === 'continue'">继续</template>
<template v-else-if="type === 'break'">终止</template>
<template v-else>结束</template>
</div>
<!-- 循环设置区域 -->
<div v-if="type === 'loop'" class="loop-settings">
<ControlInput
v-model="indexVar"
label="变量"
:is-variable="true"
class="loop-input"
/>
<ControlInput v-model="startValue" label="从" class="loop-input" />
<ControlInput v-model="endValue" label="到" class="loop-input" />
<ControlInput v-model="stepValue" label="步进" class="loop-input" />
</div>
<!-- 只在循环开始时显示添加按钮 -->
<q-btn-dropdown
v-if="type === 'loop'"
@ -17,7 +30,7 @@
dropdown-icon="add"
no-icon-animation
size="sm"
class="control-btn"
class="control-btn q-ml-sm"
>
<q-list>
<q-item
@ -50,45 +63,19 @@
</q-item>
</q-list>
</q-btn-dropdown>
<!-- 循环设置区域 -->
<div v-if="type === 'loop'" class="loop-settings">
<q-input
dense
borderless
v-model="indexVar"
:is-variable="true"
class="loop-input"
>
<template v-slot:prepend>
<q-badge class="loop-input-prepend">变量</q-badge>
</template>
</q-input>
<q-input dense borderless v-model="startValue" class="loop-input">
<template v-slot:prepend>
<q-badge class="loop-input-prepend"></q-badge>
</template>
</q-input>
<q-input dense borderless v-model="endValue" class="loop-input">
<template v-slot:prepend>
<q-badge class="loop-input-prepend"></q-badge>
</template>
</q-input>
<q-input dense borderless v-model="stepValue" class="loop-input">
<template v-slot:prepend>
<q-badge class="loop-input-prepend">步进</q-badge>
</template>
</q-input>
</div>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import ControlInput from "../ui/ControlInput.vue";
export default defineComponent({
name: "LoopControl",
components: {
ControlInput,
},
inheritAttrs: false,
props: {
modelValue: String,
@ -189,7 +176,6 @@ export default defineComponent({
.loop-control {
display: flex;
align-items: center;
gap: 4px;
}
.control-type-label {
@ -214,16 +200,11 @@ export default defineComponent({
.loop-settings {
display: flex;
gap: 4px;
flex: 1;
}
.loop-input :deep(.q-field__control),
.loop-input :deep(.q-field__native),
.loop-input :deep(.q-field__marginal) {
padding: 0 5px;
height: 21px !important;
min-height: 21px;
font-size: 13px;
max-width: 80px;
.loop-input {
width: 80px;
}
/* 暗色模式适配 */

View File

@ -0,0 +1,54 @@
<template>
<div class="control-input-wrapper">
<q-input
dense
borderless
:model-value="modelValue"
@update:model-value="$emit('update:modelValue', $event)"
class="control-input"
v-bind="$attrs"
>
<template v-slot:prepend>
<q-badge class="control-input-prepend" color="primary">{{
label
}}</q-badge>
</template>
</q-input>
</div>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "ControlInput",
inheritAttrs: false,
props: {
modelValue: {
type: [String, Number],
default: "",
},
label: {
type: String,
required: true,
},
},
emits: ["update:modelValue"],
});
</script>
<style scoped>
.control-input :deep(.q-field__control),
.control-input :deep(.q-field__native),
.control-input :deep(.q-field__marginal) {
height: 21px !important;
min-height: 21px;
font-size: 13px;
}
.control-input-prepend {
font-size: 12px;
font-weight: normal;
padding: 2px 4px;
}
</style>

View File

@ -16,5 +16,12 @@ export const controlCommands = {
isControlFlow: true,
commandChain: ["loop", "end"],
},
{
value: "forEach",
label: "遍历数组",
component: "ForEachControl",
isControlFlow: true,
commandChain: ["forEach", "end"],
},
],
};