fix: 修复前端API调用和响应处理,补全i18n多语言包
1. 修复启动卡住问题 - 创建专用 authRequestClient 连接到认证中心 - 修复认证相关API路由错误 2. 修复API响应处理 - 移除错误的 defaultResponseInterceptor - 添加自定义响应拦截器直接返回 response.data - 修复分页数据提取(response.items) 3. 修复类型定义 - Tenant: contactPhone 可选,status 改为 string - User: 添加 phone, tenantId, tenantName, emailConfirmed - Role: 添加 tenantId, isSystem, userCount - OAuth: 修改 Id 类型为 string - 修正所有 DTO 的必填字段 4. 修复查询参数 - 租户列表使用 name 而不是 keyword 5. 补全 i18n 多语言包 - 添加 app, tenant, user, role, oauth, common 模块 - 中文:"蜂铃管理平台"、"蜂铃控制台" - 英文:Fengling Management Platform、Fengling Console 6. 修复租户管理逻辑 - 添加 editingId 跟踪编辑状态 - 修复 handleSave 使用正确的租户ID
This commit is contained in:
parent
fa93d71725
commit
d2d70b462e
@ -13,7 +13,7 @@ VITE_AUTH_SERVER_URL=http://localhost:5132
|
|||||||
VITE_AUTH_SERVICE_URL=http://localhost:5132
|
VITE_AUTH_SERVICE_URL=http://localhost:5132
|
||||||
VITE_OAUTH_CLIENT_ID=fengling-console
|
VITE_OAUTH_CLIENT_ID=fengling-console
|
||||||
VITE_OAUTH_REDIRECT_URI=http://localhost:5777/auth/callback
|
VITE_OAUTH_REDIRECT_URI=http://localhost:5777/auth/callback
|
||||||
VITE_OAUTH_SCOPE=api offline_access openid profile email
|
VITE_OAUTH_SCOPE=fengling_api offline_access openid profile email
|
||||||
|
|
||||||
# 是否开启 Nitro Mock服务,true 为开启,false 为关闭
|
# 是否开启 Nitro Mock服务,true 为开启,false 为关闭
|
||||||
VITE_NITRO_MOCK=false
|
VITE_NITRO_MOCK=false
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { User } from 'oidc-client-ts';
|
import type { User } from 'oidc-client-ts';
|
||||||
import { baseRequestClient } from '#/api/request';
|
import { authRequestClient, baseRequestClient } from '#/api/request';
|
||||||
import { ElNotification } from 'element-plus';
|
import { ElNotification } from 'element-plus';
|
||||||
|
|
||||||
export namespace AuthApi {
|
export namespace AuthApi {
|
||||||
@ -51,7 +51,7 @@ export function getUserInfoFromToken(user: AuthApi.OidcUser): AuthApi.UserInfo {
|
|||||||
*/
|
*/
|
||||||
export async function getUserInfoApi(): Promise<AuthApi.UserInfo> {
|
export async function getUserInfoApi(): Promise<AuthApi.UserInfo> {
|
||||||
try {
|
try {
|
||||||
return await baseRequestClient.get<AuthApi.UserInfo>('/connect/userinfo', {
|
return await authRequestClient.get<AuthApi.UserInfo>('/connect/userinfo', {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@ -73,7 +73,7 @@ export async function getUserInfoApi(): Promise<AuthApi.UserInfo> {
|
|||||||
*/
|
*/
|
||||||
export async function logoutApi() {
|
export async function logoutApi() {
|
||||||
try {
|
try {
|
||||||
await baseRequestClient.post('/connect/logout', {
|
await authRequestClient.post('/connect/logout', {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import type { FenglingApi } from './typings';
|
|||||||
import { requestClient } from '#/api/request';
|
import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
export namespace LogApi {
|
export namespace LogApi {
|
||||||
|
const apiPrefix = '/console'
|
||||||
|
|
||||||
export async function getAuditLogList(params: {
|
export async function getAuditLogList(params: {
|
||||||
page?: number
|
page?: number
|
||||||
pageSize?: number
|
pageSize?: number
|
||||||
@ -13,7 +15,7 @@ export namespace LogApi {
|
|||||||
endDate?: string
|
endDate?: string
|
||||||
}) {
|
}) {
|
||||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Log.AuditLog>>(
|
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Log.AuditLog>>(
|
||||||
'/logs/audit',
|
`${apiPrefix}/logs/audit`,
|
||||||
{ params }
|
{ params }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -28,7 +30,7 @@ export namespace LogApi {
|
|||||||
endDate?: string
|
endDate?: string
|
||||||
}) {
|
}) {
|
||||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Log.AccessLog>>(
|
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Log.AccessLog>>(
|
||||||
'/logs/access',
|
`${apiPrefix}/logs/access`,
|
||||||
{ params }
|
{ params }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import type { FenglingApi } from './typings';
|
|||||||
import { baseRequestClient } from '#/api/request';
|
import { baseRequestClient } from '#/api/request';
|
||||||
|
|
||||||
export namespace OAuthApi {
|
export namespace OAuthApi {
|
||||||
|
|
||||||
|
const apiPrefix = '/console';
|
||||||
/**
|
/**
|
||||||
* 获取OAuth客户端列表
|
* 获取OAuth客户端列表
|
||||||
*/
|
*/
|
||||||
@ -16,7 +18,7 @@ export namespace OAuthApi {
|
|||||||
...(params.keyword ? { keyword: params.keyword } : {}),
|
...(params.keyword ? { keyword: params.keyword } : {}),
|
||||||
});
|
});
|
||||||
return await baseRequestClient.get<FenglingApi.PaginatedResponse<FenglingApi.OAuth.OAuthClient>>(
|
return await baseRequestClient.get<FenglingApi.PaginatedResponse<FenglingApi.OAuth.OAuthClient>>(
|
||||||
`/oauth/clients?${queryParams.toString()}`,
|
`${apiPrefix}/oauth/clients?${queryParams.toString()}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +26,7 @@ export namespace OAuthApi {
|
|||||||
* 获取OAuth客户端详情
|
* 获取OAuth客户端详情
|
||||||
*/
|
*/
|
||||||
export async function getClient(id: number): Promise<FenglingApi.OAuth.OAuthClient> {
|
export async function getClient(id: number): Promise<FenglingApi.OAuth.OAuthClient> {
|
||||||
return await baseRequestClient.get<FenglingApi.OAuth.OAuthClient>(`/oauth/clients/${id}`);
|
return await baseRequestClient.get<FenglingApi.OAuth.OAuthClient>(`${apiPrefix}/oauth/clients/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +35,7 @@ export namespace OAuthApi {
|
|||||||
export async function createClient(
|
export async function createClient(
|
||||||
data: FenglingApi.OAuth.CreateOAuthClientDto,
|
data: FenglingApi.OAuth.CreateOAuthClientDto,
|
||||||
): Promise<FenglingApi.OAuth.OAuthClient> {
|
): Promise<FenglingApi.OAuth.OAuthClient> {
|
||||||
return await baseRequestClient.post<FenglingApi.OAuth.OAuthClient>('/oauth/clients', data);
|
return await baseRequestClient.post<FenglingApi.OAuth.OAuthClient, FenglingApi.OAuth.CreateOAuthClientDto>(`${apiPrefix}/oauth/clients`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,27 +45,27 @@ export namespace OAuthApi {
|
|||||||
id: number,
|
id: number,
|
||||||
data: FenglingApi.OAuth.UpdateOAuthClientDto,
|
data: FenglingApi.OAuth.UpdateOAuthClientDto,
|
||||||
): Promise<FenglingApi.OAuth.OAuthClient> {
|
): Promise<FenglingApi.OAuth.OAuthClient> {
|
||||||
return await baseRequestClient.put<FenglingApi.OAuth.OAuthClient>(`/oauth/clients/${id}`, data);
|
return await baseRequestClient.put<FenglingApi.OAuth.OAuthClient, FenglingApi.OAuth.UpdateOAuthClientDto>(`${apiPrefix}/oauth/clients/${id}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除OAuth客户端
|
* 删除OAuth客户端
|
||||||
*/
|
*/
|
||||||
export async function deleteClient(id: number): Promise<void> {
|
export async function deleteClient(id: number): Promise<void> {
|
||||||
await baseRequestClient.delete(`/oauth/clients/${id}`);
|
await baseRequestClient.delete<void>(`${apiPrefix}/oauth/clients/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置OAuth客户端密钥
|
* 重置OAuth客户端密钥
|
||||||
*/
|
*/
|
||||||
export async function resetClientSecret(id: number): Promise<{ clientSecret: string }> {
|
export async function resetClientSecret(id: number): Promise<{ clientSecret: string }> {
|
||||||
return await baseRequestClient.post<{ clientSecret: string }>(`/oauth/clients/${id}/reset-secret`);
|
return await baseRequestClient.post<{ clientSecret: string }>(`${apiPrefix}/oauth/clients/${id}/reset-secret`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启用/禁用OAuth客户端
|
* 启用/禁用OAuth客户端
|
||||||
*/
|
*/
|
||||||
export async function toggleClientStatus(id: number, status: 'active' | 'inactive'): Promise<void> {
|
export async function toggleClientStatus(id: number, status: 'active' | 'inactive'): Promise<void> {
|
||||||
await baseRequestClient.put(`/oauth/clients/${id}/status`, { status });
|
await baseRequestClient.put<void, { status: string }>(`${apiPrefix}/oauth/clients/${id}/status`, { status });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,34 +3,35 @@ import type { FenglingApi } from './typings';
|
|||||||
import { requestClient } from '#/api/request';
|
import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
export namespace RoleApi {
|
export namespace RoleApi {
|
||||||
|
const apiPrefix = '/console'
|
||||||
export async function getRoleList(params: {
|
export async function getRoleList(params: {
|
||||||
page?: number
|
page?: number
|
||||||
pageSize?: number
|
pageSize?: number
|
||||||
keyword?: string
|
keyword?: string
|
||||||
}) {
|
}) {
|
||||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Role.Role>>(
|
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Role.Role>>(
|
||||||
'/roles',
|
`${apiPrefix}/roles`,
|
||||||
{ params }
|
{ params }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRoleById(id: number) {
|
export async function getRoleById(id: number) {
|
||||||
return requestClient.get<FenglingApi.Role.Role>(`/roles/${id}`);
|
return requestClient.get<FenglingApi.Role.Role>(`${apiPrefix}/roles/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createRole(data: FenglingApi.Role.CreateRoleDto) {
|
export async function createRole(data: FenglingApi.Role.CreateRoleDto) {
|
||||||
return requestClient.post<FenglingApi.Role.Role>('/roles', data);
|
return requestClient.post<FenglingApi.Role.Role, FenglingApi.Role.CreateRoleDto>(`${apiPrefix}/roles`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateRole(id: number, data: FenglingApi.Role.UpdateRoleDto) {
|
export async function updateRole(id: number, data: FenglingApi.Role.UpdateRoleDto) {
|
||||||
return requestClient.put<FenglingApi.Role.Role>(`/roles/${id}`, data);
|
return requestClient.put<void, FenglingApi.Role.UpdateRoleDto>(`${apiPrefix}/roles/${id}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteRole(id: number) {
|
export async function deleteRole(id: number) {
|
||||||
return requestClient.delete(`/roles/${id}`);
|
return requestClient.delete<void>(`${apiPrefix}/roles/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAllRoles() {
|
export async function getAllRoles() {
|
||||||
return requestClient.get<FenglingApi.Role.Role[]>('/roles/all');
|
return requestClient.get<FenglingApi.Role.Role[]>(`${apiPrefix}/roles/all`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,53 +3,72 @@ import type { FenglingApi } from './typings';
|
|||||||
import { requestClient } from '#/api/request';
|
import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
export namespace TenantApi {
|
export namespace TenantApi {
|
||||||
|
|
||||||
|
const apiPrefix = '/console';
|
||||||
export async function getTenantList(params: {
|
export async function getTenantList(params: {
|
||||||
page?: number
|
page?: number
|
||||||
pageSize?: number
|
pageSize?: number
|
||||||
keyword?: string
|
name?: string
|
||||||
|
tenantId?: string
|
||||||
status?: string
|
status?: string
|
||||||
}) {
|
}) {
|
||||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Tenant.Tenant>>(
|
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Tenant.Tenant>>(
|
||||||
'/tenants',
|
`${apiPrefix}/tenants`,
|
||||||
{ params }
|
{ params }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTenantById(id: number) {
|
export async function getTenantById(id: number) {
|
||||||
return requestClient.get<FenglingApi.Tenant.Tenant>(`/tenants/${id}`);
|
return requestClient.get<FenglingApi.Tenant.Tenant>(`${apiPrefix}/tenants/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createTenant(data: FenglingApi.Tenant.CreateTenantDto) {
|
export async function createTenant(data: FenglingApi.Tenant.CreateTenantDto) {
|
||||||
return requestClient.post<FenglingApi.Tenant.Tenant>('/tenants', data);
|
return requestClient.post<FenglingApi.Tenant.Tenant, FenglingApi.Tenant.CreateTenantDto>(`${apiPrefix}/tenants`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateTenant(id: number, data: FenglingApi.Tenant.UpdateTenantDto) {
|
export async function updateTenant(id: number, data: FenglingApi.Tenant.UpdateTenantDto) {
|
||||||
return requestClient.put<FenglingApi.Tenant.Tenant>(`/tenants/${id}`, data);
|
return requestClient.put<void, FenglingApi.Tenant.UpdateTenantDto>(`${apiPrefix}/tenants/${id}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteTenant(id: number) {
|
export async function deleteTenant(id: number) {
|
||||||
return requestClient.delete(`/tenants/${id}`);
|
return requestClient.delete<void>(`${apiPrefix}/tenants/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function activateTenant(id: number) {
|
export async function activateTenant(id: number) {
|
||||||
return requestClient.post(`/tenants/${id}/activate`);
|
return requestClient.post<void>(`${apiPrefix}/tenants/${id}/activate`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deactivateTenant(id: number) {
|
export async function deactivateTenant(id: number) {
|
||||||
return requestClient.post(`/tenants/${id}/deactivate`);
|
return requestClient.post<void>(`${apiPrefix}/tenants/${id}/deactivate`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function extendTenantExpiry(id: number, expiresAt: string) {
|
export async function extendTenantExpiry(id: number, expiresAt: string) {
|
||||||
return requestClient.post(`/tenants/${id}/extend`, { expiresAt });
|
return requestClient.post<void, { expiresAt: string }>(`${apiPrefix}/tenants/${id}/extend`, { expiresAt });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTenantUsers(id: number) {
|
export async function getTenantUsers(id: number) {
|
||||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.User.User>>(
|
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.User.User>>(
|
||||||
`/tenants/${id}/users`
|
`${apiPrefix}/tenants/${id}/users`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTenantRoles(id: number) {
|
||||||
|
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Role.Role>>(
|
||||||
|
`${apiPrefix}/tenants/${id}/roles`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTenantStatistics(id: number) {
|
export async function getTenantStatistics(id: number) {
|
||||||
return requestClient.get(`/tenants/${id}/statistics`);
|
return requestClient.get<Record<string, any>>(`${apiPrefix}/tenants/${id}/statistics`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTenantSettings(id: number) {
|
||||||
|
return requestClient.get<FenglingApi.Tenant.TenantSettings>(
|
||||||
|
`${apiPrefix}/tenants/${id}/settings`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateTenantSettings(id: number, data: FenglingApi.Tenant.TenantSettings) {
|
||||||
|
return requestClient.put<void, FenglingApi.Tenant.TenantSettings>(`${apiPrefix}/tenants/${id}/settings`, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,10 @@ export namespace FenglingApi {
|
|||||||
name: string
|
name: string
|
||||||
contactName: string
|
contactName: string
|
||||||
contactEmail: string
|
contactEmail: string
|
||||||
contactPhone: string
|
contactPhone?: string
|
||||||
maxUsers?: number
|
maxUsers?: number
|
||||||
userCount: number
|
userCount: number
|
||||||
status: 'active' | 'inactive' | 'expired'
|
status: string
|
||||||
expiresAt?: string
|
expiresAt?: string
|
||||||
description?: string
|
description?: string
|
||||||
createdAt: string
|
createdAt: string
|
||||||
@ -20,33 +20,45 @@ export namespace FenglingApi {
|
|||||||
name: string
|
name: string
|
||||||
contactName: string
|
contactName: string
|
||||||
contactEmail: string
|
contactEmail: string
|
||||||
contactPhone: string
|
contactPhone?: string
|
||||||
maxUsers?: number
|
maxUsers?: number
|
||||||
expiresAt?: string
|
expiresAt?: string
|
||||||
status: 'active' | 'inactive'
|
status?: string
|
||||||
description?: string
|
description?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateTenantDto {
|
export interface UpdateTenantDto {
|
||||||
name?: string
|
name: string
|
||||||
contactName?: string
|
contactName: string
|
||||||
contactEmail?: string
|
contactEmail: string
|
||||||
contactPhone?: string
|
contactPhone?: string
|
||||||
maxUsers?: number
|
maxUsers?: number
|
||||||
expiresAt?: string
|
expiresAt?: string
|
||||||
status?: 'active' | 'inactive'
|
status?: string
|
||||||
description?: string
|
description?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TenantSettings {
|
||||||
|
allowRegistration: boolean
|
||||||
|
allowedEmailDomains: string
|
||||||
|
defaultRoleId?: number
|
||||||
|
passwordPolicy: string[]
|
||||||
|
minPasswordLength: number
|
||||||
|
sessionTimeout: number
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace User {
|
export namespace User {
|
||||||
export interface User {
|
export interface User {
|
||||||
id: number
|
id: number
|
||||||
userName: string
|
userName?: string
|
||||||
email: string
|
email?: string
|
||||||
realName?: string
|
realName?: string
|
||||||
tenantId?: string
|
phone?: string
|
||||||
|
tenantId: number
|
||||||
|
tenantName: string
|
||||||
roles: string[]
|
roles: string[]
|
||||||
|
emailConfirmed: boolean
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
createdAt: string
|
createdAt: string
|
||||||
}
|
}
|
||||||
@ -54,17 +66,21 @@ export namespace FenglingApi {
|
|||||||
export interface CreateUserDto {
|
export interface CreateUserDto {
|
||||||
userName: string
|
userName: string
|
||||||
email: string
|
email: string
|
||||||
realName?: string
|
realName: string
|
||||||
password: string
|
password: string
|
||||||
tenantId?: string
|
phone?: string
|
||||||
|
tenantId?: number
|
||||||
roleIds: number[]
|
roleIds: number[]
|
||||||
|
emailConfirmed?: boolean
|
||||||
|
isActive?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateUserDto {
|
export interface UpdateUserDto {
|
||||||
email?: string
|
email: string
|
||||||
realName?: string
|
realName: string
|
||||||
|
phone?: string
|
||||||
|
emailConfirmed?: boolean
|
||||||
isActive?: boolean
|
isActive?: boolean
|
||||||
roleIds?: number[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResetPasswordDto {
|
export interface ResetPasswordDto {
|
||||||
@ -75,10 +91,13 @@ export namespace FenglingApi {
|
|||||||
export namespace Role {
|
export namespace Role {
|
||||||
export interface Role {
|
export interface Role {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name?: string
|
||||||
displayName: string
|
displayName?: string
|
||||||
description?: string
|
description?: string
|
||||||
permissions: string[]
|
tenantId?: number
|
||||||
|
isSystem: boolean
|
||||||
|
permissions?: string[]
|
||||||
|
userCount: number
|
||||||
createdAt: string
|
createdAt: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,56 +105,55 @@ export namespace FenglingApi {
|
|||||||
name: string
|
name: string
|
||||||
displayName: string
|
displayName: string
|
||||||
description?: string
|
description?: string
|
||||||
|
tenantId?: number
|
||||||
permissions: string[]
|
permissions: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateRoleDto {
|
export interface UpdateRoleDto {
|
||||||
displayName?: string
|
displayName: string
|
||||||
description?: string
|
description?: string
|
||||||
permissions?: string[]
|
permissions: string[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace OAuth {
|
export namespace OAuth {
|
||||||
export interface OAuthClient {
|
export interface OAuthClient {
|
||||||
id: number
|
id: string
|
||||||
clientId: string
|
clientId: string
|
||||||
displayName: string
|
displayName: string
|
||||||
redirectUris: string[]
|
redirectUris: string[]
|
||||||
postLogoutRedirectUris: string[]
|
postLogoutRedirectUris: string[]
|
||||||
scopes: string[]
|
scopes: string[]
|
||||||
grantTypes: string[]
|
grantTypes: string[]
|
||||||
clientType: 'confidential' | 'public'
|
clientType?: string
|
||||||
consentType: 'explicit' | 'implicit' | 'external'
|
consentType?: string
|
||||||
status: 'active' | 'inactive'
|
status: string
|
||||||
description?: string
|
description?: string
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateOAuthClientDto {
|
export interface CreateOAuthClientDto {
|
||||||
clientId: string
|
clientId: string
|
||||||
displayName: string
|
|
||||||
clientSecret?: string
|
clientSecret?: string
|
||||||
redirectUris: string[]
|
displayName: string
|
||||||
postLogoutRedirectUris: string[]
|
redirectUris?: string[]
|
||||||
scopes: string[]
|
postLogoutRedirectUris?: string[]
|
||||||
grantTypes: string[]
|
scopes?: string[]
|
||||||
clientType?: 'confidential' | 'public'
|
grantTypes?: string[]
|
||||||
consentType?: 'explicit' | 'implicit' | 'external'
|
clientType?: string
|
||||||
status?: 'active' | 'inactive'
|
consentType?: string
|
||||||
|
status?: string
|
||||||
description?: string
|
description?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateOAuthClientDto {
|
export interface UpdateOAuthClientDto {
|
||||||
displayName: string
|
displayName?: string
|
||||||
redirectUris: string[]
|
redirectUris?: string[]
|
||||||
postLogoutRedirectUris: string[]
|
postLogoutRedirectUris?: string[]
|
||||||
scopes: string[]
|
scopes?: string[]
|
||||||
grantTypes: string[]
|
grantTypes?: string[]
|
||||||
clientType: 'confidential' | 'public'
|
clientType?: string
|
||||||
consentType: 'explicit' | 'implicit' | 'external'
|
consentType?: string
|
||||||
status: 'active' | 'inactive'
|
status?: string
|
||||||
description?: string
|
description?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,9 @@ import type { FenglingApi } from './typings';
|
|||||||
import { requestClient } from '#/api/request';
|
import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
export namespace UserApi {
|
export namespace UserApi {
|
||||||
|
|
||||||
|
const apiPrefix = '/console';
|
||||||
|
|
||||||
export async function getUserList(params: {
|
export async function getUserList(params: {
|
||||||
page?: number
|
page?: number
|
||||||
pageSize?: number
|
pageSize?: number
|
||||||
@ -11,28 +14,28 @@ export namespace UserApi {
|
|||||||
isActive?: boolean
|
isActive?: boolean
|
||||||
}) {
|
}) {
|
||||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.User.User>>(
|
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.User.User>>(
|
||||||
'/users',
|
`${apiPrefix}/users`,
|
||||||
{ params }
|
{ params }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserById(id: number) {
|
export async function getUserById(id: number) {
|
||||||
return requestClient.get<FenglingApi.User.User>(`/users/${id}`);
|
return requestClient.get<FenglingApi.User.User>(`${apiPrefix}/users/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createUser(data: FenglingApi.User.CreateUserDto) {
|
export async function createUser(data: FenglingApi.User.CreateUserDto) {
|
||||||
return requestClient.post<FenglingApi.User.User>('/users', data);
|
return requestClient.post<FenglingApi.User.User, FenglingApi.User.CreateUserDto>(`${apiPrefix}/users`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateUser(id: number, data: FenglingApi.User.UpdateUserDto) {
|
export async function updateUser(id: number, data: FenglingApi.User.UpdateUserDto) {
|
||||||
return requestClient.put<FenglingApi.User.User>(`/users/${id}`, data);
|
return requestClient.put<void, FenglingApi.User.UpdateUserDto>(`${apiPrefix}/users/${id}`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteUser(id: number) {
|
export async function deleteUser(id: number) {
|
||||||
return requestClient.delete(`/users/${id}`);
|
return requestClient.delete<void>(`${apiPrefix}/users/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resetUserPassword(id: number, data: FenglingApi.User.ResetPasswordDto) {
|
export async function resetUserPassword(id: number, data: FenglingApi.User.ResetPasswordDto) {
|
||||||
return requestClient.post(`/users/${id}/reset-password`, data);
|
return requestClient.post<void, FenglingApi.User.ResetPasswordDto>(`${apiPrefix}/users/${id}/reset-password`, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,13 +78,19 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 处理返回的响应数据格式
|
// 处理返回的响应数据格式
|
||||||
client.addResponseInterceptor(
|
// NOTE: 后端直接返回数据,如 {items: [...], totalCount: 1}
|
||||||
defaultResponseInterceptor({
|
// 不使用 {code, data} 包装格式,所以禁用 defaultResponseInterceptor
|
||||||
codeField: 'code',
|
// 添加自定义响应拦截器,直接返回 response.data
|
||||||
dataField: 'data',
|
client.addResponseInterceptor({
|
||||||
successCode: 0,
|
fulfilled: (response) => {
|
||||||
}),
|
console.log('[Response] Success:', response.config?.method?.toUpperCase(), response.config?.url, response.data);
|
||||||
);
|
return response.data;
|
||||||
|
},
|
||||||
|
rejected: (error) => {
|
||||||
|
console.error('[Response] Error:', error.config?.method?.toUpperCase(), error.config?.url, error.response?.data || error.message);
|
||||||
|
return Promise.reject(error);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// token过期的处理
|
// token过期的处理
|
||||||
client.addResponseInterceptor(
|
client.addResponseInterceptor(
|
||||||
@ -113,7 +119,11 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const requestClient = createRequestClient(apiURL, {
|
export const requestClient = createRequestClient(apiURL, {
|
||||||
responseReturn: 'data',
|
// responseReturn: 'data', // 后端直接返回数据,不需要从 data 字段提取
|
||||||
});
|
});
|
||||||
|
|
||||||
export const baseRequestClient = new RequestClient({ baseURL: apiURL });
|
export const baseRequestClient = new RequestClient({ baseURL: apiURL });
|
||||||
|
|
||||||
|
// 认证服务客户端 - 直接连接到OIDC服务器
|
||||||
|
const authServerURL = import.meta.env.VITE_AUTH_SERVER_URL || 'http://localhost:5132';
|
||||||
|
export const authRequestClient = new RequestClient({ baseURL: authServerURL });
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
{
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "Fengling Management Platform",
|
||||||
|
"title": "Fengling Console"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
@ -11,5 +15,148 @@
|
|||||||
"title": "Dashboard",
|
"title": "Dashboard",
|
||||||
"analytics": "Analytics",
|
"analytics": "Analytics",
|
||||||
"workspace": "Workspace"
|
"workspace": "Workspace"
|
||||||
|
},
|
||||||
|
"tenant": {
|
||||||
|
"title": "Tenant Management",
|
||||||
|
"id": "ID",
|
||||||
|
"tenantId": "Tenant ID",
|
||||||
|
"name": "Tenant Name",
|
||||||
|
"contactName": "Contact Name",
|
||||||
|
"contactEmail": "Contact Email",
|
||||||
|
"contactPhone": "Contact Phone",
|
||||||
|
"maxUsers": "Max Users",
|
||||||
|
"userCount": "User Count",
|
||||||
|
"status": "Status",
|
||||||
|
"expiresAt": "Expires At",
|
||||||
|
"createdAt": "Created At",
|
||||||
|
"description": "Description",
|
||||||
|
"actions": "Actions",
|
||||||
|
"search": "Search Tenants",
|
||||||
|
"searchPlaceholder": "Search by name",
|
||||||
|
"create": "Create Tenant",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirmDelete": "Are you sure to delete this tenant?",
|
||||||
|
"statusActive": "Active",
|
||||||
|
"statusInactive": "Inactive",
|
||||||
|
"statusExpired": "Expired",
|
||||||
|
"created": "Tenant created successfully",
|
||||||
|
"updated": "Tenant updated successfully",
|
||||||
|
"deleted": "Tenant deleted successfully",
|
||||||
|
"loadFailed": "Failed to load tenants",
|
||||||
|
"saveFailed": "Failed to save tenant",
|
||||||
|
"deleteFailed": "Failed to delete tenant"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"title": "User Management",
|
||||||
|
"id": "ID",
|
||||||
|
"userName": "Username",
|
||||||
|
"email": "Email",
|
||||||
|
"realName": "Real Name",
|
||||||
|
"phone": "Phone",
|
||||||
|
"tenant": "Tenant",
|
||||||
|
"roles": "Roles",
|
||||||
|
"isActive": "Status",
|
||||||
|
"emailConfirmed": "Email Confirmed",
|
||||||
|
"createdAt": "Created At",
|
||||||
|
"actions": "Actions",
|
||||||
|
"search": "Search Users",
|
||||||
|
"searchPlaceholder": "Search by username or email",
|
||||||
|
"create": "Create User",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"resetPassword": "Reset Password",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirmDelete": "Are you sure to delete this user?",
|
||||||
|
"active": "Active",
|
||||||
|
"inactive": "Inactive",
|
||||||
|
"created": "User created successfully",
|
||||||
|
"updated": "User updated successfully",
|
||||||
|
"deleted": "User deleted successfully",
|
||||||
|
"passwordReset": "Password reset successfully",
|
||||||
|
"loadFailed": "Failed to load users",
|
||||||
|
"saveFailed": "Failed to save user",
|
||||||
|
"deleteFailed": "Failed to delete user"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"title": "Role Management",
|
||||||
|
"id": "ID",
|
||||||
|
"name": "Role Name",
|
||||||
|
"displayName": "Display Name",
|
||||||
|
"description": "Description",
|
||||||
|
"tenant": "Tenant",
|
||||||
|
"isSystem": "System Role",
|
||||||
|
"permissions": "Permissions",
|
||||||
|
"userCount": "User Count",
|
||||||
|
"createdAt": "Created At",
|
||||||
|
"actions": "Actions",
|
||||||
|
"search": "Search Roles",
|
||||||
|
"searchPlaceholder": "Search by role name",
|
||||||
|
"create": "Create Role",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirmDelete": "Are you sure to delete this role?",
|
||||||
|
"systemRole": "System Role",
|
||||||
|
"created": "Role created successfully",
|
||||||
|
"updated": "Role updated successfully",
|
||||||
|
"deleted": "Role deleted successfully",
|
||||||
|
"loadFailed": "Failed to load roles",
|
||||||
|
"saveFailed": "Failed to save role",
|
||||||
|
"deleteFailed": "Failed to delete role"
|
||||||
|
},
|
||||||
|
"oauth": {
|
||||||
|
"title": "OAuth Client Management",
|
||||||
|
"id": "ID",
|
||||||
|
"clientId": "Client ID",
|
||||||
|
"displayName": "Display Name",
|
||||||
|
"description": "Description",
|
||||||
|
"redirectUris": "Redirect URIs",
|
||||||
|
"postLogoutRedirectUris": "Post Logout Redirect URIs",
|
||||||
|
"scopes": "Scopes",
|
||||||
|
"grantTypes": "Grant Types",
|
||||||
|
"clientType": "Client Type",
|
||||||
|
"consentType": "Consent Type",
|
||||||
|
"status": "Status",
|
||||||
|
"actions": "Actions",
|
||||||
|
"search": "Search Clients",
|
||||||
|
"searchPlaceholder": "Search by client ID or name",
|
||||||
|
"create": "Create Client",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"resetSecret": "Reset Secret",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirmDelete": "Are you sure to delete this client?",
|
||||||
|
"confirmResetSecret": "Are you sure to reset client secret?",
|
||||||
|
"secretReset": "Client secret reset successfully",
|
||||||
|
"active": "Active",
|
||||||
|
"inactive": "Inactive",
|
||||||
|
"created": "Client created successfully",
|
||||||
|
"updated": "Client updated successfully",
|
||||||
|
"deleted": "Client deleted successfully",
|
||||||
|
"loadFailed": "Failed to load clients",
|
||||||
|
"saveFailed": "Failed to save client",
|
||||||
|
"deleteFailed": "Failed to delete client"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"total": "Total {count} items",
|
||||||
|
"page": "Page {page}",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"noData": "No data",
|
||||||
|
"search": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"pleaseInput": "Please input",
|
||||||
|
"pleaseSelect": "Please select",
|
||||||
|
"required": "This field is required",
|
||||||
|
"success": "Operation successful",
|
||||||
|
"error": "Operation failed",
|
||||||
|
"warning": "Warning",
|
||||||
|
"info": "Information"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
{
|
{
|
||||||
|
"app": {
|
||||||
|
"name": "蜂铃管理平台",
|
||||||
|
"title": "蜂铃控制台"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": "登录",
|
"login": "登录",
|
||||||
"register": "注册",
|
"register": "注册",
|
||||||
@ -11,5 +15,148 @@
|
|||||||
"title": "概览",
|
"title": "概览",
|
||||||
"analytics": "分析页",
|
"analytics": "分析页",
|
||||||
"workspace": "工作台"
|
"workspace": "工作台"
|
||||||
|
},
|
||||||
|
"tenant": {
|
||||||
|
"title": "租户管理",
|
||||||
|
"id": "ID",
|
||||||
|
"tenantId": "租户ID",
|
||||||
|
"name": "租户名称",
|
||||||
|
"contactName": "联系人",
|
||||||
|
"contactEmail": "联系邮箱",
|
||||||
|
"contactPhone": "联系电话",
|
||||||
|
"maxUsers": "最大用户数",
|
||||||
|
"userCount": "用户数",
|
||||||
|
"status": "状态",
|
||||||
|
"expiresAt": "过期时间",
|
||||||
|
"createdAt": "创建时间",
|
||||||
|
"description": "描述",
|
||||||
|
"actions": "操作",
|
||||||
|
"search": "搜索租户",
|
||||||
|
"searchPlaceholder": "按名称搜索",
|
||||||
|
"create": "新建租户",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirmDelete": "确定要删除这个租户吗?",
|
||||||
|
"statusActive": "激活",
|
||||||
|
"statusInactive": "未激活",
|
||||||
|
"statusExpired": "已过期",
|
||||||
|
"created": "租户创建成功",
|
||||||
|
"updated": "租户更新成功",
|
||||||
|
"deleted": "租户删除成功",
|
||||||
|
"loadFailed": "加载租户失败",
|
||||||
|
"saveFailed": "保存租户失败",
|
||||||
|
"deleteFailed": "删除租户失败"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"title": "用户管理",
|
||||||
|
"id": "ID",
|
||||||
|
"userName": "用户名",
|
||||||
|
"email": "邮箱",
|
||||||
|
"realName": "真实姓名",
|
||||||
|
"phone": "手机号",
|
||||||
|
"tenant": "租户",
|
||||||
|
"roles": "角色",
|
||||||
|
"isActive": "状态",
|
||||||
|
"emailConfirmed": "邮箱已验证",
|
||||||
|
"createdAt": "创建时间",
|
||||||
|
"actions": "操作",
|
||||||
|
"search": "搜索用户",
|
||||||
|
"searchPlaceholder": "按用户名或邮箱搜索",
|
||||||
|
"create": "新建用户",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"resetPassword": "重置密码",
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirmDelete": "确定要删除这个用户吗?",
|
||||||
|
"active": "激活",
|
||||||
|
"inactive": "未激活",
|
||||||
|
"created": "用户创建成功",
|
||||||
|
"updated": "用户更新成功",
|
||||||
|
"deleted": "用户删除成功",
|
||||||
|
"passwordReset": "密码重置成功",
|
||||||
|
"loadFailed": "加载用户失败",
|
||||||
|
"saveFailed": "保存用户失败",
|
||||||
|
"deleteFailed": "删除用户失败"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"title": "角色管理",
|
||||||
|
"id": "ID",
|
||||||
|
"name": "角色名称",
|
||||||
|
"displayName": "显示名称",
|
||||||
|
"description": "描述",
|
||||||
|
"tenant": "租户",
|
||||||
|
"isSystem": "系统角色",
|
||||||
|
"permissions": "权限",
|
||||||
|
"userCount": "用户数",
|
||||||
|
"createdAt": "创建时间",
|
||||||
|
"actions": "操作",
|
||||||
|
"search": "搜索角色",
|
||||||
|
"searchPlaceholder": "按角色名称搜索",
|
||||||
|
"create": "新建角色",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirmDelete": "确定要删除这个角色吗?",
|
||||||
|
"systemRole": "系统角色",
|
||||||
|
"created": "角色创建成功",
|
||||||
|
"updated": "角色更新成功",
|
||||||
|
"deleted": "角色删除成功",
|
||||||
|
"loadFailed": "加载角色失败",
|
||||||
|
"saveFailed": "保存角色失败",
|
||||||
|
"deleteFailed": "删除角色失败"
|
||||||
|
},
|
||||||
|
"oauth": {
|
||||||
|
"title": "OAuth客户端管理",
|
||||||
|
"id": "ID",
|
||||||
|
"clientId": "客户端ID",
|
||||||
|
"displayName": "显示名称",
|
||||||
|
"description": "描述",
|
||||||
|
"redirectUris": "回调地址",
|
||||||
|
"postLogoutRedirectUris": "登出回调地址",
|
||||||
|
"scopes": "授权范围",
|
||||||
|
"grantTypes": "授权类型",
|
||||||
|
"clientType": "客户端类型",
|
||||||
|
"consentType": "同意类型",
|
||||||
|
"status": "状态",
|
||||||
|
"actions": "操作",
|
||||||
|
"search": "搜索客户端",
|
||||||
|
"searchPlaceholder": "按客户端ID或名称搜索",
|
||||||
|
"create": "新建客户端",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"resetSecret": "重置密钥",
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirmDelete": "确定要删除这个客户端吗?",
|
||||||
|
"confirmResetSecret": "确定要重置客户端密钥吗?",
|
||||||
|
"secretReset": "密钥重置成功",
|
||||||
|
"active": "激活",
|
||||||
|
"inactive": "未激活",
|
||||||
|
"created": "客户端创建成功",
|
||||||
|
"updated": "客户端更新成功",
|
||||||
|
"deleted": "客户端删除成功",
|
||||||
|
"loadFailed": "加载客户端失败",
|
||||||
|
"saveFailed": "保存客户端失败",
|
||||||
|
"deleteFailed": "删除客户端失败"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"total": "共 {count} 条",
|
||||||
|
"page": "第 {page} 页",
|
||||||
|
"loading": "加载中...",
|
||||||
|
"noData": "暂无数据",
|
||||||
|
"search": "搜索",
|
||||||
|
"reset": "重置",
|
||||||
|
"confirm": "确认",
|
||||||
|
"pleaseInput": "请输入",
|
||||||
|
"pleaseSelect": "请选择",
|
||||||
|
"required": "此项必填",
|
||||||
|
"success": "操作成功",
|
||||||
|
"error": "操作失败",
|
||||||
|
"warning": "警告",
|
||||||
|
"info": "信息"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
ElTag,
|
ElTag,
|
||||||
ElMessage,
|
ElMessage,
|
||||||
ElPopconfirm,
|
ElPopconfirm,
|
||||||
|
ElPagination,
|
||||||
} from 'element-plus';
|
} from 'element-plus';
|
||||||
|
|
||||||
import { TenantApi, type FenglingApi } from '#/api/fengling';
|
import { TenantApi, type FenglingApi } from '#/api/fengling';
|
||||||
@ -24,9 +25,10 @@ const loading = ref(false);
|
|||||||
const tableData = ref<FenglingApi.Tenant.Tenant[]>([]);
|
const tableData = ref<FenglingApi.Tenant.Tenant[]>([]);
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
const dialogTitle = ref('Create Tenant');
|
const dialogTitle = ref('Create Tenant');
|
||||||
const formData = ref<Partial<FenglingApi.Tenant.CreateTenantDto>>({});
|
const formData = ref<Partial<FenglingApi.Tenant.CreateTenantDto | FenglingApi.Tenant.UpdateTenantDto>>({});
|
||||||
const searchKeyword = ref('');
|
const searchKeyword = ref('');
|
||||||
const searchStatus = ref('');
|
const searchStatus = ref('');
|
||||||
|
const editingId = ref<number | null>(null);
|
||||||
|
|
||||||
const pagination = ref({
|
const pagination = ref({
|
||||||
page: 1,
|
page: 1,
|
||||||
@ -40,13 +42,16 @@ const loadTenants = async () => {
|
|||||||
const response = await TenantApi.getTenantList({
|
const response = await TenantApi.getTenantList({
|
||||||
page: pagination.value.page,
|
page: pagination.value.page,
|
||||||
pageSize: pagination.value.pageSize,
|
pageSize: pagination.value.pageSize,
|
||||||
keyword: searchKeyword.value || undefined,
|
name: searchKeyword.value || undefined,
|
||||||
status: searchStatus.value || undefined,
|
status: searchStatus.value || undefined,
|
||||||
});
|
});
|
||||||
tableData.value = response.items;
|
console.log('[Tenant] Response:', response);
|
||||||
pagination.value.total = response.totalCount;
|
console.log('[Tenant] Items:', response.items);
|
||||||
} catch (error) {
|
tableData.value = response.items || [];
|
||||||
ElMessage.error('Failed to load tenants');
|
pagination.value.total = response.totalCount || 0;
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('[Tenant] Error loading tenants:', error);
|
||||||
|
ElMessage.error(error?.response?.data?.message || 'Failed to load tenants');
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
@ -54,6 +59,7 @@ const loadTenants = async () => {
|
|||||||
|
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
dialogTitle.value = 'Create Tenant';
|
dialogTitle.value = 'Create Tenant';
|
||||||
|
editingId.value = null;
|
||||||
formData.value = {
|
formData.value = {
|
||||||
status: 'active',
|
status: 'active',
|
||||||
};
|
};
|
||||||
@ -62,6 +68,7 @@ const handleCreate = () => {
|
|||||||
|
|
||||||
const handleEdit = (row: FenglingApi.Tenant.Tenant) => {
|
const handleEdit = (row: FenglingApi.Tenant.Tenant) => {
|
||||||
dialogTitle.value = 'Edit Tenant';
|
dialogTitle.value = 'Edit Tenant';
|
||||||
|
editingId.value = row.id;
|
||||||
formData.value = {
|
formData.value = {
|
||||||
name: row.name,
|
name: row.name,
|
||||||
contactName: row.contactName,
|
contactName: row.contactName,
|
||||||
@ -69,7 +76,7 @@ const handleEdit = (row: FenglingApi.Tenant.Tenant) => {
|
|||||||
contactPhone: row.contactPhone,
|
contactPhone: row.contactPhone,
|
||||||
maxUsers: row.maxUsers,
|
maxUsers: row.maxUsers,
|
||||||
expiresAt: row.expiresAt,
|
expiresAt: row.expiresAt,
|
||||||
status: row.status === 'expired' ? 'inactive' : row.status,
|
status: row.status,
|
||||||
description: row.description,
|
description: row.description,
|
||||||
};
|
};
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
@ -91,13 +98,19 @@ const handleSave = async () => {
|
|||||||
await TenantApi.createTenant(formData.value as FenglingApi.Tenant.CreateTenantDto);
|
await TenantApi.createTenant(formData.value as FenglingApi.Tenant.CreateTenantDto);
|
||||||
ElMessage.success('Tenant created successfully');
|
ElMessage.success('Tenant created successfully');
|
||||||
} else {
|
} else {
|
||||||
await TenantApi.updateTenant(tableData.value[0].id, formData.value as FenglingApi.Tenant.UpdateTenantDto);
|
if (!editingId.value) {
|
||||||
|
ElMessage.error('Tenant ID is missing');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await TenantApi.updateTenant(editingId.value, formData.value as FenglingApi.Tenant.UpdateTenantDto);
|
||||||
ElMessage.success('Tenant updated successfully');
|
ElMessage.success('Tenant updated successfully');
|
||||||
}
|
}
|
||||||
dialogVisible.value = false;
|
dialogVisible.value = false;
|
||||||
|
editingId.value = null;
|
||||||
loadTenants();
|
loadTenants();
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
ElMessage.error('Failed to save tenant');
|
console.error('[Tenant] Save error:', error);
|
||||||
|
ElMessage.error(error?.message || 'Failed to save tenant');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
ElMessage,
|
ElMessage,
|
||||||
ElPopconfirm,
|
ElPopconfirm,
|
||||||
ElSwitch,
|
ElSwitch,
|
||||||
|
ElPagination,
|
||||||
} from 'element-plus';
|
} from 'element-plus';
|
||||||
|
|
||||||
import { UserApi, type FenglingApi } from '#/api/fengling';
|
import { UserApi, type FenglingApi } from '#/api/fengling';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user