mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-29 20:32:44 +08:00
编排新增HTML解析、上传、下载
This commit is contained in:
parent
ebbc7b7661
commit
01183d06e8
@ -4,6 +4,7 @@ const fs = require("fs");
|
||||
const kill = require("tree-kill");
|
||||
const iconv = require("iconv-lite");
|
||||
const path = require("path");
|
||||
const axios = require("axios");
|
||||
|
||||
const getQuickcommandTempFile = require("./getQuickcommandTempFile");
|
||||
const getCommandToLaunchTerminal = require("./getCommandToLaunchTerminal");
|
||||
@ -72,9 +73,9 @@ const quickcommand = {
|
||||
},
|
||||
|
||||
// 下载文件
|
||||
downloadFile: function (url, file = {}) {
|
||||
downloadFile: function (url, file) {
|
||||
return new Promise((reslove, reject) => {
|
||||
if (file instanceof Object)
|
||||
if (!file || file instanceof Object)
|
||||
file = window.utools.showSaveDialog(JSON.parse(JSON.stringify(file)));
|
||||
axios({
|
||||
method: "get",
|
||||
@ -95,13 +96,13 @@ const quickcommand = {
|
||||
},
|
||||
|
||||
// 上传文件
|
||||
uploadFile: function (url, file = {}, name = "file", formData = {}) {
|
||||
uploadFile: function (url, file, name = "file", formData = {}) {
|
||||
return new Promise((reslove, reject) => {
|
||||
var objfile;
|
||||
if (file instanceof File) {
|
||||
objfile = file;
|
||||
} else {
|
||||
if (file instanceof Object)
|
||||
if (!file || file instanceof Object)
|
||||
file = window.utools.showOpenDialog(
|
||||
JSON.parse(JSON.stringify(file))
|
||||
)[0];
|
||||
|
14
plugin/lib/quickcomposer/data/htmlParser.js
Normal file
14
plugin/lib/quickcomposer/data/htmlParser.js
Normal file
@ -0,0 +1,14 @@
|
||||
const htmlParser = (html, selector = "", attr = "") => {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, "text/html");
|
||||
if (!selector) return doc;
|
||||
const elements = doc.querySelectorAll(selector);
|
||||
if (!attr) return elements;
|
||||
let result = Array.from(elements).map((element) => element[attr]);
|
||||
if (result.length === 1) return result[0];
|
||||
return result;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
htmlParser,
|
||||
};
|
@ -1,9 +1,11 @@
|
||||
const string = require("./string");
|
||||
const buffer = require("./buffer");
|
||||
const zlib = require("./zlib");
|
||||
const htmlParser = require("./htmlParser");
|
||||
|
||||
module.exports = {
|
||||
...string,
|
||||
...htmlParser,
|
||||
buffer,
|
||||
zlib,
|
||||
};
|
||||
|
@ -1,82 +1,89 @@
|
||||
<template>
|
||||
<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="key in optionsKeys"
|
||||
:key="key.value"
|
||||
:class="[
|
||||
key.width ? `col-${key.width}` : 'col',
|
||||
optionsKeys.length > 1 ? 'q-pr-sm' : '',
|
||||
]"
|
||||
>
|
||||
<VariableInput
|
||||
:model-value="item[key.value]"
|
||||
:label="key.label"
|
||||
:no-icon="true"
|
||||
@update:model-value="
|
||||
(val) => updateItemKeyValue(index, key.value, val)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="col">
|
||||
<VariableInput
|
||||
:model-value="item"
|
||||
:label="`${label || '项目'} ${index + 1}`"
|
||||
:icon="icon || 'code'"
|
||||
:options="{
|
||||
items: options.items,
|
||||
}"
|
||||
@update:model-value="(val) => updateItemValue(index, val)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div class="col-auto">
|
||||
<div class="btn-container">
|
||||
<template v-if="items.length === 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="center-btn"
|
||||
@click="addItem"
|
||||
<component
|
||||
:is="!!label ? 'BorderLabel' : 'div'"
|
||||
:label="label"
|
||||
:icon="icon"
|
||||
: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="key in optionsKeys"
|
||||
:key="key.value"
|
||||
:class="[
|
||||
key.width ? `col-${key.width}` : 'col',
|
||||
optionsKeys.length > 1 ? 'q-pr-sm' : '',
|
||||
]"
|
||||
>
|
||||
<VariableInput
|
||||
:model-value="item[key.value]"
|
||||
:label="key.label"
|
||||
:no-icon="true"
|
||||
@update:model-value="
|
||||
(val) => updateItemKeyValue(index, key.value, val)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="index === items.length - 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="top-btn"
|
||||
@click="removeItem(index)"
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="col">
|
||||
<VariableInput
|
||||
:model-value="item"
|
||||
:label="`${label || '项目'} ${index + 1}`"
|
||||
:icon="icon || 'code'"
|
||||
:options="{
|
||||
items: options.items,
|
||||
}"
|
||||
@update:model-value="(val) => updateItemValue(index, val)"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="bottom-btn"
|
||||
@click="addItem"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="center-btn"
|
||||
@click="removeItem(index)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<div class="col-auto">
|
||||
<div class="btn-container">
|
||||
<template v-if="items.length === 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="center-btn"
|
||||
@click="addItem"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="index === items.length - 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="top-btn"
|
||||
@click="removeItem(index)"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="bottom-btn"
|
||||
@click="addItem"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="center-btn"
|
||||
@click="removeItem(index)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -118,16 +125,19 @@
|
||||
import { defineComponent } from "vue";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ArrayEditor",
|
||||
components: {
|
||||
VariableInput,
|
||||
BorderLabel,
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => [],
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
@ -137,6 +147,10 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
isCollapse: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
|
@ -1,12 +1,20 @@
|
||||
<template>
|
||||
<div class="border-label" :class="{ collapsed }" :data-label="label">
|
||||
<div class="label-header" @click="toggleCollapse">
|
||||
<div class="label-header row items-center" @click="toggleCollapse">
|
||||
<q-icon
|
||||
:name="collapsed ? 'expand_more' : 'expand_less'"
|
||||
size="16px"
|
||||
class="collapse-icon"
|
||||
/>
|
||||
<span class="label-text">{{ label }}</span>
|
||||
<div class="label-text row items-center">
|
||||
<q-icon
|
||||
v-if="icon"
|
||||
:name="icon"
|
||||
size="16px"
|
||||
class="collapse-icon q-pl-sm"
|
||||
/>
|
||||
<div class="label-text">{{ label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content" :class="{ collapsed }">
|
||||
<slot></slot>
|
||||
@ -33,6 +41,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
data() {
|
||||
|
@ -1,102 +1,110 @@
|
||||
<template>
|
||||
<div class="dict-editor">
|
||||
<div
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
class="row q-col-gutter-sm items-center"
|
||||
>
|
||||
<div class="col-4">
|
||||
<q-select
|
||||
v-if="options?.items"
|
||||
:model-value="item.key"
|
||||
:options="options.items"
|
||||
label="名称"
|
||||
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="code" />
|
||||
</template>
|
||||
</q-select>
|
||||
<q-input
|
||||
v-else
|
||||
:model-value="item.key"
|
||||
label="名称"
|
||||
dense
|
||||
filled
|
||||
@update:model-value="(val) => updateItemKey(val, index)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="code" />
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VariableInput
|
||||
:model-value="item.value"
|
||||
label="值"
|
||||
icon="code"
|
||||
class="col-grow"
|
||||
@update:model-value="(val) => updateItemValue(val, index)"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="btn-container">
|
||||
<template v-if="items.length === 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="center-btn"
|
||||
@click="addItem"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="index === items.length - 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="top-btn"
|
||||
@click="removeItem(index)"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="bottom-btn"
|
||||
@click="addItem"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="center-btn"
|
||||
@click="removeItem(index)"
|
||||
/>
|
||||
</template>
|
||||
<component
|
||||
:is="!!label ? 'BorderLabel' : 'div'"
|
||||
:label="label"
|
||||
:icon="icon"
|
||||
:model-value="isCollapse"
|
||||
>
|
||||
<div class="dict-editor">
|
||||
<div
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
class="row q-col-gutter-sm items-center"
|
||||
>
|
||||
<div class="col-4">
|
||||
<q-select
|
||||
v-if="options?.items"
|
||||
:model-value="item.key"
|
||||
:options="options.items"
|
||||
label="名称"
|
||||
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="code" />
|
||||
</template>
|
||||
</q-select>
|
||||
<q-input
|
||||
v-else
|
||||
:model-value="item.key"
|
||||
label="名称"
|
||||
dense
|
||||
filled
|
||||
@update:model-value="(val) => updateItemKey(val, index)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="code" />
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VariableInput
|
||||
:model-value="item.value"
|
||||
label="值"
|
||||
icon="code"
|
||||
class="col-grow"
|
||||
@update:model-value="(val) => updateItemValue(val, index)"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="btn-container">
|
||||
<template v-if="items.length === 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="center-btn"
|
||||
@click="addItem"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="index === items.length - 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="top-btn"
|
||||
@click="removeItem(index)"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="add"
|
||||
class="bottom-btn"
|
||||
@click="addItem"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="center-btn"
|
||||
@click="removeItem(index)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||
|
||||
/**
|
||||
* 字典编辑器组件
|
||||
@ -124,16 +132,30 @@ export default defineComponent({
|
||||
name: "DictEditor",
|
||||
components: {
|
||||
VariableInput,
|
||||
BorderLabel,
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({}),
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
isCollapse: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
data() {
|
||||
|
@ -29,12 +29,17 @@
|
||||
@update:model-value="$emit('update', index, $event)"
|
||||
:label="config.label"
|
||||
:options="config.options"
|
||||
:icon="config.icon"
|
||||
:is-collapse="config.isCollapse"
|
||||
/>
|
||||
<DictEditor
|
||||
v-else-if="config.type === 'dictEditor'"
|
||||
:model-value="values[index]"
|
||||
@update:model-value="$emit('update', index, $event)"
|
||||
:label="config.label"
|
||||
:options="config.options"
|
||||
:icon="config.icon"
|
||||
:is-collapse="config.isCollapse"
|
||||
/>
|
||||
<q-toggle
|
||||
v-else-if="config.type === 'switch'"
|
||||
|
@ -116,12 +116,12 @@
|
||||
|
||||
<!-- 环境变量 -->
|
||||
<div class="col-12">
|
||||
<BorderLabel label="环境变量">
|
||||
<DictEditor
|
||||
:model-value="argvs.options.env"
|
||||
@update:model-value="(val) => updateArgvs('options.env', val)"
|
||||
/>
|
||||
</BorderLabel>
|
||||
<DictEditor
|
||||
:model-value="argvs.options.env"
|
||||
@update:model-value="(val) => updateArgvs('options.env', val)"
|
||||
label="环境变量"
|
||||
icon="environment"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</q-slide-transition>
|
||||
@ -136,7 +136,6 @@ import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import NumberInput from "components/composer/common/NumberInput.vue";
|
||||
import DictEditor from "components/composer/common/DictEditor.vue";
|
||||
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "SystemCommandEditor",
|
||||
@ -144,7 +143,6 @@ export default defineComponent({
|
||||
VariableInput,
|
||||
NumberInput,
|
||||
DictEditor,
|
||||
BorderLabel,
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
@ -166,7 +164,6 @@ export default defineComponent({
|
||||
],
|
||||
defaultArgvs: {
|
||||
command: newVarInputVal("str"),
|
||||
},
|
||||
options: {
|
||||
cwd: newVarInputVal("str"),
|
||||
env: {},
|
||||
@ -174,9 +171,10 @@ export default defineComponent({
|
||||
encoding: "buffer",
|
||||
timeout: 0,
|
||||
maxBuffer: 1024 * 1024, // 1MB
|
||||
shell: newVarInputVal("str"),
|
||||
windowsHide: true,
|
||||
},
|
||||
shell: newVarInputVal("str"),
|
||||
windowsHide: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -440,5 +440,43 @@ export const dataCommands = {
|
||||
icon: "compress",
|
||||
isAsync: true,
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.data.htmlParser",
|
||||
label: "HTML解析",
|
||||
desc: "解析 HTML 字符串",
|
||||
icon: "html",
|
||||
config: [
|
||||
{
|
||||
label: "要解析的 HTML",
|
||||
type: "varInput",
|
||||
icon: "html",
|
||||
placeholder: "例如:<div>Hello, World!</div>",
|
||||
width: 12,
|
||||
},
|
||||
{
|
||||
label: "CSS选择器",
|
||||
type: "varInput",
|
||||
icon: "css",
|
||||
placeholder: "例如:.class",
|
||||
width: 7,
|
||||
},
|
||||
{
|
||||
label: "属性",
|
||||
type: "varInput",
|
||||
icon: "colorize",
|
||||
options: {
|
||||
items: [
|
||||
{ label: "innerText", value: "innerText" },
|
||||
{ label: "innerHTML", value: "innerHTML" },
|
||||
{ label: "href", value: "href" },
|
||||
{ label: "src", value: "src" },
|
||||
{ label: "value", value: "value" },
|
||||
],
|
||||
},
|
||||
defaultValue: newVarInputVal("str"),
|
||||
width: 5,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { newVarInputVal } from "../varInputValManager";
|
||||
|
||||
export const networkCommands = {
|
||||
label: "网络操作",
|
||||
icon: "language",
|
||||
@ -313,5 +315,63 @@ export const networkCommands = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcommand.downloadFile",
|
||||
label: "下载文件",
|
||||
desc: "下载文件",
|
||||
icon: "file_download",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
label: "文件URL",
|
||||
type: "varInput",
|
||||
icon: "link",
|
||||
defaultValue: newVarInputVal("str", "https://"),
|
||||
width: 12,
|
||||
},
|
||||
{
|
||||
label: "保存路径",
|
||||
type: "varInput",
|
||||
icon: "folder",
|
||||
width: 12,
|
||||
placeholder: "留空则弹出对话框选择保存路径",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcommand.uploadFile",
|
||||
label: "上传文件",
|
||||
desc: "上传文件",
|
||||
icon: "file_upload",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
label: "上传接口地址",
|
||||
type: "varInput",
|
||||
icon: "link",
|
||||
defaultValue: newVarInputVal("str", "https://"),
|
||||
width: 12,
|
||||
},
|
||||
{
|
||||
label: "文件路径",
|
||||
type: "varInput",
|
||||
icon: "file_present",
|
||||
width: 12,
|
||||
placeholder: "留空则弹出对话框选择文件",
|
||||
},
|
||||
{
|
||||
label: "文件名",
|
||||
type: "varInput",
|
||||
icon: "text_fields",
|
||||
defaultValue: newVarInputVal("str", "file"),
|
||||
width: 12,
|
||||
},
|
||||
{
|
||||
label: "额外表单数据(可选)",
|
||||
type: "dictEditor",
|
||||
width: 12,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user