mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-24 09:00:06 +08:00
Revert "Refactor UI components for consistent styling"
This reverts commit 7e6035d98b.
This commit is contained in:
parent
7e6035d98b
commit
7f81bf45ee
@ -188,20 +188,10 @@ export const UpdateNapCatHandler: RequestHandler = async (_req, res) => {
|
||||
try {
|
||||
// 获取最新release信息
|
||||
const latestRelease = await getLatestRelease() as Release;
|
||||
|
||||
// 验证 release 响应
|
||||
if (!latestRelease || !latestRelease.tag_name) {
|
||||
throw new Error('无法获取最新版本信息,请稍后重试');
|
||||
}
|
||||
|
||||
if (!latestRelease.assets || !Array.isArray(latestRelease.assets)) {
|
||||
throw new Error('无法获取下载资源列表,可能是 GitHub API 请求限制,请稍后重试');
|
||||
}
|
||||
|
||||
const ReleaseName = WebUiDataRuntime.getWorkingEnv() === NapCatCoreWorkingEnv.Framework ? 'NapCat.Framework.zip' : 'NapCat.Shell.zip';
|
||||
const shellZipAsset = latestRelease.assets.find(asset => asset.name === ReleaseName);
|
||||
if (!shellZipAsset) {
|
||||
throw new Error(`未找到${ReleaseName}文件,可用的资源: ${latestRelease.assets.map(a => a.name).join(', ')}`);
|
||||
throw new Error(`未找到${ReleaseName}文件`);
|
||||
}
|
||||
|
||||
// 创建临时目录
|
||||
@ -289,13 +279,12 @@ export const UpdateNapCatHandler: RequestHandler = async (_req, res) => {
|
||||
// 发送成功响应
|
||||
const message = failedFiles.length > 0
|
||||
? `更新完成,重启应用以应用剩余${failedFiles.length}个文件的更新`
|
||||
: '更新完成,请重启 NapCat 以应用更新';
|
||||
: '更新完成';
|
||||
sendSuccess(res, {
|
||||
status: 'completed',
|
||||
message,
|
||||
newVersion: latestRelease.tag_name,
|
||||
failedFilesCount: failedFiles.length,
|
||||
needRestart: true
|
||||
failedFilesCount: failedFiles.length
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
|
||||
@ -1,22 +1,29 @@
|
||||
import { Card, CardBody } from '@heroui/card';
|
||||
import { Image } from '@heroui/image';
|
||||
import { useLocalStorage } from '@uidotdev/usehooks';
|
||||
import clsx from 'clsx';
|
||||
import { BsTencentQq } from 'react-icons/bs';
|
||||
|
||||
import key from '@/const/key';
|
||||
import { SelfInfo } from '@/types/user';
|
||||
|
||||
import PageLoading from './page_loading';
|
||||
|
||||
export interface QQInfoCardProps {
|
||||
data?: SelfInfo
|
||||
error?: Error
|
||||
loading?: boolean
|
||||
data?: SelfInfo;
|
||||
error?: Error;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const QQInfoCard: React.FC<QQInfoCardProps> = ({ data, error, loading }) => {
|
||||
const [backgroundImage] = useLocalStorage<string>(key.backgroundImage, '');
|
||||
const hasBackground = !!backgroundImage;
|
||||
return (
|
||||
<Card
|
||||
className='relative bg-primary-100 bg-opacity-60 overflow-hidden flex-shrink-0 shadow-md shadow-primary-300 dark:shadow-primary-50'
|
||||
className={clsx(
|
||||
'relative backdrop-blur-sm border border-white/40 dark:border-white/10 overflow-hidden flex-shrink-0 shadow-sm',
|
||||
hasBackground ? 'bg-white/10 dark:bg-black/10' : 'bg-white/60 dark:bg-black/40'
|
||||
)}
|
||||
shadow='none'
|
||||
radius='lg'
|
||||
>
|
||||
@ -31,28 +38,40 @@ const QQInfoCard: React.FC<QQInfoCardProps> = ({ data, error, loading }) => {
|
||||
</CardBody>
|
||||
)
|
||||
: (
|
||||
<CardBody className='flex-row items-center gap-2 overflow-hidden relative'>
|
||||
<div className='absolute right-0 bottom-0 text-5xl text-primary-400'>
|
||||
<BsTencentQq />
|
||||
</div>
|
||||
<CardBody className='flex-row items-center gap-4 overflow-hidden relative p-4'>
|
||||
{!hasBackground && (
|
||||
<div className='absolute right-[-10px] bottom-[-10px] text-7xl text-default-400/10 rotate-12 pointer-events-none'>
|
||||
<BsTencentQq />
|
||||
</div>
|
||||
)}
|
||||
<div className='relative flex-shrink-0 z-10'>
|
||||
<Image
|
||||
src={
|
||||
data?.avatarUrl ??
|
||||
`https://q1.qlogo.cn/g?b=qq&nk=${data?.uin}&s=1`
|
||||
}
|
||||
className='shadow-md rounded-full w-12 aspect-square'
|
||||
data?.avatarUrl ??
|
||||
`https://q1.qlogo.cn/g?b=qq&nk=${data?.uin}&s=1`
|
||||
}
|
||||
className='shadow-sm rounded-full w-14 aspect-square ring-2 ring-white/50 dark:ring-white/10'
|
||||
/>
|
||||
<div
|
||||
className={clsx(
|
||||
'w-4 h-4 rounded-full absolute right-0.5 bottom-0 border-2 border-primary-100 z-10',
|
||||
data?.online ? 'bg-green-500' : 'bg-gray-500'
|
||||
'w-3.5 h-3.5 rounded-full absolute right-0.5 bottom-0.5 border-2 border-white dark:border-zinc-900 z-10',
|
||||
data?.online ? 'bg-success-500' : 'bg-default-400'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex-col justify-center'>
|
||||
<div className='text-lg truncate'>{data?.nick}</div>
|
||||
<div className='text-primary-500 text-sm'>{data?.uin}</div>
|
||||
<div className='flex-col justify-center z-10'>
|
||||
<div className={clsx(
|
||||
'text-xl font-bold truncate mb-0.5',
|
||||
hasBackground ? 'text-white drop-shadow-sm' : 'text-default-800 dark:text-gray-100'
|
||||
)}>
|
||||
{data?.nick || '未知用户'}
|
||||
</div>
|
||||
<div className={clsx(
|
||||
'font-mono text-xs tracking-wider',
|
||||
hasBackground ? 'text-white/80' : 'text-default-500 opacity-80'
|
||||
)}>
|
||||
{data?.uin || 'Unknown'}
|
||||
</div>
|
||||
</div>
|
||||
</CardBody>
|
||||
)}
|
||||
|
||||
@ -3,15 +3,16 @@ import { Button } from '@heroui/button';
|
||||
import { Chip } from '@heroui/chip';
|
||||
import { Spinner } from '@heroui/spinner';
|
||||
import { Tooltip } from '@heroui/tooltip';
|
||||
import { useLocalStorage } from '@uidotdev/usehooks';
|
||||
import { useRequest } from 'ahooks';
|
||||
import clsx from 'clsx';
|
||||
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 key from '@/const/key';
|
||||
import WebUIManager from '@/controllers/webui_manager';
|
||||
import useDialog from '@/hooks/use-dialog';
|
||||
|
||||
@ -21,6 +22,7 @@ export interface SystemInfoItemProps {
|
||||
icon?: React.ReactNode;
|
||||
value?: React.ReactNode;
|
||||
endContent?: React.ReactNode;
|
||||
hasBackground?: boolean;
|
||||
}
|
||||
|
||||
const SystemInfoItem: React.FC<SystemInfoItemProps> = ({
|
||||
@ -28,12 +30,21 @@ const SystemInfoItem: React.FC<SystemInfoItemProps> = ({
|
||||
value = '--',
|
||||
icon,
|
||||
endContent,
|
||||
hasBackground = false,
|
||||
}) => {
|
||||
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={clsx(
|
||||
'flex text-sm gap-2 p-3 items-center rounded-lg border border-white/20 transition-colors',
|
||||
hasBackground
|
||||
? 'bg-white/10 hover:bg-white/20 text-white/90'
|
||||
: 'bg-white/50 dark:bg-white/5 hover:bg-white/70 dark:hover:bg-white/10 text-default-600 dark:text-gray-300'
|
||||
)}>
|
||||
<div className="text-lg opacity-80">{icon}</div>
|
||||
<div className='w-24 font-medium'>{title}</div>
|
||||
<div className={clsx(
|
||||
'text-xs font-mono',
|
||||
hasBackground ? 'text-white/70' : 'text-default-500'
|
||||
)}>{value}</div>
|
||||
<div className='ml-auto'>{endContent}</div>
|
||||
</div>
|
||||
);
|
||||
@ -261,7 +272,11 @@ const NewVersionTip = (props: NewVersionTipProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const NapCatVersion = () => {
|
||||
interface NapCatVersionProps {
|
||||
hasBackground?: boolean;
|
||||
}
|
||||
|
||||
const NapCatVersion: React.FC<NapCatVersionProps> = ({ hasBackground = false }) => {
|
||||
const {
|
||||
data: packageData,
|
||||
loading: packageLoading,
|
||||
@ -274,6 +289,7 @@ const NapCatVersion = () => {
|
||||
<SystemInfoItem
|
||||
title='NapCat 版本'
|
||||
icon={<IoLogoOctocat className='text-xl' />}
|
||||
hasBackground={hasBackground}
|
||||
value={
|
||||
packageError
|
||||
? (
|
||||
@ -302,18 +318,28 @@ const SystemInfo: React.FC<SystemInfoProps> = (props) => {
|
||||
loading: qqVersionLoading,
|
||||
error: qqVersionError,
|
||||
} = useRequest(WebUIManager.getQQVersion);
|
||||
const [backgroundImage] = useLocalStorage<string>(key.backgroundImage, '');
|
||||
const hasBackground = !!backgroundImage;
|
||||
|
||||
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' />
|
||||
<Card className={clsx(
|
||||
'backdrop-blur-sm border border-white/40 dark:border-white/10 shadow-sm overflow-visible flex-1',
|
||||
hasBackground ? 'bg-white/10 dark:bg-black/10' : 'bg-white/60 dark:bg-black/40'
|
||||
)}>
|
||||
<CardHeader className={clsx(
|
||||
'pb-0 items-center gap-2 font-bold px-4 pt-4',
|
||||
hasBackground ? 'text-white drop-shadow-sm' : 'text-default-700 dark:text-white'
|
||||
)}>
|
||||
<FaCircleInfo className='text-lg opacity-80' />
|
||||
<span>系统信息</span>
|
||||
</CardHeader>
|
||||
<CardBody className='flex-1'>
|
||||
<div className='flex flex-col justify-between h-full'>
|
||||
<NapCatVersion />
|
||||
<div className='flex flex-col gap-2 justify-between h-full'>
|
||||
<NapCatVersion hasBackground={hasBackground} />
|
||||
<SystemInfoItem
|
||||
title='QQ 版本'
|
||||
icon={<FaQq className='text-lg' />}
|
||||
hasBackground={hasBackground}
|
||||
value={
|
||||
qqVersionError
|
||||
? (
|
||||
@ -332,11 +358,13 @@ const SystemInfo: React.FC<SystemInfoProps> = (props) => {
|
||||
title='WebUI 版本'
|
||||
icon={<IoLogoChrome className='text-xl' />}
|
||||
value='Next'
|
||||
hasBackground={hasBackground}
|
||||
/>
|
||||
<SystemInfoItem
|
||||
title='系统版本'
|
||||
icon={<RiMacFill className='text-xl' />}
|
||||
value={archInfo}
|
||||
hasBackground={hasBackground}
|
||||
/>
|
||||
</div>
|
||||
</CardBody>
|
||||
|
||||
@ -1,18 +1,21 @@
|
||||
import { Card, CardBody } from '@heroui/card';
|
||||
import { Image } from '@heroui/image';
|
||||
import { useLocalStorage } from '@uidotdev/usehooks';
|
||||
import clsx from 'clsx';
|
||||
import { BiSolidMemoryCard } from 'react-icons/bi';
|
||||
import { GiCpu } from 'react-icons/gi';
|
||||
|
||||
import bkg from '@/assets/images/bg/1AD934174C0107F14BAD8776D29C5F90.png';
|
||||
import key from '@/const/key';
|
||||
|
||||
import UsagePie from './usage_pie';
|
||||
|
||||
export interface SystemStatusItemProps {
|
||||
title: string
|
||||
value?: string | number
|
||||
size?: 'md' | 'lg'
|
||||
unit?: string
|
||||
title: string;
|
||||
value?: string | number;
|
||||
size?: 'md' | 'lg';
|
||||
unit?: string;
|
||||
hasBackground?: boolean;
|
||||
}
|
||||
|
||||
const SystemStatusItem: React.FC<SystemStatusItemProps> = ({
|
||||
@ -20,25 +23,35 @@ const SystemStatusItem: React.FC<SystemStatusItemProps> = ({
|
||||
value = '-',
|
||||
size = 'md',
|
||||
unit,
|
||||
hasBackground = false,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'shadow-sm shadow-primary-100 p-2 rounded-md text-sm bg-content1 bg-opacity-30',
|
||||
size === 'lg' ? 'col-span-2' : 'col-span-1 flex justify-between'
|
||||
'p-2 rounded-lg text-sm border border-white/20 transition-colors',
|
||||
size === 'lg' ? 'col-span-2' : 'col-span-1 flex justify-between',
|
||||
hasBackground
|
||||
? 'bg-white/10 hover:bg-white/20'
|
||||
: 'bg-white/50 dark:bg-white/5 hover:bg-white/70 dark:hover:bg-white/10'
|
||||
)}
|
||||
>
|
||||
<div className='w-24'>{title}</div>
|
||||
<div className='text-default-400'>
|
||||
<div className={clsx(
|
||||
'w-24 font-medium',
|
||||
hasBackground ? 'text-white/90' : 'text-default-600'
|
||||
)}>{title}</div>
|
||||
<div className={clsx(
|
||||
'font-mono text-xs',
|
||||
hasBackground ? 'text-white/70' : 'text-default-500'
|
||||
)}>
|
||||
{value}
|
||||
{unit}
|
||||
{unit && <span className="ml-0.5 opacity-70">{unit}</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export interface SystemStatusDisplayProps {
|
||||
data?: SystemStatus
|
||||
data?: SystemStatus;
|
||||
}
|
||||
|
||||
const SystemStatusDisplay: React.FC<SystemStatusDisplayProps> = ({ data }) => {
|
||||
@ -53,9 +66,14 @@ const SystemStatusDisplay: React.FC<SystemStatusDisplayProps> = ({ data }) => {
|
||||
memoryUsage.system = (systemUsage / system) * 100;
|
||||
memoryUsage.qq = (qqUsage / system) * 100;
|
||||
}
|
||||
const [backgroundImage] = useLocalStorage<string>(key.backgroundImage, '');
|
||||
const hasBackground = !!backgroundImage;
|
||||
|
||||
return (
|
||||
<Card className='bg-opacity-60 shadow-sm shadow-primary-100 col-span-1 lg:col-span-2 relative overflow-hidden'>
|
||||
<Card className={clsx(
|
||||
'backdrop-blur-sm border border-white/40 dark:border-white/10 shadow-sm col-span-1 lg:col-span-2 relative overflow-hidden',
|
||||
hasBackground ? 'bg-white/10 dark:bg-black/10' : 'bg-white/60 dark:bg-black/40'
|
||||
)}>
|
||||
<div className='absolute h-full right-0 top-0'>
|
||||
<Image
|
||||
src={bkg}
|
||||
@ -69,27 +87,35 @@ const SystemStatusDisplay: React.FC<SystemStatusDisplayProps> = ({ data }) => {
|
||||
</div>
|
||||
<CardBody className='overflow-visible md:flex-row gap-4 items-center justify-stretch z-10'>
|
||||
<div className='flex-1 w-full md:max-w-96'>
|
||||
<h2 className='text-lg font-semibold flex items-center gap-1 text-primary-400'>
|
||||
<GiCpu className='text-xl' />
|
||||
<h2 className={clsx(
|
||||
'text-lg font-semibold flex items-center gap-2 mb-2',
|
||||
hasBackground ? 'text-white drop-shadow-sm' : 'text-default-700 dark:text-gray-200'
|
||||
)}>
|
||||
<GiCpu className='text-xl opacity-80' />
|
||||
<span>CPU</span>
|
||||
</h2>
|
||||
<div className='grid grid-cols-2 gap-2'>
|
||||
<SystemStatusItem title='型号' value={data?.cpu.model} size='lg' />
|
||||
<SystemStatusItem title='内核数' value={data?.cpu.core} />
|
||||
<SystemStatusItem title='主频' value={data?.cpu.speed} unit='GHz' />
|
||||
<SystemStatusItem title='型号' value={data?.cpu.model} size='lg' hasBackground={hasBackground} />
|
||||
<SystemStatusItem title='内核数' value={data?.cpu.core} hasBackground={hasBackground} />
|
||||
<SystemStatusItem title='主频' value={data?.cpu.speed} unit='GHz' hasBackground={hasBackground} />
|
||||
<SystemStatusItem
|
||||
title='使用率'
|
||||
value={data?.cpu.usage.system}
|
||||
unit='%'
|
||||
hasBackground={hasBackground}
|
||||
/>
|
||||
<SystemStatusItem
|
||||
title='QQ主线程'
|
||||
value={data?.cpu.usage.qq}
|
||||
unit='%'
|
||||
hasBackground={hasBackground}
|
||||
/>
|
||||
</div>
|
||||
<h2 className='text-lg font-semibold flex items-center gap-1 text-primary-400 mt-2'>
|
||||
<BiSolidMemoryCard className='text-xl' />
|
||||
<h2 className={clsx(
|
||||
'text-lg font-semibold flex items-center gap-2 mb-2 mt-4',
|
||||
hasBackground ? 'text-white drop-shadow-sm' : 'text-default-700 dark:text-gray-200'
|
||||
)}>
|
||||
<BiSolidMemoryCard className='text-xl opacity-80' />
|
||||
<span>内存</span>
|
||||
</h2>
|
||||
<div className='grid grid-cols-2 gap-2'>
|
||||
@ -98,16 +124,19 @@ const SystemStatusDisplay: React.FC<SystemStatusDisplayProps> = ({ data }) => {
|
||||
value={data?.memory.total}
|
||||
size='lg'
|
||||
unit='MB'
|
||||
hasBackground={hasBackground}
|
||||
/>
|
||||
<SystemStatusItem
|
||||
title='使用量'
|
||||
value={data?.memory.usage.system}
|
||||
unit='MB'
|
||||
hasBackground={hasBackground}
|
||||
/>
|
||||
<SystemStatusItem
|
||||
title='QQ主线程'
|
||||
value={data?.memory.usage.qq}
|
||||
unit='MB'
|
||||
hasBackground={hasBackground}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -99,10 +99,8 @@ const Layout: React.FC<{ children: React.ReactNode; }> = ({ children }) => {
|
||||
transition={{ duration: 0.4 }}
|
||||
className={clsx(
|
||||
'flex-1 overflow-y-auto',
|
||||
'bg-white/60 dark:bg-black/40 backdrop-blur-xl',
|
||||
'shadow-[0_8px_32px_0_rgba(31,38,135,0.07)]',
|
||||
'transition-all duration-300 ease-in-out',
|
||||
openSideBar ? 'm-3 ml-0 rounded-3xl border border-white/40 dark:border-white/10' : 'm-0 rounded-none',
|
||||
openSideBar ? 'ml-0' : 'ml-0',
|
||||
'pb-10 md:pb-0'
|
||||
)}
|
||||
>
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import { Card, CardBody } from '@heroui/card';
|
||||
import { useLocalStorage } from '@uidotdev/usehooks';
|
||||
import { useRequest } from 'ahooks';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useEffect, useState, useRef } from 'react';
|
||||
import key from '@/const/key';
|
||||
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
@ -92,6 +95,9 @@ const SystemStatusCard: React.FC<SystemStatusCardProps> = ({ setArchInfo }) => {
|
||||
|
||||
const DashboardIndexPage: React.FC = () => {
|
||||
const [archInfo, setArchInfo] = useState<string>();
|
||||
// @ts-ignore
|
||||
const [backgroundImage] = useLocalStorage<string>(key.backgroundImage, '');
|
||||
const hasBackground = !!backgroundImage;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -105,7 +111,10 @@ const DashboardIndexPage: React.FC = () => {
|
||||
<SystemStatusCard setArchInfo={setArchInfo} />
|
||||
</div>
|
||||
<Networks />
|
||||
<Card className='bg-opacity-60 shadow-sm shadow-primary-100'>
|
||||
<Card className={clsx(
|
||||
'backdrop-blur-sm border border-white/40 dark:border-white/10 shadow-sm transition-all',
|
||||
hasBackground ? 'bg-white/10 dark:bg-black/10' : 'bg-white/60 dark:bg-black/40'
|
||||
)}>
|
||||
<CardBody>
|
||||
<Hitokoto />
|
||||
</CardBody>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user