diff --git a/plugin/lib/quickcommand.js b/plugin/lib/quickcommand.js index c24ce33..f0e1cae 100644 --- a/plugin/lib/quickcommand.js +++ b/plugin/lib/quickcommand.js @@ -58,13 +58,19 @@ const quickcommand = { { timeout: ms, }, - (err, stdout, stderr) => { + () => { var end = new Date().getTime(); callback(end - start); } ); }, + asyncSleep: async function (ms) { + return new Promise((resolve) => { + this.setTimeout(resolve, ms); + }); + }, + // 关闭进程 kill: function (pid, signal = "SIGTERM", cb) { kill(pid, signal, cb); diff --git a/plugin/lib/quickcomposer/browser/execScript.js b/plugin/lib/quickcomposer/browser/execScript.js index b183ba3..b610681 100644 --- a/plugin/lib/quickcomposer/browser/execScript.js +++ b/plugin/lib/quickcomposer/browser/execScript.js @@ -72,7 +72,8 @@ const submitForm = async (tab, buttonSelector, inputSelectors) => { const getText = async (tab, selector) => { return await executeScript( tab, - `document.querySelector('${selector}')?.textContent || ''` + `const element = document.querySelector('${selector}'); + return element?.textContent || element?.innerText || '';` ); }; @@ -80,7 +81,7 @@ const getHtml = async (tab, selector) => { return await executeScript( tab, `const element = document.querySelector('${selector}'); - return element ? element.innerHTML : '';` + return element?.outerHTML || '';` ); }; @@ -110,7 +111,7 @@ const scrollToElement = async (tab, selector) => { }; const getScrollPosition = async (tab) => { - return await executeScript( + const result = await executeScript( tab, ` return JSON.stringify({ @@ -119,10 +120,11 @@ const getScrollPosition = async (tab) => { }); ` ); + return JSON.parse(result); }; const getPageSize = async (tab) => { - return await executeScript( + const result = await executeScript( tab, ` return JSON.stringify({ @@ -137,6 +139,7 @@ const getPageSize = async (tab) => { }); ` ); + return JSON.parse(result); }; const waitForElement = async (tab, selector, timeout = 5000) => { diff --git a/plugin/lib/quickcomposer/data/index.js b/plugin/lib/quickcomposer/data/index.js index 469db08..f99859c 100644 --- a/plugin/lib/quickcomposer/data/index.js +++ b/plugin/lib/quickcomposer/data/index.js @@ -4,6 +4,7 @@ const zlib = require("./zlib"); const { htmlParser } = require("./htmlParser"); const array = require("./array"); const time = require("./time"); +const { regexTransform } = require("./regexTransform"); module.exports = { htmlParser, @@ -12,4 +13,5 @@ module.exports = { zlib, array, time, + regexTransform, }; diff --git a/plugin/lib/quickcomposer/data/regexTransform.js b/plugin/lib/quickcomposer/data/regexTransform.js new file mode 100644 index 0000000..9a960d7 --- /dev/null +++ b/plugin/lib/quickcomposer/data/regexTransform.js @@ -0,0 +1,9 @@ +const regexTransform = (text, regex, replacement) => { + if (replacement) { + return text.replace(regex, replacement); + } else { + return text.match(regex); + } +}; + +module.exports = { regexTransform }; diff --git a/plugin/lib/quickcomposer/data/time.js b/plugin/lib/quickcomposer/data/time.js index 7db96aa..658c102 100644 --- a/plugin/lib/quickcomposer/data/time.js +++ b/plugin/lib/quickcomposer/data/time.js @@ -76,44 +76,207 @@ const time = { parse: function (time, format) { if (!time) return null; + const now = new Date(); + let year = now.getFullYear(); + let month = now.getMonth() + 1; // 转换为正常月份 + let day = now.getDate(); + let hours = 0; + let minutes = 0; + let seconds = 0; + // 处理时间戳 if (format === "timestamp") { - return new Date(Number(time) * 1000); + const date = new Date(Number(time) * 1000); + return this._formatTimeObject(date); } if (format === "timestamp_ms") { - return new Date(Number(time)); + const date = new Date(Number(time)); + return this._formatTimeObject(date); } - // 处理标准格式 - const now = new Date(); - const year = now.getFullYear(); - let result; + // 如果没有指定格式,尝试自动识别 + if (!format) { + // 尝试直接解析 + const date = new Date(time); + if (date.getTime()) { + return this._formatTimeObject(date); + } - switch (format) { - case "YYYY-MM-DD": - case "YYYY-MM-DD HH:mm:ss": - case "YYYY-MM-DD HH:mm": - result = new Date(time); - break; - case "YYYY年MM月DD日": - time = time.replace(/[年月日]/g, (match) => { - return { 年: "-", 月: "-", 日: "" }[match]; - }); - result = new Date(time); - break; - case "MM/DD/YYYY": - const [month, day, yyyy] = time.split("/"); - result = new Date(yyyy, month - 1, day); - break; - case "DD/MM/YYYY": - const [dd, mm, yy] = time.split("/"); - result = new Date(yy, mm - 1, dd); - break; - default: - result = new Date(time); + // 尝试解析常见格式 + const patterns = { + // 标准格式 + "YYYY-MM-DD HH:mm:ss": + /^(\d{4})-(\d{1,2})-(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/, + "YYYY-MM-DD HH:mm": /^(\d{4})-(\d{1,2})-(\d{1,2}) (\d{1,2}):(\d{1,2})$/, + "YYYY-MM-DD": /^(\d{4})-(\d{1,2})-(\d{1,2})$/, + // 中文格式 + "YYYY年MM月DD日 HH时mm分ss秒": + /^(\d{4})年(\d{1,2})月(\d{1,2})日 (\d{1,2})时(\d{1,2})分(\d{1,2})秒$/, + "YYYY年MM月DD日 HH:mm:ss": + /^(\d{4})年(\d{1,2})月(\d{1,2})日 (\d{1,2}):(\d{1,2}):(\d{1,2})$/, + YYYY年MM月DD日: /^(\d{4})年(\d{1,2})月(\d{1,2})日$/, + // 斜杠格式 + "MM/DD/YYYY HH:mm:ss": + /^(\d{1,2})\/(\d{1,2})\/(\d{4}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/, + "DD/MM/YYYY HH:mm:ss": + /^(\d{1,2})\/(\d{1,2})\/(\d{4}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/, + "MM/DD/YYYY": /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/, + "DD/MM/YYYY": /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/, + // 点号格式 + "DD.MM.YYYY": /^(\d{1,2})\.(\d{1,2})\.(\d{4})$/, + // 时间格式 + "HH:mm:ss": /^(\d{1,2}):(\d{1,2}):(\d{1,2})$/, + "HH:mm": /^(\d{1,2}):(\d{1,2})$/, + }; + + for (const [patternFormat, regex] of Object.entries(patterns)) { + const matches = time.match(regex); + if (matches) { + format = patternFormat; + break; + } + } } - return result.getTime() ? result : null; + // 解析时间字符串 + const parseTimeString = (timeStr) => { + const parts = timeStr.split(/[: ]/); + return { + hours: parseInt(parts[0]) || 0, + minutes: parseInt(parts[1]) || 0, + seconds: parseInt(parts[2]) || 0, + }; + }; + + // 根据格式解析 + if (format) { + // 移除所有非数字和分隔符 + const cleanTime = time.replace(/[^0-9/\-.: ]/g, ""); + const parts = cleanTime.split(/[/\-.: ]/); + + switch (format) { + case "YYYY-MM-DD": + case "YYYY-MM-DD HH:mm:ss": + case "YYYY-MM-DD HH:mm": + case "YYYY年MM月DD日": + case "YYYY年MM月DD日 HH:mm:ss": + case "YYYY年MM月DD日 HH时mm分ss秒": + year = parseInt(parts[0]); + month = parseInt(parts[1]); + day = parseInt(parts[2]); + if (parts.length > 3) { + const timeStr = parts.slice(3).join(":"); + const timeObj = parseTimeString(timeStr); + hours = timeObj.hours; + minutes = timeObj.minutes; + seconds = timeObj.seconds; + } + break; + case "MM/DD/YYYY": + case "MM/DD/YYYY HH:mm:ss": + year = parseInt(parts[2]); + month = parseInt(parts[0]); + day = parseInt(parts[1]); + if (parts.length > 3) { + const timeStr = parts.slice(3).join(":"); + const timeObj = parseTimeString(timeStr); + hours = timeObj.hours; + minutes = timeObj.minutes; + seconds = timeObj.seconds; + } + break; + case "DD/MM/YYYY": + case "DD/MM/YYYY HH:mm:ss": + case "DD.MM.YYYY": + year = parseInt(parts[2]); + month = parseInt(parts[1]); + day = parseInt(parts[0]); + if (parts.length > 3) { + const timeStr = parts.slice(3).join(":"); + const timeObj = parseTimeString(timeStr); + hours = timeObj.hours; + minutes = timeObj.minutes; + seconds = timeObj.seconds; + } + break; + case "HH:mm:ss": + case "HH:mm": + const timeObj = parseTimeString(cleanTime); + hours = timeObj.hours; + minutes = timeObj.minutes; + seconds = timeObj.seconds; + break; + default: + // 尝试使用原生解析 + const date = new Date(time); + if (date.getTime()) { + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + hours = date.getHours(); + minutes = date.getMinutes(); + seconds = date.getSeconds(); + } + } + } + + // 验证日期是否有效 + const testDate = new Date(year, month - 1, day, hours, minutes, seconds); + if (!testDate.getTime()) return null; + + return this._formatTimeObject(testDate); + }, + + // 格式化时间对象 + _formatTimeObject: function (date) { + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const day = date.getDate(); + const hours = date.getHours(); + const minutes = date.getMinutes(); + const seconds = date.getSeconds(); + + return { + date: { + year, + month, + day, + }, + time: { + hours, + minutes, + seconds, + }, + formats: { + // 标准格式 + iso: date.toISOString(), + locale: date.toLocaleString(), + localeDate: date.toLocaleDateString(), + localeTime: date.toLocaleTimeString(), + // 常用格式 + "YYYY-MM-DD": `${year}-${this._pad(month)}-${this._pad(day)}`, + "YYYY-MM-DD HH:mm:ss": `${year}-${this._pad(month)}-${this._pad( + day + )} ${this._pad(hours)}:${this._pad(minutes)}:${this._pad(seconds)}`, + dateCN: `${year}年${this._pad(month)}月${this._pad(day)}日`, + "MM/DD/YYYY": `${this._pad(month)}/${this._pad(day)}/${year}`, + "DD/MM/YYYY": `${this._pad(day)}/${this._pad(month)}/${year}`, + "HH:mm:ss": `${this._pad(hours)}:${this._pad(minutes)}:${this._pad( + seconds + )}`, + }, + timestamp: Math.floor(date.getTime() / 1000), + timestamp_ms: date.getTime(), + // 日历信息 + calendar: { + week: date.getDay(), + weekText: ["日", "一", "二", "三", "四", "五", "六"][date.getDay()], + isWeekend: date.getDay() === 0 || date.getDay() === 6, + isLeapYear: (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0, + daysInMonth: new Date(year, month, 0).getDate(), + constellation: this._getConstellation(month, day), + }, + }; }, // 时间加减 diff --git a/plugin/lib/quickcomposer/macos/app.js b/plugin/lib/quickcomposer/macos/app.js index aa1de79..49e2c7d 100644 --- a/plugin/lib/quickcomposer/macos/app.js +++ b/plugin/lib/quickcomposer/macos/app.js @@ -192,7 +192,8 @@ module.exports = { // 启动应用 launch: async function (appName) { - return await quickcommand.runAppleScript(` + if (!appName) return; + await quickcommand.runAppleScript(` tell application "${appName}" activate end tell @@ -201,7 +202,8 @@ module.exports = { // 退出应用 quit: async function (appName) { - return await quickcommand.runAppleScript(` + if (!appName) return; + await quickcommand.runAppleScript(` tell application "${appName}" quit end tell @@ -210,7 +212,8 @@ module.exports = { // 隐藏应用 hide: async function (appName) { - return await quickcommand.runAppleScript(` + if (!appName) return; + await quickcommand.runAppleScript(` tell application "System Events" set visible of process "${appName}" to false end tell @@ -219,7 +222,8 @@ module.exports = { // 显示应用 show: async function (appName) { - return await quickcommand.runAppleScript(` + if (!appName) return; + await quickcommand.runAppleScript(` tell application "System Events" set visible of process "${appName}" to true end tell @@ -231,7 +235,8 @@ module.exports = { // 最小化窗口 minimize: async function (appName) { - return await quickcommand.runAppleScript(` + if (!appName) return; + await quickcommand.runAppleScript(` tell application "System Events" tell process "${appName}" try @@ -244,7 +249,8 @@ module.exports = { // 最大化窗口 maximize: async function (appName) { - return await quickcommand.runAppleScript(` + if (!appName) return; + await quickcommand.runAppleScript(` tell application "System Events" tell process "${appName}" try @@ -258,6 +264,7 @@ module.exports = { // 获取窗口信息 getWindows: async function (appName) { + if (!appName) return; const result = await quickcommand.runAppleScript(` tell application "System Events" tell process "${appName}" @@ -341,6 +348,7 @@ module.exports = { // 获取应用脚本字典 getScriptDictionary: async function (appName) { + if (!appName) return; try { const { execSync } = require("child_process"); diff --git a/plugin/lib/quickcomposer/macos/finder.js b/plugin/lib/quickcomposer/macos/finder.js index d7c6b57..4c2ebe4 100644 --- a/plugin/lib/quickcomposer/macos/finder.js +++ b/plugin/lib/quickcomposer/macos/finder.js @@ -23,7 +23,7 @@ module.exports = { return json end tell `); - return JSON.parse(result); + return JSON.parse(result.replace(/missing value/g, "null")); }, // 获取当前文件夹 diff --git a/plugin/lib/quickcomposer/network/url.js b/plugin/lib/quickcomposer/network/url.js index bef341d..50eac27 100644 --- a/plugin/lib/quickcomposer/network/url.js +++ b/plugin/lib/quickcomposer/network/url.js @@ -54,17 +54,6 @@ function formatQuery(queryParams) { } } -// 解析路径名 -function parsePath(path) { - return url.parse(path); -} - -// 解析主机名 -function parseHost(host) { - const { hostname, port } = url.parse(`http://${host}`); - return { hostname, port }; -} - // 解析 URL 参数 function getQueryParam(urlString, param) { const { query } = url.parse(urlString, true); @@ -92,32 +81,13 @@ function isAbsolute(urlString) { return url.parse(urlString).protocol !== null; } -// 解析 URL 的各个部分 -function parseComponents(urlString) { - const { protocol, auth, hostname, port, pathname, search, hash } = - url.parse(urlString); - - return { - protocol: protocol?.replace(":", ""), - auth, - hostname, - port, - pathname, - search: search?.replace("?", ""), - hash: hash?.replace("#", ""), - }; -} - module.exports = { parse, format, parseQuery, formatQuery, - parsePath, - parseHost, getQueryParam, addQueryParam, removeQueryParam, isAbsolute, - parseComponents, }; diff --git a/src/components/composer/MultiParams.vue b/src/components/composer/MultiParams.vue index 0b15bed..3e6d6c2 100644 --- a/src/components/composer/MultiParams.vue +++ b/src/components/composer/MultiParams.vue @@ -3,7 +3,7 @@ @@ -77,7 +77,7 @@ export default defineComponent({ newArgvs[this.commonConfig.length + index] = config.defaultValue; }); - this.updateModelValue(value, newArgvs); + this.updateModelValue(value, newArgvs, true); }, }, argvs() { @@ -189,14 +189,18 @@ export default defineComponent({ ); return `${subFeature}${allArgvs.join(",")}`; }, - updateModelValue(funcName, argvs) { - this.$emit("update:modelValue", { + updateModelValue(funcName, argvs, resetOutputVariable = false) { + const newModelValue = { ...this.modelValue, value: funcName, argvs, summary: this.getSummary(argvs), code: this.generateCode(funcName, argvs), - }); + }; + if (resetOutputVariable) { + delete newModelValue.outputVariable; + } + this.$emit("update:modelValue", newModelValue); }, getColumnStyle(width = 12) { const columnWidth = (width / 12) * 100; @@ -204,15 +208,6 @@ export default defineComponent({ width: `calc(${columnWidth}% - var(--grid-gap))`, }; }, - updateFuncName(value) { - this.funcName = value; - // 如果切换了子命令,更新输出变量 - const selectSubCommand = this.getSelectSubCommand(value); - if (!selectSubCommand) return; - const newModelValue = { ...this.modelValue, value: value }; - delete newModelValue.outputVariable; - this.$emit("update:modelValue", newModelValue); - }, }, mounted() { const argvs = this.modelValue.argvs || this.defaultArgvs; diff --git a/src/components/composer/card/OutputEditor.vue b/src/components/composer/card/OutputEditor.vue index 8eb6c97..07ab494 100644 --- a/src/components/composer/card/OutputEditor.vue +++ b/src/components/composer/card/OutputEditor.vue @@ -6,7 +6,7 @@ - +
-