This commit is contained in:
2025-11-10 00:59:40 +08:00
parent 78c46aed71
commit bac96fcbe6
76 changed files with 8726 additions and 0 deletions

View File

@@ -0,0 +1,237 @@
import api from '@/api/http'
import { setToken, getRefreshToken } from '@/utils/auth'
const SERVER_BASE = import.meta.env.VITE_BASE_URL + '/app-api/member'
/**
* 保存 token 的辅助函数
* @param {Object} info - 包含 accessToken 和 refreshToken 的对象
*/
function saveTokens(info) {
if (info?.accessToken || info?.refreshToken) {
setToken({
accessToken: info.accessToken || '',
refreshToken: info.refreshToken || '',
})
}
}
/**
* 响应拦截(可选):统一错误处理
*/
// api.interceptors.response.use(
// (resp) => resp,
// (err) => {
// // 统一错误日志/提示
// return Promise.reject(err);
// }
// );
/**
* 短信场景枚举(请与后端配置保持一致)
* - MEMBER_LOGIN: 会员短信登录场景
* - MEMBER_UPDATE_PASSWORD: 已登录用户修改密码(短信校验)场景
* - MEMBER_RESET_PASSWORD: 未登录用户忘记密码重置(短信校验)场景
* 如有"注册"独立场景可在此添加MEMBER_REGISTER: 13
*/
export const SMS_SCENE = {
MEMBER_LOGIN: 1,
MEMBER_UPDATE_PASSWORD: 3,
MEMBER_RESET_PASSWORD: 4,
};
/**
* 短信模板编码常量
*/
export const SMS_TEMPLATE_CODE = {
USER_REGISTER: 'muye-user-code', // 用户注册模板编码
};
/**
* 账号密码登录
* POST /member/auth/login
*
* @param {string} mobile - 手机号(必填)
* @param {string} password - 密码(必填,长度 4-16
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
*/
export async function loginByPassword(mobile, password) {
const { data } = await api.post(`${SERVER_BASE}/auth/login`, { mobile, password });
const info = data || {};
saveTokens(info);
return info;
}
/**
* 发送短信验证码
* POST /member/auth/send-sms-code
*
* @param {string} mobile - 手机号(登录/忘记密码等需要;修改密码场景可不传)
* @param {number} scene - 短信场景(见 SMS_SCENE
* @param {string} templateCode - 模板编码(可选,如 'muye-user-code'
* @returns {Promise<Object>} 后端通用响应结构
*/
export async function sendSmsCode(mobile, scene, templateCode) {
const body = { scene };
if (mobile) body.mobile = mobile; // 修改密码场景后端会根据当前登录用户自动填充手机号
if (templateCode) body.templateCode = templateCode; // 添加模板编码参数
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, body);
return data;
}
/**
* 校验短信验证码(可选前置校验,一般直接在业务接口 use
* POST /member/auth/validate-sms-code
*
* @param {string} mobile - 手机号(必填)
* @param {string} code - 验证码必填4-6 位数字)
* @param {number} scene - 短信场景(必填,见 SMS_SCENE
* @returns {Promise<Object>} 后端通用响应结构
*/
export async function validateSmsCode(mobile, code, scene) {
const { data } = await api.post(`${SERVER_BASE}/auth/validate-sms-code`, { mobile, code, scene });
return data;
}
/**
* 手机+验证码登录(首次即自动注册)
* POST /member/auth/sms-login
*
* @param {string} mobile - 手机号(必填)
* @param {string} code - 短信验证码(必填)
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
*/
export async function loginBySms(mobile, code) {
const { data } = await api.post(`${SERVER_BASE}/auth/sms-login`, { mobile, code });
const info = data || {};
saveTokens(info);
return info;
}
/**
* 刷新令牌
* POST /member/auth/refresh-token?refreshToken=xxx
*
* @returns {Promise<Object>} data.data: { accessToken, refreshToken, expiresTime, userInfo }
*/
export async function refreshToken() {
const rt = getRefreshToken();
if (!rt) throw new Error('缺少 refresh_token');
// refreshToken 作为 URL 查询参数传递
const { data } = await api.post(`${SERVER_BASE}/auth/refresh-token`, null, { params: { refreshToken: rt } });
const info = data || {};
saveTokens(info);
return info;
}
/**
* 登录态下:发送“修改密码”验证码
* - 场景SMS_SCENE.MEMBER_UPDATE_PASSWORD
* - 特性:后端会以当前登录用户的手机号为准,无需传 mobile
* POST /member/auth/send-sms-code
*
* @returns {Promise<Object>} 后端通用响应结构
*/
export async function sendUpdatePasswordCode() {
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, {
scene: SMS_SCENE.MEMBER_UPDATE_PASSWORD,
});
return data;
}
/**
* 登录态下:通过短信验证码修改密码
* PUT /member/user/update-password
*
* @param {string} newPassword - 新密码必填4-16 位)
* @param {string} smsCode - 短信验证码必填4-6 位数字)
* @returns {Promise<Object>} 后端通用响应结构
*/
export async function updatePasswordBySmsCode(newPassword, smsCode) {
const { data } = await api.put(`${SERVER_BASE}/user/update-password`, {
password: newPassword,
code: smsCode,
});
return data;
}
/**
* 未登录:发送“忘记密码”验证码
* - 场景SMS_SCENE.MEMBER_RESET_PASSWORD
* POST /member/auth/send-sms-code
*
* @param {string} mobile - 手机号(必填)
* @returns {Promise<Object>} 后端通用响应结构
*/
export async function sendResetPasswordCode(mobile) {
const { data } = await api.post(`${SERVER_BASE}/auth/send-sms-code`, {
mobile,
scene: SMS_SCENE.MEMBER_RESET_PASSWORD,
});
return data;
}
/**
* 未登录:通过手机验证码重置密码(忘记密码)
* PUT /member/user/reset-password
*
* @param {string} mobile - 手机号(必填)
* @param {string} newPassword - 新密码必填4-16 位)
* @param {string} smsCode - 短信验证码必填4-6 位数字)
* @returns {Promise<Object>} 后端通用响应结构
*/
export async function resetPasswordBySms(mobile, newPassword, smsCode) {
const { data } = await api.put(`${SERVER_BASE}/user/reset-password`, {
mobile,
password: newPassword,
code: smsCode,
});
return data;
}
/**
* “手机+验证码+密码注册”组合流程(基于短信登录即注册 + 设置密码)
* 说明:
* - 1) 发送登录场景验证码(可选:若已拿到 code 可跳过)
* - 2) 短信登录:首次会自动注册并返回 token
* - 3) 登录态下发送“修改密码”验证码
* - 4) 用短信验证码设置密码
*
* @param {string} mobile - 手机号(必填)
* @param {string} loginCode - 第一次登录使用的短信验证码(必填)
* @param {string} newPassword - 注册后设置的新密码(必填)
* @param {string} updatePwdCode - 设置密码用到的短信验证码(必填)
* @returns {Promise<void>}
*/
export async function registerWithMobileCodePassword(mobile, loginCode, newPassword, updatePwdCode) {
// 1) 可选:发送登录场景验证码(若已拿到 loginCode 可跳过)
// await sendSmsCode(mobile, SMS_SCENE.MEMBER_LOGIN);
// 2) 短信登录(首次即注册)
await loginBySms(mobile, loginCode);
// 3) 登录态下发送“修改密码”验证码(短信会发到当前账号绑定的手机号)
// await sendUpdatePasswordCode();
// 4) 用短信验证码设置密码
await updatePasswordBySmsCode(newPassword, updatePwdCode);
}
/**
* 导出一个默认对象,便于统一引入
*/
export default {
SMS_SCENE,
SMS_TEMPLATE_CODE,
loginByPassword,
sendSmsCode,
validateSmsCode,
loginBySms,
refreshToken,
sendUpdatePasswordCode,
updatePasswordBySmsCode,
sendResetPasswordCode,
resetPasswordBySms,
registerWithMobileCodePassword,
};

