mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-18 20:30:08 +08:00
Introduces backend and frontend logic to fetch the latest NapCat version tag from multiple sources, exposes a new API endpoint, and adds a UI prompt to notify users of new versions with an update button. Also includes minor code style improvements in dialog context.
348 lines
10 KiB
TypeScript
348 lines
10 KiB
TypeScript
import { Card, CardBody, CardHeader } from '@heroui/card';
|
|
import { Button } from '@heroui/button';
|
|
import { Chip } from '@heroui/chip';
|
|
import { Spinner } from '@heroui/spinner';
|
|
import { Tooltip } from '@heroui/tooltip';
|
|
import { useRequest } from 'ahooks';
|
|
import { FaCircleInfo, FaInfo, FaQq } from 'react-icons/fa6';
|
|
import { IoLogoChrome, IoLogoOctocat } from 'react-icons/io';
|
|
import { RiMacFill } from 'react-icons/ri';
|
|
import { useState } from 'react';
|
|
import toast from 'react-hot-toast';
|
|
|
|
|
|
|
|
import WebUIManager from '@/controllers/webui_manager';
|
|
import useDialog from '@/hooks/use-dialog';
|
|
|
|
|
|
export interface SystemInfoItemProps {
|
|
title: string;
|
|
icon?: React.ReactNode;
|
|
value?: React.ReactNode;
|
|
endContent?: React.ReactNode;
|
|
}
|
|
|
|
const SystemInfoItem: React.FC<SystemInfoItemProps> = ({
|
|
title,
|
|
value = '--',
|
|
icon,
|
|
endContent,
|
|
}) => {
|
|
return (
|
|
<div className='flex text-sm gap-1 p-2 items-center shadow-sm shadow-primary-100 dark:shadow-primary-100 rounded text-primary-400'>
|
|
{icon}
|
|
<div className='w-24'>{title}</div>
|
|
<div className='text-primary-200'>{value}</div>
|
|
<div className='ml-auto'>{endContent}</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export interface NewVersionTipProps {
|
|
currentVersion?: string;
|
|
}
|
|
|
|
// const NewVersionTip = (props: NewVersionTipProps) => {
|
|
// const { currentVersion } = props;
|
|
// const dialog = useDialog();
|
|
// const { data: releaseData, error } = useRequest(() =>
|
|
// request.get<GithubRelease[]>(
|
|
// 'https://api.github.com/repos/NapNeko/NapCatQQ/releases'
|
|
// )
|
|
// );
|
|
|
|
// if (error) {
|
|
// return (
|
|
// <Tooltip content='检查新版本失败'>
|
|
// <Button
|
|
// isIconOnly
|
|
// radius='full'
|
|
// color='primary'
|
|
// variant='shadow'
|
|
// className='!w-5 !h-5 !min-w-0 text-small shadow-md'
|
|
// onPress={() => {
|
|
// dialog.alert({
|
|
// title: '检查新版本失败',
|
|
// content: error.message,
|
|
// });
|
|
// }}
|
|
// >
|
|
// <FaInfo />
|
|
// </Button>
|
|
// </Tooltip>
|
|
// );
|
|
// }
|
|
|
|
// const latestVersion = releaseData?.data?.[0]?.tag_name;
|
|
|
|
// if (!latestVersion || !currentVersion) {
|
|
// return null;
|
|
// }
|
|
|
|
// if (compareVersion(latestVersion, currentVersion) <= 0) {
|
|
// return null;
|
|
// }
|
|
|
|
// const middleVersions: GithubRelease[] = [];
|
|
|
|
// for (let i = 0; i < releaseData.data.length; i++) {
|
|
// const versionInfo = releaseData.data[i];
|
|
// if (compareVersion(versionInfo.tag_name, currentVersion) > 0) {
|
|
// middleVersions.push(versionInfo);
|
|
// } else {
|
|
// break;
|
|
// }
|
|
// }
|
|
|
|
// const AISummaryComponent = () => {
|
|
// const {
|
|
// data: aiSummaryData,
|
|
// loading: aiSummaryLoading,
|
|
// error: aiSummaryError,
|
|
// run: runAiSummary,
|
|
// } = useRequest(
|
|
// (version) =>
|
|
// request.get<ServerResponse<string | null>>(
|
|
// `https://release.nc.152710.xyz/?version=${version}`,
|
|
// {
|
|
// timeout: 30000,
|
|
// }
|
|
// ),
|
|
// {
|
|
// manual: true,
|
|
// }
|
|
// );
|
|
|
|
// useEffect(() => {
|
|
// runAiSummary(currentVersion);
|
|
// }, [currentVersion, runAiSummary]);
|
|
|
|
// if (aiSummaryLoading) {
|
|
// return (
|
|
// <div className='flex justify-center py-1'>
|
|
// <Spinner size='sm' />
|
|
// </div>
|
|
// );
|
|
// }
|
|
// if (aiSummaryError) {
|
|
// return <div className='text-center text-primary-500'>AI 摘要获取失败</div>;
|
|
// }
|
|
// return <span className='text-default-700'>{aiSummaryData?.data.data}</span>;
|
|
// };
|
|
|
|
// return (
|
|
// <Tooltip content='有新版本可用'>
|
|
// <Button
|
|
// isIconOnly
|
|
// radius='full'
|
|
// color='primary'
|
|
// variant='shadow'
|
|
// className='!w-5 !h-5 !min-w-0 text-small shadow-md'
|
|
// onPress={() => {
|
|
// dialog.confirm({
|
|
// title: '有新版本可用',
|
|
// content: (
|
|
// <div className='space-y-2'>
|
|
// <div className='text-sm space-x-2'>
|
|
// <span>当前版本</span>
|
|
// <Chip color='primary' variant='flat'>
|
|
// v{currentVersion}
|
|
// </Chip>
|
|
// </div>
|
|
// <div className='text-sm space-x-2'>
|
|
// <span>最新版本</span>
|
|
// <Chip color='primary'>{latestVersion}</Chip>
|
|
// </div>
|
|
// <div className='p-2 rounded-md bg-content2 text-sm'>
|
|
// <div className='text-primary-400 font-bold flex items-center gap-1 mb-1'>
|
|
// <BsStars />
|
|
// <span>AI总结</span>
|
|
// </div>
|
|
// <AISummaryComponent />
|
|
// </div>
|
|
// <div className='text-sm space-y-2 !mt-4'>
|
|
// {middleVersions.map((versionInfo) => (
|
|
// <div
|
|
// key={versionInfo.tag_name}
|
|
// className='p-4 bg-content1 rounded-md shadow-small'
|
|
// >
|
|
// <TailwindMarkdown content={versionInfo.body} />
|
|
// </div>
|
|
// ))}
|
|
// </div>
|
|
// </div>
|
|
// ),
|
|
// scrollBehavior: 'inside',
|
|
// size: '3xl',
|
|
// confirmText: '前往下载',
|
|
// onConfirm () {
|
|
// window.open(
|
|
// 'https://github.com/NapNeko/NapCatQQ/releases',
|
|
// '_blank',
|
|
// 'noopener'
|
|
// );
|
|
// },
|
|
// });
|
|
// }}
|
|
// >
|
|
// <FaInfo />
|
|
// </Button>
|
|
// </Tooltip>
|
|
// );
|
|
// };
|
|
|
|
const NewVersionTip = (props: NewVersionTipProps) => {
|
|
const { currentVersion } = props;
|
|
const dialog = useDialog();
|
|
const { data: latestVersion, error } = useRequest(WebUIManager.getLatestTag);
|
|
const [updating, setUpdating] = useState(false);
|
|
|
|
if (error || !latestVersion || !currentVersion || latestVersion === currentVersion) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<Tooltip content='有新版本可用'>
|
|
<Button
|
|
isIconOnly
|
|
radius='full'
|
|
color='primary'
|
|
variant='shadow'
|
|
className='!w-5 !h-5 !min-w-0 text-small shadow-md'
|
|
onPress={() => {
|
|
dialog.confirm({
|
|
title: '有新版本可用',
|
|
content: (
|
|
<div className='space-y-2'>
|
|
<div className='text-sm space-x-2'>
|
|
<span>当前版本</span>
|
|
<Chip color='primary' variant='flat'>
|
|
{currentVersion}
|
|
</Chip>
|
|
</div>
|
|
<div className='text-sm space-x-2'>
|
|
<span>最新版本</span>
|
|
<Chip color='primary'>{latestVersion}</Chip>
|
|
</div>
|
|
{updating && (
|
|
<div className='flex justify-center'>
|
|
<Spinner size='sm' />
|
|
</div>
|
|
)}
|
|
</div>
|
|
),
|
|
confirmText: updating ? '更新中...' : '更新',
|
|
onConfirm: async () => {
|
|
setUpdating(true);
|
|
toast('更新中,预计需要几分钟,请耐心等待', {
|
|
duration: 3000,
|
|
});
|
|
try {
|
|
await WebUIManager.UpdateNapCat();
|
|
toast.success('更新完成,重启生效', {
|
|
duration: 5000,
|
|
});
|
|
} catch (error) {
|
|
console.error('Update failed:', error);
|
|
toast.success('更新异常', {
|
|
duration: 5000,
|
|
});
|
|
} finally {
|
|
setUpdating(false);
|
|
}
|
|
},
|
|
});
|
|
}}
|
|
>
|
|
<FaInfo />
|
|
</Button>
|
|
</Tooltip>
|
|
);
|
|
};
|
|
|
|
const NapCatVersion = () => {
|
|
const {
|
|
data: packageData,
|
|
loading: packageLoading,
|
|
error: packageError,
|
|
} = useRequest(WebUIManager.GetNapCatVersion);
|
|
|
|
const currentVersion = packageData?.version;
|
|
|
|
return (
|
|
<SystemInfoItem
|
|
title='NapCat 版本'
|
|
icon={<IoLogoOctocat className='text-xl' />}
|
|
value={
|
|
packageError
|
|
? (
|
|
`错误:${packageError.message}`
|
|
)
|
|
: packageLoading
|
|
? (
|
|
<Spinner size='sm' />
|
|
)
|
|
: (
|
|
currentVersion
|
|
)
|
|
}
|
|
endContent={<NewVersionTip currentVersion={currentVersion} />}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export interface SystemInfoProps {
|
|
archInfo?: string;
|
|
}
|
|
const SystemInfo: React.FC<SystemInfoProps> = (props) => {
|
|
const { archInfo } = props;
|
|
const {
|
|
data: qqVersionData,
|
|
loading: qqVersionLoading,
|
|
error: qqVersionError,
|
|
} = useRequest(WebUIManager.getQQVersion);
|
|
return (
|
|
<Card className='bg-opacity-60 shadow-sm shadow-primary-100 dark:shadow-primary-100 overflow-visible flex-1'>
|
|
<CardHeader className='pb-0 items-center gap-1 text-primary-500 font-extrabold'>
|
|
<FaCircleInfo className='text-lg' />
|
|
<span>系统信息</span>
|
|
</CardHeader>
|
|
<CardBody className='flex-1'>
|
|
<div className='flex flex-col justify-between h-full'>
|
|
<NapCatVersion />
|
|
<SystemInfoItem
|
|
title='QQ 版本'
|
|
icon={<FaQq className='text-lg' />}
|
|
value={
|
|
qqVersionError
|
|
? (
|
|
`错误:${qqVersionError.message}`
|
|
)
|
|
: qqVersionLoading
|
|
? (
|
|
<Spinner size='sm' />
|
|
)
|
|
: (
|
|
qqVersionData
|
|
)
|
|
}
|
|
/>
|
|
<SystemInfoItem
|
|
title='WebUI 版本'
|
|
icon={<IoLogoChrome className='text-xl' />}
|
|
value='Next'
|
|
/>
|
|
<SystemInfoItem
|
|
title='系统版本'
|
|
icon={<RiMacFill className='text-xl' />}
|
|
value={archInfo}
|
|
/>
|
|
</div>
|
|
</CardBody>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export default SystemInfo;
|