修复 command-run 接口日志绑定

This commit is contained in:
whyour 2025-07-12 20:29:44 +08:00
parent 0587644a6b
commit 50769c43dd
6 changed files with 79 additions and 83 deletions

View File

@ -279,14 +279,14 @@ export default (app: Router) => {
res.end(); res.end();
}, },
onError: async (message: string) => { onError: async (message: string) => {
res.write(`\n${message}`); res.write(message);
const absolutePath = await handleLogPath(logPath); const absolutePath = await handleLogPath(logPath);
await fs.appendFile(absolutePath, `\n${message}`); await fs.appendFile(absolutePath, message);
}, },
onLog: async (message: string) => { onLog: async (message: string) => {
res.write(`\n${message}`); res.write(message);
const absolutePath = await handleLogPath(logPath); const absolutePath = await handleLogPath(logPath);
await fs.appendFile(absolutePath, `\n${message}`); await fs.appendFile(absolutePath, message);
}, },
}, },
); );

View File

@ -573,7 +573,7 @@ export default class CronService {
return typeof doc.status === 'number' && return typeof doc.status === 'number' &&
[CrontabStatus.queued, CrontabStatus.running].includes(doc.status) [CrontabStatus.queued, CrontabStatus.running].includes(doc.status)
? '运行中...' ? '运行中...'
: '任务空闲中'; : '日志不存在...';
} }
} }

View File

