完善选项列表切换不同类型时的选项处理逻辑

This commit is contained in:
fofolee 2025-01-08 11:52:28 +08:00
parent f742e6f121
commit b528cfa97d
4 changed files with 117 additions and 43 deletions

View File

@ -5,12 +5,15 @@
<div
v-for="key in optionsKeys"
:key="key.value"
:class="['col', optionsKeys.length > 1 ? 'q-pr-sm' : '']"
:class="[
key.width ? `col-${key.width}` : 'col',
optionsKeys.length > 1 ? 'q-pr-sm' : '',
]"
>
<VariableInput
:model-value="item[key.value]"
:label="key.label"
:icon="icon || 'code'"
:no-icon="true"
@update:model-value="
(val) => updateItemKeyValue(index, key.value, val)
"
@ -155,6 +158,7 @@ export default defineComponent({
return {
value: key.value || key,
label: key.label || key,
width: key.width,
};
}) || []
);

View File

@ -131,7 +131,7 @@
</q-btn-dropdown>
</template>
<template v-slot:prepend>
<q-icon :name="icon || 'code'" />
<q-icon v-if="!noIcon" :name="icon || 'code'" />
</template>
</q-input>
</template>
@ -187,6 +187,7 @@ export default defineComponent({
},
label: String,
icon: String,
noIcon: Boolean,
options: {
type: Object,
default: () => ({}),

View File

@ -6,7 +6,7 @@
<!-- 选项类型选择 -->
<div class="col model-type-select">
<OperationCard
v-model="argvs.optionType"
:model-value="argvs.optionType"
:options="[
{ label: '纯文本', value: 'plaintext', icon: 'text_fields' },
{ label: 'HTML', value: 'html', icon: 'code' },
@ -14,7 +14,7 @@
]"
square
height="36px"
@update:model-value="updateArgvs('optionType', $event)"
@update:model-value="handleOptionTypeChange"
/>
</div>
@ -22,7 +22,7 @@
<div class="col-2.5 input-mode-select">
<q-select
:model-value="argvs.inputMode"
@update:model-value="updateArgvs('inputMode', $event)"
@update:model-value="handleInputModeChange"
:options="[
{
label: '手动输入',
@ -132,6 +132,11 @@
:model-value="argvs.selects"
:options="{
keys: [
{
value: 'id',
label: 'id',
width: 3,
},
{
value: 'title',
label: '标题',
@ -174,28 +179,22 @@ import ArrayEditor from "../common/ArrayEditor.vue";
import OperationCard from "../common/OperationCard.vue";
import { parseFunction, stringifyArgv } from "js/composer/formatString";
const jsonDefaultSelects = {
selects: new Array(3).fill({
title: {
value: "",
isString: true,
__varInputVal__: true,
},
description: {
value: "",
isString: true,
__varInputVal__: true,
},
}),
const newVarInputVal = (type = "str", val = "") => {
if (typeof val !== "string") val = JSON.stringify(val);
return {
value: val,
isString: type === "str",
__varInputVal__: true,
};
};
const textDefaultSelects = {
selects: new Array(3).fill({
value: "",
isString: true,
__varInputVal__: true,
}),
};
const jsonDefaultSelects = new Array(3).fill().map((_, index) => ({
id: newVarInputVal("var", index),
title: newVarInputVal("str"),
description: newVarInputVal("str"),
}));
const textDefaultSelects = new Array(3).fill(newVarInputVal("str"));
const defaultSelects = {
json: jsonDefaultSelects,
@ -248,12 +247,25 @@ export default defineComponent({
},
},
methods: {
updateArgvs(key, value) {
/**
* 更新参数
* @param {string|string[]} keys - 键名
* @param {string|string[]} values -
*/
updateArgvs(keys, values) {
if (typeof keys === "string") {
keys = [keys];
values = [values];
}
const argvs = { ...this.argvs };
const keys = key.split(".");
const lastKey = keys.pop();
const target = keys.reduce((obj, key) => obj[key], argvs);
target[lastKey] = value;
//
keys.forEach((key, index) => {
//
const subKeys = key.split(".");
const lastKey = subKeys.pop();
const target = subKeys.reduce((obj, key) => obj[key], argvs);
target[lastKey] = values[index];
});
this.updateModelValue(argvs);
},
generateCode(argvs = this.argvs) {
@ -285,13 +297,16 @@ export default defineComponent({
try {
const result = parseFunction(code, {
variableFormatPaths: ["arg0", "arg1.placeholder"],
variableFormatPaths: ["arg0", "arg0[*]", "arg1.placeholder"],
});
if (!result) return this.defaultArgvs;
const [selects, options = {}] = result.argvs;
const inputMode = selects.__varInputVal__ ? "variable" : "manual";
return {
...this.defaultArgvs,
inputMode,
selects,
...options,
};
@ -318,20 +333,46 @@ export default defineComponent({
argvs,
});
},
handleOptionTypeChange(newOptionType) {
const oldOptionType = this.argvs.optionType;
//
if (oldOptionType === newOptionType) return;
// selects
if (this.argvs.inputMode === "variable") {
this.updateArgvs("optionType", newOptionType);
return;
}
const oldSelects = this.argvs.selects;
let newSelects = oldSelects;
// JSONJSONtitledescription
if (oldOptionType === "json") {
newSelects = oldSelects.map(
(item) => item.title || item.description || newVarInputVal("str")
);
} else if (newOptionType === "json") {
// JSONJSONtitledescription
newSelects = oldSelects.map((item) => ({
title: item,
description: item,
}));
}
this.updateArgvs(["optionType", "selects"], [newOptionType, newSelects]);
},
handleInputModeChange(newInputMode) {
let newSelects = this.argvs.selects;
if (newInputMode === "variable") {
newSelects = newVarInputVal("var");
} else {
newSelects = defaultSelects[this.argvs.optionType];
}
this.updateArgvs(["inputMode", "selects"], [newInputMode, newSelects]);
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.defaultArgvs);
}
},
watch: {
"argvs.optionType": {
immediate: true,
handler(newVal) {
this.argvs.selects = defaultSelects[newVal];
},
},
},
});
</script>

View File

@ -306,9 +306,37 @@ export const parseFunction = (functionStr, options = {}) => {
return obj;
}, {});
case "ArrayExpression":
return node.elements.map((element, index) =>
processNode(element, `${currentPath}[${index}]`)
);
return node.elements.map((element, index) => {
const elementPath = `${currentPath}[${index}]`;
const processedElement = processNode(element, elementPath);
if (
shouldUseVariableFormat &&
typeof processedElement === "object"
) {
return Object.entries(processedElement).reduce(
(acc, [key, value]) => {
// 如果值已经是 varInputVal 格式,直接使用
if (value?.__varInputVal__) {
acc[key] = value;
} else {
// 否则转换为 varInputVal 格式
acc[key] = {
value:
typeof value === "string"
? value
: JSON.stringify(value),
isString: typeof value === "string",
__varInputVal__: true,
};
}
return acc;
},
{}
);
}
return processedElement;
});
case "ObjectProperty":
return processNode(node.value, currentPath);
case "MemberExpression":