From 9d724dbb8d28bd8eb29e203544ea3d79b28f5455 Mon Sep 17 00:00:00 2001 From: chris <1637083533@qq.com> Date: Tue, 29 Apr 2025 14:58:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=93=E5=BA=93=E5=86=B2?= =?UTF-8?q?=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/home-sidebar/HomeSidebar.tsx | 118 ++++++++-------- web/src/app/home/layout.tsx | 4 +- .../PluginInstalledComponent.tsx | 1 + .../plugin-card/PluginCardComponent.tsx | 22 ++- .../plugin-market/PluginMarketComponent.tsx | 126 ++++++++---------- 5 files changed, 131 insertions(+), 140 deletions(-) diff --git a/web/src/app/home/components/home-sidebar/HomeSidebar.tsx b/web/src/app/home/components/home-sidebar/HomeSidebar.tsx index 56a6d6f5..7a950e91 100644 --- a/web/src/app/home/components/home-sidebar/HomeSidebar.tsx +++ b/web/src/app/home/components/home-sidebar/HomeSidebar.tsx @@ -1,81 +1,71 @@ -"use client" +"use client"; -import styles from "./HomeSidebar.module.css" +import styles from "./HomeSidebar.module.css"; import { useEffect, useState } from "react"; -import { SidebarChild, SidebarChildVO } from "@/app/home/components/home-sidebar/HomeSidebarChild"; -import { useRouter, usePathname, useSearchParams } from "next/navigation"; +import { + SidebarChild, + SidebarChildVO +} from "@/app/home/components/home-sidebar/HomeSidebarChild"; +import { useRouter, usePathname } from "next/navigation"; import { sidebarConfigList } from "@/app/home/components/home-sidebar/sidbarConfigList"; // TODO 侧边导航栏要加动画 export default function HomeSidebar({ - onSelectedChange + onSelectedChangeAction }: { - onSelectedChange: (sidebarChild: SidebarChildVO) => void + onSelectedChangeAction: (sidebarChild: SidebarChildVO) => void; }) { - // 路由相关 - const router = useRouter() - const pathname = usePathname(); - const searchParams = useSearchParams(); - // 路由被动变化时处理 - useEffect(() => { - handleRouteChange(pathname) - }, [pathname, searchParams]); + // 路由相关 + const router = useRouter(); + const pathname = usePathname(); + // 路由被动变化时处理 + useEffect(() => { + handleRouteChange(pathname); + }, [pathname]); - const [selectedChild, setSelectedChild] = useState(sidebarConfigList[0]) + const [selectedChild, setSelectedChild] = useState( + sidebarConfigList[0] + ); - useEffect(() => { - console.log('HomeSidebar挂载完成'); - initSelect() - return () => console.log('HomeSidebar卸载'); - }, []); + useEffect(() => { + console.log("HomeSidebar挂载完成"); + initSelect(); + return () => console.log("HomeSidebar卸载"); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + function handleChildClick(child: SidebarChildVO) { + setSelectedChild(child); + handleRoute(child); + onSelectedChangeAction(child); + } + function initSelect() { + handleChildClick(sidebarConfigList[0]); + } - function handleChildClick(child: SidebarChildVO) { - setSelectedChild(child) - handleRoute(child) - onSelectedChange(child) - } - - function initSelect() { - // 根据当前URL路径选择相应的菜单项,而不是总是使用第一个菜单项 - const currentPath = pathname; - const matchedChild = sidebarConfigList.find(child => child.route === currentPath); - - if (matchedChild) { - // 如果找到匹配的菜单项,则选择它 - setSelectedChild(matchedChild); - onSelectedChange(matchedChild); - } else { - // 如果没有匹配项,则回退到默认选择第一个菜单项 - handleChildClick(sidebarConfigList[0]); - } - } - - function handleRoute(child: SidebarChildVO) { - console.log(child) - router.push(`${child.route}`) - } - - function handleRouteChange(pathname: string) { - // TODO 这段逻辑并不好,未来router封装好后改掉 - // 判断在home下,并且路由更改的是自己的路由子组件则更新UI - const routeList = pathname.split('/') - if ( - routeList[1] === "home" && - sidebarConfigList.find(childConfig => - childConfig.route === pathname - ) - ) { - console.log("find success") - const routeSelectChild = sidebarConfigList.find(childConfig => - childConfig.route === pathname - ) - if (routeSelectChild) { - setSelectedChild(routeSelectChild) - } - } + function handleRoute(child: SidebarChildVO) { + console.log(child); + router.push(`${child.route}`); + } + + function handleRouteChange(pathname: string) { + // TODO 这段逻辑并不好,未来router封装好后改掉 + // 判断在home下,并且路由更改的是自己的路由子组件则更新UI + const routeList = pathname.split("/"); + if ( + routeList[1] === "home" && + sidebarConfigList.find((childConfig) => childConfig.route === pathname) + ) { + console.log("find success"); + const routeSelectChild = sidebarConfigList.find( + (childConfig) => childConfig.route === pathname + ); + if (routeSelectChild) { + setSelectedChild(routeSelectChild); + } } + } return ( diff --git a/web/src/app/home/layout.tsx b/web/src/app/home/layout.tsx index 8ac4efb4..c765aef0 100644 --- a/web/src/app/home/layout.tsx +++ b/web/src/app/home/layout.tsx @@ -18,7 +18,7 @@ export default function HomeLayout({ }>) { const router = useRouter(); const [title, setTitle] = useState("") - const onSelectedChange = (child: SidebarChildVO) => { + const onSelectedChangeAction = (child: SidebarChildVO) => { setTitle(child.name) } @@ -28,7 +28,7 @@ export default function HomeLayout({ {/* HomeSidebar 为侧边栏 */} diff --git a/web/src/app/home/plugins/plugin-installed/PluginInstalledComponent.tsx b/web/src/app/home/plugins/plugin-installed/PluginInstalledComponent.tsx index 2897cef8..be770733 100644 --- a/web/src/app/home/plugins/plugin-installed/PluginInstalledComponent.tsx +++ b/web/src/app/home/plugins/plugin-installed/PluginInstalledComponent.tsx @@ -16,6 +16,7 @@ export default function PluginInstalledComponent() { useEffect(() => { initData() + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) function initData() { diff --git a/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx b/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx index 267bb3b7..9efbbe9e 100644 --- a/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx +++ b/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx @@ -1,13 +1,33 @@ import styles from "./pluginCard.module.css" import { PluginCardVO } from "@/app/home/plugins/plugin-installed/PluginCardVO"; import { GithubOutlined, LinkOutlined, ToolOutlined } from '@ant-design/icons'; -import { Tag } from 'antd' +import { Switch, Tag } from 'antd' +import { useState } from "react"; +import { httpClient } from "@/app/infra/http/HttpClient"; export default function PluginCardComponent({ cardVO }: { cardVO: PluginCardVO }) { + const [initialized, setInitialized] = useState(cardVO.isInitialized); + const [switchEnable, setSwitchEnable] = useState(true); + + function handleEnable() { + setSwitchEnable(false); + httpClient + .togglePlugin(cardVO.author, cardVO.name, !initialized) + .then(() => { + setInitialized(!initialized); + }) + .catch((err) => { + console.log("error: ", err); + }) + .finally(() => { + setSwitchEnable(true); + }); + } + return (
{/* header */} diff --git a/web/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx b/web/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx index 793db49c..9e84c0ff 100644 --- a/web/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx +++ b/web/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx @@ -1,90 +1,70 @@ -"use client" +"use client"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import styles from "@/app/home/plugins/plugins.module.css"; import { PluginMarketCardVO } from "@/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO"; import PluginMarketCardComponent from "@/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardComponent"; import { Input, Pagination } from "antd"; -import { debounce } from "lodash" +import { spaceClient } from "@/app/infra/http/HttpClient"; export default function PluginMarketComponent() { - const [marketPluginList, setMarketPluginList] = useState([]) - const [searchKeyword, setSearchKeyword] = useState("") - const [currentPage, setCurrentPage] = useState(1) - const [totalItems, setTotalItems] = useState(0) - const [loading, setLoading] = useState(false) - const pageSize = 10 // 每页显示的项目数量 + const [marketPluginList, setMarketPluginList] = useState< + PluginMarketCardVO[] + >([]); + const [totalCount, setTotalCount] = useState(0); + const [nowPage, setNowPage] = useState(1); + const [searchKeyword, setSearchKeyword] = useState(""); + const [loading, setLoading] = useState(false); + const pageSize = 10; useEffect(() => { - fetchPlugins(searchKeyword, currentPage) - }, [currentPage]) + initData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); - // 获取插件列表,整合了搜索和分页功能 - async function fetchPlugins(keyword: string = "", page: number = 1): Promise { - setLoading(true) - try { - // 实际应用中,这里应该调用API获取数据 - const result = await mockFetchPlugins(keyword, page, pageSize) - setMarketPluginList(result.data) - setTotalItems(result.total) - } finally { - setLoading(false) - } - } - - // 模拟从API获取数据 - async function mockFetchPlugins(keyword: string, page: number, pageSize: number): Promise<{ data: PluginMarketCardVO[], total: number }> { - // 模拟API延迟 - await new Promise(resolve => setTimeout(resolve, 300)) - - // 创建模拟数据 - const allPlugins: PluginMarketCardVO[] = [] - const totalPlugins = 50 // 模拟总数据量 - - for (let i = 0; i < totalPlugins; i++) { - allPlugins.push(new PluginMarketCardVO({ - pluginId: `plugin-${i}`, - description: `这是插件 ${i} 的描述,包含一些详细信息`, - name: `插件 ${i}`, - author: `/author-${i % 5}`, // 模拟5个不同的作者 - version: `0.${i % 10}`, - githubURL: `https://github.com/author-${i % 5}/plugin-${i}`, - starCount: 10 + Math.floor(Math.random() * 100) - })) - } - - // 根据关键词过滤 - const filtered = keyword - ? allPlugins.filter(p => - p.name.toLowerCase().includes(keyword.toLowerCase()) || - p.description.toLowerCase().includes(keyword.toLowerCase())) - : allPlugins - - // 分页处理 - const start = (page - 1) * pageSize - const end = start + pageSize - const paginatedData = filtered.slice(start, end) - - return { - data: paginatedData, - total: filtered.length - } + function initData() { + getPluginList(); } function onInputSearchKeyword(keyword: string) { - setSearchKeyword(keyword) - setCurrentPage(1) // 搜索时重置为第一页 - debounceSearch(keyword) + // 这里记得加防抖,暂时没加 + setSearchKeyword(keyword); + setNowPage(1); + getPluginList(1, keyword); } - const debounceSearch = useCallback( - debounce((keyword: string) => { - fetchPlugins(keyword, 1) - }, 500), [] - ) + function getPluginList( + page: number = nowPage, + keyword: string = searchKeyword + ) { + setLoading(true); + spaceClient.getMarketPlugins(page, pageSize, keyword).then((res) => { + setMarketPluginList( + res.plugins.map( + (marketPlugin) => + new PluginMarketCardVO({ + author: marketPlugin.author, + description: marketPlugin.description, + githubURL: marketPlugin.repository, + name: marketPlugin.name, + pluginId: String(marketPlugin.ID), + starCount: marketPlugin.stars, + version: "version" in marketPlugin ? String(marketPlugin.version) : "1.0.0", // Default version if not provided + }) + ) + ); + setTotalCount(res.total); + setLoading(false); + console.log("market plugins:", res); + }).catch(error => { + console.error("获取插件列表失败:", error); + setLoading(false); + }); + } function handlePageChange(page: number) { - setCurrentPage(page) + setNowPage(page); + getPluginList(page); } return ( @@ -111,11 +91,11 @@ export default function PluginMarketComponent() { )) )}
- {totalItems > 0 && ( + {totalCount > 0 && (