feat: plugin market pagination access api

This commit is contained in:
HYana
2025-04-28 19:06:41 +08:00
parent 3d31ace50b
commit 9850a0c2bf
4 changed files with 67 additions and 67 deletions
@@ -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 PluginMarketCardComponent from "@/app/home/plugins/plugin-market/plugin-market-card/PluginMarketCardComponent";
import {Input, Pagination} from "antd"; import {Input, Pagination} from "antd";
import {debounce} from "lodash" import {debounce} from "lodash"
import {httpClient, spaceClient} from "@/app/infra/http/HttpClient";
export default function PluginMarketComponent () { export default function PluginMarketComponent () {
const [marketPluginList, setMarketPluginList] = useState<PluginMarketCardVO[]>([]) const [marketPluginList, setMarketPluginList] = useState<PluginMarketCardVO[]>([])
const [totalCount, setTotalCount] = useState(0)
const [nowPage, setNowPage] = useState(1)
const [searchKeyword, setSearchKeyword] = useState("") const [searchKeyword, setSearchKeyword] = useState("")
useEffect(() => { useEffect(() => {
@@ -20,65 +23,25 @@ export default function PluginMarketComponent () {
} }
function onInputSearchKeyword(keyword: string) { function onInputSearchKeyword(keyword: string) {
// 这里记得加防抖,暂时没加
setSearchKeyword(keyword) 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<PluginMarketCardVO[]> { function getPluginList(page: number = nowPage, keyword: string = searchKeyword) {
// TODO 实现搜索 spaceClient.getMarketPlugins(page, 10, keyword).then(res => {
const demoResult: PluginMarketCardVO[] = [] setMarketPluginList(res.plugins.map(marketPlugin => new PluginMarketCardVO({
for (let i = 0; i < keyword.length; i ++) { author: marketPlugin.author,
demoResult.push(new PluginMarketCardVO({ description: marketPlugin.description,
author: "/hanahana", githubURL: marketPlugin.repository,
description: "一个搜索测试的描述", name: marketPlugin.name,
githubURL: "", pluginId: String(marketPlugin.ID),
name: "搜索插件" + i, starCount: marketPlugin.stars,
pluginId: `${i}`, })))
starCount: 19 + i, setTotalCount(res.total)
version: `0.${i}`, console.log("market plugins:", res)
}))
}
return demoResult
}
function getPluginList(pageNumber: number = 1) {
new Promise<PluginMarketCardVO[]>((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)
}) })
} }
@@ -104,8 +67,9 @@ export default function PluginMarketComponent () {
</div> </div>
<Pagination <Pagination
defaultCurrent={1} defaultCurrent={1}
total={500} total={totalCount}
onChange={(pageNumber) => { onChange={(pageNumber) => {
setNowPage(pageNumber)
getPluginList(pageNumber) getPluginList(pageNumber)
}} }}
/> />
@@ -1,7 +1,6 @@
export interface IPluginMarketCardVO { export interface IPluginMarketCardVO {
pluginId: string; pluginId: string;
author: string, author: string,
version: string,
name: string, name: string,
description: string, description: string,
starCount: number, starCount: number,
@@ -13,7 +12,6 @@ export class PluginMarketCardVO implements IPluginMarketCardVO {
description: string; description: string;
name: string; name: string;
author: string; author: string;
version: string;
githubURL: string; githubURL: string;
starCount: number; starCount: number;
@@ -21,11 +19,8 @@ export class PluginMarketCardVO implements IPluginMarketCardVO {
this.description = prop.description this.description = prop.description
this.name = prop.name this.name = prop.name
this.author = prop.author this.author = prop.author
this.version = prop.version
this.githubURL = prop.githubURL this.githubURL = prop.githubURL
this.starCount = prop.starCount this.starCount = prop.starCount
this.pluginId = prop.pluginId this.pluginId = prop.pluginId
} }
} }
@@ -180,3 +180,25 @@ export interface AsyncTask {
export interface ApiRespUserToken { export interface ApiRespUserToken {
token: string; token: string;
} }
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
}
+24 -5
View File
@@ -26,7 +26,7 @@ import {
ApiRespSystemInfo, ApiRespSystemInfo,
ApiRespAsyncTasks, ApiRespAsyncTasks,
ApiRespAsyncTask, ApiRespAsyncTask,
ApiRespUserToken ApiRespUserToken, MarketPluginResponse
} from "../api/api-types"; } from "../api/api-types";
import { notification } from "antd"; import { notification } from "antd";
@@ -50,19 +50,22 @@ export interface RequestConfig extends AxiosRequestConfig {
class HttpClient { class HttpClient {
private instance: AxiosInstance; private instance: AxiosInstance;
private disableToken: boolean = false
// 暂不需要SSR // 暂不需要SSR
// private ssrInstance: AxiosInstance | null = null // private ssrInstance: AxiosInstance | null = null
constructor(baseURL?: string) { constructor(
baseURL?: string,
disableToken?: boolean
) {
this.instance = axios.create({ this.instance = axios.create({
baseURL: baseURL || this.getBaseUrl(), baseURL: baseURL || this.getBaseUrl(),
timeout: 15000, timeout: 15000,
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest"
} }
}); });
this.disableToken = disableToken || false
this.initInterceptors(); this.initInterceptors();
} }
@@ -102,7 +105,7 @@ class HttpClient {
// config.headers.Cookie = cookies().toString() // config.headers.Cookie = cookies().toString()
// 客户端添加认证头 // 客户端添加认证头
if (typeof window !== "undefined") { if (typeof window !== "undefined" && !this.disableToken) {
const session = this.getSessionSync(); const session = this.getSessionSync();
config.headers.Authorization = `Bearer ${session}`; config.headers.Authorization = `Bearer ${session}`;
} }
@@ -352,6 +355,19 @@ class HttpClient {
return this.post(`/api/v1/plugins/${author}/${name}/update`); return this.post(`/api/v1/plugins/${author}/${name}/update`);
} }
public getMarketPlugins(
page: number,
page_size: number,
query: string,
): Promise<MarketPluginResponse> {
return this.post(`/api/v1/market/plugins`, {
page,
page_size,
query,
sort_by: "stars",
sort_order: "DESC"
})
}
public installPluginFromGithub( public installPluginFromGithub(
source: string source: string
): Promise<AsyncTaskCreatedResp> { ): Promise<AsyncTaskCreatedResp> {
@@ -397,3 +413,6 @@ class HttpClient {
} }
export const httpClient = new HttpClient("https://version-4.langbot.dev"); export const httpClient = new HttpClient("https://version-4.langbot.dev");
// 临时写法,未来两种Client都继承自HttpClient父类,不允许共享方法
export const spaceClient = new HttpClient("https://space.langbot.app")