mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-01-16 13:20:33 +00:00
Refactor update dialog for new version notification
Replaces the old update confirmation and toast logic with a new dialog-based update flow, including detailed status feedback (idle, updating, success, error) and improved user guidance. Removes react-hot-toast dependency and introduces a dedicated UpdateDialogContent component for clearer update progress and error handling.
This commit is contained in:
parent
7f81bf45ee
commit
c4f7107038
@ -10,7 +10,6 @@ import { FaCircleInfo, FaInfo, FaQq } from 'react-icons/fa6';
|
|||||||
import { IoLogoChrome, IoLogoOctocat } from 'react-icons/io';
|
import { IoLogoChrome, IoLogoOctocat } from 'react-icons/io';
|
||||||
import { RiMacFill } from 'react-icons/ri';
|
import { RiMacFill } from 'react-icons/ri';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import toast from 'react-hot-toast';
|
|
||||||
|
|
||||||
import key from '@/const/key';
|
import key from '@/const/key';
|
||||||
import WebUIManager from '@/controllers/webui_manager';
|
import WebUIManager from '@/controllers/webui_manager';
|
||||||
@ -203,16 +202,161 @@ export interface NewVersionTipProps {
|
|||||||
// );
|
// );
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
// 更新状态类型
|
||||||
|
type UpdateStatus = 'idle' | 'updating' | 'success' | 'error';
|
||||||
|
|
||||||
|
// 更新对话框内容组件
|
||||||
|
const UpdateDialogContent: React.FC<{
|
||||||
|
currentVersion: string;
|
||||||
|
latestVersion: string;
|
||||||
|
status: UpdateStatus;
|
||||||
|
errorMessage?: string;
|
||||||
|
}> = ({ currentVersion, latestVersion, status, errorMessage }) => {
|
||||||
|
return (
|
||||||
|
<div className='space-y-4'>
|
||||||
|
{/* 版本信息 */}
|
||||||
|
<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'>v{latestVersion}</Chip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 更新状态显示 */}
|
||||||
|
{status === 'updating' && (
|
||||||
|
<div className='flex flex-col items-center justify-center gap-3 py-4 px-4 rounded-lg bg-primary-50/50 dark:bg-primary-900/20 border border-primary-200/50 dark:border-primary-700/30'>
|
||||||
|
<Spinner size='md' color='primary' />
|
||||||
|
<div className='text-center'>
|
||||||
|
<p className='text-sm font-medium text-primary-600 dark:text-primary-400'>
|
||||||
|
正在更新中...
|
||||||
|
</p>
|
||||||
|
<p className='text-xs text-default-500 mt-1'>
|
||||||
|
请耐心等待,更新可能需要几分钟
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{status === 'success' && (
|
||||||
|
<div className='flex flex-col items-center justify-center gap-3 py-4 px-4 rounded-lg bg-success-50/50 dark:bg-success-900/20 border border-success-200/50 dark:border-success-700/30'>
|
||||||
|
<div className='w-12 h-12 rounded-full bg-success-100 dark:bg-success-900/40 flex items-center justify-center'>
|
||||||
|
<svg className='w-6 h-6 text-success-600 dark:text-success-400' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
|
||||||
|
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M5 13l4 4L19 7' />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div className='text-center'>
|
||||||
|
<p className='text-sm font-medium text-success-600 dark:text-success-400'>
|
||||||
|
更新完成
|
||||||
|
</p>
|
||||||
|
<p className='text-xs text-default-500 mt-1'>
|
||||||
|
请重启 NapCat 以应用新版本
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className='mt-2 p-3 rounded-lg bg-warning-50/50 dark:bg-warning-900/20 border border-warning-200/50 dark:border-warning-700/30'>
|
||||||
|
<p className='text-xs text-warning-700 dark:text-warning-400 flex items-center gap-1'>
|
||||||
|
<svg className='w-4 h-4' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
|
||||||
|
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z' />
|
||||||
|
</svg>
|
||||||
|
<span>请手动重启 NapCat,更新才会生效</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{status === 'error' && (
|
||||||
|
<div className='flex flex-col items-center justify-center gap-3 py-4 px-4 rounded-lg bg-danger-50/50 dark:bg-danger-900/20 border border-danger-200/50 dark:border-danger-700/30'>
|
||||||
|
<div className='w-12 h-12 rounded-full bg-danger-100 dark:bg-danger-900/40 flex items-center justify-center'>
|
||||||
|
<svg className='w-6 h-6 text-danger-600 dark:text-danger-400' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
|
||||||
|
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M6 18L18 6M6 6l12 12' />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div className='text-center'>
|
||||||
|
<p className='text-sm font-medium text-danger-600 dark:text-danger-400'>
|
||||||
|
更新失败
|
||||||
|
</p>
|
||||||
|
<p className='text-xs text-default-500 mt-1'>
|
||||||
|
{errorMessage || '请稍后重试或手动更新'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const NewVersionTip = (props: NewVersionTipProps) => {
|
const NewVersionTip = (props: NewVersionTipProps) => {
|
||||||
const { currentVersion } = props;
|
const { currentVersion } = props;
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const { data: latestVersion, error } = useRequest(WebUIManager.getLatestTag);
|
const { data: latestVersion, error } = useRequest(WebUIManager.getLatestTag);
|
||||||
const [updating, setUpdating] = useState(false);
|
const [updateStatus, setUpdateStatus] = useState<UpdateStatus>('idle');
|
||||||
|
|
||||||
if (error || !latestVersion || !currentVersion || latestVersion === currentVersion) {
|
if (error || !latestVersion || !currentVersion || latestVersion === currentVersion) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleUpdate = async () => {
|
||||||
|
setUpdateStatus('updating');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await WebUIManager.UpdateNapCat();
|
||||||
|
setUpdateStatus('success');
|
||||||
|
// 显示更新成功对话框
|
||||||
|
dialog.alert({
|
||||||
|
title: '更新完成',
|
||||||
|
content: (
|
||||||
|
<UpdateDialogContent
|
||||||
|
currentVersion={currentVersion}
|
||||||
|
latestVersion={latestVersion}
|
||||||
|
status='success'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
confirmText: '我知道了',
|
||||||
|
size: 'md',
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Update failed:', err);
|
||||||
|
const errMessage = err instanceof Error ? err.message : '未知错误';
|
||||||
|
setUpdateStatus('error');
|
||||||
|
// 显示更新失败对话框
|
||||||
|
dialog.alert({
|
||||||
|
title: '更新失败',
|
||||||
|
content: (
|
||||||
|
<UpdateDialogContent
|
||||||
|
currentVersion={currentVersion}
|
||||||
|
latestVersion={latestVersion}
|
||||||
|
status='error'
|
||||||
|
errorMessage={errMessage}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
confirmText: '确定',
|
||||||
|
size: 'md',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showUpdateDialog = () => {
|
||||||
|
dialog.confirm({
|
||||||
|
title: '发现新版本',
|
||||||
|
content: (
|
||||||
|
<UpdateDialogContent
|
||||||
|
currentVersion={currentVersion}
|
||||||
|
latestVersion={latestVersion}
|
||||||
|
status='idle'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
confirmText: '立即更新',
|
||||||
|
cancelText: '稍后更新',
|
||||||
|
size: 'md',
|
||||||
|
onConfirm: handleUpdate,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip content='有新版本可用'>
|
<Tooltip content='有新版本可用'>
|
||||||
<Button
|
<Button
|
||||||
@ -221,50 +365,8 @@ const NewVersionTip = (props: NewVersionTipProps) => {
|
|||||||
color='primary'
|
color='primary'
|
||||||
variant='shadow'
|
variant='shadow'
|
||||||
className='!w-5 !h-5 !min-w-0 text-small shadow-md'
|
className='!w-5 !h-5 !min-w-0 text-small shadow-md'
|
||||||
onPress={() => {
|
isLoading={updateStatus === 'updating'}
|
||||||
dialog.confirm({
|
onPress={showUpdateDialog}
|
||||||
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'>v{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 />
|
<FaInfo />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user