View File

@@ -0,0 +1,74 @@
import request from '@/api/http'
import { fetchEventSource } from '@microsoft/fetch-event-source'
import { getAccessToken } from '@/utils/auth'
const SERVER_BASE_AI= import.meta.env.VITE_BASE_URL + '/admin-api/ai'
// AI chat 聊天
export const ChatMessageApi = {
// 创建【我的】聊天对话
createChatConversationMy: async (data) => {
return await request.post(`${SERVER_BASE_AI}/chat/conversation/create-my`, data)
},
// 发送 Stream 消息(对象入参,便于维护)
// 为什么不用 axios 呢?因为它不支持 SSE 调用
sendChatMessageStream: async (options) => {
const {
conversationId,
content,
ctrl,
enableContext = true,
enableWebSearch = false,
onMessage,
onError,
onClose,
attachmentUrls = []
} = options || {}
const token = getAccessToken()
let retryCount = 0
const maxRetries = 0 // 禁用自动重试
return fetchEventSource(`${SERVER_BASE_AI}/chat/message/send-stream`, {
method: 'post',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
},
openWhenHidden: true,
body: JSON.stringify({
conversationId,
content,
useContext: enableContext,
useSearch: enableWebSearch,
attachmentUrls: attachmentUrls || []
}),
onmessage: onMessage,
onerror: (err) => {
retryCount++
console.error('SSE错误重试次数:', retryCount, err)
// 调用自定义错误处理
if (typeof onError === 'function') {
onError(err)
}
// 超过最大重试次数,停止重连
if (retryCount > maxRetries) {
throw err // 抛出错误,停止自动重连
}
},
onclose: () => {
// 调用自定义关闭处理
if (typeof onClose === 'function') {
onClose()
}
},
signal: ctrl ? ctrl.signal : undefined
})
},
}

