mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-08 22:51:25 +08:00
Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
724bd9e4e7 | ||
|
72abdf4524 | ||
|
b400bbb48d | ||
|
c2514e9f2d | ||
|
c32a5a4829 | ||
|
0d4f49fcf4 | ||
|
55516159ba | ||
|
d4e58e58be | ||
|
d1b117186f | ||
|
3fb17dcd99 | ||
|
ffbae3f33f | ||
|
a762b87d2b | ||
|
3d2d15e177 | ||
|
14769bb7e7 | ||
|
5d76d4d657 | ||
|
ebde8999bf | ||
|
31f0d66ebc | ||
|
c1f86c20d2 | ||
|
bbdc2c6d65 | ||
|
0979e5648c | ||
|
f9a22595be | ||
|
823a95079a | ||
|
39ee88b02a | ||
|
fcf3d5912e | ||
|
71375e2c86 | ||
|
34230fa140 | ||
|
f9e0c29c08 | ||
|
65936e7d0d | ||
|
1da46e8dc5 | ||
|
7f26c0f176 | ||
|
0ab029a5b3 | ||
|
4c2f835222 | ||
|
05402fed3d | ||
|
efb2ed933c | ||
|
2e94f7897c | ||
|
8ea4bad14d | ||
|
01f5becfb6 | ||
|
6e19a5c8ee | ||
|
c6d03a1a98 | ||
|
c32b08758a | ||
|
32f8fad362 | ||
|
abcb672d70 | ||
|
f61fe17c6a |
4
build.sh
Executable file
4
build.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
git pull
|
||||||
|
cd plugin && npm i && cd .. && npm i
|
||||||
|
quasar build
|
4
dev.sh
Executable file
4
dev.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
git pull
|
||||||
|
cd plugin && npm i && cd .. && npm i
|
||||||
|
quasar dev
|
144
plugin/lib/ai.js
144
plugin/lib/ai.js
@ -17,6 +17,7 @@ window.aiResponseParser = (content) => {
|
|||||||
const API_TYPES = {
|
const API_TYPES = {
|
||||||
OPENAI: "openai",
|
OPENAI: "openai",
|
||||||
OLLAMA: "ollama",
|
OLLAMA: "ollama",
|
||||||
|
UTOOLS: "utools",
|
||||||
};
|
};
|
||||||
|
|
||||||
// 角色提示词
|
// 角色提示词
|
||||||
@ -122,7 +123,7 @@ function buildRequestData(content, apiConfig) {
|
|||||||
const roleMessage = rolePrompt
|
const roleMessage = rolePrompt
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
role: "user",
|
role: "system",
|
||||||
content: rolePrompt,
|
content: rolePrompt,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -151,21 +152,6 @@ function buildRequestData(content, apiConfig) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理普通响应
|
|
||||||
function parseResponse(response, apiType) {
|
|
||||||
if (apiType === API_TYPES.OPENAI) {
|
|
||||||
if (!response.data.choices || !response.data.choices[0]) {
|
|
||||||
throw new Error("OpenAI 响应格式错误");
|
|
||||||
}
|
|
||||||
return response.data.choices[0].message.content;
|
|
||||||
} else {
|
|
||||||
if (!response.data.message) {
|
|
||||||
throw new Error("Ollama 响应格式错误");
|
|
||||||
}
|
|
||||||
return response.data.message.content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理模型列表响应
|
// 处理模型列表响应
|
||||||
function parseModelsResponse(response, apiType) {
|
function parseModelsResponse(response, apiType) {
|
||||||
if (apiType === API_TYPES.OPENAI) {
|
if (apiType === API_TYPES.OPENAI) {
|
||||||
@ -181,6 +167,24 @@ function parseModelsResponse(response, apiType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reasoning_content_start = false;
|
||||||
|
function processContentWithReason(response, onStream) {
|
||||||
|
if (response.reasoning_content) {
|
||||||
|
if (!reasoning_content_start) {
|
||||||
|
reasoning_content_start = true;
|
||||||
|
onStream("<think>", false);
|
||||||
|
}
|
||||||
|
onStream(response.reasoning_content, false);
|
||||||
|
}
|
||||||
|
if (response.content) {
|
||||||
|
if (reasoning_content_start) {
|
||||||
|
reasoning_content_start = false;
|
||||||
|
onStream("</think>", false);
|
||||||
|
}
|
||||||
|
onStream(response.content, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 处理 OpenAI 流式响应
|
// 处理 OpenAI 流式响应
|
||||||
async function handleOpenAIStreamResponse(line, onStream) {
|
async function handleOpenAIStreamResponse(line, onStream) {
|
||||||
if (line.startsWith("data:")) {
|
if (line.startsWith("data:")) {
|
||||||
@ -190,9 +194,9 @@ async function handleOpenAIStreamResponse(line, onStream) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const json = JSON.parse(jsonStr);
|
const json = JSON.parse(jsonStr);
|
||||||
const content = json.choices[0]?.delta?.content;
|
const response = json.choices[0]?.delta;
|
||||||
if (content) {
|
if (response) {
|
||||||
onStream(content, false);
|
processContentWithReason(response, onStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,13 +208,30 @@ async function handleOllamaStreamResponse(line, onStream) {
|
|||||||
onStream("", true);
|
onStream("", true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (json.message?.content) {
|
const response = json.message;
|
||||||
onStream(json.message.content, false);
|
if (response) {
|
||||||
|
processContentWithReason(response, onStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理 uTools AI 流式响应
|
||||||
|
async function handleUToolsAIStreamResponse(response, onStream) {
|
||||||
|
processContentWithReason(response, onStream);
|
||||||
|
}
|
||||||
|
|
||||||
// 处理流式响应
|
// 处理流式响应
|
||||||
async function handleStreamResponse(response, apiConfig, onStream) {
|
async function handleStreamResponse(response, apiConfig, onStream) {
|
||||||
|
// 处理 uTools AI 响应
|
||||||
|
if (apiConfig.apiType === API_TYPES.UTOOLS) {
|
||||||
|
try {
|
||||||
|
await handleUToolsAIStreamResponse(response, onStream);
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理其他 API 的流式响应
|
||||||
const reader = response.body.getReader();
|
const reader = response.body.getReader();
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
let buffer = "";
|
let buffer = "";
|
||||||
@ -283,24 +304,27 @@ async function chat(content, apiConfig, options = {}) {
|
|||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
// 验证必要参数
|
// 验证必要参数
|
||||||
if (!apiConfig.apiUrl || !content.prompt || !apiConfig.model) {
|
if (apiConfig.apiType === API_TYPES.UTOOLS) {
|
||||||
throw new Error("API地址、模型名称和提示词不能为空");
|
if (!content.prompt || !apiConfig.model) {
|
||||||
|
throw new Error("模型名称和提示词不能为空");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!apiConfig.apiUrl) {
|
||||||
|
throw new Error("API地址不能为空");
|
||||||
|
}
|
||||||
|
if (!apiConfig.apiUrl || !content.prompt || !apiConfig.model) {
|
||||||
|
throw new Error("API地址、模型名称和提示词不能为空");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建请求URL和配置
|
let controller;
|
||||||
const url = buildApiUrl(
|
|
||||||
apiConfig.apiUrl,
|
|
||||||
API_ENDPOINTS[apiConfig.apiType].chat
|
|
||||||
);
|
|
||||||
const config = buildRequestConfig(apiConfig);
|
|
||||||
const requestData = buildRequestData(content, apiConfig);
|
|
||||||
|
|
||||||
// 显示进度条
|
// 显示进度条
|
||||||
const processBar = showProcessBar
|
const processBar = showProcessBar
|
||||||
? await quickcommand.showProcessBar({
|
? await quickcommand.showProcessBar({
|
||||||
text: "AI思考中...",
|
text: "AI思考中...",
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
if (controller) {
|
if (typeof controller !== "undefined") {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -327,11 +351,65 @@ async function chat(content, apiConfig, options = {}) {
|
|||||||
onStream(chunk, isDone);
|
onStream(chunk, isDone);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 统一使用 fetch 处理请求
|
// 处理 uTools AI 请求
|
||||||
const controller = new AbortController();
|
if (apiConfig.apiType === API_TYPES.UTOOLS) {
|
||||||
|
try {
|
||||||
|
const messages = buildRequestData(content, apiConfig).messages;
|
||||||
|
controller = utools.ai(
|
||||||
|
{
|
||||||
|
model: apiConfig.model,
|
||||||
|
messages: messages,
|
||||||
|
},
|
||||||
|
(chunk) => {
|
||||||
|
handleUToolsAIStreamResponse(chunk, streamHandler);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
onFetch(controller);
|
||||||
|
|
||||||
|
await controller;
|
||||||
|
|
||||||
|
// 在流式响应完全结束后,发送一个空字符串表示结束
|
||||||
|
streamHandler("", true);
|
||||||
|
|
||||||
|
// 完成时更新进度条并关闭
|
||||||
|
if (processBar) {
|
||||||
|
quickcommand.updateProcessBar(
|
||||||
|
{
|
||||||
|
text: "AI响应完成",
|
||||||
|
complete: true,
|
||||||
|
},
|
||||||
|
processBar
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
result: fullResponse,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
if (error.name === "AbortError") {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "请求已取消",
|
||||||
|
cancelled: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一使用 fetch 处理其他 API 请求
|
||||||
|
controller = new AbortController();
|
||||||
|
|
||||||
onFetch(controller);
|
onFetch(controller);
|
||||||
|
|
||||||
|
const url = buildApiUrl(
|
||||||
|
apiConfig.apiUrl,
|
||||||
|
API_ENDPOINTS[apiConfig.apiType].chat
|
||||||
|
);
|
||||||
|
const config = buildRequestConfig(apiConfig);
|
||||||
|
const requestData = buildRequestData(content, apiConfig);
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: config.headers,
|
headers: config.headers,
|
||||||
|
@ -14,7 +14,10 @@ window.getModelsFromAiApi = getModels;
|
|||||||
|
|
||||||
const systemDialog = require("./dialog/service");
|
const systemDialog = require("./dialog/service");
|
||||||
|
|
||||||
const { getQuickcommandTempFile } = require("./getQuickcommandFile");
|
const {
|
||||||
|
getQuickcommandTempFile,
|
||||||
|
getQuickcommandFolderFile,
|
||||||
|
} = require("./getQuickcommandFile");
|
||||||
|
|
||||||
const createTerminalCommand = require("./createTerminalCommand");
|
const createTerminalCommand = require("./createTerminalCommand");
|
||||||
|
|
||||||
@ -153,18 +156,26 @@ const quickcommand = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 载入在线资源
|
// 载入在线资源
|
||||||
loadRemoteScript: async function (url) {
|
loadRemoteScript: async function (url, options) {
|
||||||
if (
|
const urlReg =
|
||||||
!/^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/.test(
|
/^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/;
|
||||||
url
|
if (!urlReg.test(url)) throw "url 不合法";
|
||||||
)
|
const { useCache = false } = options;
|
||||||
)
|
if (useCache) {
|
||||||
throw "url 不合法";
|
const urlHash = quickcomposer.coding.md5Hash(url);
|
||||||
let local = getQuickcommandTempFile("js");
|
const fileName = path.basename(url, ".js") + "." + urlHash.slice(8, -8);
|
||||||
await this.downloadFile(url, local);
|
const local = getQuickcommandFolderFile(fileName, "js");
|
||||||
let source = require(local);
|
if (!fs.existsSync(local)) {
|
||||||
fs.unlinkSync(local);
|
await this.downloadFile(url, local);
|
||||||
return source;
|
}
|
||||||
|
return require(local);
|
||||||
|
} else {
|
||||||
|
const local = getQuickcommandTempFile("js");
|
||||||
|
await this.downloadFile(url, local);
|
||||||
|
let source = require(local);
|
||||||
|
fs.unlinkSync(local);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 唤醒 uTools
|
// 唤醒 uTools
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const fs = require("fs").promises;
|
const fs = require("fs").promises;
|
||||||
|
const fsSync = require("fs");
|
||||||
const path = require("path");
|
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;
|
const { filePath, transferOperation, newPath } = config;
|
||||||
|
|
||||||
// 检查文件是否存在
|
// 检查文件是否存在
|
||||||
try {
|
if (!fsSync.existsSync(filePath)) throw "文件或目录不存在!";
|
||||||
const stats = await fs.lstat(filePath);
|
// 确保目标目录存在
|
||||||
|
await mkdir(path.dirname(newPath));
|
||||||
// 确保目标目录存在
|
if (transferOperation === "copy") {
|
||||||
await fs.mkdir(path.dirname(newPath), { recursive: true });
|
await copy(filePath, newPath);
|
||||||
if (transferOperation === "copy") {
|
} else if (transferOperation === "rename") {
|
||||||
const processBar = await quickcommand.showProcessBar({
|
await move(filePath, newPath);
|
||||||
text: "复制中...",
|
} else {
|
||||||
});
|
throw new Error(`不支持的操作类型: ${transferOperation}`);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
plugin/package-lock.json
generated
28
plugin/package-lock.json
generated
@ -5,7 +5,7 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.8.2",
|
||||||
"chrome-remote-interface": "^0.33.2",
|
"chrome-remote-interface": "^0.33.2",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dompurify": "^3.2.4",
|
"dompurify": "^3.2.4",
|
||||||
@ -15,7 +15,7 @@
|
|||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"pinyin-match": "^1.2.6",
|
"pinyin-match": "^1.2.6",
|
||||||
"png2icons": "^2.0.1",
|
"png2icons": "^2.0.1",
|
||||||
"ses": "^1.10.0",
|
"ses": "^1.12.0",
|
||||||
"sm-crypto": "^0.3.13",
|
"sm-crypto": "^0.3.13",
|
||||||
"tree-kill": "^1.2.2"
|
"tree-kill": "^1.2.2"
|
||||||
}
|
}
|
||||||
@ -40,9 +40,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.7.9",
|
"version": "1.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
|
||||||
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
@ -229,9 +229,9 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
"node_modules/ses": {
|
"node_modules/ses": {
|
||||||
"version": "1.10.0",
|
"version": "1.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/ses/-/ses-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/ses/-/ses-1.12.0.tgz",
|
||||||
"integrity": "sha512-HXmJbNEgY/4hsQfaz5dna39vVKNyvlElRmJYk+bjTqSXSElT0Hr6NKwWVg4j0TxP6IuHp/PNMoWJKIRXzmLbAQ==",
|
"integrity": "sha512-jvmwXE2lFxIIY1j76hFjewIIhYMR9Slo3ynWZGtGl5M7VUCw3EA0wetS+JCIbl2UcSQjAT0yGAHkyxPJreuC9w==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@endo/env-options": "^1.1.8"
|
"@endo/env-options": "^1.1.8"
|
||||||
@ -293,9 +293,9 @@
|
|||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "1.7.9",
|
"version": "1.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
|
||||||
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
@ -419,9 +419,9 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
"ses": {
|
"ses": {
|
||||||
"version": "1.10.0",
|
"version": "1.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/ses/-/ses-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/ses/-/ses-1.12.0.tgz",
|
||||||
"integrity": "sha512-HXmJbNEgY/4hsQfaz5dna39vVKNyvlElRmJYk+bjTqSXSElT0Hr6NKwWVg4j0TxP6IuHp/PNMoWJKIRXzmLbAQ==",
|
"integrity": "sha512-jvmwXE2lFxIIY1j76hFjewIIhYMR9Slo3ynWZGtGl5M7VUCw3EA0wetS+JCIbl2UcSQjAT0yGAHkyxPJreuC9w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@endo/env-options": "^1.1.8"
|
"@endo/env-options": "^1.1.8"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.8.2",
|
||||||
"chrome-remote-interface": "^0.33.2",
|
"chrome-remote-interface": "^0.33.2",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dompurify": "^3.2.4",
|
"dompurify": "^3.2.4",
|
||||||
@ -10,7 +10,7 @@
|
|||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"pinyin-match": "^1.2.6",
|
"pinyin-match": "^1.2.6",
|
||||||
"png2icons": "^2.0.1",
|
"png2icons": "^2.0.1",
|
||||||
"ses": "^1.10.0",
|
"ses": "^1.12.0",
|
||||||
"sm-crypto": "^0.3.13",
|
"sm-crypto": "^0.3.13",
|
||||||
"tree-kill": "^1.2.2"
|
"tree-kill": "^1.2.2"
|
||||||
}
|
}
|
||||||
|
17
src/App.vue
17
src/App.vue
@ -16,6 +16,8 @@ import programmings from "./js/options/programs.js";
|
|||||||
import defaultProfile from "./js/options/defaultProfile.js";
|
import defaultProfile from "./js/options/defaultProfile.js";
|
||||||
import Cron from "croner";
|
import Cron from "croner";
|
||||||
import QuickCommand from "components/quickcommandUI/QuickCommand";
|
import QuickCommand from "components/quickcommandUI/QuickCommand";
|
||||||
|
import { generateFlowsCode } from "js/composer/generateCode";
|
||||||
|
|
||||||
// import autoDetach from "./js/autoDetach.js";
|
// import autoDetach from "./js/autoDetach.js";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -157,10 +159,13 @@ export default defineComponent({
|
|||||||
reslove([`超过${timeout}ms未响应`]);
|
reslove([`超过${timeout}ms未响应`]);
|
||||||
}, timeout);
|
}, timeout);
|
||||||
let command = dbManager.getDB("qc_" + featureCode);
|
let command = dbManager.getDB("qc_" + featureCode);
|
||||||
let commandCode = command.cmd;
|
let commandCode =
|
||||||
|
command.program === "quickcomposer"
|
||||||
|
? generateFlowsCode(command.flows)
|
||||||
|
: command.cmd;
|
||||||
if (mainInput)
|
if (mainInput)
|
||||||
commandCode = commandCode.replace(/\{\{input\}\}/g, mainInput);
|
commandCode = commandCode.replace(/\{\{input\}\}/g, mainInput);
|
||||||
if (command.program === "quickcommand") {
|
if (["quickcommand", "quickcomposer"].includes(command.program)) {
|
||||||
window.runCodeInSandbox(commandCode, (stdout, stderr) => {
|
window.runCodeInSandbox(commandCode, (stdout, stderr) => {
|
||||||
stderr && reslove([stderr.toString()]);
|
stderr && reslove([stderr.toString()]);
|
||||||
reslove(stdout);
|
reslove(stdout);
|
||||||
@ -168,10 +173,10 @@ export default defineComponent({
|
|||||||
} else {
|
} else {
|
||||||
let option =
|
let option =
|
||||||
command.program === "custom"
|
command.program === "custom"
|
||||||
? command.customOptions
|
? command.customOptions || {}
|
||||||
: this.programs[command.program];
|
: this.programs[command.program] || {};
|
||||||
option.scptarg = command.scptarg;
|
option.scptarg = command.scptarg || "";
|
||||||
option.charset = command.charset;
|
option.charset = command.charset || {};
|
||||||
window.runCodeFile(
|
window.runCodeFile(
|
||||||
commandCode,
|
commandCode,
|
||||||
option,
|
option,
|
||||||
|
@ -170,8 +170,8 @@ export default {
|
|||||||
getCommandOpt(command) {
|
getCommandOpt(command) {
|
||||||
let option =
|
let option =
|
||||||
command.program === "custom"
|
command.program === "custom"
|
||||||
? command.customOptions
|
? command.customOptions || {}
|
||||||
: programs[command.program];
|
: programs[command.program] || {};
|
||||||
option.scptarg = command.scptarg || "";
|
option.scptarg = command.scptarg || "";
|
||||||
option.charset = command.charset || {};
|
option.charset = command.charset || {};
|
||||||
option.envPath = this.$root.nativeProfile.envPath.trim() || "";
|
option.envPath = this.$root.nativeProfile.envPath.trim() || "";
|
||||||
|
@ -213,7 +213,7 @@ export default defineComponent({
|
|||||||
const response = await window.quickcommand.askAI(
|
const response = await window.quickcommand.askAI(
|
||||||
{
|
{
|
||||||
prompt: promptText,
|
prompt: promptText,
|
||||||
context: [...presetContext, ...this.chatHistory.slice(0, -2)],
|
context: [presetContext, ...this.chatHistory.slice(0, -2)],
|
||||||
},
|
},
|
||||||
this.selectedApi,
|
this.selectedApi,
|
||||||
{
|
{
|
||||||
@ -291,7 +291,7 @@ export default defineComponent({
|
|||||||
shell: "liunx shell脚本",
|
shell: "liunx shell脚本",
|
||||||
};
|
};
|
||||||
const languageName = languageMap[language] || language;
|
const languageName = languageMap[language] || language;
|
||||||
const commonInstructions = `接下来我所有的对话中的需求都请通过编写${languageName}代码来实现,并请遵循以下原则:
|
const commonInstructions = `接下来所有的对话中的需求都请通过编写${languageName}代码来实现,并请遵循以下原则:
|
||||||
- 编写简洁、可读性强的代码
|
- 编写简洁、可读性强的代码
|
||||||
- 遵循${languageName}最佳实践和设计模式
|
- 遵循${languageName}最佳实践和设计模式
|
||||||
- 使用恰当的命名规范和代码组织
|
- 使用恰当的命名规范和代码组织
|
||||||
@ -312,7 +312,7 @@ export default defineComponent({
|
|||||||
const specificInstructions = languageSpecific[language] || "";
|
const specificInstructions = languageSpecific[language] || "";
|
||||||
|
|
||||||
const lastInstructions =
|
const lastInstructions =
|
||||||
"\n请直接给我MARKDOWN格式的代码,任何情况下都不需要做解释和说明";
|
"\n请直接提供MARKDOWN格式的代码(以```脚本语言开头,以```结尾),任何情况下都不需要做解释和说明";
|
||||||
|
|
||||||
return commonInstructions + specificInstructions + lastInstructions;
|
return commonInstructions + specificInstructions + lastInstructions;
|
||||||
},
|
},
|
||||||
@ -330,48 +330,26 @@ export default defineComponent({
|
|||||||
];
|
];
|
||||||
},
|
},
|
||||||
getPresetContext() {
|
getPresetContext() {
|
||||||
|
let finnalPrompt = ""
|
||||||
|
|
||||||
const languagePrompt = this.getLanguagePrompt(this.language);
|
const languagePrompt = this.getLanguagePrompt(this.language);
|
||||||
|
|
||||||
let presetContext = [
|
finnalPrompt += languagePrompt;
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: languagePrompt,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "assistant",
|
|
||||||
content: "好的,我会严格按照你的要求编写代码。",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (this.submitDocs && this.language === "quickcommand") {
|
if (this.submitDocs && this.language === "quickcommand") {
|
||||||
const docs = this.getLanguageDocs(this.language);
|
const docs = this.getLanguageDocs(this.language);
|
||||||
|
|
||||||
presetContext.push(
|
finnalPrompt += `\n你现在使用的是一种特殊的环境,支持uTools和quickcommand两种特殊的接口,请优先使用uTools和quickcommand接口解决需求,然后再使用当前语言通用的解决方案`;
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: `你现在使用的是一种特殊的环境,支持uTools和quickcommand两种特殊的接口,请优先使用uTools和quickcommand接口解决需求,然后再使用当前语言通用的解决方案`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "assistant",
|
|
||||||
content: "好的,我会注意。",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
docs.forEach((doc) => {
|
docs.forEach((doc) => {
|
||||||
presetContext.push(
|
finnalPrompt += `\n这是${doc.name}的API文档:\n${doc.api}`;
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: `这是${doc.name}的API文档:\n${doc.api}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "assistant",
|
|
||||||
content: "好的,我会认真学习并记住这些接口。",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return presetContext;
|
return {
|
||||||
|
role: "system",
|
||||||
|
content: finnalPrompt,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
openAIAssistantHelp() {
|
openAIAssistantHelp() {
|
||||||
window.showUb.help("#KUCwm");
|
window.showUb.help("#KUCwm");
|
||||||
|
@ -2,25 +2,20 @@
|
|||||||
<q-card style="width: 800px" class="q-pa-sm">
|
<q-card style="width: 800px" class="q-pa-sm">
|
||||||
<div class="text-h5 q-my-md q-px-sm">API配置</div>
|
<div class="text-h5 q-my-md q-px-sm">API配置</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex q-mb-md q-px-sm" style="height: 26px">
|
<div class="q-pa-sm row q-gutter-sm">
|
||||||
<ButtonGroup
|
<q-btn
|
||||||
v-model="apiToAdd"
|
v-for="option in aiOptions"
|
||||||
class="col"
|
:key="option.value"
|
||||||
:options="[
|
icon="add_link"
|
||||||
{ label: 'OPENAI', value: 'openai' },
|
dense
|
||||||
{ label: 'OLLAMA', value: 'ollama' },
|
|
||||||
]"
|
|
||||||
height="26px"
|
|
||||||
/>
|
|
||||||
<q-icon
|
|
||||||
name="add_box"
|
|
||||||
@click="addModel"
|
|
||||||
color="primary"
|
color="primary"
|
||||||
size="26px"
|
:label="option.label"
|
||||||
class="cursor-pointer q-ml-sm"
|
@click="addModel(option.value)"
|
||||||
|
class="col"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<q-scroll-area
|
<q-scroll-area
|
||||||
|
ref="scrollArea"
|
||||||
:style="`height: ${getConfigListHeight()}px;`"
|
:style="`height: ${getConfigListHeight()}px;`"
|
||||||
class="q-px-sm"
|
class="q-px-sm"
|
||||||
:vertical-thumb-style="{
|
:vertical-thumb-style="{
|
||||||
@ -80,6 +75,7 @@
|
|||||||
? '例:https://api.openai.com'
|
? '例:https://api.openai.com'
|
||||||
: '例:http://localhost:11434'
|
: '例:http://localhost:11434'
|
||||||
"
|
"
|
||||||
|
v-show="aiConfig.apiType !== 'utools'"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<q-badge
|
<q-badge
|
||||||
@ -130,7 +126,7 @@
|
|||||||
dense
|
dense
|
||||||
v-model="aiConfig.apiToken"
|
v-model="aiConfig.apiToken"
|
||||||
v-if="aiConfig.apiType === 'openai'"
|
v-if="aiConfig.apiType === 'openai'"
|
||||||
type="password"
|
:type="tokenInputTypes[index] || 'password'"
|
||||||
class="col-7"
|
class="col-7"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
@ -141,6 +137,22 @@
|
|||||||
class="q-pa-xs"
|
class="q-pa-xs"
|
||||||
/>
|
/>
|
||||||
</template>
|
</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>
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -163,28 +175,54 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent, ref } from "vue";
|
||||||
import { dbManager } from "js/utools.js";
|
import { dbManager } from "js/utools.js";
|
||||||
import ButtonGroup from "components/composer/common/ButtonGroup.vue";
|
|
||||||
import draggable from "vuedraggable";
|
import draggable from "vuedraggable";
|
||||||
import { getUniqueId } from "js/common/uuid.js";
|
import { getUniqueId } from "js/common/uuid.js";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "AIConfig",
|
name: "AIConfig",
|
||||||
components: {
|
components: {
|
||||||
ButtonGroup,
|
|
||||||
draggable,
|
draggable,
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const initAiOptions = utools.allAiModels
|
||||||
|
? [{ label: "uTools内置AI", value: "utools" }]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const aiOptions = ref([
|
||||||
|
...initAiOptions,
|
||||||
|
{ label: "OPENAI接口(需Key)", value: "openai" },
|
||||||
|
{ label: "OLLAMA接口", value: "ollama" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
aiOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
apiToAdd: "openai",
|
|
||||||
aiConfigs: [],
|
aiConfigs: [],
|
||||||
models: [],
|
models: [],
|
||||||
|
tokenInputTypes: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
emits: ["save"],
|
emits: ["save"],
|
||||||
methods: {
|
methods: {
|
||||||
async getModels(aiConfig) {
|
async getModels(aiConfig) {
|
||||||
|
if (aiConfig.apiType === "utools") {
|
||||||
|
try {
|
||||||
|
const models = await utools.allAiModels();
|
||||||
|
this.models = models.map((model) => model.id);
|
||||||
|
} catch (error) {
|
||||||
|
quickcommand.showMessageBox(
|
||||||
|
"获取 uTools AI 模型失败: " + error.message,
|
||||||
|
"error"
|
||||||
|
);
|
||||||
|
this.models = [];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
const { success, result, error } = await window.getModelsFromAiApi(
|
const { success, result, error } = await window.getModelsFromAiApi(
|
||||||
aiConfig
|
aiConfig
|
||||||
);
|
);
|
||||||
@ -205,15 +243,22 @@ export default defineComponent({
|
|||||||
deleteModel(index) {
|
deleteModel(index) {
|
||||||
this.aiConfigs.splice(index, 1);
|
this.aiConfigs.splice(index, 1);
|
||||||
},
|
},
|
||||||
addModel() {
|
addModel(apiType) {
|
||||||
this.aiConfigs.push({
|
const defaultConfig = {
|
||||||
id: getUniqueId(),
|
id: getUniqueId(),
|
||||||
apiType: this.apiToAdd,
|
apiType: apiType,
|
||||||
apiUrl: "",
|
apiUrl: "",
|
||||||
apiToken: "",
|
apiToken: "",
|
||||||
model: "",
|
model: "",
|
||||||
name: "",
|
name: "",
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (apiType === "utools") {
|
||||||
|
defaultConfig.apiUrl = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.aiConfigs.unshift(defaultConfig);
|
||||||
|
|
||||||
},
|
},
|
||||||
getConfigListHeight() {
|
getConfigListHeight() {
|
||||||
const counts = Math.min(this.aiConfigs.length, 3);
|
const counts = Math.min(this.aiConfigs.length, 3);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="composer-flow">
|
<div class="composer-flow">
|
||||||
<ChainStyles ref="chainStyles" :commands="commands" />
|
<ChainStyles ref="chainStyles" :commands="commands" />
|
||||||
|
|
||||||
<q-scroll-area class="command-scroll">
|
<q-scroll-area class="command-scroll" ref="scrollArea">
|
||||||
<div
|
<div
|
||||||
class="command-flow-container"
|
class="command-flow-container"
|
||||||
@dragover.prevent="onDragOver"
|
@dragover.prevent="onDragOver"
|
||||||
@ -541,6 +541,12 @@ export default defineComponent({
|
|||||||
this.$emit("update:modelValue", newCommands);
|
this.$emit("update:modelValue", newCommands);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
// 当高度超过1000时,会出现非预期的自动滚动,暂时找不到原因,先强制滚动到顶部
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.scrollArea.setScrollPosition("vertical", 0);
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -117,9 +117,7 @@ export default defineComponent({
|
|||||||
...category,
|
...category,
|
||||||
commands: this.commands
|
commands: this.commands
|
||||||
.filter(
|
.filter(
|
||||||
(cmd) =>
|
(cmd) => cmd.label && window.pinyinMatch.match(cmd.label, query)
|
||||||
(cmd.label && window.pinyinMatch.match(cmd.label, query)) ||
|
|
||||||
(cmd.value && window.pinyinMatch.match(cmd.value, query))
|
|
||||||
)
|
)
|
||||||
.filter((cmd) => cmd.type === category.label),
|
.filter((cmd) => cmd.type === category.label),
|
||||||
}))
|
}))
|
||||||
|
@ -323,7 +323,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showCommandConfig() {
|
showCommandConfig() {
|
||||||
return !this.isRunComposerPage && this.commandConfig.features;
|
return !this.isRunComposerPage && !!this.commandConfig.features;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -590,14 +590,23 @@ export default defineComponent({
|
|||||||
.flow-container {
|
.flow-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.command-config-panel {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 8px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.flow-wrapper {
|
.flow-wrapper {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.variable-panel {
|
.variable-panel {
|
||||||
@ -624,8 +633,4 @@ export default defineComponent({
|
|||||||
border-bottom: 2px solid var(--q-primary);
|
border-bottom: 2px solid var(--q-primary);
|
||||||
transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-config-panel {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import OperationCard from "components/composer/common/OperationCard.vue";
|
import OperationCard from "components/composer/common/OperationCard.vue";
|
||||||
import ParamInput from "components/composer/param/ParamInput.vue";
|
import ParamInput from "components/composer/param/ParamInput.vue";
|
||||||
import { stringifyArgv, parseFunction } from "js/composer/formatString";
|
import { stringifyArgv } from "js/composer/formatString";
|
||||||
import {
|
import {
|
||||||
newVarInputVal,
|
newVarInputVal,
|
||||||
isVarInputVal,
|
isVarInputVal,
|
||||||
@ -68,7 +68,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
hasSubCommands() {
|
hasSubCommands() {
|
||||||
@ -143,42 +143,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
return `${subCommand}(${finalArgvs.join(",")})`;
|
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) {
|
getAllInputValues(argvs) {
|
||||||
const flatArgvs = [];
|
const flatArgvs = [];
|
||||||
if (!argvs) return flatArgvs;
|
if (!argvs) return flatArgvs;
|
||||||
@ -237,9 +201,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
if (Array.isArray(this.argvs)) {
|
||||||
if (!this.modelValue.code && Array.isArray(argvs)) {
|
this.updateModelValue(this.subCommand, this.argvs);
|
||||||
this.updateModelValue(this.subCommand, argvs);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -29,7 +29,7 @@ import { defineComponent } from "vue";
|
|||||||
import ButtonGroup from "components/composer/common/ButtonGroup.vue";
|
import ButtonGroup from "components/composer/common/ButtonGroup.vue";
|
||||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
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";
|
import AISelector from "components/ai/AISelector.vue";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "AskAIEditor",
|
name: "AskAIEditor",
|
||||||
@ -69,30 +69,18 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
generateCode(argvs = this.argvs) {
|
||||||
return `${this.modelValue.value}(${stringifyArgv(
|
return `${this.modelValue.value}(${stringifyArgv(
|
||||||
argvs.content
|
argvs.content
|
||||||
)}, ${JSON.stringify(argvs.apiConfig)})`;
|
)}, ${JSON.stringify(argvs.apiConfig)})`;
|
||||||
},
|
},
|
||||||
getSummary(argvs) {
|
getSummary(argvs) {
|
||||||
return "问AI:" + argvs.content.prompt;
|
return "问AI:" + stringifyArgv(argvs.content.prompt);
|
||||||
},
|
},
|
||||||
updateArgvs(keyPath, newValue) {
|
updateArgvs(keyPath, newValue) {
|
||||||
const newArgvs = { ...this.argvs };
|
const newArgvs = { ...this.argvs };
|
||||||
|
@ -16,16 +16,16 @@
|
|||||||
<q-icon name="linear_scale" size="xs" />
|
<q-icon name="linear_scale" size="xs" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="chain-icon">
|
<div v-else class="chain-icon">
|
||||||
<q-icon name="fork_left" size="xs" />
|
<q-icon :name="getChianIcon()" size="xs" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<div class="command-label">
|
<div class="command-label" v-if="!isControlFlow">
|
||||||
<div class="drag-handle text-subtitle2 command-label-text">
|
<div class="drag-handle text-subtitle2 command-label-text">
|
||||||
{{ command.label }}
|
{{ command.label }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="isCollapsed && !isControlFlow"
|
v-if="isCollapsed"
|
||||||
class="summary-container"
|
class="summary-container"
|
||||||
@click.stop="isEditingSummary = true"
|
@click.stop="isEditingSummary = true"
|
||||||
>
|
>
|
||||||
@ -78,6 +78,8 @@
|
|||||||
@update:outputVariable="$emit('update:outputVariable', $event)"
|
@update:outputVariable="$emit('update:outputVariable', $event)"
|
||||||
@run="$emit('run')"
|
@run="$emit('run')"
|
||||||
@remove="$emit('remove')"
|
@remove="$emit('remove')"
|
||||||
|
@add-print="$emit('add-print')"
|
||||||
|
@copy="$emit('copy')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -107,6 +109,8 @@ export default {
|
|||||||
"run",
|
"run",
|
||||||
"remove",
|
"remove",
|
||||||
"toggle-collapse",
|
"toggle-collapse",
|
||||||
|
"copy",
|
||||||
|
"add-print",
|
||||||
],
|
],
|
||||||
computed: {
|
computed: {
|
||||||
contentClass() {
|
contentClass() {
|
||||||
@ -135,6 +139,15 @@ export default {
|
|||||||
return this.command.userComments || this.command.summary;
|
return this.command.userComments || this.command.summary;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
getChianIcon() {
|
||||||
|
return (
|
||||||
|
this.command?.subCommands?.find(
|
||||||
|
(command) => command.value === this.command.commandType
|
||||||
|
)?.icon || "fork_left"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -143,6 +156,7 @@ export default {
|
|||||||
.chain-icon {
|
.chain-icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin-right: 2px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,15 +176,18 @@ export default {
|
|||||||
.command-label {
|
.command-label {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
cursor: grab;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-right: 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);
|
color: var(--q-primary);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import VariableInput from "components/composer/common/VariableInput.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";
|
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "AsymmetricCryptoEditor",
|
name: "AsymmetricCryptoEditor",
|
||||||
@ -224,7 +224,7 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
algorithms() {
|
algorithms() {
|
||||||
@ -261,18 +261,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
generateCode(argvs = this.argvs) {
|
||||||
return `${this.modelValue.value}(${stringifyArgv({
|
return `${this.modelValue.value}(${stringifyArgv({
|
||||||
text: argvs.text,
|
text: argvs.text,
|
||||||
@ -321,10 +309,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -190,7 +190,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import VariableInput from "components/composer/common/VariableInput.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";
|
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -226,7 +226,7 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
keyCodecs() {
|
keyCodecs() {
|
||||||
@ -324,18 +324,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.updateModelValue(argvs);
|
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) {
|
getSummary(argvs) {
|
||||||
const text = window.lodashM.truncate(argvs.text.value, {
|
const text = window.lodashM.truncate(argvs.text.value, {
|
||||||
length: 30,
|
length: 30,
|
||||||
@ -355,10 +343,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="control-command-wrapper">
|
<div class="control-command-wrapper">
|
||||||
<div class="control-command">
|
<div class="control-command">
|
||||||
<!-- 类型标签 -->
|
<!-- 类型标签 -->
|
||||||
<div class="control-type-label">
|
<div class="control-type-label drag-handle">
|
||||||
{{ currentFunction?.label || modelValue.commandType }}
|
{{ currentFunction?.label || modelValue.commandType }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -25,7 +25,7 @@
|
|||||||
no-icon-animation
|
no-icon-animation
|
||||||
class="control-btn"
|
class="control-btn"
|
||||||
>
|
>
|
||||||
<q-list>
|
<q-list dense>
|
||||||
<q-item
|
<q-item
|
||||||
v-for="func in branchOptions"
|
v-for="func in branchOptions"
|
||||||
:key="func.value"
|
:key="func.value"
|
||||||
@ -87,7 +87,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
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;
|
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) {
|
updateModelValue(argvs) {
|
||||||
const code = this.generateCode(argvs);
|
const code = this.generateCode(argvs);
|
||||||
|
|
||||||
@ -180,9 +143,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (!this.modelValue.code) {
|
this.updateModelValue(this.argvs);
|
||||||
this.updateModelValue(this.defaultArgvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -207,6 +168,12 @@ export default defineComponent({
|
|||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-type-label:hover {
|
||||||
|
color: var(--q-primary) !important;
|
||||||
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-settings {
|
.control-settings {
|
||||||
|
@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
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 VariableInput from "components/composer/common/VariableInput.vue";
|
||||||
import NumberInput from "components/composer/common/NumberInput.vue";
|
import NumberInput from "components/composer/common/NumberInput.vue";
|
||||||
import OperationCard from "components/composer/common/OperationCard.vue";
|
import OperationCard from "components/composer/common/OperationCard.vue";
|
||||||
@ -208,10 +208,7 @@ export default defineComponent({
|
|||||||
argvs: {
|
argvs: {
|
||||||
get() {
|
get() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs ||
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
this.parseCodeToArgvs(this.modelValue.code) || {
|
|
||||||
...this.defaultArgvs,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -234,49 +231,6 @@ export default defineComponent({
|
|||||||
argvs.data
|
argvs.data
|
||||||
)}, "${argvs.method}", ${stringifyArgv(options)})`;
|
)}, "${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) {
|
updateArgvs(key, value) {
|
||||||
this.argvs = {
|
this.argvs = {
|
||||||
...this.argvs,
|
...this.argvs,
|
||||||
@ -300,10 +254,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -97,7 +97,6 @@ import VariableInput from "components/composer/common/VariableInput.vue";
|
|||||||
import RegexInput from "./RegexInput.vue";
|
import RegexInput from "./RegexInput.vue";
|
||||||
import RegexBuilder from "./RegexBuilder.vue";
|
import RegexBuilder from "./RegexBuilder.vue";
|
||||||
import RegexTester from "./RegexTester.vue";
|
import RegexTester from "./RegexTester.vue";
|
||||||
import { parseToHasType } from "js/composer/formatString";
|
|
||||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -141,7 +140,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
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);
|
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) {
|
getSummary(argvs) {
|
||||||
return argvs.isReplace
|
return argvs.isReplace
|
||||||
? argvs.textValue.value +
|
? argvs.textValue.value +
|
||||||
@ -274,10 +248,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -240,8 +240,16 @@
|
|||||||
<VariableInput
|
<VariableInput
|
||||||
:model-value="argvs.newPath"
|
:model-value="argvs.newPath"
|
||||||
@update:model-value="updateArgvs('newPath', $event)"
|
@update:model-value="updateArgvs('newPath', $event)"
|
||||||
label="目标路径"
|
label="目标路径(含被复制/移动的文件名)"
|
||||||
icon="drive_file_rename_outline"
|
icon="drive_file_rename_outline"
|
||||||
|
:options="{
|
||||||
|
dialog: {
|
||||||
|
options: {
|
||||||
|
title: '选择文件',
|
||||||
|
properties: ['openFile', 'showHiddenFiles'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}"
|
||||||
class="col-6"
|
class="col-6"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
import { stringifyArgv } from "js/composer/formatString";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "ReturnEditor",
|
name: "ReturnEditor",
|
||||||
@ -34,32 +34,15 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
return this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs);
|
||||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
generateCode(argvs = this.argvs) {
|
||||||
return `${this.modelValue.value} ${stringifyArgv(argvs.returnValue)}`;
|
return `${this.modelValue.value} ${stringifyArgv(argvs.returnValue)}`;
|
||||||
},
|
},
|
||||||
getSummary(argvs) {
|
getSummary(argvs) {
|
||||||
return "返回" + " " + argvs.returnValue.value;
|
return "返回" + " " + stringifyArgv(argvs.returnValue);
|
||||||
},
|
},
|
||||||
updateArgvs(key, newValue) {
|
updateArgvs(key, newValue) {
|
||||||
this.argvs[key] = newValue;
|
this.argvs[key] = newValue;
|
||||||
@ -75,10 +58,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -156,7 +156,7 @@ import VariableInput from "components/composer/common/VariableInput.vue";
|
|||||||
import ArrayEditor from "components/composer/common/ArrayEditor.vue";
|
import ArrayEditor from "components/composer/common/ArrayEditor.vue";
|
||||||
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||||
import CheckButton from "components/composer/common/CheckButton.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 programs from "js/options/programs";
|
||||||
import VariableList from "components/composer/common/varinput/VariableList.vue";
|
import VariableList from "components/composer/common/varinput/VariableList.vue";
|
||||||
|
|
||||||
@ -197,9 +197,7 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs ||
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
this.parseCodeToArgvs(this.modelValue.code) ||
|
|
||||||
this.defaultArgvs
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
isCodeSnippet() {
|
isCodeSnippet() {
|
||||||
@ -211,29 +209,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
generateCode(argvs = this.argvs) {
|
||||||
const variables = argvs.code.match(/"?___([^_]+?)___"?/g);
|
const variables = argvs.code.match(/"?___([^_]+?)___"?/g);
|
||||||
const replaceStr =
|
const replaceStr =
|
||||||
@ -317,10 +292,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -132,7 +132,7 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
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}" })`;
|
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) {
|
updateModelValue(argvs) {
|
||||||
this.$emit("update:modelValue", {
|
this.$emit("update:modelValue", {
|
||||||
...this.modelValue,
|
...this.modelValue,
|
||||||
@ -246,10 +217,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -150,7 +150,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import NumberInput from "components/composer/common/NumberInput.vue";
|
import NumberInput from "components/composer/common/NumberInput.vue";
|
||||||
import { parseFunction } from "js/composer/formatString";
|
|
||||||
|
|
||||||
// 检测操作系统
|
// 检测操作系统
|
||||||
const isMac = window.utools.isMacOs();
|
const isMac = window.utools.isMacOs();
|
||||||
@ -438,7 +437,7 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
mainKeyDisplay() {
|
mainKeyDisplay() {
|
||||||
@ -622,44 +621,7 @@ export default defineComponent({
|
|||||||
...this.argvs,
|
...this.argvs,
|
||||||
...argv,
|
...argv,
|
||||||
};
|
};
|
||||||
this.$emit("update:modelValue", {
|
this.updateModelValue(newArgvs);
|
||||||
...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;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
handleKeyInput(val) {
|
handleKeyInput(val) {
|
||||||
let newMainKey;
|
let newMainKey;
|
||||||
@ -703,16 +665,24 @@ export default defineComponent({
|
|||||||
.join(" + ");
|
.join(" + ");
|
||||||
return `${modifiers} + ${shortcut.mainKey}`;
|
return `${modifiers} + ${shortcut.mainKey}`;
|
||||||
},
|
},
|
||||||
},
|
getSummary(argvs) {
|
||||||
mounted() {
|
const modifiers = Object.entries(argvs.modifiers)
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
.filter(([_, active]) => active)
|
||||||
if (!this.modelValue.code) {
|
.map(([key]) => this.modifierLabels[key])
|
||||||
|
.join(" + ");
|
||||||
|
return modifiers ? `${modifiers} + ${argvs.mainKey}` : argvs.mainKey;
|
||||||
|
},
|
||||||
|
updateModelValue(argvs) {
|
||||||
this.$emit("update:modelValue", {
|
this.$emit("update:modelValue", {
|
||||||
...this.modelValue,
|
...this.modelValue,
|
||||||
argvs,
|
argvs: argvs,
|
||||||
code: this.generateCode(argvs),
|
code: this.generateCode(argvs),
|
||||||
|
summary: this.getSummary(argvs),
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.updateModelValue(this.argvs);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -459,7 +459,7 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
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)})`;
|
return `${this.modelValue.value}(${JSON.stringify(keySequence)})`;
|
||||||
},
|
},
|
||||||
updateValue(newArgvs) {
|
updateValue(newArgvs = this.argvs) {
|
||||||
const updatedModelValue = {
|
const updatedModelValue = {
|
||||||
...this.modelValue,
|
...this.modelValue,
|
||||||
argvs: newArgvs || this.argvs,
|
argvs: newArgvs,
|
||||||
code: this.generateCode(newArgvs || this.argvs),
|
code: this.generateCode(newArgvs),
|
||||||
|
summary: this.getSummary(newArgvs),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.$emit("update:modelValue", updatedModelValue);
|
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) {
|
appendSequence(newSequence) {
|
||||||
const startId = Date.now();
|
const startId = Date.now();
|
||||||
this.argvs.sequence.push(
|
this.argvs.sequence.push(
|
||||||
@ -627,37 +638,6 @@ export default defineComponent({
|
|||||||
);
|
);
|
||||||
this.updateValue();
|
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) {
|
toggleModifier(index, key) {
|
||||||
// 创建新的 argvs 对象
|
// 创建新的 argvs 对象
|
||||||
const newArgvs = {
|
const newArgvs = {
|
||||||
@ -678,10 +658,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -132,7 +132,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
import { stringifyArgv } from "js/composer/formatString";
|
||||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||||
import VariableInput from "components/composer/common/VariableInput.vue";
|
import VariableInput from "components/composer/common/VariableInput.vue";
|
||||||
import NumberInput from "components/composer/common/NumberInput.vue";
|
import NumberInput from "components/composer/common/NumberInput.vue";
|
||||||
@ -182,9 +182,7 @@ export default defineComponent({
|
|||||||
argvs: {
|
argvs: {
|
||||||
get() {
|
get() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs ||
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
this.parseCodeToArgvs(this.modelValue.code) ||
|
|
||||||
this.defaultArgvs
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -193,32 +191,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
generateCode(argvs) {
|
||||||
const args = [];
|
const args = [];
|
||||||
|
|
||||||
@ -260,7 +232,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getSummary(argvs) {
|
getSummary(argvs) {
|
||||||
return argvs.command.value;
|
return stringifyArgv(argvs.command);
|
||||||
},
|
},
|
||||||
updateModelValue(argvs) {
|
updateModelValue(argvs) {
|
||||||
this.$emit("update:modelValue", {
|
this.$emit("update:modelValue", {
|
||||||
@ -272,10 +244,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -50,6 +50,7 @@ import UBrowserBasic from "components/composer/ubrowser/UBrowserBasic.vue";
|
|||||||
import UBrowserOperations from "components/composer/ubrowser/UBrowserOperations.vue";
|
import UBrowserOperations from "components/composer/ubrowser/UBrowserOperations.vue";
|
||||||
import UBrowserRun from "components/composer/ubrowser/UBrowserRun.vue";
|
import UBrowserRun from "components/composer/ubrowser/UBrowserRun.vue";
|
||||||
import { generateUBrowserCode } from "js/composer/generateUBrowserCode";
|
import { generateUBrowserCode } from "js/composer/generateUBrowserCode";
|
||||||
|
import { stringifyArgv } from "src/js/composer/formatString";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "UBrowserEditor",
|
name: "UBrowserEditor",
|
||||||
@ -83,7 +84,7 @@ export default {
|
|||||||
return this.modelValue.argvs || this.defaultArgvs;
|
return this.modelValue.argvs || this.defaultArgvs;
|
||||||
},
|
},
|
||||||
summary() {
|
summary() {
|
||||||
const goto = this.argvs.goto?.url || "";
|
const goto = stringifyArgv(this.argvs.goto?.url || "");
|
||||||
return `访问 ${goto}`;
|
return `访问 ${goto}`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -112,9 +113,6 @@ export default {
|
|||||||
code: this.generateCode(),
|
code: this.generateCode(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
parseCodeToArgvs(code) {
|
|
||||||
// TODO: 实现代码解析逻辑
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -14,12 +14,15 @@
|
|||||||
bordered
|
bordered
|
||||||
class="action-card cursor-pointer"
|
class="action-card cursor-pointer"
|
||||||
:class="{
|
:class="{
|
||||||
'action-selected': selectedActionKeys.includes(actionKey),
|
'action-selected': actionCount[actionKey] > 0,
|
||||||
}"
|
}"
|
||||||
@click="toggleAction(actionKey)"
|
@click="addAction(actionKey)"
|
||||||
>
|
>
|
||||||
<div class="q-pa-xs text-caption text-wrap text-center">
|
<div class="q-pa-xs text-caption text-wrap text-center">
|
||||||
{{ action.label }}
|
{{ action.label }}
|
||||||
|
<q-badge v-if="actionCount[actionKey]" color="primary" floating>
|
||||||
|
{{ actionCount[actionKey] }}
|
||||||
|
</q-badge>
|
||||||
</div>
|
</div>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
@ -38,7 +41,7 @@
|
|||||||
<q-chip
|
<q-chip
|
||||||
square
|
square
|
||||||
removable
|
removable
|
||||||
@remove="toggleAction(selectedActionKey)"
|
@remove="removeAction(index)"
|
||||||
class="text-caption q-mb-sm"
|
class="text-caption q-mb-sm"
|
||||||
:style="{
|
:style="{
|
||||||
paddingLeft: '7px',
|
paddingLeft: '7px',
|
||||||
@ -125,6 +128,13 @@ export default {
|
|||||||
selectedActionArgs() {
|
selectedActionArgs() {
|
||||||
return this.modelValue.map((x) => x.args);
|
return this.modelValue.map((x) => x.args);
|
||||||
},
|
},
|
||||||
|
actionCount() {
|
||||||
|
const count = {};
|
||||||
|
this.selectedActionKeys.forEach((key) => {
|
||||||
|
count[key] = (count[key] || 0) + 1;
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
moveAction(index, direction) {
|
moveAction(index, direction) {
|
||||||
@ -138,26 +148,25 @@ export default {
|
|||||||
this.$emit("update:model-value", newOperation);
|
this.$emit("update:model-value", newOperation);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleAction(actionKey) {
|
addAction(actionKey) {
|
||||||
const index = this.selectedActionKeys.indexOf(actionKey);
|
|
||||||
let newOperation = [...this.modelValue];
|
let newOperation = [...this.modelValue];
|
||||||
if (index !== -1) {
|
// 添加操作
|
||||||
// 移除操作
|
const { config, value } = this.operationsMap[actionKey];
|
||||||
newOperation.splice(index, 1);
|
const args = config?.length
|
||||||
} else {
|
? config.map((field) => field.defaultValue)
|
||||||
// 添加操作
|
: [];
|
||||||
const { config, value } = this.operationsMap[actionKey];
|
|
||||||
const args = config?.length
|
|
||||||
? config.map((field) => field.defaultValue)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const newOperationItem = { value, args };
|
const newOperationItem = { value, args };
|
||||||
if (actionKey !== value) {
|
if (actionKey !== value) {
|
||||||
newOperationItem.key = actionKey;
|
newOperationItem.key = actionKey;
|
||||||
}
|
|
||||||
|
|
||||||
newOperation.push(newOperationItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newOperation.push(newOperationItem);
|
||||||
|
this.$emit("update:model-value", newOperation);
|
||||||
|
},
|
||||||
|
removeAction(index) {
|
||||||
|
let newOperation = [...this.modelValue];
|
||||||
|
newOperation.splice(index, 1);
|
||||||
this.$emit("update:model-value", newOperation);
|
this.$emit("update:model-value", newOperation);
|
||||||
},
|
},
|
||||||
updateActionArgs(argvIndex, argvVal, actionIndex) {
|
updateActionArgs(argvIndex, argvVal, actionIndex) {
|
||||||
@ -250,4 +259,11 @@ export default {
|
|||||||
.row.q-col-gutter-xs > * {
|
.row.q-col-gutter-xs > * {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.q-badge {
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
right: -4px;
|
||||||
|
top: -4px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -152,8 +152,8 @@ import VariableInput from "components/composer/common/VariableInput.vue";
|
|||||||
import ArrayEditor from "components/composer/common/ArrayEditor.vue";
|
import ArrayEditor from "components/composer/common/ArrayEditor.vue";
|
||||||
import OperationCard from "components/composer/common/OperationCard.vue";
|
import OperationCard from "components/composer/common/OperationCard.vue";
|
||||||
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||||
import { parseFunction, stringifyArgv } from "js/composer/formatString";
|
import { stringifyArgv } from "js/composer/formatString";
|
||||||
import { newVarInputVal, isVarInputVal } from "js/composer/varInputValManager";
|
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||||
|
|
||||||
const jsonDefaultSelects = new Array(3).fill().map((_, index) => ({
|
const jsonDefaultSelects = new Array(3).fill().map((_, index) => ({
|
||||||
id: newVarInputVal("var", index),
|
id: newVarInputVal("var", index),
|
||||||
@ -235,7 +235,7 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
argvs() {
|
argvs() {
|
||||||
return (
|
return (
|
||||||
this.modelValue.argvs || this.parseCodeToArgvs(this.modelValue.code)
|
this.modelValue.argvs || window.lodashM.cloneDeep(this.defaultArgvs)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
optionTypes() {
|
optionTypes() {
|
||||||
@ -310,32 +310,6 @@ export default defineComponent({
|
|||||||
Object.keys(options).length ? `, ${stringifyArgv(options)}` : ""
|
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) {
|
getSummary(argvs) {
|
||||||
const count = Array.isArray(argvs.selects) ? argvs.selects.length : "?";
|
const count = Array.isArray(argvs.selects) ? argvs.selects.length : "?";
|
||||||
return `显示${count}个${
|
return `显示${count}个${
|
||||||
@ -390,10 +364,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const argvs = this.modelValue.argvs || this.defaultArgvs;
|
this.updateModelValue(this.argvs);
|
||||||
if (!this.modelValue.code) {
|
|
||||||
this.updateModelValue(argvs);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -87,9 +87,11 @@ export default {
|
|||||||
const savedTagOrder = dbManager.getDB(TAG_ORDER_KEY);
|
const savedTagOrder = dbManager.getDB(TAG_ORDER_KEY);
|
||||||
if (savedTagOrder.length) {
|
if (savedTagOrder.length) {
|
||||||
this.savedTagOrder = savedTagOrder;
|
this.savedTagOrder = savedTagOrder;
|
||||||
this.commandManager.changeCurrentTag(this.savedTagOrder[0]);
|
}
|
||||||
} else {
|
if (!this.commandManager.state.currentTag) {
|
||||||
this.commandManager.changeCurrentTag(this.allQuickCommandTags[0]);
|
this.commandManager.changeCurrentTag(
|
||||||
|
this.savedTagOrder[0] || this.allQuickCommandTags[0]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
size="xs"
|
size="xs"
|
||||||
label="插件会员"
|
label="插件会员"
|
||||||
@click="showPayPage = true"
|
@click="showPayPage = true"
|
||||||
><q-tooltip>2元解锁本插件所有会员特权</q-tooltip></q-btn
|
><q-tooltip>{{ memberPrice }}元解锁本插件所有会员特权</q-tooltip></q-btn
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<q-separator vertical inset class="q-mx-lg" />
|
<q-separator vertical inset class="q-mx-lg" />
|
||||||
|
@ -141,7 +141,7 @@ export default {
|
|||||||
* @param position 消息显示位置,默认为"top"
|
* @param position 消息显示位置,默认为"top"
|
||||||
*/
|
*/
|
||||||
showMessageBox: (message, icon = "success", time, 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 === "success") icon = "positive";
|
||||||
if (icon === "error") icon = "negative";
|
if (icon === "error") icon = "negative";
|
||||||
if (typeof time === "undefined")
|
if (typeof time === "undefined")
|
||||||
|
@ -114,9 +114,13 @@ export default {
|
|||||||
|
|
||||||
return this.items.filter((x) => {
|
return this.items.filter((x) => {
|
||||||
if (this.is.json) {
|
if (this.is.json) {
|
||||||
const titleMatch = window.pinyinMatch.match(x.title, this.searchWords);
|
const titleMatch = window.pinyinMatch.match(
|
||||||
|
x.title,
|
||||||
|
this.searchWords
|
||||||
|
);
|
||||||
const descMatch =
|
const descMatch =
|
||||||
x.description && window.pinyinMatch.match(x.description, this.searchWords);
|
x.description &&
|
||||||
|
window.pinyinMatch.match(x.description, this.searchWords);
|
||||||
return titleMatch || descMatch;
|
return titleMatch || descMatch;
|
||||||
} else {
|
} else {
|
||||||
return window.pinyinMatch.match(x, this.searchWords);
|
return window.pinyinMatch.match(x, this.searchWords);
|
||||||
@ -212,6 +216,7 @@ export default {
|
|||||||
this.searchWords = text;
|
this.searchWords = text;
|
||||||
if (this.matchedItems.length < this.currentIndex + 1)
|
if (this.matchedItems.length < this.currentIndex + 1)
|
||||||
this.currentIndex = 0;
|
this.currentIndex = 0;
|
||||||
|
this.setUtoolsHeight(this.itemHeight * this.matchedItemsSize);
|
||||||
}, this.options.options.placeholder);
|
}, this.options.options.placeholder);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -23,16 +23,10 @@ export const controlCommands = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: "否则",
|
|
||||||
value: "else",
|
|
||||||
icon: "fork_left",
|
|
||||||
codeTemplate: "} else {",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: "否则满足",
|
label: "否则满足",
|
||||||
value: "else if",
|
value: "else if",
|
||||||
icon: "fork_left",
|
icon: "fork_right",
|
||||||
codeTemplate: "} else if (${condition}) {",
|
codeTemplate: "} else if (${condition}) {",
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
@ -43,10 +37,16 @@ export const controlCommands = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "否则",
|
||||||
|
value: "else",
|
||||||
|
icon: "airline_stops",
|
||||||
|
codeTemplate: "} else {",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "结束",
|
label: "结束",
|
||||||
value: "end",
|
value: "end",
|
||||||
codeTemplate: "}",
|
codeTemplate: "};",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -112,7 +112,7 @@ export const controlCommands = {
|
|||||||
{
|
{
|
||||||
label: "结束",
|
label: "结束",
|
||||||
value: "end",
|
value: "end",
|
||||||
codeTemplate: "}",
|
codeTemplate: "};",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -169,7 +169,7 @@ export const controlCommands = {
|
|||||||
{
|
{
|
||||||
label: "结束",
|
label: "结束",
|
||||||
value: "end",
|
value: "end",
|
||||||
codeTemplate: "}",
|
codeTemplate: "};",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -225,7 +225,7 @@ export const controlCommands = {
|
|||||||
{
|
{
|
||||||
label: "结束",
|
label: "结束",
|
||||||
value: "end",
|
value: "end",
|
||||||
codeTemplate: "}",
|
codeTemplate: "};",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -266,7 +266,7 @@ export const controlCommands = {
|
|||||||
{
|
{
|
||||||
label: "结束",
|
label: "结束",
|
||||||
value: "end",
|
value: "end",
|
||||||
codeTemplate: "}",
|
codeTemplate: "};",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -295,7 +295,7 @@ export const controlCommands = {
|
|||||||
{
|
{
|
||||||
label: "匹配分支",
|
label: "匹配分支",
|
||||||
value: "case",
|
value: "case",
|
||||||
icon: "check",
|
icon: "fork_right",
|
||||||
codeTemplate: "case ${value}:",
|
codeTemplate: "case ${value}:",
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
@ -305,16 +305,22 @@ export const controlCommands = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "中断",
|
||||||
|
value: "break",
|
||||||
|
icon: "stop",
|
||||||
|
codeTemplate: "break;",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "默认分支",
|
label: "默认分支",
|
||||||
value: "default",
|
value: "default",
|
||||||
icon: "last_page",
|
icon: "airline_stops",
|
||||||
codeTemplate: "default:",
|
codeTemplate: "default:",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "结束",
|
label: "结束",
|
||||||
value: "end",
|
value: "end",
|
||||||
codeTemplate: "}",
|
codeTemplate: "};",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -334,7 +340,7 @@ export const controlCommands = {
|
|||||||
{
|
{
|
||||||
label: "捕获异常",
|
label: "捕获异常",
|
||||||
value: "catch",
|
value: "catch",
|
||||||
icon: "error",
|
icon: "priority_high",
|
||||||
codeTemplate: "} catch (${errorVar}) {",
|
codeTemplate: "} catch (${errorVar}) {",
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
@ -354,7 +360,7 @@ export const controlCommands = {
|
|||||||
{
|
{
|
||||||
label: "结束",
|
label: "结束",
|
||||||
value: "end",
|
value: "end",
|
||||||
codeTemplate: "}",
|
codeTemplate: "};",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -28,6 +28,7 @@ export const networkCommands = {
|
|||||||
label: "HTTP请求结果",
|
label: "HTTP请求结果",
|
||||||
suggestName: "responseResult",
|
suggestName: "responseResult",
|
||||||
structure: {
|
structure: {
|
||||||
|
data: { label: "响应数据", suggestName: "responseData" },
|
||||||
status: { label: "HTTP状态码", suggestName: "responseStatus" },
|
status: { label: "HTTP状态码", suggestName: "responseStatus" },
|
||||||
statusText: {
|
statusText: {
|
||||||
label: "HTTP状态信息",
|
label: "HTTP状态信息",
|
||||||
@ -36,7 +37,6 @@ export const networkCommands = {
|
|||||||
headers: { label: "服务器响应头", suggestName: "responseHeaders" },
|
headers: { label: "服务器响应头", suggestName: "responseHeaders" },
|
||||||
config: { label: "请求配置信息", suggestName: "requestConfig" },
|
config: { label: "请求配置信息", suggestName: "requestConfig" },
|
||||||
request: { label: "发送的请求", suggestName: "request" },
|
request: { label: "发送的请求", suggestName: "request" },
|
||||||
data: { label: "响应数据", suggestName: "responseData" },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -4,13 +4,13 @@ export function generateCode(flow) {
|
|||||||
// 获取变量赋值代码,如果变量已经存在,则直接赋值,否则声明并赋值
|
// 获取变量赋值代码,如果变量已经存在,则直接赋值,否则声明并赋值
|
||||||
const getVarAssignCode = (varName, varValue) => {
|
const getVarAssignCode = (varName, varValue) => {
|
||||||
if (usedVarNames.includes(varName)) {
|
if (usedVarNames.includes(varName)) {
|
||||||
return `${varName} = ${varValue};`;
|
return `${varName} = ${varValue}`;
|
||||||
}
|
}
|
||||||
usedVarNames.push(varName);
|
usedVarNames.push(varName);
|
||||||
if (!varValue) {
|
if (!varValue) {
|
||||||
return `let ${varName};`;
|
return `let ${varName}`;
|
||||||
}
|
}
|
||||||
return `let ${varName} = ${varValue};`;
|
return `let ${varName} = ${varValue}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getVarByPath = (name, path) => {
|
const getVarByPath = (name, path) => {
|
||||||
@ -36,10 +36,11 @@ export function generateCode(flow) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const indent = " ";
|
const indent = " ";
|
||||||
|
const comma = ";";
|
||||||
|
|
||||||
// 局部变量赋值
|
// 局部变量赋值
|
||||||
manualVars.forEach((v) => {
|
manualVars.forEach((v) => {
|
||||||
code.push(indent + getVarAssignCode(v.name, v.value));
|
code.push(indent + getVarAssignCode(v.name, v.value) + comma);
|
||||||
});
|
});
|
||||||
|
|
||||||
commands.forEach((cmd) => {
|
commands.forEach((cmd) => {
|
||||||
@ -65,7 +66,7 @@ export function generateCode(flow) {
|
|||||||
const extractVarCode = Object.entries(details)
|
const extractVarCode = Object.entries(details)
|
||||||
.map(
|
.map(
|
||||||
([path, varName]) =>
|
([path, varName]) =>
|
||||||
`let ${varName} = ${getVarByPath(promiseName, path)}`
|
`let ${varName} = ${getVarByPath(promiseName, path)};`
|
||||||
)
|
)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|
||||||
@ -80,20 +81,22 @@ export function generateCode(flow) {
|
|||||||
})`;
|
})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code.push(indent + cmdCode);
|
code.push(indent + cmdCode + comma);
|
||||||
} else if (cmd.asyncMode === "await") {
|
} else if (cmd.asyncMode === "await") {
|
||||||
// 使用 await 模式
|
// 使用 await 模式
|
||||||
const promiseName = name || "__result";
|
const promiseName = name || "__result";
|
||||||
cmdCode = getVarAssignCode(promiseName, `await ${cmdCode}`);
|
cmdCode = getVarAssignCode(promiseName, `await ${cmdCode}`);
|
||||||
code.push(indent + cmdCode);
|
code.push(indent + cmdCode + comma);
|
||||||
// 处理详细变量
|
// 处理详细变量
|
||||||
if (details) {
|
if (details) {
|
||||||
Object.entries(details).forEach(([path, varName]) => {
|
Object.entries(details).forEach(([path, varName]) => {
|
||||||
code.push(
|
code.push(
|
||||||
`${indent}${getVarAssignCode(
|
indent +
|
||||||
varName,
|
`${getVarAssignCode(
|
||||||
getVarByPath(promiseName, path)
|
varName,
|
||||||
)}`
|
getVarByPath(promiseName, path)
|
||||||
|
)}` +
|
||||||
|
comma
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -101,15 +104,17 @@ export function generateCode(flow) {
|
|||||||
// 非Async命令
|
// 非Async命令
|
||||||
const resultVarName = name || "__result";
|
const resultVarName = name || "__result";
|
||||||
cmdCode = getVarAssignCode(resultVarName, `${cmdCode}`);
|
cmdCode = getVarAssignCode(resultVarName, `${cmdCode}`);
|
||||||
code.push(indent + cmdCode);
|
code.push(indent + cmdCode + comma);
|
||||||
// 处理详细变量
|
// 处理详细变量
|
||||||
if (details) {
|
if (details) {
|
||||||
Object.entries(details).forEach(([path, varName]) => {
|
Object.entries(details).forEach(([path, varName]) => {
|
||||||
code.push(
|
code.push(
|
||||||
`${indent}${getVarAssignCode(
|
indent +
|
||||||
varName,
|
`${getVarAssignCode(
|
||||||
getVarByPath(resultVarName, path)
|
varName,
|
||||||
)}`
|
getVarByPath(resultVarName, path)
|
||||||
|
)}` +
|
||||||
|
comma
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -119,11 +124,11 @@ export function generateCode(flow) {
|
|||||||
if (cmd.asyncMode === "await") {
|
if (cmd.asyncMode === "await") {
|
||||||
cmdCode = `await ${cmdCode}`;
|
cmdCode = `await ${cmdCode}`;
|
||||||
}
|
}
|
||||||
code.push(indent + cmdCode);
|
code.push(indent + cmdCode + (cmd.isControlFlow ? "" : comma));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
code.push("}"); // Close the function
|
code.push("};"); // Close the function
|
||||||
|
|
||||||
// 如果是主函数,则自动执行
|
// 如果是主函数,则自动执行
|
||||||
if (funcName === "main") {
|
if (funcName === "main") {
|
||||||
|
@ -70,8 +70,6 @@ export function generateUBrowserCode(argvs) {
|
|||||||
// 添加其他操作
|
// 添加其他操作
|
||||||
if (argvs.operations?.length) {
|
if (argvs.operations?.length) {
|
||||||
argvs.operations.forEach(({ value, args }) => {
|
argvs.operations.forEach(({ value, args }) => {
|
||||||
if (!args?.length) return;
|
|
||||||
|
|
||||||
const stringifiedArgs = args
|
const stringifiedArgs = args
|
||||||
.map((arg) => stringifyArgv(arg))
|
.map((arg) => stringifyArgv(arg))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
@ -323,6 +323,19 @@ export const ubrowserOperationConfigs = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
markdown: {
|
||||||
|
value: "markdown",
|
||||||
|
label: "转markdown",
|
||||||
|
icon: "get_app",
|
||||||
|
config: [
|
||||||
|
{
|
||||||
|
label: "CSS 或 XPath 选择器,不传递则转换整个网页内容",
|
||||||
|
icon: "find_in_page",
|
||||||
|
component: "VariableInput",
|
||||||
|
width: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
setCookies: {
|
setCookies: {
|
||||||
value: "setCookies",
|
value: "setCookies",
|
||||||
label: "设置Cookie",
|
label: "设置Cookie",
|
||||||
@ -478,13 +491,13 @@ export const ubrowserOperationConfigs = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
setValue: {
|
setValue: {
|
||||||
value: "setValue",
|
value: "value",
|
||||||
label: "设置值",
|
label: "设置值",
|
||||||
icon: "check_box",
|
icon: "check_box",
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
label: "元素选择器",
|
label: "元素选择器",
|
||||||
icon: "varInput",
|
icon: "find_in_page",
|
||||||
component: "VariableInput",
|
component: "VariableInput",
|
||||||
width: 6,
|
width: 6,
|
||||||
},
|
},
|
||||||
|
@ -167,6 +167,8 @@ export default {
|
|||||||
},
|
},
|
||||||
// 编辑命令
|
// 编辑命令
|
||||||
editCommand(commandOrCode) {
|
editCommand(commandOrCode) {
|
||||||
|
// 防止多次触发
|
||||||
|
if (this.isEditorShow) return;
|
||||||
// 即可传入 code,也可直接传入 command
|
// 即可传入 code,也可直接传入 command
|
||||||
const command =
|
const command =
|
||||||
typeof commandOrCode === "string"
|
typeof commandOrCode === "string"
|
||||||
@ -182,6 +184,8 @@ export default {
|
|||||||
},
|
},
|
||||||
// 新建命令
|
// 新建命令
|
||||||
addNewCommand(program = "quickcommand") {
|
addNewCommand(program = "quickcommand") {
|
||||||
|
// 防止多次触发
|
||||||
|
if (this.isEditorShow) return;
|
||||||
this.editorComponent =
|
this.editorComponent =
|
||||||
program === "quickcomposer" ? "ComposerEditor" : "CommandEditor";
|
program === "quickcomposer" ? "ComposerEditor" : "CommandEditor";
|
||||||
this.commandManager.state.currentCommand =
|
this.commandManager.state.currentCommand =
|
||||||
|
@ -346,8 +346,10 @@ interface quickcommandApi {
|
|||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param url 脚本地址
|
* @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 标识的进程 , 默认为关闭进程
|
* 将 signal 发送给 pid 标识的进程 , 默认为关闭进程
|
||||||
|
133
src/plugins/monaco/types/utools.api.d.ts
vendored
133
src/plugins/monaco/types/utools.api.d.ts
vendored
@ -138,6 +138,11 @@ interface UBrowser {
|
|||||||
* 配合 when 使用
|
* 配合 when 使用
|
||||||
*/
|
*/
|
||||||
end(): this;
|
end(): this;
|
||||||
|
/**
|
||||||
|
* 转为markdown
|
||||||
|
* @param selector CSS 或 XPath 选择器,不传递则转换整个网页内容
|
||||||
|
*/
|
||||||
|
markdown(selector: string): this;
|
||||||
/**
|
/**
|
||||||
* 单击元素
|
* 单击元素
|
||||||
*/
|
*/
|
||||||
@ -662,6 +667,134 @@ interface UToolsApi {
|
|||||||
isLinux(): boolean;
|
isLinux(): boolean;
|
||||||
|
|
||||||
ubrowser: UBrowser;
|
ubrowser: UBrowser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用 AI 能力,支持 Function Calling
|
||||||
|
* @param option AI 选项
|
||||||
|
* @param streamCallback 流式调用函数 (可选)
|
||||||
|
* @returns 返回定制的 PromiseLike
|
||||||
|
*/
|
||||||
|
ai(option: AiOption): PromiseLike<Message>;
|
||||||
|
ai(
|
||||||
|
option: AiOption,
|
||||||
|
streamCallback: (chunk: Message) => void
|
||||||
|
): PromiseLike<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有 AI 模型
|
||||||
|
* @returns 返回 AI 模型数组
|
||||||
|
*/
|
||||||
|
allAiModels(): Promise<AiModel[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI 选项接口
|
||||||
|
*/
|
||||||
|
interface AiOption {
|
||||||
|
/**
|
||||||
|
* AI 模型, 为空默认使用 deepseek-v3
|
||||||
|
*/
|
||||||
|
model?: string;
|
||||||
|
/**
|
||||||
|
* 消息列表
|
||||||
|
*/
|
||||||
|
messages: Message[];
|
||||||
|
/**
|
||||||
|
* 工具列表
|
||||||
|
*/
|
||||||
|
tools?: Tool[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI 消息接口
|
||||||
|
*/
|
||||||
|
interface Message {
|
||||||
|
/**
|
||||||
|
* 消息角色
|
||||||
|
* system:系统消息
|
||||||
|
* user:用户消息
|
||||||
|
* assistant:AI 消息
|
||||||
|
*/
|
||||||
|
role: "system" | "user" | "assistant";
|
||||||
|
/**
|
||||||
|
* 消息内容
|
||||||
|
*/
|
||||||
|
content?: string;
|
||||||
|
/**
|
||||||
|
* 消息推理内容,一般只有推理模型会返回
|
||||||
|
*/
|
||||||
|
reasoning_content?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI 工具接口
|
||||||
|
*/
|
||||||
|
interface Tool {
|
||||||
|
/**
|
||||||
|
* 工具类型
|
||||||
|
* function:函数工具
|
||||||
|
*/
|
||||||
|
type: "function";
|
||||||
|
/**
|
||||||
|
* 函数工具配置
|
||||||
|
*/
|
||||||
|
function?: {
|
||||||
|
/**
|
||||||
|
* 函数名称
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* 函数描述
|
||||||
|
*/
|
||||||
|
description: string;
|
||||||
|
/**
|
||||||
|
* 函数参数
|
||||||
|
*/
|
||||||
|
parameters: {
|
||||||
|
type: "object";
|
||||||
|
properties: Record<string, any>;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 必填参数
|
||||||
|
*/
|
||||||
|
required?: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI 模型接口
|
||||||
|
*/
|
||||||
|
interface AiModel {
|
||||||
|
/**
|
||||||
|
* AI 模型 ID,用于 utools.ai 调用的 model 参数
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* AI 模型名称
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
/**
|
||||||
|
* AI 模型描述
|
||||||
|
*/
|
||||||
|
description: string;
|
||||||
|
/**
|
||||||
|
* AI 模型图标
|
||||||
|
*/
|
||||||
|
icon: string;
|
||||||
|
/**
|
||||||
|
* AI 模型调用消耗
|
||||||
|
*/
|
||||||
|
cost: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promise 扩展类型,包含 abort() 函数
|
||||||
|
*/
|
||||||
|
interface PromiseLike<T> extends Promise<T> {
|
||||||
|
/**
|
||||||
|
* 中止 AI 调用
|
||||||
|
*/
|
||||||
|
abort(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare var utools: UToolsApi;
|
declare var utools: UToolsApi;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user