feat: paginate dashboard clients and proxies via API v2 (#5354)

Move the frps dashboard Clients and Proxies views to the paginated
/api/v2/clients and /api/v2/proxies endpoints instead of fetching all
data at once, and extend server-side proxy search so the search box
keeps working under pagination.

Frontend:
- Add V2Envelope/V2Page types and getV2 HTTP helper to api/http.ts
- Add v2 paginated fetch functions to api/client.ts and api/proxy.ts
- Add ClientV2Info and ProxyV2Info types for v2 API responses
- Rewrite Clients.vue with server-side pagination, status/user search
  filtering, and ElPagination component
- Rewrite Proxies.vue with server-side pagination, type tabs, client
  dropdown filter, and a search box that passes q to the API
- Default page size 10, selectable sizes [10, 20, 50, 100]

Backend:
- Extend /api/v2/proxies q matching to also cover online proxy spec
  fields: TCP/UDP remotePort and HTTP/HTTPS/TCPMux customDomains and
  subdomain, so dashboard search no longer needs to scan every page
- Add controller_v2 tests for the new spec-field matching
This commit is contained in:
fatedier
2026-06-03 14:08:45 +08:00
committed by GitHub
parent c6c545289c
commit 9bde0b07de
9 changed files with 536 additions and 175 deletions

View File

@@ -1,10 +1,26 @@
import { http } from './http'
import type { ClientInfoData } from '../types/client'
import { buildQueryString, http } from './http'
import type { V2Page } from './http'
import type { ClientInfoData, ClientListV2Params } from '../types/client'
export const getClients = () => {
return http.get<ClientInfoData[]>('../api/clients')
}
export const getClientsV2 = (params: ClientListV2Params = {}) => {
return http.getV2<V2Page<ClientInfoData>>(
`../api/v2/clients${buildQueryString({
page: params.page,
pageSize: params.pageSize,
status:
params.status && params.status !== 'all' ? params.status : undefined,
q: params.q || undefined,
user: params.user,
clientID: params.clientID || undefined,
runID: params.runID || undefined,
})}`,
)
}
export const getClient = (key: string) => {
return http.get<ClientInfoData>(`../api/clients/${key}`)
}