[AC-AISVC-50] 合入第一个稳定版本 #2

Merged
MerCry merged 32 commits from feature/prompt-unification-and-logging into main 2026-02-26 13:03:31 +00:00
7 changed files with 53 additions and 24 deletions
Showing only changes of commit b91b57cfa4 - Show all commits

View File

@ -98,7 +98,6 @@ const isValidTenantId = (tenantId: string): boolean => {
const fetchTenantList = async () => {
loading.value = true
try {
// ID
if (!isValidTenantId(currentTenantId.value)) {
console.warn('Invalid tenant ID format, resetting to default:', currentTenantId.value)
currentTenantId.value = 'default@ash@2026'
@ -108,7 +107,6 @@ const fetchTenantList = async () => {
const response = await getTenantList()
tenantList.value = response.tenants || []
//
if (tenantList.value.length > 0 && !tenantList.value.find(t => t.id === currentTenantId.value)) {
const firstTenant = tenantList.value[0]
currentTenantId.value = firstTenant.id
@ -117,8 +115,7 @@ const fetchTenantList = async () => {
} catch (error) {
ElMessage.error('获取租户列表失败')
console.error('Failed to fetch tenant list:', error)
// 使
tenantList.value = [{ id: 'default@ash@2026', name: 'default (2026)' }]
tenantList.value = [{ id: 'default@ash@2026', name: 'default (2026)', displayName: 'default', year: '2026', createdAt: new Date().toISOString() }]
} finally {
loading.value = false
}

View File

@ -13,7 +13,7 @@ export interface TenantListResponse {
total: number
}
export function getTenantList() {
export function getTenantList(): Promise<TenantListResponse> {
return request<TenantListResponse>({
url: '/admin/tenants',
method: 'get'

View File

@ -1,21 +1,22 @@
import axios from 'axios'
import axios, { type AxiosRequestConfig } from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useTenantStore } from '@/stores/tenant'
// 创建 axios 实例
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API || '/api',
timeout: 60000
})
// 请求拦截器
service.interceptors.request.use(
(config) => {
const tenantStore = useTenantStore()
if (tenantStore.currentTenantId) {
config.headers['X-Tenant-Id'] = tenantStore.currentTenantId
}
// TODO: 如果有 token 也可以在这里注入 Authorization
const apiKey = import.meta.env.VITE_APP_API_KEY
if (apiKey) {
config.headers['X-API-Key'] = apiKey
}
return config
},
(error) => {
@ -24,11 +25,9 @@ service.interceptors.request.use(
}
)
// 响应拦截器
service.interceptors.response.use(
(response) => {
const res = response.data
// 这里可以根据后端的 code 进行统一处理
return res
},
(error) => {
@ -42,7 +41,6 @@ service.interceptors.response.use(
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// TODO: 跳转到登录页或执行退出逻辑
location.href = '/login'
})
} else if (status === 403) {
@ -69,4 +67,13 @@ service.interceptors.response.use(
}
)
export default service
interface RequestConfig extends AxiosRequestConfig {
url: string
method?: string
}
function request<T = any>(config: RequestConfig): Promise<T> {
return service.request<any, T>(config)
}
export default request

View File

@ -102,10 +102,17 @@ interface DocumentItem {
createTime: string
}
interface IndexJob {
jobId: string
status: string
progress: number
errorMsg?: string
}
const tableData = ref<DocumentItem[]>([])
const loading = ref(false)
const jobDialogVisible = ref(false)
const currentJob = ref<any>(null)
const currentJob = ref<IndexJob | null>(null)
const pollingJobs = ref<Set<string>>(new Set())
let pollingInterval: number | null = null
@ -150,10 +157,15 @@ const fetchDocuments = async () => {
}
}
const fetchJobStatus = async (jobId: string) => {
const fetchJobStatus = async (jobId: string): Promise<IndexJob | null> => {
try {
const res = await getIndexJob(jobId)
return res
const res: any = await getIndexJob(jobId)
return {
jobId: res.jobId || jobId,
status: res.status || 'pending',
progress: res.progress || 0,
errorMsg: res.errorMsg
}
} catch (error) {
console.error('Failed to fetch job status:', error)
return null
@ -246,19 +258,21 @@ const handleFileChange = async (event: Event) => {
try {
loading.value = true
const res = await uploadDocument(formData)
ElMessage.success(`文档上传成功任务ID: ${res.jobId}`)
const res: any = await uploadDocument(formData)
const jobId = res.jobId as string
ElMessage.success(`文档上传成功任务ID: ${jobId}`)
console.log('Upload response:', res)
const newDoc: DocumentItem = {
docId: res.docId || '',
name: file.name,
status: res.status || 'pending',
jobId: res.jobId,
status: (res.status as string) || 'pending',
jobId: jobId,
createTime: new Date().toLocaleString('zh-CN')
}
tableData.value.unshift(newDoc)
startPolling(res.jobId)
startPolling(jobId)
} catch (error) {
ElMessage.error('文档上传失败')
console.error('Upload error:', error)

View File

@ -327,7 +327,7 @@ const runStreamExperiment = async () => {
} else if (parsed.type === 'error') {
streamError.value = parsed.message || '流式输出错误'
streaming.value = false
ElMessage.error(streamError.value)
ElMessage.error(streamError.value || '未知错误')
}
} catch {
streamContent.value += data

10
ai-service-admin/src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_BASE_API: string
readonly VITE_APP_API_KEY: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}

View File

@ -15,7 +15,8 @@
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"types": ["vite/client"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]