diff --git a/src/components/composer/ComposerFlow.vue b/src/components/composer/ComposerFlow.vue
index e2236a2..4820f62 100644
--- a/src/components/composer/ComposerFlow.vue
+++ b/src/components/composer/ComposerFlow.vue
@@ -325,7 +325,8 @@ export default defineComponent({
const tempFlow = [
command,
{
- code: `console.log(${command.outputVariable})`,
+ //没有输出,则不打印
+ code: `${command.outputVariable} && console.log(${command.outputVariable})`,
},
];
// 触发运行事件
diff --git a/src/components/composer/MultiParams.vue b/src/components/composer/MultiParams.vue
index 7ede917..78fb93a 100644
--- a/src/components/composer/MultiParams.vue
+++ b/src/components/composer/MultiParams.vue
@@ -29,36 +29,68 @@
class="flex-item"
:style="{ flex: item.width || 12 }"
>
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -69,6 +101,7 @@ import { defineComponent } from "vue";
import VariableInput from "components/composer/common/VariableInput.vue";
import NumberInput from "components/composer/common/NumberInput.vue";
import ArrayEditor from "components/composer/common/ArrayEditor.vue";
+import DictEditor from "components/composer/common/DictEditor.vue";
import { stringifyArgv, parseFunction } from "js/composer/formatString";
export default defineComponent({
@@ -77,6 +110,7 @@ export default defineComponent({
VariableInput,
NumberInput,
ArrayEditor,
+ DictEditor,
},
props: {
modelValue: {
@@ -141,6 +175,8 @@ export default defineComponent({
variableFormatPaths.push(`arg${index}`);
} else if (item.type === "arrayEditor") {
variableFormatPaths.push(`arg${index}[*]`);
+ } else if (item.type === "dictEditor") {
+ variableFormatPaths.push(`arg${index}.**`);
}
});
try {
diff --git a/src/components/composer/common/ArrayEditor.vue b/src/components/composer/common/ArrayEditor.vue
index 87b1db0..8d0dd70 100644
--- a/src/components/composer/common/ArrayEditor.vue
+++ b/src/components/composer/common/ArrayEditor.vue
@@ -1,11 +1,11 @@
-
+
updateItemValue(index, val)"
/>
@@ -81,8 +83,8 @@
* @property {String} label - 输入框标签
* @property {String} icon - 输入框图标
* @property {Object} options - 配置选项
- * @property {String[]} [optionsKeys] - 多键对象模式的键名列表
- * @property {String[]} [options] - 下拉选择模式的选项列表
+ * @property {String[]} [options.keys] - 多键对象模式的键名列表
+ * @property {String[]} [options.items] - 下拉选择模式的选项列表
*
* @example
* // 基础数组
@@ -95,7 +97,7 @@
* ]
*
* // 多键对象数组
- * optionsKeys = ['name', 'age', 'email']
+ * options.keys = ['name', 'age', 'email']
* [
* {
* name: { value: "张三", isString: true, __varInputVal__: true },
@@ -105,7 +107,7 @@
* ]
*
* // 下拉选择模式
- * options = ['选项1', '选项2', '选项3']
+ * options.items = ['选项1', '选项2', '选项3']
* [
* {
* value: "选项1",
@@ -136,12 +138,8 @@ export default defineComponent({
default: "",
},
options: {
- type: Array,
- default: null,
- },
- optionsKeys: {
- type: Array,
- default: null,
+ type: Object,
+ default: () => ({}),
},
},
emits: ["update:modelValue"],
@@ -152,9 +150,9 @@ export default defineComponent({
},
methods: {
initializeItems() {
- if (this.optionsKeys) {
+ if (this.options.keys) {
const item = {};
- this.optionsKeys.forEach((key) => {
+ this.options.keys.forEach((key) => {
item[key] = {
value: "",
isString: false,
@@ -178,9 +176,9 @@ export default defineComponent({
*/
addItem() {
let newItems = [];
- if (this.optionsKeys) {
+ if (this.options.keys) {
const newItem = {};
- this.optionsKeys.forEach((key) => {
+ this.options.keys.forEach((key) => {
newItem[key] = {
value: "",
isString: false,
@@ -208,9 +206,9 @@ export default defineComponent({
const newItems = [...this.items];
newItems.splice(index, 1);
if (newItems.length === 0) {
- if (this.optionsKeys) {
+ if (this.options.keys) {
const newItem = {};
- this.optionsKeys.forEach((key) => {
+ this.options.keys.forEach((key) => {
newItem[key] = {
value: "",
isString: false,
diff --git a/src/components/composer/common/DictEditor.vue b/src/components/composer/common/DictEditor.vue
index a10a489..ce51305 100644
--- a/src/components/composer/common/DictEditor.vue
+++ b/src/components/composer/common/DictEditor.vue
@@ -137,7 +137,7 @@ export default defineComponent({
},
options: {
type: Object,
- default: null,
+ default: () => ({}),
},
},
emits: ["update:modelValue"],
diff --git a/src/components/composer/common/VariableInput.vue b/src/components/composer/common/VariableInput.vue
index 4a9d7ab..ac379d5 100644
--- a/src/components/composer/common/VariableInput.vue
+++ b/src/components/composer/common/VariableInput.vue
@@ -11,10 +11,9 @@
v-if="hasSelectedVariable"
flat
dense
- round
icon="close"
size="sm"
- class="clear-btn q-mr-xs"
+ class="clear-btn prepend-btn"
@click="clearVariable"
>
清除选中的变量
@@ -22,10 +21,9 @@
@@ -37,29 +35,40 @@
-
+
- {{ getOptionLabel(option) }}
+ {{ getItemLabel(item) }}
+
+ 选择文件
+
@@ -118,8 +127,12 @@ import { defineComponent, inject } from "vue";
* @property {Object} modelValue - 输入框的值对象
* @property {String} label - 输入框标签
* @property {String} icon - 输入框图标
- * @property {String[]} [options] - 可选的下拉选项列表
- *
+ * @property {Object} [options] - 可选的配置对象
+ * @property {Array} [options.items] - 选项列表
+ * @property {Boolean} [options.dialog] - 是否显示文件选择对话框
+ * @property {Object} [options.dialog] - 文件选择对话框配置
+ * @property {String} [options.dialog.type] - 对话框类型,open 或 save
+ * @property {Object} [options.dialog.options] - 对话框选项,对应 utools.showOpenDialog 和 utools.showSaveDialog 的 options
* @example
* // modelValue 对象格式
* {
@@ -127,6 +140,18 @@ import { defineComponent, inject } from "vue";
* isString: true, // 是否是字符串
* __varInputVal__: true // 用于标识是变量输入框
* }
+ * @example
+ * // options 对象格式
+ * {
+ * items: ["item1", "item2", "item3"], // 选项列表
+ * dialog: {
+ * type: "open", // 对话框类型,open 或 save
+ * options: {
+ * title: "选择文件",
+ * defaultPath: "/",
+ * },
+ * },
+ * }
*/
export default defineComponent({
name: "VariableInput",
@@ -144,18 +169,8 @@ 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"}]
- );
- });
- },
+ type: Object,
+ default: () => ({}),
},
},
@@ -202,14 +217,13 @@ export default defineComponent({
},
// 标准化选项格式
- normalizedOptions() {
- console.log(this.options);
- if (!this.options) return [];
- return this.options.map((option) => {
- if (typeof option === "string") {
- return { label: option, value: option };
+ normalizedItems() {
+ if (!this.options.items) return [];
+ return this.options.items.map((item) => {
+ if (typeof item === "string") {
+ return { label: item, value: item };
}
- return option;
+ return item;
});
},
},
@@ -245,22 +259,56 @@ export default defineComponent({
});
},
- getOptionLabel(option) {
+ getItemLabel(option) {
return typeof option === "string" ? option : option.label;
},
- getOptionValue(option) {
+ getItemValue(option) {
return typeof option === "string" ? option : option.value;
},
- selectOption(option) {
- const value = this.getOptionValue(option);
+ selectItem(option) {
+ const value = this.getItemValue(option);
this.$emit("update:modelValue", {
value,
isString: true,
__varInputVal__: true,
});
},
+ escapePath(paths) {
+ if (!paths) return null;
+ if (typeof paths === "string") return paths.replace(/\\/g, "\\\\");
+ return paths.map((path) => path.replace(/\\/g, "\\\\"));
+ },
+ handleFileOpen(dialog) {
+ let { type, options } = window.lodashM.cloneDeep(dialog);
+ if (!type) type = "open";
+ if (type === "open") {
+ const files = this.escapePath(utools.showOpenDialog(options));
+ if (!files) return;
+ if (files.length > 1) {
+ this.$emit("update:modelValue", {
+ value: files,
+ isString: false,
+ __varInputVal__: true,
+ });
+ } else if (files.length === 1) {
+ this.$emit("update:modelValue", {
+ value: files[0],
+ isString: true,
+ __varInputVal__: true,
+ });
+ }
+ } else {
+ const file = this.escapePath(utools.showSaveDialog(options));
+ if (!file) return;
+ this.$emit("update:modelValue", {
+ value: file,
+ isString: true,
+ __varInputVal__: true,
+ });
+ }
+ },
},
});
@@ -275,31 +323,20 @@ export default defineComponent({
padding-right: 8px;
}
-/* 字符串切换按钮样式 */
-.string-toggle {
+.prepend-btn {
min-width: 24px;
padding: 4px;
opacity: 0.6;
transition: all 0.3s ease;
}
-.string-toggle:hover {
+.prepend-btn:hover {
opacity: 1;
transform: scale(1.05);
}
-/* 变量下拉框样式 */
-.variable-dropdown {
- min-width: 32px;
- padding: 4px;
- opacity: 0.8;
- transition: all 0.3s ease;
- margin-left: 4px;
-}
-
-.variable-dropdown:hover {
- opacity: 1;
- transform: scale(1.05);
+.clear-btn:hover {
+ color: var(--q-negative);
}
/* 变量列表样式 */
@@ -316,7 +353,7 @@ export default defineComponent({
}
.variable-item:hover {
- background: var(--q-primary-opacity-10);
+ backg: var(--q-primary-opacity-10);
}
.variable-label {
@@ -341,33 +378,7 @@ export default defineComponent({
background: rgba(255, 255, 255, 0.1);
}
-/* 清空按钮样式 */
-.clear-btn {
- opacity: 0.6;
- transition: all 0.3s ease;
-}
-
-.clear-btn:hover {
- opacity: 1;
- 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 {
+.options-item-list {
min-width: 120px;
padding: 4px;
}
@@ -383,11 +394,11 @@ export default defineComponent({
}
.option-item:hover {
- background: var(--q-primary-opacity-10);
+ backg: var(--q-primary-opacity-10);
}
/* 暗色模式适配 */
.body--dark .option-item:hover {
- background: rgba(255, 255, 255, 0.1);
+ backg: rgba(255, 255, 255, 0.1);
}
diff --git a/src/components/composer/file/FileOperationEditor.vue b/src/components/composer/file/FileOperationEditor.vue
index 31b8aaa..baaac9a 100644
--- a/src/components/composer/file/FileOperationEditor.vue
+++ b/src/components/composer/file/FileOperationEditor.vue
@@ -54,25 +54,24 @@
-
-
-
- 选择文件
-
-
+
@@ -584,23 +583,6 @@ export default defineComponent({
this.updateModelValue(argvs);
},
- async selectFile() {
- const result = window.utools.showOpenDialog({
- title: "选择文件",
- properties: [
- this.shouldSelectDirectory ? "openDirectory" : "openFile",
- "showHiddenFiles",
- ],
- buttonLabel: "选择",
- });
- if (result && result[0]) {
- this.updateArgvs("filePath", {
- value: result[0],
- isString: true,
- __varInputVal__: true,
- });
- }
- },
updateMode() {
const modeMap = {
read: 4,
diff --git a/src/components/composer/network/AxiosConfigEditor.vue b/src/components/composer/network/AxiosConfigEditor.vue
index 75f3175..5a2d499 100644
--- a/src/components/composer/network/AxiosConfigEditor.vue
+++ b/src/components/composer/network/AxiosConfigEditor.vue
@@ -90,7 +90,9 @@
:model-value="argvs.headers['User-Agent']"
@update:model-value="updateArgvs('headers.User-Agent', $event)"
label="User Agent"
- :options="userAgentOptions"
+ :options="{
+ items: userAgentOptions,
+ }"
icon="devices"
class="col-grow"
/>
diff --git a/src/js/composer/commands/fileCommands.js b/src/js/composer/commands/fileCommands.js
index 49a3f0b..a06579e 100644
--- a/src/js/composer/commands/fileCommands.js
+++ b/src/js/composer/commands/fileCommands.js
@@ -19,6 +19,12 @@ export const fileCommands = {
label: "文件、文件夹或软件的绝对路径",
type: "varInput",
icon: "folder_open",
+ options: {
+ dialog: {
+ type: "open",
+ options: {},
+ },
+ },
},
],
},
@@ -31,6 +37,12 @@ export const fileCommands = {
label: "文件、文件夹或软件的绝对路径",
type: "varInput",
icon: "location_on",
+ options: {
+ dialog: {
+ type: "open",
+ options: {},
+ },
+ },
},
],
},
@@ -43,6 +55,15 @@ export const fileCommands = {
label: "文件或软件的绝对路径",
type: "varInput",
icon: "folder_open",
+ options: {
+ dialog: {
+ type: "open",
+ options: {
+ filters: [{ extensions: ["exe", "app"] }],
+ properties: ["openFile", "openDirectory"],
+ },
+ },
+ },
},
],
},