diff --git a/web_ui/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx b/web_ui/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx index 64f73f7e..f7ba31be 100644 --- a/web_ui/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx +++ b/web_ui/src/app/home/plugins/plugin-market/PluginMarketComponent.tsx @@ -6,9 +6,12 @@ import {PluginMarketCardVO} from "@/app/home/plugins/plugin-market/plugin-market import PluginMarketCardComponent from "@/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardComponent"; import {Input, Pagination} from "antd"; import {debounce} from "lodash" +import {httpClient, spaceClient} from "@/app/infra/http/HttpClient"; export default function PluginMarketComponent () { const [marketPluginList, setMarketPluginList] = useState([]) + const [totalCount, setTotalCount] = useState(0) + const [nowPage, setNowPage] = useState(1) const [searchKeyword, setSearchKeyword] = useState("") useEffect(() => { @@ -20,65 +23,25 @@ export default function PluginMarketComponent () { } function onInputSearchKeyword(keyword: string) { + // 这里记得加防抖,暂时没加 setSearchKeyword(keyword) - debounceSearch(keyword) + setNowPage(1) + getPluginList(1, keyword) } - const debounceSearch = useCallback( - debounce((keyword: string) => { - console.log("debounce search", keyword) - searchPlugin(keyword).then(marketPluginList => { - setMarketPluginList(marketPluginList) - }) - }, 500), [] - ) - async function searchPlugin(keyword: string, pageNumber: number = 1): Promise { - // TODO 实现搜索 - const demoResult: PluginMarketCardVO[] = [] - for (let i = 0; i < keyword.length; i ++) { - demoResult.push(new PluginMarketCardVO({ - author: "/hanahana", - description: "一个搜索测试的描述", - githubURL: "?", - name: "搜索插件" + i, - pluginId: `${i}`, - starCount: 19 + i, - version: `0.${i}`, - })) - } - return demoResult - } - - function getPluginList(pageNumber: number = 1) { - new Promise((resolve, reject) => { - const result = [ - new PluginMarketCardVO({ - pluginId: "aaa", - description: "一般的描述", - name: "插件AAA", - author: "/hana", - version: "0.1", - githubURL: "", - starCount: 23 - }), - ] - for (let i = 0; i < pageNumber; i ++) { - result.push( - new PluginMarketCardVO({ - pluginId: "aaa", - description: "一般的描述", - name: "插件AAA", - author: "/hana", - version: "0.1", - githubURL: "", - starCount: 23 - }) - ) - } - resolve(result) - }).then((value) => { - setMarketPluginList(value) + function getPluginList(page: number = nowPage, keyword: string = searchKeyword) { + spaceClient.getMarketPlugins(page, 10, 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, + }))) + setTotalCount(res.total) + console.log("market plugins:", res) }) } @@ -104,8 +67,9 @@ export default function PluginMarketComponent () { { + setNowPage(pageNumber) getPluginList(pageNumber) }} /> diff --git a/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO.ts b/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO.ts index 4a806ec4..6af3f199 100644 --- a/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO.ts +++ b/web_ui/src/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardVO.ts @@ -1,7 +1,6 @@ export interface IPluginMarketCardVO { pluginId: string; author: string, - version: string, name: string, description: string, starCount: number, @@ -13,7 +12,6 @@ export class PluginMarketCardVO implements IPluginMarketCardVO { description: string; name: string; author: string; - version: string; githubURL: string; starCount: number; @@ -21,11 +19,8 @@ export class PluginMarketCardVO implements IPluginMarketCardVO { this.description = prop.description this.name = prop.name this.author = prop.author - this.version = prop.version this.githubURL = prop.githubURL this.starCount = prop.starCount this.pluginId = prop.pluginId } - - } diff --git a/web_ui/src/app/infra/api/api-types/index.ts b/web_ui/src/app/infra/api/api-types/index.ts index 69aa4515..9a94fbad 100644 --- a/web_ui/src/app/infra/api/api-types/index.ts +++ b/web_ui/src/app/infra/api/api-types/index.ts @@ -179,4 +179,26 @@ export interface AsyncTask { export interface ApiRespUserToken { token: string; -} \ No newline at end of file +} + +export interface MarketPlugin { + ID: number + CreatedAt: string // ISO 8601 格式日期 + UpdatedAt: string + DeletedAt: string | null + name: string + author: string + description: string + repository: string // GitHub 仓库路径 + artifacts_path: string + stars: number + downloads: number + status: "synced" | string // 可根据实际状态值扩展联合类型 + synced_at: string + pushed_at: string // 最后一次代码推送时间 +} + +export interface MarketPluginResponse { + plugins: MarketPlugin[] + total: number +} diff --git a/web_ui/src/app/infra/http/HttpClient.ts b/web_ui/src/app/infra/http/HttpClient.ts index c092f08d..15efe49e 100644 --- a/web_ui/src/app/infra/http/HttpClient.ts +++ b/web_ui/src/app/infra/http/HttpClient.ts @@ -26,7 +26,7 @@ import { ApiRespSystemInfo, ApiRespAsyncTasks, ApiRespAsyncTask, - ApiRespUserToken + ApiRespUserToken, MarketPluginResponse } from "../api/api-types"; import { notification } from "antd"; @@ -50,19 +50,22 @@ export interface RequestConfig extends AxiosRequestConfig { class HttpClient { private instance: AxiosInstance; + private disableToken: boolean = false // 暂不需要SSR // private ssrInstance: AxiosInstance | null = null - constructor(baseURL?: string) { + constructor( + baseURL?: string, + disableToken?: boolean + ) { this.instance = axios.create({ baseURL: baseURL || this.getBaseUrl(), timeout: 15000, headers: { "Content-Type": "application/json", - "X-Requested-With": "XMLHttpRequest" } }); - + this.disableToken = disableToken || false this.initInterceptors(); } @@ -102,7 +105,7 @@ class HttpClient { // config.headers.Cookie = cookies().toString() // 客户端添加认证头 - if (typeof window !== "undefined") { + if (typeof window !== "undefined" && !this.disableToken) { const session = this.getSessionSync(); config.headers.Authorization = `Bearer ${session}`; } @@ -352,6 +355,19 @@ class HttpClient { return this.post(`/api/v1/plugins/${author}/${name}/update`); } + public getMarketPlugins( + page: number, + page_size: number, + query: string, + ): Promise { + return this.post(`/api/v1/market/plugins`, { + page, + page_size, + query, + sort_by: "stars", + sort_order: "DESC" + }) + } public installPluginFromGithub( source: string ): Promise { @@ -397,3 +413,6 @@ class HttpClient { } export const httpClient = new HttpClient("https://version-4.langbot.dev"); + +// 临时写法,未来两种Client都继承自HttpClient父类,不允许共享方法 +export const spaceClient = new HttpClient("https://space.langbot.app")