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']"
|
:model-value="argvs.headers['User-Agent']"
|
||||||
@update:model-value="updateArgvs('headers.User-Agent', $event)"
|
@update:model-value="updateArgvs('headers.User-Agent', $event)"
|
||||||
label="User Agent"
|
label="User Agent"
|
||||||
|
:options="userAgentOptions"
|
||||||
icon="devices"
|
icon="devices"
|
||||||
class="col-grow"
|
class="col-grow"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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">
|
<div class="col-12">
|
||||||
<DictEditor
|
<DictEditor
|
||||||
@ -168,10 +152,7 @@ import { defineComponent } from "vue";
|
|||||||
import VariableInput from "components/composer/ui/VariableInput.vue";
|
import VariableInput from "components/composer/ui/VariableInput.vue";
|
||||||
import NumberInput from "components/composer/ui/NumberInput.vue";
|
import NumberInput from "components/composer/ui/NumberInput.vue";
|
||||||
import DictEditor from "components/composer/ui/DictEditor.vue";
|
import DictEditor from "components/composer/ui/DictEditor.vue";
|
||||||
import {
|
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
||||||
stringifyArgv,
|
|
||||||
parseFunction,
|
|
||||||
} from "js/composer/formatString";
|
|
||||||
import {
|
import {
|
||||||
userAgent,
|
userAgent,
|
||||||
commonHeaders,
|
commonHeaders,
|
||||||
@ -471,11 +452,9 @@ export default defineComponent({
|
|||||||
? `, ${stringifyArgv(restConfig)}`
|
? `, ${stringifyArgv(restConfig)}`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
return `${
|
return `${this.modelValue.value}.${method.toLowerCase()}(${stringifyArgv(
|
||||||
this.modelValue.value
|
url
|
||||||
}.${method.toLowerCase()}(${stringifyArgv(url)}${
|
)}${this.hasRequestData ? `, ${stringifyArgv(data)}` : ""}${configStr})`;
|
||||||
this.hasRequestData ? `, ${stringifyArgv(data)}` : ""
|
|
||||||
}${configStr})`;
|
|
||||||
},
|
},
|
||||||
updateArgvs(key, value) {
|
updateArgvs(key, value) {
|
||||||
const argvs = { ...this.argvs };
|
const argvs = { ...this.argvs };
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="array-editor">
|
<div class="array-editor">
|
||||||
<div v-for="(item, index) in items" :key="index" class="row items-center">
|
<div v-for="(item, index) in items" :key="index" class="row items-center">
|
||||||
<template v-if="options?.keys">
|
<template v-if="optionsKeys">
|
||||||
<div
|
<div
|
||||||
v-for="key in options.keys"
|
v-for="key in optionsKeys"
|
||||||
:key="key"
|
:key="key"
|
||||||
:class="['col', options.keys.length > 1 ? 'q-pr-sm' : '']"
|
:class="['col', optionsKeys.length > 1 ? 'q-pr-sm' : '']"
|
||||||
>
|
>
|
||||||
<VariableInput
|
<VariableInput
|
||||||
:model-value="item[key]"
|
:model-value="item[key]"
|
||||||
@ -17,34 +17,13 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<template v-if="options?.items">
|
<VariableInput
|
||||||
<q-select
|
:model-value="item"
|
||||||
:model-value="item.value"
|
:label="`${label || '项目'} ${index + 1}`"
|
||||||
:options="filterOptions"
|
:icon="icon || 'code'"
|
||||||
:label="`${label || '项目'} ${index + 1}`"
|
:options="options"
|
||||||
dense
|
@update:model-value="(val) => updateItemValue(index, val)"
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
@ -102,8 +81,8 @@
|
|||||||
* @property {String} label - 输入框标签
|
* @property {String} label - 输入框标签
|
||||||
* @property {String} icon - 输入框图标
|
* @property {String} icon - 输入框图标
|
||||||
* @property {Object} options - 配置选项
|
* @property {Object} options - 配置选项
|
||||||
* @property {String[]} [options.keys] - 多键对象模式的键名列表
|
* @property {String[]} [optionsKeys] - 多键对象模式的键名列表
|
||||||
* @property {String[]} [options.items] - 下拉选择模式的选项列表
|
* @property {String[]} [options] - 下拉选择模式的选项列表
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // 基础数组
|
* // 基础数组
|
||||||
@ -116,7 +95,7 @@
|
|||||||
* ]
|
* ]
|
||||||
*
|
*
|
||||||
* // 多键对象数组
|
* // 多键对象数组
|
||||||
* options.keys = ['name', 'age', 'email']
|
* optionsKeys = ['name', 'age', 'email']
|
||||||
* [
|
* [
|
||||||
* {
|
* {
|
||||||
* name: { value: "张三", isString: true, __varInputVal__: true },
|
* name: { value: "张三", isString: true, __varInputVal__: true },
|
||||||
@ -126,7 +105,7 @@
|
|||||||
* ]
|
* ]
|
||||||
*
|
*
|
||||||
* // 下拉选择模式
|
* // 下拉选择模式
|
||||||
* options.items = ['选项1', '选项2', '选项3']
|
* options = ['选项1', '选项2', '选项3']
|
||||||
* [
|
* [
|
||||||
* {
|
* {
|
||||||
* value: "选项1",
|
* value: "选项1",
|
||||||
@ -157,7 +136,11 @@ export default defineComponent({
|
|||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
type: Object,
|
type: Array,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
optionsKeys: {
|
||||||
|
type: Array,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -166,10 +149,6 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
// 本地维护的数组数据
|
// 本地维护的数组数据
|
||||||
localItems: this.initializeItems(),
|
localItems: this.initializeItems(),
|
||||||
// 选项模式下的过滤选项
|
|
||||||
filterOptions: this.options?.items || [],
|
|
||||||
// 选项模式下的输入值
|
|
||||||
inputValue: "",
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -191,7 +170,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
if (this.options?.keys) {
|
if (this.options?.keys) {
|
||||||
const item = {};
|
const item = {};
|
||||||
this.options.keys.forEach((key) => {
|
this.optionsKeys.forEach((key) => {
|
||||||
item[key] = {
|
item[key] = {
|
||||||
value: "",
|
value: "",
|
||||||
isString: false,
|
isString: false,
|
||||||
@ -214,9 +193,9 @@ export default defineComponent({
|
|||||||
* 根据配置创建相应的数据结构
|
* 根据配置创建相应的数据结构
|
||||||
*/
|
*/
|
||||||
addItem() {
|
addItem() {
|
||||||
if (this.options?.keys) {
|
if (this.optionsKeys) {
|
||||||
const newItem = {};
|
const newItem = {};
|
||||||
this.options.keys.forEach((key) => {
|
this.optionsKeys.forEach((key) => {
|
||||||
newItem[key] = {
|
newItem[key] = {
|
||||||
value: "",
|
value: "",
|
||||||
isString: false,
|
isString: false,
|
||||||
@ -243,9 +222,9 @@ export default defineComponent({
|
|||||||
const newItems = [...this.items];
|
const newItems = [...this.items];
|
||||||
newItems.splice(index, 1);
|
newItems.splice(index, 1);
|
||||||
if (newItems.length === 0) {
|
if (newItems.length === 0) {
|
||||||
if (this.options?.keys) {
|
if (this.optionsKeys) {
|
||||||
const newItem = {};
|
const newItem = {};
|
||||||
this.options.keys.forEach((key) => {
|
this.optionsKeys.forEach((key) => {
|
||||||
newItem[key] = {
|
newItem[key] = {
|
||||||
value: "",
|
value: "",
|
||||||
isString: false,
|
isString: false,
|
||||||
@ -282,59 +261,6 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
this.items = newItems;
|
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>
|
</script>
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
:icon="isString ? 'format_quote' : 'data_object'"
|
:icon="isString ? 'format_quote' : 'data_object'"
|
||||||
size="sm"
|
size="sm"
|
||||||
class="string-toggle"
|
class="string-toggle"
|
||||||
@click="isString = !isString"
|
@click="toggleType"
|
||||||
v-if="!hasSelectedVariable"
|
v-if="!hasSelectedVariable"
|
||||||
>
|
>
|
||||||
<q-tooltip>{{
|
<q-tooltip>{{
|
||||||
@ -35,7 +35,32 @@
|
|||||||
: "当前类型是:变量、数字、表达式等,点击切换"
|
: "当前类型是:变量、数字、表达式等,点击切换"
|
||||||
}}</q-tooltip>
|
}}</q-tooltip>
|
||||||
</q-btn>
|
</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
|
<q-btn-dropdown
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
@ -93,6 +118,7 @@ import { defineComponent, inject } from "vue";
|
|||||||
* @property {Object} modelValue - 输入框的值对象
|
* @property {Object} modelValue - 输入框的值对象
|
||||||
* @property {String} label - 输入框标签
|
* @property {String} label - 输入框标签
|
||||||
* @property {String} icon - 输入框图标
|
* @property {String} icon - 输入框图标
|
||||||
|
* @property {String[]} [options] - 可选的下拉选项列表
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // modelValue 对象格式
|
* // modelValue 对象格式
|
||||||
@ -117,6 +143,20 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
label: String,
|
label: String,
|
||||||
icon: 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"],
|
emits: ["update:modelValue"],
|
||||||
@ -137,6 +177,18 @@ export default defineComponent({
|
|||||||
return this.selectedVariable !== null;
|
return this.selectedVariable !== null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isString: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue.isString;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$emit("update:modelValue", {
|
||||||
|
...this.modelValue,
|
||||||
|
isString: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
inputValue: {
|
inputValue: {
|
||||||
get() {
|
get() {
|
||||||
return this.modelValue.value;
|
return this.modelValue.value;
|
||||||
@ -148,16 +200,17 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isString: {
|
|
||||||
get() {
|
// 标准化选项格式
|
||||||
return this.modelValue.isString;
|
normalizedOptions() {
|
||||||
},
|
console.log(this.options);
|
||||||
set(value) {
|
if (!this.options) return [];
|
||||||
this.$emit("update:modelValue", {
|
return this.options.map((option) => {
|
||||||
...this.modelValue,
|
if (typeof option === "string") {
|
||||||
isString: value,
|
return { label: option, value: option };
|
||||||
});
|
}
|
||||||
},
|
return option;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -183,6 +236,31 @@ export default defineComponent({
|
|||||||
__varInputVal__: true,
|
__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>
|
</script>
|
||||||
@ -274,4 +352,42 @@ export default defineComponent({
|
|||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
color: var(--q-negative);
|
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>
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user