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_OAUTH_CLIENT_ID=fengling-console
|
||||
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 为关闭
|
||||
VITE_NITRO_MOCK=false
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { User } from 'oidc-client-ts';
|
||||
import { baseRequestClient } from '#/api/request';
|
||||
import { authRequestClient, baseRequestClient } from '#/api/request';
|
||||
import { ElNotification } from 'element-plus';
|
||||
|
||||
export namespace AuthApi {
|
||||
@ -51,7 +51,7 @@ export function getUserInfoFromToken(user: AuthApi.OidcUser): AuthApi.UserInfo {
|
||||
*/
|
||||
export async function getUserInfoApi(): Promise<AuthApi.UserInfo> {
|
||||
try {
|
||||
return await baseRequestClient.get<AuthApi.UserInfo>('/connect/userinfo', {
|
||||
return await authRequestClient.get<AuthApi.UserInfo>('/connect/userinfo', {
|
||||
withCredentials: true,
|
||||
});
|
||||
} catch (error: any) {
|
||||
@ -73,7 +73,7 @@ export async function getUserInfoApi(): Promise<AuthApi.UserInfo> {
|
||||
*/
|
||||
export async function logoutApi() {
|
||||
try {
|
||||
await baseRequestClient.post('/connect/logout', {
|
||||
await authRequestClient.post('/connect/logout', {
|
||||
withCredentials: true,
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@ -3,6 +3,8 @@ import type { FenglingApi } from './typings';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace LogApi {
|
||||
const apiPrefix = '/console'
|
||||
|
||||
export async function getAuditLogList(params: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
@ -13,7 +15,7 @@ export namespace LogApi {
|
||||
endDate?: string
|
||||
}) {
|
||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Log.AuditLog>>(
|
||||
'/logs/audit',
|
||||
`${apiPrefix}/logs/audit`,
|
||||
{ params }
|
||||
);
|
||||
}
|
||||
@ -28,7 +30,7 @@ export namespace LogApi {
|
||||
endDate?: string
|
||||
}) {
|
||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Log.AccessLog>>(
|
||||
'/logs/access',
|
||||
`${apiPrefix}/logs/access`,
|
||||
{ params }
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@ import type { FenglingApi } from './typings';
|
||||
import { baseRequestClient } from '#/api/request';
|
||||
|
||||
export namespace OAuthApi {
|
||||
|
||||
const apiPrefix = '/console';
|
||||
/**
|
||||
* 获取OAuth客户端列表
|
||||
*/
|
||||
@ -16,7 +18,7 @@ export namespace OAuthApi {
|
||||
...(params.keyword ? { keyword: params.keyword } : {}),
|
||||
});
|
||||
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客户端详情
|
||||
*/
|
||||
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(
|
||||
data: FenglingApi.OAuth.CreateOAuthClientDto,
|
||||
): 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,
|
||||
data: FenglingApi.OAuth.UpdateOAuthClientDto,
|
||||
): 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客户端
|
||||
*/
|
||||
export async function deleteClient(id: number): Promise<void> {
|
||||
await baseRequestClient.delete(`/oauth/clients/${id}`);
|
||||
await baseRequestClient.delete<void>(`${apiPrefix}/oauth/clients/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置OAuth客户端密钥
|
||||
*/
|
||||
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客户端
|
||||
*/
|
||||
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';
|
||||
|
||||
export namespace RoleApi {
|
||||
const apiPrefix = '/console'
|
||||
export async function getRoleList(params: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
}) {
|
||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Role.Role>>(
|
||||
'/roles',
|
||||
`${apiPrefix}/roles`,
|
||||
{ params }
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
return requestClient.delete(`/roles/${id}`);
|
||||
return requestClient.delete<void>(`${apiPrefix}/roles/${id}`);
|
||||
}
|
||||
|
||||
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';
|
||||
|
||||
export namespace TenantApi {
|
||||
|
||||
const apiPrefix = '/console';
|
||||
export async function getTenantList(params: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
name?: string
|
||||
tenantId?: string
|
||||
status?: string
|
||||
}) {
|
||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.Tenant.Tenant>>(
|
||||
'/tenants',
|
||||
`${apiPrefix}/tenants`,
|
||||
{ params }
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
return requestClient.delete(`/tenants/${id}`);
|
||||
return requestClient.delete<void>(`${apiPrefix}/tenants/${id}`);
|
||||
}
|
||||
|
||||
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) {
|
||||
return requestClient.post(`/tenants/${id}/deactivate`);
|
||||
return requestClient.post<void>(`${apiPrefix}/tenants/${id}/deactivate`);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
contactName: string
|
||||
contactEmail: string
|
||||
contactPhone: string
|
||||
contactPhone?: string
|
||||
maxUsers?: number
|
||||
userCount: number
|
||||
status: 'active' | 'inactive' | 'expired'
|
||||
status: string
|
||||
expiresAt?: string
|
||||
description?: string
|
||||
createdAt: string
|
||||
@ -20,33 +20,45 @@ export namespace FenglingApi {
|
||||
name: string
|
||||
contactName: string
|
||||
contactEmail: string
|
||||
contactPhone: string
|
||||
contactPhone?: string
|
||||
maxUsers?: number
|
||||
expiresAt?: string
|
||||
status: 'active' | 'inactive'
|
||||
status?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface UpdateTenantDto {
|
||||
name?: string
|
||||
contactName?: string
|
||||
contactEmail?: string
|
||||
name: string
|
||||
contactName: string
|
||||
contactEmail: string
|
||||
contactPhone?: string
|
||||
maxUsers?: number
|
||||
expiresAt?: string
|
||||
status?: 'active' | 'inactive'
|
||||
status?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface TenantSettings {
|
||||
allowRegistration: boolean
|
||||
allowedEmailDomains: string
|
||||
defaultRoleId?: number
|
||||
passwordPolicy: string[]
|
||||
minPasswordLength: number
|
||||
sessionTimeout: number
|
||||
}
|
||||
}
|
||||
|
||||
export namespace User {
|
||||
export interface User {
|
||||
id: number
|
||||
userName: string
|
||||
email: string
|
||||
userName?: string
|
||||
email?: string
|
||||
realName?: string
|
||||
tenantId?: string
|
||||
phone?: string
|
||||
tenantId: number
|
||||
tenantName: string
|
||||
roles: string[]
|
||||
emailConfirmed: boolean
|
||||
isActive: boolean
|
||||
createdAt: string
|
||||
}
|
||||
@ -54,17 +66,21 @@ export namespace FenglingApi {
|
||||
export interface CreateUserDto {
|
||||
userName: string
|
||||
email: string
|
||||
realName?: string
|
||||
realName: string
|
||||
password: string
|
||||
tenantId?: string
|
||||
phone?: string
|
||||
tenantId?: number
|
||||
roleIds: number[]
|
||||
emailConfirmed?: boolean
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
export interface UpdateUserDto {
|
||||
email?: string
|
||||
realName?: string
|
||||
email: string
|
||||
realName: string
|
||||
phone?: string
|
||||
emailConfirmed?: boolean
|
||||
isActive?: boolean
|
||||
roleIds?: number[]
|
||||
}
|
||||
|
||||
export interface ResetPasswordDto {
|
||||
@ -75,10 +91,13 @@ export namespace FenglingApi {
|
||||
export namespace Role {
|
||||
export interface Role {
|
||||
id: number
|
||||
name: string
|
||||
displayName: string
|
||||
name?: string
|
||||
displayName?: string
|
||||
description?: string
|
||||
permissions: string[]
|
||||
tenantId?: number
|
||||
isSystem: boolean
|
||||
permissions?: string[]
|
||||
userCount: number
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
@ -86,56 +105,55 @@ export namespace FenglingApi {
|
||||
name: string
|
||||
displayName: string
|
||||
description?: string
|
||||
tenantId?: number
|
||||
permissions: string[]
|
||||
}
|
||||
|
||||
export interface UpdateRoleDto {
|
||||
displayName?: string
|
||||
displayName: string
|
||||
description?: string
|
||||
permissions?: string[]
|
||||
permissions: string[]
|
||||
}
|
||||
}
|
||||
|
||||
export namespace OAuth {
|
||||
export interface OAuthClient {
|
||||
id: number
|
||||
id: string
|
||||
clientId: string
|
||||
displayName: string
|
||||
redirectUris: string[]
|
||||
postLogoutRedirectUris: string[]
|
||||
scopes: string[]
|
||||
grantTypes: string[]
|
||||
clientType: 'confidential' | 'public'
|
||||
consentType: 'explicit' | 'implicit' | 'external'
|
||||
status: 'active' | 'inactive'
|
||||
clientType?: string
|
||||
consentType?: string
|
||||
status: string
|
||||
description?: string
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export interface CreateOAuthClientDto {
|
||||
clientId: string
|
||||
displayName: string
|
||||
clientSecret?: string
|
||||
redirectUris: string[]
|
||||
postLogoutRedirectUris: string[]
|
||||
scopes: string[]
|
||||
grantTypes: string[]
|
||||
clientType?: 'confidential' | 'public'
|
||||
consentType?: 'explicit' | 'implicit' | 'external'
|
||||
status?: 'active' | 'inactive'
|
||||
displayName: string
|
||||
redirectUris?: string[]
|
||||
postLogoutRedirectUris?: string[]
|
||||
scopes?: string[]
|
||||
grantTypes?: string[]
|
||||
clientType?: string
|
||||
consentType?: string
|
||||
status?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface UpdateOAuthClientDto {
|
||||
displayName: string
|
||||
redirectUris: string[]
|
||||
postLogoutRedirectUris: string[]
|
||||
scopes: string[]
|
||||
grantTypes: string[]
|
||||
clientType: 'confidential' | 'public'
|
||||
consentType: 'explicit' | 'implicit' | 'external'
|
||||
status: 'active' | 'inactive'
|
||||
displayName?: string
|
||||
redirectUris?: string[]
|
||||
postLogoutRedirectUris?: string[]
|
||||
scopes?: string[]
|
||||
grantTypes?: string[]
|
||||
clientType?: string
|
||||
consentType?: string
|
||||
status?: string
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,9 @@ import type { FenglingApi } from './typings';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace UserApi {
|
||||
|
||||
const apiPrefix = '/console';
|
||||
|
||||
export async function getUserList(params: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
@ -11,28 +14,28 @@ export namespace UserApi {
|
||||
isActive?: boolean
|
||||
}) {
|
||||
return requestClient.get<FenglingApi.PaginatedResponse<FenglingApi.User.User>>(
|
||||
'/users',
|
||||
`${apiPrefix}/users`,
|
||||
{ params }
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
return requestClient.delete(`/users/${id}`);
|
||||
return requestClient.delete<void>(`${apiPrefix}/users/${id}`);
|
||||
}
|
||||
|
||||
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(
|
||||
defaultResponseInterceptor({
|
||||
codeField: 'code',
|
||||
dataField: 'data',
|
||||
successCode: 0,
|
||||
}),
|
||||
);
|
||||
// NOTE: 后端直接返回数据,如 {items: [...], totalCount: 1}
|
||||
// 不使用 {code, data} 包装格式,所以禁用 defaultResponseInterceptor
|
||||
// 添加自定义响应拦截器,直接返回 response.data
|
||||
client.addResponseInterceptor({
|
||||
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过期的处理
|
||||
client.addResponseInterceptor(
|
||||
@ -113,7 +119,11 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
|
||||
}
|
||||
|
||||
export const requestClient = createRequestClient(apiURL, {
|
||||
responseReturn: 'data',
|
||||
// responseReturn: 'data', // 后端直接返回数据,不需要从 data 字段提取
|
||||
});
|
||||
|
||||
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": {
|
||||
"login": "Login",
|
||||
"register": "Register",
|
||||
@ -11,5 +15,148 @@
|
||||
"title": "Dashboard",
|
||||
"analytics": "Analytics",
|
||||
"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": {
|
||||
"login": "登录",
|
||||
"register": "注册",
|
||||
@ -11,5 +15,148 @@
|
||||
"title": "概览",
|
||||
"analytics": "分析页",
|
||||
"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,
|
||||
ElMessage,
|
||||
ElPopconfirm,
|
||||
ElPagination,
|
||||
} from 'element-plus';
|
||||
|
||||
import { TenantApi, type FenglingApi } from '#/api/fengling';
|
||||
@ -24,9 +25,10 @@ const loading = ref(false);
|
||||
const tableData = ref<FenglingApi.Tenant.Tenant[]>([]);
|
||||
const dialogVisible = ref(false);
|
||||
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 searchStatus = ref('');
|
||||
const editingId = ref<number | null>(null);
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
@ -40,13 +42,16 @@ const loadTenants = async () => {
|
||||
const response = await TenantApi.getTenantList({
|
||||
page: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
keyword: searchKeyword.value || undefined,
|
||||
name: searchKeyword.value || undefined,
|
||||
status: searchStatus.value || undefined,
|
||||
});
|
||||
tableData.value = response.items;
|
||||
pagination.value.total = response.totalCount;
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to load tenants');
|
||||
console.log('[Tenant] Response:', response);
|
||||
console.log('[Tenant] Items:', response.items);
|
||||
tableData.value = response.items || [];
|
||||
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 {
|
||||
loading.value = false;
|
||||
}
|
||||
@ -54,6 +59,7 @@ const loadTenants = async () => {
|
||||
|
||||
const handleCreate = () => {
|
||||
dialogTitle.value = 'Create Tenant';
|
||||
editingId.value = null;
|
||||
formData.value = {
|
||||
status: 'active',
|
||||
};
|
||||
@ -62,6 +68,7 @@ const handleCreate = () => {
|
||||
|
||||
const handleEdit = (row: FenglingApi.Tenant.Tenant) => {
|
||||
dialogTitle.value = 'Edit Tenant';
|
||||
editingId.value = row.id;
|
||||
formData.value = {
|
||||
name: row.name,
|
||||
contactName: row.contactName,
|
||||
@ -69,7 +76,7 @@ const handleEdit = (row: FenglingApi.Tenant.Tenant) => {
|
||||
contactPhone: row.contactPhone,
|
||||
maxUsers: row.maxUsers,
|
||||
expiresAt: row.expiresAt,
|
||||
status: row.status === 'expired' ? 'inactive' : row.status,
|
||||
status: row.status,
|
||||
description: row.description,
|
||||
};
|
||||
dialogVisible.value = true;
|
||||
@ -91,13 +98,19 @@ const handleSave = async () => {
|
||||
await TenantApi.createTenant(formData.value as FenglingApi.Tenant.CreateTenantDto);
|
||||
ElMessage.success('Tenant created successfully');
|
||||
} 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');
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
editingId.value = null;
|
||||
loadTenants();
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to save tenant');
|
||||
} catch (error: any) {
|
||||
console.error('[Tenant] Save error:', error);
|
||||
ElMessage.error(error?.message || 'Failed to save tenant');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
ElMessage,
|
||||
ElPopconfirm,
|
||||
ElSwitch,
|
||||
ElPagination,
|
||||
} from 'element-plus';
|
||||
|
||||
import { UserApi, type FenglingApi } from '#/api/fengling';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user