mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-12-18 09:57:23 +08:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71375e2c86 | ||
|
|
34230fa140 | ||
|
|
f9e0c29c08 | ||
|
|
65936e7d0d | ||
|
|
1da46e8dc5 | ||
|
|
7f26c0f176 | ||
|
|
0ab029a5b3 | ||
|
|
4c2f835222 | ||
|
|
05402fed3d | ||
|
|
efb2ed933c | ||
|
|
2e94f7897c | ||
|
|
8ea4bad14d | ||
|
|
01f5becfb6 | ||
|
|
6e19a5c8ee | ||
|
|
c6d03a1a98 | ||
|
|
c32b08758a | ||
|
|
32f8fad362 | ||
|
|
abcb672d70 |
@@ -14,7 +14,10 @@ window.getModelsFromAiApi = getModels;
|
||||
|
||||
const systemDialog = require("./dialog/service");
|
||||
|
||||
const { getQuickcommandTempFile } = require("./getQuickcommandFile");
|
||||
const {
|
||||
getQuickcommandTempFile,
|
||||
getQuickcommandFolderFile,
|
||||
} = require("./getQuickcommandFile");
|
||||
|
||||
const createTerminalCommand = require("./createTerminalCommand");
|
||||
|
||||
@@ -153,18 +156,26 @@ const quickcommand = {
|
||||
},
|
||||
|
||||
// 载入在线资源
|
||||
loadRemoteScript: async function (url) {
|
||||
if (
|
||||
!/^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/.test(
|
||||
url
|
||||
)
|
||||
)
|
||||
throw "url 不合法";
|
||||
let local = getQuickcommandTempFile("js");
|
||||
await this.downloadFile(url, local);
|
||||
let source = require(local);
|
||||
fs.unlinkSync(local);
|
||||
return source;
|
||||
loadRemoteScript: async function (url, options) {
|
||||
const urlReg =
|
||||
/^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/;
|
||||
if (!urlReg.test(url)) throw "url 不合法";
|
||||
const { useCache = false } = options;
|
||||
if (useCache) {
|
||||
const urlHash = quickcomposer.coding.md5Hash(url);
|
||||
const fileName = path.basename(url, ".js") + "." + urlHash.slice(8, -8);
|
||||
const local = getQuickcommandFolderFile(fileName, "js");
|
||||
if (!fs.existsSync(local)) {
|
||||
await this.downloadFile(url, local);
|
||||
}
|
||||
return require(local);
|
||||
} else {
|
||||
const local = getQuickcommandTempFile("js");
|
||||
await this.downloadFile(url, local);
|
||||
let source = require(local);
|
||||
fs.unlinkSync(local);
|
||||
return source;
|
||||
}
|
||||
},
|
||||
|
||||
// 唤醒 uTools
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const fs = require("fs").promises;
|
||||
const fsSync = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
/**
|
||||
@@ -164,6 +165,240 @@ async function permission(config) {
|
||||
}
|
||||
}
|
||||
|
||||
async function mkdir(targetDir) {
|
||||
// 在 Windows 上,在根目录上使用 fs.mkdir() (即使使用递归参数)也会导致错误
|
||||
// 所以还是要先检查目录是否存在
|
||||
if (fsSync.existsSync(targetDir)) return;
|
||||
await fs.mkdir(targetDir, { recursive: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化速度显示
|
||||
* @param {number} bytesPerSecond 每秒字节数
|
||||
* @returns {string} 格式化后的速度字符串
|
||||
*/
|
||||
function formatSpeed(bytesPerSecond) {
|
||||
if (bytesPerSecond >= 1024 * 1024) {
|
||||
return `${(bytesPerSecond / (1024 * 1024)).toFixed(2)} MB/s`;
|
||||
} else if (bytesPerSecond >= 1024) {
|
||||
return `${(bytesPerSecond / 1024).toFixed(2)} KB/s`;
|
||||
}
|
||||
return `${bytesPerSecond.toFixed(2)} B/s`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取目录下所有文件的总大小和文件数
|
||||
* @param {string} dir 目录路径
|
||||
* @returns {Promise<{totalSize: number, fileCount: number}>}
|
||||
*/
|
||||
async function getDirStats(dir) {
|
||||
let totalSize = 0;
|
||||
let fileCount = 0;
|
||||
|
||||
async function walk(currentDir) {
|
||||
const entries = await fs.readdir(currentDir);
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(currentDir, entry);
|
||||
const stat = await fs.lstat(fullPath);
|
||||
if (stat.isDirectory()) {
|
||||
await walk(fullPath);
|
||||
} else {
|
||||
totalSize += stat.size;
|
||||
fileCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await walk(dir);
|
||||
return { totalSize, fileCount };
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用流复制文件,支持进度显示
|
||||
* @param {string} src 源文件路径
|
||||
* @param {string} dest 目标文件路径
|
||||
* @param {Object} progressInfo 进度信息
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function copyFileWithProgress(src, dest, progressInfo) {
|
||||
const {
|
||||
processBar,
|
||||
totalSize,
|
||||
fileCount,
|
||||
processedFiles,
|
||||
startTime,
|
||||
signal, // AbortController 的 signal
|
||||
} = progressInfo;
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
let currentCopiedSize = 0;
|
||||
let lastUpdate = Date.now();
|
||||
let lastCopiedSize = 0;
|
||||
|
||||
const readStream = fsSync.createReadStream(src);
|
||||
const writeStream = fsSync.createWriteStream(dest);
|
||||
|
||||
// 监听中止信号
|
||||
signal.addEventListener("abort", () => {
|
||||
readStream.destroy();
|
||||
writeStream.destroy();
|
||||
fs.unlink(dest).catch(() => {});
|
||||
reject(new Error("操作已取消"));
|
||||
});
|
||||
|
||||
readStream.on("data", (chunk) => {
|
||||
currentCopiedSize += chunk.length;
|
||||
progressInfo.copiedSize += chunk.length;
|
||||
const now = Date.now();
|
||||
|
||||
if (now - lastUpdate >= 100) {
|
||||
const progress = Math.round(
|
||||
(progressInfo.copiedSize / totalSize) * 100
|
||||
);
|
||||
const timeSpent = (now - lastUpdate) / 1000;
|
||||
const bytesCopied = currentCopiedSize - lastCopiedSize;
|
||||
const speed = bytesCopied / timeSpent;
|
||||
|
||||
quickcommand.updateProcessBar(
|
||||
{
|
||||
value: progress,
|
||||
text:
|
||||
`[${processedFiles}/${fileCount}][${formatBytes(
|
||||
progressInfo.copiedSize
|
||||
)}/${formatBytes(totalSize)}] ${formatSpeed(speed)}<br/>` +
|
||||
`${path.basename(src)}`,
|
||||
},
|
||||
processBar
|
||||
);
|
||||
|
||||
lastUpdate = now;
|
||||
lastCopiedSize = currentCopiedSize;
|
||||
}
|
||||
});
|
||||
|
||||
writeStream.on("finish", () => {
|
||||
progressInfo.processedFiles++;
|
||||
resolve();
|
||||
});
|
||||
|
||||
writeStream.on("error", reject);
|
||||
readStream.on("error", reject);
|
||||
|
||||
readStream.pipe(writeStream);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function copyDirWithProcess(src, dest, progressInfo) {
|
||||
await mkdir(dest);
|
||||
const entries = await fs.readdir(src);
|
||||
|
||||
for (const entry of entries) {
|
||||
// 检查是否已中止
|
||||
if (progressInfo.signal.aborted) {
|
||||
throw new Error("操作已取消");
|
||||
}
|
||||
|
||||
const srcPath = path.join(src, entry);
|
||||
const destPath = path.join(dest, entry);
|
||||
const entryStat = await fs.lstat(srcPath);
|
||||
|
||||
if (entryStat.isDirectory()) {
|
||||
await copyDirWithProcess(srcPath, destPath, progressInfo);
|
||||
} else {
|
||||
await copyFileWithProgress(srcPath, destPath, progressInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copy(filePath, newPath) {
|
||||
const controller = new AbortController();
|
||||
let isCompleted = false; // 添加完成标志
|
||||
|
||||
const processBar = await quickcommand.showProcessBar({
|
||||
text: "正在计算文件大小...",
|
||||
value: 0,
|
||||
onClose: () => {
|
||||
// 只有在未完成时才触发取消
|
||||
if (!isCompleted) {
|
||||
controller.abort();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
let totalSize = 0;
|
||||
let fileCount = 0;
|
||||
const stat = await fs.stat(filePath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
const stats = await getDirStats(filePath);
|
||||
totalSize = stats.totalSize;
|
||||
fileCount = stats.fileCount;
|
||||
} else {
|
||||
totalSize = stat.size;
|
||||
fileCount = 1;
|
||||
}
|
||||
|
||||
const progressInfo = {
|
||||
processBar,
|
||||
totalSize,
|
||||
copiedSize: 0,
|
||||
fileCount,
|
||||
processedFiles: 0,
|
||||
startTime: Date.now(),
|
||||
signal: controller.signal,
|
||||
};
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
await copyDirWithProcess(filePath, newPath, progressInfo);
|
||||
} else {
|
||||
await copyFileWithProgress(filePath, newPath, progressInfo);
|
||||
}
|
||||
|
||||
const totalTime = (Date.now() - progressInfo.startTime) / 1000;
|
||||
const averageSpeed = totalSize / totalTime;
|
||||
|
||||
isCompleted = true; // 标记为已完成
|
||||
quickcommand.updateProcessBar(
|
||||
{
|
||||
value: 100,
|
||||
text:
|
||||
`总大小: ${formatBytes(totalSize)} - 文件数: ${fileCount} <br/>` +
|
||||
`平均速度: ${formatSpeed(averageSpeed)} - 用时: ${totalTime.toFixed(
|
||||
1
|
||||
)}s`,
|
||||
complete: true,
|
||||
},
|
||||
processBar
|
||||
);
|
||||
} catch (error) {
|
||||
if (error.message === "操作已取消") {
|
||||
// 清理目标文件/目录
|
||||
fs.rm(newPath, { recursive: true }).catch(() => {});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function move(filePath, newPath) {
|
||||
try {
|
||||
// rename 不支持跨驱动器
|
||||
await fs.rename(filePath, newPath);
|
||||
} catch (error) {
|
||||
try {
|
||||
await copy(filePath, newPath);
|
||||
if (!fsSync.existsSync(newPath)) return;
|
||||
await fs.rm(filePath, { recursive: true });
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件复制移动操作
|
||||
*/
|
||||
@@ -171,53 +406,15 @@ async function transfer(config) {
|
||||
const { filePath, transferOperation, newPath } = config;
|
||||
|
||||
// 检查文件是否存在
|
||||
try {
|
||||
const stats = await fs.lstat(filePath);
|
||||
|
||||
// 确保目标目录存在
|
||||
await fs.mkdir(path.dirname(newPath), { recursive: true });
|
||||
if (transferOperation === "copy") {
|
||||
const processBar = await quickcommand.showProcessBar({
|
||||
text: "复制中...",
|
||||
});
|
||||
if (stats.isDirectory()) {
|
||||
// 复制目录
|
||||
const copyDir = async (src, dest) => {
|
||||
await fs.mkdir(dest, { recursive: true });
|
||||
const entries = await fs.readdir(src);
|
||||
for (const entry of entries) {
|
||||
const srcPath = path.join(src, entry);
|
||||
const destPath = path.join(dest, entry);
|
||||
const entryStat = await fs.lstat(srcPath);
|
||||
if (entryStat.isDirectory()) {
|
||||
await copyDir(srcPath, destPath);
|
||||
} else {
|
||||
await fs.copyFile(srcPath, destPath);
|
||||
}
|
||||
quickcommand.updateProcessBar({ text: entry }, processBar);
|
||||
}
|
||||
};
|
||||
await copyDir(filePath, newPath);
|
||||
} else {
|
||||
// 复制文件
|
||||
await fs.copyFile(filePath, newPath);
|
||||
}
|
||||
processBar.close();
|
||||
} else if (transferOperation === "rename") {
|
||||
const processBar = await quickcommand.showProcessBar({
|
||||
text: "处理中...",
|
||||
});
|
||||
await fs.rename(filePath, newPath);
|
||||
processBar.close();
|
||||
} else {
|
||||
throw new Error(`不支持的操作类型: ${transferOperation}`);
|
||||
}
|
||||
} catch (error) {
|
||||
processBar?.close();
|
||||
if (error.code === "ENOENT") {
|
||||
throw new Error("文件或目录不存在");
|
||||
}
|
||||
throw error;
|
||||
if (!fsSync.existsSync(filePath)) throw "文件或目录不存在!";
|
||||
// 确保目标目录存在
|
||||
await mkdir(path.dirname(newPath));
|
||||
if (transferOperation === "copy") {
|
||||
await copy(filePath, newPath);
|
||||
} else if (transferOperation === "rename") {
|
||||
await move(filePath, newPath);
|
||||
} else {
|
||||
throw new Error(`不支持的操作类型: ${transferOperation}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ export default defineComponent({
|
||||
const specificInstructions = languageSpecific[language] || "";
|
||||
|
||||
const lastInstructions =
|
||||
"\n请直接给我MARKDOWN格式的代码,任何情况下都不需要做解释和说明";
|
||||
"\n请直接给我MARKDOWN格式的代码(以```脚本语言开头,以```结尾),任何情况下都不需要做解释和说明";
|
||||
|
||||
return commonInstructions + specificInstructions + lastInstructions;
|
||||
},
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
dense
|
||||
v-model="aiConfig.apiToken"
|
||||
v-if="aiConfig.apiType === 'openai'"
|
||||
type="password"
|
||||
:type="tokenInputTypes[index] || 'password'"
|
||||
class="col-7"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
@@ -141,6 +141,22 @@
|
||||
class="q-pa-xs"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:append>
|
||||
<q-icon
|
||||
name="visibility_off"
|
||||
@click="tokenInputTypes[index] = 'password'"
|
||||
size="16px"
|
||||
class="cursor-pointer"
|
||||
v-if="tokenInputTypes[index] === 'text'"
|
||||
/>
|
||||
<q-icon
|
||||
name="visibility"
|
||||
@click="tokenInputTypes[index] = 'text'"
|
||||
size="16px"
|
||||
class="cursor-pointer"
|
||||
v-else
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,6 +196,7 @@ export default defineComponent({
|
||||
apiToAdd: "openai",
|
||||
aiConfigs: [],
|
||||
models: [],
|
||||
tokenInputTypes: [],
|
||||
};
|
||||
},
|
||||
emits: ["save"],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="composer-flow">
|
||||
<ChainStyles ref="chainStyles" :commands="commands" />
|
||||
|
||||
<q-scroll-area class="command-scroll">
|
||||
<q-scroll-area class="command-scroll" ref="scrollArea">
|
||||
<div
|
||||
class="command-flow-container"
|
||||
@dragover.prevent="onDragOver"
|
||||
@@ -541,6 +541,12 @@ export default defineComponent({
|
||||
this.$emit("update:modelValue", newCommands);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 当高度超过1000时,会出现非预期的自动滚动,暂时找不到原因,先强制滚动到顶部
|
||||
this.$nextTick(() => {
|
||||
this.$refs.scrollArea.setScrollPosition("vertical", 0);
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -117,9 +117,7 @@ export default defineComponent({
|
||||
...category,
|
||||
commands: this.commands
|
||||
.filter(
|
||||
(cmd) =>
|
||||
(cmd.label && window.pinyinMatch.match(cmd.label, query)) ||
|
||||
(cmd.value && window.pinyinMatch.match(cmd.value, query))
|
||||
(cmd) => cmd.label && window.pinyinMatch.match(cmd.label, query)
|
||||
)
|
||||
.filter((cmd) => cmd.type === category.label),
|
||||
}))
|
||||
|
||||
@@ -323,7 +323,7 @@ export default defineComponent({
|
||||
},
|
||||
computed: {
|
||||
showCommandConfig() {
|
||||
return !this.isRunComposerPage && this.commandConfig.features;
|
||||
return !this.isRunComposerPage && !!this.commandConfig.features;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -590,14 +590,23 @@ export default defineComponent({
|
||||
.flow-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.command-config-panel {
|
||||
flex-shrink: 0;
|
||||
padding: 8px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.flow-wrapper {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.variable-panel {
|
||||
@@ -624,8 +633,4 @@ export default defineComponent({
|
||||
border-bottom: 2px solid var(--q-primary);
|
||||
transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
|
||||
.command-config-panel {
|
||||
padding: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import { defineComponent } from "vue";
|
||||
import OperationCard from "components/composer/common/OperationCard.vue";
|
||||
import ParamInput from "components/composer/param/ParamInput.vue";
|
||||
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
import {
|
||||
newVarInputVal,
|
||||
isVarInputVal,
|
||||
@@ -68,7 +68,7 @@ export default defineComponent({
|
||||
},
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
hasSubCommands() {
|
||||
@@ -143,42 +143,6 @@ export default defineComponent({
|
||||
|
||||
return `${subCommand}(${finalArgvs.join(",")})`;
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
let argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
|
||||
if (this.localCommand.isExpression) {
|
||||
return [code];
|
||||
}
|
||||
|
||||
const variableFormatPaths = [];
|
||||
|
||||
const addVariableFormatPath = (prefix, config) => {
|
||||
if (config.component === "VariableInput") {
|
||||
variableFormatPaths.push(prefix);
|
||||
} else if (config.component === "ArrayEditor") {
|
||||
variableFormatPaths.push(`${prefix}[*].**`, `${prefix}[*]`);
|
||||
} else if (config.component === "DictEditor") {
|
||||
variableFormatPaths.push(`${prefix}.**`);
|
||||
}
|
||||
};
|
||||
|
||||
this.localConfig.forEach((item, index) => {
|
||||
if (item.component === "OptionEditor") {
|
||||
Object.entries(item.options).forEach(([key, config]) => {
|
||||
addVariableFormatPath(`arg${index}.${key}`, config);
|
||||
});
|
||||
} else {
|
||||
addVariableFormatPath(`arg${index}`, item);
|
||||
}
|
||||
});
|
||||
try {
|
||||
argvs = parseFunction(code, { variableFormatPaths }).argvs;
|
||||
} catch (e) {
|
||||
console.log("解析参数失败:", e);
|
||||
}
|
||||
return argvs;
|
||||
},
|
||||
getAllInputValues(argvs) {
|
||||
const flatArgvs = [];
|
||||
if (!argvs) return flatArgvs;
|
||||
@@ -237,9 +201,8 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code && Array.isArray(argvs)) {
|
||||
this.updateModelValue(this.subCommand, argvs);
|
||||
if (Array.isArray(this.argvs)) {
|
||||
this.updateModelValue(this.subCommand, this.argvs);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ import { defineComponent } from "vue";
|
||||
import ButtonGroup from "components/composer/common/ButtonGroup.vue";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
import AISelector from "components/ai/AISelector.vue";
|
||||
export default defineComponent({
|
||||
name: "AskAIEditor",
|
||||
@@ -69,30 +69,18 @@ export default defineComponent({
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
try {
|
||||
const variableFormatPaths = ["arg0.prompt"];
|
||||
const params = parseFunction(code, { variableFormatPaths });
|
||||
return params;
|
||||
} catch (e) {
|
||||
console.error("解析参数失败:", e);
|
||||
}
|
||||
return argvs;
|
||||
},
|
||||
generateCode(argvs = this.argvs) {
|
||||
return `${this.modelValue.value}(${stringifyArgv(
|
||||
argvs.content
|
||||
)}, ${JSON.stringify(argvs.apiConfig)})`;
|
||||
},
|
||||
getSummary(argvs) {
|
||||
return "问AI:" + argvs.content.prompt;
|
||||
return "问AI:" + stringifyArgv(argvs.content.prompt);
|
||||
},
|
||||
updateArgvs(keyPath, newValue) {
|
||||
const newArgvs = { ...this.argvs };
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
<q-icon name="linear_scale" size="xs" />
|
||||
</div>
|
||||
<div v-else class="chain-icon">
|
||||
<q-icon name="fork_left" size="xs" />
|
||||
<q-icon :name="getChianIcon()" size="xs" />
|
||||
</div>
|
||||
|
||||
<!-- 标题 -->
|
||||
<div class="command-label">
|
||||
<div class="command-label" v-if="!isControlFlow">
|
||||
<div class="drag-handle text-subtitle2 command-label-text">
|
||||
{{ command.label }}
|
||||
</div>
|
||||
<div
|
||||
v-if="isCollapsed && !isControlFlow"
|
||||
v-if="isCollapsed"
|
||||
class="summary-container"
|
||||
@click.stop="isEditingSummary = true"
|
||||
>
|
||||
@@ -78,6 +78,8 @@
|
||||
@update:outputVariable="$emit('update:outputVariable', $event)"
|
||||
@run="$emit('run')"
|
||||
@remove="$emit('remove')"
|
||||
@add-print="$emit('add-print')"
|
||||
@copy="$emit('copy')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -107,6 +109,8 @@ export default {
|
||||
"run",
|
||||
"remove",
|
||||
"toggle-collapse",
|
||||
"copy",
|
||||
"add-print",
|
||||
],
|
||||
computed: {
|
||||
contentClass() {
|
||||
@@ -135,6 +139,15 @@ export default {
|
||||
return this.command.userComments || this.command.summary;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getChianIcon() {
|
||||
return (
|
||||
this.command?.subCommands?.find(
|
||||
(command) => command.value === this.command.commandType
|
||||
)?.icon || "fork_left"
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -143,6 +156,7 @@ export default {
|
||||
.chain-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 2px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
@@ -162,15 +176,18 @@ export default {
|
||||
.command-label {
|
||||
user-select: none;
|
||||
pointer-events: all;
|
||||
cursor: grab;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.command-label:hover {
|
||||
.command-label-text {
|
||||
cursor: grab;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.command-label-text:hover {
|
||||
color: var(--q-primary);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
export default defineComponent({
|
||||
name: "AsymmetricCryptoEditor",
|
||||
@@ -224,7 +224,7 @@ export default defineComponent({
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
algorithms() {
|
||||
@@ -261,18 +261,6 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
try {
|
||||
const variableFormatPaths = ["arg0.text"];
|
||||
const params = parseFunction(code, { variableFormatPaths });
|
||||
return params.argvs[0];
|
||||
} catch (e) {
|
||||
console.error("解析加密参数失败:", e);
|
||||
}
|
||||
return argvs;
|
||||
},
|
||||
generateCode(argvs = this.argvs) {
|
||||
return `${this.modelValue.value}(${stringifyArgv({
|
||||
text: argvs.text,
|
||||
@@ -321,10 +309,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
|
||||
export default defineComponent({
|
||||
@@ -226,7 +226,7 @@ export default defineComponent({
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
keyCodecs() {
|
||||
@@ -324,18 +324,6 @@ export default defineComponent({
|
||||
|
||||
this.updateModelValue(argvs);
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
try {
|
||||
const variableFormatPaths = ["arg0.text"];
|
||||
const params = parseFunction(code, { variableFormatPaths });
|
||||
return params.argvs[0];
|
||||
} catch (e) {
|
||||
console.error("解析加密参数失败:", e);
|
||||
}
|
||||
return argvs;
|
||||
},
|
||||
getSummary(argvs) {
|
||||
const text = window.lodashM.truncate(argvs.text.value, {
|
||||
length: 30,
|
||||
@@ -355,10 +343,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="control-command-wrapper">
|
||||
<div class="control-command">
|
||||
<!-- 类型标签 -->
|
||||
<div class="control-type-label">
|
||||
<div class="control-type-label drag-handle">
|
||||
{{ currentFunction?.label || modelValue.commandType }}
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
no-icon-animation
|
||||
class="control-btn"
|
||||
>
|
||||
<q-list>
|
||||
<q-list dense>
|
||||
<q-item
|
||||
v-for="func in branchOptions"
|
||||
:key="func.value"
|
||||
@@ -87,7 +87,7 @@ export default defineComponent({
|
||||
},
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -123,44 +123,7 @@ export default defineComponent({
|
||||
|
||||
return code;
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
if (!code) return this.defaultArgvs;
|
||||
if (!this.currentFunction?.codeTemplate) return {};
|
||||
|
||||
const template = this.currentFunction.codeTemplate;
|
||||
const argvs = {};
|
||||
|
||||
// 如果没有变量模板,直接返回空对象
|
||||
if (!template.includes("${")) return {};
|
||||
|
||||
// 将模板转换为正则表达式
|
||||
const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
let pattern = escapeRegExp(template);
|
||||
|
||||
// 收集所有变量名
|
||||
const variables = [];
|
||||
const variablePattern = /\${(\w+)}/g;
|
||||
let match;
|
||||
|
||||
while ((match = variablePattern.exec(template)) !== null) {
|
||||
variables.push(match[1]);
|
||||
pattern = pattern.replace(escapeRegExp(`\${${match[1]}}`), "([^}]*?)");
|
||||
}
|
||||
|
||||
// 创建正则表达式并匹配代码
|
||||
const regex = new RegExp(`^${pattern}$`);
|
||||
const matches = code.match(regex);
|
||||
|
||||
if (matches) {
|
||||
// 从第二个元素开始,依次赋值给变量
|
||||
variables.forEach((variable, index) => {
|
||||
argvs[variable] = matches[index + 1] || "";
|
||||
});
|
||||
return argvs;
|
||||
}
|
||||
|
||||
return this.defaultArgvs;
|
||||
},
|
||||
updateModelValue(argvs) {
|
||||
const code = this.generateCode(argvs);
|
||||
|
||||
@@ -180,9 +143,7 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(this.defaultArgvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -207,6 +168,12 @@ export default defineComponent({
|
||||
opacity: 0.9;
|
||||
user-select: none;
|
||||
flex-shrink: 0;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.control-type-label:hover {
|
||||
color: var(--q-primary) !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.control-settings {
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import NumberInput from "components/composer/common/NumberInput.vue";
|
||||
import OperationCard from "components/composer/common/OperationCard.vue";
|
||||
@@ -208,10 +208,7 @@ export default defineComponent({
|
||||
argvs: {
|
||||
get() {
|
||||
return (
|
||||
this.modelValue.argvs ||
|
||||
this.parseCodeToArgvs(this.modelValue.code) || {
|
||||
...this.defaultArgvs,
|
||||
}
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
set(value) {
|
||||
@@ -234,49 +231,6 @@ export default defineComponent({
|
||||
argvs.data
|
||||
)}, "${argvs.method}", ${stringifyArgv(options)})`;
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
if (!code) return null;
|
||||
|
||||
try {
|
||||
// 定义需要使用variable格式的路径
|
||||
const variableFormatPaths = [
|
||||
"arg0", // 数据参数
|
||||
];
|
||||
|
||||
// 使用 parseFunction 解析代码
|
||||
const result = parseFunction(code, { variableFormatPaths });
|
||||
if (!result) return this.defaultArgvs;
|
||||
|
||||
const operation = result.name.split(".").pop();
|
||||
const [data, method, options] = result.argvs;
|
||||
|
||||
const newArgvs = {
|
||||
...this.defaultArgvs,
|
||||
operation,
|
||||
data,
|
||||
method: method?.value || "gzip",
|
||||
};
|
||||
|
||||
if (options) {
|
||||
if (method?.value === "brotli") {
|
||||
newArgvs.options = {
|
||||
params: options.params || this.defaultArgvs.options.params,
|
||||
};
|
||||
} else {
|
||||
newArgvs.options = {
|
||||
level: options.level ?? this.defaultArgvs.options.level,
|
||||
memLevel: options.memLevel ?? this.defaultArgvs.options.memLevel,
|
||||
strategy: options.strategy ?? this.defaultArgvs.options.strategy,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return newArgvs;
|
||||
} catch (e) {
|
||||
console.error("解析Zlib参数失败:", e);
|
||||
return this.defaultArgvs;
|
||||
}
|
||||
},
|
||||
updateArgvs(key, value) {
|
||||
this.argvs = {
|
||||
...this.argvs,
|
||||
@@ -300,10 +254,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -97,7 +97,6 @@ import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import RegexInput from "./RegexInput.vue";
|
||||
import RegexBuilder from "./RegexBuilder.vue";
|
||||
import RegexTester from "./RegexTester.vue";
|
||||
import { parseToHasType } from "js/composer/formatString";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
|
||||
export default defineComponent({
|
||||
@@ -141,7 +140,7 @@ export default defineComponent({
|
||||
},
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -230,31 +229,6 @@ export default defineComponent({
|
||||
this.updateArgvs("regexValue", newContent);
|
||||
}
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
const match = code.match(/^.*?\((.*)\)$/);
|
||||
if (!match) return argvs;
|
||||
const params = match[1];
|
||||
const parts = params.split(",");
|
||||
const text = parts[0];
|
||||
const regexPart = parts[1];
|
||||
const replace = parts[2];
|
||||
if (regexPart) {
|
||||
const [_, pattern, flags] = regexPart.match(/\/(.*?)\/(.*)/) || [];
|
||||
return {
|
||||
textValue: parseToHasType(text),
|
||||
regexValue: pattern,
|
||||
replaceValue: parseToHasType(replace),
|
||||
flags: {
|
||||
ignoreCase: flags.includes("i"),
|
||||
multiline: flags.includes("m"),
|
||||
global: flags.includes("g"),
|
||||
},
|
||||
isReplace: !!replace,
|
||||
};
|
||||
}
|
||||
},
|
||||
getSummary(argvs) {
|
||||
return argvs.isReplace
|
||||
? argvs.textValue.value +
|
||||
@@ -274,10 +248,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -240,8 +240,16 @@
|
||||
<VariableInput
|
||||
:model-value="argvs.newPath"
|
||||
@update:model-value="updateArgvs('newPath', $event)"
|
||||
label="目标路径"
|
||||
label="目标路径(含被复制/移动的文件名)"
|
||||
icon="drive_file_rename_outline"
|
||||
:options="{
|
||||
dialog: {
|
||||
options: {
|
||||
title: '选择文件',
|
||||
properties: ['openFile', 'showHiddenFiles'],
|
||||
},
|
||||
},
|
||||
}"
|
||||
class="col-6"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import { defineComponent } from "vue";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ReturnEditor",
|
||||
@@ -34,32 +34,15 @@ export default defineComponent({
|
||||
},
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
);
|
||||
return this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
code = code.trim().replace(/^return\s(.*)/, "tempFunc($1)");
|
||||
try {
|
||||
const variableFormatPaths = ["arg0"];
|
||||
const params = parseFunction(code, { variableFormatPaths });
|
||||
return {
|
||||
returnValue: params.argvs[0],
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("解析参数失败:", e);
|
||||
}
|
||||
return argvs;
|
||||
},
|
||||
generateCode(argvs = this.argvs) {
|
||||
return `${this.modelValue.value} ${stringifyArgv(argvs.returnValue)}`;
|
||||
},
|
||||
getSummary(argvs) {
|
||||
return "返回" + " " + argvs.returnValue.value;
|
||||
return "返回" + " " + stringifyArgv(argvs.returnValue);
|
||||
},
|
||||
updateArgvs(key, newValue) {
|
||||
this.argvs[key] = newValue;
|
||||
@@ -75,10 +58,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -156,7 +156,7 @@ import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import ArrayEditor from "components/composer/common/ArrayEditor.vue";
|
||||
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||
import CheckButton from "components/composer/common/CheckButton.vue";
|
||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
import programs from "js/options/programs";
|
||||
import VariableList from "components/composer/common/varinput/VariableList.vue";
|
||||
|
||||
@@ -197,9 +197,7 @@ export default defineComponent({
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs ||
|
||||
this.parseCodeToArgvs(this.modelValue.code) ||
|
||||
this.defaultArgvs
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
isCodeSnippet() {
|
||||
@@ -211,29 +209,6 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
parseCodeToArgvs(code) {
|
||||
if (!code) return this.defaultArgvs;
|
||||
if (this.isCodeSnippet) {
|
||||
const result = parseFunction(code);
|
||||
return {
|
||||
code: quickcomposer.coding.base64Decode(result.argvs?.[0]),
|
||||
};
|
||||
}
|
||||
try {
|
||||
const variableFormatPaths = ["arg1.args[*]"];
|
||||
const result = parseFunction(code, { variableFormatPaths });
|
||||
if (!result) return this.defaultArgvs;
|
||||
|
||||
const [scriptCode, options] = result.argvs;
|
||||
return {
|
||||
code: scriptCode,
|
||||
...options,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("解析参数失败:", e);
|
||||
return this.defaultArgvs;
|
||||
}
|
||||
},
|
||||
generateCode(argvs = this.argvs) {
|
||||
const variables = argvs.code.match(/"?___([^_]+?)___"?/g);
|
||||
const replaceStr =
|
||||
@@ -317,10 +292,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -132,7 +132,7 @@ export default defineComponent({
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -208,35 +208,6 @@ export default defineComponent({
|
||||
return `${this.modelValue.value}("data:image/png;base64,${config.imageData}", { threshold: ${config.threshold}, mouseAction: "${config.mouseAction}" })`;
|
||||
},
|
||||
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
|
||||
// 从代码字符串解析配置
|
||||
try {
|
||||
const imageDataMatch = code.match(/"data:image\/png;base64,([^"]+)"/);
|
||||
const thresholdMatch = code.match(/threshold:\s*([\d.]+)/);
|
||||
const mouseActionMatch = code.match(/mouseAction:\s*"([^"]+)"/);
|
||||
let { imagePreview, threshold, mouseAction } = argvs;
|
||||
|
||||
if (imageDataMatch) {
|
||||
imagePreview = `data:image/png;base64,${imageDataMatch[1]}`;
|
||||
}
|
||||
if (thresholdMatch) {
|
||||
threshold = parseFloat(thresholdMatch[1]);
|
||||
}
|
||||
if (mouseActionMatch) {
|
||||
mouseAction = mouseActionMatch[1];
|
||||
}
|
||||
return {
|
||||
imagePreview,
|
||||
threshold,
|
||||
mouseAction,
|
||||
};
|
||||
} catch (e) {
|
||||
return argvs;
|
||||
}
|
||||
},
|
||||
updateModelValue(argvs) {
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
@@ -246,10 +217,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -150,7 +150,6 @@
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import NumberInput from "components/composer/common/NumberInput.vue";
|
||||
import { parseFunction } from "js/composer/formatString";
|
||||
|
||||
// 检测操作系统
|
||||
const isMac = window.utools.isMacOs();
|
||||
@@ -438,7 +437,7 @@ export default defineComponent({
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
mainKeyDisplay() {
|
||||
@@ -622,44 +621,7 @@ export default defineComponent({
|
||||
...this.argvs,
|
||||
...argv,
|
||||
};
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
argvs: newArgvs,
|
||||
code: this.generateCode(newArgvs),
|
||||
});
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
try {
|
||||
const result = parseFunction(code);
|
||||
if (!result || !result.argvs || !result.argvs[0]) return argvs;
|
||||
|
||||
const keys = result.argvs[0];
|
||||
const options = result.argvs[1] || {};
|
||||
|
||||
if (keys.length > 0) {
|
||||
argvs.mainKey = keys[0];
|
||||
Object.keys(argvs.modifiers).forEach((key) => {
|
||||
// 在非 Mac 系统上,将 meta 转换为 command
|
||||
const modKey = !isMac && key === "command" ? "meta" : key;
|
||||
argvs.modifiers[key] = keys.slice(1).includes(modKey);
|
||||
});
|
||||
}
|
||||
|
||||
// 解析选项对象
|
||||
if (options) {
|
||||
if (options.repeatCount) argvs.repeatCount = options.repeatCount;
|
||||
if (options.repeatInterval)
|
||||
argvs.repeatInterval = options.repeatInterval;
|
||||
if (options.keyDelay) argvs.keyDelay = options.keyDelay;
|
||||
}
|
||||
|
||||
return argvs;
|
||||
} catch (e) {
|
||||
console.error("Failed to parse key string:", e);
|
||||
return argvs;
|
||||
}
|
||||
this.updateModelValue(newArgvs);
|
||||
},
|
||||
handleKeyInput(val) {
|
||||
let newMainKey;
|
||||
@@ -703,16 +665,24 @@ export default defineComponent({
|
||||
.join(" + ");
|
||||
return `${modifiers} + ${shortcut.mainKey}`;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
getSummary(argvs) {
|
||||
const modifiers = Object.entries(argvs.modifiers)
|
||||
.filter(([_, active]) => active)
|
||||
.map(([key]) => this.modifierLabels[key])
|
||||
.join(" + ");
|
||||
return modifiers ? `${modifiers} + ${argvs.mainKey}` : argvs.mainKey;
|
||||
},
|
||||
updateModelValue(argvs) {
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
argvs,
|
||||
argvs: argvs,
|
||||
code: this.generateCode(argvs),
|
||||
summary: this.getSummary(argvs),
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -459,7 +459,7 @@ export default defineComponent({
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -608,15 +608,26 @@ export default defineComponent({
|
||||
}
|
||||
return `${this.modelValue.value}(${JSON.stringify(keySequence)})`;
|
||||
},
|
||||
updateValue(newArgvs) {
|
||||
updateValue(newArgvs = this.argvs) {
|
||||
const updatedModelValue = {
|
||||
...this.modelValue,
|
||||
argvs: newArgvs || this.argvs,
|
||||
code: this.generateCode(newArgvs || this.argvs),
|
||||
argvs: newArgvs,
|
||||
code: this.generateCode(newArgvs),
|
||||
summary: this.getSummary(newArgvs),
|
||||
};
|
||||
|
||||
this.$emit("update:modelValue", updatedModelValue);
|
||||
},
|
||||
getSingleSummary(item) {
|
||||
const modifiers = Object.entries(item.modifiers)
|
||||
.filter(([_, active]) => active)
|
||||
.map(([key]) => this.modifierLabels[key])
|
||||
.join(" + ");
|
||||
return modifiers ? `${modifiers} + ${item.mainKey}` : item.mainKey;
|
||||
},
|
||||
getSummary(argvs) {
|
||||
return argvs.sequence.map(this.getSingleSummary).join("; ");
|
||||
},
|
||||
appendSequence(newSequence) {
|
||||
const startId = Date.now();
|
||||
this.argvs.sequence.push(
|
||||
@@ -627,37 +638,6 @@ export default defineComponent({
|
||||
);
|
||||
this.updateValue();
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
const argvs = window.lodashM.cloneDeep(this.defaultArgvs);
|
||||
if (!code) return argvs;
|
||||
try {
|
||||
const match = code.match(/\((.*)\)/s);
|
||||
if (match) {
|
||||
const args = eval(`[${match[1]}]`);
|
||||
if (Array.isArray(args[0])) {
|
||||
argvs.sequence = args[0].map((keys) => {
|
||||
const mainKey = keys[0];
|
||||
const modifiers = {
|
||||
control: keys.includes("control"),
|
||||
alt: keys.includes("alt"),
|
||||
shift: keys.includes("shift"),
|
||||
command:
|
||||
!isMac && keys.includes("meta")
|
||||
? true
|
||||
: keys.includes("command"),
|
||||
};
|
||||
return { mainKey, modifiers, id: Date.now() + Math.random() };
|
||||
});
|
||||
if (args[1] && args[1].interval) {
|
||||
argvs.interval = args[1].interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to parse existing code:", e);
|
||||
}
|
||||
return argvs;
|
||||
},
|
||||
toggleModifier(index, key) {
|
||||
// 创建新的 argvs 对象
|
||||
const newArgvs = {
|
||||
@@ -678,10 +658,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateValue(argvs);
|
||||
}
|
||||
this.updateValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import NumberInput from "components/composer/common/NumberInput.vue";
|
||||
@@ -182,9 +182,7 @@ export default defineComponent({
|
||||
argvs: {
|
||||
get() {
|
||||
return (
|
||||
this.modelValue.argvs ||
|
||||
this.parseCodeToArgvs(this.modelValue.code) ||
|
||||
this.defaultArgvs
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
set(value) {
|
||||
@@ -193,32 +191,6 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
parseCodeToArgvs(code) {
|
||||
if (!code) return null;
|
||||
|
||||
// 定义需要使用variable格式的路径
|
||||
const variableFormatPaths = [
|
||||
"arg0", // 命令字符串
|
||||
"arg1.cwd", // 工作目录
|
||||
"arg1.env.**", // 环境变量
|
||||
];
|
||||
|
||||
// 解析代码
|
||||
const result = parseFunction(code, { variableFormatPaths });
|
||||
if (!result) return this.defaultArgvs;
|
||||
|
||||
// 返回解析结果
|
||||
const [command, options = {}] = result.argvs;
|
||||
return {
|
||||
command: command || this.defaultArgvs.command,
|
||||
options: {
|
||||
...this.defaultArgvs.options,
|
||||
...options,
|
||||
cwd: options.cwd || this.defaultArgvs.options.cwd,
|
||||
env: options.env || this.defaultArgvs.options.env,
|
||||
},
|
||||
};
|
||||
},
|
||||
generateCode(argvs) {
|
||||
const args = [];
|
||||
|
||||
@@ -260,7 +232,7 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
getSummary(argvs) {
|
||||
return argvs.command.value;
|
||||
return stringifyArgv(argvs.command);
|
||||
},
|
||||
updateModelValue(argvs) {
|
||||
this.$emit("update:modelValue", {
|
||||
@@ -272,10 +244,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -50,6 +50,7 @@ import UBrowserBasic from "components/composer/ubrowser/UBrowserBasic.vue";
|
||||
import UBrowserOperations from "components/composer/ubrowser/UBrowserOperations.vue";
|
||||
import UBrowserRun from "components/composer/ubrowser/UBrowserRun.vue";
|
||||
import { generateUBrowserCode } from "js/composer/generateUBrowserCode";
|
||||
import { stringifyArgv } from "src/js/composer/formatString";
|
||||
|
||||
export default {
|
||||
name: "UBrowserEditor",
|
||||
@@ -83,7 +84,7 @@ export default {
|
||||
return this.modelValue.argvs || this.defaultArgvs;
|
||||
},
|
||||
summary() {
|
||||
const goto = this.argvs.goto?.url || "";
|
||||
const goto = stringifyArgv(this.argvs.goto?.url || "");
|
||||
return `访问 ${goto}`;
|
||||
},
|
||||
},
|
||||
@@ -112,9 +113,6 @@ export default {
|
||||
code: this.generateCode(),
|
||||
});
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
// TODO: 实现代码解析逻辑
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -152,8 +152,8 @@ import VariableInput from "components/composer/common/VariableInput.vue";
|
||||
import ArrayEditor from "components/composer/common/ArrayEditor.vue";
|
||||
import OperationCard from "components/composer/common/OperationCard.vue";
|
||||
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
||||
import { newVarInputVal, isVarInputVal } from "js/composer/varInputValManager";
|
||||
import { stringifyArgv } from "js/composer/formatString";
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
|
||||
const jsonDefaultSelects = new Array(3).fill().map((_, index) => ({
|
||||
id: newVarInputVal("var", index),
|
||||
@@ -235,7 +235,7 @@ export default defineComponent({
|
||||
computed: {
|
||||
argvs() {
|
||||
return (
|
||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
||||
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||
);
|
||||
},
|
||||
optionTypes() {
|
||||
@@ -310,32 +310,6 @@ export default defineComponent({
|
||||
Object.keys(options).length ? `, ${stringifyArgv(options)}` : ""
|
||||
})`;
|
||||
},
|
||||
parseCodeToArgvs(code) {
|
||||
if (!code) return this.defaultArgvs;
|
||||
|
||||
try {
|
||||
const result = parseFunction(code, {
|
||||
variableFormatPaths: ["arg0", "arg0[*]", "arg1.placeholder"],
|
||||
});
|
||||
|
||||
if (!result) return this.defaultArgvs;
|
||||
|
||||
const subCommand = result.name;
|
||||
|
||||
const [selects, options = {}] = result.argvs;
|
||||
const inputMode = isVarInputVal(selects) ? "variable" : "manual";
|
||||
return {
|
||||
...this.defaultArgvs,
|
||||
inputMode,
|
||||
selects,
|
||||
subCommand,
|
||||
...options,
|
||||
};
|
||||
} catch (e) {
|
||||
console.warn("选择列表参数解析失败:" + e, code);
|
||||
return this.defaultArgvs;
|
||||
}
|
||||
},
|
||||
getSummary(argvs) {
|
||||
const count = Array.isArray(argvs.selects) ? argvs.selects.length : "?";
|
||||
return `显示${count}个${
|
||||
@@ -390,10 +364,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
||||
if (!this.modelValue.code) {
|
||||
this.updateModelValue(argvs);
|
||||
}
|
||||
this.updateModelValue(this.argvs);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -87,9 +87,11 @@ export default {
|
||||
const savedTagOrder = dbManager.getDB(TAG_ORDER_KEY);
|
||||
if (savedTagOrder.length) {
|
||||
this.savedTagOrder = savedTagOrder;
|
||||
this.commandManager.changeCurrentTag(this.savedTagOrder[0]);
|
||||
} else {
|
||||
this.commandManager.changeCurrentTag(this.allQuickCommandTags[0]);
|
||||
}
|
||||
if (!this.commandManager.state.currentTag) {
|
||||
this.commandManager.changeCurrentTag(
|
||||
this.savedTagOrder[0] || this.allQuickCommandTags[0]
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
size="xs"
|
||||
label="插件会员"
|
||||
@click="showPayPage = true"
|
||||
><q-tooltip>2元解锁本插件所有会员特权</q-tooltip></q-btn
|
||||
><q-tooltip>{{ memberPrice }}元解锁本插件所有会员特权</q-tooltip></q-btn
|
||||
>
|
||||
</div>
|
||||
<q-separator vertical inset class="q-mx-lg" />
|
||||
|
||||
@@ -141,7 +141,7 @@ export default {
|
||||
* @param position 消息显示位置,默认为"top"
|
||||
*/
|
||||
showMessageBox: (message, icon = "success", time, position = "top") => {
|
||||
message = window.lodashM.truncate(message, { length: 1200 });
|
||||
message = window.lodashM.truncate(message.toString(), { length: 1200 });
|
||||
if (icon === "success") icon = "positive";
|
||||
if (icon === "error") icon = "negative";
|
||||
if (typeof time === "undefined")
|
||||
|
||||
@@ -23,16 +23,10 @@ export const controlCommands = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "否则",
|
||||
value: "else",
|
||||
icon: "fork_left",
|
||||
codeTemplate: "} else {",
|
||||
},
|
||||
{
|
||||
label: "否则满足",
|
||||
value: "else if",
|
||||
icon: "fork_left",
|
||||
icon: "fork_right",
|
||||
codeTemplate: "} else if (${condition}) {",
|
||||
config: [
|
||||
{
|
||||
@@ -43,6 +37,12 @@ export const controlCommands = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "否则",
|
||||
value: "else",
|
||||
icon: "airline_stops",
|
||||
codeTemplate: "} else {",
|
||||
},
|
||||
{
|
||||
label: "结束",
|
||||
value: "end",
|
||||
@@ -295,7 +295,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "匹配分支",
|
||||
value: "case",
|
||||
icon: "check",
|
||||
icon: "fork_right",
|
||||
codeTemplate: "case ${value}:",
|
||||
config: [
|
||||
{
|
||||
@@ -305,10 +305,16 @@ export const controlCommands = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "中断",
|
||||
value: "break",
|
||||
icon: "stop",
|
||||
codeTemplate: "break;",
|
||||
},
|
||||
{
|
||||
label: "默认分支",
|
||||
value: "default",
|
||||
icon: "last_page",
|
||||
icon: "airline_stops",
|
||||
codeTemplate: "default:",
|
||||
},
|
||||
{
|
||||
@@ -334,7 +340,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "捕获异常",
|
||||
value: "catch",
|
||||
icon: "error",
|
||||
icon: "priority_high",
|
||||
codeTemplate: "} catch (${errorVar}) {",
|
||||
config: [
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@ export const networkCommands = {
|
||||
label: "HTTP请求结果",
|
||||
suggestName: "responseResult",
|
||||
structure: {
|
||||
data: { label: "响应数据", suggestName: "responseData" },
|
||||
status: { label: "HTTP状态码", suggestName: "responseStatus" },
|
||||
statusText: {
|
||||
label: "HTTP状态信息",
|
||||
@@ -36,7 +37,6 @@ export const networkCommands = {
|
||||
headers: { label: "服务器响应头", suggestName: "responseHeaders" },
|
||||
config: { label: "请求配置信息", suggestName: "requestConfig" },
|
||||
request: { label: "发送的请求", suggestName: "request" },
|
||||
data: { label: "响应数据", suggestName: "responseData" },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -167,6 +167,8 @@ export default {
|
||||
},
|
||||
// 编辑命令
|
||||
editCommand(commandOrCode) {
|
||||
// 防止多次触发
|
||||
if (this.isEditorShow) return;
|
||||
// 即可传入 code,也可直接传入 command
|
||||
const command =
|
||||
typeof commandOrCode === "string"
|
||||
@@ -182,6 +184,8 @@ export default {
|
||||
},
|
||||
// 新建命令
|
||||
addNewCommand(program = "quickcommand") {
|
||||
// 防止多次触发
|
||||
if (this.isEditorShow) return;
|
||||
this.editorComponent =
|
||||
program === "quickcomposer" ? "ComposerEditor" : "CommandEditor";
|
||||
this.commandManager.state.currentCommand =
|
||||
|
||||
@@ -346,8 +346,10 @@ interface quickcommandApi {
|
||||
* ```
|
||||
*
|
||||
* @param url 脚本地址
|
||||
* @param options 选项
|
||||
* @param options.useCache 使用缓存,默认为假。为真时会将远程脚本缓存到本地的utools.getPath("userData")/quickcommand目录,否则每次都会下载脚本
|
||||
*/
|
||||
loadRemoteScript(url: string): Promise<object>;
|
||||
loadRemoteScript(url: string, options?: { useCache?: boolean }): Promise<object>;
|
||||
|
||||
/**
|
||||
* 将 signal 发送给 pid 标识的进程 , 默认为关闭进程
|
||||
|
||||
Reference in New Issue
Block a user