From 999d9f8e01decd56a2a8ff1342845d139c1f3726 Mon Sep 17 00:00:00 2001 From: whyour Date: Sat, 5 Mar 2022 01:24:52 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E8=AF=A6=E6=83=85=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=97=A5=E5=BF=97=E5=88=97=E8=A1=A8=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .umirc.ts | 1 + back/api/cron.ts | 20 + back/services/cron.ts | 34 + package.json | 94 +- src/pages/crontab/detail.tsx | 113 +- src/pages/crontab/index.less | 7 + src/pages/crontab/index.tsx | 15 +- src/pages/crontab/logModal.tsx | 10 +- yarn.lock | 11730 ------------------------------- 10 files changed, 235 insertions(+), 11790 deletions(-) delete mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore index cb4233d3..94af1ace 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /node_modules /npm-debug.log* /yarn-error.log +/yarn.lock /pnpm-lock.yaml /package-lock.json diff --git a/.umirc.ts b/.umirc.ts index 5222bea4..16204613 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -10,6 +10,7 @@ export default defineConfig({ }, fastRefresh: {}, esbuild: {}, + webpack5: {}, dynamicImport: { loading: '@/components/pageLoading', }, diff --git a/back/api/cron.ts b/back/api/cron.ts index 2c9f292a..da3c7a2f 100644 --- a/back/api/cron.ts +++ b/back/api/cron.ts @@ -333,4 +333,24 @@ export default (app: Router) => { } }, ); + + route.get( + '/:id/logs', + celebrate({ + params: Joi.object({ + id: Joi.number().required(), + }), + }), + async (req: Request, res: Response, next: NextFunction) => { + const logger: Logger = Container.get('logger'); + try { + const cronService = Container.get(CronService); + const data = await cronService.logs(parseInt(req.params.id)); + return res.send({ code: 200, data }); + } catch (e) { + logger.error('🔥 error: %o', e); + return next(e); + } + }, + ); }; diff --git a/back/services/cron.ts b/back/services/cron.ts index 4c8d1a08..c78c349c 100644 --- a/back/services/cron.ts +++ b/back/services/cron.ts @@ -347,6 +347,40 @@ export default class CronService { } } + public async logs(id: number) { + const doc = await this.getDb({ id }); + if (!doc) { + return []; + } + + const [, commandStr, url] = doc.command.split(/ +/); + let logPath = this.getKey(commandStr); + const isQlCommand = doc.command.startsWith('ql '); + const key = + (url && ['repo', 'raw'].includes(commandStr) && this.getKey(url)) || + logPath; + if (isQlCommand) { + logPath = 'update'; + } + let logDir = `${config.logPath}${logPath}`; + if (existsSync(logDir)) { + let files = await promises.readdir(logDir); + console.log(files); + if (isQlCommand) { + files = files.filter((x) => x.includes(key)); + } + return files + .map((x) => ({ + filename: x, + directory: logPath, + time: fs.statSync(`${logDir}/${x}`).mtime.getTime(), + })) + .sort((a, b) => b.time - a.time); + } else { + return []; + } + } + private getKey(command: string) { const start = command.lastIndexOf('/') !== -1 ? command.lastIndexOf('/') + 1 : 0; diff --git a/package.json b/package.json index bccd7231..1ecf238c 100644 --- a/package.json +++ b/package.json @@ -26,16 +26,16 @@ }, "dependencies": { "@otplib/preset-default": "^12.0.1", - "@sentry/node": "^6.17.2", - "@sentry/tracing": "^6.17.2", - "body-parser": "^1.19.0", - "celebrate": "^13.0.3", - "chokidar": "^3.5.2", + "@sentry/node": "^6.18.1", + "@sentry/tracing": "^6.18.1", + "body-parser": "^1.19.2", + "celebrate": "^15.0.1", + "chokidar": "^3.5.3", "cors": "^2.8.5", - "cron-parser": "^3.5.0", - "dotenv": "^8.2.0", - "express": "^4.17.1", - "express-jwt": "^6.0.0", + "cron-parser": "^4.2.1", + "dotenv": "^16.0.0", + "express": "^4.17.3", + "express-jwt": "^6.1.1", "express-urlrewrite": "^1.4.0", "got": "^11.8.2", "hpagent": "^0.1.2", @@ -43,55 +43,55 @@ "jsonwebtoken": "^8.5.1", "lodash": "^4.17.21", "nedb": "^1.8.0", - "node-fetch": "^2.6.1", - "node-schedule": "^2.0.0", - "nodemailer": "^6.7.0", - "p-queue": "6.6.2", + "node-fetch": "^3.2.1", + "node-schedule": "^2.1.0", + "nodemailer": "^6.7.2", + "p-queue": "7.2.0", "reflect-metadata": "^0.1.13", - "sequelize": "^7.0.0-alpha.3", + "sequelize": "^6.17.0", "serve-handler": "^6.1.3", - "sockjs": "^0.3.21", + "sockjs": "^0.3.24", "sqlite3": "^5.0.2", "toad-scheduler": "^1.6.0", - "typedi": "^0.8.0", + "typedi": "^0.10.0", "uuid": "^8.3.2", - "winston": "^3.3.3", - "yargs": "^17.2.1" + "winston": "^3.6.0", + "yargs": "^17.3.1" }, "devDependencies": { - "@ant-design/icons": "^4.6.2", - "@ant-design/pro-layout": "^6.26.0", + "@ant-design/icons": "^4.7.0", + "@ant-design/pro-layout": "^6.33.1", "@monaco-editor/react": "^4.3.1", - "@sentry/react": "^6.17.2", - "@types/cors": "^2.8.10", - "@types/express": "^4.17.8", - "@types/express-jwt": "^6.0.1", - "@types/jsonwebtoken": "^8.5.0", - "@types/lodash": "^4.14.170", + "@sentry/react": "^6.18.1", + "@types/cors": "^2.8.12", + "@types/express": "^4.17.13", + "@types/express-jwt": "^6.0.4", + "@types/jsonwebtoken": "^8.5.8", + "@types/lodash": "^4.14.179", "@types/nedb": "^1.8.12", - "@types/node": "^14.11.2", - "@types/node-fetch": "^2.5.8", + "@types/node": "^17.0.21", + "@types/node-fetch": "^2.6.1", "@types/node-schedule": "^1.3.2", "@types/nodemailer": "^6.4.4", - "@types/qrcode.react": "^1.0.1", - "@types/react": "^17.0.0", - "@types/react-dom": "^17.0.0", + "@types/qrcode.react": "^1.0.2", + "@types/react": "^17.0.39", + "@types/react-dom": "^17.0.13", "@types/serve-handler": "^6.1.1", "@types/sockjs": "^0.3.33", "@types/sockjs-client": "^1.5.1", - "@types/uuid": "^8.3.3", - "@umijs/plugin-antd": "^0.11.0", + "@types/uuid": "^8.3.4", + "@umijs/plugin-antd": "^0.15.0", "@umijs/plugin-esbuild": "^1.4.1", - "@umijs/test": "^3.3.9", + "@umijs/test": "^3.5.21", "ansi-to-react": "^6.1.6", - "antd": "^4.17.0-alpha.6", - "codemirror": "^5.62.2", - "compression-webpack-plugin": "6.1.1", + "antd": "^4.18.9", + "codemirror": "^5.65.2", + "compression-webpack-plugin": "9.2.0", "concurrently": "^7.0.0", - "darkreader": "4.9.40", - "lint-staged": "^10.0.7", - "nodemon": "^2.0.4", - "prettier": "^2.2.0", + "darkreader": "4.9.44", + "lint-staged": "^12.3.4", + "nodemon": "^2.0.15", + "prettier": "^2.5.1", "qiniu": "^7.4.0", "qrcode.react": "^1.0.1", "react": "17.x", @@ -101,13 +101,13 @@ "react-dnd-html5-backend": "^14.0.0", "react-dom": "17.x", "react-split-pane": "^0.1.92", - "sockjs-client": "^1.5.2", - "ts-node": "^9.0.0", - "typescript": "^4.1.2", - "umi": "^3.5.0", - "umi-request": "^1.3.5", + "sockjs-client": "^1.6.0", + "ts-node": "^10.6.0", + "typescript": "^4.6.2", + "umi": "^3.5.21", + "umi-request": "^1.4.0", "vh-check": "^2.0.5", - "webpack": "^5.28.0", + "webpack": "^5.70.0", "yorkie": "^2.0.0" } } diff --git a/src/pages/crontab/detail.tsx b/src/pages/crontab/detail.tsx index c99e30d8..151280b9 100644 --- a/src/pages/crontab/detail.tsx +++ b/src/pages/crontab/detail.tsx @@ -7,7 +7,7 @@ import { Button, Card, Tag, - Popover, + List, Divider, } from 'antd'; import { @@ -15,14 +15,14 @@ import { CloseCircleOutlined, FieldTimeOutlined, Loading3QuartersOutlined, + FileOutlined, } from '@ant-design/icons'; import { CrontabStatus } from './index'; import { diffTime } from '@/utils/date'; - -const contentList: any = { - log:

log content

, - script:

script content

, -}; +import { request } from '@/utils/http'; +import config from '@/utils/config'; +import CronLogModal from './logModal'; +import Editor from '@monaco-editor/react'; const tabList = [ { @@ -35,23 +35,114 @@ const tabList = [ }, ]; +interface LogItem { + directory: string; + filename: string; +} + const language = navigator.language || navigator.languages[0]; const CronDetailModal = ({ cron = {}, handleCancel, visible, + theme, }: { cron?: any; visible: boolean; handleCancel: (needUpdate?: boolean) => void; + theme: string; }) => { const [activeTabKey, setActiveTabKey] = useState('log'); + const [loading, setLoading] = useState(true); + const [logs, setLogs] = useState([]); + const [log, setLog] = useState(''); + const [value, setValue] = useState(''); + const [isLogModalVisible, setIsLogModalVisible] = useState(false); + + const contentList: any = { + log: ( + ( + onClickItem(item)}> + + {item.directory}/{item.filename} + + )} + /> + ), + script: ( + + ), + }; + + const onClickItem = (item: LogItem) => { + request + .get(`${config.apiPrefix}logs/${item.directory}/${item.filename}`) + .then((data) => { + setLog(data.data); + setIsLogModalVisible(true); + }); + }; const onTabChange = (key: string) => { setActiveTabKey(key); }; + const getLogs = () => { + setLoading(true); + request + .get(`${config.apiPrefix}crons/${cron.id}/logs`) + .then((data: any) => { + if (data.code === 200) { + setLogs(data.data); + } + }) + .finally(() => setLoading(false)); + }; + + const getScript = () => { + const cmd = cron.command.split(' ') as string[]; + if (cmd[0] === 'task') { + if (cmd[1].startsWith('/ql/data/scripts')) { + cmd[1] = cmd[1].replace('/ql/data/scripts/', ''); + } + + let [p, s] = cmd[1].split('/'); + if (!s) { + s = p; + p = ''; + } + request + .get(`${config.apiPrefix}scripts/${s}?path=${p || ''}`) + .then((data) => { + setValue(data.data); + }); + } + }; + + useEffect(() => { + if (cron && cron.id) { + getLogs(); + getScript(); + } + }, [cron]); + return ( -
+
状态
@@ -158,6 +249,14 @@ const CronDetailModal = ({ {contentList[activeTabKey]}
+ { + setIsLogModalVisible(false); + }} + cron={cron} + data={log} + /> ); }; diff --git a/src/pages/crontab/index.less b/src/pages/crontab/index.less index 6405f1ad..b127061f 100644 --- a/src/pages/crontab/index.less +++ b/src/pages/crontab/index.less @@ -19,3 +19,10 @@ margin-top: 18px; } } + +.log-item { + cursor: pointer; + &:hover { + background: #fafafa; + } +} diff --git a/src/pages/crontab/index.tsx b/src/pages/crontab/index.tsx index 3b546297..03b43ce4 100644 --- a/src/pages/crontab/index.tsx +++ b/src/pages/crontab/index.tsx @@ -70,7 +70,7 @@ enum OperationPath { 'unpin', } -const Crontab = ({ headerStyle, isPhone }: any) => { +const Crontab = ({ headerStyle, isPhone, theme }: any) => { const columns: any = [ { title: '任务名', @@ -90,14 +90,16 @@ const Crontab = ({ headerStyle, isPhone }: any) => { trigger={isPhone ? 'click' : 'hover'} content={
- {record.labels?.map((label: string, i: number) => ( + {record.labels?.map((label: string) => ( { - onSearch(`label:${label}`); + style={{ cursor: 'point' }} + onClick={(e) => { + e.stopPropagation(); + setSearchText(`label:${label}`); }} > - {label} + {label} ))}
@@ -838,7 +840,9 @@ const Crontab = ({ headerStyle, isPhone }: any) => { placeholder="请输入名称或者关键词" style={{ width: 'auto' }} enterButton + allowClear loading={loading} + value={searchText} onSearch={onSearch} />,