提示词保存
This commit is contained in:
@@ -1,118 +0,0 @@
|
||||
# API 统一管理说明
|
||||
|
||||
## 📁 目录结构
|
||||
|
||||
```
|
||||
api/
|
||||
├── config.js # API 基础配置(统一管理所有基础 URL)
|
||||
├── index.js # 统一导出入口(所有 API 服务从这里导出)
|
||||
├── http.js # Axios 实例和拦截器
|
||||
├── auth.js # 认证相关 API
|
||||
├── chat.js # 聊天相关 API
|
||||
├── common.js # 通用服务 API
|
||||
└── tikhub/ # TikHub 相关 API
|
||||
├── index.js
|
||||
├── tikhub.js
|
||||
└── types.js
|
||||
```
|
||||
|
||||
## 🚀 使用方式
|
||||
|
||||
### 方式一:从统一入口导入(推荐)
|
||||
|
||||
```javascript
|
||||
// 导入所有 API
|
||||
import { ChatMessageApi, AuthApi, CommonService, TikhubService } from '@/api'
|
||||
|
||||
// 或按需导入
|
||||
import { ChatMessageApi } from '@/api'
|
||||
import { AuthApi } from '@/api'
|
||||
```
|
||||
|
||||
### 方式二:从具体文件导入(兼容旧代码)
|
||||
|
||||
```javascript
|
||||
// 仍然支持原有的导入方式
|
||||
import { ChatMessageApi } from '@/api/chat'
|
||||
import { CommonService } from '@/api/common'
|
||||
```
|
||||
|
||||
### 方式三:使用配置工具函数
|
||||
|
||||
```javascript
|
||||
import { getApiUrl, API_BASE } from '@/api/config'
|
||||
|
||||
// 获取完整 API URL
|
||||
const url = getApiUrl('ADMIN_AI', '/chat/conversation/create-my')
|
||||
// 结果: /admin-api/ai/chat/conversation/create-my
|
||||
|
||||
// 直接使用配置
|
||||
const baseUrl = API_BASE.ADMIN_AI
|
||||
```
|
||||
|
||||
## 📝 API 配置说明
|
||||
|
||||
### config.js
|
||||
|
||||
所有 API 基础 URL 统一在 `config.js` 中管理:
|
||||
|
||||
```javascript
|
||||
export const API_BASE = {
|
||||
ADMIN: '/admin-api', // 管理后台基础路径
|
||||
APP: '/app-api', // 会员端基础路径
|
||||
ADMIN_AI: '/admin-api/ai', // AI 模块(管理后台)
|
||||
APP_MEMBER: '/app-api/member', // 会员模块
|
||||
TIKHUB: '/webApi/admin-api/ai/tikHup', // TikHub(管理后台)
|
||||
TIKHUB_APP: '/app-api/api/tikHup', // TikHub(会员端)
|
||||
}
|
||||
```
|
||||
|
||||
### 添加新的 API 模块
|
||||
|
||||
1. 在 `config.js` 中添加新的基础路径:
|
||||
```javascript
|
||||
export const API_BASE = {
|
||||
// ... 现有配置
|
||||
NEW_MODULE: `${BASE_URL}/admin-api/new-module`,
|
||||
}
|
||||
```
|
||||
|
||||
2. 创建新的 API 文件(如 `new-module.js`):
|
||||
```javascript
|
||||
import request from '@/api/http'
|
||||
import { API_BASE } from '@/api/config'
|
||||
|
||||
const BASE = API_BASE.NEW_MODULE
|
||||
|
||||
export const NewModuleApi = {
|
||||
getList: () => request.get(`${BASE}/list`),
|
||||
create: (data) => request.post(`${BASE}/create`, data),
|
||||
}
|
||||
```
|
||||
|
||||
3. 在 `index.js` 中导出:
|
||||
```javascript
|
||||
export { NewModuleApi } from './new-module'
|
||||
```
|
||||
|
||||
## 🔧 HTTP 实例
|
||||
|
||||
所有 API 都使用统一的 HTTP 实例(`http.js`),已配置:
|
||||
- ✅ 自动 Token 注入
|
||||
- ✅ 统一错误处理
|
||||
- ✅ 请求/响应拦截器
|
||||
- ✅ 白名单机制(无需 Token 的接口)
|
||||
|
||||
## 📌 注意事项
|
||||
|
||||
1. **基础 URL 配置**:所有 API 的基础 URL 都应该在 `config.js` 中定义,不要在业务文件中硬编码
|
||||
2. **统一导出**:新增 API 服务后,记得在 `index.js` 中导出
|
||||
3. **向后兼容**:保持原有的导入方式仍然可用,方便逐步迁移
|
||||
|
||||
## 🎯 最佳实践
|
||||
|
||||
1. **使用统一入口**:优先使用 `@/api` 统一导入
|
||||
2. **配置集中管理**:所有 URL 配置都在 `config.js`
|
||||
3. **类型安全**:使用 TypeScript 时,可以为 API 添加类型定义
|
||||
4. **错误处理**:利用 HTTP 拦截器统一处理错误
|
||||
|
||||
@@ -4,7 +4,8 @@ import { getAccessToken } from '@/utils/auth'
|
||||
// 使用公共配置
|
||||
import { API_BASE } from '@gold/config/api'
|
||||
|
||||
const SERVER_BASE_AI = API_BASE.ADMIN_AI
|
||||
// C 端使用 APP_AI,如果不存在则回退到 ADMIN_AI
|
||||
const SERVER_BASE_AI = API_BASE.APP_AI || API_BASE.ADMIN_AI
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +1,41 @@
|
||||
import http from '@/api/http'
|
||||
/**
|
||||
* 应用层 API 服务
|
||||
* 封装应用特定的 API 调用,使用 mono 级别的服务
|
||||
*/
|
||||
|
||||
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
||||
import { getAuthHeader } from '@gold/utils/token-manager'
|
||||
// 使用公共配置和 API 服务创建器
|
||||
import { TikHubService } from '@gold/api/services'
|
||||
import { API_BASE } from '@gold/config/api'
|
||||
import { createApiService } from '@gold/api/services'
|
||||
// 初始化公共 hook 的 API 服务
|
||||
import { setApiService } from '@gold/hooks/web/useVoiceText'
|
||||
|
||||
// 使用本地代理前缀 /tikhub,开发环境通过 Vite 代理到 https://api.tikhub.io
|
||||
// 注意:API_BASE.TIKHUB 不存在,应该使用 TIKHUB_APP
|
||||
const SERVER_BASE = API_BASE.TIKHUB_APP || API_BASE.TIKHUB || ''
|
||||
|
||||
// 创建公共 API 服务实例
|
||||
const apiService = createApiService({
|
||||
http,
|
||||
getAuthHeader,
|
||||
baseUrl: SERVER_BASE,
|
||||
})
|
||||
|
||||
// 设置全局 API 服务(供 useVoiceText hook 使用)
|
||||
setApiService(apiService)
|
||||
/**
|
||||
* TikHub API 基础路径
|
||||
*/
|
||||
const TIKHUB_BASE = API_BASE.TIKHUB_APP || API_BASE.TIKHUB || ''
|
||||
|
||||
/**
|
||||
* 应用层通用服务
|
||||
*/
|
||||
export const CommonService = {
|
||||
/**
|
||||
* 视频转字符(音频转文字)
|
||||
* 直接使用 mono 级别的 TikHub 服务
|
||||
*/
|
||||
videoToCharacters(data) {
|
||||
return apiService.videoToCharacters(data)
|
||||
return TikHubService.videoToCharacters(data)
|
||||
},
|
||||
|
||||
/**
|
||||
* 调用工作流
|
||||
*/
|
||||
callWorkflow(data) {
|
||||
return apiService.callWorkflow(data)
|
||||
return TikHubService.callWorkflow(data)
|
||||
},
|
||||
|
||||
// 流式调用 workflow
|
||||
callWorkflowStream: async (options) => {
|
||||
/**
|
||||
* 流式调用工作流(SSE)
|
||||
*/
|
||||
async callWorkflowStream(options) {
|
||||
const {
|
||||
data,
|
||||
ctrl,
|
||||
@@ -42,9 +47,9 @@ export const CommonService = {
|
||||
const authHeader = getAuthHeader()
|
||||
|
||||
let retryCount = 0
|
||||
const maxRetries = 0 // 禁用自动重试
|
||||
const maxRetries = 0
|
||||
|
||||
return fetchEventSource(`${SERVER_BASE}/callWorkflow`, {
|
||||
return fetchEventSource(`${TIKHUB_BASE}/callWorkflow`, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -57,18 +62,15 @@ export const CommonService = {
|
||||
retryCount++
|
||||
console.error('SSE错误,重试次数:', retryCount, err)
|
||||
|
||||
// 调用自定义错误处理
|
||||
if (typeof onError === 'function') {
|
||||
onError(err)
|
||||
}
|
||||
|
||||
// 超过最大重试次数,停止重连
|
||||
if (retryCount > maxRetries) {
|
||||
throw err // 抛出错误,停止自动重连
|
||||
throw err
|
||||
}
|
||||
},
|
||||
onclose: () => {
|
||||
// 调用自定义关闭处理
|
||||
if (typeof onClose === 'function') {
|
||||
onClose()
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* API 基础配置
|
||||
* 统一管理所有 API 的基础 URL
|
||||
*
|
||||
* 注意:此文件已迁移到公共模块 @gold/config/api
|
||||
* 为了保持向后兼容,这里重新导出公共配置
|
||||
* 新代码建议直接使用 @gold/config/api
|
||||
*/
|
||||
|
||||
// 从公共模块导入
|
||||
export { API_BASE, getApiUrl } from '@gold/config/api'
|
||||
|
||||
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* API 使用示例
|
||||
* 此文件仅作为参考,展示如何使用统一的 API 管理
|
||||
*/
|
||||
|
||||
// ========== 方式一:从统一入口导入(推荐) ==========
|
||||
import {
|
||||
ChatMessageApi,
|
||||
CommonService,
|
||||
TikhubService,
|
||||
API_BASE,
|
||||
getApiUrl,
|
||||
http
|
||||
} from '@/api'
|
||||
|
||||
// 使用示例
|
||||
async function example1() {
|
||||
// 使用 ChatMessageApi
|
||||
const conversationId = await ChatMessageApi.createChatConversationMy({
|
||||
roleId: 1
|
||||
})
|
||||
|
||||
// 使用 CommonService
|
||||
const result = await CommonService.videoToCharacters({ videoUrl: 'xxx' })
|
||||
|
||||
// 使用 TikhubService
|
||||
await TikhubService.postTikHup({
|
||||
type: 'DOUYIN_WEB_HOT_SEARCH',
|
||||
methodType: 'GET',
|
||||
urlParams: { keyword: '测试' }
|
||||
})
|
||||
|
||||
// 使用配置
|
||||
const baseUrl = API_BASE.ADMIN_AI
|
||||
const fullUrl = getApiUrl('ADMIN_AI', '/chat/conversation/create-my')
|
||||
|
||||
// 直接使用 http 实例
|
||||
await http.get('/some-endpoint')
|
||||
}
|
||||
|
||||
// ========== 方式二:从具体文件导入(兼容旧代码) ==========
|
||||
import { ChatMessageApi } from '@/api/chat'
|
||||
import { CommonService } from '@/api/common'
|
||||
// 使用公共配置
|
||||
import { API_BASE } from '@gold/config/api'
|
||||
|
||||
async function example2() {
|
||||
// 原有方式仍然可用
|
||||
await ChatMessageApi.createChatConversationMy({ roleId: 1 })
|
||||
}
|
||||
|
||||
// ========== 方式三:按需导入认证 API ==========
|
||||
import {
|
||||
loginBySms,
|
||||
sendSmsCode,
|
||||
SMS_SCENE
|
||||
} from '@/api'
|
||||
|
||||
async function example3() {
|
||||
// 发送验证码
|
||||
await sendSmsCode('13800138000', SMS_SCENE.MEMBER_LOGIN)
|
||||
|
||||
// 短信登录
|
||||
await loginBySms('13800138000', '123456')
|
||||
}
|
||||
|
||||
export default {
|
||||
example1,
|
||||
example2,
|
||||
example3
|
||||
}
|
||||
|
||||
@@ -1,126 +1,168 @@
|
||||
import axios from 'axios'
|
||||
/**
|
||||
* 应用层 HTTP 客户端
|
||||
* 使用 mono 级别的 axios 实例,添加应用特定的 401 处理
|
||||
*/
|
||||
|
||||
import { message } from 'ant-design-vue'
|
||||
import { getAuthHeader, clearAllTokens } from '@gold/utils/token-manager'
|
||||
import { clearAllTokens, getRefreshToken } from '@gold/utils/token-manager'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { createClientAxios } from '@gold/api/axios/client'
|
||||
import { refreshToken } from '@/api/auth'
|
||||
|
||||
// 刷新 token 的状态管理
|
||||
let isRefreshing = false
|
||||
let refreshPromise = null
|
||||
|
||||
/**
|
||||
* 不需要 token 的接口白名单
|
||||
* 支持完整路径匹配或路径包含匹配
|
||||
* 处理 403 禁止访问错误(应用层特定逻辑)
|
||||
* 先尝试刷新 token,如果失败或没有 refresh token 才提示用户
|
||||
*/
|
||||
const WHITE_LIST = [
|
||||
'/auth/login', // 密码登录
|
||||
'/auth/send-sms-code', // 发送验证码
|
||||
'/auth/sms-login', // 短信登录
|
||||
'/auth/validate-sms-code', // 验证验证码
|
||||
'/auth/register', // 注册(如果有)
|
||||
'/auth/reset-password', // 重置密码
|
||||
'/auth/refresh-token', // 刷新token(可选,根据后端要求)
|
||||
]
|
||||
|
||||
/**
|
||||
* 检查 URL 是否在白名单中
|
||||
* @param {string} url - 请求 URL
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isInWhiteList(url) {
|
||||
if (!url) return false
|
||||
return WHITE_LIST.some((path) => url.includes(path))
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 创建 axios 实例
|
||||
const http = axios.create({
|
||||
baseURL: '/',
|
||||
timeout: 180000, // 3分钟
|
||||
})
|
||||
|
||||
// 请求拦截:自动注入 Token
|
||||
http.interceptors.request.use((config) => {
|
||||
// 检查是否需要 token(不在白名单中且未显式设置 isToken = false)
|
||||
const needToken = config.headers?.isToken !== false && !isInWhiteList(config.url || '')
|
||||
config.headers['tenant-id'] = import.meta.env.VITE_TENANT_ID
|
||||
if (needToken) {
|
||||
// 使用统一的 token 管理器获取 header
|
||||
const authHeader = getAuthHeader()
|
||||
if (authHeader) {
|
||||
config.headers.Authorization = authHeader
|
||||
}
|
||||
}
|
||||
|
||||
// 允许跨域第三方域名,使用绝对地址时保持原样
|
||||
return config
|
||||
})
|
||||
|
||||
http.interceptors.response.use(
|
||||
(resp) => {
|
||||
const data = resp.data
|
||||
// 检查响应数据中的 code 字段
|
||||
if (data && typeof data.code === 'number' && (data.code === 0 || data.code === 200)) {
|
||||
return data
|
||||
} else {
|
||||
// code 不为 0 时,检查是否为401
|
||||
if (data && typeof data.code === 'number' && data.code === 401) {
|
||||
handle401Error()
|
||||
}
|
||||
// code 不为 0 时,抛出错误
|
||||
const error = new Error(data?.message || data?.msg || '请求失败')
|
||||
error.code = data?.code
|
||||
error.data = data
|
||||
return Promise.reject(error)
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// 处理 HTTP 状态码 401
|
||||
if (error.response && error.response.status === 401) {
|
||||
handle401Error()
|
||||
}
|
||||
// 统一错误处理:输出关键信息,便于排查 403 等问题
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* 处理 401 未授权错误
|
||||
* 清空 token 并退出登录
|
||||
*
|
||||
* 注意:使用防抖机制避免多个请求同时401时重复处理
|
||||
*/
|
||||
function handle401Error() {
|
||||
// 避免重复处理(防止多个请求同时401导致多次调用)
|
||||
if (handle401Error.processed) {
|
||||
async function handleApp403Error() {
|
||||
// 避免重复处理
|
||||
if (handleApp403Error.processed) {
|
||||
return
|
||||
}
|
||||
|
||||
handle401Error.processed = true
|
||||
handleApp403Error.processed = true
|
||||
|
||||
// 1. 清空所有 token
|
||||
try {
|
||||
clearAllTokens() // 统一使用 token-manager 的清空函数
|
||||
// 检查是否有 refresh token
|
||||
const refreshTokenValue = getRefreshToken()
|
||||
|
||||
if (refreshTokenValue) {
|
||||
// 如果有 refresh token,尝试刷新
|
||||
try {
|
||||
// 如果正在刷新,等待刷新完成
|
||||
if (isRefreshing && refreshPromise) {
|
||||
await refreshPromise
|
||||
handleApp403Error.processed = false
|
||||
return
|
||||
}
|
||||
|
||||
// 开始刷新 token
|
||||
isRefreshing = true
|
||||
refreshPromise = refreshToken()
|
||||
|
||||
await refreshPromise
|
||||
|
||||
// 刷新成功,重置状态
|
||||
isRefreshing = false
|
||||
refreshPromise = null
|
||||
handleApp403Error.processed = false
|
||||
|
||||
// 刷新成功,不提示用户(静默刷新)
|
||||
return
|
||||
} catch (refreshError) {
|
||||
// 刷新失败,清除状态
|
||||
isRefreshing = false
|
||||
refreshPromise = null
|
||||
console.error('刷新 token 失败:', refreshError)
|
||||
|
||||
// 刷新失败才提示用户
|
||||
message.warning('登录状态已过期,请重新登录', 3)
|
||||
handleApp403Error.processed = false
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 没有 refresh token,提示用户
|
||||
message.warning('登录状态已过期,请重新登录', 3)
|
||||
handleApp403Error.processed = false
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('清空 token 失败:', e)
|
||||
console.error('处理 403 错误失败:', e)
|
||||
handleApp403Error.processed = false
|
||||
}
|
||||
|
||||
// 2. 退出登录状态(清空用户信息)
|
||||
try {
|
||||
const userStore = useUserStore()
|
||||
// logout() 会清空用户信息和本地存储
|
||||
userStore.logout()
|
||||
} catch (e) {
|
||||
console.error('退出登录失败:', e)
|
||||
}
|
||||
|
||||
// 3. 提示用户(延迟显示,避免在清空过程中显示)
|
||||
setTimeout(() => {
|
||||
message.warning('登录已过期,请重新登录', 3)
|
||||
}, 100)
|
||||
|
||||
// 4. 延迟重置标志,避免短时间内重复处理
|
||||
setTimeout(() => {
|
||||
handle401Error.processed = false
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 401 未授权错误(应用层特定逻辑)
|
||||
* 先尝试刷新 token,如果失败或没有 refresh token 才退出登录
|
||||
*/
|
||||
async function handleApp401Error() {
|
||||
// 避免重复处理
|
||||
if (handleApp401Error.processed) {
|
||||
return
|
||||
}
|
||||
|
||||
handleApp401Error.processed = true
|
||||
|
||||
try {
|
||||
// 检查是否有 refresh token
|
||||
const refreshTokenValue = getRefreshToken()
|
||||
|
||||
if (refreshTokenValue) {
|
||||
// 如果有 refresh token,尝试刷新
|
||||
try {
|
||||
// 如果正在刷新,等待刷新完成
|
||||
if (isRefreshing && refreshPromise) {
|
||||
await refreshPromise
|
||||
handleApp401Error.processed = false
|
||||
return
|
||||
}
|
||||
|
||||
// 开始刷新 token
|
||||
isRefreshing = true
|
||||
refreshPromise = refreshToken()
|
||||
|
||||
await refreshPromise
|
||||
|
||||
// 刷新成功,重置状态
|
||||
isRefreshing = false
|
||||
refreshPromise = null
|
||||
handleApp401Error.processed = false
|
||||
|
||||
// 刷新成功,不提示用户(静默刷新)
|
||||
return
|
||||
} catch (refreshError) {
|
||||
// 刷新失败,清除状态
|
||||
isRefreshing = false
|
||||
refreshPromise = null
|
||||
console.error('刷新 token 失败:', refreshError)
|
||||
|
||||
// 继续执行退出登录逻辑
|
||||
}
|
||||
}
|
||||
|
||||
// 没有 refresh token 或刷新失败,执行退出登录
|
||||
try {
|
||||
clearAllTokens()
|
||||
} catch (e) {
|
||||
console.error('清空 token 失败:', e)
|
||||
}
|
||||
|
||||
try {
|
||||
const userStore = useUserStore()
|
||||
userStore.logout()
|
||||
} catch (e) {
|
||||
console.error('退出登录失败:', e)
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
message.warning('登录已过期,请重新登录', 3)
|
||||
}, 100)
|
||||
|
||||
} catch (e) {
|
||||
console.error('处理 401 错误失败:', e)
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
handleApp401Error.processed = false
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建应用层 HTTP 客户端
|
||||
* 基于 mono 级别的 axios 实例,添加应用特定的错误处理
|
||||
*/
|
||||
const http = createClientAxios({
|
||||
baseURL: '/',
|
||||
timeout: 180000,
|
||||
on401: handleApp401Error,
|
||||
on403: handleApp403Error,
|
||||
})
|
||||
|
||||
// 注意:403 处理已在 createClientAxios 的响应拦截器中通过 on403 回调处理
|
||||
|
||||
export default http
|
||||
|
||||
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
* 所有 API 服务都从这里导出,方便统一管理和使用
|
||||
*/
|
||||
|
||||
// 配置
|
||||
export { default as API_BASE, getApiUrl } from './config'
|
||||
|
||||
// HTTP 实例
|
||||
export { default as http, default as request } from './http'
|
||||
|
||||
@@ -15,6 +12,9 @@ export * from './auth'
|
||||
// 聊天相关 API
|
||||
export { ChatMessageApi } from './chat'
|
||||
|
||||
// 用户提示词 API
|
||||
export { UserPromptApi } from './userPrompt'
|
||||
|
||||
// 通用服务 API
|
||||
export { CommonService } from './common'
|
||||
export { default as CommonServiceDefault } from './common'
|
||||
@@ -23,20 +23,3 @@ export { default as CommonServiceDefault } from './common'
|
||||
export { TikhubService, default as TikhubServiceDefault } from './tikhub'
|
||||
export { InterfaceType, MethodType, InterfaceUrlMap, ParamType } from './tikhub/types'
|
||||
|
||||
/**
|
||||
* 统一导出所有 API 服务(便于按需导入)
|
||||
*/
|
||||
export default {
|
||||
// 配置
|
||||
config: () => import('./config'),
|
||||
|
||||
// HTTP 实例
|
||||
http: () => import('./http'),
|
||||
|
||||
// API 服务
|
||||
auth: () => import('./auth'),
|
||||
chat: () => import('./chat'),
|
||||
common: () => import('./common'),
|
||||
tikhub: () => import('./tikhub'),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// TikHub API 统一导出入口
|
||||
export { TikhubService } from './tikhub/tikhub.js'
|
||||
export { default } from './tikhub/tikhub.js'
|
||||
export { InterfaceType, MethodType, InterfaceUrlMap, ParamType } from './tikhub/types.js'
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
# TikHub API 模块
|
||||
|
||||
本模块提供了统一的 TikHub 接口调用中间层,支持多种平台的 API 接口。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
tikhub/
|
||||
├── types.js # 枚举定义:InterfaceType、MethodType
|
||||
├── tikhub.js # 核心服务类 TikhubService
|
||||
├── index.js # 统一导出入口
|
||||
├── example.js # 使用示例
|
||||
└── README.md # 本文档
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 导入模块
|
||||
|
||||
```javascript
|
||||
import TikhubService, { InterfaceType, MethodType } from '@/api/tikhub'
|
||||
```
|
||||
|
||||
### 2. 调用接口
|
||||
|
||||
```javascript
|
||||
// 调用抖音热门搜索接口
|
||||
const response = await TikhubService.postTikHup(
|
||||
InterfaceType.DOUYIN_WEB_HOT_SEARCH, // 接口类型
|
||||
MethodType.GET, // HTTP 方法
|
||||
{ keyword: '测试关键词' } // 实际接口参数
|
||||
)
|
||||
```
|
||||
|
||||
## API 说明
|
||||
|
||||
### TikhubService.postTikHup(type, methodType, urlParams)
|
||||
|
||||
统一调用 TikHub 接口的中间层方法。
|
||||
|
||||
**参数:**
|
||||
- `type` (String) - 接口类型,使用 `InterfaceType` 枚举值
|
||||
- `methodType` (String) - HTTP 方法类型,使用 `MethodType` 枚举值
|
||||
- `urlParams` (Object|String) - 实际接口的参数
|
||||
|
||||
**返回:**
|
||||
- Promise - axios 响应对象
|
||||
|
||||
**示例:**
|
||||
|
||||
```javascript
|
||||
// 获取小红书热门榜单
|
||||
await TikhubService.postTikHup(
|
||||
InterfaceType.XIAOHONGSHU_WEB_HOT_LIST,
|
||||
MethodType.GET,
|
||||
{ page: 1, page_size: 20 }
|
||||
)
|
||||
|
||||
// 搜索抖音内容
|
||||
await TikhubService.postTikHup(
|
||||
InterfaceType.DOUYIN_GENERAL_SEARCH_V4,
|
||||
MethodType.POST,
|
||||
{
|
||||
keyword: '热门内容',
|
||||
sort_type: 0,
|
||||
publish_time: 0,
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## 枚举说明
|
||||
|
||||
### InterfaceType - 接口类型
|
||||
|
||||
支持的所有接口类型:
|
||||
|
||||
| 枚举值 | 说明 |
|
||||
|--------|------|
|
||||
| `XIAOHONGSHU_USER_INFO` | 小红书 - 获取用户信息 |
|
||||
| `DOUYIN_WEB_USER_POST_VIDEOS` | 抖音 - 网页端获取用户发布的视频 |
|
||||
| `DOUYIN_APP_USER_POST_VIDEOS` | 抖音 - APP端V3获取用户发布的视频 |
|
||||
| `DOUYIN_APP_GENERAL_SEARCH` | 抖音 - APP端V3通用搜索结果 |
|
||||
| `DOUYIN_SEARCH_SUGGEST` | 抖音 - 搜索建议 |
|
||||
| `DOUYIN_GENERAL_SEARCH_V4` | 抖音 - 通用搜索V4 |
|
||||
| `XIAOHONGSHU_WEB_HOT_LIST` | 小红书 - 网页端V2热门榜单 |
|
||||
| `DOUYIN_WEB_HOT_SEARCH` | 抖音 - 网页端热门搜索结果 |
|
||||
| `KUAISHOU_WEB_HOT_LIST` | 快手 - 网页端热门榜单V2 |
|
||||
| `BILIBILI_WEB_POPULAR` | B站 - 网页端流行内容 |
|
||||
| `WEIBO_WEB_HOT_SEARCH` | 微博 - 网页端V2热门搜索指数 |
|
||||
| `DOUYIN_WEB_GENERAL_SEARCH` | 抖音 - 网页端通用搜索结果 |
|
||||
|
||||
### MethodType - HTTP 方法
|
||||
|
||||
| 枚举值 | 说明 |
|
||||
|--------|------|
|
||||
| `GET` | GET 请求 |
|
||||
| `POST` | POST 请求 |
|
||||
| `PUT` | PUT 请求 |
|
||||
| `DELETE` | DELETE 请求 |
|
||||
| `PATCH` | PATCH 请求 |
|
||||
|
||||
## 使用示例
|
||||
|
||||
详细的使用示例请参考 `example.js` 文件。
|
||||
|
||||
### 示例 1:获取抖音热门搜索
|
||||
|
||||
```javascript
|
||||
import TikhubService, { InterfaceType, MethodType } from '@/api/tikhub'
|
||||
|
||||
async function getDouyinHotSearch() {
|
||||
try {
|
||||
const response = await TikhubService.postTikHup(
|
||||
InterfaceType.DOUYIN_WEB_HOT_SEARCH,
|
||||
MethodType.GET,
|
||||
{ keyword: '测试关键词' }
|
||||
)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('调用失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 示例 2:获取用户发布的视频
|
||||
|
||||
```javascript
|
||||
async function getUserVideos() {
|
||||
return await TikhubService.postTikHup(
|
||||
InterfaceType.DOUYIN_WEB_USER_POST_VIDEOS,
|
||||
MethodType.GET,
|
||||
{
|
||||
sec_user_id: 'MS4wLjABAAAxxxxxxxx',
|
||||
count: 20,
|
||||
max_cursor: 0,
|
||||
}
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
```javascript
|
||||
try {
|
||||
const response = await TikhubService.postTikHup(
|
||||
InterfaceType.DOUYIN_WEB_HOT_SEARCH,
|
||||
MethodType.GET,
|
||||
{ keyword: '测试' }
|
||||
)
|
||||
console.log('成功:', response)
|
||||
} catch (error) {
|
||||
if (error.message.includes('无效的接口类型')) {
|
||||
console.error('接口类型错误')
|
||||
} else {
|
||||
console.error('请求失败:', error.message)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 后端接口格式
|
||||
|
||||
本模块会调用后端接口 `/webApi/admin-api/ai/tikHup/post_tik_hup`,传递的参数格式为:
|
||||
|
||||
```json
|
||||
{
|
||||
"interface_type": "8",
|
||||
"method_type": "GET",
|
||||
"platform_url": "https://api.tikhub.io/api/v1/douyin/web/fetch_hot_search_result",
|
||||
"url_params": { "keyword": "测试" }
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 所有接口类型必须使用 `InterfaceType` 枚举,不能使用字符串数字
|
||||
2. HTTP 方法必须使用 `MethodType` 枚举
|
||||
3. `urlParams` 可以是对象或字符串,取决于实际接口的要求
|
||||
4. 后端会根据 `interface_type` 从数据库中获取对应的 `platform_token`
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* TikHub API 统一导出
|
||||
*/
|
||||
export { TikhubService } from './tikhub.js'
|
||||
export { default } from './tikhub.js'
|
||||
export { TikhubService, default } from './tikhub.js'
|
||||
export { InterfaceType, MethodType, InterfaceUrlMap, ParamType } from './types.js'
|
||||
|
||||
|
||||
68
frontend/app/web-gold/src/api/userPrompt.js
Normal file
68
frontend/app/web-gold/src/api/userPrompt.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import http from '@/api/http'
|
||||
import { API_BASE } from '@gold/config/api'
|
||||
|
||||
// C 端使用 APP_AI,如果不存在则回退到 ADMIN_AI
|
||||
// 后端路径是 /app-api/ai/user-prompt,参考 chat API 的实现
|
||||
const SERVER_BASE_AI = API_BASE.APP_AI || API_BASE.ADMIN_AI
|
||||
|
||||
/**
|
||||
* 用户提示词 API
|
||||
*/
|
||||
export const UserPromptApi = {
|
||||
/**
|
||||
* 创建用户提示词
|
||||
* @param {Object} data - 提示词数据
|
||||
* @returns {Promise} 响应数据
|
||||
*/
|
||||
createUserPrompt: async (data) => {
|
||||
return await http.post(`${SERVER_BASE_AI}/user-prompt/create`, data)
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新用户提示词
|
||||
* @param {Object} data - 提示词数据
|
||||
* @returns {Promise} 响应数据
|
||||
*/
|
||||
updateUserPrompt: async (data) => {
|
||||
return await http.put(`${SERVER_BASE_AI}/user-prompt/update`, data)
|
||||
},
|
||||
|
||||
/**
|
||||
* 分页查询用户提示词
|
||||
* @param {Object} params - 查询参数
|
||||
* @returns {Promise} 响应数据
|
||||
*/
|
||||
getUserPromptPage: async (params) => {
|
||||
return await http.get(`${SERVER_BASE_AI}/user-prompt/page`, { params })
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取单个用户提示词
|
||||
* @param {Number} id - 提示词ID
|
||||
* @returns {Promise} 响应数据
|
||||
*/
|
||||
getUserPrompt: async (id) => {
|
||||
return await http.get(`${SERVER_BASE_AI}/user-prompt/get`, { params: { id } })
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除用户提示词
|
||||
* @param {Number} id - 提示词ID
|
||||
* @returns {Promise} 响应数据
|
||||
*/
|
||||
deleteUserPrompt: async (id) => {
|
||||
return await http.delete(`${SERVER_BASE_AI}/user-prompt/delete`, { params: { id } })
|
||||
},
|
||||
|
||||
/**
|
||||
* 批量删除用户提示词
|
||||
* @param {Array<Number>} ids - 提示词ID列表
|
||||
* @returns {Promise} 响应数据
|
||||
*/
|
||||
deleteUserPromptList: async (ids) => {
|
||||
return await http.delete(`${SERVER_BASE_AI}/user-prompt/delete-list`, { params: { ids } })
|
||||
},
|
||||
}
|
||||
|
||||
export default UserPromptApi
|
||||
|
||||
Reference in New Issue
Block a user