mirror of
https://github.com/hamster1963/nezha-dash.git
synced 2025-04-24 21:10:45 +08:00
refactor: modularize ServerListClient with utility functions and components
This commit is contained in:
parent
1713189333
commit
07afc44eb7
@ -20,6 +20,77 @@ const ServerGlobal = dynamic(() => import("./Global"), {
|
|||||||
loading: () => <GlobalLoading />,
|
loading: () => <GlobalLoading />,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const sortServersByDisplayIndex = (servers: any[]) => {
|
||||||
|
return servers.sort((a, b) => {
|
||||||
|
const displayIndexDiff = (b.display_index || 0) - (a.display_index || 0)
|
||||||
|
return displayIndexDiff !== 0 ? displayIndexDiff : a.id - b.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterServersByStatus = (servers: any[], status: string) => {
|
||||||
|
return status === "all"
|
||||||
|
? servers
|
||||||
|
: servers.filter((server) => [status].includes(server.online_status ? "online" : "offline"))
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterServersByTag = (servers: any[], tag: string, defaultTag: string) => {
|
||||||
|
return tag === defaultTag ? servers : servers.filter((server) => server.tag === tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortServersByNetwork = (servers: any[]) => {
|
||||||
|
return [...servers].sort((a, b) => {
|
||||||
|
if (!a.online_status && b.online_status) return 1
|
||||||
|
if (a.online_status && !b.online_status) return -1
|
||||||
|
if (!a.online_status && !b.online_status) return 0
|
||||||
|
return b.status.NetInSpeed + b.status.NetOutSpeed - (a.status.NetInSpeed + a.status.NetOutSpeed)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTagCounts = (servers: any[]) => {
|
||||||
|
return servers.reduce((acc: Record<string, number>, server) => {
|
||||||
|
if (server.tag) {
|
||||||
|
acc[server.tag] = (acc[server.tag] || 0) + 1
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
|
const LoadingState = ({ t }: { t: any }) => (
|
||||||
|
<div className="flex flex-col items-center min-h-96 justify-center ">
|
||||||
|
<div className="font-semibold flex items-center gap-2 text-sm">
|
||||||
|
<Loader visible={true} />
|
||||||
|
{t("connecting")}...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const ErrorState = ({ error, t }: { error: Error; t: any }) => (
|
||||||
|
<div className="flex flex-col items-center justify-center">
|
||||||
|
<p className="text-sm font-medium opacity-40">{error.message}</p>
|
||||||
|
<p className="text-sm font-medium opacity-40">{t("error_message")}</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const ServerList = ({ servers, inline, containerRef }: { servers: any[]; inline: string; containerRef: any }) => {
|
||||||
|
if (inline === "1") {
|
||||||
|
return (
|
||||||
|
<section ref={containerRef} className="flex flex-col gap-2 overflow-x-scroll scrollbar-hidden">
|
||||||
|
{servers.map((serverInfo) => (
|
||||||
|
<ServerCardInline key={serverInfo.id} serverInfo={serverInfo} />
|
||||||
|
))}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section ref={containerRef} className="grid grid-cols-1 gap-2 md:grid-cols-2">
|
||||||
|
{servers.map((serverInfo) => (
|
||||||
|
<ServerCard key={serverInfo.id} serverInfo={serverInfo} />
|
||||||
|
))}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default function ServerListClient() {
|
export default function ServerListClient() {
|
||||||
const { status } = useStatus()
|
const { status } = useStatus()
|
||||||
const { filter } = useFilter()
|
const { filter } = useFilter()
|
||||||
@ -36,12 +107,9 @@ export default function ServerListClient() {
|
|||||||
if (inlineState !== null) {
|
if (inlineState !== null) {
|
||||||
setInline(inlineState)
|
setInline(inlineState)
|
||||||
}
|
}
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const savedTag = sessionStorage.getItem("selectedTag") || defaultTag
|
const savedTag = sessionStorage.getItem("selectedTag") || defaultTag
|
||||||
setTag(savedTag)
|
setTag(savedTag)
|
||||||
|
|
||||||
restoreScrollPosition()
|
restoreScrollPosition()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -71,73 +139,30 @@ export default function ServerListClient() {
|
|||||||
|
|
||||||
const { data, error } = useServerData()
|
const { data, error } = useServerData()
|
||||||
|
|
||||||
if (error)
|
if (error) return <ErrorState error={error} t={t} />
|
||||||
return (
|
if (!data?.result) return <LoadingState t={t} />
|
||||||
<div className="flex flex-col items-center justify-center">
|
|
||||||
<p className="text-sm font-medium opacity-40">{error.message}</p>
|
|
||||||
<p className="text-sm font-medium opacity-40">{t("error_message")}</p>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!data?.result)
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center min-h-96 justify-center ">
|
|
||||||
<div className="font-semibold flex items-center gap-2 text-sm">
|
|
||||||
<Loader visible={true} />
|
|
||||||
{t("connecting")}...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const { result } = data
|
const { result } = data
|
||||||
const sortedServers = result.sort((a, b) => {
|
const sortedServers = sortServersByDisplayIndex(result)
|
||||||
const displayIndexDiff = (b.display_index || 0) - (a.display_index || 0)
|
const filteredServersByStatus = filterServersByStatus(sortedServers, status)
|
||||||
if (displayIndexDiff !== 0) return displayIndexDiff
|
|
||||||
return a.id - b.id
|
|
||||||
})
|
|
||||||
|
|
||||||
const filteredServersByStatus =
|
|
||||||
status === "all"
|
|
||||||
? sortedServers
|
|
||||||
: sortedServers.filter((server) =>
|
|
||||||
[status].includes(server.online_status ? "online" : "offline"),
|
|
||||||
)
|
|
||||||
|
|
||||||
const allTag = filteredServersByStatus.map((server) => server.tag).filter(Boolean)
|
const allTag = filteredServersByStatus.map((server) => server.tag).filter(Boolean)
|
||||||
const uniqueTags = [...new Set(allTag)]
|
const uniqueTags = [...new Set(allTag)]
|
||||||
uniqueTags.unshift(defaultTag)
|
uniqueTags.unshift(defaultTag)
|
||||||
|
|
||||||
const filteredServers =
|
let filteredServers = filterServersByTag(filteredServersByStatus, tag, defaultTag)
|
||||||
tag === defaultTag
|
|
||||||
? filteredServersByStatus
|
|
||||||
: filteredServersByStatus.filter((server) => server.tag === tag)
|
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
filteredServers.sort((a, b) => {
|
filteredServers = sortServersByNetwork(filteredServers)
|
||||||
if (!a.online_status && b.online_status) return 1
|
|
||||||
if (a.online_status && !b.online_status) return -1
|
|
||||||
if (!a.online_status && !b.online_status) return 0
|
|
||||||
return (
|
|
||||||
b.status.NetInSpeed + b.status.NetOutSpeed - (a.status.NetInSpeed + a.status.NetOutSpeed)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagCountMap: Record<string, number> = {}
|
const tagCountMap = getTagCounts(filteredServersByStatus)
|
||||||
for (const server of filteredServersByStatus) {
|
|
||||||
if (server.tag) {
|
|
||||||
tagCountMap[server.tag] = (tagCountMap[server.tag] || 0) + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section className="flex items-center gap-2 w-full overflow-hidden">
|
<section className="flex items-center gap-2 w-full overflow-hidden">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => setShowMap(!showMap)}
|
||||||
setShowMap(!showMap)
|
|
||||||
}}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-[50px] text-white cursor-pointer [text-shadow:_0_1px_0_rgb(0_0_0_/_20%)] bg-blue-600 p-[10px] transition-all shadow-[inset_0_1px_0_rgba(255,255,255,0.2)]",
|
"rounded-[50px] text-white cursor-pointer [text-shadow:_0_1px_0_rgb(0_0_0_/_20%)] bg-blue-600 p-[10px] transition-all shadow-[inset_0_1px_0_rgba(255,255,255,0.2)]",
|
||||||
{
|
{
|
||||||
@ -150,11 +175,12 @@ export default function ServerListClient() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInline(inline === "0" ? "1" : "0")
|
const newInline = inline === "0" ? "1" : "0"
|
||||||
localStorage.setItem("inline", inline === "0" ? "1" : "0")
|
setInline(newInline)
|
||||||
|
localStorage.setItem("inline", newInline)
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-[50px] text-white cursor-pointer [text-shadow:_0_1px_0_rgb(0_0_0_/_20%)] bg-blue-600 p-[10px] transition-all shadow-[inset_0_1px_0_rgba(255,255,255,0.2)] ",
|
"rounded-[50px] text-white cursor-pointer [text-shadow:_0_1px_0_rgb(0_0_0_/_20%)] bg-blue-600 p-[10px] transition-all shadow-[inset_0_1px_0_rgba(255,255,255,0.2)]",
|
||||||
{
|
{
|
||||||
"shadow-[inset_0_1px_0_rgba(0,0,0,0.2)] bg-blue-500": inline === "1",
|
"shadow-[inset_0_1px_0_rgba(0,0,0,0.2)] bg-blue-500": inline === "1",
|
||||||
},
|
},
|
||||||
@ -172,24 +198,7 @@ export default function ServerListClient() {
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
{showMap && <ServerGlobal />}
|
{showMap && <ServerGlobal />}
|
||||||
{inline === "1" && (
|
<ServerList servers={filteredServers} inline={inline} containerRef={containerRef} />
|
||||||
<section
|
|
||||||
ref={containerRef}
|
|
||||||
className="flex flex-col gap-2 overflow-x-scroll scrollbar-hidden"
|
|
||||||
>
|
|
||||||
{filteredServers.map((serverInfo) => (
|
|
||||||
<ServerCardInline key={serverInfo.id} serverInfo={serverInfo} />
|
|
||||||
))}
|
|
||||||
</section>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{inline === "0" && (
|
|
||||||
<section ref={containerRef} className="grid grid-cols-1 gap-2 md:grid-cols-2">
|
|
||||||
{filteredServers.map((serverInfo) => (
|
|
||||||
<ServerCard key={serverInfo.id} serverInfo={serverInfo} />
|
|
||||||
))}
|
|
||||||
</section>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user