diff --git a/apps/web-ele/.env.development b/apps/web-ele/.env.development index 95c8d24..ff15679 100644 --- a/apps/web-ele/.env.development +++ b/apps/web-ele/.env.development @@ -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 diff --git a/apps/web-ele/src/api/core/auth.ts b/apps/web-ele/src/api/core/auth.ts index fc3cecc..378efc7 100644 --- a/apps/web-ele/src/api/core/auth.ts +++ b/apps/web-ele/src/api/core/auth.ts @@ -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 { try { - return await baseRequestClient.get('/connect/userinfo', { + return await authRequestClient.get('/connect/userinfo', { withCredentials: true, }); } catch (error: any) { @@ -73,7 +73,7 @@ export async function getUserInfoApi(): Promise { */ export async function logoutApi() { try { - await baseRequestClient.post('/connect/logout', { + await authRequestClient.post('/connect/logout', { withCredentials: true, }); } catch (error) { diff --git a/apps/web-ele/src/api/fengling/log.ts b/apps/web-ele/src/api/fengling/log.ts index a81ae82..3da4b44 100644 --- a/apps/web-ele/src/api/fengling/log.ts +++ b/apps/web-ele/src/api/fengling/log.ts @@ -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>( - '/logs/audit', + `${apiPrefix}/logs/audit`, { params } ); } @@ -28,7 +30,7 @@ export namespace LogApi { endDate?: string }) { return requestClient.get>( - '/logs/access', + `${apiPrefix}/logs/access`, { params } ); } diff --git a/apps/web-ele/src/api/fengling/oauth.ts b/apps/web-ele/src/api/fengling/oauth.ts index 4b694b5..38cf465 100644 --- a/apps/web-ele/src/api/fengling/oauth.ts +++ b/apps/web-ele/src/api/fengling/oauth.ts @@ -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>( - `/oauth/clients?${queryParams.toString()}`, + `${apiPrefix}/oauth/clients?${queryParams.toString()}`, ); } @@ -24,7 +26,7 @@ export namespace OAuthApi { * 获取OAuth客户端详情 */ export async function getClient(id: number): Promise { - return await baseRequestClient.get(`/oauth/clients/${id}`); + return await baseRequestClient.get(`${apiPrefix}/oauth/clients/${id}`); } /** @@ -33,7 +35,7 @@ export namespace OAuthApi { export async function createClient( data: FenglingApi.OAuth.CreateOAuthClientDto, ): Promise { - return await baseRequestClient.post('/oauth/clients', data); + return await baseRequestClient.post(`${apiPrefix}/oauth/clients`, data); } /** @@ -43,27 +45,27 @@ export namespace OAuthApi { id: number, data: FenglingApi.OAuth.UpdateOAuthClientDto, ): Promise { - return await baseRequestClient.put(`/oauth/clients/${id}`, data); + return await baseRequestClient.put(`${apiPrefix}/oauth/clients/${id}`, data); } /** * 删除OAuth客户端 */ export async function deleteClient(id: number): Promise { - await baseRequestClient.delete(`/oauth/clients/${id}`); + await baseRequestClient.delete(`${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 { - await baseRequestClient.put(`/oauth/clients/${id}/status`, { status }); + await baseRequestClient.put(`${apiPrefix}/oauth/clients/${id}/status`, { status }); } } diff --git a/apps/web-ele/src/api/fengling/role.ts b/apps/web-ele/src/api/fengling/role.ts index e834b7a..32d9faf 100644 --- a/apps/web-ele/src/api/fengling/role.ts +++ b/apps/web-ele/src/api/fengling/role.ts @@ -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>( - '/roles', + `${apiPrefix}/roles`, { params } ); } export async function getRoleById(id: number) { - return requestClient.get(`/roles/${id}`); + return requestClient.get(`${apiPrefix}/roles/${id}`); } export async function createRole(data: FenglingApi.Role.CreateRoleDto) { - return requestClient.post('/roles', data); + return requestClient.post(`${apiPrefix}/roles`, data); } export async function updateRole(id: number, data: FenglingApi.Role.UpdateRoleDto) { - return requestClient.put(`/roles/${id}`, data); + return requestClient.put(`${apiPrefix}/roles/${id}`, data); } export async function deleteRole(id: number) { - return requestClient.delete(`/roles/${id}`); + return requestClient.delete(`${apiPrefix}/roles/${id}`); } export async function getAllRoles() { - return requestClient.get('/roles/all'); + return requestClient.get(`${apiPrefix}/roles/all`); } } diff --git a/apps/web-ele/src/api/fengling/tenant.ts b/apps/web-ele/src/api/fengling/tenant.ts index 82d2931..18d09e6 100644 --- a/apps/web-ele/src/api/fengling/tenant.ts +++ b/apps/web-ele/src/api/fengling/tenant.ts @@ -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>( - '/tenants', + `${apiPrefix}/tenants`, { params } ); } export async function getTenantById(id: number) { - return requestClient.get(`/tenants/${id}`); + return requestClient.get(`${apiPrefix}/tenants/${id}`); } export async function createTenant(data: FenglingApi.Tenant.CreateTenantDto) { - return requestClient.post('/tenants', data); + return requestClient.post(`${apiPrefix}/tenants`, data); } export async function updateTenant(id: number, data: FenglingApi.Tenant.UpdateTenantDto) { - return requestClient.put(`/tenants/${id}`, data); + return requestClient.put(`${apiPrefix}/tenants/${id}`, data); } export async function deleteTenant(id: number) { - return requestClient.delete(`/tenants/${id}`); + return requestClient.delete(`${apiPrefix}/tenants/${id}`); } export async function activateTenant(id: number) { - return requestClient.post(`/tenants/${id}/activate`); + return requestClient.post(`${apiPrefix}/tenants/${id}/activate`); } export async function deactivateTenant(id: number) { - return requestClient.post(`/tenants/${id}/deactivate`); + return requestClient.post(`${apiPrefix}/tenants/${id}/deactivate`); } export async function extendTenantExpiry(id: number, expiresAt: string) { - return requestClient.post(`/tenants/${id}/extend`, { expiresAt }); + return requestClient.post(`${apiPrefix}/tenants/${id}/extend`, { expiresAt }); } export async function getTenantUsers(id: number) { return requestClient.get>( - `/tenants/${id}/users` + `${apiPrefix}/tenants/${id}/users` + ); + } + + export async function getTenantRoles(id: number) { + return requestClient.get>( + `${apiPrefix}/tenants/${id}/roles` ); } export async function getTenantStatistics(id: number) { - return requestClient.get(`/tenants/${id}/statistics`); + return requestClient.get>(`${apiPrefix}/tenants/${id}/statistics`); + } + + export async function getTenantSettings(id: number) { + return requestClient.get( + `${apiPrefix}/tenants/${id}/settings` + ); + } + + export async function updateTenantSettings(id: number, data: FenglingApi.Tenant.TenantSettings) { + return requestClient.put(`${apiPrefix}/tenants/${id}/settings`, data); } } diff --git a/apps/web-ele/src/api/fengling/typings.ts b/apps/web-ele/src/api/fengling/typings.ts index af83075..d70b961 100644 --- a/apps/web-ele/src/api/fengling/typings.ts +++ b/apps/web-ele/src/api/fengling/typings.ts @@ -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 } } diff --git a/apps/web-ele/src/api/fengling/user.ts b/apps/web-ele/src/api/fengling/user.ts index 3bb7643..ca80d13 100644 --- a/apps/web-ele/src/api/fengling/user.ts +++ b/apps/web-ele/src/api/fengling/user.ts @@ -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>( - '/users', + `${apiPrefix}/users`, { params } ); } export async function getUserById(id: number) { - return requestClient.get(`/users/${id}`); + return requestClient.get(`${apiPrefix}/users/${id}`); } export async function createUser(data: FenglingApi.User.CreateUserDto) { - return requestClient.post('/users', data); + return requestClient.post(`${apiPrefix}/users`, data); } export async function updateUser(id: number, data: FenglingApi.User.UpdateUserDto) { - return requestClient.put(`/users/${id}`, data); + return requestClient.put(`${apiPrefix}/users/${id}`, data); } export async function deleteUser(id: number) { - return requestClient.delete(`/users/${id}`); + return requestClient.delete(`${apiPrefix}/users/${id}`); } export async function resetUserPassword(id: number, data: FenglingApi.User.ResetPasswordDto) { - return requestClient.post(`/users/${id}/reset-password`, data); + return requestClient.post(`${apiPrefix}/users/${id}/reset-password`, data); } } diff --git a/apps/web-ele/src/api/request.ts b/apps/web-ele/src/api/request.ts index fd60118..822d9c3 100644 --- a/apps/web-ele/src/api/request.ts +++ b/apps/web-ele/src/api/request.ts @@ -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 }); diff --git a/apps/web-ele/src/locales/langs/en-US/page.json b/apps/web-ele/src/locales/langs/en-US/page.json index 39f1641..bfcd5c0 100644 --- a/apps/web-ele/src/locales/langs/en-US/page.json +++ b/apps/web-ele/src/locales/langs/en-US/page.json @@ -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" } } diff --git a/apps/web-ele/src/locales/langs/zh-CN/page.json b/apps/web-ele/src/locales/langs/zh-CN/page.json index 2192d1d..2ea9a27 100644 --- a/apps/web-ele/src/locales/langs/zh-CN/page.json +++ b/apps/web-ele/src/locales/langs/zh-CN/page.json @@ -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": "信息" } } diff --git a/apps/web-ele/src/views/fengling/tenants/index.vue b/apps/web-ele/src/views/fengling/tenants/index.vue index c52a8ca..4a29016 100644 --- a/apps/web-ele/src/views/fengling/tenants/index.vue +++ b/apps/web-ele/src/views/fengling/tenants/index.vue @@ -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([]); const dialogVisible = ref(false); const dialogTitle = ref('Create Tenant'); -const formData = ref>({}); +const formData = ref>({}); const searchKeyword = ref(''); const searchStatus = ref(''); +const editingId = ref(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'); } }; diff --git a/apps/web-ele/src/views/fengling/users/index.vue b/apps/web-ele/src/views/fengling/users/index.vue index 5eca1da..6d7f126 100644 --- a/apps/web-ele/src/views/fengling/users/index.vue +++ b/apps/web-ele/src/views/fengling/users/index.vue @@ -13,6 +13,7 @@ import { ElMessage, ElPopconfirm, ElSwitch, + ElPagination, } from 'element-plus'; import { UserApi, type FenglingApi } from '#/api/fengling';