View File

@@ -0,0 +1,67 @@
import http from '@/api/http'
import { fetchEventSource } from '@microsoft/fetch-event-source'
import { getAuthHeader } from '@/utils/token-manager'
// 使用本地代理前缀 /tikhub开发环境通过 Vite 代理到 https://api.tikhub.io
const SERVER_BASE = '/webApi/admin-api/ai/tikHup'
export const CommonService = {
videoToCharacters(data) {
return http.post(`${SERVER_BASE}/videoToCharacters2`, data)
},
callWorkflow(data) {
return http.post(`${SERVER_BASE}/callWorkflow`, data)
},
// 流式调用 workflow
callWorkflowStream: async (options) => {
const {
data,
ctrl,
onMessage,
onError,
onClose
} = options || {}
const authHeader = getAuthHeader()
let retryCount = 0
const maxRetries = 0 // 禁用自动重试
return fetchEventSource(`${SERVER_BASE}/callWorkflow`, {
method: 'post',
headers: {
'Content-Type': 'application/json',
...(authHeader ? { Authorization: authHeader } : {})
},
openWhenHidden: true,
body: JSON.stringify(data),
onmessage: onMessage,
onerror: (err) => {
retryCount++
console.error('SSE错误重试次数:', retryCount, err)
// 调用自定义错误处理
if (typeof onError === 'function') {
onError(err)
}
// 超过最大重试次数,停止重连
if (retryCount > maxRetries) {
throw err // 抛出错误,停止自动重连
}
},
onclose: () => {
// 调用自定义关闭处理
if (typeof onClose === 'function') {
onClose()
}
},
signal: ctrl ? ctrl.signal : undefined
})
}
}
export default CommonService

View File

@@ -0,0 +1,80 @@
import axios from 'axios'
import { getAuthHeader } from '@/utils/token-manager'
/**
* 不需要 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))
}
/**
* 可选:多租户场景可在此处统一注入 tenant-id
* api.interceptors.request.use((config) => {
* config.headers['tenant-id'] = '1';
* return config;
* });
*/
// 创建 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 || '')
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 时,抛出错误
const error = new Error(data?.message || data?.msg || '请求失败')
error.code = data?.code
error.data = data
return Promise.reject(error)
}
},
(error) => {
// 统一错误处理:输出关键信息,便于排查 403 等问题
return Promise.reject(error)
}
)
export default http

View File

@@ -0,0 +1,5 @@
// TikHub API 统一导出入口
export { TikhubService } from './tikhub/tikhub.js'
export { default } from './tikhub/tikhub.js'
export { InterfaceType, MethodType, InterfaceUrlMap, ParamType } from './tikhub/types.js'

View File

@@ -0,0 +1,180 @@
# 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`

View File

@@ -0,0 +1,7 @@
/**
* TikHub API 统一导出
*/
export { TikhubService } from './tikhub.js'
export { default } from './tikhub.js'
export { InterfaceType, MethodType, InterfaceUrlMap, ParamType } from './types.js'

View File

@@ -0,0 +1,55 @@
import http from '@/api/http'
import { InterfaceType, MethodType, InterfaceUrlMap, ParamType } from './types'
import qs from 'qs'
// 使用本地代理前缀 /tikhub开发环境通过 Vite 代理到 https://api.tikhub.io
const SERVER_TIKHUB = '/webApi/admin-api/ai/tikHup'
/**
* TikHub API 服务类
*/
export const TikhubService = {
/**
* 统一调用 TikHub 接口的中间层方法
* @param {String} type - 接口类型,使用 InterfaceType 枚举
* @param {String} methodType - HTTP 方法类型,使用 MethodType 枚举
* @param {Object|String} urlParams - 实际接口的参数
* @returns {Promise} axios 响应
*
* @example
* // 调用抖音热门搜索接口
* TikhubService.postTikHup(
* InterfaceType.DOUYIN_WEB_HOT_SEARCH,
* MethodType.GET,
* { keyword: '测试' }
* )
*/
postTikHup({
type,
methodType,
urlParams,
paramType = '',
}) {
// 验证接口类型是否存在
if (!InterfaceUrlMap[type]) {
throw new Error(`无效的接口类型: ${type}`)
}
// 构造请求参数
const requestData = {
type: type,
methodType: methodType,
paramType,
urlParams: paramType === ParamType.JSON ? JSON.stringify(urlParams) : qs.stringify(urlParams),
}
return http.post(`${SERVER_TIKHUB}/postTikHup`, qs.stringify(requestData))
},
}
export default TikhubService
// 导出枚举,方便外部使用
export { InterfaceType, MethodType, InterfaceUrlMap }

