fix: synchronize runtime locales and harden online updates

Translate UI, scheduler, validation, preload and maintenance messages dynamically, and propagate locale changes between workers. Harden update checks, downloads and terminal states, verify Debian pnpm, and ignore generated test artifacts.
This commit is contained in:
whyour
2026-10-17 07:07:09 +08:00
parent 8305825ffd
commit ef348b445b
72 changed files with 1733 additions and 553 deletions
+75 -63
View File
@@ -1,24 +1,25 @@
import { disableBody } from "@/utils";
import config from "@/utils/config";
import { request } from "@/utils/http";
import WebSocketManager from "@/utils/websocket";
import Ansi from "ansi-to-react";
import { Button, Modal, Statistic, message } from "antd";
import { useCallback, useEffect, useRef, useState } from "react";
import intl from "react-intl-universal";
import { disableBody } from '@/utils';
import config from '@/utils/config';
import { request } from '@/utils/http';
import WebSocketManager from '@/utils/websocket';
import Ansi from 'ansi-to-react';
import { Button, Modal, Statistic, message } from 'antd';
import { useCallback, useEffect, useRef, useState } from 'react';
import intl from 'react-intl-universal';
const { Countdown } = Statistic;
const CheckUpdate = ({ systemInfo }: any) => {
const [updateLoading, setUpdateLoading] = useState(false);
const [value, setValue] = useState("");
const [value, setValue] = useState('');
const modalRef = useRef<any>();
const lastStatusRef = useRef<string | undefined>();
const [updateStatus, setUpdateStatus] = useState<string>();
const checkUpgrade = () => {
if (updateLoading) return;
if (updateLoading || modalRef.current) return;
setUpdateLoading(true);
message.loading(intl.get("检查更新中..."), 0);
message.loading(intl.get('检查更新中...'), 0);
request
.put(`${config.apiPrefix}system/update-check`)
.then(({ code, data }) => {
@@ -33,7 +34,7 @@ const CheckUpdate = ({ systemInfo }: any) => {
})
.catch((error: any) => {
message.destroy();
console.log(error);
message.error(intl.get('检查更新失败,请检查网络后重试'));
})
.finally(() => {
setUpdateLoading(false);
@@ -43,25 +44,19 @@ const CheckUpdate = ({ systemInfo }: any) => {
const showForceUpdateModal = (data: any) => {
Modal.confirm({
width: 500,
title: intl.get("更新"),
title: intl.get('更新'),
content: (
<>
<div>{intl.get("已经是最新版了!")}</div>
<div>{intl.get('已经是最新版了!')}</div>
<div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}>
{intl.get("青龙")} {data.lastVersion}{" "}
{intl.get("是目前检测到的最新可用版本了。")}
{intl.get('青龙')} {data.lastVersion}{' '}
{intl.get('是目前检测到的最新可用版本了。')}
</div>
</>
),
okText: intl.get("重新下载"),
okText: intl.get('重新下载'),
onOk() {
showUpdatingModal();
request
.put(`${config.apiPrefix}system/update`)
.then((_data: any) => { })
.catch((error: any) => {
console.log(error);
});
startUpdate();
},
});
};
@@ -72,10 +67,12 @@ const CheckUpdate = ({ systemInfo }: any) => {
width: 500,
title: (
<>
<div>{intl.get("更新可用")}</div>
<div>{intl.get('更新可用')}</div>
<div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}>
{intl.get("新版本")} {lastVersion}{" "}
{intl.get("可用,你使用的版本为")} {systemInfo.version}。
{intl.get('新版本可用,当前版本', {
version: lastVersion,
current: systemInfo.version,
})}
</div>
</>
),
@@ -84,52 +81,60 @@ const CheckUpdate = ({ systemInfo }: any) => {
<Ansi>{lastLog}</Ansi>
</pre>
),
okText: intl.get("下载更新"),
cancelText: intl.get("以后再说"),
okText: intl.get('下载更新'),
cancelText: intl.get('以后再说'),
onOk() {
showUpdatingModal();
request
.put(`${config.apiPrefix}system/update`)
.then((_data: any) => { })
.catch((error: any) => {
console.log(error);
});
startUpdate();
},
});
};
const showUpdatingModal = () => {
setValue("");
setValue('');
lastStatusRef.current = 'running';
setUpdateStatus('running');
modalRef.current = Modal.info({
width: 600,
maskClosable: false,
closable: false,
keyboard: false,
okButtonProps: { disabled: true },
title: intl.get("下载更新中..."),
title: intl.get('下载更新中...'),
centered: true,
content: (
<pre>
<Ansi>{value}</Ansi>
</pre>
),
afterClose: () => {
modalRef.current = undefined;
},
content: <pre />,
});
};
const startUpdate = async () => {
showUpdatingModal();
try {
const response = await request.put(`${config.apiPrefix}system/update`);
if (response.code !== 200) throw new Error(response.message);
} catch {
lastStatusRef.current = 'failed';
setUpdateStatus('failed');
message.error(intl.get('更新失败,请检查网络及日志或稍后再试'));
}
};
const reloadSystem = (type?: string) => {
request
.put(`${config.apiPrefix}update/${type}`)
.then((_data: any) => {
.then(({ code }: any) => {
if (code !== 200) return;
message.success({
content: (
<span>
{intl.get("系统将在")}
{intl.get('系统将在')}
<Countdown
className="inline-countdown"
format="ss"
value={Date.now() + 1000 * 30}
/>
{intl.get("秒后自动刷新")}
{intl.get('秒后自动刷新')}
</span>
),
duration: 30,
@@ -148,15 +153,15 @@ const CheckUpdate = ({ systemInfo }: any) => {
Modal.confirm({
width: 600,
maskClosable: false,
title: intl.get("确认重启"),
title: intl.get('确认重启'),
centered: true,
content: intl.get("系统安装包下载成功,确认重启"),
okText: intl.get("重启"),
content: intl.get('系统安装包下载成功,确认重启'),
okText: intl.get('重启'),
onOk() {
reloadSystem("system");
reloadSystem('system');
},
onCancel() {
modalRef.current.update({
modalRef.current?.update({
maskClosable: true,
closable: true,
okButtonProps: { disabled: false },
@@ -166,8 +171,8 @@ const CheckUpdate = ({ systemInfo }: any) => {
};
useEffect(() => {
if (!value) return;
const updateFailed = lastStatusRef.current === 'failed';
if (!modalRef.current) return;
const updateFailed = updateStatus === 'failed';
modalRef.current.update({
maskClosable: updateFailed,
@@ -182,27 +187,32 @@ const CheckUpdate = ({ systemInfo }: any) => {
</>
),
});
}, [value]);
}, [value, updateStatus]);
const handleMessage = useCallback((payload: any) => {
if (!modalRef.current || lastStatusRef.current !== 'running') return;
const { message: _message, status } = payload;
if (status === 'failed') {
lastStatusRef.current = 'failed';
message.error(intl.get("更新失败,请检查网络及日志或稍后再试"));
setUpdateStatus('failed');
message.error(intl.get('更新失败,请检查网络及日志或稍后再试'));
}
if (status === 'success') {
lastStatusRef.current = 'success';
setUpdateStatus('success');
setTimeout(() => {
showReloadModal();
if (modalRef.current && lastStatusRef.current === 'success') {
showReloadModal();
}
}, 1000);
}
setTimeout(() => {
document
.querySelector("#log-identifier")
?.scrollIntoView({ behavior: "smooth" });
.querySelector('#log-identifier')
?.scrollIntoView({ behavior: 'smooth' });
}, 600);
if (_message) {
@@ -212,24 +222,26 @@ const CheckUpdate = ({ systemInfo }: any) => {
useEffect(() => {
const ws = WebSocketManager.getInstance();
ws.subscribe("updateSystemVersion", handleMessage);
ws.subscribe('updateSystemVersion', handleMessage);
return () => {
ws.unsubscribe("updateSystemVersion", handleMessage);
ws.unsubscribe('updateSystemVersion', handleMessage);
modalRef.current?.destroy();
modalRef.current = undefined;
};
}, []);
return (
<>
<Button type="primary" onClick={checkUpgrade}>
{intl.get("检查更新")}
{intl.get('检查更新')}
</Button>
<Button
type="primary"
onClick={() => reloadSystem("reload")}
onClick={() => reloadSystem('reload')}
style={{ marginLeft: 8 }}
>
{intl.get("重新启动")}
{intl.get('重新启动')}
</Button>
</>
);