重构 API 层架构:统一 HTTP 请求、新增算力调度后端路由
- 请求拦截器统一 Auth 头不带 Bearer 前缀,新增 /suanli 前缀路由到算力调度后端 - 任务创建/轮询/历史接口迁移至 apis/display,改为 axios 调用替代原始 fetch - 模型 API 分离为两层:apis 纯 HTTP 调用 + utils 缓存业务逻辑 - 新增历史任务列表接口 requestTaskHistory(支持 user_id/platform_code 筛选和分页) - 响应拦截器兼容 status/code 双字段,用户信息兼容新旧 data 格式 - 移除免费次数(freeTimes)体系 - 更新 CLAUDE.md 文档
This commit is contained in:
parent
72267ab2c9
commit
5da5496492
@ -3,8 +3,7 @@ VITE_BASE = '/'
|
||||
|
||||
# 主服务
|
||||
VITE_API_PREFIX = '/api'
|
||||
VITE_API_BASE_URL = 'http://test.xueai.art/api' # http://huanda.xueai.art http://106.54.11.219/api 43.248.131.153:8003
|
||||
VITE_API_WS_URL = 'ws://test.xueai.art/api'
|
||||
VITE_API_BASE_URL = 'http://test.xueai.art/newapi/api' # http://huanda.xueai.art http://106.54.11.219/api 43.248.131.153:8003
|
||||
|
||||
# 支付服务
|
||||
VITE_API_PAY_PREFIX = '/pay'
|
||||
@ -12,7 +11,8 @@ VITE_API_PAY_TARGET = 'http://test.xueai.art' # http://43.248.133.202 test.xue
|
||||
|
||||
# 任务处理模块
|
||||
VITE_API_WORKFLOW_UPLOAD = 'http://43.248.97.19:4000/aigc/workflow/file/upload' # https://sxwz.xueai.art/workflow https://designtools.xueai.art/workflow
|
||||
VITE_API_WORKFLOW_WS = 'ws://43.248.97.19:4000/testworkflow'
|
||||
VITE_API_TASK_PREFIX = '/suanli'
|
||||
VITE_API_TASK_TARGET = 'http://test.xueai.art'
|
||||
|
||||
# 是否开启开发者工具
|
||||
VITE_OPEN_DEVTOOLS = false
|
||||
|
||||
@ -7,7 +7,6 @@ VITE_BUILD_MOCK = false
|
||||
# 主服务
|
||||
VITE_API_PREFIX = '/api'
|
||||
VITE_API_BASE_URL = 'https://sxwz.xueai.art/api'
|
||||
VITE_API_WS_URL = 'wss://sxwz.xueai.art/api'
|
||||
|
||||
# 支付服务
|
||||
VITE_API_PAY_PREFIX = '/pay'
|
||||
@ -15,7 +14,8 @@ VITE_API_PAY_TARGET = 'https://sxwz.xueai.art' # http://43.248.133.202
|
||||
|
||||
# 任务处理模块
|
||||
VITE_API_WORKFLOW_UPLOAD = 'https://designtools.xueai.art/workflow/file/upload' # https://sxwz.xueai.art/workflow https://designtools.xueai.art/workflow
|
||||
VITE_API_WORKFLOW_WS = 'wss://talkingdraw.xueai.art/testworkflow'
|
||||
VITE_API_TASK_PREFIX = '/suanli'
|
||||
VITE_API_TASK_TARGET = 'http://test.xueai.art'
|
||||
|
||||
# 模型资源
|
||||
VITE_API_MODEL_RESOURCE = 'https://resources.xueai.art/AIGC'
|
||||
|
||||
72
CLAUDE.md
72
CLAUDE.md
@ -16,7 +16,7 @@ Vue 3 (Composition API) + Vite 7 + Pinia + Vue Router + Element Plus + Less + pn
|
||||
|
||||
## 架构概览
|
||||
|
||||
AI 绘画/视频生成前端操作平台,通过 HTTP 接口对接后端和第三方 AI 平台(RunningHub),提交生成任务并轮询结果。
|
||||
AI 绘画/视频生成前端操作平台,通过 HTTP 接口对接算力调度后端(suanli)和第三方 AI 平台(RunningHub),提交生成任务并轮询结果。
|
||||
|
||||
### 关键目录
|
||||
|
||||
@ -25,36 +25,70 @@ src/
|
||||
├── main.js # 入口:创建 Vue 应用,安装 Pinia/Router/VueVirtualScroller
|
||||
├── router/index.js # 路由定义 + token 验证守卫
|
||||
├── stores/ # Pinia 状态管理
|
||||
│ ├── user.js # 用户认证、信息、免费次数
|
||||
│ ├── user.js # 用户认证、信息
|
||||
│ └── display.js # 生成历史列表、UI 状态(滚动、画布等)
|
||||
├── apis/ # HTTP API 模块(auth/display),通过 axios 实例调用
|
||||
├── apis/ # HTTP API 层:纯请求封装,不含业务逻辑
|
||||
│ ├── auth/ # 认证相关(登录、token 校验、用户信息)
|
||||
│ └── display/ # 任务创建/轮询/历史、平台模型、收藏/删除
|
||||
├── components/ # 通用组件
|
||||
│ ├── dialogBox/ # 生成参数输入面板(核心交互入口),含模型选择、比例、上传等子组件
|
||||
│ ├── virtual-scroller/# 虚拟滚动列表组件(自定义实现,reverse 模式)
|
||||
│ └── canvas/ # 图片画布编辑(圆/矩形选区,局部重绘)
|
||||
├── views/ # 页面(home、login)
|
||||
├── utils/
|
||||
│ ├── request.js # Axios 实例,拦截器处理 token 和不同服务的 baseURL 路由
|
||||
│ ├── websocket.js # 任务生成入口:HTTP POST 创建任务 + 20s 轮询获取结果
|
||||
│ ├── request.js # Axios 实例 + 拦截器:统一 Auth(不带 Bearer)+ 按前缀路由 baseURL
|
||||
│ ├── websocket.js # 任务生成入口:组装参数 → 调用 API → 20s 轮询直至完成/失败
|
||||
│ ├── modelApi.js # 模型业务层:localStorage 每日缓存 + 模型名称→UUID 查找
|
||||
│ ├── createTask.js # 调用平台适配器 Playload() 构造任务 body
|
||||
│ ├── modelConfig.js # 从远程 JSON 加载 workflow 配置,localStorage 每日缓存
|
||||
│ ├── modelApi.js # 从 /suanli/v1/platforms/:code/models 获取模型列表及 UUID
|
||||
│ └── auth.ts # token 存取工具(localStorage)
|
||||
├── config/
|
||||
│ ├── index.js # 平台配置入口,导出 runninghub 适配器
|
||||
│ └── runninghub/ # RunningHub 平台适配器:Playload() 构造和 result() 解析
|
||||
```
|
||||
|
||||
### API 层设计原则
|
||||
|
||||
- `src/apis/` 中的函数只做**纯 HTTP 调用**(`service.get/post/delete` 等),不包含缓存、localStorage、业务判断等逻辑
|
||||
- 缓存、数据转换等业务逻辑放在 `src/utils/` 中,调用 apis 层的原始函数
|
||||
|
||||
示例:`utils/modelApi.js` 导入 `apis/display` 的原始 `fetchPlatformModels`,在其上叠加 localStorage 每日缓存和 `getModelId` 查找逻辑。
|
||||
|
||||
### 核心数据流
|
||||
|
||||
1. 用户在 `dialogBox` 中设置参数(模型、提示词、比例、上传图片等)
|
||||
2. 点击生成 → `dialogBox:handleStart()` 组装 data(含 modelId、params、imgs、request)
|
||||
3. 调用 `websocket.js:generate(data, generateData)`
|
||||
4. `generate()` 内部先通过 `createTask(data)` → `runninghub.Playload()` 构造 RunningHub workflow payload 作为 body
|
||||
5. 调用 `modelApi.getModelId(type, modelName)` 从 `/suanli/v1/platforms/:code/models` 查找模型 UUID(带 localStorage 每日缓存)
|
||||
6. POST `/api/v1/tasks` 提交任务(`{ model_id, body, request }`),携带 `X-Session-Id` 用于预扣费
|
||||
5. 调用 `modelApi.getModelId(type, modelName)` 查找模型 UUID(带 localStorage 每日缓存)
|
||||
6. 调用 `requestCreateTask(body, sessionId)` → POST `/suanli/v1/tasks`(`{ model_id, body, request }`,携带 `X-Session-Id` 用于预扣费)
|
||||
7. 返回 task_id → `displayStore.addGeneratingItem()` 在前端列表插入"生成中"条目
|
||||
8. 每 20 秒轮询 GET `/api/v1/tasks/{task_id}`,completed 时调用 `updateItemToSuccess()` 更新列表
|
||||
8. 每 20 秒轮询 `requestTaskStatus(taskId)` → GET `/suanli/v1/tasks/{task_id}`,completed 时调用 `updateItemToSuccess()` 更新列表
|
||||
|
||||
### 接口速查
|
||||
|
||||
| 函数 | 端点 | 用途 |
|
||||
|------|------|------|
|
||||
| `requestCreateTask` | POST `/suanli/v1/tasks` | 创建生成任务 |
|
||||
| `requestTaskStatus` | GET `/suanli/v1/tasks/:id` | 查询单个任务状态 |
|
||||
| `requestTaskHistory` | GET `/suanli/v1/tasks/history` | 历史任务列表(支持 `user_id`/`platform_code`/`page`/`pageSize`) |
|
||||
| `fetchPlatformModels` | GET `/suanli/v1/platforms/:code/models` | 获取平台模型列表 |
|
||||
| `cancelOrCollect` | POST `/collect/toggle` | 收藏/取消收藏 |
|
||||
| `deleteGenerateHistory` | DELETE `/taskRecordHistory/delete` | 删除历史记录 |
|
||||
|
||||
### 请求拦截器路由
|
||||
|
||||
拦截器统一设置 `Authorization: <token>`(不带 Bearer 前缀),根据 URL 前缀切换后端:
|
||||
|
||||
| URL 前缀 | 环境变量 | 示例 target |
|
||||
|----------|----------|-------------|
|
||||
| `/suanli` | `VITE_API_TASK_TARGET` | `http://test.xueai.art` |
|
||||
| `/pay` | `VITE_API_PAY_TARGET` | `http://test.xueai.art` |
|
||||
| 其他 | `VITE_API_BASE_URL`(默认) | `http://test.xueai.art/newapi/api` |
|
||||
|
||||
### 响应格式兼容
|
||||
|
||||
响应拦截器同时识别 `code === 0` 和 `status === 0` 两种成功状态。用户信息接口兼容新旧两种格式:`data.userInfo` 嵌套(新)和 `data` 扁平(旧),在 store 的 `getInfo()` 中做了 `const u = res.data.userInfo || res.data` 的兼容处理。
|
||||
|
||||
### 平台编码映射
|
||||
|
||||
@ -63,28 +97,14 @@ src/
|
||||
| Painting | `ai_painting_talk` |
|
||||
| Video | `ai_video_talk` |
|
||||
|
||||
映射函数 `getPlatformCode()` 位于 `utils/modelApi.js`。
|
||||
|
||||
### 自动导入
|
||||
|
||||
- `unplugin-auto-import`:自动导入 Vue/Router/Pinia API,`.vue` 中无需手动 import
|
||||
- `unplugin-vue-components`:自动注册 `src/components/` 下的组件和 Element Plus 组件
|
||||
- Element Plus 图标通过 `unplugin-icons` 按需加载
|
||||
|
||||
### 环境变量
|
||||
|
||||
`VITE_API_BASE_URL` 定义主 API 地址(含 `/api` 后缀)。请求拦截器根据 URL 前缀自动切换后端服务:
|
||||
|
||||
| 前缀 | 用途 |
|
||||
|------|------|
|
||||
| `/pay` | 支付服务 |
|
||||
| `/api`(默认) | 主服务(含任务创建 `/api/v1/tasks`) |
|
||||
|
||||
新增的 `/suanli` 接口使用 `VITE_API_BASE_URL` 去掉 `/api` 后缀作为基础 URL。
|
||||
|
||||
### 路由守卫
|
||||
|
||||
`src/router/index.js` 的 `beforeEach` 守卫检查 token 存在性和有效性(调用 `/auth/check/token`),无效则跳转 `/login`。支持通过 URL query `?token=xxx` 传入 token。
|
||||
|
||||
### Authorization 头
|
||||
|
||||
- 通过 axios 的请求(auth/display 等):拦截器自动加 `Bearer` 前缀
|
||||
- 通过 fetch 的请求(任务创建/轮询/模型列表):直接传 token,**不加** `Bearer` 前缀
|
||||
`src/router/index.js` 的 `beforeEach` 守卫检查 token 存在性和有效性(调用 `POST /login/validateToken`),无效则跳转 `/login`。支持通过 URL query `?token=xxx` 传入 token。
|
||||
|
||||
3
components.d.ts
vendored
3
components.d.ts
vendored
@ -11,7 +11,10 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
2: typeof import('./src/components/virtual-scroller/VirtualScroller copy 2.vue')['default']
|
||||
3: typeof import('./src/components/virtual-scroller/VirtualScroller copy 3.vue')['default']
|
||||
Canvas: typeof import('./src/components/canvas/index.vue')['default']
|
||||
copy: typeof import('./src/components/virtual-scroller/VirtualScroller copy.vue')['default']
|
||||
DialogBox: typeof import('./src/components/dialogBox/index.vue')['default']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
||||
|
||||
@ -38,14 +38,10 @@ export function logout() {
|
||||
|
||||
/** @desc 获取用户信息 */
|
||||
export const getUserInfo = () => {
|
||||
return service.get(`${BASE_URL}/user/info`)
|
||||
}
|
||||
|
||||
/** @desc 获取路由信息 */
|
||||
export const getUserRoute = () => {
|
||||
return service.get(`${BASE_URL}/route`)
|
||||
return service.get(`/sysUser/currentUser
|
||||
`)
|
||||
}
|
||||
|
||||
export const checkUsertoken = () => {
|
||||
return service.get(`${BASE_URL}/check/token`)
|
||||
return service.post(`/login/validateToken`)
|
||||
}
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
import service from '@/utils/request'
|
||||
|
||||
// 获取生成历史列表
|
||||
export function getGenerateHistoryList(query) {
|
||||
return service.get('/taskRecordHistory', { params: query })
|
||||
}
|
||||
// ==================== 历史记录 API(axios) ====================
|
||||
|
||||
// 取消或收藏
|
||||
export function cancelOrCollect(query) {
|
||||
@ -15,7 +12,28 @@ export function deleteGenerateHistory(query) {
|
||||
return service.delete('/taskRecordHistory/delete', { params: query })
|
||||
}
|
||||
|
||||
// 获取免费次数
|
||||
export function getFreeTimes(id) {
|
||||
return service.get('/plantformBalance/userBalances', { params: { id } })
|
||||
}
|
||||
// ==================== 任务 API(axios,经由 /suanli 前缀路由到算力调度后端) ====================
|
||||
|
||||
// 创建生成任务(HTTP POST /suanli/v1/tasks)
|
||||
export function requestCreateTask(body, sessionId) {
|
||||
return service.post('/suanli/v1/tasks', body, {
|
||||
headers: { 'X-Session-Id': sessionId }
|
||||
})
|
||||
}
|
||||
|
||||
// 查询任务状态 / 获取历史任务结果(HTTP GET /suanli/v1/tasks/:id)
|
||||
export function requestTaskStatus(taskId) {
|
||||
return service.get(`/suanli/v1/tasks/${taskId}`)
|
||||
}
|
||||
|
||||
// 获取历史任务列表(HTTP GET /suanli/v1/tasks/history,支持平台筛选和分页)
|
||||
export function requestTaskHistory(params) {
|
||||
return service.get('/suanli/v1/tasks/history', { params })
|
||||
}
|
||||
|
||||
// ==================== 平台模型 API ====================
|
||||
|
||||
// 获取平台模型列表(原始 HTTP 调用,不含缓存逻辑)
|
||||
export function fetchPlatformModels(code) {
|
||||
return service.get(`/suanli/v1/platforms/${code}/models`)
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@
|
||||
|
||||
<script setup>
|
||||
import { generate } from '@/utils/websocket'
|
||||
import { useDisplayStore, useUserStore } from '@/stores'
|
||||
import { useDisplayStore } from '@/stores'
|
||||
import request from '@/utils/request'
|
||||
import { getModelId } from '@/utils/modelApi'
|
||||
|
||||
@ -742,7 +742,6 @@ const handleSend = async () => {
|
||||
modelName: 'GPT',
|
||||
modelId,
|
||||
quantity: 1,
|
||||
free: useUserStore().freeTimes,
|
||||
params: [
|
||||
{ name: 'prompt', data: inputText.value + '并且去除掉图1中的框' },
|
||||
{ name: 'index', data: 1 },
|
||||
|
||||
@ -83,7 +83,7 @@ import ImageUploader from './imageUploader/index.vue'
|
||||
import VideoImageUploader from './videoImageUploader/index.vue'
|
||||
import Time from './Time/index.vue'
|
||||
import { Sender } from 'vue-element-plus-x'
|
||||
import { useDisplayStore, useUserStore } from '@/stores'
|
||||
import { useDisplayStore } from '@/stores'
|
||||
import { generate } from '@/utils/websocket'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { fetchModelConfig } from '@/utils/modelConfig'
|
||||
@ -106,8 +106,6 @@ const props = defineProps({
|
||||
|
||||
const router = useRouter()
|
||||
const useDisplay = useDisplayStore()
|
||||
const useUser = useUserStore()
|
||||
|
||||
const isgerenate = ref(false)
|
||||
|
||||
const model = ref() // 模型
|
||||
@ -234,7 +232,6 @@ const handleStart = async () => {
|
||||
modelName: model.value,
|
||||
modelId: modelId || modelDisplayConfig.value?.modelId || '',
|
||||
quantity: quantity.value,
|
||||
free: useUser.freeTimes,
|
||||
params: [
|
||||
{ name: 'prompt', data: prompt.value},
|
||||
{ name: 'quantity', data: quantity.value},
|
||||
@ -301,16 +298,8 @@ watch(() => props.type, (newType) => {
|
||||
} else {
|
||||
model.value = 'flux'
|
||||
}
|
||||
const chargeType = newType === 'Painting' ? 1 : 4
|
||||
useUser.fetchFreeTimes(chargeType)
|
||||
}, { immediate: true })
|
||||
|
||||
// 组件挂载时获取免费次数
|
||||
onMounted(async () => {
|
||||
const chargeType = props.type === 'Painting' ? 1 : 4
|
||||
await useUser.fetchFreeTimes(chargeType)
|
||||
console.log('免费次数', useUser.freeTimes)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
@ -4,7 +4,6 @@ import {
|
||||
getUserInfo as getUserInfoApi,
|
||||
logout as logoutApi
|
||||
} from '@/apis/auth'
|
||||
import { getFreeTimes } from '@/apis/display'
|
||||
import { clearToken, getToken, setToken } from '@/utils/auth'
|
||||
|
||||
const storeSetup = () => {
|
||||
@ -34,7 +33,6 @@ const storeSetup = () => {
|
||||
|
||||
const dept = ref({}) // 当前用户所在部门集合
|
||||
const isLogin = ref(false)
|
||||
const freeTimes = ref(0) // 免费次数
|
||||
|
||||
// 重置token
|
||||
const resetToken = () => {
|
||||
@ -45,49 +43,40 @@ const storeSetup = () => {
|
||||
// 检查token有效性
|
||||
const checkTokenValid = async () => {
|
||||
const res = await checkUsertokenApi()
|
||||
console.log('checkTokenValid:', res) // 打印响应数据以进行调试
|
||||
if (res.code === '401' || res.success === false) {
|
||||
// 检查响应数据是否存在,以避免空响应导致的错误
|
||||
console.error('Token is invalid:', res.message)// 打印错误信息以进行调试
|
||||
console.log('checkTokenValid:', res)
|
||||
if (res.code === '401' || res.status === '401' || res.success === false) {
|
||||
console.error('Token is invalid:', res.message)
|
||||
return false
|
||||
}
|
||||
console.log('Token is valid') // 打印成功信息以进行调试
|
||||
console.log('Token is valid')
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
const getInfo = async () => {
|
||||
const res = await getUserInfoApi()
|
||||
Object.assign(userInfo, res.data)
|
||||
// userInfo.avatar = getAvatar(res.data.avatar, res.data.gender)
|
||||
userInfo.username = res.data.username
|
||||
if (typeof res.data.routers === 'string' && res.data.routers.trim() !== '') {
|
||||
userInfo.routers = res.data.routers.split(',').map((item) => item.trim()) // 补充trim处理更完善
|
||||
// 兼容新旧格式:新格式 data.userInfo 嵌套,旧格式 data 扁平
|
||||
const u = res.data.userInfo || res.data
|
||||
Object.assign(userInfo, u)
|
||||
userInfo.id = u.userId || u.id
|
||||
userInfo.username = u.userName || u.username
|
||||
if (typeof u.routers === 'string' && u.routers.trim() !== '') {
|
||||
userInfo.routers = u.routers.split(',').map((item) => item.trim())
|
||||
} else {
|
||||
userInfo.routers = []
|
||||
}
|
||||
if (res.data.roles && res.data.roles.length) {
|
||||
roles.value = res.data.roles
|
||||
permissions.value = res.data.permissions
|
||||
// 角色和权限在 data 层级(非 userInfo 内)
|
||||
const roleList = res.data.roles || u.roles
|
||||
if (roleList?.length) {
|
||||
roles.value = roleList
|
||||
permissions.value = res.data.permissions || u.permissions || []
|
||||
}
|
||||
}
|
||||
|
||||
// 获取免费次数
|
||||
const fetchFreeTimes = async (chargeType = 1) => {
|
||||
if (userInfo.id) {
|
||||
const res = await getFreeTimes(userInfo.id)
|
||||
const balanceList = res.data || []
|
||||
const target = balanceList.find((item) => item.chargeType === chargeType)
|
||||
freeTimes.value = target?.balance || 0
|
||||
return freeTimes.value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// 登录
|
||||
const accountLogin = async (req) => {
|
||||
const res = await accountLoginApi(req)
|
||||
if (res.data == null || res.code === '500' || res.success === false) {
|
||||
if (res.data == null || res.code === '500' || res.status === 500 || res.success === false) {
|
||||
// eslint-disable-next-line no-undef
|
||||
ElMessage({
|
||||
title: '提示',
|
||||
@ -134,14 +123,12 @@ const storeSetup = () => {
|
||||
dept,
|
||||
username,
|
||||
isLogin,
|
||||
freeTimes,
|
||||
accountLogin,
|
||||
logout,
|
||||
logoutCallBack,
|
||||
getInfo,
|
||||
resetToken,
|
||||
checkTokenValid,
|
||||
fetchFreeTimes
|
||||
checkTokenValid
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { fetchPlatformModels as fetchModelsRaw } from '@/apis/display'
|
||||
|
||||
const CACHE_PREFIX = 'platform_models_'
|
||||
|
||||
@ -53,13 +53,7 @@ export function getPlatformCode(type) {
|
||||
}
|
||||
}
|
||||
|
||||
// suanli 接口的基础 URL(不带 /api 后缀)
|
||||
function getSuanliBaseUrl() {
|
||||
const apiBase = import.meta.env.VITE_API_BASE_URL || ''
|
||||
return apiBase.replace(/\/api$/, '')
|
||||
}
|
||||
|
||||
// 获取平台模型列表
|
||||
// 获取平台模型列表(带 localStorage 每日缓存)
|
||||
export async function fetchPlatformModels(code) {
|
||||
const cached = getFromCache(code)
|
||||
if (cached) {
|
||||
@ -68,19 +62,7 @@ export async function fetchPlatformModels(code) {
|
||||
}
|
||||
|
||||
try {
|
||||
const token = getToken()
|
||||
const baseUrl = getSuanliBaseUrl()
|
||||
const url = `${baseUrl}/suanli/v1/platforms/${code}/models`
|
||||
|
||||
console.log(`从远程获取平台模型列表: ${url}`)
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': token
|
||||
}
|
||||
})
|
||||
|
||||
const result = await response.json()
|
||||
const result = await fetchModelsRaw(code)
|
||||
|
||||
if (result.code === 0 && result.data?.models) {
|
||||
saveToCache(code, result.data.models)
|
||||
|
||||
@ -29,21 +29,19 @@ const StatusCodeMessage = {
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
if (!config.headers) {
|
||||
config.headers = {}
|
||||
}
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
if (!config.headers) {
|
||||
config.headers = {}
|
||||
}
|
||||
// console.log(config.baseURL)
|
||||
if (config.url?.startsWith(import.meta.env.VITE_API_PAY_PREFIX)) { // 支付服务路由
|
||||
|
||||
// 统一 Auth 头不带 Bearer 前缀
|
||||
if (token) config.headers.Authorization = token
|
||||
|
||||
if (config.url?.startsWith(import.meta.env.VITE_API_TASK_PREFIX)) { // 算力调度后端
|
||||
config.baseURL = import.meta.env.VITE_API_TASK_TARGET
|
||||
} else if (config.url?.startsWith(import.meta.env.VITE_API_PAY_PREFIX)) { // 支付服务路由
|
||||
config.baseURL = import.meta.env.VITE_API_PAY_TARGET
|
||||
} else if (config.url?.startsWith(import.meta.env.VITE_API_AIGC_PREFIX)) { // 资源服务路由
|
||||
// config.url = config.url.replace(import.meta.env.VITE_API_AIGC_PREFIX, '')
|
||||
config.baseURL = import.meta.env.VITE_API_AIGC_TARGET
|
||||
} else if (config.url?.startsWith(import.meta.env.VITE_API_MUSIC_WORKFLOW_PREFIX)) { // 音频生成平台工作流服务路由
|
||||
config.url = config.url.replace(import.meta.env.VITE_API_MUSIC_WORKFLOW_PREFIX, '')
|
||||
config.baseURL = import.meta.env.VITE_API_MUSIC_WORKFLOW_TARGET
|
||||
}
|
||||
return config
|
||||
},
|
||||
@ -57,11 +55,11 @@ service.interceptors.request.use(
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
const { data } = response
|
||||
const { success, code, msg } = data
|
||||
if (success || code === 0) {
|
||||
const { success, code, status, msg, message } = data
|
||||
if (success || code === 0 || status === 0) {
|
||||
console.log('msg: \n', msg)
|
||||
return response.data
|
||||
} else if (code === 401 && response.config.url !== '/auth/check/token`') { // 判断code=401时进行页面刷新,但是不对检验token这个路由的请求判断,防止出现死循环
|
||||
} else if (code === 401 && response.config.url !== '/login/validateToken`') { // 判断code=401时进行页面刷新,但是不对检验token这个路由的请求判断,防止出现死循环
|
||||
userError()
|
||||
}
|
||||
console.log('CodeMessage: \n', StatusCodeMessage[code])
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { ElNotification } from 'element-plus'
|
||||
import { h } from 'vue'
|
||||
import { useDisplayStore, useUserStore } from '@/stores'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { useDisplayStore } from '@/stores'
|
||||
import { createTask } from '@/utils/createTask'
|
||||
import { userError } from '@/utils/tokenError'
|
||||
import { requestCreateTask, requestTaskStatus } from '@/apis/display'
|
||||
|
||||
export function getChargeType(chargeType) {
|
||||
switch (chargeType) {
|
||||
@ -63,8 +63,6 @@ const activePollIntervals = new Set()
|
||||
|
||||
export async function generate(data, generateData) {
|
||||
const useDisplay = useDisplayStore()
|
||||
const token = getToken()
|
||||
const baseUrl = import.meta.env.VITE_API_BASE_URL
|
||||
let taskId = null
|
||||
let pollInterval = null
|
||||
|
||||
@ -94,17 +92,7 @@ export async function generate(data, generateData) {
|
||||
}
|
||||
|
||||
// POST 创建任务
|
||||
const createResponse = await fetch(`${baseUrl}/v1/tasks`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': token,
|
||||
'X-Session-Id': sessionId
|
||||
},
|
||||
body: JSON.stringify(requestBody)
|
||||
})
|
||||
|
||||
const createResult = await createResponse.json()
|
||||
const createResult = await requestCreateTask(requestBody, sessionId)
|
||||
|
||||
if (createResult.code !== 0) {
|
||||
ElNotification({
|
||||
@ -131,14 +119,7 @@ export async function generate(data, generateData) {
|
||||
// 轮询任务状态
|
||||
const pollTask = async () => {
|
||||
try {
|
||||
const pollResponse = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': token
|
||||
}
|
||||
})
|
||||
|
||||
const pollResult = await pollResponse.json()
|
||||
const pollResult = await requestTaskStatus(taskId)
|
||||
|
||||
if (pollResult.code !== 0) return
|
||||
|
||||
@ -153,7 +134,6 @@ export async function generate(data, generateData) {
|
||||
const urls = taskData.outputs?.images?.map(img => img.url) || []
|
||||
if (urls.length > 0) {
|
||||
useDisplay.updateItemToSuccess(taskId, urls)
|
||||
if (useUserStore().freeTimes) await useUserStore().fetchFreeTimes()
|
||||
websocketSuccess()
|
||||
} else {
|
||||
websocketError(4403, '未获取到生成结果')
|
||||
|
||||
@ -73,9 +73,10 @@ import RefreshOverlay from './components/RefreshOverlay.vue'
|
||||
import Select from '@/components/Select/index.vue'
|
||||
import { VirtualScroller } from '@/components/virtual-scroller'
|
||||
import Canvas from '@/components/canvas/index.vue'
|
||||
import { getGenerateHistoryList } from '@/apis/display'
|
||||
import { requestTaskHistory } from '@/apis/display'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { getChargeType } from '@/utils/websocket'
|
||||
import { getPlatformCode } from '@/utils/modelApi'
|
||||
|
||||
const props = defineProps({
|
||||
if: {
|
||||
@ -163,12 +164,11 @@ const fetchHistory = async (isLoadMore = false) => {
|
||||
try {
|
||||
const pageToFetch = isLoadMore ? currentPage.value + 1 : 1
|
||||
|
||||
const result = await getGenerateHistoryList({
|
||||
userId: userStore.userInfo.id,
|
||||
chargeType: chargeType.value,
|
||||
page: pageToFetch,
|
||||
size: 10,
|
||||
sort: 'createTime,desc'
|
||||
const result = await requestTaskHistory({
|
||||
user_id: userStore.userInfo.id,
|
||||
platform_code: getPlatformCode(props.type),
|
||||
page: pageToFetch,
|
||||
pageSize: 10
|
||||
})
|
||||
|
||||
const dataList = result.data?.list || result.data || []
|
||||
|
||||
Loading…
Reference in New Issue
Block a user