diff --git a/plugin/lib/quickcomposer/file/archive.js b/plugin/lib/quickcomposer/file/archive.js new file mode 100644 index 0000000..a4457bb --- /dev/null +++ b/plugin/lib/quickcomposer/file/archive.js @@ -0,0 +1,131 @@ +const { spawn } = require("child_process"); +const path = require("path"); +const os = require("os"); + +/** + * 压缩文件和目录 + * @param {string} operation 操作类型 (compress/extract) + * @param {string} format 归档格式 (zip/tar/gzip) + * @param {string|Array} source 源文件/文件夹路径 + * @param {string} destination 目标路径 + * @returns {Promise} + */ +async function archive( + operation = "compress", + format = "zip", + source, + destination +) { + // 处理参数 + const sources = Array.isArray(source) ? source : [source]; + const isWindows = os.platform() === "win32"; + + // 验证必要参数 + if (!source || !destination) { + throw new Error("源文件和目标路径不能为空"); + } + + return new Promise((resolve, reject) => { + let command, args; + + if (operation === "compress") { + if (format === "zip") { + if (isWindows) { + // Windows使用PowerShell的Compress-Archive + command = "powershell.exe"; + const sourceList = sources.map((s) => `'${s}'`).join(","); + args = [ + "-NoProfile", + "-NonInteractive", + "-Command", + `Compress-Archive -Path ${sourceList} -DestinationPath '${destination}' -Force`, + ]; + } else { + // Unix系统使用zip命令 + command = "zip"; + args = ["-r", destination, ...sources]; + } + } else if (format === "tar") { + if (isWindows) { + reject(new Error("Windows系统不支持TAR格式")); + return; + } + command = "tar"; + args = ["-czf", destination, ...sources]; + } else if (format === "gzip") { + if (sources.length > 1) { + reject(new Error("GZIP格式只支持单个文件")); + return; + } + if (isWindows) { + reject(new Error("Windows系统不支持GZIP格式")); + return; + } + command = "gzip"; + args = ["-c", sources[0]]; + } + } else if (operation === "extract") { + if (format === "zip") { + if (isWindows) { + // Windows使用PowerShell的Expand-Archive + command = "powershell.exe"; + args = [ + "-NoProfile", + "-NonInteractive", + "-Command", + `Expand-Archive -Path '${sources[0]}' -DestinationPath '${destination}' -Force`, + ]; + } else { + // Unix系统使用unzip命令 + command = "unzip"; + args = ["-o", sources[0], "-d", destination]; + } + } else if (format === "tar") { + if (isWindows) { + reject(new Error("Windows系统不支持TAR格式")); + return; + } + command = "tar"; + args = ["-xzf", sources[0], "-C", destination]; + } else if (format === "gzip") { + if (isWindows) { + reject(new Error("Windows系统不支持GZIP格式")); + return; + } + command = "gunzip"; + args = ["-c", sources[0]]; + } + } + + if (!command || !args) { + reject(new Error(`不支持的操作或格式: ${operation} ${format}`)); + return; + } + + const proc = spawn(command, args); + + proc.stdout.on("data", (data) => { + console.log(`归档输出: ${data}`); + }); + + proc.stderr.on("data", (data) => { + console.error(`归档错误: ${data}`); + }); + + proc.on("close", (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`归档操作失败,退出码: ${code}`)); + } + }); + + proc.on("error", (err) => { + reject(new Error(`执行归档命令失败: ${err.message}`)); + }); + }); +} + +module.exports = { + archive, +}; diff --git a/plugin/lib/quickcomposer/file/index.js b/plugin/lib/quickcomposer/file/index.js index 34e535d..5a4281a 100644 --- a/plugin/lib/quickcomposer/file/index.js +++ b/plugin/lib/quickcomposer/file/index.js @@ -1,5 +1,7 @@ const operation = require("./operation"); +const archive = require("./archive"); module.exports = { operation: operation.operation, + archive: archive.archive, }; diff --git a/plugin/lib/quickcomposer/math/basic.js b/plugin/lib/quickcomposer/math/basic.js new file mode 100644 index 0000000..8e642cf --- /dev/null +++ b/plugin/lib/quickcomposer/math/basic.js @@ -0,0 +1,165 @@ +/** + * 基本算术运算 + * @param {string} expression 算术表达式 + * @returns {number} 计算结果 + */ +function evaluate(expression) { + // 移除所有空白字符 + expression = expression.replace(/\s+/g, ""); + + // 检查表达式是否为空 + if (!expression) { + throw new Error("表达式不能为空"); + } + + // 检查表达式是否包含非法字符 + if (!/^[0-9+\-*/().]+$/.test(expression)) { + throw new Error("表达式包含非法字符"); + } + + // 检查括号是否匹配 + let bracketCount = 0; + for (const char of expression) { + if (char === "(") bracketCount++; + if (char === ")") bracketCount--; + if (bracketCount < 0) { + throw new Error("括号不匹配"); + } + } + if (bracketCount !== 0) { + throw new Error("括号不匹配"); + } + + try { + // 使用 Function 构造函数创建一个安全的计算环境 + const result = new Function(`return ${expression}`)(); + + // 检查结果是否为有限数 + if (!Number.isFinite(result)) { + throw new Error("计算结果无效"); + } + + return result; + } catch (error) { + throw new Error("表达式计算错误: " + error.message); + } +} + +/** + * 计算阶乘 + * @param {number} n 非负整数 + * @returns {number} 阶乘结果 + */ +function factorial(n) { + if (!Number.isInteger(n)) { + throw new Error("阶乘只能计算整数"); + } + if (n < 0) { + throw new Error("阶乘不能计算负数"); + } + if (n > 170) { + throw new Error("数字过大,可能导致溢出"); + } + + let result = 1; + for (let i = 2; i <= n; i++) { + result *= i; + } + return result; +} + +/** + * 计算绝对值 + * @param {number} x 数字 + * @returns {number} 绝对值 + */ +function abs(x) { + return Math.abs(x); +} + +/** + * 向上取整 + * @param {number} x 数字 + * @returns {number} 向上取整结果 + */ +function ceil(x) { + return Math.ceil(x); +} + +/** + * 向下取整 + * @param {number} x 数字 + * @returns {number} 向下取整结果 + */ +function floor(x) { + return Math.floor(x); +} + +/** + * 四舍五入 + * @param {number} x 数字 + * @param {number} [decimals=0] 保留小数位数 + * @returns {number} 四舍五入结果 + */ +function round(x, decimals = 0) { + if (!Number.isInteger(decimals) || decimals < 0) { + throw new Error("小数位数必须是非负整数"); + } + const factor = Math.pow(10, decimals); + return Math.round(x * factor) / factor; +} + +/** + * 计算平方根 + * @param {number} x 非负数 + * @returns {number} 平方根 + */ +function sqrt(x) { + if (x < 0) { + throw new Error("不能计算负数的平方根"); + } + return Math.sqrt(x); +} + +/** + * 计算幂 + * @param {number} base 底数 + * @param {number} exponent 指数 + * @returns {number} 幂运算结果 + */ +function pow(base, exponent) { + const result = Math.pow(base, exponent); + if (!Number.isFinite(result)) { + throw new Error("计算结果超出范围"); + } + return result; +} + +/** + * 计算对数 + * @param {number} x 正数 + * @param {number} [base=Math.E] 底数 + * @returns {number} 对数值 + */ +function log(x, base = Math.E) { + if (x <= 0) { + throw new Error("对数只能计算正数"); + } + if (base <= 0 || base === 1) { + throw new Error("对数的底数必须是大于0且不等于1的数"); + } + + return base === Math.E ? Math.log(x) : Math.log(x) / Math.log(base); +} + +module.exports = { + evaluate, + factorial, + abs, + ceil, + floor, + round, + sqrt, + pow, + log, +}; diff --git a/plugin/lib/quickcomposer/math/conversion.js b/plugin/lib/quickcomposer/math/conversion.js new file mode 100644 index 0000000..6eb00d0 --- /dev/null +++ b/plugin/lib/quickcomposer/math/conversion.js @@ -0,0 +1,198 @@ +/** + * 长度单位转换 + * @param {number} value 数值 + * @param {string} fromUnit 源单位 + * @param {string} toUnit 目标单位 + * @returns {number} 转换结果 + */ +function length(value, fromUnit, toUnit) { + const units = { + mm: 0.001, // 毫米 + cm: 0.01, // 厘米 + dm: 0.1, // 分米 + m: 1, // 米(基准单位) + km: 1000, // 千米 + in: 0.0254, // 英寸 + ft: 0.3048, // 英尺 + yd: 0.9144, // 码 + mi: 1609.344, // 英里 + }; + + if (!(fromUnit in units)) { + throw new Error(`不支持的源单位: ${fromUnit}`); + } + if (!(toUnit in units)) { + throw new Error(`不支持的目标单位: ${toUnit}`); + } + + // 先转换为米,再转换为目标单位 + return (value * units[fromUnit]) / units[toUnit]; +} + +/** + * 重量单位转换 + * @param {number} value 数值 + * @param {string} fromUnit 源单位 + * @param {string} toUnit 目标单位 + * @returns {number} 转换结果 + */ +function weight(value, fromUnit, toUnit) { + const units = { + mg: 0.001, // 毫克 + g: 1, // 克(基准单位) + kg: 1000, // 千克 + t: 1000000, // 吨 + oz: 28.3495, // 盎司 + lb: 453.592, // 磅 + }; + + if (!(fromUnit in units)) { + throw new Error(`不支持的源单位: ${fromUnit}`); + } + if (!(toUnit in units)) { + throw new Error(`不支持的目标单位: ${toUnit}`); + } + + // 先转换为克,再转换为目标单位 + return (value * units[fromUnit]) / units[toUnit]; +} + +/** + * 面积单位转换 + * @param {number} value 数值 + * @param {string} fromUnit 源单位 + * @param {string} toUnit 目标单位 + * @returns {number} 转换结果 + */ +function area(value, fromUnit, toUnit) { + const units = { + mm2: 0.000001, // 平方毫米 + cm2: 0.0001, // 平方厘米 + dm2: 0.01, // 平方分米 + m2: 1, // 平方米(基准单位) + km2: 1000000, // 平方千米 + ha: 10000, // 公顷 + in2: 0.00064516, // 平方英寸 + ft2: 0.092903, // 平方英尺 + yd2: 0.836127, // 平方码 + ac: 4046.86, // 英亩 + mi2: 2589988.11, // 平方英里 + }; + + if (!(fromUnit in units)) { + throw new Error(`不支持的源单位: ${fromUnit}`); + } + if (!(toUnit in units)) { + throw new Error(`不支持的目标单位: ${toUnit}`); + } + + // 先转换为平方米,再转换为目标单位 + return (value * units[fromUnit]) / units[toUnit]; +} + +/** + * 体积单位转换 + * @param {number} value 数值 + * @param {string} fromUnit 源单位 + * @param {string} toUnit 目标单位 + * @returns {number} 转换结果 + */ +function volume(value, fromUnit, toUnit) { + const units = { + ml: 0.001, // 毫升 + l: 1, // 升(基准单位) + m3: 1000, // 立方米 + cm3: 0.001, // 立方厘米 + mm3: 0.000001, // 立方毫米 + gal: 3.78541, // 加仑(美制) + qt: 0.946353, // 夸脱(美制) + pt: 0.473176, // 品脱(美制) + cup: 0.236588, // 杯(美制) + floz: 0.0295735, // 液量盎司(美制) + }; + + if (!(fromUnit in units)) { + throw new Error(`不支持的源单位: ${fromUnit}`); + } + if (!(toUnit in units)) { + throw new Error(`不支持的目标单位: ${toUnit}`); + } + + // 先转换为升,再转换为目标单位 + return (value * units[fromUnit]) / units[toUnit]; +} + +/** + * 温度单位转换 + * @param {number} value 数值 + * @param {string} fromUnit 源单位 + * @param {string} toUnit 目标单位 + * @returns {number} 转换结果 + */ +function temperature(value, fromUnit, toUnit) { + const conversions = { + C: { + F: (v) => (v * 9) / 5 + 32, + K: (v) => v + 273.15, + C: (v) => v, + }, + F: { + C: (v) => ((v - 32) * 5) / 9, + K: (v) => ((v - 32) * 5) / 9 + 273.15, + F: (v) => v, + }, + K: { + C: (v) => v - 273.15, + F: (v) => ((v - 273.15) * 9) / 5 + 32, + K: (v) => v, + }, + }; + + if (!(fromUnit in conversions)) { + throw new Error(`不支持的源单位: ${fromUnit}`); + } + if (!(toUnit in conversions[fromUnit])) { + throw new Error(`不支持的目标单位: ${toUnit}`); + } + + return conversions[fromUnit][toUnit](value); +} + +/** + * 时间单位转换 + * @param {number} value 数值 + * @param {string} fromUnit 源单位 + * @param {string} toUnit 目标单位 + * @returns {number} 转换结果 + */ +function time(value, fromUnit, toUnit) { + const units = { + ms: 0.001, // 毫秒 + s: 1, // 秒(基准单位) + min: 60, // 分钟 + h: 3600, // 小时 + d: 86400, // 天 + w: 604800, // 周 + mo: 2592000, // 月(按30天计算) + y: 31536000, // 年(按365天计算) + }; + + if (!(fromUnit in units)) { + throw new Error(`不支持的源单位: ${fromUnit}`); + } + if (!(toUnit in units)) { + throw new Error(`不支持的目标单位: ${toUnit}`); + } + + // 先转换为秒,再转换为目标单位 + return (value * units[fromUnit]) / units[toUnit]; +} + +module.exports = { + length, + weight, + area, + volume, + temperature, + time, +}; diff --git a/plugin/lib/quickcomposer/math/geometry.js b/plugin/lib/quickcomposer/math/geometry.js new file mode 100644 index 0000000..fcfd16d --- /dev/null +++ b/plugin/lib/quickcomposer/math/geometry.js @@ -0,0 +1,96 @@ +/** + * 圆形计算 + * @param {number} radius 半径 + * @returns {Object} 计算结果 + */ +function circle(radius) { + if (radius < 0) { + throw new Error("半径不能为负数"); + } + + return { + area: Math.PI * radius * radius, // 面积 + perimeter: 2 * Math.PI * radius, // 周长 + diameter: 2 * radius, // 直径 + }; +} + +/** + * 矩形计算 + * @param {number} width 宽度 + * @param {number} height 高度 + * @returns {Object} 计算结果 + */ +function rectangle(width, height) { + if (width < 0 || height < 0) { + throw new Error("长度不能为负数"); + } + + return { + area: width * height, // 面积 + perimeter: 2 * (width + height), // 周长 + diagonal: Math.sqrt(width * width + height * height), // 对角线长度 + }; +} + +/** + * 三角形计算 + * @param {number} a 边长a + * @param {number} b 边长b + * @param {number} c 边长c + * @returns {Object} 计算结果 + */ +function triangle(a, b, c) { + if (a < 0 || b < 0 || c < 0) { + throw new Error("边长不能为负数"); + } + + // 检查三角形是否合法(任意两边之和大于第三边) + if (a + b <= c || b + c <= a || a + c <= b) { + throw new Error("不能构成三角形"); + } + + // 半周长 + const s = (a + b + c) / 2; + + // 使用海伦公式计算面积 + const area = Math.sqrt(s * (s - a) * (s - b) * (s - c)); + + // 计算三个角的角度(弧度) + const angleA = Math.acos((b * b + c * c - a * a) / (2 * b * c)); + const angleB = Math.acos((a * a + c * c - b * b) / (2 * a * c)); + const angleC = Math.acos((a * a + b * b - c * c) / (2 * a * b)); + + // 判断三角形类型 + const angles = [angleA, angleB, angleC].map( + (angle) => (angle * 180) / Math.PI + ); + let type; + if (angles.some((angle) => Math.abs(angle - 90) < 0.000001)) { + type = "直角三角形"; + } else if (angles.some((angle) => angle > 90)) { + type = "钝角三角形"; + } else { + type = "锐角三角形"; + } + + return { + area, // 面积 + perimeter: a + b + c, // 周长 + angles: { + // 三个角的度数 + A: angles[0], + B: angles[1], + C: angles[2], + }, + type, // 三角形类型 + inradius: area / s, // 内切圆半径 + circumradius: (a * b * c) / (4 * area), // 外接圆半径 + }; +} + +module.exports = { + circle, + rectangle, + triangle, +}; diff --git a/plugin/lib/quickcomposer/math/index.js b/plugin/lib/quickcomposer/math/index.js index 382c85b..a56ef92 100644 --- a/plugin/lib/quickcomposer/math/index.js +++ b/plugin/lib/quickcomposer/math/index.js @@ -1,5 +1,15 @@ +const basic = require("./basic"); +const statistics = require("./statistics"); +const geometry = require("./geometry"); +const trigonometry = require("./trigonometry"); +const conversion = require("./conversion"); const random = require("./random"); module.exports = { + basic, + statistics, + geometry, + trigonometry, + conversion, random, }; diff --git a/plugin/lib/quickcomposer/math/random.js b/plugin/lib/quickcomposer/math/random.js index 0a335b6..9f64664 100644 --- a/plugin/lib/quickcomposer/math/random.js +++ b/plugin/lib/quickcomposer/math/random.js @@ -1,23 +1,63 @@ -const randomInt = (start, end) => { - return Math.round(Math.random() * (end - start) + start); +/** + * 生成随机数 + * @param {number} min 最小值 + * @param {number} max 最大值 + * @param {number} count 生成数量 + * @param {number} decimals 小数位数 + * @returns {number|number[]} 随机数或随机数数组 + */ +function number(min = 0, max = 100, count = 1, decimals = 0) { + if (min >= max) { + throw new Error("最小值必须小于最大值"); + } + if (count < 1) { + throw new Error("生成数量必须大于0"); + } + if (decimals < 0) { + throw new Error("小数位数不能为负数"); + } + + const factor = Math.pow(10, decimals); + const generate = () => { + const random = Math.random() * (max - min) + min; + return Math.round(random * factor) / factor; + }; + + if (count === 1) { + return generate(); + } + + return Array.from({ length: count }, generate); +} + +/** + * 生成随机整数 + * @param {number} min 最小值 + * @param {number} max 最大值 + * @param {number} count 生成数量 + * @returns {number|number[]} 随机整数或随机整数数组 + */ +function integer(min = 0, max = 100, count = 1) { + min = Math.ceil(min); + max = Math.floor(max); + + if (min >= max) { + throw new Error("最小值必须小于最大值"); + } + if (count < 1) { + throw new Error("生成数量必须大于0"); + } + + const generate = () => Math.floor(Math.random() * (max - min + 1)) + min; + + if (count === 1) { + return generate(); + } + + return Array.from({ length: count }, generate); +} + +module.exports = { + number, + integer, }; - -const random = (isInt = false, start, end) => { - if (!start && !end) { - return isInt ? randomInt(0, 1000000) : Math.random(); - } - - if (!end) { - end = Math.abs(randomInt(0, 1000000) - start); - } - - if (!start) { - start = 0; - } - - // 有start和end:返回区间随机数 - const random = Math.random() * (end - start) + start; - return isInt ? Math.round(random) : random; -}; - -module.exports = random; diff --git a/plugin/lib/quickcomposer/math/statistics.js b/plugin/lib/quickcomposer/math/statistics.js new file mode 100644 index 0000000..77435ce --- /dev/null +++ b/plugin/lib/quickcomposer/math/statistics.js @@ -0,0 +1,140 @@ +/** + * 计算数组的平均值 + * @param {number[]} numbers 数字数组 + * @returns {number} 平均值 + */ +function mean(numbers) { + if (!Array.isArray(numbers) || numbers.length === 0) { + throw new Error("输入必须是非空数组"); + } + return numbers.reduce((sum, num) => sum + num, 0) / numbers.length; +} + +/** + * 计算数组的中位数 + * @param {number[]} numbers 数字数组 + * @returns {number} 中位数 + */ +function median(numbers) { + if (!Array.isArray(numbers) || numbers.length === 0) { + throw new Error("输入必须是非空数组"); + } + + const sorted = [...numbers].sort((a, b) => a - b); + const mid = Math.floor(sorted.length / 2); + + if (sorted.length % 2 === 0) { + return (sorted[mid - 1] + sorted[mid]) / 2; + } + return sorted[mid]; +} + +/** + * 计算数组的众数 + * @param {number[]} numbers 数字数组 + * @returns {number[]} 众数数组(可能有多个) + */ +function mode(numbers) { + if (!Array.isArray(numbers) || numbers.length === 0) { + throw new Error("输入必须是非空数组"); + } + + const frequency = new Map(); + let maxFreq = 0; + + // 计算每个数字出现的频率 + for (const num of numbers) { + const freq = (frequency.get(num) || 0) + 1; + frequency.set(num, freq); + maxFreq = Math.max(maxFreq, freq); + } + + // 找出所有出现频率最高的数字 + return Array.from(frequency.entries()) + .filter(([_, freq]) => freq === maxFreq) + .map(([num]) => num) + .sort((a, b) => a - b); +} + +/** + * 计算数组的方差 + * @param {number[]} numbers 数字数组 + * @param {boolean} [population=true] 是否为总体方差 + * @returns {number} 方差 + */ +function variance(numbers, population = true) { + if (!Array.isArray(numbers) || numbers.length === 0) { + throw new Error("输入必须是非空数组"); + } + + const avg = mean(numbers); + const squaredDiffs = numbers.map((num) => Math.pow(num - avg, 2)); + const divisor = population ? numbers.length : numbers.length - 1; + + return squaredDiffs.reduce((sum, diff) => sum + diff, 0) / divisor; +} + +/** + * 计算数组的标准差 + * @param {number[]} numbers 数字数组 + * @param {boolean} [population=true] 是否为总体标准差 + * @returns {number} 标准差 + */ +function standardDeviation(numbers, population = true) { + return Math.sqrt(variance(numbers, population)); +} + +/** + * 计算数组的范围 + * @param {number[]} numbers 数字数组 + * @returns {Object} 包含最小值、最大值和范围的对象 + */ +function range(numbers) { + if (!Array.isArray(numbers) || numbers.length === 0) { + throw new Error("输入必须是非空数组"); + } + + const min = Math.min(...numbers); + const max = Math.max(...numbers); + + return { + min, // 最小值 + max, // 最大值 + range: max - min, // 范围 + }; +} + +/** + * 计算数组的四分位数 + * @param {number[]} numbers 数字数组 + * @returns {Object} 包含四分位数的对象 + */ +function quartiles(numbers) { + if (!Array.isArray(numbers) || numbers.length === 0) { + throw new Error("输入必须是非空数组"); + } + + const sorted = [...numbers].sort((a, b) => a - b); + const mid = Math.floor(sorted.length / 2); + + const q2 = median(sorted); + const q1 = median(sorted.slice(0, mid)); + const q3 = median(sorted.slice(sorted.length % 2 ? mid + 1 : mid)); + + return { + q1, // 第一四分位数 + q2, // 第二四分位数(中位数) + q3, // 第三四分位数 + iqr: q3 - q1, // 四分位距 + }; +} + +module.exports = { + mean, + median, + mode, + variance, + standardDeviation, + range, + quartiles, +}; diff --git a/plugin/lib/quickcomposer/math/trigonometry.js b/plugin/lib/quickcomposer/math/trigonometry.js new file mode 100644 index 0000000..b6b57de --- /dev/null +++ b/plugin/lib/quickcomposer/math/trigonometry.js @@ -0,0 +1,143 @@ +/** + * 角度转弧度 + * @param {number} degrees 角度 + * @returns {number} 弧度 + */ +function degreesToRadians(degrees) { + return (degrees * Math.PI) / 180; +} + +/** + * 弧度转角度 + * @param {number} radians 弧度 + * @returns {number} 角度 + */ +function radiansToDegrees(radians) { + return (radians * 180) / Math.PI; +} + +/** + * 正弦函数 + * @param {number} angle 角度 + * @param {boolean} [useRadians=false] 是否使用弧度 + * @returns {number} 正弦值 + */ +function sin(angle, useRadians = false) { + const rad = useRadians ? angle : degreesToRadians(angle); + return Math.sin(rad); +} + +/** + * 余弦函数 + * @param {number} angle 角度 + * @param {boolean} [useRadians=false] 是否使用弧度 + * @returns {number} 余弦值 + */ +function cos(angle, useRadians = false) { + const rad = useRadians ? angle : degreesToRadians(angle); + return Math.cos(rad); +} + +/** + * 正切函数 + * @param {number} angle 角度 + * @param {boolean} [useRadians=false] 是否使用弧度 + * @returns {number} 正切值 + */ +function tan(angle, useRadians = false) { + const rad = useRadians ? angle : degreesToRadians(angle); + return Math.tan(rad); +} + +/** + * 反正弦函数 + * @param {number} value 正弦值 + * @param {boolean} [returnRadians=false] 是否返回弧度 + * @returns {number} 角度或弧度 + */ +function asin(value, returnRadians = false) { + if (value < -1 || value > 1) { + throw new Error("反正弦函数的输入值必须在 [-1, 1] 范围内"); + } + const rad = Math.asin(value); + return returnRadians ? rad : radiansToDegrees(rad); +} + +/** + * 反余弦函数 + * @param {number} value 余弦值 + * @param {boolean} [returnRadians=false] 是否返回弧度 + * @returns {number} 角度或弧度 + */ +function acos(value, returnRadians = false) { + if (value < -1 || value > 1) { + throw new Error("反余弦函数的输入值必须在 [-1, 1] 范围内"); + } + const rad = Math.acos(value); + return returnRadians ? rad : radiansToDegrees(rad); +} + +/** + * 反正切函数 + * @param {number} value 正切值 + * @param {boolean} [returnRadians=false] 是否返回弧度 + * @returns {number} 角度或弧度 + */ +function atan(value, returnRadians = false) { + const rad = Math.atan(value); + return returnRadians ? rad : radiansToDegrees(rad); +} + +/** + * 双参数反正切函数 + * @param {number} y y坐标 + * @param {number} x x坐标 + * @param {boolean} [returnRadians=false] 是否返回弧度 + * @returns {number} 角度或弧度 + */ +function atan2(y, x, returnRadians = false) { + const rad = Math.atan2(y, x); + return returnRadians ? rad : radiansToDegrees(rad); +} + +/** + * 双曲正弦函数 + * @param {number} x 输入值 + * @returns {number} 双曲正弦值 + */ +function sinh(x) { + return Math.sinh(x); +} + +/** + * 双曲余弦函数 + * @param {number} x 输入值 + * @returns {number} 双曲余弦值 + */ +function cosh(x) { + return Math.cosh(x); +} + +/** + * 双曲正切函数 + * @param {number} x 输入值 + * @returns {number} 双曲正切值 + */ +function tanh(x) { + return Math.tanh(x); +} + +module.exports = { + degreesToRadians, + radiansToDegrees, + sin, + cos, + tan, + asin, + acos, + atan, + atan2, + sinh, + cosh, + tanh, +}; diff --git a/src/js/composer/commands/fileCommands.js b/src/js/composer/commands/fileCommands.js index c7c743a..b4a35d4 100644 --- a/src/js/composer/commands/fileCommands.js +++ b/src/js/composer/commands/fileCommands.js @@ -67,6 +67,68 @@ export const fileCommands = { }, ], }, + { + value: "quickcomposer.file.archive", + label: "文件归档", + desc: "压缩和解压文件", + icon: "archive", + isAsync: true, + config: [ + { + key: "operation", + label: "操作类型", + type: "select", + icon: "settings", + width: 6, + defaultValue: "compress", + options: [ + { label: "压缩", value: "compress" }, + { label: "解压", value: "extract" }, + ], + }, + { + key: "format", + label: "归档格式", + type: "select", + icon: "format_shapes", + width: 6, + defaultValue: "zip", + options: [ + { label: "ZIP", value: "zip" }, + { label: "TAR", value: "tar" }, + { label: "GZIP", value: "gzip" }, + ], + }, + { + key: "source", + label: "源文件/文件夹", + type: "varInput", + icon: "folder_open", + width: 12, + options: { + dialog: { + type: "open", + options: { + properties: ["openFile", "openDirectory", "multiSelections"], + }, + }, + }, + }, + { + key: "destination", + label: "目标路径", + type: "varInput", + icon: "save", + width: 12, + options: { + dialog: { + type: "save", + options: {}, + }, + }, + }, + ], + }, { value: "utools.shellTrashItem", label: "删除文件到回收站", diff --git a/src/js/composer/commands/mathCommands.js b/src/js/composer/commands/mathCommands.js index 550d0a2..d5d2556 100644 --- a/src/js/composer/commands/mathCommands.js +++ b/src/js/composer/commands/mathCommands.js @@ -4,117 +4,353 @@ export const mathCommands = { defaultOpened: false, commands: [ { - value: "Math.sin", - label: "数学计算", - desc: "数学函数计算", - icon: "calculate", - outputVariable: "calculatedText", - saveOutput: true, + value: "quickcomposer.math.basic.evaluate", + label: "基础运算", + desc: "基础数学运算", + icon: "exposure", config: [ { - label: "要计算的数值", - icon: "numbers", - type: "numInput", + key: "expression", + label: "表达式", + type: "varInput", + icon: "functions", + width: 12, }, ], subCommands: [ { - label: "正弦(sin)", - value: "Math.sin", - icon: "functions", + value: "quickcomposer.math.basic.evaluate", + label: "计算表达式", + icon: "calculate", }, { - label: "余弦(cos)", - value: "Math.cos", - icon: "functions", + value: "quickcomposer.math.basic.round", + label: "四舍五入", + icon: "exposure", + config: [ + { + key: "decimals", + label: "小数位数", + type: "numInput", + icon: "pin", + width: 6, + min: 0, + defaultValue: 2, + }, + ], }, { - label: "正切(tan)", - value: "Math.tan", - icon: "functions", + value: "quickcomposer.math.basic.floor", + label: "向下取整", + icon: "arrow_downward", }, { - label: "反正弦(asin)", - value: "Math.asin", - icon: "functions", + value: "quickcomposer.math.basic.ceil", + label: "向上取整", + icon: "arrow_upward", }, { - label: "反余弦(acos)", - value: "Math.acos", - icon: "functions", + value: "quickcomposer.math.basic.abs", + label: "绝对值", + icon: "unfold_more", }, { - label: "反正切(atan)", - value: "Math.atan", - icon: "functions", - }, - { - label: "平方根(sqrt)", - value: "Math.sqrt", - icon: "functions", - }, - { - label: "自然对数(ln)", - value: "Math.log", - icon: "functions", - }, - { - label: "10对数(log10)", - value: "Math.log10", - icon: "functions", - }, - { - label: "绝对值(abs)", - value: "Math.abs", - icon: "functions", - }, - { - label: "向上取整(ceil)", - value: "Math.ceil", - icon: "functions", - }, - { - label: "向下取整(floor)", - value: "Math.floor", - icon: "functions", - }, - { - label: "四舍五入(round)", - value: "Math.round", - icon: "functions", - }, - { - label: "幂运算(pow)", - value: "Math.pow", + value: "quickcomposer.math.basic.factorial", + label: "阶乘", icon: "functions", }, ], }, { - value: "quickcomposer.math.random", + value: "quickcomposer.math.random.number", label: "随机数", + desc: "生成随机数", + icon: "casino", config: [ { - label: "整数", - type: "switch", - defaultValue: false, - width: 2, + key: "min", + label: "最小值", + type: "numInput", + icon: "arrow_downward", + width: 6, + defaultValue: 0, }, { - label: "起始值", - icon: "last_page", + key: "max", + label: "最大值", type: "numInput", - width: 5, + icon: "arrow_upward", + width: 6, + defaultValue: 100, }, { - label: "结束值", - icon: "first_page", + key: "count", + label: "生成数量", type: "numInput", - width: 5, + icon: "format_list_numbered", + width: 6, + min: 1, + defaultValue: 1, + }, + { + key: "decimals", + label: "小数位数", + type: "numInput", + icon: "pin", + width: 6, + min: 0, + defaultValue: 0, + }, + ], + subCommands: [ + { + value: "quickcomposer.math.random.number", + label: "随机数", + icon: "casino", + }, + { + value: "quickcomposer.math.random.integer", + label: "随机整数", + icon: "casino", + }, + ], + }, + { + value: "quickcomposer.math.statistics", + label: "统计计算", + desc: "统计学相关计算", + icon: "bar_chart", + config: [ + { + key: "numbers", + label: "数据集合", + type: "varInput", + icon: "dataset", + width: 12, + placeholder: "用逗号分隔的数字,如: 1,2,3,4,5", + }, + ], + subCommands: [ + { + value: "quickcomposer.math.statistics.mean", + label: "平均值", + icon: "horizontal_rule", + }, + { + value: "quickcomposer.math.statistics.median", + label: "中位数", + icon: "align_vertical_center", + }, + { + value: "quickcomposer.math.statistics.mode", + label: "众数", + icon: "stacked_bar_chart", + }, + { + value: "quickcomposer.math.statistics.variance", + label: "方差", + icon: "analytics", + }, + { + value: "quickcomposer.math.statistics.stddev", + label: "标准差", + icon: "ssid_chart", + }, + { + value: "quickcomposer.math.statistics.sum", + label: "求和", + icon: "add", + }, + { + value: "quickcomposer.math.statistics.product", + label: "求积", + icon: "close", + }, + { + value: "quickcomposer.math.statistics.max", + label: "最大值", + icon: "keyboard_double_arrow_up", + }, + { + value: "quickcomposer.math.statistics.min", + label: "最小值", + icon: "keyboard_double_arrow_down", + }, + { + value: "quickcomposer.math.statistics.range", + label: "极差", + icon: "height", + }, + ], + }, + { + value: "quickcomposer.math.geometry.circle", + label: "几何计算", + desc: "几何图形计算", + icon: "architecture", + subCommands: [ + { + value: "quickcomposer.math.geometry.circle", + label: "圆形计算", + icon: "circle", + config: [ + { + key: "radius", + label: "半径", + type: "numInput", + icon: "radio_button_checked", + width: 12, + min: 0, + }, + ], + }, + { + value: "quickcomposer.math.geometry.rectangle", + label: "矩形计算", + icon: "rectangle", + config: [ + { + key: "width", + label: "宽度", + type: "numInput", + icon: "width", + width: 6, + min: 0, + }, + { + key: "height", + label: "高度", + type: "numInput", + icon: "height", + width: 6, + min: 0, + }, + ], + }, + { + value: "quickcomposer.math.geometry.triangle", + label: "三角形计算", + icon: "change_history", + config: [ + { + key: "a", + label: "边长a", + type: "numInput", + icon: "straighten", + width: 4, + min: 0, + }, + { + key: "b", + label: "边长b", + type: "numInput", + icon: "straighten", + width: 4, + min: 0, + }, + { + key: "c", + label: "边长c", + type: "numInput", + icon: "straighten", + width: 4, + min: 0, + }, + ], + }, + ], + }, + { + value: "quickcomposer.math.trigonometry.sin", + label: "三角函数", + desc: "三角函数计算", + icon: "show_chart", + config: [ + { + key: "angle", + label: "角度值", + type: "numInput", + icon: "rotate_right", + width: 12, + }, + ], + subCommands: [ + { + value: "quickcomposer.math.trigonometry.sin", + label: "正弦(sin)", + icon: "show_chart", + }, + { + value: "quickcomposer.math.trigonometry.cos", + label: "余弦(cos)", + icon: "show_chart", + }, + { + value: "quickcomposer.math.trigonometry.tan", + label: "正切(tan)", + icon: "show_chart", + }, + { + value: "quickcomposer.math.trigonometry.asin", + label: "反正弦(arcsin)", + icon: "show_chart", + }, + { + value: "quickcomposer.math.trigonometry.acos", + label: "反余弦(arccos)", + icon: "show_chart", + }, + { + value: "quickcomposer.math.trigonometry.atan", + label: "反正切(arctan)", + icon: "show_chart", + }, + ], + }, + { + value: "quickcomposer.math.conversion.decimal", + label: "单位换算", + desc: "数学单位换算", + icon: "swap_horiz", + config: [ + { + key: "value", + label: "数值", + type: "numInput", + icon: "pin", + width: 12, + }, + { + key: "from", + label: "从", + type: "select", + icon: "input", + width: 6, + options: [ + { label: "十进制", value: "decimal" }, + { label: "二进制", value: "binary" }, + { label: "八进制", value: "octal" }, + { label: "十六进制", value: "hex" }, + { label: "度", value: "degrees" }, + { label: "弧度", value: "radians" }, + ], + }, + { + key: "to", + label: "到", + type: "select", + icon: "output", + width: 6, + options: [ + { label: "十进制", value: "decimal" }, + { label: "二进制", value: "binary" }, + { label: "八进制", value: "octal" }, + { label: "十六进制", value: "hex" }, + { label: "度", value: "degrees" }, + { label: "弧度", value: "radians" }, + ], }, ], - outputVariable: "randomNumber", - saveOutput: true, }, ], };