mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-08 06:16:27 +08:00
更新Varinput支持下拉选项
This commit is contained in:
parent
2dbd6f0c50
commit
b8d48cb102
@ -90,27 +90,11 @@
|
||||
:model-value="argvs.headers['User-Agent']"
|
||||
@update:model-value="updateArgvs('headers.User-Agent', $event)"
|
||||
label="User Agent"
|
||||
:options="userAgentOptions"
|
||||
icon="devices"
|
||||
class="col-grow"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-auto flex items-center">
|
||||
<q-btn-dropdown flat dense dropdown-icon="menu">
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="ua in userAgentOptions"
|
||||
:key="ua.value"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="setUserAgent(ua.value)"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ ua.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<DictEditor
|
||||
@ -168,10 +152,7 @@ import { defineComponent } from "vue";
|
||||
import VariableInput from "components/composer/ui/VariableInput.vue";
|
||||
import NumberInput from "components/composer/ui/NumberInput.vue";
|
||||
import DictEditor from "components/composer/ui/DictEditor.vue";
|
||||
import {
|
||||
stringifyArgv,
|
||||
parseFunction,
|
||||
} from "js/composer/formatString";
|
||||
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
||||
import {
|
||||
userAgent,
|
||||
commonHeaders,
|
||||
@ -471,11 +452,9 @@ export default defineComponent({
|
||||
? `, ${stringifyArgv(restConfig)}`
|
||||
: "";
|
||||
|
||||
return `${
|
||||
this.modelValue.value
|
||||
}.${method.toLowerCase()}(${stringifyArgv(url)}${
|
||||
this.hasRequestData ? `, ${stringifyArgv(data)}` : ""
|
||||
}${configStr})`;
|
||||
return `${this.modelValue.value}.${method.toLowerCase()}(${stringifyArgv(
|
||||
url
|
||||
)}${this.hasRequestData ? `, ${stringifyArgv(data)}` : ""}${configStr})`;
|
||||
},
|
||||
updateArgvs(key, value) {
|
||||
const argvs = { ...this.argvs };
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="array-editor">
|
||||
<div v-for="(item, index) in items" :key="index" class="row items-center">
|
||||
<template v-if="options?.keys">
|
||||
<template v-if="optionsKeys">
|
||||
<div
|
||||
v-for="key in options.keys"
|
||||
v-for="key in optionsKeys"
|
||||
:key="key"
|
||||
:class="['col', options.keys.length > 1 ? 'q-pr-sm' : '']"
|
||||
:class="['col', optionsKeys.length > 1 ? 'q-pr-sm' : '']"
|
||||
>
|
||||
<VariableInput
|
||||
:model-value="item[key]"
|
||||
@ -17,34 +17,13 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="col">
|
||||
<template v-if="options?.items">
|
||||
<q-select
|
||||
:model-value="item.value"
|
||||
:options="filterOptions"
|
||||
:label="`${label || '项目'} ${index + 1}`"
|
||||
dense
|
||||
filled
|
||||
use-input
|
||||
input-debounce="0"
|
||||
:hide-selected="!!inputValue"
|
||||
@filter="filterFn"
|
||||
@update:model-value="(val) => handleSelect(val, index)"
|
||||
@input-value="(val) => handleInput(val, index)"
|
||||
@blur="handleBlur"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon :name="icon || 'code'" />
|
||||
</template>
|
||||
</q-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<VariableInput
|
||||
:model-value="item"
|
||||
:label="`${label || '项目'} ${index + 1}`"
|
||||
:icon="icon || 'code'"
|
||||
@update:model-value="(val) => updateItemValue(index, val)"
|
||||
/>
|
||||
</template>
|
||||
<VariableInput
|
||||
:model-value="item"
|
||||
:label="`${label || '项目'} ${index + 1}`"
|
||||
:icon="icon || 'code'"
|
||||
:options="options"
|
||||
@update:model-value="(val) => updateItemValue(index, val)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div class="col-auto">
|
||||
@ -102,8 +81,8 @@
|
||||
* @property {String} label - 输入框标签
|
||||
* @property {String} icon - 输入框图标
|
||||
* @property {Object} options - 配置选项
|
||||
* @property {String[]} [options.keys] - 多键对象模式的键名列表
|
||||
* @property {String[]} [options.items] - 下拉选择模式的选项列表
|
||||
* @property {String[]} [optionsKeys] - 多键对象模式的键名列表
|
||||
* @property {String[]} [options] - 下拉选择模式的选项列表
|
||||
*
|
||||
* @example
|
||||
* // 基础数组
|
||||
@ -116,7 +95,7 @@
|
||||
* ]
|
||||
*
|
||||
* // 多键对象数组
|
||||
* options.keys = ['name', 'age', 'email']
|
||||
* optionsKeys = ['name', 'age', 'email']
|
||||
* [
|
||||
* {
|
||||
* name: { value: "张三", isString: true, __varInputVal__: true },
|
||||
@ -126,7 +105,7 @@
|
||||
* ]
|
||||
*
|
||||
* // 下拉选择模式
|
||||
* options.items = ['选项1', '选项2', '选项3']
|
||||
* options = ['选项1', '选项2', '选项3']
|
||||
* [
|
||||
* {
|
||||
* value: "选项1",
|
||||
@ -157,7 +136,11 @@ export default defineComponent({
|
||||
default: "",
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
optionsKeys: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
@ -166,10 +149,6 @@ export default defineComponent({
|
||||
return {
|
||||
// 本地维护的数组数据
|
||||
localItems: this.initializeItems(),
|
||||
// 选项模式下的过滤选项
|
||||
filterOptions: this.options?.items || [],
|
||||
// 选项模式下的输入值
|
||||
inputValue: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -191,7 +170,7 @@ export default defineComponent({
|
||||
|
||||
if (this.options?.keys) {
|
||||
const item = {};
|
||||
this.options.keys.forEach((key) => {
|
||||
this.optionsKeys.forEach((key) => {
|
||||
item[key] = {
|
||||
value: "",
|
||||
isString: false,
|
||||
@ -214,9 +193,9 @@ export default defineComponent({
|
||||
* 根据配置创建相应的数据结构
|
||||
*/
|
||||
addItem() {
|
||||
if (this.options?.keys) {
|
||||
if (this.optionsKeys) {
|
||||
const newItem = {};
|
||||
this.options.keys.forEach((key) => {
|
||||
this.optionsKeys.forEach((key) => {
|
||||
newItem[key] = {
|
||||
value: "",
|
||||
isString: false,
|
||||
@ -243,9 +222,9 @@ export default defineComponent({
|
||||
const newItems = [...this.items];
|
||||
newItems.splice(index, 1);
|
||||
if (newItems.length === 0) {
|
||||
if (this.options?.keys) {
|
||||
if (this.optionsKeys) {
|
||||
const newItem = {};
|
||||
this.options.keys.forEach((key) => {
|
||||
this.optionsKeys.forEach((key) => {
|
||||
newItem[key] = {
|
||||
value: "",
|
||||
isString: false,
|
||||
@ -282,59 +261,6 @@ export default defineComponent({
|
||||
};
|
||||
this.items = newItems;
|
||||
},
|
||||
/**
|
||||
* 选项模式下的输入处理
|
||||
* 当输入的值不在选项中时,创建新值
|
||||
*/
|
||||
handleInput(val, index) {
|
||||
this.inputValue = val;
|
||||
if (val && !this.filterOptions.includes(val)) {
|
||||
const newItems = [...this.items];
|
||||
newItems[index] = {
|
||||
value: val,
|
||||
isString: false,
|
||||
__varInputVal__: true,
|
||||
};
|
||||
this.items = newItems;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 选项模式下的选择处理
|
||||
*/
|
||||
handleSelect(val, index) {
|
||||
this.inputValue = "";
|
||||
const newItems = [...this.items];
|
||||
newItems[index] = {
|
||||
value: val,
|
||||
isString: false,
|
||||
__varInputVal__: true,
|
||||
};
|
||||
this.items = newItems;
|
||||
},
|
||||
/**
|
||||
* 选项模式下的失焦处理
|
||||
*/
|
||||
handleBlur() {
|
||||
this.inputValue = "";
|
||||
},
|
||||
/**
|
||||
* 选项模式下的过滤处理
|
||||
* 根据输入值过滤可选项
|
||||
*/
|
||||
filterFn(val, update) {
|
||||
if (!this.options?.items) return;
|
||||
|
||||
update(() => {
|
||||
if (val === "") {
|
||||
this.filterOptions = this.options.items;
|
||||
} else {
|
||||
const needle = val.toLowerCase();
|
||||
this.filterOptions = this.options.items.filter(
|
||||
(v) => v.toLowerCase().indexOf(needle) > -1
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -26,7 +26,7 @@
|
||||
:icon="isString ? 'format_quote' : 'data_object'"
|
||||
size="sm"
|
||||
class="string-toggle"
|
||||
@click="isString = !isString"
|
||||
@click="toggleType"
|
||||
v-if="!hasSelectedVariable"
|
||||
>
|
||||
<q-tooltip>{{
|
||||
@ -35,7 +35,32 @@
|
||||
: "当前类型是:变量、数字、表达式等,点击切换"
|
||||
}}</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<!-- 选项下拉按钮 -->
|
||||
<q-btn-dropdown
|
||||
v-if="options && !hasSelectedVariable"
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
dropdown-icon="menu"
|
||||
no-icon-animation
|
||||
class="options-dropdown"
|
||||
>
|
||||
<q-list class="options-list">
|
||||
<q-item
|
||||
v-for="option in normalizedOptions"
|
||||
:key="getOptionValue(option)"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="selectOption(option)"
|
||||
class="option-item"
|
||||
>
|
||||
<q-item-section>
|
||||
{{ getOptionLabel(option) }}
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
<!-- 变量选择下拉 -->
|
||||
<q-btn-dropdown
|
||||
flat
|
||||
dense
|
||||
@ -93,6 +118,7 @@ import { defineComponent, inject } from "vue";
|
||||
* @property {Object} modelValue - 输入框的值对象
|
||||
* @property {String} label - 输入框标签
|
||||
* @property {String} icon - 输入框图标
|
||||
* @property {String[]} [options] - 可选的下拉选项列表
|
||||
*
|
||||
* @example
|
||||
* // modelValue 对象格式
|
||||
@ -117,6 +143,20 @@ export default defineComponent({
|
||||
},
|
||||
label: String,
|
||||
icon: String,
|
||||
options: {
|
||||
type: Array,
|
||||
default: null,
|
||||
validator(value) {
|
||||
if (!value) return true;
|
||||
// 检查数组中的每一项是否符合格式要求
|
||||
return value.every((item) => {
|
||||
return (
|
||||
typeof item === "string" || // ["xxx", "yyy"]
|
||||
(typeof item === "object" && "label" in item && "value" in item) // [{label: "xxx", value: "yyy"}]
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
emits: ["update:modelValue"],
|
||||
@ -137,6 +177,18 @@ export default defineComponent({
|
||||
return this.selectedVariable !== null;
|
||||
},
|
||||
|
||||
isString: {
|
||||
get() {
|
||||
return this.modelValue.isString;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
isString: value,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
inputValue: {
|
||||
get() {
|
||||
return this.modelValue.value;
|
||||
@ -148,16 +200,17 @@ export default defineComponent({
|
||||
});
|
||||
},
|
||||
},
|
||||
isString: {
|
||||
get() {
|
||||
return this.modelValue.isString;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
isString: value,
|
||||
});
|
||||
},
|
||||
|
||||
// 标准化选项格式
|
||||
normalizedOptions() {
|
||||
console.log(this.options);
|
||||
if (!this.options) return [];
|
||||
return this.options.map((option) => {
|
||||
if (typeof option === "string") {
|
||||
return { label: option, value: option };
|
||||
}
|
||||
return option;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@ -183,6 +236,31 @@ export default defineComponent({
|
||||
__varInputVal__: true,
|
||||
});
|
||||
},
|
||||
|
||||
// 切换类型
|
||||
toggleType() {
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
isString: !this.modelValue.isString,
|
||||
});
|
||||
},
|
||||
|
||||
getOptionLabel(option) {
|
||||
return typeof option === "string" ? option : option.label;
|
||||
},
|
||||
|
||||
getOptionValue(option) {
|
||||
return typeof option === "string" ? option : option.value;
|
||||
},
|
||||
|
||||
selectOption(option) {
|
||||
const value = this.getOptionValue(option);
|
||||
this.$emit("update:modelValue", {
|
||||
value,
|
||||
isString: true,
|
||||
__varInputVal__: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@ -274,4 +352,42 @@ export default defineComponent({
|
||||
transform: scale(1.1);
|
||||
color: var(--q-negative);
|
||||
}
|
||||
|
||||
/* 选项下拉框样式 */
|
||||
.options-dropdown {
|
||||
min-width: 32px;
|
||||
padding: 4px;
|
||||
opacity: 0.8;
|
||||
transition: all 0.3s ease;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.options-dropdown:hover {
|
||||
opacity: 1;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.options-list {
|
||||
min-width: 120px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.option-item {
|
||||
border-radius: 4px;
|
||||
padding: 0px 16px;
|
||||
transition: all 0.3s ease;
|
||||
min-height: 40px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.option-item:hover {
|
||||
background: var(--q-primary-opacity-10);
|
||||
}
|
||||
|
||||
/* 暗色模式适配 */
|
||||
.body--dark .option-item:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user