2025-01-06 00:28:54 +08:00

298 lines
7.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="flex-container">
<div
v-if="hasFunctionSelector"
class="flex-item"
:style="{ flex: localCommand.functionSelector.width || 3 }"
>
<div class="operation-cards">
<div
v-for="option in localCommand.functionSelector?.options"
:key="option.value"
:class="['operation-card', { active: funcName === option.value }]"
:data-value="option.value"
@click="funcName = option.value"
>
<q-icon
:name="option.icon || localCommand.icon || 'functions'"
size="16px"
:color="funcName === option.value ? 'primary' : 'grey'"
/>
<div class="text-caption">{{ option.label }}</div>
</div>
</div>
</div>
<div class="flex-container">
<div
v-for="(item, index) in localConfig"
:key="index"
class="flex-item"
:style="{ flex: item.width || 12 }"
>
<div v-if="item.type === 'varInput'">
<VariableInput
:model-value="argvs[index]"
@update:model-value="updateArgv(index, $event)"
:label="item.label"
:icon="item.icon"
/>
</div>
<div v-else-if="item.type === 'numInput'">
<NumberInput
:model-value="argvs[index]"
@update:model-value="updateArgv(index, $event)"
:label="item.label"
:icon="item.icon"
/>
</div>
<div v-else-if="item.type === 'switch'">
<q-toggle
:model-value="argvs[index]"
@update:model-value="updateArgv(index, $event)"
:label="item.label"
:icon="item.icon"
/>
</div>
</div>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import VariableInput from "components/composer/ui/VariableInput.vue";
import NumberInput from "components/composer/ui/NumberInput.vue";
import { stringifyWithType, parseToHasType } from "js/composer/formatString";
export default defineComponent({
name: "MultiParams",
components: {
VariableInput,
NumberInput,
},
props: {
modelValue: {
type: Object,
default: () => ({}),
required: true,
},
},
emits: ["update:modelValue"],
computed: {
localCommand() {
return this.modelValue;
},
localConfig() {
return (this.modelValue.config || []).map((item) => {
return {
...item,
value: item.defaultValue,
};
});
},
defaultArgvs() {
return this.localConfig.map((item) => item.value);
},
funcName: {
get() {
return this.modelValue.value;
},
set(value) {
this.updateModelValue(value, this.defaultArgvs);
},
},
argvs() {
return (
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
);
},
hasFunctionSelector() {
return !!this.localCommand.functionSelector;
},
},
methods: {
updateArgv(index, value) {
const newArgvs = [...this.argvs];
newArgvs[index] = value;
this.updateModelValue(this.funcName, newArgvs);
},
generateCode(funcName, argvs) {
const newArgvs = argvs
.map((argv) => stringifyWithType(argv))
.filter((item) => item != null && item !== "");
console.log(newArgvs);
return `${funcName}(${newArgvs.join(",")})`;
},
parseCodeToArgvs(code) {
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
if (!code) return argvs;
// 匹配函数名和参数
const pattern = new RegExp(`^${this.funcName}\\((.*?)\\)$`);
const match = code.match(pattern);
if (match) {
try {
const paramStr = match[1].trim();
if (!paramStr) return argvs;
// 分割参数,考虑括号嵌套
let params = [];
let bracketCount = 0;
let currentParam = "";
for (let i = 0; i < paramStr.length; i++) {
const char = paramStr[i];
if (char === "," && bracketCount === 0) {
params.push(currentParam.trim());
currentParam = "";
continue;
}
if (char === "{") bracketCount++;
if (char === "}") bracketCount--;
currentParam += char;
}
if (currentParam) {
params.push(currentParam.trim());
}
// 根据配置处理每个参数
params.forEach((param, index) => {
if (index >= this.localConfig.length) return;
const config = this.localConfig[index];
if (config.type === "varInput") {
// 对于 VariableInput 类型,解析为带有 __varInputVal__ 标记的对象
argvs[index] = parseToHasType(param);
} else if (config.type === "numInput") {
// 对于 NumberInput 类型,转换为数字
argvs[index] = Number(param) || 0;
} else {
// 其他类型直接使用值
argvs[index] = param;
}
});
return argvs;
} catch (e) {
console.error("解析参数失败:", e);
}
}
return argvs;
},
getSummary(argvs) {
// 虽然header里对溢出做了处理但是这里截断主要是为了节省存储空间
const funcNameLabel = this.localCommand.functionSelector?.options.find(
(option) => option.value === this.funcName
)?.label;
const subFeature = funcNameLabel ? `${funcNameLabel} ` : "";
const allArgvs = argvs
.map((item) =>
item?.hasOwnProperty("__varInputVal__")
? window.lodashM.truncate(item.value, {
length: 30,
omission: "...",
})
: item
)
.filter((item) => item != null && item != "");
return `${subFeature}${allArgvs.join(",")}`;
},
updateModelValue(funcName, argvs) {
this.$emit("update:modelValue", {
...this.modelValue,
value: funcName,
argvs,
summary: this.getSummary(argvs),
code: this.generateCode(funcName, argvs),
});
},
},
mounted() {
if (!this.modelValue.argvs && !this.modelValue.code) {
this.updateModelValue(this.funcName, this.defaultArgvs);
}
},
watch: {
funcName: {
immediate: true,
handler(newVal) {
// 当操作卡片改变时,确保它在视图中可见
this.$nextTick(() => {
document
.querySelector(`.operation-card[data-value="${newVal}"]`)
?.scrollIntoView({
behavior: "smooth",
block: "nearest",
inline: "nearest",
});
});
},
},
},
});
</script>
<style scoped>
.flex-container {
display: flex;
flex-wrap: wrap;
gap: 8px;
width: 100%;
}
.flex-item {
min-width: 100px;
}
@media (max-width: 600px) {
.flex-item {
flex: 1 1 100% !important;
}
}
.operation-cards {
display: flex;
align-items: center;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
padding: 1px;
gap: 8px;
border-radius: 8px;
}
.operation-cards::-webkit-scrollbar {
display: none;
}
.operation-card {
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid transparent;
border-radius: 6px;
min-width: 72px;
padding: 2px 0;
background: rgba(0, 0, 0, 0.05);
}
.body--dark .operation-card {
background: rgba(0, 0, 0, 0.05);
}
.operation-card:hover {
background: var(--q-primary-opacity-5);
transform: translateY(-1px);
border: 1px solid var(--q-primary-opacity-10);
}
.operation-card.active {
border-color: var(--q-primary);
background: var(--q-primary-opacity-5);
}
.body--dark .operation-card.active {
border-color: var(--q-primary-opacity-50);
}
</style>