diff --git a/.umirc.ts b/.umirc.ts index 492d220a..7ff3cc24 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -13,9 +13,6 @@ export default defineConfig({ outputPath: 'static/dist', fastRefresh: true, favicons: [`https://qn.whyour.cn/favicon.svg`], - mfsu: { - strategy: 'eager', - }, publicPath: process.env.NODE_ENV === 'production' ? './' : '/', proxy: { [`${baseUrl}api/public`]: { diff --git a/back/config/util.ts b/back/config/util.ts index 6e82ed3a..952ebf89 100644 --- a/back/config/util.ts +++ b/back/config/util.ts @@ -387,28 +387,22 @@ export function emptyDir(path: string) { fs.rmdirSync(path); } -export function promiseExec(command: string): Promise { - return new Promise((resolve, reject) => { - exec( - command, - { maxBuffer: 200 * 1024 * 1024, encoding: 'utf8' }, - (err, stdout, stderr) => { - resolve(stdout || stderr || JSON.stringify(err)); - }, - ); - }); +export async function promiseExec(command: string): Promise { + try { + const { stderr, stdout } = await promisify(exec)(command, { maxBuffer: 200 * 1024 * 1024, encoding: 'utf8' }); + return stdout || stderr; + } catch (error) { + return JSON.stringify(error); + } } -export function promiseExecSuccess(command: string): Promise { - return new Promise((resolve) => { - exec( - command, - { maxBuffer: 200 * 1024 * 1024, encoding: 'utf8' }, - (err, stdout, stderr) => { - resolve(stdout || ''); - }, - ); - }); +export async function promiseExecSuccess(command: string): Promise { + try { + const { stdout } = await promisify(exec)(command, { maxBuffer: 200 * 1024 * 1024, encoding: 'utf8' }); + return stdout || ''; + } catch (error) { + return ''; + } } export function parseHeaders(headers: string) { @@ -501,7 +495,7 @@ export async function killTask(pid: number) { [pid, ...pids].forEach((x) => { process.kill(x, 2); }); - } catch (error) {} + } catch (error) { } } else { process.kill(pid, 2); } diff --git a/back/loaders/app.ts b/back/loaders/app.ts index 0798e28e..14ea2f22 100644 --- a/back/loaders/app.ts +++ b/back/loaders/app.ts @@ -7,18 +7,23 @@ import linkDeps from './deps'; import initTask from './initTask'; export default async ({ expressApp }: { expressApp: Application }) => { - await depInjectorLoader(); - Logger.info('✌️ Dependency Injector loaded'); - - await expressLoader({ app: expressApp }); - Logger.info('✌️ Express loaded'); - - await initData(); - Logger.info('✌️ init data loaded'); - - await linkDeps(); - Logger.info('✌️ link deps loaded'); - - initTask(); - Logger.info('✌️ init task loaded'); + try { + depInjectorLoader(); + Logger.info('✌️ Dependency Injector loaded'); + + expressLoader({ app: expressApp }); + Logger.info('✌️ Express loaded'); + + await initData(); + Logger.info('✌️ init data loaded'); + + await linkDeps(); + Logger.info('✌️ link deps loaded'); + + initTask(); + Logger.info('✌️ init task loaded'); + } catch (error) { + Logger.info('✌️ depInjectorLoader expressLoader initData linkDeps failed'); + Logger.error(error); + } }; diff --git a/back/loaders/db.ts b/back/loaders/db.ts index ebdd7d10..5cc16989 100644 --- a/back/loaders/db.ts +++ b/back/loaders/db.ts @@ -125,6 +125,6 @@ export default async () => { Logger.info('✌️ DB loaded'); } catch (error) { Logger.info('✌️ DB load failed'); - Logger.info(error); + Logger.error(error); } }; diff --git a/back/loaders/deps.ts b/back/loaders/deps.ts index 3da8bfe8..26f450a8 100644 --- a/back/loaders/deps.ts +++ b/back/loaders/deps.ts @@ -37,7 +37,7 @@ async function linkCommand() { if (fs.existsSync(target)) { fs.unlinkSync(target); } - fs.symlink(source, target, (err) => {}); + fs.symlink(source, target, (err) => { }); } } diff --git a/back/schedule/health.ts b/back/schedule/health.ts index ddc8b5c6..bda0ec9b 100644 --- a/back/schedule/health.ts +++ b/back/schedule/health.ts @@ -24,7 +24,7 @@ const check = async ( `tail -n 300 ~/.pm2/logs/schedule-error.log`, ); return callback( - new Error(`${scheduleErrLog || ''}\n${panelErrLog || ''}\n${res}`), + new Error(`${scheduleErrLog || ''}\n${panelErrLog || ''}\n${res}`.trim()), ); default: diff --git a/back/services/cron.ts b/back/services/cron.ts index ef1eb025..1d915da4 100644 --- a/back/services/cron.ts +++ b/back/services/cron.ts @@ -161,7 +161,7 @@ export default class CronService { case 'In': q[Op.or] = [ { - [property]: value, + [property]: Array.isArray(value) ? value : [value], }, property === 'status' && value.includes(2) ? { isDisabled: 1 } @@ -172,7 +172,7 @@ export default class CronService { q[Op.and] = [ { [property]: { - [Op.notIn]: value, + [Op.notIn]: Array.isArray(value) ? value : [value], }, }, property === 'status' && value.includes(2) diff --git a/sample/notify.py b/sample/notify.py index a3c174c0..63c38f9a 100644 --- a/sample/notify.py +++ b/sample/notify.py @@ -458,7 +458,7 @@ class WeCom: return respone["errmsg"] def send_mpnews(self, title, message, media_id, touser="@all"): - send_url = f"https://{self.HOST}/cgi-bin/message/send?access_token={self.get_access_token()}" + send_url = f"https://{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}" send_values = { "touser": touser, "msgtype": "mpnews", diff --git a/shell/task.sh b/shell/task.sh index 24339810..17bd5d41 100755 --- a/shell/task.sh +++ b/shell/task.sh @@ -14,7 +14,7 @@ single_hanle() { ## 选择python3还是node define_program() { local file_param=$1 - if [[ $file_param == *.js ]]; then + if [[ $file_param == *.js ]] || [[ $file_param == *.mjs ]]; then which_program="node" elif [[ $file_param == *.py ]] || [[ $file_param == *.pyc ]]; then which_program="python3" diff --git a/src/app.ts b/src/app.ts index 4339670e..aae44ab3 100644 --- a/src/app.ts +++ b/src/app.ts @@ -3,13 +3,17 @@ import intl from 'react-intl-universal'; export function rootContainer(container: any) { const locales = { - 'en-US': require('./locales/en-US.json'), - 'zh-CN': require('./locales/zh-CN.json'), + 'en': require('./locales/en-US.json'), + 'zh': require('./locales/zh-CN.json'), }; let currentLocale = intl.determineLocale({ urlLocaleKey: 'lang', cookieLocaleKey: 'lang', - }); + }).slice(0, 2); + + if (!currentLocale || !Object.keys(locales).includes(currentLocale)) { + currentLocale = 'zh'; + } intl.init({ currentLocale, locales }); return container; diff --git a/src/components/name.tsx b/src/components/name.tsx index 7085e06f..bbca8085 100644 --- a/src/components/name.tsx +++ b/src/components/name.tsx @@ -13,7 +13,7 @@ export default function Name< options: Options; }) { const { loading, data } = useRequest(service, options); - console.log(loading, data); + return ( {data?.data?.name} diff --git a/src/locales/en-US.json b/src/locales/en-US.json index f6934212..3376465e 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -396,16 +396,57 @@ "关联订阅": "Associate Subscription", "订阅": "Subscription", "创建": "Create", - "创建订阅成功": "Subscription created successfully", - "gotify的url地址,例如 https://push.example.de:8080": "Gotify URL address, e.g., https://push.example.de:8080", - "BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)": "BARK push icon, custom push icon (requires iOS 15 or above to display)", - "BARK推送铃声,铃声列表去APP查看复制填写": "BARK push ringtone, check the ringtone list in the APP and copy it", - "BARK推送消息的分组, 默认为qinglong": "BARK push message grouping, default is qinglong", - "telegram代理配置认证参数, 用户名与密码用英文冒号连接 user:password": "Telegram proxy configuration authentication parameters, connect username and password with a colon, e.g., user:password", - "企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa": "WeChat Work Bot webhook (see documentation at https://work.weixin.qq.com/api/doc/90000/90136/91770), e.g., 693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa", - "corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcfrs,B-76WERQ,qinglong,1000001,2COat": "corpid, corpsecret, touser (note: separate multiple member IDs with |), agentid, message type (optional, defaults to text message type) – separated by commas (`,`), e.g., wwcfrs, B-76WERQ, qinglong, 1000001, 2COat", - "密钥key,智能微秘书个人中心获取apikey,申请地址:https://wechat.aibotk.com/signup?from=ql": "Key, obtain the API key from the Smart WeChat Assistant's personal center, apply at: https://wechat.aibotk.com/signup?from=ql", - "一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "The 'Group Code' for one-to-many push (under one-to-many push->Your Group (create one if none exists)->Group Code. If you are the creator of the group, you also need to click 'View QR Code' for scanning and binding, otherwise you cannot receive group message push)", "同时删除关联任务和脚本": "Delete associated tasks and scripts as well", - "夹及其子文件": "Folder and its sub-files" + "未找到": "Not Found", + "保存成功": "Saved successfully", + "删除成功": "Deleted successfully", + "批量删除成功": "Batch deleted successfully", + "启动中...": "Starting...", + "任务未运行": "Task not running", + "更新任务成功": "Task updated successfully", + "创建任务成功": "Task created successfully", + "编辑任务": "Edit Task", + "Cron表达式格式有误": "Incorrect Cron Expression Format", + "添加Labels成功": "Labels added successfully", + "删除Labels成功": "Labels deleted successfully", + "编辑视图": "Edit View", + "排序方式": "Sort Order", + "开始时间": "Start Time", + "安装": "Install", + "结束时间": "End Time", + "编辑依赖": "Edit Dependency", + "更新环境变量名称成功": "Environment Variable Name updated successfully", + "更新变量成功": "Variable updated successfully", + "创建变量成功": "Variable created successfully", + "编辑变量": "Edit Variable", + "加载中...": "Loading...", + "夹下所以日志": "Folder and All Subfiles", + "创建文件夹成功": "Folder created successfully", + "创建文件成功": "File created successfully", + "夹及其子文件": "Folder and Its Subfiles", + "更新名称成功": "Name updated successfully", + "保存文件成功": "File saved successfully", + "更新应用成功": "Application updated successfully", + "创建应用成功": "Application created successfully", + "编辑应用": "Edit Application", + "检查更新中...": "Checking for updates...", + "失败,请检查": "Failed, please check", + "更新失败,请检查网络及日志或稍后再试": "Update failed, please check network and logs or try again later", + "更新包下载成功": "Update package download successful", + "重置secret": "Reset secret", + "重置成功": "Reset successful", + "通知发送成功": "Notification sent successfully", + "通知关闭成功": "Notification closed successfully", + "测试中...": "Testing...", + "上传": "Upload", + "下载": "Download", + "更新成功": "Update successful", + "激活成功": "Activation successful", + "验证失败": "Validation failed", + "更新订阅成功": "Subscription updated successfully", + "创建订阅成功": "Subscription created successfully", + "编辑订阅": "Edit Subscription", + "Subscription表达式格式有误": "Incorrect Subscription Expression Format", + "一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "The 'Group Code' for One-to-Many Push (Below One-to-Many Push->Your Group (if not, create one)->Group Code, if you are the creator of the group, you also need to click 'View QR Code' to scan and bind, otherwise you cannot receive group messages)", + "登录已过期,请重新登录": "Login session has expired, please log in again" } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index ee7a3855..47606399 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -147,7 +147,7 @@ "启动中,请稍后...": "启动中,请稍后...", "欢迎使用": "欢迎使用", "欢迎使用青龙": "欢迎使用青龙", - "支持python3、javascript、shell、typescript 的定时任务管理面板": "支持python3、javaScript、shell、typescript 的定时任务管理面板", + "支持python3、javascript、shell、typescript 的定时任务管理面板": "支持python3、javascript、shell、typescript 的定时任务管理面板", "开始安装": "开始安装", "账户设置": "账户设置", "用户名": "用户名", @@ -396,5 +396,57 @@ "关联订阅": "关联订阅", "订阅": "订阅", "创建": "创建", - "同时删除关联任务和脚本": "同时删除关联任务和脚本" + "同时删除关联任务和脚本": "同时删除关联任务和脚本", + "未找到": "未找到", + "保存成功": "保存成功", + "删除成功": "删除成功", + "批量删除成功": "批量删除成功", + "启动中...": "启动中...", + "任务未运行": "任务未运行", + "更新任务成功": "更新任务成功", + "创建任务成功": "创建任务成功", + "编辑任务": "编辑任务", + "Cron表达式格式有误": "Cron表达式格式有误", + "添加Labels成功": "添加Labels成功", + "删除Labels成功": "删除Labels成功", + "编辑视图": "编辑视图", + "排序方式": "排序方式", + "开始时间": "开始时间", + "安装": "安装", + "结束时间": "结束时间", + "编辑依赖": "编辑依赖", + "更新环境变量名称成功": "更新环境变量名称成功", + "更新变量成功": "更新变量成功", + "创建变量成功": "创建变量成功", + "编辑变量": "编辑变量", + "加载中...": "加载中...", + "夹下所以日志": "夹下所以日志", + "创建文件夹成功": "创建文件夹成功", + "创建文件成功": "创建文件成功", + "夹及其子文件": "夹及其子文件", + "更新名称成功": "更新名称成功", + "保存文件成功": "保存文件成功", + "更新应用成功": "更新应用成功", + "创建应用成功": "创建应用成功", + "编辑应用": "编辑应用", + "检查更新中...": "检查更新中...", + "失败,请检查": "失败,请检查", + "更新失败,请检查网络及日志或稍后再试": "更新失败,请检查网络及日志或稍后再试", + "更新包下载成功": "更新包下载成功", + "重置secret": "重置secret", + "重置成功": "重置成功", + "通知发送成功": "通知发送成功", + "通知关闭成功": "通知关闭成功", + "测试中...": "测试中...", + "上传": "上传", + "下载": "下载", + "更新成功": "更新成功", + "激活成功": "激活成功", + "验证失败": "验证失败", + "更新订阅成功": "更新订阅成功", + "创建订阅成功": "创建订阅成功", + "编辑订阅": "编辑订阅", + "Subscription表达式格式有误": "Subscription表达式格式有误", + "一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)", + "登录已过期,请重新登录": "登录已过期,请重新登录" } diff --git a/src/pages/config/index.tsx b/src/pages/config/index.tsx index aae5d5cd..97059631 100644 --- a/src/pages/config/index.tsx +++ b/src/pages/config/index.tsx @@ -55,7 +55,7 @@ const Config = () => { .post(`${config.apiPrefix}configs/save`, { content, name: select }) .then(({ code, data }) => { if (code === 200) { - message.success('保存成功'); + message.success(intl.get('保存成功')); } setConfirmLoading(false); }); diff --git a/src/pages/crontab/detail.tsx b/src/pages/crontab/detail.tsx index f90201ab..37b8e949 100644 --- a/src/pages/crontab/detail.tsx +++ b/src/pages/crontab/detail.tsx @@ -30,7 +30,7 @@ import config from '@/utils/config'; import CronLogModal from './logModal'; import Editor from '@monaco-editor/react'; import IconFont from '@/components/iconfont'; -import { getCommandScript } from '@/utils'; +import { getCommandScript, getEditorMode } from '@/utils'; import VirtualList from 'rc-virtual-list'; import useScrollHeight from '@/hooks/useScrollHeight'; @@ -46,12 +46,6 @@ const tabList = [ tab: intl.get('脚本'), }, ]; -const LangMap: any = { - '.py': 'python', - '.js': 'javascript', - '.sh': 'shell', - '.ts': 'typescript', -}; interface LogItem { directory: string; @@ -109,7 +103,7 @@ const CronDetailModal = ({ ), script: scriptInfo.filename && ( { .delete(`${config.apiPrefix}crons`, { data: [record.id] }) .then(({ code, data }) => { if (code === 200) { - message.success('删除成功'); + message.success(intl.get('删除成功')); const result = [...value]; const i = result.findIndex((x) => x.id === record.id); if (i !== -1) { @@ -729,7 +729,7 @@ const Crontab = () => { .delete(`${config.apiPrefix}crons`, { data: selectedRowIds }) .then(({ code, data }) => { if (code === 200) { - message.success('批量删除成功'); + message.success(intl.get('批量删除成功')); setSelectedRowIds([]); getCrons(); } @@ -905,6 +905,11 @@ const Crontab = () => { setViewConf(view ? view : null); }; + const [vt] = useVT( + () => ({ scroll: { y: tableScrollHeight } }), + [tableScrollHeight], + ); + return ( { rowSelection={rowSelection} rowClassName={getRowClassName} onChange={onPageChange} + components={isPhone || pageConf.size < 50 ? undefined : vt} /> { - const [value, setValue] = useState('启动中...'); + const [value, setValue] = useState(intl.get('启动中...')); const [loading, setLoading] = useState(true); const [executing, setExecuting] = useState(true); const [isPhone, setIsPhone] = useState(false); diff --git a/src/pages/crontab/modal.tsx b/src/pages/crontab/modal.tsx index 33e7876a..2dbbc254 100644 --- a/src/pages/crontab/modal.tsx +++ b/src/pages/crontab/modal.tsx @@ -99,7 +99,7 @@ const CronModal = ({ if (!value || cronParse.parseExpression(value).hasNext()) { return Promise.resolve(); } else { - return Promise.reject('Cron表达式格式有误'); + return Promise.reject(intl.get('Cron表达式格式有误')); } }, }, diff --git a/src/pages/crontab/viewManageModal.tsx b/src/pages/crontab/viewManageModal.tsx index aad73042..4c405de1 100644 --- a/src/pages/crontab/viewManageModal.tsx +++ b/src/pages/crontab/viewManageModal.tsx @@ -157,7 +157,7 @@ const ViewManageModal = ({ .delete(`${config.apiPrefix}crons/views`, { data: [record.id] }) .then(({ code, data }) => { if (code === 200) { - message.success('删除成功'); + message.success(intl.get('删除成功')); cronViewChange(); } }); diff --git a/src/pages/dependence/index.tsx b/src/pages/dependence/index.tsx index 520ea441..611184ba 100644 --- a/src/pages/dependence/index.tsx +++ b/src/pages/dependence/index.tsx @@ -400,7 +400,7 @@ const Dependence = () => { const { type, message, references } = socketMessage; if ( type === 'installDependence' && - message.includes('开始时间') && + message.includes(intl.get('开始时间')) && references.length > 0 ) { const result = [...value]; @@ -409,7 +409,7 @@ const Dependence = () => { if (index !== -1) { result.splice(index, 1, { ...value[index], - status: message.includes('安装') ? Status.安装中 : Status.删除中, + status: message.includes(intl.get('安装')) ? Status.安装中 : Status.删除中, }); } } @@ -417,14 +417,14 @@ const Dependence = () => { } if ( type === 'installDependence' && - message.includes('结束时间') && + message.includes(intl.get('结束时间')) && references.length > 0 ) { let status; - if (message.includes('安装')) { - status = message.includes('成功') ? Status.已安装 : Status.安装失败; + if (message.includes(intl.get('安装'))) { + status = message.includes(intl.get('成功')) ? Status.已安装 : Status.安装失败; } else { - status = message.includes('成功') ? Status.已删除 : Status.删除失败; + status = message.includes(intl.get('成功')) ? Status.已删除 : Status.删除失败; } const result = [...value]; for (let i = 0; i < references.length; i++) { diff --git a/src/pages/dependence/logModal.tsx b/src/pages/dependence/logModal.tsx index 87599139..6713c836 100644 --- a/src/pages/dependence/logModal.tsx +++ b/src/pages/dependence/logModal.tsx @@ -56,8 +56,8 @@ const DependenceLogModal = ({ ) { const log = (data.log || []).join('') as string; setValue(log); - setExecuting(!log.includes('结束时间')); - setIsRemoveFailed(log.includes('删除失败')); + setExecuting(!log.includes(intl.get('结束时间'))); + setIsRemoveFailed(log.includes(intl.get('删除失败'))); } }) .finally(() => { @@ -103,9 +103,9 @@ const DependenceLogModal = ({ references.length > 0 && references.includes(dependence.id) ) { - if (message.includes('结束时间')) { + if (message.includes(intl.get('结束时间'))) { setExecuting(false); - setIsRemoveFailed(message.includes('删除失败')); + setIsRemoveFailed(message.includes(intl.get('删除失败'))); } setValue(`${value}${message}`); } diff --git a/src/pages/diff/index.tsx b/src/pages/diff/index.tsx index 4b6190f9..bf557425 100644 --- a/src/pages/diff/index.tsx +++ b/src/pages/diff/index.tsx @@ -54,7 +54,7 @@ const Diff = () => { }) .then(({ code, data }) => { if (code === 200) { - message.success('保存成功'); + message.success(intl.get('保存成功')); } }); }; diff --git a/src/pages/env/editNameModal.tsx b/src/pages/env/editNameModal.tsx index d0b7cb9d..b10cca2c 100644 --- a/src/pages/env/editNameModal.tsx +++ b/src/pages/env/editNameModal.tsx @@ -25,7 +25,7 @@ const EditNameModal = ({ }); if (code === 200) { - message.success('更新环境变量名称成功'); + message.success(intl.get('更新环境变量名称成功')); handleCancel(); } setLoading(false); diff --git a/src/pages/env/index.tsx b/src/pages/env/index.tsx index 678a3937..b13b4a98 100644 --- a/src/pages/env/index.tsx +++ b/src/pages/env/index.tsx @@ -254,7 +254,7 @@ const Env = () => { .then(({ code, data }) => { if (code === 200) { message.success( - `${record.status === Status.已禁用 ? intl.get('启用') : intl.get('禁用')}成功`, + `${record.status === Status.已禁用 ? intl.get('启用') : intl.get('禁用')}${intl.get('成功')}`, ); const newStatus = record.status === Status.已禁用 ? Status.已启用 : Status.已禁用; @@ -300,7 +300,7 @@ const Env = () => { .delete(`${config.apiPrefix}envs`, { data: [record.id] }) .then(({ code, data }) => { if (code === 200) { - message.success('删除成功'); + message.success(intl.get('删除成功')); const result = [...value]; result.splice(index, 1); setValue(result); @@ -420,7 +420,7 @@ const Env = () => { .delete(`${config.apiPrefix}envs`, { data: selectedRowIds }) .then(({ code, data }) => { if (code === 200) { - message.success('批量删除成功'); + message.success(intl.get('批量删除成功')); setSelectedRowIds([]); getEnvs(); } diff --git a/src/pages/error/index.tsx b/src/pages/error/index.tsx index 7a0572d4..30a5cc88 100644 --- a/src/pages/error/index.tsx +++ b/src/pages/error/index.tsx @@ -9,17 +9,22 @@ import { SharedContext } from '@/layouts'; import { Alert, Typography } from 'antd'; const Error = () => { - const { user, theme, reloadUser } = useOutletContext(); + const { user } = useOutletContext(); const [loading, setLoading] = useState(false); - const [data, setData] = useState('暂无日志'); + const [data, setData] = useState(intl.get('暂无日志')); const retryTimes = useRef(1); - const getLog = (needLoading: boolean = true) => { + const getHealthStatus = (needLoading: boolean = true) => { needLoading && setLoading(true); request .get(`${config.apiPrefix}public/health`) .then(({ error, data }) => { if (data?.status === 1) { + if (retryTimes.current > 1) { + setTimeout(() => { + window.location.reload(); + }); + } return; } if (retryTimes.current > 3) { @@ -28,7 +33,7 @@ const Error = () => { } retryTimes.current += 1; setTimeout(() => { - getLog(false); + getHealthStatus(false); }, 3000); }) .finally(() => needLoading && setLoading(false)); @@ -41,7 +46,7 @@ const Error = () => { }, [user]); useEffect(() => { - getLog(); + getHealthStatus(); }, []); return ( @@ -69,7 +74,7 @@ const Error = () => {
{intl.get('2. 容器内执行 ql -l check、ql -l update')}
{intl.get( - '3. 如果无法解决,容器内执行 pm2 logs,拷贝执行结果', + '3. 如果无法解决,容器内执行 pm2 logs,拷贝执行结果' )} {intl.get('提交 issue')} diff --git a/src/pages/log/index.tsx b/src/pages/log/index.tsx index 9b0bfdd9..7bd4d796 100644 --- a/src/pages/log/index.tsx +++ b/src/pages/log/index.tsx @@ -75,7 +75,7 @@ const Log = () => { return; } - setValue('加载中...'); + setValue(intl.get('加载中...')); getLog(node); }; diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index f66a9097..5dc22945 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -187,7 +187,9 @@ const Login = () => {
diff --git a/src/pages/script/editModal.tsx b/src/pages/script/editModal.tsx index 58bcc64e..e6995d86 100644 --- a/src/pages/script/editModal.tsx +++ b/src/pages/script/editModal.tsx @@ -8,21 +8,9 @@ import Editor from '@monaco-editor/react'; import SaveModal from './saveModal'; import SettingModal from './setting'; import { useTheme } from '@/utils/hooks'; -import { logEnded } from '@/utils'; +import { getEditorMode, logEnded } from '@/utils'; const { Option } = Select; -const LangMap: any = { - '.py': 'python', - '.js': 'javascript', - '.sh': 'shell', - '.ts': 'typescript', -}; -const prefixMap: any = { - python: '.py', - javascript: '.js', - shell: '.sh', - typescript: '.ts', -}; const EditModal = ({ treeData, @@ -65,7 +53,7 @@ const EditModal = ({ return; } - const newMode = LangMap[value.slice(-3)] || ''; + const newMode = getEditorMode(value); setCNode(node); setLanguage(newMode); getDetail(node); @@ -145,7 +133,7 @@ const EditModal = ({ setCNode(currentNode); setValue(content as string); setSelectedKey(currentNode.key); - const newMode = LangMap[currentNode.title.slice(-3)] || ''; + const newMode = getEditorMode(currentNode.title); setLanguage(newMode); } }, [content, currentNode]); diff --git a/src/pages/script/index.tsx b/src/pages/script/index.tsx index fa6d6e86..5901cb1d 100644 --- a/src/pages/script/index.tsx +++ b/src/pages/script/index.tsx @@ -37,7 +37,7 @@ import EditScriptNameModal from './editNameModal'; import debounce from 'lodash/debounce'; import { history, useOutletContext, useLocation } from '@umijs/max'; import { parse } from 'query-string'; -import { depthFirstSearch, findNode } from '@/utils'; +import { depthFirstSearch, findNode, getEditorMode } from '@/utils'; import { SharedContext } from '@/layouts'; import useFilterTreeData from '@/hooks/useFilterTreeData'; import uniq from 'lodash/uniq'; @@ -46,13 +46,6 @@ import RenameModal from './renameModal'; const { Text } = Typography; -const LangMap: any = { - '.py': 'python', - '.js': 'javascript', - '.sh': 'shell', - '.ts': 'typescript', -}; - const Script = () => { const { headerStyle, isPhone, theme, socketMessage } = useOutletContext(); @@ -133,9 +126,9 @@ const Script = () => { return; } - const newMode = value ? LangMap[value.slice(-3)] : ''; + const newMode = getEditorMode(value); setMode(isPhone && newMode === 'typescript' ? 'javascript' : newMode); - setValue('加载中...'); + setValue(intl.get('加载中...')); getDetail(node); }; @@ -201,7 +194,7 @@ const Script = () => { const cancelEdit = () => { setIsEditing(false); - setValue('加载中...'); + setValue(intl.get('加载中...')); getDetail(currentNode); }; diff --git a/src/pages/script/renameModal.tsx b/src/pages/script/renameModal.tsx index 86e033aa..29b84649 100644 --- a/src/pages/script/renameModal.tsx +++ b/src/pages/script/renameModal.tsx @@ -29,7 +29,7 @@ const RenameModal = ({ ); if (code === 200) { - message.success('更新名称成功'); + message.success(intl.get('更新名称成功')); handleCancel(); } setLoading(false); diff --git a/src/pages/script/saveModal.tsx b/src/pages/script/saveModal.tsx index 52dedaea..fc7a81b8 100644 --- a/src/pages/script/saveModal.tsx +++ b/src/pages/script/saveModal.tsx @@ -23,7 +23,7 @@ const SaveModal = ({ .post(`${config.apiPrefix}scripts`, payload) .then(({ code, data }) => { if (code === 200) { - message.success('保存文件成功'); + message.success(intl.get('保存文件成功')); handleCancel(data); } setLoading(false); diff --git a/src/pages/script/setting.tsx b/src/pages/script/setting.tsx index 54758286..40f85a94 100644 --- a/src/pages/script/setting.tsx +++ b/src/pages/script/setting.tsx @@ -23,7 +23,7 @@ const SettingModal = ({ .post(`${config.apiPrefix}scripts`, payload) .then(({ code, data }) => { if (code === 200) { - message.success('保存文件成功'); + message.success(intl.get('保存文件成功')); handleCancel(data); } setLoading(false); diff --git a/src/pages/setting/about.tsx b/src/pages/setting/about.tsx index 491edf53..6c7369d6 100644 --- a/src/pages/setting/about.tsx +++ b/src/pages/setting/about.tsx @@ -10,6 +10,7 @@ const { Link } = Typography; enum TVersion { 'develop' = '开发版', 'master' = '正式版', + 'debian' = '正式版' } const About = ({ systemInfo }: { systemInfo: SharedContext['systemInfo'] }) => { diff --git a/src/pages/setting/checkUpdate.tsx b/src/pages/setting/checkUpdate.tsx index d4d29a46..36078458 100644 --- a/src/pages/setting/checkUpdate.tsx +++ b/src/pages/setting/checkUpdate.tsx @@ -14,7 +14,7 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => { const checkUpgrade = () => { if (updateLoading) return; setUpdateLoading(true); - message.loading('检查更新中...', 0); + message.loading(intl.get('检查更新中...'), 0); request .put(`${config.apiPrefix}system/update-check`) .then(({ code, data }) => { @@ -177,7 +177,7 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => { } const newMessage = `${value}${_message}`; - const updateFailed = newMessage.includes('失败'); + const updateFailed = newMessage.includes(intl.get('失败')); modalRef.current.update({ maskClosable: updateFailed, @@ -198,8 +198,8 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => { ), }); - if (updateFailed && !value.includes('失败,请检查')) { - message.error('更新失败,请检查网络及日志或稍后再试'); + if (updateFailed && !value.includes(intl.get('失败,请检查'))) { + message.error(intl.get('更新失败,请检查网络及日志或稍后再试')); } setValue(newMessage); @@ -209,7 +209,7 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => { .getElementById('log-identifier')! .scrollIntoView({ behavior: 'smooth', block: 'nearest' }); - if (_message.includes('更新包下载成功')) { + if (_message.includes(intl.get('更新包下载成功'))) { setTimeout(() => { showReloadModal(); }, 1000); diff --git a/src/pages/setting/index.tsx b/src/pages/setting/index.tsx index 8e20860b..90fe677e 100644 --- a/src/pages/setting/index.tsx +++ b/src/pages/setting/index.tsx @@ -154,7 +154,7 @@ const Setting = () => { .delete(`${config.apiPrefix}apps`, { data: [record.id] }) .then(({ code, data }) => { if (code === 200) { - message.success('删除成功'); + message.success(intl.get('删除成功')); const result = [...dataSource]; result.splice(index, 1); setDataSource(result); @@ -188,7 +188,7 @@ const Setting = () => { .put(`${config.apiPrefix}apps/${record.id}/reset-secret`) .then(({ code, data }) => { if (code === 200) { - message.success('重置成功'); + message.success(intl.get('重置成功')); handleApp(data); } }); diff --git a/src/pages/setting/other.tsx b/src/pages/setting/other.tsx index 075d6aeb..7046e8d4 100644 --- a/src/pages/setting/other.tsx +++ b/src/pages/setting/other.tsx @@ -41,8 +41,8 @@ const Other = ({ const [form] = Form.useForm(); const modalRef = useRef(); const [exportLoading, setExportLoading] = useState(false); - const showUploadProgress = useProgress('上传'); - const showDownloadProgress = useProgress('下载'); + const showUploadProgress = useProgress(intl.get('上传')); + const showDownloadProgress = useProgress(intl.get('下载')); const { enable: enableDarkMode, @@ -85,7 +85,7 @@ const Other = ({ .put(`${config.apiPrefix}system/config`, systemConfig) .then(({ code, data }) => { if (code === 200) { - message.success('更新成功'); + message.success(intl.get('更新成功')); } }) .catch((error: any) => { @@ -162,7 +162,7 @@ const Other = ({ return ( diff --git a/src/pages/setting/security.tsx b/src/pages/setting/security.tsx index 7bae87ae..d20f57ac 100644 --- a/src/pages/setting/security.tsx +++ b/src/pages/setting/security.tsx @@ -67,12 +67,12 @@ const SecuritySettings = ({ user, userChange }: any) => { .then(({ code, data }) => { if (code === 200) { if (data) { - message.success('激活成功'); + message.success(intl.get('激活成功')); setTwoFactoring(false); setTwoFactorActivated(true); userChange(); } else { - message.success('验证失败'); + message.success(intl.get('验证失败')); } } }) diff --git a/src/pages/subscription/index.tsx b/src/pages/subscription/index.tsx index 5dbfc314..d27577e7 100644 --- a/src/pages/subscription/index.tsx +++ b/src/pages/subscription/index.tsx @@ -366,7 +366,7 @@ const Subscription = () => { }) .then(({ code, data }) => { if (code === 200) { - message.success('删除成功'); + message.success(intl.get('删除成功')); const result = [...value]; const i = result.findIndex((x) => x.id === record.id); if (i !== -1) { diff --git a/src/pages/subscription/logModal.tsx b/src/pages/subscription/logModal.tsx index 51bb292e..09df132b 100644 --- a/src/pages/subscription/logModal.tsx +++ b/src/pages/subscription/logModal.tsx @@ -23,7 +23,7 @@ const SubscriptionLogModal = ({ data?: string; logUrl?: string; }) => { - const [value, setValue] = useState('启动中...'); + const [value, setValue] = useState(intl.get('启动中...')); const [loading, setLoading] = useState(true); const [executing, setExecuting] = useState(true); const [isPhone, setIsPhone] = useState(false); diff --git a/src/pages/subscription/modal.tsx b/src/pages/subscription/modal.tsx index a3e5795c..21d8ffb3 100644 --- a/src/pages/subscription/modal.tsx +++ b/src/pages/subscription/modal.tsx @@ -392,7 +392,7 @@ const SubscriptionModal = ({ ) { return Promise.resolve(); } else { - return Promise.reject('Subscription表达式格式有误'); + return Promise.reject(intl.get('Subscription表达式格式有误')); } }, }, diff --git a/src/utils/config.ts b/src/utils/config.ts index 074d7c22..826e2307 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -105,7 +105,7 @@ export default { gotify: [ { label: 'gotifyUrl', - tip: intl.get('gotify的url地址,例如 https://push.example.de:8080'), + tip: intl.get('gotify的url地址,例如 https://push.example.de:8080'), required: true, }, { @@ -126,16 +126,14 @@ export default { goCqHttpBot: [ { label: 'goCqHttpBotUrl', - tip: intl.get( - '推送到个人QQ: http://127.0.0.1/send_private_msg,群:http://127.0.0.1/send_group_msg', + tip: intl.get('推送到个人QQ: http://127.0.0.1/send_private_msg,群:http://127.0.0.1/send_group_msg', ), required: true, }, { label: 'goCqHttpBotToken', tip: intl.get('访问密钥'), required: true }, { label: 'goCqHttpBotQq', - tip: intl.get( - '如果GOBOT_URL设置 /send_private_msg 则需要填入 user_id=个人QQ 相反如果是 /send_group_msg 则需要填入 group_id=QQ群', + tip: intl.get('如果GOBOT_URL设置 /send_private_msg 则需要填入 user_id=个人QQ 相反如果是 /send_group_msg 则需要填入 group_id=QQ群', ), required: true, }, @@ -155,26 +153,24 @@ export default { }, { label: 'pushDeerUrl', - tip: intl.get( - 'PushDeer的自架API endpoint,默认是 https://api2.pushdeer.com/message/push', + tip: intl.get('PushDeer的自架API endpoint,默认是 https://api2.pushdeer.com/message/push', ), }, ], bark: [ { label: 'barkPush', - tip: intl.get( - 'Bark的信息IP/设备码,例如:https://api.day.app/XXXXXXXX', + tip: intl.get('Bark的信息IP/设备码,例如:https://api.day.app/XXXXXXXX', ), required: true, }, { label: 'barkIcon', - tip: intl.get('BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)'), + tip: intl.get('BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)'), }, { label: 'barkSound', - tip: intl.get('BARK推送铃声,铃声列表去APP查看复制填写'), + tip: intl.get('BARK推送铃声,铃声列表去APP查看复制填写'), }, { label: 'barkGroup', @@ -184,8 +180,7 @@ export default { telegramBot: [ { label: 'telegramBotToken', - tip: intl.get( - 'telegram机器人的token,例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw', + tip: intl.get('telegram机器人的token,例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw', ), required: true, }, @@ -198,8 +193,7 @@ export default { { label: 'telegramBotProxyPort', tip: intl.get('代理端口') }, { label: 'telegramBotProxyAuth', - tip: intl.get( - 'telegram代理配置认证参数, 用户名与密码用英文冒号连接 user:password', + tip: intl.get('telegram代理配置认证参数,用户名与密码用英文冒号连接 user:password', ), }, { @@ -210,23 +204,20 @@ export default { dingtalkBot: [ { label: 'dingtalkBotToken', - tip: intl.get( - '钉钉机器人webhook token,例如:5a544165465465645d0f31dca676e7bd07415asdasd', + tip: intl.get('钉钉机器人webhook token,例如:5a544165465465645d0f31dca676e7bd07415asdasd', ), required: true, }, { label: 'dingtalkBotSecret', - tip: intl.get( - '密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串', + tip: intl.get('密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串', ), }, ], weWorkBot: [ { label: 'weWorkBotKey', - tip: intl.get( - '企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa', + tip: intl.get('企业微信机器人的webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa', ), required: true, }, @@ -238,8 +229,7 @@ export default { weWorkApp: [ { label: 'weWorkAppKey', - tip: intl.get( - 'corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcfrs,B-76WERQ,qinglong,1000001,2COat', + tip: intl.get('corpid、corpsecret、touser(注:多个成员ID使用|隔开)、agentid、消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcfrs,B-76WERQ,qinglong,1000001,2COat', ), required: true, }, @@ -251,8 +241,7 @@ export default { aibotk: [ { label: 'aibotkKey', - tip: intl.get( - '密钥key,智能微秘书个人中心获取apikey,申请地址:https://wechat.aibotk.com/signup?from=ql', + tip: intl.get('密钥key,智能微秘书个人中心获取apikey,申请地址:https://wechat.aibotk.com/signup?from=ql', ), required: true, }, @@ -268,8 +257,7 @@ export default { }, { label: 'aibotkName', - tip: intl.get( - '要发送的用户昵称或群名,如果目标是群,需要填群名,如果目标是好友,需要填好友昵称', + tip: intl.get('要发送的用户昵称或群名,如果目标是群,需要填群名,如果目标是好友,需要填好友昵称', ), required: true, }, @@ -277,8 +265,7 @@ export default { iGot: [ { label: 'iGotPushKey', - tip: intl.get( - 'iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX', + tip: intl.get('iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX', ), required: true, }, @@ -286,23 +273,20 @@ export default { pushPlus: [ { label: 'pushPlusToken', - tip: intl.get( - '微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/', + tip: intl.get('微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/', ), required: true, }, { label: 'pushPlusUser', - tip: intl.get( - '一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)', + tip: intl.get('一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)', ), }, ], lark: [ { label: 'larkKey', - tip: intl.get( - '飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973', + tip: intl.get('飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973', ), required: true, }, @@ -310,8 +294,7 @@ export default { email: [ { label: 'emailService', - tip: intl.get( - '邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://nodemailer.com/smtp/well-known/', + tip: intl.get('邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://nodemailer.com/smtp/well-known/', ), required: true, }, @@ -344,8 +327,7 @@ export default { }, { label: 'webhookUrl', - tip: intl.get( - '请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置', + tip: intl.get('请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置', ), required: true, placeholder: 'https://xxx.cn/api?content=$title\n', @@ -357,8 +339,7 @@ export default { }, { label: 'webhookBody', - tip: intl.get( - '请求体格式key1: value1,多个换行分割。url或者body中必须包含$title,$content可选,对应api内容的位置', + tip: intl.get('请求体格式key1: value1,多个换行分割。url或者body中必须包含$title,$content可选,对应api内容的位置', ), placeholder: 'key1: $title\nkey2: $content', }, diff --git a/src/utils/const.ts b/src/utils/const.ts index 51f1fe0b..dd45e08d 100644 --- a/src/utils/const.ts +++ b/src/utils/const.ts @@ -1 +1,9 @@ export const LOG_END_SYMBOL = '     '; + +export const LANG_MAP = { + '.py': 'python', + '.js': 'javascript', + '.mjs': 'javascript', + '.sh': 'shell', + '.ts': 'typescript', +}; diff --git a/src/utils/http.ts b/src/utils/http.ts index ada85f1a..cee0fd00 100644 --- a/src/utils/http.ts +++ b/src/utils/http.ts @@ -1,3 +1,4 @@ +import intl from 'react-intl-universal' import { message } from 'antd'; import config from './config'; import { history } from '@umijs/max'; @@ -32,7 +33,7 @@ const errorHandler = function (error: AxiosError) { history.push('/error'); } else if (responseStatus === 401) { if (history.location.pathname !== '/login') { - message.error('登录已过期,请重新登录'); + message.error(intl.get('登录已过期,请重新登录')); localStorage.removeItem(config.authKey); history.push('/login'); } diff --git a/src/utils/index.ts b/src/utils/index.ts index a96262b4..28866e71 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,5 @@ import intl from 'react-intl-universal'; -import { LOG_END_SYMBOL } from './const'; +import { LANG_MAP, LOG_END_SYMBOL } from './const'; import cron_parser from 'cron-parser'; export default function browserType() { @@ -154,9 +154,9 @@ export default function browserType() { shell === 'none' ? {} : { - shell, // wechat qq uc 360 2345 sougou liebao maxthon - shellVs, - }, + shell, // wechat qq uc 360 2345 sougou liebao maxthon + shellVs, + }, ); console.log( @@ -335,7 +335,18 @@ export function parseCrontab(schedule: string): Date { if (time) { return time.next().toDate(); } - } catch (error) {} + } catch (error) { } return new Date('1970'); } + +export function getExtension(filename: string) { + if (!filename) return ''; + const arr = filename.split('.'); + return `.${arr[arr.length - 1]}`; +} + +export function getEditorMode(filename: string) { + const extension = getExtension(filename) as keyof typeof LANG_MAP; + return LANG_MAP[extension]; +} \ No newline at end of file diff --git a/version.yaml b/version.yaml index b07b1eca..943cc5fa 100644 --- a/version.yaml +++ b/version.yaml @@ -1,6 +1,12 @@ -version: 2.15.20 -changeLogLink: https://t.me/jiao_long/386 -publishTime: 2023-07-22 16:00 +version: 2.16.0 +changeLogLink: https://t.me/jiao_long/388 +publishTime: 2023-08-06 16:00 changeLog: | - 1. 修复判断 linux 依赖已安装逻辑 - 2. 修复未启动完成时,页面提示 500 + 1. 多语言支持英文界面 + 2. 定时任务增加关联订阅 + 3. 删除订阅支持自动删除任务和脚本 + 4. 定时任务支持运行 mjs 后缀文件 + 5. PushMe消息通道增加 params 参数 + 6. 修复 6 位 cron 不以 task 开头定时任务运行失败 + 7. 修复任务详情日志列表过多卡顿 + 8. 修复定时任务列表虚拟滚动