Skip to content

Commit 11fac04

Browse files
feat: api
1 parent cdd8321 commit 11fac04

6 files changed

Lines changed: 49 additions & 41 deletions

File tree

ui/src/api/API_README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Admin API;Chat 目录作为独立体系预留。
55

66
```text
77
src/api/
8+
├── constants.ts # Admin 与 Chat 的 API base 路径常量
89
├── admin/
910
│ ├── auth/ # Admin 登录认证与当前用户接口
1011
│ │ └── types.ts # 认证 API 与认证 Store 共用类型
@@ -154,8 +155,12 @@ API 枚举与类型统一在 `src/api` 范围内管理,相关规则由本文
154155

155156
## 请求约定
156157

157-
- Admin 业务接口只声明相对资源路径,`/admin/api` 等部署前缀由 `core/request.ts` 统一处理。
158-
- Admin Router 与请求客户端直接读取 `window.MaxKB` 运行时路径配置;`Window`
158+
- `constants.ts` 统一导出 `ADMIN_API_BASE_PATH``CHAT_API_BASE_PATH`,分别优先读取
159+
`window.MaxKB.prefix``window.MaxKB.chatPrefix`,再回退到 `VITE_BASE_PATH` 和各自默认路径;
160+
去掉末尾斜杠后追加 `/api`。Admin、Chat 请求客户端和会话流式请求复用这些常量。
161+
- Admin 普通业务接口只声明相对资源路径,由 `core/request.ts` 的 Axios baseURL 处理部署前缀;
162+
流式接口显式传入对应的 API base 常量。
163+
- Admin Router 直接读取 `window.MaxKB` 运行时路径配置,请求客户端通过上述常量读取;`Window`
159164
`MaxKBRuntimeConfig` 的全局类型统一声明在根目录 `env.d.ts`
160165
- Admin 普通 JSON 请求使用 Axios;`request.ts` 导出 Axios 实例以及 `promise``get`
161166
`post``put``del`、流式响应 `postStream` 和 Blob 文件 `downloadRequest` 请求封装。
@@ -171,6 +176,7 @@ API 枚举与类型统一在 `src/api` 范围内管理,相关规则由本文
171176
登录页。
172177
- loading 不作为 API 函数参数,由调用接口的页面或 Store 管理。
173178
- 流式 POST 请求使用 `postStream` 返回原始 `Response`,由业务组件按具体协议解析数据块;
179+
参数顺序为 `postStream(base, path, data?, config?)``config.signal` 用于取消请求。
174180
鉴权、语言请求头和错误状态仍由请求基础设施统一处理。
175181
- 上传、下载和其他特殊请求在真实需求出现时独立设计,不提前塞入普通 JSON 请求客户端。
176182

ui/src/api/admin/core/request.ts

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import { useStore } from '@/stores'
66
import type { ApiResponse, LoadingTarget } from './types'
77
import type { Dict } from '@/api/types'
88
import { MsgError } from '@/utils/message'
9+
import { ADMIN_API_BASE_PATH } from '@/api/constants'
910

1011
const DEFAULT_TIMEOUT = 30 * 60 * 1_000 // 30 minutes
11-
const ADMIN_BASE_PATH = window.MaxKB?.prefix || import.meta.env.VITE_BASE_PATH || '/admin/'
1212

1313
interface ExportRequestConfig extends AxiosRequestConfig {
1414
skipGlobalErrorMessage?: boolean
@@ -128,7 +128,7 @@ async function downloadExportResponse(response: AxiosResponse<Blob>, fileName: s
128128
return true
129129
}
130130

131-
export const request = axios.create({ baseURL: `${ADMIN_BASE_PATH.replace(/\/+$/, '')}/api`, timeout: DEFAULT_TIMEOUT, withCredentials: false })
131+
export const request = axios.create({ baseURL: ADMIN_API_BASE_PATH, timeout: DEFAULT_TIMEOUT, withCredentials: false })
132132

133133
request.interceptors.request.use(setRequestHeaders)
134134

@@ -195,29 +195,9 @@ export function get<T = unknown>(url: string, params?: Dict<unknown>, loading?:
195195
return promise<T>(request.get<ApiResponse<T>>(url, { params, timeout }), loading)
196196
}
197197

198-
/** 发送指定方法的 Blob 请求并触发浏览器下载。 */
199-
export async function downloadRequest(
200-
url: string,
201-
method: string,
202-
data?: unknown,
203-
params?: Dict<unknown>,
204-
loading?: LoadingTarget,
205-
): Promise<boolean> {
206-
startLoading(loading)
207-
try {
208-
const response = await request.request<Blob>({
209-
url,
210-
method,
211-
data,
212-
params,
213-
responseType: 'blob',
214-
skipGlobalErrorMessage: true,
215-
} as ExportRequestConfig)
216-
217-
return downloadExportResponse(response, 'download')
218-
} finally {
219-
finishLoading(loading)
220-
}
198+
/** 发送 POST 请求。 */
199+
export function post<TData = unknown, T = unknown>(url: string, data?: TData, params?: Dict<unknown>, loading?: LoadingTarget, timeout?: number) {
200+
return promise<T>(request.post<ApiResponse<T>>(url, data, { params, timeout }), loading)
221201
}
222202

223203
/** 发送 GET 请求并将 Blob 响应下载为文件。 */
@@ -250,13 +230,33 @@ export async function postExportExcel<TData = unknown>(
250230
}
251231
}
252232

253-
/** 发送 POST 请求。 */
254-
export function post<TData = unknown, T = unknown>(url: string, data?: TData, params?: Dict<unknown>, loading?: LoadingTarget, timeout?: number) {
255-
return promise<T>(request.post<ApiResponse<T>>(url, data, { params, timeout }), loading)
233+
/** 发送指定方法的 Blob 请求并触发浏览器下载。 */
234+
export async function downloadRequest(
235+
url: string,
236+
method: string,
237+
data?: unknown,
238+
params?: Dict<unknown>,
239+
loading?: LoadingTarget,
240+
): Promise<boolean> {
241+
startLoading(loading)
242+
try {
243+
const response = await request.request<Blob>({
244+
url,
245+
method,
246+
data,
247+
params,
248+
responseType: 'blob',
249+
skipGlobalErrorMessage: true,
250+
} as ExportRequestConfig)
251+
252+
return downloadExportResponse(response, 'download')
253+
} finally {
254+
finishLoading(loading)
255+
}
256256
}
257257

258258
/** 发送 POST 请求并返回可逐块读取的原始响应。 */
259-
export function postStream(base: string, path: string, data?: unknown) {
259+
export function postStream(base: string, path: string, data?: unknown, config?: StreamRequestConfig): Promise<Response> {
260260
const { auth, user } = useStore()
261261
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
262262
if (auth.token) {
@@ -269,6 +269,7 @@ export function postStream(base: string, path: string, data?: unknown) {
269269
method: 'POST',
270270
headers,
271271
body: data === undefined ? undefined : JSON.stringify(data),
272+
signal: config?.signal,
272273
})
273274
}
274275

ui/src/api/admin/workspace/application/application.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { del, get, getExportFile, post, postStream, put } from '../../core/reque
22
import type { ParamsPage, ResponsePage } from '../../core/types'
33
import type { ApplicationDetail, ApplicationFormPayload, Dict, PromptGeneratePayload } from '@/api/types'
44
import { getWorkspaceId } from '@/utils/resource-context'
5+
import { ADMIN_API_BASE_PATH } from '@/api/constants'
56

67
const getPrefix = () => {
78
const workspaceId = getWorkspaceId()
@@ -74,7 +75,7 @@ const putApplicationPublish = (applicationId: string) => {
7475

7576
/** 使用指定模型流式生成或优化系统提示词。 */
7677
const postPromptGenerate = (applicationId: string, modelId: string, payload: PromptGeneratePayload, signal?: AbortSignal) => {
77-
return postStream(`${getPrefix()}/${applicationId}/model/${modelId}/prompt_generate`, payload, { signal })
78+
return postStream(ADMIN_API_BASE_PATH, `${getPrefix()}/${applicationId}/model/${modelId}/prompt_generate`, payload, { signal })
7879
}
7980

8081
export default {

ui/src/api/chat/core/request.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import { useStore } from '@/stores'
99
import type { ApiResponse, LoadingTarget } from './types'
1010
import type { Dict } from '@/api/types'
1111
import { MsgError } from '@/utils/message'
12+
import { CHAT_API_BASE_PATH } from '@/api/constants'
1213

1314
const DEFAULT_TIMEOUT = 30 * 60 * 1_000 // 30 minutes
14-
const CHAT_BASE_PATH = window.MaxKB?.chatPrefix || import.meta.env.VITE_BASE_PATH || '/chat/'
1515

1616
function setRequestHeaders(config: InternalAxiosRequestConfig) {
1717
const { auth, user } = useStore()
@@ -64,7 +64,7 @@ async function getResponseErrorMessage(error: unknown) {
6464
}
6565

6666
export const request = axios.create({
67-
baseURL: `${CHAT_BASE_PATH.replace(/\/+$/, '')}/api`,
67+
baseURL: CHAT_API_BASE_PATH,
6868
timeout: DEFAULT_TIMEOUT,
6969
withCredentials: false,
7070
})

ui/src/api/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** Admin 与 Chat 的 API 部署路径配置。 */
2+
const trimTrailingSlash = (value: string) => value.replace(/\/+$/, '')
3+
4+
export const ADMIN_API_BASE_PATH = trimTrailingSlash(window.MaxKB?.prefix || import.meta.env.VITE_BASE_PATH || '/admin/') + '/api'
5+
6+
export const CHAT_API_BASE_PATH = trimTrailingSlash(window.MaxKB?.chatPrefix || import.meta.env.VITE_BASE_PATH || '/chat/') + '/api'

ui/src/components/conversation/api/index.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,7 @@ import {
2121
} from '@/api/chat/core/request'
2222
import { useStore } from '@/stores'
2323
import { getWorkspaceId } from '@/utils/resource-context'
24-
25-
const trimTrailingSlash = (value: string) => value.replace(/\/+$/, '')
26-
const adminApiBase =
27-
trimTrailingSlash(window.MaxKB?.prefix || import.meta.env.VITE_BASE_PATH || '/admin/') + '/api'
28-
29-
const chatApiBase =
30-
trimTrailingSlash(window.MaxKB?.chatPrefix || import.meta.env.VITE_BASE_PATH || '/chat/') + '/api'
24+
import { ADMIN_API_BASE_PATH as adminApiBase, CHAT_API_BASE_PATH as chatApiBase } from '@/api/constants'
3125

3226
/** 发送流式 POST 请求,返回原始 `Response` 供 SSE 读取。 */
3327
function postStream(base: string, path: string, data?: unknown) {

0 commit comments

Comments
 (0)