fix: 租户模型列表问题未解决,待进一步调试
This commit is contained in:
parent
b5fa1b0d63
commit
f52f3b27aa
28
api/app.py
28
api/app.py
@ -1,5 +1,6 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from typing import List
|
||||||
from fastapi import FastAPI, Depends, HTTPException, status, Request, Body, Response, UploadFile, File
|
from fastapi import FastAPI, Depends, HTTPException, status, Request, Body, Response, UploadFile, File
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
@ -116,7 +117,9 @@ async def get_current_user(token: str = Depends(oauth2_scheme)):
|
|||||||
# 打印接收到的token用于调试
|
# 打印接收到的token用于调试
|
||||||
logger.info(f"Received token: {token[:10]}...{token[-10:]}")
|
logger.info(f"Received token: {token[:10]}...{token[-10:]}")
|
||||||
|
|
||||||
|
print(f"Full token: {token}") # 调试日志
|
||||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||||
|
print(f"Decoded payload: {payload}") # 调试日志
|
||||||
username: str = payload.get("sub")
|
username: str = payload.get("sub")
|
||||||
if username is None:
|
if username is None:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
@ -424,19 +427,21 @@ async def create_tenant(tenant: TenantCreate, current_user: dict = Depends(get_c
|
|||||||
logger.error(f"创建租户失败: {e}")
|
logger.error(f"创建租户失败: {e}")
|
||||||
raise HTTPException(status_code=400, detail="创建租户失败")
|
raise HTTPException(status_code=400, detail="创建租户失败")
|
||||||
|
|
||||||
@app.get("/api/tenants/")
|
@app.get("/api/tenants/", response_model=List[TenantResponse])
|
||||||
async def list_tenants(current_user: dict = Depends(get_current_user)):
|
async def list_tenants(
|
||||||
|
search: str = None,
|
||||||
|
current_user: dict = Depends(get_current_user)
|
||||||
|
):
|
||||||
"""查询租户列表"""
|
"""查询租户列表"""
|
||||||
try:
|
try:
|
||||||
tenants = TenantManager.get_all_tenants()
|
logger.info(f"Current user accessing tenants: {current_user['username']}")
|
||||||
return {
|
tenants = TenantManager.search_tenants(search) if search else TenantManager.get_all_tenants()
|
||||||
"tenants": [{
|
if not tenants:
|
||||||
"id": str(t["id"]),
|
raise HTTPException(
|
||||||
"name": t["name"],
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
"description": t.get("description", ""),
|
detail="未找到匹配的租户"
|
||||||
"created_at": t.get("created_at", datetime.now(timezone.utc))
|
)
|
||||||
} for t in tenants]
|
return tenants
|
||||||
}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"查询租户列表失败: {e}")
|
logger.error(f"查询租户列表失败: {e}")
|
||||||
raise HTTPException(status_code=400, detail="查询租户列表失败")
|
raise HTTPException(status_code=400, detail="查询租户列表失败")
|
||||||
@ -445,6 +450,7 @@ async def list_tenants(current_user: dict = Depends(get_current_user)):
|
|||||||
async def get_tenant(name: str, current_user: dict = Depends(get_current_user)):
|
async def get_tenant(name: str, current_user: dict = Depends(get_current_user)):
|
||||||
"""查询特定租户"""
|
"""查询特定租户"""
|
||||||
try:
|
try:
|
||||||
|
logger.info(f"Current user accessing tenant {name}: {current_user['username']}")
|
||||||
tenant = TenantManager.get_tenant_by_name(name)
|
tenant = TenantManager.get_tenant_by_name(name)
|
||||||
if not tenant:
|
if not tenant:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|||||||
@ -61,16 +61,19 @@ class ModelManager:
|
|||||||
cursor.execute(query, (tenant_id,))
|
cursor.execute(query, (tenant_id,))
|
||||||
models = cursor.fetchall()
|
models = cursor.fetchall()
|
||||||
|
|
||||||
return [{
|
return {
|
||||||
"id": str(model[0]),
|
"tenant_id": tenant_id,
|
||||||
"provider_name": model[1],
|
"models": [{
|
||||||
"model_name": model[2],
|
"id": str(model[0]),
|
||||||
"model_type": model[3],
|
"provider_name": model[1],
|
||||||
"encrypted_config": json.loads(model[4]),
|
"model_name": model[2],
|
||||||
"is_valid": model[5],
|
"model_type": model[3],
|
||||||
"created_at": model[6],
|
"encrypted_config": json.loads(model[4]),
|
||||||
"updated_at": model[7]
|
"is_valid": model[5],
|
||||||
} for model in models]
|
"created_at": model[6],
|
||||||
|
"updated_at": model[7]
|
||||||
|
} for model in models]
|
||||||
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取租户模型失败: {e}")
|
logger.error(f"获取租户模型失败: {e}")
|
||||||
raise
|
raise
|
||||||
|
|||||||
@ -54,5 +54,5 @@ class TenantResponse(BaseModel):
|
|||||||
"""租户响应模型"""
|
"""租户响应模型"""
|
||||||
id: str
|
id: str
|
||||||
name: str
|
name: str
|
||||||
description: str
|
description: Optional[str] = None
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
|
|||||||
@ -107,9 +107,42 @@ class TenantManager:
|
|||||||
def get_all_tenants():
|
def get_all_tenants():
|
||||||
"""获取所有租户信息"""
|
"""获取所有租户信息"""
|
||||||
try:
|
try:
|
||||||
query = "SELECT id, encrypt_public_key FROM tenants;"
|
query = """
|
||||||
|
SELECT
|
||||||
|
id::text,
|
||||||
|
name,
|
||||||
|
encrypt_public_key,
|
||||||
|
created_at
|
||||||
|
FROM tenants;
|
||||||
|
"""
|
||||||
tenants = execute_query(query, cursor_factory=RealDictCursor)
|
tenants = execute_query(query, cursor_factory=RealDictCursor)
|
||||||
|
if not tenants:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 确保返回字段名正确
|
||||||
return tenants
|
return tenants
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取所有租户信息失败: {e}")
|
logger.error(f"获取所有租户信息失败: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def search_tenants(search_term: str):
|
||||||
|
"""根据名称搜索租户"""
|
||||||
|
try:
|
||||||
|
query = """
|
||||||
|
SELECT
|
||||||
|
id::text,
|
||||||
|
name,
|
||||||
|
encrypt_public_key,
|
||||||
|
created_at
|
||||||
|
FROM tenants
|
||||||
|
WHERE name ILIKE %s;
|
||||||
|
"""
|
||||||
|
tenants = execute_query(query, (f"%{search_term}%",), cursor_factory=RealDictCursor)
|
||||||
|
if not tenants:
|
||||||
|
return []
|
||||||
|
|
||||||
|
return tenants
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"搜索租户失败: {e}")
|
||||||
|
return []
|
||||||
|
|||||||
@ -29,6 +29,7 @@ export function assignModelToTenant(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getTenantModels(tenantId: string): Promise<ApiResponse<TenantModelResponse>> {
|
export function getTenantModels(tenantId: string): Promise<ApiResponse<TenantModelResponse>> {
|
||||||
|
console.log('请求模型列表API,路径:', `/api/models/${tenantId}`)
|
||||||
return request({
|
return request({
|
||||||
url: `/api/models/${tenantId}`,
|
url: `/api/models/${tenantId}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
|
|||||||
@ -23,8 +23,31 @@ export interface ModelResponse {
|
|||||||
created_at: string
|
created_at: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ModelItem {
|
||||||
|
id: string
|
||||||
|
model_name: string
|
||||||
|
provider_name: string
|
||||||
|
model_type: string
|
||||||
|
encrypted_config: any
|
||||||
|
is_valid: boolean
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModelItem {
|
||||||
|
id: string
|
||||||
|
provider_name: string
|
||||||
|
model_name: string
|
||||||
|
model_type: string
|
||||||
|
encrypted_config: any
|
||||||
|
is_valid: boolean
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface TenantModelResponse {
|
export interface TenantModelResponse {
|
||||||
tenant_id: string
|
tenant_id: string
|
||||||
tenant_name: string
|
models: {
|
||||||
models: ModelResponse[]
|
models: ModelItem[]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,17 +7,15 @@ import type {
|
|||||||
CreateTenantResponse
|
CreateTenantResponse
|
||||||
} from './types'
|
} from './types'
|
||||||
|
|
||||||
export const fetchTenants = (params: { page?: number; pageSize?: number }) =>
|
export const fetchTenants = (params: { search?: string; page?: number; pageSize?: number }) =>
|
||||||
request<{
|
request<{
|
||||||
tenants: {
|
id: string
|
||||||
id: string
|
name: string
|
||||||
name: string
|
description: string
|
||||||
description: string
|
createdAt: string
|
||||||
createdAt: string
|
}[]>({
|
||||||
}[]
|
|
||||||
}>({
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/api/tenants',
|
url: '/api/tenants/',
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -8,11 +8,14 @@ const service = createAxios()
|
|||||||
service.interceptors.request.use(
|
service.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
const token = localStorage.getItem('access_token')
|
const token = localStorage.getItem('access_token')
|
||||||
|
console.log('Request interceptor - token:', token) // 调试日志
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers.Authorization = `Bearer ${token}`
|
config.headers.Authorization = `Bearer ${token}`
|
||||||
|
console.log('Authorization header set:', config.headers.Authorization) // 调试日志
|
||||||
}
|
}
|
||||||
config.headers['Content-Type'] = 'application/json'
|
config.headers['Content-Type'] = 'application/json'
|
||||||
config.withCredentials = true
|
config.withCredentials = true
|
||||||
|
console.log('Final request config:', config) // 调试日志
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
|||||||
@ -107,7 +107,7 @@ import {
|
|||||||
} from '@/api/model'
|
} from '@/api/model'
|
||||||
import { fetchTenants } from '@/api/tenant'
|
import { fetchTenants } from '@/api/tenant'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import type { ModelResponse } from '@/api/model/types'
|
import type { ModelResponse, ModelItem } from '@/api/model/types'
|
||||||
|
|
||||||
interface Tenant {
|
interface Tenant {
|
||||||
id: string
|
id: string
|
||||||
@ -130,27 +130,67 @@ const assignForm = ref({
|
|||||||
|
|
||||||
const searchTenants = async () => {
|
const searchTenants = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetchTenants({ search: searchQuery.value })
|
const tenants = await fetchTenants({ search: searchQuery.value })
|
||||||
searchedTenants.value = res.tenants
|
searchedTenants.value = tenants
|
||||||
} catch (error) {
|
if (tenants.length === 0) {
|
||||||
ElMessage.error('查询租户失败')
|
ElMessage.warning('未找到匹配的租户')
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.response?.status === 404) {
|
||||||
|
searchedTenants.value = []
|
||||||
|
ElMessage.warning('未找到匹配的租户')
|
||||||
|
} else {
|
||||||
|
ElMessage.error('查询租户失败')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const showTenantModels = async (tenantId: string) => {
|
const showTenantModels = async (tenantId: string) => {
|
||||||
try {
|
try {
|
||||||
const res = await getTenantModels(tenantId)
|
console.log('开始请求模型列表,租户ID:', tenantId)
|
||||||
models.value = res.data.models
|
const res = await getTenantModels(tenantId).catch(err => {
|
||||||
modelDialogVisible.value = true
|
console.error('获取模型列表失败:', err)
|
||||||
} catch (error) {
|
console.error('错误详情:', err.response?.data || err.message)
|
||||||
ElMessage.error('加载模型列表失败')
|
throw err
|
||||||
|
})
|
||||||
|
console.log('完整API响应:', JSON.stringify(res, null, 2))
|
||||||
|
console.log('响应数据:', res.data)
|
||||||
|
console.log('响应数据.models:', res.data?.models)
|
||||||
|
if (res?.data?.models?.models) {
|
||||||
|
models.value = res.data.models.models.map((m: ModelItem) => ({
|
||||||
|
id: m.id,
|
||||||
|
model_name: m.model_name,
|
||||||
|
provider_name: m.provider_name,
|
||||||
|
model_type: m.model_type,
|
||||||
|
created_at: m.created_at,
|
||||||
|
updated_at: m.updated_at
|
||||||
|
}))
|
||||||
|
modelDialogVisible.value = true
|
||||||
|
} else {
|
||||||
|
ElMessage.error('获取模型列表失败: 返回数据格式不正确')
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error('加载模型列表失败: ' +
|
||||||
|
(error.response?.data?.message ||
|
||||||
|
error.message ||
|
||||||
|
'未知错误'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleTenantChange = async (tenantId: string) => {
|
const handleTenantChange = async (tenantId: string) => {
|
||||||
try {
|
try {
|
||||||
const res = await getTenantModels(tenantId)
|
const res = await getTenantModels(tenantId)
|
||||||
models.value = res.data.models
|
if (res?.data?.models?.models) {
|
||||||
|
models.value = res.data.models.models.map((m: ModelItem) => ({
|
||||||
|
id: m.id,
|
||||||
|
model_name: m.model_name,
|
||||||
|
provider_name: m.provider_name,
|
||||||
|
model_type: m.model_type,
|
||||||
|
created_at: m.created_at
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
ElMessage.error('获取模型列表失败: 返回数据格式不正确')
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('加载模型列表失败')
|
ElMessage.error('加载模型列表失败')
|
||||||
}
|
}
|
||||||
@ -182,7 +222,17 @@ const loadModels = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const res = await getTenantModels(currentTenantId)
|
const res = await getTenantModels(currentTenantId)
|
||||||
models.value = res.data.models
|
if (res?.data?.models?.models) {
|
||||||
|
models.value = res.data.models.models.map((m: ModelItem) => ({
|
||||||
|
id: m.id,
|
||||||
|
model_name: m.model_name,
|
||||||
|
provider_name: m.provider_name,
|
||||||
|
model_type: m.model_type,
|
||||||
|
created_at: m.created_at
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
ElMessage.error('获取模型列表失败: 返回数据格式不正确')
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('加载模型列表失败')
|
ElMessage.error('加载模型列表失败')
|
||||||
}
|
}
|
||||||
@ -190,8 +240,7 @@ const loadModels = async () => {
|
|||||||
|
|
||||||
const loadTenants = async () => {
|
const loadTenants = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetchTenants({})
|
tenants.value = await fetchTenants({})
|
||||||
tenants.value = res.tenants
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('加载租户列表失败')
|
ElMessage.error('加载租户列表失败')
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user