Skip to content

Commit ef2dafd

Browse files
committed
refactor(admin): migrate data layer to V2 API response contract
- transformResponse unwraps the { data, meta? } envelope and lifts meta.pagination into { data, pagination } - onResponseError reads the { error: { code, message } } body; BusinessError carries an optional code - Pager becomes { page, size, total, totalPages }; ripple field renames through table, list views and pagination hooks - enrichment-admin / search-admin keep local legacy pager types (those endpoints still emit the legacy pagination shape) - drop the removed ?select= param from posts/notes/pages api + callers
1 parent a771da6 commit ef2dafd

24 files changed

Lines changed: 115 additions & 103 deletions

File tree

apps/admin/src/api/notes.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { request } from '~/utils/request'
66
export interface GetNotesParams {
77
page?: number
88
size?: number
9-
select?: string
109
sortBy?: string
1110
sortOrder?: number
1211
db_query?: Record<string, boolean>

apps/admin/src/api/pages.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { request } from '~/utils/request'
66
export interface GetPagesParams {
77
page?: number
88
size?: number
9-
select?: string
109
}
1110

1211
export interface CreatePageData {

apps/admin/src/api/posts.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { request } from '~/utils/request'
66
export interface GetPostsParams {
77
page?: number
88
size?: number
9-
select?: string
109
sortBy?: string
1110
sortOrder?: number
1211
categoryIds?: string[]

apps/admin/src/components/table/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ export const Table = defineComponent({
123123
noPagination
124124
? undefined
125125
: pager?.value && {
126-
page: pager.value.currentPage,
126+
page: pager.value.page,
127127
pageSize: pager.value.size,
128-
pageCount: pager.value.totalPage,
128+
pageCount: pager.value.totalPages,
129129
// showQuickJumper: ui.viewport.value.mobile ? false : true,
130130
showQuickJumper: true,
131131
pageSlot: ui.viewport.value.mobile

apps/admin/src/hooks/use-memo-fetch-data-list.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ export const createMemoDataListFetchHook = <
2525
loading.value = false
2626
data.forEach((i) => idSet.add(i.id))
2727

28-
currentPage = pagination.currentPage
29-
if (!pagination.hasNextPage) {
28+
currentPage = pagination.page
29+
if (pagination.page >= pagination.totalPages) {
3030
isEnd = true
3131
}
3232
}

apps/admin/src/models/base.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
export interface Pager {
2-
total: number
2+
page: number
33
size: number
4-
currentPage: number
5-
totalPage: number
6-
hasPrevPage: boolean
7-
hasNextPage: boolean
4+
total: number
5+
totalPages: number
86
}
97

108
export interface PaginateResult<T> {

apps/admin/src/models/enrichment.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import type { Pager } from './base'
1+
export interface LegacyPager {
2+
total: number
3+
size: number
4+
currentPage: number
5+
totalPage: number
6+
hasPrevPage: boolean
7+
hasNextPage: boolean
8+
}
29

310
export interface EnrichmentImage {
411
url: string
@@ -66,7 +73,7 @@ export interface EnrichmentRow {
6673

6774
export interface EnrichmentListResponse {
6875
data: EnrichmentRow[]
69-
pagination: Pager
76+
pagination: LegacyPager
7077
}
7178

7279
export interface EnrichmentScreenshotRow {
@@ -91,7 +98,7 @@ export interface EnrichmentScreenshotJoinedRow extends EnrichmentScreenshotRow {
9198

9299
export interface EnrichmentScreenshotListResponse {
93100
data: EnrichmentScreenshotJoinedRow[]
94-
pagination: Pager
101+
pagination: LegacyPager
95102
}
96103

97104
export interface EnrichmentScreenshotQuota {

apps/admin/src/models/search-index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import type { Pager } from './base'
1+
export interface SearchIndexLegacyPager {
2+
total: number
3+
size: number
4+
currentPage: number
5+
totalPage: number
6+
hasPrevPage: boolean
7+
hasNextPage: boolean
8+
}
29

310
export type SearchIndexRefType = 'post' | 'note' | 'page'
411

@@ -32,7 +39,7 @@ export interface SearchDocumentAdminRow {
3239

3340
export interface SearchDocumentAdminListResponse {
3441
data: SearchDocumentAdminRow[]
35-
pagination: Pager
42+
pagination: SearchIndexLegacyPager
3643
}
3744

3845
export interface SearchDocumentAdminListParams {

apps/admin/src/utils/request.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ import { ofetch } from 'ofetch'
22
import { toast } from 'vue-sonner'
33
import type { FetchOptions } from 'ofetch'
44

5-
import { simpleCamelcaseKeys } from './camelcase-keys'
6-
75
import { API_URL } from '~/constants/env'
86

97
import { router } from '../router/router'
8+
import { simpleCamelcaseKeys } from './camelcase-keys'
109
import { uuid } from './index'
1110

1211
export class SystemError extends Error {
@@ -24,6 +23,7 @@ export class BusinessError extends Error {
2423
message: string | string[],
2524
public statusCode: number,
2625
public data?: unknown,
26+
public code?: string | number,
2727
) {
2828
super(Array.isArray(message) ? message.join(', ') : message)
2929
this.name = 'BusinessError'
@@ -73,10 +73,11 @@ export const $api = ofetch.create({
7373
}
7474

7575
const data = response._data
76-
const message = data?.message || '请求失败'
76+
const message = data?.error?.message || data?.message || '请求失败'
77+
const code = data?.error?.code
7778
const displayMsg = Array.isArray(message) ? message.join(', ') : message
7879
toast.error(displayMsg)
79-
throw new BusinessError(message, status, data)
80+
throw new BusinessError(message, status, data, code)
8081
},
8182
})
8283

@@ -86,27 +87,31 @@ export type RequestOptions<T = unknown> = Omit<FetchOptions<'json'>, 'body'> & {
8687
bypassTransform?: boolean
8788
}
8889

89-
/**
90-
* 转换响应数据
91-
* 1. camelCase 转换
92-
* 2. 解包后端包装的数组响应 { data: [...] } -> [...]
93-
*/
90+
function isPlainObject(value: unknown): value is Record<string, unknown> {
91+
return !!value && typeof value === 'object' && !Array.isArray(value)
92+
}
93+
94+
function isResponseEnvelope(value: unknown): value is Record<string, unknown> {
95+
return (
96+
isPlainObject(value) &&
97+
'data' in value &&
98+
Object.keys(value).every((key) => key === 'data' || key === 'meta')
99+
)
100+
}
101+
94102
function transformResponse<T>(data: unknown, bypass?: boolean): T {
95103
if (bypass || !data || typeof data !== 'object') {
96104
return data as T
97105
}
98106

99-
let result = simpleCamelcaseKeys(data as Record<string, unknown>)
107+
const result = simpleCamelcaseKeys(data as Record<string, unknown>)
100108

101-
if (
102-
result &&
103-
typeof result === 'object' &&
104-
!Array.isArray(result) &&
105-
'data' in result &&
106-
Array.isArray(result.data) &&
107-
Object.keys(result).length === 1
108-
) {
109-
result = result.data
109+
if (isResponseEnvelope(result)) {
110+
const meta = (result as any).meta
111+
if (meta && isPlainObject(meta.pagination)) {
112+
return { data: (result as any).data, pagination: meta.pagination } as T
113+
}
114+
return (result as any).data as T
110115
}
111116

112117
return result as T

apps/admin/src/views/ai/components/article-selector-modal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,15 @@ export const ArticleSelectorModal = defineComponent({
115115
shouldFetchPosts
116116
? hasKeyword
117117
? searchApi.searchPosts({ keyword, size: 50 })
118-
: postsApi.getList({ size: 50, select: 'title' })
118+
: postsApi.getList({ size: 50 })
119119
: Promise.resolve({ data: [] }),
120120
shouldFetchNotes
121121
? hasKeyword
122122
? searchApi.searchNotes({ keyword, size: 50 })
123-
: notesApi.getList({ size: 50, select: 'title' })
123+
: notesApi.getList({ size: 50 })
124124
: Promise.resolve({ data: [] }),
125125
shouldFetchPages
126-
? pagesApi.getList({ select: 'title' })
126+
? pagesApi.getList({})
127127
: Promise.resolve({ data: [] }),
128128
])
129129

0 commit comments

Comments
 (0)