mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-29 04:12:45 +08:00
优化ArrayDict/DictEditor参数传递,修复formatString处理Array时的BUG
This commit is contained in:
parent
41b3501945
commit
5e70c4c9a0
@ -6,7 +6,6 @@ const quickcomposer = {
|
||||
network: require("./quickcomposer/network"),
|
||||
coding: require("./quickcomposer/coding"),
|
||||
math: require("./quickcomposer/math"),
|
||||
ui: require("./quickcomposer/ui"),
|
||||
audio: require("./quickcomposer/audio"),
|
||||
image: require("./quickcomposer/image"),
|
||||
};
|
||||
|
@ -1,50 +0,0 @@
|
||||
const showSaveDialog = (
|
||||
title,
|
||||
defaultPath,
|
||||
buttonLabel,
|
||||
message,
|
||||
extensions,
|
||||
properties
|
||||
) => {
|
||||
return window.utools.showSaveDialog({
|
||||
title,
|
||||
defaultPath,
|
||||
buttonLabel,
|
||||
message,
|
||||
properties,
|
||||
filters: [
|
||||
{
|
||||
name: "文件",
|
||||
extensions,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const showOpenDialog = (
|
||||
title,
|
||||
defaultPath,
|
||||
buttonLabel,
|
||||
message,
|
||||
extensions,
|
||||
properties
|
||||
) => {
|
||||
return window.utools.showOpenDialog({
|
||||
title,
|
||||
defaultPath,
|
||||
buttonLabel,
|
||||
message,
|
||||
properties,
|
||||
filters: [
|
||||
{
|
||||
name: "文件",
|
||||
extensions,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
showSaveDialog,
|
||||
showOpenDialog,
|
||||
};
|
@ -1,6 +0,0 @@
|
||||
const { showSaveDialog, showOpenDialog } = require("./dialog");
|
||||
|
||||
module.exports = {
|
||||
showSaveDialog,
|
||||
showOpenDialog,
|
||||
};
|
@ -96,7 +96,7 @@ export default defineComponent({
|
||||
},
|
||||
saveFlow() {
|
||||
const flow = window.lodashM.cloneDeep(this.commandFlow);
|
||||
const uselessProps = ["config", "argvs", "label", "type"];
|
||||
const uselessProps = ["config", "argvs", "label", "component", "subCommands", "options", "defaultValue"];
|
||||
// 移除不必要属性
|
||||
flow.forEach((cmd) => {
|
||||
for (const props of uselessProps) {
|
||||
|
@ -6,25 +6,21 @@
|
||||
:model-value="isCollapse"
|
||||
>
|
||||
<div class="array-editor">
|
||||
<div v-for="(item, index) in items" :key="index" class="row items-center">
|
||||
<template v-if="optionsKeys.length">
|
||||
<div v-for="(row, index) in rows" :key="index" class="row items-center">
|
||||
<template v-if="columns">
|
||||
<div
|
||||
v-for="key in optionsKeys"
|
||||
:key="key.value"
|
||||
v-for="column in processedColumns"
|
||||
:key="column.key"
|
||||
:class="[
|
||||
key.width ? `col-${key.width}` : 'col',
|
||||
optionsKeys.length > 1 ? 'q-pr-sm' : '',
|
||||
column.width ? `col-${column.width}` : 'col',
|
||||
Object.keys(columns).length > 1 ? 'q-pr-sm' : '',
|
||||
]"
|
||||
>
|
||||
<VariableInput
|
||||
:model-value="item[key.value] || key.defaultValue"
|
||||
:label="key.label"
|
||||
:no-icon="true"
|
||||
:placeholder="key.placeholder"
|
||||
:options="key.options"
|
||||
:disable-toggle-type="key.disableToggleType"
|
||||
:model-value="row[column.key]"
|
||||
v-bind="column"
|
||||
@update:model-value="
|
||||
(val) => updateItemKeyValue(index, key.value, val)
|
||||
(val) => updateColumn(index, column.key, val)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
@ -32,38 +28,32 @@
|
||||
<template v-else>
|
||||
<div class="col">
|
||||
<VariableInput
|
||||
:model-value="item"
|
||||
:label="`${label || '项目'} ${index + 1}`"
|
||||
:icon="icon || 'code'"
|
||||
:placeholder="placeholder"
|
||||
:options="{
|
||||
items: options.items,
|
||||
}"
|
||||
:disable-toggle-type="disableToggleType"
|
||||
@update:model-value="(val) => updateItemValue(index, val)"
|
||||
:model-value="row"
|
||||
v-bind="$attrs"
|
||||
@update:model-value="(val) => updateValue(index, val)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div class="col-auto">
|
||||
<div class="btn-container">
|
||||
<template v-if="items.length === 1">
|
||||
<template v-if="rows.length === 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="center-btn"
|
||||
@click="addItem"
|
||||
@click="addRow"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="index === items.length - 1">
|
||||
<template v-else-if="index === rows.length - 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="top-btn"
|
||||
@click="removeItem(index)"
|
||||
@click="removeRow(index)"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
@ -71,7 +61,7 @@
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="bottom-btn"
|
||||
@click="addItem"
|
||||
@click="addRow"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
@ -81,7 +71,7 @@
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="center-btn"
|
||||
@click="removeItem(index)"
|
||||
@click="removeRow(index)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
@ -94,63 +84,62 @@
|
||||
<script>
|
||||
/**
|
||||
* 数组编辑器组件
|
||||
* @description 支持单值数组和多键对象数组的编辑
|
||||
* @description 支持简单数组和对象数组的编辑
|
||||
*
|
||||
* @property {Array} modelValue - 绑定的数组值
|
||||
* @property {String} label - 输入框标签
|
||||
* @property {String} icon - 输入框图标
|
||||
* @property {Object} options - 配置选项
|
||||
* @property {Object} columns - 列配置(可选)
|
||||
*
|
||||
* @property {String[]} [options.keys] - 多键对象模式的键名列表
|
||||
* @property {String[]} [options.keys.value] - 元素为对象时,对象的键名
|
||||
* @property {String[]} [options.keys.label] - 对应varInput的label
|
||||
* @property {String[]} [options.keys.placeholder] - 对应varInput的placeholder
|
||||
* @property {String[]} [options.keys.defaultValue] - 对应varInput的defaultValue
|
||||
* @property {Object} [options.keys.options] - 对应varInput的options
|
||||
*
|
||||
* @property {String[]} [options.items] - 下拉选择模式的选项列表
|
||||
* @property {Object} [options.defaultValue] - 初始化时,默认的值,决定显示几个元素,对应元素内容
|
||||
* @example
|
||||
* // 基础数组
|
||||
* // 1. 简单数组(不传 columns)
|
||||
* // 值示例:
|
||||
* [
|
||||
* newVarInputVal("str", "张三")
|
||||
* newVarInputVal('str', '选项1'),
|
||||
* newVarInputVal('str', '选项2')
|
||||
* ]
|
||||
*
|
||||
* // 多键对象数组
|
||||
* options.keys = ['name', 'age', 'email']
|
||||
* 属性透传:
|
||||
* ArrayEditor属性全部透传给VariableInput
|
||||
*
|
||||
* options.keys= [
|
||||
* {
|
||||
* label: "姓名",
|
||||
* value: "name",
|
||||
* placeholder: "姓名",
|
||||
* 初始值:
|
||||
* 使用defaultValue属性设置初始值
|
||||
* 使用defaultRowValue属性设置新增行时的初始值
|
||||
*
|
||||
* // 2. 对象数组(传入 columns)
|
||||
* columns = {
|
||||
* name: {
|
||||
* label: '姓名',
|
||||
* placeholder: '请输入姓名',
|
||||
* width: 6,
|
||||
* options: {
|
||||
* items: ["张三", "李四", "王五"],
|
||||
* multiSelect: true,
|
||||
* items: ['张三', '李四', '王五']
|
||||
* },
|
||||
* defaultValue: newVarInputVal('str', '张三')
|
||||
* },
|
||||
* age: {
|
||||
* label: '年龄',
|
||||
* placeholder: '请输入年龄',
|
||||
* width: 4,
|
||||
* defaultValue: newVarInputVal('str', '18')
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* }
|
||||
* // 值示例:
|
||||
* [
|
||||
* {
|
||||
* name: newVarInputVal("str", "张三"),
|
||||
* age: newVarInputVal("str", "18"),
|
||||
* email: newVarInputVal("str", "zhangsan@example.com")
|
||||
* name: newVarInputVal('str', '张三'),
|
||||
* age: newVarInputVal('str', '18')
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* // 下拉选择模式
|
||||
* options.items = ['选项1', '选项2', '选项3']
|
||||
* [
|
||||
* newVarInputVal("str", "选项1"),
|
||||
* newVarInputVal("str", "选项2"),
|
||||
* newVarInputVal("str", "选项3")
|
||||
* ]
|
||||
* 属性透传:
|
||||
* columns的每一个对象的值的属性全部透传给VariableInput
|
||||
*
|
||||
* 初始值:
|
||||
* 使用defaultValue属性设置初始的每一行
|
||||
* columns的每一个对象的defaultValue属性设置新增行时的初始值
|
||||
*/
|
||||
import { defineComponent } from "vue";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import VariableInput from "./VariableInput.vue";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||
import BorderLabel from "./BorderLabel.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ArrayEditor",
|
||||
@ -164,9 +153,17 @@ export default defineComponent({
|
||||
required: true,
|
||||
default: () => [],
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: "",
|
||||
columns: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
defaultValue: {
|
||||
type: [Object, Array],
|
||||
default: null,
|
||||
},
|
||||
defaultRowValue: {
|
||||
type: [Object, String],
|
||||
default: null,
|
||||
},
|
||||
topLabel: {
|
||||
type: String,
|
||||
@ -180,103 +177,89 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
disableToggleType: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
computed: {
|
||||
items() {
|
||||
return this.modelValue.length ? this.modelValue : this.initializeItems();
|
||||
rows() {
|
||||
return this.modelValue.length ? this.modelValue : this.initializeRow();
|
||||
},
|
||||
optionsKeys() {
|
||||
return (
|
||||
this.options?.keys?.map((key) => {
|
||||
return {
|
||||
...key,
|
||||
value: key.value || key,
|
||||
label: key.label || key,
|
||||
};
|
||||
}) || []
|
||||
);
|
||||
processedColumns() {
|
||||
if (!this.columns) return null;
|
||||
|
||||
return Object.entries(this.columns).map(([key, config]) => ({
|
||||
key,
|
||||
...config,
|
||||
width: config.width || null,
|
||||
defaultValue: config.defaultValue || newVarInputVal("str"),
|
||||
}));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
initializeItems() {
|
||||
if (this.optionsKeys?.length) {
|
||||
const item = {};
|
||||
this.optionsKeys.forEach((key) => {
|
||||
item[key] = newVarInputVal("str");
|
||||
});
|
||||
return [item];
|
||||
initializeRow() {
|
||||
if (!this.columns) {
|
||||
// 简单数组模式:使用 defaultValue 或创建新的 VarInputVal
|
||||
return this.defaultValue || [newVarInputVal("str")];
|
||||
}
|
||||
|
||||
return [newVarInputVal("str")];
|
||||
},
|
||||
/**
|
||||
* 添加新的数组项
|
||||
* 根据配置创建相应的数据结构
|
||||
*/
|
||||
addItem() {
|
||||
let newItems = [];
|
||||
if (this.options.keys) {
|
||||
const newItem = {};
|
||||
this.options.keys.forEach((key) => {
|
||||
newItem[key] = newVarInputVal("str");
|
||||
});
|
||||
newItems = [...this.items, newItem];
|
||||
} else {
|
||||
newItems = [...this.items, newVarInputVal("str")];
|
||||
// 对象数组模式
|
||||
if (this.defaultValue) {
|
||||
return [this.defaultValue];
|
||||
}
|
||||
this.$emit("update:modelValue", newItems);
|
||||
|
||||
const row = {};
|
||||
Object.entries(this.columns).forEach(([key, config]) => {
|
||||
row[key] = config.defaultValue || newVarInputVal("str");
|
||||
});
|
||||
return [row];
|
||||
},
|
||||
/**
|
||||
* 移除指定索引的数组项
|
||||
* 如果移除后数组为空,则创建一个新的空项
|
||||
*/
|
||||
removeItem(index) {
|
||||
const newItems = [...this.items];
|
||||
newItems.splice(index, 1);
|
||||
if (newItems.length === 0) {
|
||||
if (this.options.keys) {
|
||||
const newItem = {};
|
||||
this.options.keys.forEach((key) => {
|
||||
newItem[key] = newVarInputVal("str");
|
||||
});
|
||||
newItems.push(newItem);
|
||||
} else {
|
||||
newItems.push(newVarInputVal("str"));
|
||||
getNewRowValue() {
|
||||
if (!this.columns) {
|
||||
// 简单数组模式:使用 defaultRowValue 或创建新的 VarInputVal
|
||||
return this.defaultRowValue || newVarInputVal("str");
|
||||
}
|
||||
|
||||
// 对象数组模式
|
||||
if (this.defaultRowValue) {
|
||||
return this.defaultRowValue;
|
||||
}
|
||||
|
||||
const row = {};
|
||||
Object.entries(this.columns).forEach(([key, config]) => {
|
||||
row[key] = config.defaultValue || newVarInputVal("str");
|
||||
});
|
||||
return row;
|
||||
},
|
||||
addRow() {
|
||||
const newRows = [...this.rows, this.getNewRowValue()];
|
||||
this.$emit("update:modelValue", newRows);
|
||||
},
|
||||
removeRow(index) {
|
||||
const newRows = [...this.rows];
|
||||
newRows.splice(index, 1);
|
||||
if (newRows.length === 0) {
|
||||
newRows.push(this.initializeRow()[0]);
|
||||
}
|
||||
this.$emit("update:modelValue", newRows);
|
||||
},
|
||||
updateValue(index, value) {
|
||||
const newRows = [...this.rows];
|
||||
newRows[index] = value;
|
||||
this.$emit("update:modelValue", newRows);
|
||||
},
|
||||
updateColumn(index, columnKey, value) {
|
||||
// 创建一个新的行数组
|
||||
const newRows = this.rows.map((row, i) => {
|
||||
// 只更新指定索引的行
|
||||
if (i === index) {
|
||||
return {
|
||||
...row,
|
||||
[columnKey]: value,
|
||||
};
|
||||
}
|
||||
}
|
||||
this.$emit("update:modelValue", newItems);
|
||||
},
|
||||
/**
|
||||
* 更新单值模式下的值
|
||||
*/
|
||||
updateItemValue(index, value) {
|
||||
const newItems = [...this.items];
|
||||
newItems[index] = value;
|
||||
this.$emit("update:modelValue", newItems);
|
||||
},
|
||||
/**
|
||||
* 更新多键模式下指定键的值
|
||||
*/
|
||||
updateItemKeyValue(index, key, value) {
|
||||
const newItems = [...this.items];
|
||||
newItems[index] = {
|
||||
...newItems[index],
|
||||
[key]: value,
|
||||
};
|
||||
this.$emit("update:modelValue", newItems);
|
||||
return row;
|
||||
});
|
||||
|
||||
this.$emit("update:modelValue", newRows);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -157,7 +157,7 @@ import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||
* }
|
||||
*
|
||||
* // 下拉选择模式
|
||||
* options.items = ['User-Agent', 'Content-Type', 'Accept']
|
||||
* options.optionKeys = ['User-Agent', 'Content-Type', 'Accept']
|
||||
* {
|
||||
* "User-Agent": newVarInputVal("str", "Mozilla/5.0"),
|
||||
* "Content-Type": newVarInputVal("str", "text/html"),
|
||||
|
@ -130,23 +130,8 @@
|
||||
<template v-if="argvs.optionType === 'json'">
|
||||
<ArrayEditor
|
||||
:model-value="argvs.selects"
|
||||
:options="{
|
||||
keys: [
|
||||
{
|
||||
value: 'id',
|
||||
label: 'id',
|
||||
width: 3,
|
||||
},
|
||||
{
|
||||
value: 'title',
|
||||
label: '标题',
|
||||
},
|
||||
{
|
||||
value: 'description',
|
||||
label: '描述',
|
||||
},
|
||||
],
|
||||
}"
|
||||
:columns="arrayEditorColumns"
|
||||
:default-row-value="arrayEditorDefaultRowValue"
|
||||
@update:model-value="updateArgvs('selects', $event)"
|
||||
>
|
||||
<template #header>
|
||||
@ -178,8 +163,7 @@ import VariableInput from "../common/VariableInput.vue";
|
||||
import ArrayEditor from "../common/ArrayEditor.vue";
|
||||
import OperationCard from "../common/OperationCard.vue";
|
||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
||||
import { newVarInputVal, isVarInputVal} from "js/composer/varInputValManager";
|
||||
|
||||
import { newVarInputVal, isVarInputVal } from "js/composer/varInputValManager";
|
||||
|
||||
const jsonDefaultSelects = new Array(3).fill().map((_, index) => ({
|
||||
id: newVarInputVal("var", index),
|
||||
@ -226,6 +210,28 @@ export default defineComponent({
|
||||
showCancelButton: false,
|
||||
closeOnSelect: true,
|
||||
},
|
||||
arrayEditorDefaultRowValue: {
|
||||
id: newVarInputVal("var"),
|
||||
title: newVarInputVal("str"),
|
||||
description: newVarInputVal("str"),
|
||||
},
|
||||
arrayEditorColumns: {
|
||||
id: {
|
||||
label: "id",
|
||||
width: 3,
|
||||
noIcon: true,
|
||||
},
|
||||
title: {
|
||||
label: "标题",
|
||||
width: 4,
|
||||
noIcon: true,
|
||||
},
|
||||
description: {
|
||||
label: "描述",
|
||||
width: 4,
|
||||
noIcon: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -335,6 +335,7 @@ export const dataCommands = {
|
||||
icon: "memory",
|
||||
width: 12,
|
||||
defaultValue: [newVarInputVal("var")],
|
||||
defaultRowValue: newVarInputVal("var"),
|
||||
disableToggleType: true,
|
||||
},
|
||||
{
|
||||
|
@ -1,5 +1,109 @@
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
|
||||
const SAVE_DIALOG_PROPERTIES = {
|
||||
component: "CheckGroup",
|
||||
icon: "settings",
|
||||
label: "选项",
|
||||
width: 12,
|
||||
options: [
|
||||
{ label: "显示隐藏文件", value: "showHiddenFiles" },
|
||||
{ label: "允许创建文件夹(Mac)", value: "createDirectory" },
|
||||
{
|
||||
label: "将.App作为目录(Mac)",
|
||||
value: "treatPackageAsDirectory",
|
||||
},
|
||||
{
|
||||
label: "显示覆盖确认(Linux)",
|
||||
value: "showOverwriteConfirmation",
|
||||
},
|
||||
{ label: "不添加到最近(Win)", value: "dontAddToRecent" },
|
||||
],
|
||||
};
|
||||
|
||||
const OPEN_DIALOG_PROPERTIES = {
|
||||
...SAVE_DIALOG_PROPERTIES,
|
||||
options: [
|
||||
{ label: "选择文件", value: "openFile" },
|
||||
{ label: "选择文件夹", value: "openDirectory" },
|
||||
{ label: "允许多选", value: "multiSelections" },
|
||||
{ label: "显示隐藏文件", value: "showHiddenFiles" },
|
||||
{ label: "提示新建路径(Win)", value: "promptToCreate" },
|
||||
{ label: "不添加到最近(Win)", value: "dontAddToRecent" },
|
||||
{ label: "允许创建文件夹(Mac)", value: "createDirectory" },
|
||||
{ label: "不解析符号链接(Mac)", value: "noResolveAliases" },
|
||||
{
|
||||
label: "将.App作为目录(Mac)",
|
||||
value: "treatPackageAsDirectory",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const DIALOG_CONFIG = {
|
||||
options: {
|
||||
title: {
|
||||
label: "标题",
|
||||
component: "VariableInput",
|
||||
icon: "title",
|
||||
width: 6,
|
||||
},
|
||||
defaultPath: {
|
||||
label: "默认路径",
|
||||
component: "VariableInput",
|
||||
icon: "folder",
|
||||
width: 6,
|
||||
},
|
||||
buttonLabel: {
|
||||
label: "按钮文本",
|
||||
component: "VariableInput",
|
||||
icon: "text_fields",
|
||||
width: 6,
|
||||
},
|
||||
message: {
|
||||
label: "提示信息",
|
||||
component: "VariableInput",
|
||||
icon: "info",
|
||||
width: 6,
|
||||
},
|
||||
filters: {
|
||||
topLabel: "过滤器",
|
||||
component: "ArrayEditor",
|
||||
icon: "filter_list",
|
||||
width: 12,
|
||||
defaultRowValue: [newVarInputVal("str"), newVarInputVal("var", "")],
|
||||
columns: {
|
||||
name: {
|
||||
label: "文件类型",
|
||||
noIcon: true,
|
||||
width: 4,
|
||||
},
|
||||
extensions: {
|
||||
label: "扩展名",
|
||||
noIcon: true,
|
||||
width: 7,
|
||||
disableToggleType: true,
|
||||
options: {
|
||||
items: ["*", "jpg", "png", "gif", "txt", "json", "exe"],
|
||||
multiSelect: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultValue: {
|
||||
title: newVarInputVal("str", "请选择"),
|
||||
defaultPath: newVarInputVal("str"),
|
||||
buttonLabel: newVarInputVal("str", "选择"),
|
||||
message: newVarInputVal("str", "请选择"),
|
||||
filters: [
|
||||
{
|
||||
name: newVarInputVal("str", "file"),
|
||||
extensions: newVarInputVal("var", '["*"]'),
|
||||
},
|
||||
],
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
},
|
||||
};
|
||||
|
||||
export const uiCommands = {
|
||||
label: "用户交互",
|
||||
icon: "web",
|
||||
@ -19,6 +123,7 @@ export const uiCommands = {
|
||||
newVarInputVal("str", "是"),
|
||||
newVarInputVal("str", "否"),
|
||||
],
|
||||
defaultRowValue: newVarInputVal("str"),
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -33,17 +138,13 @@ export const uiCommands = {
|
||||
label: "输入框",
|
||||
component: "ArrayEditor",
|
||||
width: 12,
|
||||
options: {
|
||||
keys: [
|
||||
{
|
||||
label: "标签",
|
||||
value: "label",
|
||||
},
|
||||
{
|
||||
label: "默认值",
|
||||
value: "value",
|
||||
},
|
||||
],
|
||||
columns: {
|
||||
label: {
|
||||
label: "标签",
|
||||
},
|
||||
value: {
|
||||
label: "默认值",
|
||||
},
|
||||
},
|
||||
defaultValue: [
|
||||
{
|
||||
@ -163,106 +264,43 @@ export const uiCommands = {
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.ui.showOpenDialog",
|
||||
value: "utools.showOpenDialog",
|
||||
label: "文件选择框",
|
||||
desc: "显示一个文件选择框,返回选择的文件路径",
|
||||
outputVariable: "filePaths",
|
||||
saveOutput: true,
|
||||
config: [
|
||||
{
|
||||
label: "标题",
|
||||
component: "VariableInput",
|
||||
defaultValue: newVarInputVal("str", "请选择文件"),
|
||||
width: 6,
|
||||
},
|
||||
{
|
||||
label: "默认路径",
|
||||
component: "VariableInput",
|
||||
defaultValue: newVarInputVal("str"),
|
||||
width: 6,
|
||||
placeholder: "默认打开的路径",
|
||||
},
|
||||
{
|
||||
label: "按钮文本",
|
||||
component: "VariableInput",
|
||||
defaultValue: newVarInputVal("str", "选择"),
|
||||
width: 3,
|
||||
},
|
||||
{
|
||||
label: "提示信息",
|
||||
component: "VariableInput",
|
||||
defaultValue: newVarInputVal("str"),
|
||||
width: 3,
|
||||
placeholder: "对话框底部的提示信息",
|
||||
defaultValue: newVarInputVal("str", "请选择"),
|
||||
},
|
||||
{
|
||||
label: "扩展名",
|
||||
component: "VariableInput",
|
||||
width: 6,
|
||||
options: {
|
||||
items: ["*", "jpg", "png", "gif", "txt", "json", "exe"],
|
||||
multiSelect: true,
|
||||
},
|
||||
defaultValue: newVarInputVal("var", '["*"]'),
|
||||
disableToggleType: true,
|
||||
},
|
||||
],
|
||||
subCommands: [
|
||||
{
|
||||
value: "quickcomposer.ui.showOpenDialog",
|
||||
value: "utools.showOpenDialog",
|
||||
label: "打开文件对话框",
|
||||
desc: "打开文件对话框",
|
||||
icon: "folder_open",
|
||||
config: [
|
||||
{
|
||||
label: "选择选项",
|
||||
component: "CheckGroup",
|
||||
icon: "settings",
|
||||
width: 12,
|
||||
options: [
|
||||
{ label: "选择文件", value: "openFile" },
|
||||
{ label: "选择文件夹", value: "openDirectory" },
|
||||
{ label: "允许多选", value: "multiSelections" },
|
||||
{ label: "显示隐藏文件", value: "showHiddenFiles" },
|
||||
{ label: "提示新建路径(Win)", value: "promptToCreate" },
|
||||
{ label: "不添加到最近(Win)", value: "dontAddToRecent" },
|
||||
{ label: "允许创建文件夹(Mac)", value: "createDirectory" },
|
||||
{ label: "不解析符号链接(Mac)", value: "noResolveAliases" },
|
||||
{
|
||||
label: "将.App作为目录(Mac)",
|
||||
value: "treatPackageAsDirectory",
|
||||
},
|
||||
],
|
||||
defaultValue: ["openFile", "showHiddenFiles"],
|
||||
label: "选项",
|
||||
component: "OptionEditor",
|
||||
defaultValue: DIALOG_CONFIG.defaultValue,
|
||||
options: {
|
||||
...DIALOG_CONFIG.options,
|
||||
properties: OPEN_DIALOG_PROPERTIES,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.ui.showSaveDialog",
|
||||
value: "utools.showSaveDialog",
|
||||
label: "保存文件对话框",
|
||||
desc: "保存文件对话框",
|
||||
icon: "save",
|
||||
config: [
|
||||
{
|
||||
label: "选择选项",
|
||||
component: "CheckGroup",
|
||||
icon: "settings",
|
||||
width: 12,
|
||||
options: [
|
||||
{ label: "显示隐藏文件", value: "showHiddenFiles" },
|
||||
{ label: "允许创建文件夹(Mac)", value: "createDirectory" },
|
||||
{
|
||||
label: "将.App作为目录(Mac)",
|
||||
value: "treatPackageAsDirectory",
|
||||
},
|
||||
{
|
||||
label: "显示覆盖确认(Linux)",
|
||||
value: "showOverwriteConfirmation",
|
||||
},
|
||||
{ label: "不添加到最近(Win)", value: "dontAddToRecent" },
|
||||
],
|
||||
defaultValue: ["showHiddenFiles"],
|
||||
label: "选项",
|
||||
component: "OptionEditor",
|
||||
defaultValue: DIALOG_CONFIG.defaultValue,
|
||||
options: {
|
||||
...DIALOG_CONFIG.options,
|
||||
properties: SAVE_DIALOG_PROPERTIES,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -6,69 +6,101 @@ import {
|
||||
} from "./varInputValManager";
|
||||
|
||||
/**
|
||||
* 递归移除对象中的空值
|
||||
* @param {Object} obj 要处理的对象
|
||||
* @returns {Object} 处理后的对象
|
||||
* 处理单个值,返回格式化后的字符串
|
||||
*/
|
||||
const removeEmptyValues = (obj) => {
|
||||
return window.lodashM.omitBy(obj, (value) => {
|
||||
// 如果value是VariableInput的输出,则取其value值
|
||||
const realValue = isVarInputVal(value) ? value.value : value;
|
||||
if (window.lodashM.isNil(realValue) || realValue === "") return true;
|
||||
// 如果value是对象,并且不是VariableInput的输出,则递归移除空值
|
||||
if (typeof value === "object" && !isVarInputVal(value))
|
||||
return window.lodashM.isEmpty(removeEmptyValues(value));
|
||||
return false;
|
||||
});
|
||||
const processValue = (value, parentPath = "") => {
|
||||
if (!value) return value;
|
||||
|
||||
if (typeof value === "object") {
|
||||
if (isVarInputVal(value)) {
|
||||
return stringifyVarInputVal(value);
|
||||
}
|
||||
return processObject(value, parentPath);
|
||||
}
|
||||
|
||||
return typeof value === "string" ? `"${value}"` : value;
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式化带缩进的值
|
||||
*/
|
||||
const formatWithIndent = (value, indent, isLast = true) => {
|
||||
return `${indent}${value}${isLast ? "" : ","}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* 递归处理对象的值并格式化成字符串
|
||||
* @param {Object} obj 要处理的对象
|
||||
* @param {string} parentPath 父路径(用于缩进)
|
||||
* @returns {string} 处理后的字符串
|
||||
*/
|
||||
const processObject = (obj, parentPath = "") => {
|
||||
// 移除空值
|
||||
obj = removeEmptyValues(obj);
|
||||
// 如果是 VariableInput 的输出,直接用 stringifyVarInputVal 处理
|
||||
|
||||
if (isVarInputVal(obj)) {
|
||||
return stringifyVarInputVal(obj);
|
||||
}
|
||||
|
||||
let result = "{\n";
|
||||
const indentLevel = parentPath.split(".").length;
|
||||
const indent = " ".repeat(indentLevel + 1);
|
||||
const closingIndent = " ".repeat(indentLevel);
|
||||
|
||||
// 处理数组
|
||||
if (Array.isArray(obj)) {
|
||||
if (obj.length === 0) return "[]";
|
||||
|
||||
const items = obj.map((item, index) =>
|
||||
formatWithIndent(
|
||||
processValue(item, parentPath + " "),
|
||||
indent,
|
||||
index === obj.length - 1
|
||||
)
|
||||
);
|
||||
|
||||
return `[\n${items.join("\n")}\n${closingIndent}]`;
|
||||
}
|
||||
|
||||
// 处理对象
|
||||
const entries = Object.entries(obj);
|
||||
if (entries.length === 0) return "{}";
|
||||
|
||||
entries.forEach(([key, value], index) => {
|
||||
let valueStr = "";
|
||||
const items = entries.map(([key, value], index) =>
|
||||
formatWithIndent(
|
||||
`"${key}": ${processValue(value, parentPath + " ")}`,
|
||||
indent,
|
||||
index === entries.length - 1
|
||||
)
|
||||
);
|
||||
|
||||
// 处理对象类型
|
||||
if (value && typeof value === "object") {
|
||||
// 如果是 VariableInput 的输出,直接用 stringifyVarInputVal 处理
|
||||
if (isVarInputVal(value)) {
|
||||
valueStr = stringifyVarInputVal(value);
|
||||
} else {
|
||||
valueStr = processObject(value, parentPath + " ");
|
||||
}
|
||||
}
|
||||
// 处理其他类型
|
||||
else if (value && typeof value === "string") {
|
||||
valueStr = `"${value}"`;
|
||||
} else {
|
||||
valueStr = value;
|
||||
return `{\n${items.join("\n")}\n${closingIndent}}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* 递归移除对象中的空值
|
||||
*/
|
||||
const removeEmptyValues = (obj) => {
|
||||
const isEmptyValue = (value) => {
|
||||
const realValue = isVarInputVal(value) ? value.value : value;
|
||||
return window.lodashM.isNil(realValue) || realValue === "";
|
||||
};
|
||||
|
||||
const processObjectValue = (value) => {
|
||||
if (typeof value === "object" && !isVarInputVal(value)) {
|
||||
return removeEmptyValues(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
// 添加缩进
|
||||
const indent = " ".repeat(parentPath.split(".").length + 1);
|
||||
result += `${indent}"${key}": ${valueStr}`;
|
||||
if (index < entries.length - 1) result += ",";
|
||||
result += "\n";
|
||||
});
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.filter((value) => !isEmptyValue(value)).map(processObjectValue);
|
||||
}
|
||||
|
||||
// 闭合括号的缩进
|
||||
const closingIndent = " ".repeat(parentPath.split(".").length);
|
||||
result += `${closingIndent}}`;
|
||||
return result;
|
||||
return window.lodashM.omitBy(
|
||||
obj,
|
||||
(value) =>
|
||||
isEmptyValue(value) ||
|
||||
(typeof value === "object" &&
|
||||
!isVarInputVal(value) &&
|
||||
window.lodashM.isEmpty(removeEmptyValues(value)))
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -264,9 +296,7 @@ export const parseFunction = (functionStr, options = {}) => {
|
||||
: node.value;
|
||||
// null
|
||||
case "NullLiteral":
|
||||
return shouldUseVariableFormat
|
||||
? newVarInputVal("var", "null")
|
||||
: null;
|
||||
return shouldUseVariableFormat ? newVarInputVal("var", "null") : null;
|
||||
case "Identifier":
|
||||
// 标识符(变量)总是不带引号的
|
||||
return shouldUseVariableFormat
|
||||
|
Loading…
x
Reference in New Issue
Block a user