feat: 实现基础设施层

axios 请求封装及七个业务模块 API,Pinia 状态管理(auth/system/models/tools),Mock 适配器与数据,以及流式对话、轮询、倒计时组合式函数。
This commit is contained in:
caoxiaozhu
2026-07-10 16:45:06 +08:00
parent 8aa67003c8
commit ca9e05aa91
17 changed files with 1197 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { login as loginApi } from '@/api/modules/system'
import { SESSION_TIMEOUT } from '@/constants'
/**
* 认证 store
* 沿用原项目 localStorage 的登录时间戳 + 5 分钟会话超时机制
*/
export const useAuthStore = defineStore('auth', () => {
const username = ref<string>(localStorage.getItem('username') || '')
const loginTime = ref<number>(parseInt(localStorage.getItem('loginTime') || '0', 10) || 0)
const isLoggedIn = computed(() => {
if (!loginTime.value) return false
return Date.now() - loginTime.value < SESSION_TIMEOUT
})
/** 登录 */
async function login(user: string, password: string) {
await loginApi(user, password)
username.value = user
loginTime.value = Date.now()
localStorage.setItem('username', user)
localStorage.setItem('loginTime', String(loginTime.value))
}
/** 续期会话(活跃时刷新) */
function refresh() {
if (isLoggedIn.value) {
loginTime.value = Date.now()
localStorage.setItem('loginTime', String(loginTime.value))
}
}
/** 退出 */
function logout() {
username.value = ''
loginTime.value = 0
localStorage.removeItem('username')
localStorage.removeItem('loginTime')
}
return { username, loginTime, isLoggedIn, login, refresh, logout }
})

View File

@@ -0,0 +1,34 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { getModelList } from '@/api/modules/model'
import type { ModelItem } from '@/types'
/**
* 模型列表缓存 store
* 列表页根据 base_model id 渲染模型名时使用
*/
export const useModelsStore = defineStore('models', () => {
const list = ref<ModelItem[]>([])
const loaded = ref(false)
async function load(force = false) {
if (loaded.value && !force) return
try {
list.value = (await getModelList()) || []
loaded.value = true
} catch {
list.value = []
}
}
/** 根据 id 获取模型名 */
function getModelName(modelId: string | number): string {
if (!modelId) return '-'
const model = list.value.find(
(m) => m.id == modelId || m.id === String(modelId) || m.id === Number(modelId),
)
return model ? model.name : `模型${modelId}`
}
return { list, loaded, load, getModelName }
})

View File

@@ -0,0 +1,36 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { getHealth } from '@/api/modules/system'
import type { HealthMetrics } from '@/types'
/**
* 顶部栏系统监控 store
* 30s 轮询 CPU/内存/磁盘使用率
*/
export const useSystemStore = defineStore('system', () => {
const metrics = ref<HealthMetrics>({})
let timer: ReturnType<typeof setInterval> | null = null
async function fetchMetrics() {
try {
metrics.value = await getHealth()
} catch {
// 静默失败,顶部栏非关键
}
}
function start() {
if (timer) return
fetchMetrics()
timer = setInterval(fetchMetrics, 30000)
}
function stop() {
if (timer) {
clearInterval(timer)
timer = null
}
}
return { metrics, fetchMetrics, start, stop }
})

View File

@@ -0,0 +1,48 @@
import { defineStore } from 'pinia'
import { ref, watch } from 'vue'
import type { CustomTool } from '@/types'
/**
* 自定义工具 storelocalStorage 持久化)
* 原 web 项目 customTools 仅存本地,无后端
*/
export const useToolsStore = defineStore('tools', () => {
const STORAGE_KEY = 'customTools'
const tools = ref<CustomTool[]>(loadFromStorage())
function loadFromStorage(): CustomTool[] {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
} catch {
return []
}
}
// 持久化
watch(
tools,
(val) => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(val))
},
{ deep: true },
)
function addTool(tool: CustomTool) {
tools.value.push(tool)
}
function updateTool(id: string, data: Partial<CustomTool>) {
const idx = tools.value.findIndex((t) => t.id === id)
if (idx !== -1) tools.value[idx] = { ...tools.value[idx], ...data }
}
function removeTool(id: string) {
tools.value = tools.value.filter((t) => t.id !== id)
}
function getTool(id: string): CustomTool | undefined {
return tools.value.find((t) => t.id === id)
}
return { tools, addTool, updateTool, removeTool, getTool }
})