@ -47,7 +47,7 @@ export default class SystemService {
@Inject('logger') private logger: winston.Logger, @Inject('logger') private logger: winston.Logger,
private scheduleService: ScheduleService, private scheduleService: ScheduleService,
private sockService: SockService, private sockService: SockService,
) {} ) { }
public async getSystemConfig() { public async getSystemConfig() {
const doc = await this.getDb({ type: AuthDataType.systemConfig }); const doc = await this.getDb({ type: AuthDataType.systemConfig });
@ -287,7 +287,7 @@ export default class SystemService {
); );
const text = await body.text(); const text = await body.text();
lastVersionContent = parseContentVersion(text); lastVersionContent = parseContentVersion(text);
} catch (error) {} } catch (error) { }
if (!lastVersionContent) { if (!lastVersionContent) {
lastVersionContent = currentVersionContent; lastVersionContent = currentVersionContent;
@ -401,11 +401,12 @@ export default class SystemService {
} }
} }
public async run({ command }: { command: string }, callback: TaskCallbacks) { public async run({ command, logPath }: { command: string; logPath?: string }, callback: TaskCallbacks) {
if (!command.startsWith(TASK_COMMAND)) { if (!command.startsWith(TASK_COMMAND)) {
command = `${TASK_COMMAND} ${command}`; command = `${TASK_COMMAND} ${command}`;
} }
this.scheduleService.runTask(`real_time=true ${command}`, callback, { const logPathPrefix = logPath ? `real_log_path=${logPath}` : ''
this.scheduleService.runTask(`${logPathPrefix} real_time=true ${command}`, callback, {
command, command,
id: command.replace(/ /g, '-'), id: command.replace(/ /g, '-'),
runOrigin: 'system', runOrigin: 'system',
@ -442,8 +443,7 @@ export default class SystemService {
} }
const dataPaths = dataDirs.map((dir) => `data/${dir}`); const dataPaths = dataDirs.map((dir) => `data/${dir}`);
await promiseExec( await promiseExec(
`cd ${config.dataPath} && cd ../ && tar -zcvf ${ `cd ${config.dataPath} && cd ../ && tar -zcvf ${config.dataTgzFile
config.dataTgzFile
} ${dataPaths.join(' ')}`, } ${dataPaths.join(' ')}`,
); );
res.download(config.dataTgzFile); res.download(config.dataTgzFile);
@ -537,7 +537,7 @@ export default class SystemService {
try { try {
const finalPath = path.join(config.dependenceCachePath, type); const finalPath = path.join(config.dependenceCachePath, type);
await fs.promises.rm(finalPath, { recursive: true }); await fs.promises.rm(finalPath, { recursive: true });
} catch (error) {} } catch (error) { }
return { code: 200 }; return { code: 200 };
} }
} }

View File

@ -2,13 +2,9 @@
echo -e "开始发布" echo -e "开始发布"
echo -e "切换master分支" echo -e "切换master分支"
git checkout master git branch -D master
git checkout -b master
echo -e "合并develop代码" git push --set-upstream origin master -f
git merge origin/develop
echo -e "提交master代码"
git push
echo -e "更新cdn文件" echo -e "更新cdn文件"
ts-node-transpile-only sample/tool.ts ts-node-transpile-only sample/tool.ts

View File

@ -1,5 +1,5 @@
import intl from 'react-intl-universal'; import intl from "react-intl-universal";
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from "react";
import { import {
Modal, Modal,
message, message,
@ -8,17 +8,17 @@ import {
Statistic, Statistic,
Button, Button,
Typography, Typography,
} from 'antd'; } from "antd";
import { request } from '@/utils/http'; import { request } from "@/utils/http";
import config from '@/utils/config'; import config from "@/utils/config";
import { import {
Loading3QuartersOutlined, Loading3QuartersOutlined,
CheckCircleOutlined, CheckCircleOutlined,
} from '@ant-design/icons'; } from "@ant-design/icons";
import { PageLoading } from '@ant-design/pro-layout'; import { PageLoading } from "@ant-design/pro-layout";
import { logEnded } from '@/utils'; import { logEnded } from "@/utils";
import { CrontabStatus } from './type'; import { CrontabStatus } from "./type";
import Ansi from 'ansi-to-react'; import Ansi from "ansi-to-react";
const { Countdown } = Statistic; const { Countdown } = Statistic;
@ -33,7 +33,7 @@ const CronLogModal = ({
data?: string; data?: string;
logUrl?: string; logUrl?: string;
}) => { }) => {
const [value, setValue] = useState<string>(intl.get('启动中...')); const [value, setValue] = useState<string>(intl.get("启动中..."));
const [loading, setLoading] = useState<any>(true); const [loading, setLoading] = useState<any>(true);
const [executing, setExecuting] = useState<any>(true); const [executing, setExecuting] = useState<any>(true);
const [isPhone, setIsPhone] = useState(false); const [isPhone, setIsPhone] = useState(false);
@ -49,15 +49,15 @@ const CronLogModal = ({
.then(({ code, data }) => { .then(({ code, data }) => {
if ( if (
code === 200 && code === 200 &&
localStorage.getItem('logCron') === uniqPath && localStorage.getItem("logCron") === uniqPath &&
data !== value data !== value
) { ) {
const log = data as string; const log = data as string;
setValue(log || intl.get('暂无日志')); setValue(log || intl.get("暂无日志"));
const hasNext = Boolean( const hasNext = Boolean(
log && !logEnded(log) && !log.includes('任务未运行'), log && !logEnded(log) && !log.includes("日志不存在"),
); );
if (!hasNext && !logEnded(value) && value !== intl.get('启动中...')) { if (!hasNext && !logEnded(value) && value !== intl.get("启动中...")) {
setTimeout(() => { setTimeout(() => {
autoScroll(); autoScroll();
}); });
@ -85,13 +85,13 @@ const CronLogModal = ({
setTimeout(() => { setTimeout(() => {
document document
.querySelector('#log-flag')! .querySelector("#log-flag")
.scrollIntoView({ behavior: 'smooth' }); ?.scrollIntoView({ behavior: "smooth" });
}, 600); }, 600);
}; };
const cancel = () => { const cancel = () => {
localStorage.removeItem('logCron'); localStorage.removeItem("logCron");
handleCancel(); handleCancel();
}; };
@ -107,7 +107,7 @@ const CronLogModal = ({
const titleElement = () => { const titleElement = () => {
return ( return (
<div style={{ display: 'flex', alignItems: 'center' }}> <div style={{ display: "flex", alignItems: "center" }}>
{(executing || loading) && <Loading3QuartersOutlined spin />} {(executing || loading) && <Loading3QuartersOutlined spin />}
{!executing && !loading && <CheckCircleOutlined />} {!executing && !loading && <CheckCircleOutlined />}
<Typography.Text ellipsis={true} style={{ marginLeft: 5 }}> <Typography.Text ellipsis={true} style={{ marginLeft: 5 }}>
@ -144,7 +144,7 @@ const CronLogModal = ({
onCancel={() => cancel()} onCancel={() => cancel()}
footer={[ footer={[
<Button type="primary" onClick={() => cancel()}> <Button type="primary" onClick={() => cancel()}>
{intl.get('知道了')} {intl.get("知道了")}
</Button>, </Button>,
]} ]}
> >
@ -156,9 +156,9 @@ const CronLogModal = ({
style={ style={
isPhone isPhone
? { ? {
fontFamily: 'Source Code Pro', fontFamily: "Source Code Pro",
zoom: 0.83, zoom: 0.83,
} }
: {} : {}
} }
> >

View File

@ -1,23 +1,23 @@
import { disableBody } from '@/utils'; import { disableBody } from "@/utils";
import config from '@/utils/config'; import config from "@/utils/config";
import { request } from '@/utils/http'; import { request } from "@/utils/http";
import WebSocketManager from '@/utils/websocket'; import WebSocketManager from "@/utils/websocket";
import Ansi from 'ansi-to-react'; import Ansi from "ansi-to-react";
import { Button, Modal, Statistic, message } from 'antd'; import { Button, Modal, Statistic, message } from "antd";
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from "react";
import intl from 'react-intl-universal'; import intl from "react-intl-universal";
const { Countdown } = Statistic; const { Countdown } = Statistic;
const CheckUpdate = ({ systemInfo }: any) => { const CheckUpdate = ({ systemInfo }: any) => {
const [updateLoading, setUpdateLoading] = useState(false); const [updateLoading, setUpdateLoading] = useState(false);
const [value, setValue] = useState(''); const [value, setValue] = useState("");
const modalRef = useRef<any>(); const modalRef = useRef<any>();
const checkUpgrade = () => { const checkUpgrade = () => {
if (updateLoading) return; if (updateLoading) return;
setUpdateLoading(true); setUpdateLoading(true);
message.loading(intl.get('检查更新中...'), 0); message.loading(intl.get("检查更新中..."), 0);
request request
.put(`${config.apiPrefix}system/update-check`) .put(`${config.apiPrefix}system/update-check`)
.then(({ code, data }) => { .then(({ code, data }) => {
@ -42,22 +42,22 @@ const CheckUpdate = ({ systemInfo }: any) => {
const showForceUpdateModal = (data: any) => { const showForceUpdateModal = (data: any) => {
Modal.confirm({ Modal.confirm({
width: 500, width: 500,
title: intl.get('更新'), title: intl.get("更新"),
content: ( content: (
<> <>
<div>{intl.get('已经是最新版了!')}</div> <div>{intl.get("已经是最新版了!")}</div>
<div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}> <div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}>
{intl.get('青龙')} {data.lastVersion}{' '} {intl.get("青龙")} {data.lastVersion}{" "}
{intl.get('是目前检测到的最新可用版本了。')} {intl.get("是目前检测到的最新可用版本了。")}
</div> </div>
</> </>
), ),
okText: intl.get('重新下载'), okText: intl.get("重新下载"),
onOk() { onOk() {
showUpdatingModal(); showUpdatingModal();
request request
.put(`${config.apiPrefix}system/update`) .put(`${config.apiPrefix}system/update`)
.then((_data: any) => {}) .then((_data: any) => { })
.catch((error: any) => { .catch((error: any) => {
console.log(error); console.log(error);
}); });
@ -71,10 +71,10 @@ const CheckUpdate = ({ systemInfo }: any) => {
width: 500, width: 500,
title: ( title: (
<> <>
<div>{intl.get('更新可用')}</div> <div>{intl.get("更新可用")}</div>
<div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}> <div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}>
{intl.get('新版本')} {lastVersion}{' '} {intl.get("新版本")} {lastVersion}{" "}
{intl.get('可用,你使用的版本为')} {systemInfo.version} {intl.get("可用,你使用的版本为")} {systemInfo.version}
</div> </div>
</> </>
), ),
@ -83,13 +83,13 @@ const CheckUpdate = ({ systemInfo }: any) => {
<Ansi>{lastLog}</Ansi> <Ansi>{lastLog}</Ansi>
</pre> </pre>
), ),
okText: intl.get('下载更新'), okText: intl.get("下载更新"),
cancelText: intl.get('以后再说'), cancelText: intl.get("以后再说"),
onOk() { onOk() {
showUpdatingModal(); showUpdatingModal();
request request
.put(`${config.apiPrefix}system/update`) .put(`${config.apiPrefix}system/update`)
.then((_data: any) => {}) .then((_data: any) => { })
.catch((error: any) => { .catch((error: any) => {
console.log(error); console.log(error);
}); });
@ -98,14 +98,14 @@ const CheckUpdate = ({ systemInfo }: any) => {
}; };
const showUpdatingModal = () => { const showUpdatingModal = () => {
setValue(''); setValue("");
modalRef.current = Modal.info({ modalRef.current = Modal.info({
width: 600, width: 600,
maskClosable: false, maskClosable: false,
closable: false, closable: false,
keyboard: false, keyboard: false,
okButtonProps: { disabled: true }, okButtonProps: { disabled: true },
title: intl.get('下载更新中...'), title: intl.get("下载更新中..."),
centered: true, centered: true,
content: ( content: (
<pre> <pre>
@ -122,13 +122,13 @@ const CheckUpdate = ({ systemInfo }: any) => {
message.success({ message.success({
content: ( content: (
<span> <span>
{intl.get('系统将在')} {intl.get("系统将在")}
<Countdown <Countdown
className="inline-countdown" className="inline-countdown"
format="ss" format="ss"
value={Date.now() + 1000 * 30} value={Date.now() + 1000 * 30}
/> />
{intl.get('秒后自动刷新')} {intl.get("秒后自动刷新")}
</span> </span>
), ),
duration: 30, duration: 30,
@ -147,12 +147,12 @@ const CheckUpdate = ({ systemInfo }: any) => {
Modal.confirm({ Modal.confirm({
width: 600, width: 600,
maskClosable: false, maskClosable: false,
title: intl.get('确认重启'), title: intl.get("确认重启"),
centered: true, centered: true,
content: intl.get('系统安装包下载成功,确认重启'), content: intl.get("系统安装包下载成功,确认重启"),
okText: intl.get('重启'), okText: intl.get("重启"),
onOk() { onOk() {
reloadSystem('system'); reloadSystem("system");
}, },
onCancel() { onCancel() {
modalRef.current.update({ modalRef.current.update({
@ -166,7 +166,7 @@ const CheckUpdate = ({ systemInfo }: any) => {
useEffect(() => { useEffect(() => {
if (!value) return; if (!value) return;
const updateFailed = value.includes('失败,请检查'); const updateFailed = value.includes("失败,请检查");
modalRef.current.update({ modalRef.current.update({
maskClosable: updateFailed, maskClosable: updateFailed,
@ -185,19 +185,19 @@ const CheckUpdate = ({ systemInfo }: any) => {
const handleMessage = useCallback((payload: any) => { const handleMessage = useCallback((payload: any) => {
let { message: _message } = payload; let { message: _message } = payload;
const updateFailed = _message.includes('失败,请检查'); const updateFailed = _message.includes("失败,请检查");
if (updateFailed) { if (updateFailed) {
message.error(intl.get('更新失败,请检查网络及日志或稍后再试')); message.error(intl.get("更新失败,请检查网络及日志或稍后再试"));
} }
setTimeout(() => { setTimeout(() => {
document document
.querySelector('#log-identifier')! .querySelector("#log-identifier")
.scrollIntoView({ behavior: 'smooth' }); ?.scrollIntoView({ behavior: "smooth" });
}, 600); }, 600);
if (_message.includes('更新包下载成功')) { if (_message.includes("更新包下载成功")) {
setTimeout(() => { setTimeout(() => {
showReloadModal(); showReloadModal();
}, 1000); }, 1000);
@ -208,24 +208,24 @@ const CheckUpdate = ({ systemInfo }: any) => {
useEffect(() => { useEffect(() => {
const ws = WebSocketManager.getInstance(); const ws = WebSocketManager.getInstance();
ws.subscribe('updateSystemVersion', handleMessage); ws.subscribe("updateSystemVersion", handleMessage);
return () => { return () => {
ws.unsubscribe('updateSystemVersion', handleMessage); ws.unsubscribe("updateSystemVersion", handleMessage);
}; };
}, []); }, []);
return ( return (
<> <>
<Button type="primary" onClick={checkUpgrade}> <Button type="primary" onClick={checkUpgrade}>
{intl.get('检查更新')} {intl.get("检查更新")}
</Button> </Button>
<Button <Button
type="primary" type="primary"
onClick={() => reloadSystem('reload')} onClick={() => reloadSystem("reload")}
style={{ marginLeft: 8 }} style={{ marginLeft: 8 }}
> >
{intl.get('重新启动')} {intl.get("重新启动")}
</Button> </Button>
</> </>
); );