View File

@@ -0,0 +1,87 @@
/**
* TikHub 接口类型枚举
* 对应数据库 tik_token 表中的 interface_type 字段
*/
export const InterfaceType = {
/** 小红书 - 获取用户信息 */
XIAOHONGSHU_USER_INFO: '1',
/** 抖音 - 网页端获取用户发布的视频 */
DOUYIN_WEB_USER_POST_VIDEOS: '2',
/** 抖音 - APP端V3获取用户发布的视频 */
DOUYIN_APP_USER_POST_VIDEOS: '3',
/** 抖音 - APP端V3通用搜索结果 */
DOUYIN_APP_GENERAL_SEARCH: '4',
/** 抖音 - 搜索建议 */
DOUYIN_SEARCH_SUGGEST: '5',
/** 抖音 - 通用搜索V4 */
DOUYIN_GENERAL_SEARCH_V4: '6',
/** 小红书 - 网页端V2热门榜单 */
XIAOHONGSHU_WEB_HOT_LIST: '7',
/** 抖音 - 网页端热门搜索结果 */
DOUYIN_WEB_HOT_SEARCH: '8',
/** 快手 - 网页端热门榜单V2 */
KUAISHOU_WEB_HOT_LIST: '9',
/** B站 - 网页端流行内容 */
BILIBILI_WEB_POPULAR: '10',
/** 微博 - 网页端V2热门搜索指数 */
WEIBO_WEB_HOT_SEARCH: '11',
/** 抖音 - 网页端通用搜索结果 */
DOUYIN_WEB_GENERAL_SEARCH: '12',
/** 抖音 - APP通用搜索结果 */
DOUYIN_SEARCH_GENERAL_SEARCH: '14',
}
/**
* HTTP 请求方法枚举
*/
export const MethodType = {
GET: 'GET',
POST: 'POST',
PUT: 'PUT',
DELETE: 'DELETE',
PATCH: 'PATCH',
}
/**
* 请求参数类型枚举
*/
export const ParamType = {
JSON: 'json',
FORM: 'form'
}
/**
* 接口类型与平台 URL 的映射
* 根据 tik_token 表中的数据生成
*/
export const InterfaceUrlMap = {
[InterfaceType.XIAOHONGSHU_USER_INFO]: 'https://api.tikhub.io/api/v1/xiaohongshu/app/get_user_info',
[InterfaceType.DOUYIN_WEB_USER_POST_VIDEOS]: 'https://api.tikhub.io/api/v1/douyin/web/fetch_user_post_videos',
[InterfaceType.DOUYIN_APP_USER_POST_VIDEOS]: 'https://api.tikhub.io/api/v1/douyin/app/v3/fetch_user_post_videos',
[InterfaceType.DOUYIN_APP_GENERAL_SEARCH]: 'https://api.tikhub.io/api/v1/douyin/app/v3/fetch_general_search_result',
[InterfaceType.DOUYIN_SEARCH_GENERAL_SEARCH]: 'https://api.tikhub.io/api/v1/douyin/search/fetch_general_search_v4',
[InterfaceType.DOUYIN_SEARCH_SUGGEST]: 'https://api.tikhub.io/api/v1/douyin/search/fetch_search_suggest',
[InterfaceType.DOUYIN_GENERAL_SEARCH_V4]: 'https://api.tikhub.io/api/v1/douyin/search/fetch_general_search_v4',
[InterfaceType.XIAOHONGSHU_WEB_HOT_LIST]: 'https://api.tikhub.io/api/v1/xiaohongshu/web_v2/fetch_hot_list',
[InterfaceType.DOUYIN_WEB_HOT_SEARCH]: 'https://api.tikhub.io/api/v1/douyin/web/fetch_hot_search_result',
[InterfaceType.KUAISHOU_WEB_HOT_LIST]: 'https://api.tikhub.io/api/v1/kuaishou/web/fetch_kuaishou_hot_list_v2',
[InterfaceType.BILIBILI_WEB_POPULAR]: 'https://api.tikhub.io/api/v1/bilibili/web/fetch_com_popular',
[InterfaceType.WEIBO_WEB_HOT_SEARCH]: 'https://api.tikhub.io/api/v1/weibo/web_v2/fetch_hot_search_index',
[InterfaceType.DOUYIN_WEB_GENERAL_SEARCH]: 'https://api.tikhub.io/api/v1/douyin/web/fetch_general_search_result',
}
export default {
InterfaceType,
MethodType,
InterfaceUrlMap,
}