From 53b948fa48f507f0364829e650f44076581f1861 Mon Sep 17 00:00:00 2001 From: ck_yeun9 Date: Tue, 17 Feb 2026 01:01:27 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=94=B9=E8=BF=9Bapi=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/administratorapi.js | 55 +++-- src/api/administratortypeapi.js | 21 +- src/api/basicapi.js | 53 +++-- src/api/csrfapi.js | 7 +- src/api/customerapi.js | 23 ++- src/api/customerpermissionapi.js | 38 ++-- src/api/customertypeapi.js | 23 ++- src/api/custotypeapi.js | 30 ++- src/api/dashboardapi.js | 27 ++- src/api/departmentapi.js | 11 +- src/api/employeeapi.js | 44 ++-- src/api/employeepermissionapi.js | 38 ++-- src/api/goodsapi.js | 21 +- src/api/hydroelectricityapi.js | 9 +- src/api/internalfinanceapi.js | 23 ++- src/api/menuapi.js | 25 ++- src/api/nationapi.js | 14 +- src/api/noticetypeapi.js | 23 ++- src/api/passportapi.js | 28 ++- src/api/permissionapi.js | 18 +- src/api/positionapi.js | 23 ++- src/api/promotioncontentapi.js | 9 +- src/api/qualificationapi.js | 23 ++- src/api/reserapi.js | 28 ++- src/api/roleapi.js | 58 ++++-- src/api/roomapi.js | 27 ++- src/api/roomstateapi.js | 5 +- src/api/roomtypeapi.js | 23 ++- src/api/spendinfoapi.js | 18 +- src/api/supervisioninfoapi.js | 10 +- src/api/utilityapi.js | 22 +- src/api/vipruleapi.js | 23 ++- src/api/workerfeatureapi.js | 6 +- src/config/apiEndpoints.js | 190 ++++++++++++++++++ src/directives/permission.js | 70 ++++--- src/layouts/MainLayout.vue | 137 ++++++++++++- src/router/index.js | 32 ++- src/utils/auth.js | 1 + src/utils/permission.js | 9 +- src/views/SignInView.vue | 8 + src/views/dashboard/DashboardView.vue | 19 +- src/views/home/HomeView.vue | 20 ++ .../systemmanagement/RoleManagementView.vue | 7 + .../UnifiedAccountPermissionView.vue | 6 + 44 files changed, 1060 insertions(+), 245 deletions(-) create mode 100644 src/config/apiEndpoints.js create mode 100644 src/views/home/HomeView.vue diff --git a/src/api/administratorapi.js b/src/api/administratorapi.js index c64ebd5..9e802a6 100644 --- a/src/api/administratorapi.js +++ b/src/api/administratorapi.js @@ -1,9 +1,25 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取管理员列表 +const buildUserNumberPayload = (userNumber) => { + if (userNumber && typeof userNumber === "object") { + return { + UserNumber: userNumber.UserNumber ?? userNumber.userNumber ?? "", + }; + } + + return { UserNumber: userNumber }; +}; + export const fetchAdmins = async (params) => { try { - const response = await api.get("/Admin/GetAllAdminList", { params }); + const response = await api.get( + API_ENDPOINTS.routes.ADMIN_GET_ALL_ADMIN_LIST, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +29,7 @@ export const fetchAdmins = async (params) => { // 添加管理员 export const addAdmin = async (data) => { try { - const response = await api.post("/Admin/AddAdmin", data); + const response = await api.post(API_ENDPOINTS.routes.ADMIN_ADD_ADMIN, data); return response.data; } catch (error) { throw error; @@ -23,7 +39,7 @@ export const addAdmin = async (data) => { // 更新管理员 export const updateAdmin = async (data) => { try { - const response = await api.post(`/Admin/UpdAdmin`, data); + const response = await api.post(API_ENDPOINTS.routes.ADMIN_UPD_ADMIN, data); return response.data; } catch (error) { throw error; @@ -33,7 +49,7 @@ export const updateAdmin = async (data) => { // 删除管理员 export const deleteAdmin = async (data) => { try { - const response = await api.post(`/Admin/DelAdmin`, data); + const response = await api.post(API_ENDPOINTS.routes.ADMIN_DEL_ADMIN, data); return response.data; } catch (error) { throw error; @@ -43,7 +59,10 @@ export const deleteAdmin = async (data) => { // 为用户分配角色(全量覆盖) export const assignUserRoles = async (data) => { try { - const response = await api.post("/Admin/AssignUserRoles", data); + const response = await api.post( + API_ENDPOINTS.routes.ADMIN_ASSIGN_USER_ROLES, + data, + ); return response.data; } catch (error) { throw error; @@ -53,9 +72,10 @@ export const assignUserRoles = async (data) => { // 读取指定用户已分配角色编码集合 export const readUserRoles = async (userNumber) => { try { - const response = await api.get("/Admin/ReadUserRoles", { - params: { userNumber }, - }); + const response = await api.post( + API_ENDPOINTS.routes.ADMIN_READ_USER_ROLES, + buildUserNumberPayload(userNumber), + ); return response.data?.Data?.Items || []; } catch (error) { throw error; @@ -65,9 +85,10 @@ export const readUserRoles = async (userNumber) => { // 读取指定用户的角色-权限明细(来自 RolePermission + Permission) export const readUserRolePermissions = async (userNumber) => { try { - const response = await api.get("/Admin/ReadUserRolePermissions", { - params: { userNumber }, - }); + const response = await api.post( + API_ENDPOINTS.routes.ADMIN_READ_USER_ROLE_PERMISSIONS, + buildUserNumberPayload(userNumber), + ); return response.data?.Data?.Items || []; } catch (error) { throw error; @@ -77,7 +98,10 @@ export const readUserRolePermissions = async (userNumber) => { // 为用户分配“直接权限”(全量覆盖) export const assignUserPermissions = async (data) => { try { - const response = await api.post("/Admin/AssignUserPermissions", data); + const response = await api.post( + API_ENDPOINTS.routes.ADMIN_ASSIGN_USER_PERMISSIONS, + data, + ); return response.data; } catch (error) { throw error; @@ -87,9 +111,10 @@ export const assignUserPermissions = async (data) => { // 读取指定用户的“直接权限”权限编码集合 export const readUserDirectPermissions = async (userNumber) => { try { - const response = await api.get("/Admin/ReadUserDirectPermissions", { - params: { userNumber }, - }); + const response = await api.post( + API_ENDPOINTS.routes.ADMIN_READ_USER_DIRECT_PERMISSIONS, + buildUserNumberPayload(userNumber), + ); return response.data?.Data?.Items || []; } catch (error) { throw error; diff --git a/src/api/administratortypeapi.js b/src/api/administratortypeapi.js index ab9bec9..1edd162 100644 --- a/src/api/administratortypeapi.js +++ b/src/api/administratortypeapi.js @@ -1,9 +1,13 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取管理员类型列表 export const fetchAdminTypes = async (params) => { try { - const response = await api.get("/Admin/GetAllAdminTypes", { params }); + const response = await api.get( + API_ENDPOINTS.routes.ADMIN_GET_ALL_ADMIN_TYPES, + { params }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +17,10 @@ export const fetchAdminTypes = async (params) => { // 添加管理员类型 export const addAdminType = async (data) => { try { - const response = await api.post("/Admin/AddAdminType", data); + const response = await api.post( + API_ENDPOINTS.routes.ADMIN_ADD_ADMIN_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +30,10 @@ export const addAdminType = async (data) => { // 更新管理员类型 export const updateAdminType = async (data) => { try { - const response = await api.post(`/Admin/UpdAdminType`, data); + const response = await api.post( + API_ENDPOINTS.routes.ADMIN_UPD_ADMIN_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +43,10 @@ export const updateAdminType = async (data) => { // 删除管理员类型 export const deleteAdminType = async (data) => { try { - const response = await api.post(`/Admin/DelAdminType`, data); + const response = await api.post( + API_ENDPOINTS.routes.ADMIN_DEL_ADMIN_TYPE, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/basicapi.js b/src/api/basicapi.js index 9389e98..02b7731 100644 --- a/src/api/basicapi.js +++ b/src/api/basicapi.js @@ -1,19 +1,25 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; const LOGIN_ENDPOINTS = { - admin: "/Admin/Login", - employee: "/Employee/EmployeeLogin", + admin: API_ENDPOINTS.login.admin, + employee: API_ENDPOINTS.login.employee, }; const TWO_FACTOR_CONTROLLERS = { - admin: "Admin", - employee: "Employee", + admin: API_ENDPOINTS.twoFactor.admin, + employee: API_ENDPOINTS.twoFactor.employee, }; -const resolveLoginEndpoint = (loginType = "admin") => +const LOGIN_TYPES = { + admin: API_ENDPOINTS.loginTypes.admin, + employee: API_ENDPOINTS.loginTypes.employee, +}; + +const resolveLoginEndpoint = (loginType = LOGIN_TYPES.admin) => LOGIN_ENDPOINTS[loginType] || LOGIN_ENDPOINTS.admin; -const resolveTwoFactorController = (loginType = "admin") => +const resolveTwoFactorController = (loginType = LOGIN_TYPES.admin) => TWO_FACTOR_CONTROLLERS[loginType] || TWO_FACTOR_CONTROLLERS.admin; const toErrorPayload = (error) => @@ -37,7 +43,7 @@ export const isTwoFactorChallenge = (payload) => payload?.Code === 1401 && payload?.Data?.RequiresTwoFactor === true; // 登录 -export const signIn = async (data, loginType = "admin") => { +export const signIn = async (data, loginType = LOGIN_TYPES.admin) => { try { const response = await api.post(resolveLoginEndpoint(loginType), data, { skipBusinessErrorHandling: true, @@ -52,7 +58,7 @@ export const signIn = async (data, loginType = "admin") => { // 登出 export const signOut = async (data) => { try { - const response = await api.post("/Admin/Logout", data); + const response = await api.post(API_ENDPOINTS.routes.ADMIN_LOGOUT, data); const resData = response.data; if (isApiSuccess(resData)) { return resData; @@ -66,29 +72,32 @@ export const signOut = async (data) => { // 获取服务器版本号 export const getServerVersion = async () => { - const response = await api.get("/version"); + const response = await api.get(API_ENDPOINTS.routes.VERSION); const resData = response.data; return resData; }; -export const fetchTwoFactorStatus = async (loginType = "admin") => { +export const fetchTwoFactorStatus = async (loginType = LOGIN_TYPES.admin) => { try { const controller = resolveTwoFactorController(loginType); - const response = await api.get(`/${controller}/GetTwoFactorStatus`, { - skipBusinessErrorHandling: true, - skipHttpErrorHandling: true, - }); + const response = await api.get( + API_ENDPOINTS.dynamic.getTwoFactorStatus(controller), + { + skipBusinessErrorHandling: true, + skipHttpErrorHandling: true, + }, + ); return response.data; } catch (error) { throw toErrorPayload(error); } }; -export const generateTwoFactorSetup = async (loginType = "admin") => { +export const generateTwoFactorSetup = async (loginType = LOGIN_TYPES.admin) => { try { const controller = resolveTwoFactorController(loginType); const response = await api.post( - `/${controller}/GenerateTwoFactorSetup`, + API_ENDPOINTS.dynamic.generateTwoFactorSetup(controller), {}, { skipBusinessErrorHandling: true, @@ -102,13 +111,13 @@ export const generateTwoFactorSetup = async (loginType = "admin") => { }; export const enableTwoFactor = async ( - loginType = "admin", + loginType = LOGIN_TYPES.admin, verificationCode = "", ) => { try { const controller = resolveTwoFactorController(loginType); const response = await api.post( - `/${controller}/EnableTwoFactor`, + API_ENDPOINTS.dynamic.enableTwoFactor(controller), { VerificationCode: verificationCode }, { skipBusinessErrorHandling: true, @@ -122,13 +131,13 @@ export const enableTwoFactor = async ( }; export const disableTwoFactor = async ( - loginType = "admin", + loginType = LOGIN_TYPES.admin, verificationCode = "", ) => { try { const controller = resolveTwoFactorController(loginType); const response = await api.post( - `/${controller}/DisableTwoFactor`, + API_ENDPOINTS.dynamic.disableTwoFactor(controller), { VerificationCode: verificationCode }, { skipBusinessErrorHandling: true, @@ -142,13 +151,13 @@ export const disableTwoFactor = async ( }; export const regenerateTwoFactorRecoveryCodes = async ( - loginType = "admin", + loginType = LOGIN_TYPES.admin, verificationCode = "", ) => { try { const controller = resolveTwoFactorController(loginType); const response = await api.post( - `/${controller}/RegenerateTwoFactorRecoveryCodes`, + API_ENDPOINTS.dynamic.regenerateTwoFactorRecoveryCodes(controller), { VerificationCode: verificationCode }, { skipBusinessErrorHandling: true, diff --git a/src/api/csrfapi.js b/src/api/csrfapi.js index 8e327bd..bfcc637 100644 --- a/src/api/csrfapi.js +++ b/src/api/csrfapi.js @@ -1,8 +1,9 @@ import api from "./index"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; export const getCsrfToken = async () => { try { - const response = await api.get("/Login/GetCSRFToken"); + const response = await api.get(API_ENDPOINTS.routes.LOGIN_GET_CSRF_TOKEN); if (!response.data.Success) { throw new Error(response.data.Message); } @@ -14,7 +15,9 @@ export const getCsrfToken = async () => { export const refreshCsrfToken = async () => { try { - const response = await api.get("/Login/RefreshCSRFToken"); + const response = await api.get( + API_ENDPOINTS.routes.LOGIN_REFRESH_CSRF_TOKEN, + ); if (!response.data.Success) { throw new Error(response.data.Message); } diff --git a/src/api/customerapi.js b/src/api/customerapi.js index e45e1fc..5cf821d 100644 --- a/src/api/customerapi.js +++ b/src/api/customerapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取客户列表 export const fetchCustomers = async (params) => { try { - const response = await api.get("/Customer/SelectCustomers", { params }); + const response = await api.get( + API_ENDPOINTS.routes.CUSTOMER_SELECT_CUSTOMERS, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchCustomers = async (params) => { // 添加客户 export const addCustomer = async (data) => { try { - const response = await api.post("/Customer/InsertCustomerInfo", data); + const response = await api.post( + API_ENDPOINTS.routes.CUSTOMER_INSERT_CUSTOMER_INFO, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addCustomer = async (data) => { // 更新客户 export const updateCustomer = async (data) => { try { - const response = await api.post(`/Customer/UpdCustomerInfo`, data); + const response = await api.post( + API_ENDPOINTS.routes.CUSTOMER_UPD_CUSTOMER_INFO, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +45,10 @@ export const updateCustomer = async (data) => { // 删除客户 export const deleteCustomer = async (data) => { try { - const response = await api.post(`/Customer/DelCustomerInfo`, data); + const response = await api.post( + API_ENDPOINTS.routes.CUSTOMER_DEL_CUSTOMER_INFO, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/customerpermissionapi.js b/src/api/customerpermissionapi.js index 2bfdfa8..23b207e 100644 --- a/src/api/customerpermissionapi.js +++ b/src/api/customerpermissionapi.js @@ -1,11 +1,23 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 读取指定客户已分配的角色(返回角色编码集合) +const buildUserNumberPayload = (customerNumber) => { + if (customerNumber && typeof customerNumber === "object") { + return { + UserNumber: customerNumber.UserNumber ?? customerNumber.userNumber ?? "", + }; + } + + return { UserNumber: customerNumber }; +}; + export const readUserRoles = async (customerNumber) => { try { - const response = await api.get("/CustomerPermission/ReadUserRoles", { - params: { userNumber: customerNumber }, - }); + const response = await api.post( + API_ENDPOINTS.routes.CUSTOMER_PERMISSION_READ_USER_ROLES, + buildUserNumberPayload(customerNumber), + ); return response.data?.Data?.Items || []; } catch (error) { throw error; @@ -16,7 +28,7 @@ export const readUserRoles = async (customerNumber) => { export const assignUserRoles = async (data) => { try { const response = await api.post( - "/CustomerPermission/AssignUserRoles", + API_ENDPOINTS.routes.CUSTOMER_PERMISSION_ASSIGN_USER_ROLES, data, ); return response.data; @@ -28,11 +40,9 @@ export const assignUserRoles = async (data) => { // 读取客户(通过角色)所拥有的权限明细(列表) export const readUserRolePermissions = async (customerNumber) => { try { - const response = await api.get( - "/CustomerPermission/ReadUserRolePermissions", - { - params: { userNumber: customerNumber }, - }, + const response = await api.post( + API_ENDPOINTS.routes.CUSTOMER_PERMISSION_READ_USER_ROLE_PERMISSIONS, + buildUserNumberPayload(customerNumber), ); return response.data?.Data?.Items || []; } catch (error) { @@ -43,11 +53,9 @@ export const readUserRolePermissions = async (customerNumber) => { // 读取客户“直接权限”(非角色继承)权限编码集合 export const readUserDirectPermissions = async (customerNumber) => { try { - const response = await api.get( - "/CustomerPermission/ReadUserDirectPermissions", - { - params: { userNumber: customerNumber }, - }, + const response = await api.post( + API_ENDPOINTS.routes.CUSTOMER_PERMISSION_READ_USER_DIRECT_PERMISSIONS, + buildUserNumberPayload(customerNumber), ); return response.data?.Data?.Items || []; } catch (error) { @@ -59,7 +67,7 @@ export const readUserDirectPermissions = async (customerNumber) => { export const assignUserPermissions = async (data) => { try { const response = await api.post( - "/CustomerPermission/AssignUserPermissions", + API_ENDPOINTS.routes.CUSTOMER_PERMISSION_ASSIGN_USER_PERMISSIONS, data, ); return response.data; diff --git a/src/api/customertypeapi.js b/src/api/customertypeapi.js index 5ccd0f6..9e184d1 100644 --- a/src/api/customertypeapi.js +++ b/src/api/customertypeapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取客户类型列表 export const fetchCustomerTypes = async (params) => { try { - const response = await api.get("/Base/SelectCustoTypeAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_CUSTO_TYPE_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchCustomerTypes = async (params) => { // 添加客户类型 export const addCustomerType = async (data) => { try { - const response = await api.post("/Base/InsertCustoType", data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_INSERT_CUSTO_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addCustomerType = async (data) => { // 更新客户类型 export const updateCustomerType = async (data) => { try { - const response = await api.post(`/Base/UpdateCustoType`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_UPDATE_CUSTO_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +45,10 @@ export const updateCustomerType = async (data) => { // 删除客户类型 export const deleteCustomerType = async (data) => { try { - const response = await api.post(`/Base/DeleteCustoType`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_DELETE_CUSTO_TYPE, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/custotypeapi.js b/src/api/custotypeapi.js index 7e9445f..5a28df8 100644 --- a/src/api/custotypeapi.js +++ b/src/api/custotypeapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取客户类型列表 export const fetchCustomerTypes = async (params) => { try { - const response = await api.get("/Base/SelectCustoTypeAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_CUSTO_TYPE_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,9 +19,10 @@ export const fetchCustomerTypes = async (params) => { // 获取可用客户类型列表 export const fetchCanUseCustomerTypes = async (params) => { try { - const response = await api.get("/Base/SelectCustoTypeAllCanUse", { - params, - }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_CUSTO_TYPE_ALL_CAN_USE, + { params }, + ); return response.data.Data; } catch (error) { throw error; @@ -25,7 +32,10 @@ export const fetchCanUseCustomerTypes = async (params) => { // 添加客户类型 export const addCustomerType = async (data) => { try { - const response = await api.post("/Base/InsertCustoType", data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_INSERT_CUSTO_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -35,7 +45,10 @@ export const addCustomerType = async (data) => { // 更新客户类型 export const updateCustomerType = async (data) => { try { - const response = await api.post(`/Base/UpdateCustoType`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_UPDATE_CUSTO_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -45,7 +58,10 @@ export const updateCustomerType = async (data) => { // 删除客户类型 export const deleteCustomerType = async (data) => { try { - const response = await api.post(`/Base/DeleteCustoType`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_DELETE_CUSTO_TYPE, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/dashboardapi.js b/src/api/dashboardapi.js index 74910e1..85bb05a 100644 --- a/src/api/dashboardapi.js +++ b/src/api/dashboardapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取房间统计信息 export const fetchRoomStatistics = async (params) => { try { - const response = await api.get("/Dashboard/RoomStatistics", { params }); + const response = await api.get( + API_ENDPOINTS.routes.DASHBOARD_ROOM_STATISTICS, + { + params, + }, + ); return response.data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchRoomStatistics = async (params) => { // 获取业务统计信息 export const fetchBusinessStatistics = async (params) => { try { - const response = await api.get("/Dashboard/BusinessStatistics", { params }); + const response = await api.get( + API_ENDPOINTS.routes.DASHBOARD_BUSINESS_STATISTICS, + { params }, + ); return response.data; } catch (error) { throw error; @@ -23,9 +32,10 @@ export const fetchBusinessStatistics = async (params) => { // 获取后勤统计信息 export const fetchLogisticsStatistics = async (params) => { try { - const response = await api.get("/Dashboard/LogisticsStatistics", { - params, - }); + const response = await api.get( + API_ENDPOINTS.routes.DASHBOARD_LOGISTICS_STATISTICS, + { params }, + ); return response.data; } catch (error) { throw error; @@ -35,9 +45,10 @@ export const fetchLogisticsStatistics = async (params) => { // 获取人事统计信息 export const fetchHumanResourcesStatistics = async (params) => { try { - const response = await api.get("/Dashboard/HumanResourcesStatistics", { - params, - }); + const response = await api.get( + API_ENDPOINTS.routes.DASHBOARD_HUMAN_RESOURCES_STATISTICS, + { params }, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/departmentapi.js b/src/api/departmentapi.js index 060545a..0193b64 100644 --- a/src/api/departmentapi.js +++ b/src/api/departmentapi.js @@ -1,9 +1,12 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取部门列表 export const fetchDepartments = async (params) => { try { - const response = await api.get("/Base/SelectDeptAll", { params }); + const response = await api.get(API_ENDPOINTS.routes.BASE_SELECT_DEPT_ALL, { + params, + }); return response.data.Data; } catch (error) { throw error; @@ -13,7 +16,7 @@ export const fetchDepartments = async (params) => { // 添加部门 export const addDepartment = async (data) => { try { - const response = await api.post("/Base/AddDept", data); + const response = await api.post(API_ENDPOINTS.routes.BASE_ADD_DEPT, data); return response.data; } catch (error) { throw error; @@ -23,7 +26,7 @@ export const addDepartment = async (data) => { // 更新部门 export const updateDepartment = async (data) => { try { - const response = await api.post(`/Base/UpdDept`, data); + const response = await api.post(API_ENDPOINTS.routes.BASE_UPD_DEPT, data); return response.data; } catch (error) { throw error; @@ -33,7 +36,7 @@ export const updateDepartment = async (data) => { // 删除部门 export const deleteDepartment = async (data) => { try { - const response = await api.post(`/Base/DelDept`, { data }); + const response = await api.post(API_ENDPOINTS.routes.BASE_DEL_DEPT, { data }); return response.data; } catch (error) { throw error; diff --git a/src/api/employeeapi.js b/src/api/employeeapi.js index 6de5c87..d34d977 100644 --- a/src/api/employeeapi.js +++ b/src/api/employeeapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取员工列表 export const fetchEmployees = async (params) => { try { - const response = await api.get("/Employee/SelectEmployeeAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.EMPLOYEE_SELECT_EMPLOYEE_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,9 +19,10 @@ export const fetchEmployees = async (params) => { //获取员工详情 export const fetchEmployeeDetail = async (params) => { try { - const response = await api.get("/Employee/SelectEmployeeInfoByEmployeeId", { - params, - }); + const response = await api.get( + API_ENDPOINTS.routes.EMPLOYEE_SELECT_EMPLOYEE_INFO_BY_EMPLOYEE_ID, + { params }, + ); return response.data; } catch (error) { throw error; @@ -26,7 +33,7 @@ export const fetchEmployeeDetail = async (params) => { export const fetchEmployeeResume = async (params) => { try { const response = await api.get( - "/EmployeeHistory/SelectHistoryByEmployeeId", + API_ENDPOINTS.routes.EMPLOYEE_HISTORY_SELECT_HISTORY_BY_EMPLOYEE_ID, { params }, ); return response.data.Data; @@ -38,7 +45,10 @@ export const fetchEmployeeResume = async (params) => { // 添加员工 export const addEmployee = async (data) => { try { - const response = await api.post("/Employee/AddEmployee", data); + const response = await api.post( + API_ENDPOINTS.routes.EMPLOYEE_ADD_EMPLOYEE, + data, + ); return response.data; } catch (error) { throw error; @@ -48,7 +58,10 @@ export const addEmployee = async (data) => { // 更新员工 export const updateEmployee = async (data) => { try { - const response = await api.post(`/Employee/UpdateEmployee`, data); + const response = await api.post( + API_ENDPOINTS.routes.EMPLOYEE_UPDATE_EMPLOYEE, + data, + ); return response.data; } catch (error) { throw error; @@ -58,7 +71,10 @@ export const updateEmployee = async (data) => { // 禁用/启用员工账号 export const managerEmployeeAccount = async (data) => { try { - const response = await api.post(`/Employee/ManagerEmployeeAccount`, data); + const response = await api.post( + API_ENDPOINTS.routes.EMPLOYEE_MANAGER_EMPLOYEE_ACCOUNT, + data, + ); return response.data; } catch (error) { throw error; @@ -69,7 +85,8 @@ export const managerEmployeeAccount = async (data) => { export const fetchEmployeeRewardPunishment = async (params) => { try { const response = await api.get( - "/RewardPunishment/SelectAllRewardPunishmentByEmployeeId", + API_ENDPOINTS.routes + .REWARD_PUNISHMENT_SELECT_ALL_REWARD_PUNISHMENT_BY_EMPLOYEE_ID, { params }, ); return response.data.Data; @@ -82,7 +99,7 @@ export const fetchEmployeeRewardPunishment = async (params) => { export const fetchEmployeeAttendance = async (params) => { try { const response = await api.get( - "/EmployeeCheck/SelectCheckInfoByEmployeeId", + API_ENDPOINTS.routes.EMPLOYEE_CHECK_SELECT_CHECK_INFO_BY_EMPLOYEE_ID, { params }, ); return response.data.Data; @@ -95,7 +112,7 @@ export const fetchEmployeeAttendance = async (params) => { export const resetEmployeePassword = async (data) => { try { const response = await api.post( - `/Employee/ResetEmployeeAccountPassword`, + API_ENDPOINTS.routes.EMPLOYEE_RESET_EMPLOYEE_ACCOUNT_PASSWORD, data, ); return response.data; @@ -107,7 +124,10 @@ export const resetEmployeePassword = async (data) => { // 上传员工头像 export const uploadEmployeeAvatar = async (data) => { try { - const response = await api.post(`/EmployeePhoto/InsertWorkerPhoto`, data); + const response = await api.post( + API_ENDPOINTS.routes.EMPLOYEE_PHOTO_INSERT_WORKER_PHOTO, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/employeepermissionapi.js b/src/api/employeepermissionapi.js index 3aaa475..09456d9 100644 --- a/src/api/employeepermissionapi.js +++ b/src/api/employeepermissionapi.js @@ -1,11 +1,23 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 读取指定员工已分配的角色(返回角色编码集合) +const buildUserNumberPayload = (employeeId) => { + if (employeeId && typeof employeeId === "object") { + return { + UserNumber: employeeId.UserNumber ?? employeeId.userNumber ?? "", + }; + } + + return { UserNumber: employeeId }; +}; + export const readUserRoles = async (employeeId) => { try { - const response = await api.get("/EmployeePermission/ReadUserRoles", { - params: { userNumber: employeeId }, - }); + const response = await api.post( + API_ENDPOINTS.routes.EMPLOYEE_PERMISSION_READ_USER_ROLES, + buildUserNumberPayload(employeeId), + ); return response.data?.Data?.Items || []; } catch (error) { throw error; @@ -16,7 +28,7 @@ export const readUserRoles = async (employeeId) => { export const assignUserRoles = async (data) => { try { const response = await api.post( - "/EmployeePermission/AssignUserRoles", + API_ENDPOINTS.routes.EMPLOYEE_PERMISSION_ASSIGN_USER_ROLES, data, ); return response.data; @@ -28,11 +40,9 @@ export const assignUserRoles = async (data) => { // 读取员工(通过角色)所拥有的权限明细(列表) export const readUserRolePermissions = async (employeeId) => { try { - const response = await api.get( - "/EmployeePermission/ReadUserRolePermissions", - { - params: { userNumber: employeeId }, - }, + const response = await api.post( + API_ENDPOINTS.routes.EMPLOYEE_PERMISSION_READ_USER_ROLE_PERMISSIONS, + buildUserNumberPayload(employeeId), ); return response.data?.Data?.Items || []; } catch (error) { @@ -43,11 +53,9 @@ export const readUserRolePermissions = async (employeeId) => { // 读取员工“直接权限”(非角色继承)权限编码集合 export const readUserDirectPermissions = async (employeeId) => { try { - const response = await api.get( - "/EmployeePermission/ReadUserDirectPermissions", - { - params: { userNumber: employeeId }, - }, + const response = await api.post( + API_ENDPOINTS.routes.EMPLOYEE_PERMISSION_READ_USER_DIRECT_PERMISSIONS, + buildUserNumberPayload(employeeId), ); return response.data?.Data?.Items || []; } catch (error) { @@ -59,7 +67,7 @@ export const readUserDirectPermissions = async (employeeId) => { export const assignUserPermissions = async (data) => { try { const response = await api.post( - "/EmployeePermission/AssignUserPermissions", + API_ENDPOINTS.routes.EMPLOYEE_PERMISSION_ASSIGN_USER_PERMISSIONS, data, ); return response.data; diff --git a/src/api/goodsapi.js b/src/api/goodsapi.js index 3d568c4..a55e940 100644 --- a/src/api/goodsapi.js +++ b/src/api/goodsapi.js @@ -1,9 +1,13 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取商品列表 export const fetchGoodss = async (params) => { try { - const response = await api.get("/Sellthing/SelectSellthingAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.SELLTHING_SELECT_SELLTHING_ALL, + { params }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +17,10 @@ export const fetchGoodss = async (params) => { // 添加商品 export const addGoods = async (data) => { try { - const response = await api.post("/Sellthing/InsertSellthing", data); + const response = await api.post( + API_ENDPOINTS.routes.SELLTHING_INSERT_SELLTHING, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +30,10 @@ export const addGoods = async (data) => { // 更新商品 export const updateGoods = async (data) => { try { - const response = await api.post(`/Sellthing/UpdateSellthing`, data); + const response = await api.post( + API_ENDPOINTS.routes.SELLTHING_UPDATE_SELLTHING, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +43,10 @@ export const updateGoods = async (data) => { // 删除商品 export const deleteGoods = async (data) => { try { - const response = await api.post(`/Sellthing/DeleteSellthing`, data); + const response = await api.post( + API_ENDPOINTS.routes.SELLTHING_DELETE_SELLTHING, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/hydroelectricityapi.js b/src/api/hydroelectricityapi.js index f7228aa..ec1db7d 100644 --- a/src/api/hydroelectricityapi.js +++ b/src/api/hydroelectricityapi.js @@ -1,10 +1,11 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 根据条件查询水电费信息 房间号(可选)使用开始时间(可选)使用结束时间(可选) export const fetchHydroelectricitys = async (params) => { try { const response = await api.get( - "/EnergyManagement/SelectEnergyManagementInfo", + API_ENDPOINTS.routes.ENERGY_MANAGEMENT_SELECT_ENERGY_MANAGEMENT_INFO, { params }, ); return response.data.Data; @@ -17,7 +18,7 @@ export const fetchHydroelectricitys = async (params) => { export const addHydroelectricity = async (data) => { try { const response = await api.post( - "/EnergyManagement/InsertEnergyManagementInfo", + API_ENDPOINTS.routes.ENERGY_MANAGEMENT_INSERT_ENERGY_MANAGEMENT_INFO, data, ); return response.data; @@ -30,7 +31,7 @@ export const addHydroelectricity = async (data) => { export const updateHydroelectricity = async (data) => { try { const response = await api.post( - `/EnergyManagement/UpdateEnergyManagementInfo`, + API_ENDPOINTS.routes.ENERGY_MANAGEMENT_UPDATE_ENERGY_MANAGEMENT_INFO, data, ); return response.data; @@ -43,7 +44,7 @@ export const updateHydroelectricity = async (data) => { export const deleteHydroelectricity = async (data) => { try { const response = await api.post( - `/EnergyManagement/DeleteEnergyManagementInfo`, + API_ENDPOINTS.routes.ENERGY_MANAGEMENT_DELETE_ENERGY_MANAGEMENT_INFO, data, ); return response.data; diff --git a/src/api/internalfinanceapi.js b/src/api/internalfinanceapi.js index 7905129..afa796e 100644 --- a/src/api/internalfinanceapi.js +++ b/src/api/internalfinanceapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取资产列表 export const fetchInternalFinances = async (params) => { try { - const response = await api.get("/Asset/SelectAssetInfoAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.ASSET_SELECT_ASSET_INFO_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchInternalFinances = async (params) => { // 添加资产 export const addInternalFinance = async (data) => { try { - const response = await api.post("/Asset/AddAssetInfo", data); + const response = await api.post( + API_ENDPOINTS.routes.ASSET_ADD_ASSET_INFO, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addInternalFinance = async (data) => { // 更新资产 export const updateInternalFinance = async (data) => { try { - const response = await api.post(`/Asset/UpdAssetInfo`, data); + const response = await api.post( + API_ENDPOINTS.routes.ASSET_UPD_ASSET_INFO, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +45,10 @@ export const updateInternalFinance = async (data) => { // 删除资产 export const deleteInternalFinance = async (data) => { try { - const response = await api.post(`/Asset/DelAssetInfo`, data); + const response = await api.post( + API_ENDPOINTS.routes.ASSET_DEL_ASSET_INFO, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/menuapi.js b/src/api/menuapi.js index 14926a2..b1215f3 100644 --- a/src/api/menuapi.js +++ b/src/api/menuapi.js @@ -1,9 +1,13 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取菜单树 export const fetchMenusTree = async (menu) => { try { - const response = await api.post("/Menu/BuildMenuAll", menu); + const response = await api.post( + API_ENDPOINTS.routes.MENU_BUILD_MENU_ALL, + menu, + ); // 后端 BaseResponse 使用 PascalCase 字段(Success/Code/Message/Data) if (!response.data.Success) { @@ -18,7 +22,9 @@ export const fetchMenusTree = async (menu) => { // 获取菜单列表 export const fetchMenus = async (params) => { try { - const response = await api.get("/Menu/SelectMenuAll", { params }); + const response = await api.get(API_ENDPOINTS.routes.MENU_SELECT_MENU_ALL, { + params, + }); return response.data.Data; } catch (error) { throw error; @@ -28,7 +34,10 @@ export const fetchMenus = async (params) => { // 创建新菜单项 export const addMenu = async (menu) => { try { - const response = await api.post("/Menu/InsertMenu", menu); + const response = await api.post( + API_ENDPOINTS.routes.MENU_INSERT_MENU, + menu, + ); return response.data; } catch (error) { throw error; @@ -38,7 +47,10 @@ export const addMenu = async (menu) => { // 更新菜单项 export const updateMenu = async (menu) => { try { - const response = await api.post(`/Menu/UpdateMenu`, menu); + const response = await api.post( + API_ENDPOINTS.routes.MENU_UPDATE_MENU, + menu, + ); return response.data; } catch (error) { throw error; @@ -48,7 +60,10 @@ export const updateMenu = async (menu) => { // 删除菜单项 export const deleteMenu = async (menu) => { try { - const response = await api.post(`/Menu/DeleteMenu`, menu); + const response = await api.post( + API_ENDPOINTS.routes.MENU_DELETE_MENU, + menu, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/nationapi.js b/src/api/nationapi.js index f2f05db..300db81 100644 --- a/src/api/nationapi.js +++ b/src/api/nationapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取民族列表 export const fetchNations = async (params) => { try { - const response = await api.get("/Base/SelectNationAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_NATION_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,7 @@ export const fetchNations = async (params) => { // 添加民族 export const addNation = async (data) => { try { - const response = await api.post("/Base/AddNation", data); + const response = await api.post(API_ENDPOINTS.routes.BASE_ADD_NATION, data); return response.data; } catch (error) { throw error; @@ -23,7 +29,7 @@ export const addNation = async (data) => { // 更新民族 export const updateNation = async (data) => { try { - const response = await api.post(`/Base/UpdNation`, data); + const response = await api.post(API_ENDPOINTS.routes.BASE_UPD_NATION, data); return response.data; } catch (error) { throw error; @@ -33,7 +39,7 @@ export const updateNation = async (data) => { // 删除民族 export const deleteNation = async (data) => { try { - const response = await api.post(`/Base/DelNation`, data); + const response = await api.post(API_ENDPOINTS.routes.BASE_DEL_NATION, data); return response.data; } catch (error) { throw error; diff --git a/src/api/noticetypeapi.js b/src/api/noticetypeapi.js index 712c7c7..fbe5344 100644 --- a/src/api/noticetypeapi.js +++ b/src/api/noticetypeapi.js @@ -1,11 +1,13 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取公告类型列表 export const fetchNoticeTypes = async (params) => { try { - const response = await api.get("/Base/SelectAppointmentNoticeTypeAll", { - params, - }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_APPOINTMENT_NOTICE_TYPE_ALL, + { params }, + ); return response.data.Data; } catch (error) { throw error; @@ -15,7 +17,10 @@ export const fetchNoticeTypes = async (params) => { // 添加公告类型 export const addNoticeType = async (data) => { try { - const response = await api.post("/Base/CreateAppointmentNoticeType", data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_CREATE_APPOINTMENT_NOTICE_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -25,7 +30,10 @@ export const addNoticeType = async (data) => { // 更新公告类型 export const updateNoticeType = async (data) => { try { - const response = await api.post(`/Base/UpdateAppointmentNoticeType`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_UPDATE_APPOINTMENT_NOTICE_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -35,7 +43,10 @@ export const updateNoticeType = async (data) => { // 删除公告类型 export const deleteNoticeType = async (data) => { try { - const response = await api.post(`/Base/DeleteAppointmentNoticeType`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_DELETE_APPOINTMENT_NOTICE_TYPE, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/passportapi.js b/src/api/passportapi.js index e32787a..01fd8a4 100644 --- a/src/api/passportapi.js +++ b/src/api/passportapi.js @@ -1,9 +1,13 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取证件类型列表 export const fetchPassports = async (params) => { try { - const response = await api.get("/Base/SelectPassPortTypeAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_PASS_PORT_TYPE_ALL, + { params }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,9 +17,10 @@ export const fetchPassports = async (params) => { // 获取可用证件类型列表 export const fetchCanUsePassports = async (params) => { try { - const response = await api.get("/Base/SelectPassPortTypeAllCanUse", { - params, - }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_PASS_PORT_TYPE_ALL_CAN_USE, + { params }, + ); return response.data.Data; } catch (error) { throw error; @@ -25,7 +30,10 @@ export const fetchCanUsePassports = async (params) => { // 添加证件类型 export const addPassport = async (data) => { try { - const response = await api.post("/Base/InsertPassPortType", data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_INSERT_PASS_PORT_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -35,7 +43,10 @@ export const addPassport = async (data) => { // 更新证件类型 export const updatePassport = async (data) => { try { - const response = await api.post(`/Base/UpdatePassPortType`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_UPDATE_PASS_PORT_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -45,7 +56,10 @@ export const updatePassport = async (data) => { // 删除证件类型 export const deletePassport = async (data) => { try { - const response = await api.post(`/Base/DeletePassPortType`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_DELETE_PASS_PORT_TYPE, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/permissionapi.js b/src/api/permissionapi.js index 66c88d6..f4bbeca 100644 --- a/src/api/permissionapi.js +++ b/src/api/permissionapi.js @@ -1,10 +1,22 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; + +const buildReadPermissionPayload = (params = {}) => ({ + PermissionNumber: params.PermissionNumber ?? params.permissionNumber ?? "", + PermissionName: params.PermissionName ?? params.permissionName ?? "", + MenuKey: params.MenuKey ?? params.menuKey ?? "", + Module: params.Module ?? params.module ?? "", + Page: params.Page ?? params.page ?? 1, + PageSize: params.PageSize ?? params.pageSize ?? 15, + IgnorePaging: params.IgnorePaging ?? params.ignorePaging ?? false, +}); export const selectPermissionList = async (params) => { try { - const response = await api.get("/Permission/SelectPermissionList", { - params, - }); + const response = await api.post( + API_ENDPOINTS.routes.PERMISSION_SELECT_PERMISSION_LIST, + buildReadPermissionPayload(params), + ); // 返回标准结构 { Items, TotalCount } return response.data?.Data || { Items: [], TotalCount: 0 }; } catch (error) { diff --git a/src/api/positionapi.js b/src/api/positionapi.js index e4f0501..0a69921 100644 --- a/src/api/positionapi.js +++ b/src/api/positionapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取职位列表 export const fetchPositions = async (params) => { try { - const response = await api.get("/Base/SelectPositionAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_POSITION_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchPositions = async (params) => { // 添加职位 export const addPosition = async (data) => { try { - const response = await api.post("/Base/AddPosition", data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_ADD_POSITION, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addPosition = async (data) => { // 更新职位 export const updatePosition = async (data) => { try { - const response = await api.post(`/Base/UpdPosition`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_UPD_POSITION, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +45,10 @@ export const updatePosition = async (data) => { // 删除职位 export const deletePosition = async (data) => { try { - const response = await api.post(`/Base/DelPosition`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_DEL_POSITION, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/promotioncontentapi.js b/src/api/promotioncontentapi.js index 224502c..845a6fe 100644 --- a/src/api/promotioncontentapi.js +++ b/src/api/promotioncontentapi.js @@ -1,10 +1,11 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取宣传联动内容列表 export const fetchPromotionContents = async (params) => { try { const response = await api.get( - "/PromotionContent/SelectPromotionContentAll", + API_ENDPOINTS.routes.PROMOTION_CONTENT_SELECT_PROMOTION_CONTENT_ALL, { params }, ); return response.data.Data; @@ -17,7 +18,7 @@ export const fetchPromotionContents = async (params) => { export const addPromotionContent = async (data) => { try { const response = await api.post( - "/PromotionContent/AddPromotionContent", + API_ENDPOINTS.routes.PROMOTION_CONTENT_ADD_PROMOTION_CONTENT, data, ); return response.data; @@ -30,7 +31,7 @@ export const addPromotionContent = async (data) => { export const updatePromotionContent = async (data) => { try { const response = await api.post( - `/PromotionContent/UpdatePromotionContent`, + API_ENDPOINTS.routes.PROMOTION_CONTENT_UPDATE_PROMOTION_CONTENT, data, ); return response.data; @@ -43,7 +44,7 @@ export const updatePromotionContent = async (data) => { export const deletePromotionContent = async (data) => { try { const response = await api.post( - `/PromotionContent/DeletePromotionContent`, + API_ENDPOINTS.routes.PROMOTION_CONTENT_DELETE_PROMOTION_CONTENT, data, ); return response.data; diff --git a/src/api/qualificationapi.js b/src/api/qualificationapi.js index 9276f06..cfa5093 100644 --- a/src/api/qualificationapi.js +++ b/src/api/qualificationapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取学历列表 export const fetchQualifications = async (params) => { try { - const response = await api.get("/Base/SelectEducationAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_EDUCATION_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchQualifications = async (params) => { // 添加学历 export const addQualification = async (data) => { try { - const response = await api.post("/Base/AddEducation", data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_ADD_EDUCATION, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addQualification = async (data) => { // 更新学历 export const updateQualification = async (data) => { try { - const response = await api.post(`/Base/UpdEducation`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_UPD_EDUCATION, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +45,10 @@ export const updateQualification = async (data) => { // 删除学历 export const deleteQualification = async (data) => { try { - const response = await api.post(`/Base/DelEducation`, data); + const response = await api.post( + API_ENDPOINTS.routes.BASE_DEL_EDUCATION, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/reserapi.js b/src/api/reserapi.js index 30e2b60..945322a 100644 --- a/src/api/reserapi.js +++ b/src/api/reserapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取预约列表 export const fetchResers = async (params) => { try { - const response = await api.get("/Reser/SelectReserAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.RESER_SELECT_RESER_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchResers = async (params) => { // 添加预约 export const addReser = async (data) => { try { - const response = await api.post("/Reser/InserReserInfo", data); + const response = await api.post( + API_ENDPOINTS.routes.RESER_INSER_RESER_INFO, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addReser = async (data) => { // 更新预约 export const updateReser = async (data) => { try { - const response = await api.post(`/Reser/UpdateReserInfo`, data); + const response = await api.post( + API_ENDPOINTS.routes.RESER_UPDATE_RESER_INFO, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +45,10 @@ export const updateReser = async (data) => { // 删除预约 export const deleteReser = async (data) => { try { - const response = await api.post(`/Reser/DeleteReserInfo`, data); + const response = await api.post( + API_ENDPOINTS.routes.RESER_DELETE_RESER_INFO, + data, + ); return response.data; } catch (error) { throw error; @@ -43,7 +58,10 @@ export const deleteReser = async (data) => { // 获取预约类型 export const fetchReserTypes = async (params) => { try { - const response = await api.get("/Reser/SelectReserTypeAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.RESER_SELECT_RESER_TYPE_ALL, + { params }, + ); return response.data.Data; } catch (error) { throw error; diff --git a/src/api/roleapi.js b/src/api/roleapi.js index 4bf02c2..f1821a5 100644 --- a/src/api/roleapi.js +++ b/src/api/roleapi.js @@ -1,9 +1,26 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取角色列表 +const buildRoleNumberPayload = (roleNumber) => { + if (roleNumber && typeof roleNumber === "object") { + return { + RoleNumber: + roleNumber.RoleNumber ?? + roleNumber.roleNumber ?? + roleNumber.roleNo ?? + "", + }; + } + + return { RoleNumber: roleNumber }; +}; + export const fetchRoles = async (params) => { try { - const response = await api.get("/Role/SelectRoleList", { params }); + const response = await api.get(API_ENDPOINTS.routes.ROLE_SELECT_ROLE_LIST, { + params, + }); return response.data.Data; } catch (error) { throw error; @@ -13,7 +30,10 @@ export const fetchRoles = async (params) => { // 添加角色 export const addRole = async (data) => { try { - const response = await api.post("/Role/InsertRole", data); + const response = await api.post( + API_ENDPOINTS.routes.ROLE_INSERT_ROLE, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +43,10 @@ export const addRole = async (data) => { // 更新角色 export const updateRole = async (data) => { try { - const response = await api.post(`/Role/UpdateRole`, data); + const response = await api.post( + API_ENDPOINTS.routes.ROLE_UPDATE_ROLE, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +56,10 @@ export const updateRole = async (data) => { // 删除角色 export const deleteRole = async (data) => { try { - const response = await api.post(`/Role/DeleteRole`, data); + const response = await api.post( + API_ENDPOINTS.routes.ROLE_DELETE_ROLE, + data, + ); return response.data; } catch (error) { throw error; @@ -43,7 +69,10 @@ export const deleteRole = async (data) => { // 角色-权限:全量覆盖式授予 export const grantRolePermissions = async (data) => { try { - const response = await api.post("/Role/GrantRolePermissions", data); + const response = await api.post( + API_ENDPOINTS.routes.ROLE_GRANT_ROLE_PERMISSIONS, + data, + ); return response.data; } catch (error) { throw error; @@ -53,9 +82,10 @@ export const grantRolePermissions = async (data) => { // 读取指定角色已授予的权限(返回后端 Data,页面逻辑做进一步兼容处理) export const readRolePermissions = async (roleNumber) => { try { - const response = await api.get("/Role/ReadRolePermissions", { - params: { roleNumber }, - }); + const response = await api.post( + API_ENDPOINTS.routes.ROLE_READ_ROLE_PERMISSIONS, + buildRoleNumberPayload(roleNumber), + ); // 后端返回标准结构 { Code, Message, Data: { Items, TotalCount } } // 这里直接返回 Items,便于上层直接按照数组处理 return response.data?.Data?.Items || []; @@ -67,9 +97,10 @@ export const readRolePermissions = async (roleNumber) => { // 角色-用户:读取指定角色下的管理员编码集合 export const readRoleUsers = async (roleNumber) => { try { - const response = await api.get("/Role/ReadRoleUsers", { - params: { roleNumber }, - }); + const response = await api.post( + API_ENDPOINTS.routes.ROLE_READ_ROLE_USERS, + buildRoleNumberPayload(roleNumber), + ); // 标准结构 { Code, Message, Data: { Items, TotalCount } } return response.data?.Data?.Items || []; } catch (error) { @@ -80,7 +111,10 @@ export const readRoleUsers = async (roleNumber) => { // 角色-用户:为角色分配管理员(全量覆盖) export const assignRoleUsers = async (data) => { try { - const response = await api.post("/Role/AssignRoleUsers", data); + const response = await api.post( + API_ENDPOINTS.routes.ROLE_ASSIGN_ROLE_USERS, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/roomapi.js b/src/api/roomapi.js index b3e8aef..4818ea6 100644 --- a/src/api/roomapi.js +++ b/src/api/roomapi.js @@ -1,9 +1,12 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取房间列表 export const fetchRooms = async (params) => { try { - const response = await api.get("/Room/SelectRoomAll", { params }); + const response = await api.get(API_ENDPOINTS.routes.ROOM_SELECT_ROOM_ALL, { + params, + }); return response.data.Data; } catch (error) { throw error; @@ -13,7 +16,12 @@ export const fetchRooms = async (params) => { // 获取可使用房间列表 export const fetchAvailableRooms = async (params) => { try { - const response = await api.get("/Room/SelectCanUseRoomAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.ROOM_SELECT_CAN_USE_ROOM_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -23,7 +31,10 @@ export const fetchAvailableRooms = async (params) => { // 添加房间 export const addRoom = async (data) => { try { - const response = await api.post("/Room/InsertRoom", data); + const response = await api.post( + API_ENDPOINTS.routes.ROOM_INSERT_ROOM, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +44,10 @@ export const addRoom = async (data) => { // 更新房间 export const updateRoom = async (data) => { try { - const response = await api.post(`/Room/UpdateRoom`, data); + const response = await api.post( + API_ENDPOINTS.routes.ROOM_UPDATE_ROOM, + data, + ); return response.data; } catch (error) { throw error; @@ -43,7 +57,10 @@ export const updateRoom = async (data) => { // 删除房间 export const deleteRoom = async (data) => { try { - const response = await api.post(`/Room/DeleteRoom`, data); + const response = await api.post( + API_ENDPOINTS.routes.ROOM_DELETE_ROOM, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/roomstateapi.js b/src/api/roomstateapi.js index 0bddc3d..82a300c 100644 --- a/src/api/roomstateapi.js +++ b/src/api/roomstateapi.js @@ -1,9 +1,12 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取房间状态列表 export const fetchRoomStates = async () => { try { - const response = await api.get("/Base/SelectRoomStateAll"); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_ROOM_STATE_ALL, + ); return response.data.Data; } catch (error) { throw error; diff --git a/src/api/roomtypeapi.js b/src/api/roomtypeapi.js index 78a4356..68fae87 100644 --- a/src/api/roomtypeapi.js +++ b/src/api/roomtypeapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取房间类型列表 export const fetchRoomTypes = async (params) => { try { - const response = await api.get("/RoomType/SelectRoomTypesAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.ROOM_TYPE_SELECT_ROOM_TYPES_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchRoomTypes = async (params) => { // 添加房间类型 export const addRoomType = async (data) => { try { - const response = await api.post("/RoomType/InsertRoomType", data); + const response = await api.post( + API_ENDPOINTS.routes.ROOM_TYPE_INSERT_ROOM_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addRoomType = async (data) => { // 更新房间类型 export const updateRoomType = async (data) => { try { - const response = await api.post(`/RoomType/UpdateRoomType`, data); + const response = await api.post( + API_ENDPOINTS.routes.ROOM_TYPE_UPDATE_ROOM_TYPE, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +45,10 @@ export const updateRoomType = async (data) => { // 删除房间类型 export const deleteRoomType = async (data) => { try { - const response = await api.post(`/RoomType/DeleteRoomType`, data); + const response = await api.post( + API_ENDPOINTS.routes.ROOM_TYPE_DELETE_ROOM_TYPE, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/spendinfoapi.js b/src/api/spendinfoapi.js index f2424d5..f70d57a 100644 --- a/src/api/spendinfoapi.js +++ b/src/api/spendinfoapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取消费信息列表 export const fetchSpendInfos = async (params) => { try { - const response = await api.get("/Spend/SelectSpendInfoAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.SPEND_SELECT_SPEND_INFO_ALL, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchSpendInfos = async (params) => { // 添加消费信息 export const addSpendInfo = async (data) => { try { - const response = await api.post("/Spend/InsertSpendInfo", data); + const response = await api.post( + API_ENDPOINTS.routes.SPEND_INSERT_SPEND_INFO, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addSpendInfo = async (data) => { // 更新消费信息 export const updateSpendInfo = async (data) => { try { - const response = await api.post(`/Spend/UpdSpendInfo`, data); + const response = await api.post( + API_ENDPOINTS.routes.SPEND_UPD_SPEND_INFO, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/supervisioninfoapi.js b/src/api/supervisioninfoapi.js index b5794b2..a40412b 100644 --- a/src/api/supervisioninfoapi.js +++ b/src/api/supervisioninfoapi.js @@ -1,10 +1,12 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取监管统计列表 export const fetchSupervisionInfos = async (params) => { try { const response = await api.get( - "/SupervisionStatistics/SelectSupervisionStatisticsAll", + API_ENDPOINTS.routes + .SUPERVISION_STATISTICS_SELECT_SUPERVISION_STATISTICS_ALL, { params }, ); return response.data.Data; @@ -17,7 +19,7 @@ export const fetchSupervisionInfos = async (params) => { export const addSupervisionInfo = async (data) => { try { const response = await api.post( - "/SupervisionStatistics/InsertSupervisionStatistics", + API_ENDPOINTS.routes.SUPERVISION_STATISTICS_INSERT_SUPERVISION_STATISTICS, data, ); return response.data; @@ -30,7 +32,7 @@ export const addSupervisionInfo = async (data) => { export const updateSupervisionInfo = async (data) => { try { const response = await api.post( - `/SupervisionStatistics/UpdateSupervisionStatistics`, + API_ENDPOINTS.routes.SUPERVISION_STATISTICS_UPDATE_SUPERVISION_STATISTICS, data, ); return response.data; @@ -43,7 +45,7 @@ export const updateSupervisionInfo = async (data) => { export const deleteSupervisionInfo = async (data) => { try { const response = await api.post( - `/SupervisionStatistics/DeleteSupervisionStatistics`, + API_ENDPOINTS.routes.SUPERVISION_STATISTICS_DELETE_SUPERVISION_STATISTICS, data, ); return response.data; diff --git a/src/api/utilityapi.js b/src/api/utilityapi.js index 5261438..3f3df4f 100644 --- a/src/api/utilityapi.js +++ b/src/api/utilityapi.js @@ -1,11 +1,13 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取操作日志列表 export const fetchOperationlogs = async (params) => { try { - const response = await api.get("/Utility/SelectOperationlogAll", { - params, - }); + const response = await api.get( + API_ENDPOINTS.routes.UTILITY_SELECT_OPERATIONLOG_ALL, + { params }, + ); return response.data.Data; } catch (error) { throw error; @@ -15,7 +17,10 @@ export const fetchOperationlogs = async (params) => { // 获取请求日志列表 export const fetchRequestlogs = async (params) => { try { - const response = await api.get("/Utility/SelectRequestlogAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.UTILITY_SELECT_REQUESTLOG_ALL, + { params }, + ); return response.data.Data; } catch (error) { throw error; @@ -25,7 +30,10 @@ export const fetchRequestlogs = async (params) => { // 获取身份证地区代码 export const fetchCardCode = async (cardcode) => { try { - const response = await api.post("/Utility/SelectCardCode", cardcode); + const response = await api.post( + API_ENDPOINTS.routes.UTILITY_SELECT_CARD_CODE, + cardcode, + ); return response.data; } catch (error) { throw error; @@ -36,7 +44,7 @@ export const fetchCardCode = async (cardcode) => { export const deleteOperationlogByRange = async (operationlog) => { try { const response = await api.post( - "/Utility/DeleteOperationlogByRange", + API_ENDPOINTS.routes.UTILITY_DELETE_OPERATIONLOG_BY_RANGE, operationlog, ); return response.data; @@ -49,7 +57,7 @@ export const deleteOperationlogByRange = async (operationlog) => { export const deleteOperationlog = async (operationlog) => { try { const response = await api.post( - "/Utility/DeleteOperationlog", + API_ENDPOINTS.routes.UTILITY_DELETE_OPERATIONLOG, operationlog, ); return response.data; diff --git a/src/api/vipruleapi.js b/src/api/vipruleapi.js index d96e262..8a072ae 100644 --- a/src/api/vipruleapi.js +++ b/src/api/vipruleapi.js @@ -1,9 +1,15 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取会员规则列表 export const fetchVipRules = async (params) => { try { - const response = await api.get("/VipRule/SelectVipRuleList", { params }); + const response = await api.get( + API_ENDPOINTS.routes.VIP_RULE_SELECT_VIP_RULE_LIST, + { + params, + }, + ); return response.data.Data; } catch (error) { throw error; @@ -13,7 +19,10 @@ export const fetchVipRules = async (params) => { // 添加会员规则 export const addVipRule = async (data) => { try { - const response = await api.post("/VipRule/AddVipRule", data); + const response = await api.post( + API_ENDPOINTS.routes.VIP_RULE_ADD_VIP_RULE, + data, + ); return response.data; } catch (error) { throw error; @@ -23,7 +32,10 @@ export const addVipRule = async (data) => { // 更新会员规则 export const updateVipRule = async (data) => { try { - const response = await api.post(`/VipRule/UpdVipRule`, data); + const response = await api.post( + API_ENDPOINTS.routes.VIP_RULE_UPD_VIP_RULE, + data, + ); return response.data; } catch (error) { throw error; @@ -33,7 +45,10 @@ export const updateVipRule = async (data) => { // 删除会员规则 export const deleteVipRule = async (data) => { try { - const response = await api.post(`/VipRule/DelVipRule`, data); + const response = await api.post( + API_ENDPOINTS.routes.VIP_RULE_DEL_VIP_RULE, + data, + ); return response.data; } catch (error) { throw error; diff --git a/src/api/workerfeatureapi.js b/src/api/workerfeatureapi.js index dd2ecec..d75993c 100644 --- a/src/api/workerfeatureapi.js +++ b/src/api/workerfeatureapi.js @@ -1,9 +1,13 @@ import api from "../api"; +import { API_ENDPOINTS } from "../config/apiEndpoints"; // 获取面貌列表 export const fetchWorkerFeatures = async (params) => { try { - const response = await api.get("/Base/SelectWorkerFeatureAll", { params }); + const response = await api.get( + API_ENDPOINTS.routes.BASE_SELECT_WORKER_FEATURE_ALL, + { params }, + ); return response.data.Data; } catch (error) { throw error; diff --git a/src/config/apiEndpoints.js b/src/config/apiEndpoints.js new file mode 100644 index 0000000..4485348 --- /dev/null +++ b/src/config/apiEndpoints.js @@ -0,0 +1,190 @@ +const ROUTES = { + ADMIN_ADD_ADMIN: "/Admin/AddAdmin", + ADMIN_ADD_ADMIN_TYPE: "/Admin/AddAdminType", + ADMIN_ASSIGN_USER_PERMISSIONS: "/Admin/AssignUserPermissions", + ADMIN_ASSIGN_USER_ROLES: "/Admin/AssignUserRoles", + ADMIN_DEL_ADMIN: "/Admin/DelAdmin", + ADMIN_DEL_ADMIN_TYPE: "/Admin/DelAdminType", + ADMIN_GET_ALL_ADMIN_LIST: "/Admin/GetAllAdminList", + ADMIN_GET_ALL_ADMIN_TYPES: "/Admin/GetAllAdminTypes", + ADMIN_LOGIN: "/Admin/Login", + ADMIN_LOGOUT: "/Admin/Logout", + ADMIN_READ_USER_DIRECT_PERMISSIONS: "/Admin/ReadUserDirectPermissions", + ADMIN_READ_USER_ROLE_PERMISSIONS: "/Admin/ReadUserRolePermissions", + ADMIN_READ_USER_ROLES: "/Admin/ReadUserRoles", + ADMIN_UPD_ADMIN: "/Admin/UpdAdmin", + ADMIN_UPD_ADMIN_TYPE: "/Admin/UpdAdminType", + ASSET_ADD_ASSET_INFO: "/Asset/AddAssetInfo", + ASSET_DEL_ASSET_INFO: "/Asset/DelAssetInfo", + ASSET_SELECT_ASSET_INFO_ALL: "/Asset/SelectAssetInfoAll", + ASSET_UPD_ASSET_INFO: "/Asset/UpdAssetInfo", + BASE_ADD_DEPT: "/Base/AddDept", + BASE_ADD_EDUCATION: "/Base/AddEducation", + BASE_ADD_NATION: "/Base/AddNation", + BASE_ADD_POSITION: "/Base/AddPosition", + BASE_CREATE_APPOINTMENT_NOTICE_TYPE: "/Base/CreateAppointmentNoticeType", + BASE_DEL_DEPT: "/Base/DelDept", + BASE_DEL_EDUCATION: "/Base/DelEducation", + BASE_DEL_NATION: "/Base/DelNation", + BASE_DEL_POSITION: "/Base/DelPosition", + BASE_DELETE_APPOINTMENT_NOTICE_TYPE: "/Base/DeleteAppointmentNoticeType", + BASE_DELETE_CUSTO_TYPE: "/Base/DeleteCustoType", + BASE_DELETE_PASS_PORT_TYPE: "/Base/DeletePassPortType", + BASE_INSERT_CUSTO_TYPE: "/Base/InsertCustoType", + BASE_INSERT_PASS_PORT_TYPE: "/Base/InsertPassPortType", + BASE_SELECT_APPOINTMENT_NOTICE_TYPE_ALL: + "/Base/SelectAppointmentNoticeTypeAll", + BASE_SELECT_CUSTO_TYPE_ALL: "/Base/SelectCustoTypeAll", + BASE_SELECT_CUSTO_TYPE_ALL_CAN_USE: "/Base/SelectCustoTypeAllCanUse", + BASE_SELECT_DEPT_ALL: "/Base/SelectDeptAll", + BASE_SELECT_EDUCATION_ALL: "/Base/SelectEducationAll", + BASE_SELECT_NATION_ALL: "/Base/SelectNationAll", + BASE_SELECT_PASS_PORT_TYPE_ALL: "/Base/SelectPassPortTypeAll", + BASE_SELECT_PASS_PORT_TYPE_ALL_CAN_USE: "/Base/SelectPassPortTypeAllCanUse", + BASE_SELECT_POSITION_ALL: "/Base/SelectPositionAll", + BASE_SELECT_ROOM_STATE_ALL: "/Base/SelectRoomStateAll", + BASE_SELECT_WORKER_FEATURE_ALL: "/Base/SelectWorkerFeatureAll", + BASE_UPD_DEPT: "/Base/UpdDept", + BASE_UPD_EDUCATION: "/Base/UpdEducation", + BASE_UPD_NATION: "/Base/UpdNation", + BASE_UPD_POSITION: "/Base/UpdPosition", + BASE_UPDATE_APPOINTMENT_NOTICE_TYPE: "/Base/UpdateAppointmentNoticeType", + BASE_UPDATE_CUSTO_TYPE: "/Base/UpdateCustoType", + BASE_UPDATE_PASS_PORT_TYPE: "/Base/UpdatePassPortType", + CUSTOMER_DEL_CUSTOMER_INFO: "/Customer/DelCustomerInfo", + CUSTOMER_INSERT_CUSTOMER_INFO: "/Customer/InsertCustomerInfo", + CUSTOMER_SELECT_CUSTOMERS: "/Customer/SelectCustomers", + CUSTOMER_UPD_CUSTOMER_INFO: "/Customer/UpdCustomerInfo", + CUSTOMER_PERMISSION_ASSIGN_USER_PERMISSIONS: + "/CustomerPermission/AssignUserPermissions", + CUSTOMER_PERMISSION_ASSIGN_USER_ROLES: "/CustomerPermission/AssignUserRoles", + CUSTOMER_PERMISSION_READ_USER_DIRECT_PERMISSIONS: + "/CustomerPermission/ReadUserDirectPermissions", + CUSTOMER_PERMISSION_READ_USER_ROLE_PERMISSIONS: + "/CustomerPermission/ReadUserRolePermissions", + CUSTOMER_PERMISSION_READ_USER_ROLES: "/CustomerPermission/ReadUserRoles", + DASHBOARD_BUSINESS_STATISTICS: "/Dashboard/BusinessStatistics", + DASHBOARD_HUMAN_RESOURCES_STATISTICS: "/Dashboard/HumanResourcesStatistics", + DASHBOARD_LOGISTICS_STATISTICS: "/Dashboard/LogisticsStatistics", + DASHBOARD_ROOM_STATISTICS: "/Dashboard/RoomStatistics", + EMPLOYEE_ADD_EMPLOYEE: "/Employee/AddEmployee", + EMPLOYEE_EMPLOYEE_LOGIN: "/Employee/EmployeeLogin", + EMPLOYEE_MANAGER_EMPLOYEE_ACCOUNT: "/Employee/ManagerEmployeeAccount", + EMPLOYEE_RESET_EMPLOYEE_ACCOUNT_PASSWORD: + "/Employee/ResetEmployeeAccountPassword", + EMPLOYEE_SELECT_EMPLOYEE_ALL: "/Employee/SelectEmployeeAll", + EMPLOYEE_SELECT_EMPLOYEE_INFO_BY_EMPLOYEE_ID: + "/Employee/SelectEmployeeInfoByEmployeeId", + EMPLOYEE_UPDATE_EMPLOYEE: "/Employee/UpdateEmployee", + EMPLOYEE_CHECK_SELECT_CHECK_INFO_BY_EMPLOYEE_ID: + "/EmployeeCheck/SelectCheckInfoByEmployeeId", + EMPLOYEE_HISTORY_SELECT_HISTORY_BY_EMPLOYEE_ID: + "/EmployeeHistory/SelectHistoryByEmployeeId", + EMPLOYEE_PERMISSION_ASSIGN_USER_PERMISSIONS: + "/EmployeePermission/AssignUserPermissions", + EMPLOYEE_PERMISSION_ASSIGN_USER_ROLES: "/EmployeePermission/AssignUserRoles", + EMPLOYEE_PERMISSION_READ_USER_DIRECT_PERMISSIONS: + "/EmployeePermission/ReadUserDirectPermissions", + EMPLOYEE_PERMISSION_READ_USER_ROLE_PERMISSIONS: + "/EmployeePermission/ReadUserRolePermissions", + EMPLOYEE_PERMISSION_READ_USER_ROLES: "/EmployeePermission/ReadUserRoles", + EMPLOYEE_PHOTO_INSERT_WORKER_PHOTO: "/EmployeePhoto/InsertWorkerPhoto", + ENERGY_MANAGEMENT_DELETE_ENERGY_MANAGEMENT_INFO: + "/EnergyManagement/DeleteEnergyManagementInfo", + ENERGY_MANAGEMENT_INSERT_ENERGY_MANAGEMENT_INFO: + "/EnergyManagement/InsertEnergyManagementInfo", + ENERGY_MANAGEMENT_SELECT_ENERGY_MANAGEMENT_INFO: + "/EnergyManagement/SelectEnergyManagementInfo", + ENERGY_MANAGEMENT_UPDATE_ENERGY_MANAGEMENT_INFO: + "/EnergyManagement/UpdateEnergyManagementInfo", + LOGIN_GET_CSRF_TOKEN: "/Login/GetCSRFToken", + LOGIN_REFRESH_CSRF_TOKEN: "/Login/RefreshCSRFToken", + MENU_BUILD_MENU_ALL: "/Menu/BuildMenuAll", + MENU_DELETE_MENU: "/Menu/DeleteMenu", + MENU_INSERT_MENU: "/Menu/InsertMenu", + MENU_SELECT_MENU_ALL: "/Menu/SelectMenuAll", + MENU_UPDATE_MENU: "/Menu/UpdateMenu", + PERMISSION_SELECT_PERMISSION_LIST: "/Permission/SelectPermissionList", + PROMOTION_CONTENT_ADD_PROMOTION_CONTENT: + "/PromotionContent/AddPromotionContent", + PROMOTION_CONTENT_DELETE_PROMOTION_CONTENT: + "/PromotionContent/DeletePromotionContent", + PROMOTION_CONTENT_SELECT_PROMOTION_CONTENT_ALL: + "/PromotionContent/SelectPromotionContentAll", + PROMOTION_CONTENT_UPDATE_PROMOTION_CONTENT: + "/PromotionContent/UpdatePromotionContent", + RESER_DELETE_RESER_INFO: "/Reser/DeleteReserInfo", + RESER_INSER_RESER_INFO: "/Reser/InserReserInfo", + RESER_SELECT_RESER_ALL: "/Reser/SelectReserAll", + RESER_SELECT_RESER_TYPE_ALL: "/Reser/SelectReserTypeAll", + RESER_UPDATE_RESER_INFO: "/Reser/UpdateReserInfo", + REWARD_PUNISHMENT_SELECT_ALL_REWARD_PUNISHMENT_BY_EMPLOYEE_ID: + "/RewardPunishment/SelectAllRewardPunishmentByEmployeeId", + ROLE_ASSIGN_ROLE_USERS: "/Role/AssignRoleUsers", + ROLE_DELETE_ROLE: "/Role/DeleteRole", + ROLE_GRANT_ROLE_PERMISSIONS: "/Role/GrantRolePermissions", + ROLE_INSERT_ROLE: "/Role/InsertRole", + ROLE_READ_ROLE_PERMISSIONS: "/Role/ReadRolePermissions", + ROLE_READ_ROLE_USERS: "/Role/ReadRoleUsers", + ROLE_SELECT_ROLE_LIST: "/Role/SelectRoleList", + ROLE_UPDATE_ROLE: "/Role/UpdateRole", + ROOM_DELETE_ROOM: "/Room/DeleteRoom", + ROOM_INSERT_ROOM: "/Room/InsertRoom", + ROOM_SELECT_CAN_USE_ROOM_ALL: "/Room/SelectCanUseRoomAll", + ROOM_SELECT_ROOM_ALL: "/Room/SelectRoomAll", + ROOM_UPDATE_ROOM: "/Room/UpdateRoom", + ROOM_TYPE_DELETE_ROOM_TYPE: "/RoomType/DeleteRoomType", + ROOM_TYPE_INSERT_ROOM_TYPE: "/RoomType/InsertRoomType", + ROOM_TYPE_SELECT_ROOM_TYPES_ALL: "/RoomType/SelectRoomTypesAll", + ROOM_TYPE_UPDATE_ROOM_TYPE: "/RoomType/UpdateRoomType", + SELLTHING_DELETE_SELLTHING: "/Sellthing/DeleteSellthing", + SELLTHING_INSERT_SELLTHING: "/Sellthing/InsertSellthing", + SELLTHING_SELECT_SELLTHING_ALL: "/Sellthing/SelectSellthingAll", + SELLTHING_UPDATE_SELLTHING: "/Sellthing/UpdateSellthing", + SPEND_INSERT_SPEND_INFO: "/Spend/InsertSpendInfo", + SPEND_SELECT_SPEND_INFO_ALL: "/Spend/SelectSpendInfoAll", + SPEND_UPD_SPEND_INFO: "/Spend/UpdSpendInfo", + SUPERVISION_STATISTICS_DELETE_SUPERVISION_STATISTICS: + "/SupervisionStatistics/DeleteSupervisionStatistics", + SUPERVISION_STATISTICS_INSERT_SUPERVISION_STATISTICS: + "/SupervisionStatistics/InsertSupervisionStatistics", + SUPERVISION_STATISTICS_SELECT_SUPERVISION_STATISTICS_ALL: + "/SupervisionStatistics/SelectSupervisionStatisticsAll", + SUPERVISION_STATISTICS_UPDATE_SUPERVISION_STATISTICS: + "/SupervisionStatistics/UpdateSupervisionStatistics", + UTILITY_DELETE_OPERATIONLOG: "/Utility/DeleteOperationlog", + UTILITY_DELETE_OPERATIONLOG_BY_RANGE: "/Utility/DeleteOperationlogByRange", + UTILITY_SELECT_CARD_CODE: "/Utility/SelectCardCode", + UTILITY_SELECT_OPERATIONLOG_ALL: "/Utility/SelectOperationlogAll", + UTILITY_SELECT_REQUESTLOG_ALL: "/Utility/SelectRequestlogAll", + VIP_RULE_ADD_VIP_RULE: "/VipRule/AddVipRule", + VIP_RULE_DEL_VIP_RULE: "/VipRule/DelVipRule", + VIP_RULE_SELECT_VIP_RULE_LIST: "/VipRule/SelectVipRuleList", + VIP_RULE_UPD_VIP_RULE: "/VipRule/UpdVipRule", + VERSION: "/version", +}; + +export const API_ENDPOINTS = { + routes: ROUTES, + login: { + admin: ROUTES.ADMIN_LOGIN, + employee: ROUTES.EMPLOYEE_EMPLOYEE_LOGIN, + }, + twoFactor: { + admin: "Admin", + employee: "Employee", + }, + loginTypes: { + admin: "admin", + employee: "employee", + }, + dynamic: { + getTwoFactorStatus: (controller) => `/${controller}/GetTwoFactorStatus`, + generateTwoFactorSetup: (controller) => + `/${controller}/GenerateTwoFactorSetup`, + enableTwoFactor: (controller) => `/${controller}/EnableTwoFactor`, + disableTwoFactor: (controller) => `/${controller}/DisableTwoFactor`, + regenerateTwoFactorRecoveryCodes: (controller) => + `/${controller}/RegenerateTwoFactorRecoveryCodes`, + }, +}; diff --git a/src/directives/permission.js b/src/directives/permission.js index d05c1cc..9d3bce3 100644 --- a/src/directives/permission.js +++ b/src/directives/permission.js @@ -1,40 +1,62 @@ -import { getAllowedMenuKeys, getAllowedPerms } from "@/utils/permission"; +import { hasPermission } from "@/utils/permission"; /** - * v-perm 指令:支持菜单键或按钮权限码两种来源 - * - 传入 string 或 string[],例如:v-perm="'system:role:grant'" 或 v-perm="['department.create','department.update']" - * - .all 修饰符表示需要全部命中(默认任意命中其一即可) + * v-perm directive: supports both menu keys and button permission codes. + * - accepts string or string[], e.g. v-perm="'system:role:grant'" + * - .all modifier means all required keys must match. */ function isPermitted(required, needAll = false) { - // 未配置要求时默认放行(方便逐步接入) - if (!required || (Array.isArray(required) && required.length === 0)) - return true; - - // 合并“菜单键集合 + 按钮权限码集合” - const allowedSet = new Set([...getAllowedMenuKeys(), ...getAllowedPerms()]); + return hasPermission(required, needAll); +} - // 首屏或尚未拉取权限列表时(两个集合都为空)默认放行,避免按钮被永久隐藏 - if (allowedSet.size === 0) { - return true; +function applyPermission(el, required, needAll) { + const permitted = isPermitted(required, needAll); + if (!permitted) { + el.style.display = "none"; + el.setAttribute("data-permission-hidden", "true"); + return; } - const reqList = Array.isArray(required) ? required : [required]; - - if (needAll) { - return reqList.every((k) => allowedSet.has(k)); + if (el.getAttribute("data-permission-hidden") === "true") { + const originalDisplay = + el.__permState && typeof el.__permState.originalDisplay === "string" + ? el.__permState.originalDisplay + : ""; + el.style.display = originalDisplay; + el.removeAttribute("data-permission-hidden"); } - return reqList.some((k) => allowedSet.has(k)); } export default { beforeMount(el, binding) { - const required = binding.value; - const needAll = !!binding.modifiers.all; + const state = { + required: binding.value, + needAll: !!binding.modifiers.all, + originalDisplay: el.style.display || "", + handler: null, + }; + + state.handler = () => { + applyPermission(el, state.required, state.needAll); + }; - const permitted = isPermitted(required, needAll); - if (!permitted) { - el.style.display = "none"; - el.setAttribute("data-permission-hidden", "true"); + el.__permState = state; + window.addEventListener("permissions-updated", state.handler); + state.handler(); + }, + updated(el, binding) { + if (!el.__permState) { + return; + } + + el.__permState.required = binding.value; + el.__permState.needAll = !!binding.modifiers.all; + applyPermission(el, el.__permState.required, el.__permState.needAll); + }, + unmounted(el) { + if (el.__permState?.handler) { + window.removeEventListener("permissions-updated", el.__permState.handler); } + delete el.__permState; }, }; diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index a3bd4aa..f34725f 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -247,6 +247,18 @@ import { } from "@/utils/index"; import { fetchMenusTree } from "../api/menuapi"; import { BaseFields } from "@/entities/common.entity"; +import { + readUserDirectPermissions as readAdminUserDirectPermissions, + readUserRolePermissions as readAdminUserRolePermissions, +} from "@/api/administratorapi"; +import { + readUserDirectPermissions as readEmployeeUserDirectPermissions, + readUserRolePermissions as readEmployeeUserRolePermissions, +} from "@/api/employeepermissionapi"; +import { + readUserDirectPermissions as readCustomerUserDirectPermissions, + readUserRolePermissions as readCustomerUserRolePermissions, +} from "@/api/customerpermissionapi"; import { AdministratorManagementPermissions, StaffManagementPermissions, @@ -426,6 +438,85 @@ const parseStoredAllowedPermissions = () => { } }; +const unique = (arr) => Array.from(new Set((arr || []).filter(Boolean))); + +const extractPermissionCodes = (items) => + unique( + (Array.isArray(items) ? items : []) + .map((item) => + typeof item === "string" + ? item + : item?.PermissionNumber || item?.PermissionCode || "", + ) + .filter(Boolean), + ); + +const decodeJwtPayload = (token) => { + try { + const payload = token?.split(".")?.[1]; + if (!payload) return null; + const base64 = payload.replace(/-/g, "+").replace(/_/g, "/"); + const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "="); + return JSON.parse(window.atob(padded)); + } catch (error) { + return null; + } +}; + +const fetchCurrentUserPermissionCodes = async () => { + const permissionReadersByLoginType = { + admin: { + readRolePermissions: readAdminUserRolePermissions, + readDirectPermissions: readAdminUserDirectPermissions, + }, + employee: { + readRolePermissions: readEmployeeUserRolePermissions, + readDirectPermissions: readEmployeeUserDirectPermissions, + }, + customer: { + readRolePermissions: readCustomerUserRolePermissions, + readDirectPermissions: readCustomerUserDirectPermissions, + }, + }; + + const readers = + permissionReadersByLoginType[loginType.value] || + permissionReadersByLoginType.admin; + + const tokenPayload = decodeJwtPayload(localStorage.getItem("token") || ""); + const identityCandidates = unique([ + localStorage.getItem("account"), + tokenPayload?.UserNumber, + tokenPayload?.userNumber, + tokenPayload?.Account, + tokenPayload?.account, + tokenPayload?.EmployeeId, + tokenPayload?.employeeId, + tokenPayload?.nameid, + tokenPayload?.sub, + ]); + + for (const identity of identityCandidates) { + try { + const [rolePermissions, directPermissions] = await Promise.all([ + readers.readRolePermissions(identity), + readers.readDirectPermissions(identity), + ]); + + const mergedCodes = unique([ + ...extractPermissionCodes(rolePermissions), + ...extractPermissionCodes(directPermissions), + ]); + + return { ok: true, codes: mergedCodes }; + } catch (error) { + // Try next candidate identity. + } + } + + return { ok: false, codes: [] }; +}; + const syncAllowedPermissions = () => { allowedPermissionCodes.value = parseStoredAllowedPermissions(); }; @@ -511,15 +602,32 @@ const refreshMenu = async () => { }; const { keys, paths, perms } = collect(menuData.value, [], [], []); - const unique = (arr) => Array.from(new Set(arr.filter(Boolean))); const allowedMenuKeys = unique(keys); const allowedPaths = unique(paths).map((p) => (p || "").replace(/\/$/, "")); - const allowedPermList = unique(perms); + const allowedPermListFromMenu = unique(perms); + const syncedPermissionCodes = await fetchCurrentUserPermissionCodes(); + const allowedPermList = syncedPermissionCodes.ok + ? syncedPermissionCodes.codes + : allowedPermListFromMenu; localStorage.setItem("allowedMenuKeys", JSON.stringify(allowedMenuKeys)); localStorage.setItem("allowedPaths", JSON.stringify(allowedPaths)); localStorage.setItem("allowedPerms", JSON.stringify(allowedPermList)); + localStorage.setItem( + "allowedPathsToken", + localStorage.getItem("token") || "", + ); allowedPermissionCodes.value = allowedPermList; + window.dispatchEvent(new Event("permissions-updated")); + + const normalize = (p) => (p || "").replace(/\/$/, ""); + const currentPath = normalize(router.currentRoute.value.path); + const hasDashboardPath = allowedPaths.some( + (path) => normalize(path) === "/dashboard", + ); + if (currentPath === "/dashboard" && !hasDashboardPath) { + await router.replace("/home"); + } // 3) 还原展开状态 openKeys.value = currentOpenKeys; @@ -581,7 +689,12 @@ const updateTwoFactorRecoveryCode = (value) => { twoFactorRecoveryCode.value = normalizeCodeOrRecoveryCode(value); }; -const copyTextWithExecCommand = (text) => { +const copyTextWithClipboard = async (text) => { + if (navigator?.clipboard?.writeText) { + await navigator.clipboard.writeText(text); + return true; + } + const textArea = document.createElement("textarea"); textArea.value = text; textArea.style.position = "fixed"; @@ -589,9 +702,14 @@ const copyTextWithExecCommand = (text) => { document.body.appendChild(textArea); textArea.focus(); textArea.select(); - const copied = document.execCommand("copy"); - document.body.removeChild(textArea); - return copied; + + try { + return document.execCommand("copy"); + } catch (error) { + return false; + } finally { + document.body.removeChild(textArea); + } }; const copyAllRecoveryCodes = async () => { @@ -601,9 +719,8 @@ const copyAllRecoveryCodes = async () => { } try { - if (navigator?.clipboard?.writeText) { - await navigator.clipboard.writeText(content); - } else if (!copyTextWithExecCommand(content)) { + const copied = await copyTextWithClipboard(content); + if (!copied) { throw new Error("Copy failed"); } showSuccessNotification(t("message.recoveryCodesCopiedSuccess")); @@ -783,6 +900,7 @@ const checkLoginStatus = () => { loginType.value = "admin"; allowedPermissionCodes.value = []; username.value = ""; + localStorage.removeItem("allowedPathsToken"); } }; @@ -799,6 +917,7 @@ const logout = async () => { localStorage.removeItem("allowedPaths"); localStorage.removeItem("allowedMenuKeys"); localStorage.removeItem("allowedPerms"); + localStorage.removeItem("allowedPathsToken"); isLoggedIn.value = false; allowedPermissionCodes.value = []; username.value = ""; diff --git a/src/router/index.js b/src/router/index.js index 9d66eee..d9296e1 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -68,6 +68,7 @@ const CustomerAccountPermission = () => const EmployeeAccountPermission = () => import("../views/systemmanagement/EmployeeAccountPermissionView.vue"); +const Home = () => import("../views/home/HomeView.vue"); const Dashboard = () => import("../views/dashboard/DashboardView.vue"); const routes = [ @@ -260,6 +261,12 @@ const routes = [ component: EmployeeAccountPermission, meta: { requiresAuth: true, requiredPerm: "system:user:assign.view" }, }, + { + path: "/home", + name: "home", + component: Home, + meta: { requiresAuth: true, ignoreAllowedPaths: true }, + }, { path: "/dashboard", name: "dashboard", @@ -303,6 +310,10 @@ router.beforeEach((to, from, next) => { } // 支持基于"权限码或菜单键"直达的路由控制(未出现在菜单里的独立页面) + if (to.meta && to.meta.ignoreAllowedPaths) { + return next(); + } + const requiredPerm = to.meta && to.meta.requiredPerm; if (requiredPerm && hasPermission(requiredPerm)) { return next(); @@ -310,11 +321,25 @@ router.beforeEach((to, from, next) => { // 基于后端返回的菜单(权限)结果做前端路由访问控制(路径白名单) const raw = localStorage.getItem("allowedPaths"); + const currentToken = localStorage.getItem("token") || ""; + const allowedPathsToken = localStorage.getItem("allowedPathsToken") || ""; + const hasAllowedPathsCache = + raw !== null && + allowedPathsToken.length > 0 && + allowedPathsToken === currentToken; const parsed = raw ? JSON.parse(raw) : []; const allowedPaths = Array.isArray(parsed) ? parsed : []; - // 尚未拉取菜单(例如刚进入系统时),先放行,由主布局内拉取并写入 - if (allowedPaths.length > 0) { + // 尚未初始化权限缓存时(例如刚进入系统),先放行。 + // 已初始化但为空数组时,说明当前账号没有可访问路径,应拦截。 + if (hasAllowedPathsCache) { + if (allowedPaths.length === 0) { + if ((to.path || "").replace(/\/$/, "") === "/dashboard") { + return next({ path: "/home" }); + } + return next({ name: "NotFound" }); + } + const normalize = (p) => (p || "").replace(/\/$/, ""); const current = normalize(to.path); @@ -327,6 +352,9 @@ router.beforeEach((to, from, next) => { .some((p) => matchPath(p, current)); if (!permitted) { + if (current === "/dashboard") { + return next({ path: "/home" }); + } return next({ name: "NotFound" }); } } diff --git a/src/utils/auth.js b/src/utils/auth.js index 5803819..22a7aca 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -34,6 +34,7 @@ export async function handleLogout() { localStorage.removeItem("allowedPerms"); localStorage.removeItem("allowedPaths"); localStorage.removeItem("allowedMenuKeys"); + localStorage.removeItem("allowedPathsToken"); // 重定向到登录页 router.push("/signin"); } diff --git a/src/utils/permission.js b/src/utils/permission.js index fc1bff8..090da8b 100644 --- a/src/utils/permission.js +++ b/src/utils/permission.js @@ -18,6 +18,13 @@ export function getAllowedPerms() { } } +export function isPermissionCacheInitialized() { + return ( + localStorage.getItem("allowedPerms") !== null || + localStorage.getItem("allowedMenuKeys") !== null + ); +} + /** * 统一的权限判断:支持菜单键或按钮权限码;支持“任意命中/全部命中”两种模式 * - required: string | string[] @@ -33,7 +40,7 @@ export function hasPermission(required, needAll = false) { const allowedMenuKeys = getAllowedMenuKeys(); // 两者都还未初始化(首次进入系统、尚未拉取菜单)时默认放行,避免首屏闪烁/误隐藏 - if (allowedPerms.length === 0 && allowedMenuKeys.length === 0) { + if (!isPermissionCacheInitialized()) { return true; } diff --git a/src/views/SignInView.vue b/src/views/SignInView.vue index 60e780f..06e42fc 100644 --- a/src/views/SignInView.vue +++ b/src/views/SignInView.vue @@ -199,7 +199,15 @@ const clearTwoFactorChallenge = () => { pendingLoginContext.value = null; }; +const clearPermissionCache = () => { + localStorage.removeItem("allowedPaths"); + localStorage.removeItem("allowedMenuKeys"); + localStorage.removeItem("allowedPerms"); + localStorage.removeItem("allowedPathsToken"); +}; + const persistLoginData = async (userData, loginType) => { + clearPermissionCache(); localStorage.setItem("token", userData.UserToken); localStorage.setItem( "username", diff --git a/src/views/dashboard/DashboardView.vue b/src/views/dashboard/DashboardView.vue index bc64a51..bf20c7c 100644 --- a/src/views/dashboard/DashboardView.vue +++ b/src/views/dashboard/DashboardView.vue @@ -246,6 +246,7 @@ import { fetchLogisticsStatistics, fetchHumanResourcesStatistics, } from "@/api/dashboardapi"; +import { getApiMessage } from "@/api/baseapi"; import { formatDate, showErrorNotification, @@ -289,6 +290,20 @@ const chartInstances = { attendance: null, }; +const resolveErrorMessage = (payload) => { + const directMessage = getApiMessage(payload); + if (directMessage && directMessage !== "Request failed") { + return directMessage; + } + + const nestedMessage = getApiMessage(payload?.response?.data); + if (nestedMessage && nestedMessage !== "Request failed") { + return nestedMessage; + } + + return t("message.requestFailed"); +}; + const loadData = async () => { try { const [roomRes, bizRes, logRes, hrRes] = await Promise.all([ @@ -337,7 +352,7 @@ const loadData = async () => { recentRecords: logRes.Data.recentRecords || [], }; } else { - showErrorNotification(`后勤数据加载失败: ${logRes.Message}`); + showErrorNotification(resolveErrorMessage(logRes)); } if (hrRes.Success) { @@ -348,7 +363,7 @@ const loadData = async () => { }; } } catch (error) { - showErrorNotification(`数据加载失败: ${error.message}`); + showErrorNotification(resolveErrorMessage(error)); } finally { loading.value = false; } diff --git a/src/views/home/HomeView.vue b/src/views/home/HomeView.vue new file mode 100644 index 0000000..0c2cabc --- /dev/null +++ b/src/views/home/HomeView.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/src/views/systemmanagement/RoleManagementView.vue b/src/views/systemmanagement/RoleManagementView.vue index 08fd474..d3d2db1 100644 --- a/src/views/systemmanagement/RoleManagementView.vue +++ b/src/views/systemmanagement/RoleManagementView.vue @@ -303,6 +303,7 @@ import ListFilter from "@/components/common/ListFilter.vue"; import { getRoleFilterConfig } from "@/filters/role.filter.config"; import { RoleManagementPermissions } from "@/common/permissioncode"; import { debounce } from "lodash-es"; +import { emitter } from "@/utils/eventBus"; const { t } = useI18n(); const route = useRoute(); @@ -321,6 +322,10 @@ const selectedRecord = ref(null); const selectedRowKeys = ref([]); const selectedRows = ref([]); +const refreshCurrentSessionPermissions = () => { + emitter.emit("refresh-menu"); +}; + const currentFilterParams = reactive({}); const roleFilterConfig = computed(() => getRoleFilterConfig(t)); @@ -819,6 +824,7 @@ const handleRolePermSave = async () => { if (res && res.Success) { showSuccessNotification(t("message.updateSuccess")); rolePermModalVisible.value = false; + refreshCurrentSessionPermissions(); } else { showErrorNotification(res?.Message || t("message.operationFailed")); } @@ -1190,6 +1196,7 @@ const handleRoleUserSave = async () => { if (res && res.Success) { showSuccessNotification(t("message.updateSuccess")); roleUserModalVisible.value = false; + refreshCurrentSessionPermissions(); } else { showErrorNotification(res?.Message || t("message.operationFailed")); } diff --git a/src/views/systemmanagement/UnifiedAccountPermissionView.vue b/src/views/systemmanagement/UnifiedAccountPermissionView.vue index b8683e2..d316275 100644 --- a/src/views/systemmanagement/UnifiedAccountPermissionView.vue +++ b/src/views/systemmanagement/UnifiedAccountPermissionView.vue @@ -166,6 +166,7 @@ import { useRoute } from "vue-router"; import { useI18n } from "vue-i18n"; import { getPageTitle } from "@/utils/pageTitle"; import { showErrorNotification, showSuccessNotification } from "@/utils/index"; +import { emitter } from "@/utils/eventBus"; import { selectPermissionList } from "@/api/permissionapi"; import { AccountPermissionPermissions } from "@/common/permissioncode"; @@ -528,6 +529,10 @@ const listTitleText = computed(() => safeT(listTitleKey.value)); const waitSelectText = computed(() => safeT(waitSelectKey.value)); const selectedLabelText = computed(() => safeT(selectedLabelKey.value)); +const refreshCurrentSessionPermissions = () => { + emitter.emit("refresh-menu"); +}; + // 行选择(单选) const rowSelection = { type: "radio", @@ -655,6 +660,7 @@ const saveDirectPermissions = async () => { loadUserDirectPermissions(selectedUserNumber.value), loadUserRolePermissions(selectedUserNumber.value), ]); + refreshCurrentSessionPermissions(); } else { showErrorNotification(res?.Message || t("message.operationFailed")); } -- Gitee From 0cab442065b84151186c5c08efa9abe55cf31a82 Mon Sep 17 00:00:00 2001 From: ck_yeun9 Date: Tue, 17 Feb 2026 02:16:48 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=98=BB=E6=96=AD?= =?UTF-8?q?=E9=A1=B9=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/apiEndpoints.js | 261 +++++++++++++------------------------ src/config/apiRoutes.json | 141 ++++++++++++++++++++ src/i18n.js | 3 + src/layouts/MainLayout.vue | 165 ++++++++++++++--------- src/router/index.js | 8 +- src/utils/auth.js | 32 ++--- src/utils/jwt.js | 89 +++++++++++++ src/views/SignInView.vue | 2 + 8 files changed, 450 insertions(+), 251 deletions(-) create mode 100644 src/config/apiRoutes.json create mode 100644 src/utils/jwt.js diff --git a/src/config/apiEndpoints.js b/src/config/apiEndpoints.js index 4485348..fdb5bf6 100644 --- a/src/config/apiEndpoints.js +++ b/src/config/apiEndpoints.js @@ -1,174 +1,101 @@ -const ROUTES = { - ADMIN_ADD_ADMIN: "/Admin/AddAdmin", - ADMIN_ADD_ADMIN_TYPE: "/Admin/AddAdminType", - ADMIN_ASSIGN_USER_PERMISSIONS: "/Admin/AssignUserPermissions", - ADMIN_ASSIGN_USER_ROLES: "/Admin/AssignUserRoles", - ADMIN_DEL_ADMIN: "/Admin/DelAdmin", - ADMIN_DEL_ADMIN_TYPE: "/Admin/DelAdminType", - ADMIN_GET_ALL_ADMIN_LIST: "/Admin/GetAllAdminList", - ADMIN_GET_ALL_ADMIN_TYPES: "/Admin/GetAllAdminTypes", - ADMIN_LOGIN: "/Admin/Login", - ADMIN_LOGOUT: "/Admin/Logout", - ADMIN_READ_USER_DIRECT_PERMISSIONS: "/Admin/ReadUserDirectPermissions", - ADMIN_READ_USER_ROLE_PERMISSIONS: "/Admin/ReadUserRolePermissions", - ADMIN_READ_USER_ROLES: "/Admin/ReadUserRoles", - ADMIN_UPD_ADMIN: "/Admin/UpdAdmin", - ADMIN_UPD_ADMIN_TYPE: "/Admin/UpdAdminType", - ASSET_ADD_ASSET_INFO: "/Asset/AddAssetInfo", - ASSET_DEL_ASSET_INFO: "/Asset/DelAssetInfo", - ASSET_SELECT_ASSET_INFO_ALL: "/Asset/SelectAssetInfoAll", - ASSET_UPD_ASSET_INFO: "/Asset/UpdAssetInfo", - BASE_ADD_DEPT: "/Base/AddDept", - BASE_ADD_EDUCATION: "/Base/AddEducation", - BASE_ADD_NATION: "/Base/AddNation", - BASE_ADD_POSITION: "/Base/AddPosition", - BASE_CREATE_APPOINTMENT_NOTICE_TYPE: "/Base/CreateAppointmentNoticeType", - BASE_DEL_DEPT: "/Base/DelDept", - BASE_DEL_EDUCATION: "/Base/DelEducation", - BASE_DEL_NATION: "/Base/DelNation", - BASE_DEL_POSITION: "/Base/DelPosition", - BASE_DELETE_APPOINTMENT_NOTICE_TYPE: "/Base/DeleteAppointmentNoticeType", - BASE_DELETE_CUSTO_TYPE: "/Base/DeleteCustoType", - BASE_DELETE_PASS_PORT_TYPE: "/Base/DeletePassPortType", - BASE_INSERT_CUSTO_TYPE: "/Base/InsertCustoType", - BASE_INSERT_PASS_PORT_TYPE: "/Base/InsertPassPortType", - BASE_SELECT_APPOINTMENT_NOTICE_TYPE_ALL: - "/Base/SelectAppointmentNoticeTypeAll", - BASE_SELECT_CUSTO_TYPE_ALL: "/Base/SelectCustoTypeAll", - BASE_SELECT_CUSTO_TYPE_ALL_CAN_USE: "/Base/SelectCustoTypeAllCanUse", - BASE_SELECT_DEPT_ALL: "/Base/SelectDeptAll", - BASE_SELECT_EDUCATION_ALL: "/Base/SelectEducationAll", - BASE_SELECT_NATION_ALL: "/Base/SelectNationAll", - BASE_SELECT_PASS_PORT_TYPE_ALL: "/Base/SelectPassPortTypeAll", - BASE_SELECT_PASS_PORT_TYPE_ALL_CAN_USE: "/Base/SelectPassPortTypeAllCanUse", - BASE_SELECT_POSITION_ALL: "/Base/SelectPositionAll", - BASE_SELECT_ROOM_STATE_ALL: "/Base/SelectRoomStateAll", - BASE_SELECT_WORKER_FEATURE_ALL: "/Base/SelectWorkerFeatureAll", - BASE_UPD_DEPT: "/Base/UpdDept", - BASE_UPD_EDUCATION: "/Base/UpdEducation", - BASE_UPD_NATION: "/Base/UpdNation", - BASE_UPD_POSITION: "/Base/UpdPosition", - BASE_UPDATE_APPOINTMENT_NOTICE_TYPE: "/Base/UpdateAppointmentNoticeType", - BASE_UPDATE_CUSTO_TYPE: "/Base/UpdateCustoType", - BASE_UPDATE_PASS_PORT_TYPE: "/Base/UpdatePassPortType", - CUSTOMER_DEL_CUSTOMER_INFO: "/Customer/DelCustomerInfo", - CUSTOMER_INSERT_CUSTOMER_INFO: "/Customer/InsertCustomerInfo", - CUSTOMER_SELECT_CUSTOMERS: "/Customer/SelectCustomers", - CUSTOMER_UPD_CUSTOMER_INFO: "/Customer/UpdCustomerInfo", - CUSTOMER_PERMISSION_ASSIGN_USER_PERMISSIONS: - "/CustomerPermission/AssignUserPermissions", - CUSTOMER_PERMISSION_ASSIGN_USER_ROLES: "/CustomerPermission/AssignUserRoles", - CUSTOMER_PERMISSION_READ_USER_DIRECT_PERMISSIONS: - "/CustomerPermission/ReadUserDirectPermissions", - CUSTOMER_PERMISSION_READ_USER_ROLE_PERMISSIONS: - "/CustomerPermission/ReadUserRolePermissions", - CUSTOMER_PERMISSION_READ_USER_ROLES: "/CustomerPermission/ReadUserRoles", - DASHBOARD_BUSINESS_STATISTICS: "/Dashboard/BusinessStatistics", - DASHBOARD_HUMAN_RESOURCES_STATISTICS: "/Dashboard/HumanResourcesStatistics", - DASHBOARD_LOGISTICS_STATISTICS: "/Dashboard/LogisticsStatistics", - DASHBOARD_ROOM_STATISTICS: "/Dashboard/RoomStatistics", - EMPLOYEE_ADD_EMPLOYEE: "/Employee/AddEmployee", - EMPLOYEE_EMPLOYEE_LOGIN: "/Employee/EmployeeLogin", - EMPLOYEE_MANAGER_EMPLOYEE_ACCOUNT: "/Employee/ManagerEmployeeAccount", - EMPLOYEE_RESET_EMPLOYEE_ACCOUNT_PASSWORD: - "/Employee/ResetEmployeeAccountPassword", - EMPLOYEE_SELECT_EMPLOYEE_ALL: "/Employee/SelectEmployeeAll", - EMPLOYEE_SELECT_EMPLOYEE_INFO_BY_EMPLOYEE_ID: - "/Employee/SelectEmployeeInfoByEmployeeId", - EMPLOYEE_UPDATE_EMPLOYEE: "/Employee/UpdateEmployee", - EMPLOYEE_CHECK_SELECT_CHECK_INFO_BY_EMPLOYEE_ID: - "/EmployeeCheck/SelectCheckInfoByEmployeeId", - EMPLOYEE_HISTORY_SELECT_HISTORY_BY_EMPLOYEE_ID: - "/EmployeeHistory/SelectHistoryByEmployeeId", - EMPLOYEE_PERMISSION_ASSIGN_USER_PERMISSIONS: - "/EmployeePermission/AssignUserPermissions", - EMPLOYEE_PERMISSION_ASSIGN_USER_ROLES: "/EmployeePermission/AssignUserRoles", - EMPLOYEE_PERMISSION_READ_USER_DIRECT_PERMISSIONS: - "/EmployeePermission/ReadUserDirectPermissions", - EMPLOYEE_PERMISSION_READ_USER_ROLE_PERMISSIONS: - "/EmployeePermission/ReadUserRolePermissions", - EMPLOYEE_PERMISSION_READ_USER_ROLES: "/EmployeePermission/ReadUserRoles", - EMPLOYEE_PHOTO_INSERT_WORKER_PHOTO: "/EmployeePhoto/InsertWorkerPhoto", - ENERGY_MANAGEMENT_DELETE_ENERGY_MANAGEMENT_INFO: - "/EnergyManagement/DeleteEnergyManagementInfo", - ENERGY_MANAGEMENT_INSERT_ENERGY_MANAGEMENT_INFO: - "/EnergyManagement/InsertEnergyManagementInfo", - ENERGY_MANAGEMENT_SELECT_ENERGY_MANAGEMENT_INFO: - "/EnergyManagement/SelectEnergyManagementInfo", - ENERGY_MANAGEMENT_UPDATE_ENERGY_MANAGEMENT_INFO: - "/EnergyManagement/UpdateEnergyManagementInfo", - LOGIN_GET_CSRF_TOKEN: "/Login/GetCSRFToken", - LOGIN_REFRESH_CSRF_TOKEN: "/Login/RefreshCSRFToken", - MENU_BUILD_MENU_ALL: "/Menu/BuildMenuAll", - MENU_DELETE_MENU: "/Menu/DeleteMenu", - MENU_INSERT_MENU: "/Menu/InsertMenu", - MENU_SELECT_MENU_ALL: "/Menu/SelectMenuAll", - MENU_UPDATE_MENU: "/Menu/UpdateMenu", - PERMISSION_SELECT_PERMISSION_LIST: "/Permission/SelectPermissionList", - PROMOTION_CONTENT_ADD_PROMOTION_CONTENT: - "/PromotionContent/AddPromotionContent", - PROMOTION_CONTENT_DELETE_PROMOTION_CONTENT: - "/PromotionContent/DeletePromotionContent", - PROMOTION_CONTENT_SELECT_PROMOTION_CONTENT_ALL: - "/PromotionContent/SelectPromotionContentAll", - PROMOTION_CONTENT_UPDATE_PROMOTION_CONTENT: - "/PromotionContent/UpdatePromotionContent", - RESER_DELETE_RESER_INFO: "/Reser/DeleteReserInfo", - RESER_INSER_RESER_INFO: "/Reser/InserReserInfo", - RESER_SELECT_RESER_ALL: "/Reser/SelectReserAll", - RESER_SELECT_RESER_TYPE_ALL: "/Reser/SelectReserTypeAll", - RESER_UPDATE_RESER_INFO: "/Reser/UpdateReserInfo", - REWARD_PUNISHMENT_SELECT_ALL_REWARD_PUNISHMENT_BY_EMPLOYEE_ID: - "/RewardPunishment/SelectAllRewardPunishmentByEmployeeId", - ROLE_ASSIGN_ROLE_USERS: "/Role/AssignRoleUsers", - ROLE_DELETE_ROLE: "/Role/DeleteRole", - ROLE_GRANT_ROLE_PERMISSIONS: "/Role/GrantRolePermissions", - ROLE_INSERT_ROLE: "/Role/InsertRole", - ROLE_READ_ROLE_PERMISSIONS: "/Role/ReadRolePermissions", - ROLE_READ_ROLE_USERS: "/Role/ReadRoleUsers", - ROLE_SELECT_ROLE_LIST: "/Role/SelectRoleList", - ROLE_UPDATE_ROLE: "/Role/UpdateRole", - ROOM_DELETE_ROOM: "/Room/DeleteRoom", - ROOM_INSERT_ROOM: "/Room/InsertRoom", - ROOM_SELECT_CAN_USE_ROOM_ALL: "/Room/SelectCanUseRoomAll", - ROOM_SELECT_ROOM_ALL: "/Room/SelectRoomAll", - ROOM_UPDATE_ROOM: "/Room/UpdateRoom", - ROOM_TYPE_DELETE_ROOM_TYPE: "/RoomType/DeleteRoomType", - ROOM_TYPE_INSERT_ROOM_TYPE: "/RoomType/InsertRoomType", - ROOM_TYPE_SELECT_ROOM_TYPES_ALL: "/RoomType/SelectRoomTypesAll", - ROOM_TYPE_UPDATE_ROOM_TYPE: "/RoomType/UpdateRoomType", - SELLTHING_DELETE_SELLTHING: "/Sellthing/DeleteSellthing", - SELLTHING_INSERT_SELLTHING: "/Sellthing/InsertSellthing", - SELLTHING_SELECT_SELLTHING_ALL: "/Sellthing/SelectSellthingAll", - SELLTHING_UPDATE_SELLTHING: "/Sellthing/UpdateSellthing", - SPEND_INSERT_SPEND_INFO: "/Spend/InsertSpendInfo", - SPEND_SELECT_SPEND_INFO_ALL: "/Spend/SelectSpendInfoAll", - SPEND_UPD_SPEND_INFO: "/Spend/UpdSpendInfo", - SUPERVISION_STATISTICS_DELETE_SUPERVISION_STATISTICS: - "/SupervisionStatistics/DeleteSupervisionStatistics", - SUPERVISION_STATISTICS_INSERT_SUPERVISION_STATISTICS: - "/SupervisionStatistics/InsertSupervisionStatistics", - SUPERVISION_STATISTICS_SELECT_SUPERVISION_STATISTICS_ALL: - "/SupervisionStatistics/SelectSupervisionStatisticsAll", - SUPERVISION_STATISTICS_UPDATE_SUPERVISION_STATISTICS: - "/SupervisionStatistics/UpdateSupervisionStatistics", - UTILITY_DELETE_OPERATIONLOG: "/Utility/DeleteOperationlog", - UTILITY_DELETE_OPERATIONLOG_BY_RANGE: "/Utility/DeleteOperationlogByRange", - UTILITY_SELECT_CARD_CODE: "/Utility/SelectCardCode", - UTILITY_SELECT_OPERATIONLOG_ALL: "/Utility/SelectOperationlogAll", - UTILITY_SELECT_REQUESTLOG_ALL: "/Utility/SelectRequestlogAll", - VIP_RULE_ADD_VIP_RULE: "/VipRule/AddVipRule", - VIP_RULE_DEL_VIP_RULE: "/VipRule/DelVipRule", - VIP_RULE_SELECT_VIP_RULE_LIST: "/VipRule/SelectVipRuleList", - VIP_RULE_UPD_VIP_RULE: "/VipRule/UpdVipRule", - VERSION: "/version", +import flatApiRoutes from "./apiRoutes.json"; + +const ROOT_ROUTE_OVERRIDES = { + VERSION: { group: "SYSTEM", name: "VERSION" }, +}; + +const toSnakeUpper = (value) => + String(value || "") + .replace(/([a-z0-9])([A-Z])/g, "$1_$2") + .replace(/[^A-Za-z0-9]+/g, "_") + .replace(/^_+|_+$/g, "") + .toUpperCase(); + +const getRouteMeta = (flatKey, path) => { + const override = ROOT_ROUTE_OVERRIDES[flatKey]; + if (override) { + return override; + } + + const segments = String(path || "") + .split("/") + .filter(Boolean); + const controller = segments[0]; + const group = controller ? toSnakeUpper(controller) : "ROOT"; + const groupPrefix = `${group}_`; + + if (flatKey.startsWith(groupPrefix)) { + return { group, name: flatKey.slice(groupPrefix.length) }; + } + + const action = segments[1]; + return { + group, + name: action ? toSnakeUpper(action) : flatKey, + }; +}; + +const validateFlatRoutes = (flatRoutes) => { + const routeByPath = new Map(); + + for (const [flatKey, path] of Object.entries(flatRoutes)) { + if (typeof path !== "string" || !path.startsWith("/")) { + throw new Error(`Invalid API route path for ${flatKey}: ${path}`); + } + + const existingKey = routeByPath.get(path); + if (existingKey && existingKey !== flatKey) { + throw new Error( + `Duplicate API route path detected: ${path} (${existingKey}, ${flatKey})`, + ); + } + + routeByPath.set(path, flatKey); + } }; +const buildGroupedRoutes = (flatRoutes) => { + const grouped = {}; + + for (const [flatKey, path] of Object.entries(flatRoutes)) { + const { group, name } = getRouteMeta(flatKey, path); + grouped[group] ||= {}; + + const existingPath = grouped[group][name]; + if (existingPath && existingPath !== path) { + throw new Error( + `Duplicate API route key detected: ${group}.${name} (${existingPath}, ${path})`, + ); + } + + grouped[group][name] = path; + } + + return grouped; +}; + +validateFlatRoutes(flatApiRoutes); + +const groupedRoutes = buildGroupedRoutes(flatApiRoutes); + +export const ROUTES = Object.freeze( + Object.fromEntries( + Object.entries(groupedRoutes).map(([group, routes]) => [ + group, + Object.freeze({ ...routes }), + ]), + ), +); + +export const LEGACY_ROUTES = Object.freeze({ ...flatApiRoutes }); + +export const API_ROUTE_KEYS = Object.freeze(Object.keys(LEGACY_ROUTES)); + export const API_ENDPOINTS = { - routes: ROUTES, + routes: Object.freeze({ ...ROUTES, ...LEGACY_ROUTES }), login: { - admin: ROUTES.ADMIN_LOGIN, - employee: ROUTES.EMPLOYEE_EMPLOYEE_LOGIN, + admin: ROUTES.ADMIN.LOGIN, + employee: ROUTES.EMPLOYEE.EMPLOYEE_LOGIN, }, twoFactor: { admin: "Admin", diff --git a/src/config/apiRoutes.json b/src/config/apiRoutes.json new file mode 100644 index 0000000..67b0a60 --- /dev/null +++ b/src/config/apiRoutes.json @@ -0,0 +1,141 @@ +{ + "ADMIN_ADD_ADMIN": "/Admin/AddAdmin", + "ADMIN_ADD_ADMIN_TYPE": "/Admin/AddAdminType", + "ADMIN_ASSIGN_USER_PERMISSIONS": "/Admin/AssignUserPermissions", + "ADMIN_ASSIGN_USER_ROLES": "/Admin/AssignUserRoles", + "ADMIN_DEL_ADMIN": "/Admin/DelAdmin", + "ADMIN_DEL_ADMIN_TYPE": "/Admin/DelAdminType", + "ADMIN_GET_ALL_ADMIN_LIST": "/Admin/GetAllAdminList", + "ADMIN_GET_ALL_ADMIN_TYPES": "/Admin/GetAllAdminTypes", + "ADMIN_LOGIN": "/Admin/Login", + "ADMIN_LOGOUT": "/Admin/Logout", + "ADMIN_READ_USER_DIRECT_PERMISSIONS": "/Admin/ReadUserDirectPermissions", + "ADMIN_READ_USER_ROLE_PERMISSIONS": "/Admin/ReadUserRolePermissions", + "ADMIN_READ_USER_ROLES": "/Admin/ReadUserRoles", + "ADMIN_UPD_ADMIN": "/Admin/UpdAdmin", + "ADMIN_UPD_ADMIN_TYPE": "/Admin/UpdAdminType", + "ASSET_ADD_ASSET_INFO": "/Asset/AddAssetInfo", + "ASSET_DEL_ASSET_INFO": "/Asset/DelAssetInfo", + "ASSET_SELECT_ASSET_INFO_ALL": "/Asset/SelectAssetInfoAll", + "ASSET_UPD_ASSET_INFO": "/Asset/UpdAssetInfo", + "BASE_ADD_DEPT": "/Base/AddDept", + "BASE_ADD_EDUCATION": "/Base/AddEducation", + "BASE_ADD_NATION": "/Base/AddNation", + "BASE_ADD_POSITION": "/Base/AddPosition", + "BASE_CREATE_APPOINTMENT_NOTICE_TYPE": "/Base/CreateAppointmentNoticeType", + "BASE_DEL_DEPT": "/Base/DelDept", + "BASE_DEL_EDUCATION": "/Base/DelEducation", + "BASE_DEL_NATION": "/Base/DelNation", + "BASE_DEL_POSITION": "/Base/DelPosition", + "BASE_DELETE_APPOINTMENT_NOTICE_TYPE": "/Base/DeleteAppointmentNoticeType", + "BASE_DELETE_CUSTO_TYPE": "/Base/DeleteCustoType", + "BASE_DELETE_PASS_PORT_TYPE": "/Base/DeletePassPortType", + "BASE_INSERT_CUSTO_TYPE": "/Base/InsertCustoType", + "BASE_INSERT_PASS_PORT_TYPE": "/Base/InsertPassPortType", + "BASE_SELECT_APPOINTMENT_NOTICE_TYPE_ALL": "/Base/SelectAppointmentNoticeTypeAll", + "BASE_SELECT_CUSTO_TYPE_ALL": "/Base/SelectCustoTypeAll", + "BASE_SELECT_CUSTO_TYPE_ALL_CAN_USE": "/Base/SelectCustoTypeAllCanUse", + "BASE_SELECT_DEPT_ALL": "/Base/SelectDeptAll", + "BASE_SELECT_EDUCATION_ALL": "/Base/SelectEducationAll", + "BASE_SELECT_NATION_ALL": "/Base/SelectNationAll", + "BASE_SELECT_PASS_PORT_TYPE_ALL": "/Base/SelectPassPortTypeAll", + "BASE_SELECT_PASS_PORT_TYPE_ALL_CAN_USE": "/Base/SelectPassPortTypeAllCanUse", + "BASE_SELECT_POSITION_ALL": "/Base/SelectPositionAll", + "BASE_SELECT_ROOM_STATE_ALL": "/Base/SelectRoomStateAll", + "BASE_SELECT_WORKER_FEATURE_ALL": "/Base/SelectWorkerFeatureAll", + "BASE_UPD_DEPT": "/Base/UpdDept", + "BASE_UPD_EDUCATION": "/Base/UpdEducation", + "BASE_UPD_NATION": "/Base/UpdNation", + "BASE_UPD_POSITION": "/Base/UpdPosition", + "BASE_UPDATE_APPOINTMENT_NOTICE_TYPE": "/Base/UpdateAppointmentNoticeType", + "BASE_UPDATE_CUSTO_TYPE": "/Base/UpdateCustoType", + "BASE_UPDATE_PASS_PORT_TYPE": "/Base/UpdatePassPortType", + "CUSTOMER_DEL_CUSTOMER_INFO": "/Customer/DelCustomerInfo", + "CUSTOMER_INSERT_CUSTOMER_INFO": "/Customer/InsertCustomerInfo", + "CUSTOMER_SELECT_CUSTOMERS": "/Customer/SelectCustomers", + "CUSTOMER_UPD_CUSTOMER_INFO": "/Customer/UpdCustomerInfo", + "CUSTOMER_PERMISSION_ASSIGN_USER_PERMISSIONS": "/CustomerPermission/AssignUserPermissions", + "CUSTOMER_PERMISSION_ASSIGN_USER_ROLES": "/CustomerPermission/AssignUserRoles", + "CUSTOMER_PERMISSION_READ_USER_DIRECT_PERMISSIONS": "/CustomerPermission/ReadUserDirectPermissions", + "CUSTOMER_PERMISSION_READ_USER_ROLE_PERMISSIONS": "/CustomerPermission/ReadUserRolePermissions", + "CUSTOMER_PERMISSION_READ_USER_ROLES": "/CustomerPermission/ReadUserRoles", + "DASHBOARD_BUSINESS_STATISTICS": "/Dashboard/BusinessStatistics", + "DASHBOARD_HUMAN_RESOURCES_STATISTICS": "/Dashboard/HumanResourcesStatistics", + "DASHBOARD_LOGISTICS_STATISTICS": "/Dashboard/LogisticsStatistics", + "DASHBOARD_ROOM_STATISTICS": "/Dashboard/RoomStatistics", + "EMPLOYEE_ADD_EMPLOYEE": "/Employee/AddEmployee", + "EMPLOYEE_EMPLOYEE_LOGIN": "/Employee/EmployeeLogin", + "EMPLOYEE_MANAGER_EMPLOYEE_ACCOUNT": "/Employee/ManagerEmployeeAccount", + "EMPLOYEE_RESET_EMPLOYEE_ACCOUNT_PASSWORD": "/Employee/ResetEmployeeAccountPassword", + "EMPLOYEE_SELECT_EMPLOYEE_ALL": "/Employee/SelectEmployeeAll", + "EMPLOYEE_SELECT_EMPLOYEE_INFO_BY_EMPLOYEE_ID": "/Employee/SelectEmployeeInfoByEmployeeId", + "EMPLOYEE_UPDATE_EMPLOYEE": "/Employee/UpdateEmployee", + "EMPLOYEE_CHECK_SELECT_CHECK_INFO_BY_EMPLOYEE_ID": "/EmployeeCheck/SelectCheckInfoByEmployeeId", + "EMPLOYEE_HISTORY_SELECT_HISTORY_BY_EMPLOYEE_ID": "/EmployeeHistory/SelectHistoryByEmployeeId", + "EMPLOYEE_PERMISSION_ASSIGN_USER_PERMISSIONS": "/EmployeePermission/AssignUserPermissions", + "EMPLOYEE_PERMISSION_ASSIGN_USER_ROLES": "/EmployeePermission/AssignUserRoles", + "EMPLOYEE_PERMISSION_READ_USER_DIRECT_PERMISSIONS": "/EmployeePermission/ReadUserDirectPermissions", + "EMPLOYEE_PERMISSION_READ_USER_ROLE_PERMISSIONS": "/EmployeePermission/ReadUserRolePermissions", + "EMPLOYEE_PERMISSION_READ_USER_ROLES": "/EmployeePermission/ReadUserRoles", + "EMPLOYEE_PHOTO_INSERT_WORKER_PHOTO": "/EmployeePhoto/InsertWorkerPhoto", + "ENERGY_MANAGEMENT_DELETE_ENERGY_MANAGEMENT_INFO": "/EnergyManagement/DeleteEnergyManagementInfo", + "ENERGY_MANAGEMENT_INSERT_ENERGY_MANAGEMENT_INFO": "/EnergyManagement/InsertEnergyManagementInfo", + "ENERGY_MANAGEMENT_SELECT_ENERGY_MANAGEMENT_INFO": "/EnergyManagement/SelectEnergyManagementInfo", + "ENERGY_MANAGEMENT_UPDATE_ENERGY_MANAGEMENT_INFO": "/EnergyManagement/UpdateEnergyManagementInfo", + "LOGIN_GET_CSRF_TOKEN": "/Login/GetCSRFToken", + "LOGIN_REFRESH_CSRF_TOKEN": "/Login/RefreshCSRFToken", + "MENU_BUILD_MENU_ALL": "/Menu/BuildMenuAll", + "MENU_DELETE_MENU": "/Menu/DeleteMenu", + "MENU_INSERT_MENU": "/Menu/InsertMenu", + "MENU_SELECT_MENU_ALL": "/Menu/SelectMenuAll", + "MENU_UPDATE_MENU": "/Menu/UpdateMenu", + "PERMISSION_SELECT_PERMISSION_LIST": "/Permission/SelectPermissionList", + "PROMOTION_CONTENT_ADD_PROMOTION_CONTENT": "/PromotionContent/AddPromotionContent", + "PROMOTION_CONTENT_DELETE_PROMOTION_CONTENT": "/PromotionContent/DeletePromotionContent", + "PROMOTION_CONTENT_SELECT_PROMOTION_CONTENT_ALL": "/PromotionContent/SelectPromotionContentAll", + "PROMOTION_CONTENT_UPDATE_PROMOTION_CONTENT": "/PromotionContent/UpdatePromotionContent", + "RESER_DELETE_RESER_INFO": "/Reser/DeleteReserInfo", + "RESER_INSER_RESER_INFO": "/Reser/InserReserInfo", + "RESER_SELECT_RESER_ALL": "/Reser/SelectReserAll", + "RESER_SELECT_RESER_TYPE_ALL": "/Reser/SelectReserTypeAll", + "RESER_UPDATE_RESER_INFO": "/Reser/UpdateReserInfo", + "REWARD_PUNISHMENT_SELECT_ALL_REWARD_PUNISHMENT_BY_EMPLOYEE_ID": "/RewardPunishment/SelectAllRewardPunishmentByEmployeeId", + "ROLE_ASSIGN_ROLE_USERS": "/Role/AssignRoleUsers", + "ROLE_DELETE_ROLE": "/Role/DeleteRole", + "ROLE_GRANT_ROLE_PERMISSIONS": "/Role/GrantRolePermissions", + "ROLE_INSERT_ROLE": "/Role/InsertRole", + "ROLE_READ_ROLE_PERMISSIONS": "/Role/ReadRolePermissions", + "ROLE_READ_ROLE_USERS": "/Role/ReadRoleUsers", + "ROLE_SELECT_ROLE_LIST": "/Role/SelectRoleList", + "ROLE_UPDATE_ROLE": "/Role/UpdateRole", + "ROOM_DELETE_ROOM": "/Room/DeleteRoom", + "ROOM_INSERT_ROOM": "/Room/InsertRoom", + "ROOM_SELECT_CAN_USE_ROOM_ALL": "/Room/SelectCanUseRoomAll", + "ROOM_SELECT_ROOM_ALL": "/Room/SelectRoomAll", + "ROOM_UPDATE_ROOM": "/Room/UpdateRoom", + "ROOM_TYPE_DELETE_ROOM_TYPE": "/RoomType/DeleteRoomType", + "ROOM_TYPE_INSERT_ROOM_TYPE": "/RoomType/InsertRoomType", + "ROOM_TYPE_SELECT_ROOM_TYPES_ALL": "/RoomType/SelectRoomTypesAll", + "ROOM_TYPE_UPDATE_ROOM_TYPE": "/RoomType/UpdateRoomType", + "SELLTHING_DELETE_SELLTHING": "/Sellthing/DeleteSellthing", + "SELLTHING_INSERT_SELLTHING": "/Sellthing/InsertSellthing", + "SELLTHING_SELECT_SELLTHING_ALL": "/Sellthing/SelectSellthingAll", + "SELLTHING_UPDATE_SELLTHING": "/Sellthing/UpdateSellthing", + "SPEND_INSERT_SPEND_INFO": "/Spend/InsertSpendInfo", + "SPEND_SELECT_SPEND_INFO_ALL": "/Spend/SelectSpendInfoAll", + "SPEND_UPD_SPEND_INFO": "/Spend/UpdSpendInfo", + "SUPERVISION_STATISTICS_DELETE_SUPERVISION_STATISTICS": "/SupervisionStatistics/DeleteSupervisionStatistics", + "SUPERVISION_STATISTICS_INSERT_SUPERVISION_STATISTICS": "/SupervisionStatistics/InsertSupervisionStatistics", + "SUPERVISION_STATISTICS_SELECT_SUPERVISION_STATISTICS_ALL": "/SupervisionStatistics/SelectSupervisionStatisticsAll", + "SUPERVISION_STATISTICS_UPDATE_SUPERVISION_STATISTICS": "/SupervisionStatistics/UpdateSupervisionStatistics", + "UTILITY_DELETE_OPERATIONLOG": "/Utility/DeleteOperationlog", + "UTILITY_DELETE_OPERATIONLOG_BY_RANGE": "/Utility/DeleteOperationlogByRange", + "UTILITY_SELECT_CARD_CODE": "/Utility/SelectCardCode", + "UTILITY_SELECT_OPERATIONLOG_ALL": "/Utility/SelectOperationlogAll", + "UTILITY_SELECT_REQUESTLOG_ALL": "/Utility/SelectRequestlogAll", + "VIP_RULE_ADD_VIP_RULE": "/VipRule/AddVipRule", + "VIP_RULE_DEL_VIP_RULE": "/VipRule/DelVipRule", + "VIP_RULE_SELECT_VIP_RULE_LIST": "/VipRule/SelectVipRuleList", + "VIP_RULE_UPD_VIP_RULE": "/VipRule/UpdVipRule", + "VERSION": "/version" +} diff --git a/src/i18n.js b/src/i18n.js index d32a238..bc6d3f4 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -90,6 +90,8 @@ const messages = { "2FA enabled. Save your recovery codes now (shown only once).", recoveryCodeLoginTip: "Recovery code was used for this login. Rebind your authenticator and regenerate recovery codes immediately.", + permissionCheckError: + "Permission check failed, Please retry or contact administrator.", refreshData: "Refresh Data", addSuccess: "Add Success", updateSuccess: "Update Success", @@ -809,6 +811,7 @@ const messages = { "2FA 已启用,请立即保存恢复备用码(仅展示一次)。", recoveryCodeLoginTip: "本次登录使用了恢复备用码,请立即重新绑定验证器并重置备用码。", + permissionCheckError: "权限检查发生错误,请重试或联系管理员", refreshData: "刷新数据", addSuccess: "添加成功", updateSuccess: "更新成功", diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 7e32de5..f920faa 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -244,6 +244,7 @@ import { formatDateTime, showErrorNotification, showSuccessNotification, + showWarningNotification, } from "@/utils/index"; import { fetchMenusTree } from "../api/menuapi"; import { BaseFields } from "@/entities/common.entity"; @@ -280,6 +281,7 @@ import { getServerVersion, } from "../api/basicapi"; import { clearRowVersionCache } from "@/api/baseapi"; +import { decodeJwtPayload, getUserIdentity, isTokenExpired } from "@/utils/jwt"; const serverVersion = ref(""); @@ -452,16 +454,20 @@ const extractPermissionCodes = (items) => .filter(Boolean), ); -const decodeJwtPayload = (token) => { - try { - const payload = token?.split(".")?.[1]; - if (!payload) return null; - const base64 = payload.replace(/-/g, "+").replace(/_/g, "/"); - const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "="); - return JSON.parse(window.atob(padded)); - } catch (error) { - return null; - } +const clearAllowedPathsCache = () => { + localStorage.removeItem("allowedPaths"); + localStorage.removeItem("allowedMenuKeys"); + localStorage.removeItem("allowedPerms"); + localStorage.removeItem("allowedPathsToken"); + localStorage.removeItem("allowedPathsExpire"); + localStorage.removeItem("allowedPathsIssuedAt"); +}; + +const getPermissionErrorMessage = () => { + const translated = t("message.permissionCheckError"); + return translated === "message.permissionCheckError" + ? "Permission check failed. Please retry or contact administrator." + : translated; }; const fetchCurrentUserPermissionCodes = async () => { @@ -484,38 +490,33 @@ const fetchCurrentUserPermissionCodes = async () => { permissionReadersByLoginType[loginType.value] || permissionReadersByLoginType.admin; - const tokenPayload = decodeJwtPayload(localStorage.getItem("token") || ""); - const identityCandidates = unique([ - localStorage.getItem("account"), - tokenPayload?.UserNumber, - tokenPayload?.userNumber, - tokenPayload?.Account, - tokenPayload?.account, - tokenPayload?.EmployeeId, - tokenPayload?.employeeId, - tokenPayload?.nameid, - tokenPayload?.sub, - ]); - - for (const identity of identityCandidates) { - try { - const [rolePermissions, directPermissions] = await Promise.all([ - readers.readRolePermissions(identity), - readers.readDirectPermissions(identity), - ]); - - const mergedCodes = unique([ - ...extractPermissionCodes(rolePermissions), - ...extractPermissionCodes(directPermissions), - ]); - - return { ok: true, codes: mergedCodes }; - } catch (error) { - // Try next candidate identity. - } + const identity = getUserIdentity( + loginType.value, + localStorage.getItem("token") || "", + localStorage.getItem("account") || "", + ); + + if (!identity) { + showWarningNotification(getPermissionErrorMessage()); + return { ok: false, codes: [] }; } - return { ok: false, codes: [] }; + try { + const [rolePermissions, directPermissions] = await Promise.all([ + readers.readRolePermissions(identity), + readers.readDirectPermissions(identity), + ]); + + const mergedCodes = unique([ + ...extractPermissionCodes(rolePermissions), + ...extractPermissionCodes(directPermissions), + ]); + + return { ok: true, codes: mergedCodes }; + } catch (error) { + showWarningNotification(getPermissionErrorMessage()); + return { ok: false, codes: [] }; + } }; const syncAllowedPermissions = () => { @@ -614,10 +615,23 @@ const refreshMenu = async () => { localStorage.setItem("allowedMenuKeys", JSON.stringify(allowedMenuKeys)); localStorage.setItem("allowedPaths", JSON.stringify(allowedPaths)); localStorage.setItem("allowedPerms", JSON.stringify(allowedPermList)); - localStorage.setItem( - "allowedPathsToken", - localStorage.getItem("token") || "", - ); + + const currentToken = localStorage.getItem("token") || ""; + const tokenPayload = decodeJwtPayload(currentToken); + const tokenIssuedAt = Number(tokenPayload?.iat); + const tokenExpireAt = Number(tokenPayload?.exp); + + localStorage.setItem("allowedPathsToken", currentToken); + if (Number.isFinite(tokenIssuedAt)) { + localStorage.setItem("allowedPathsIssuedAt", String(tokenIssuedAt)); + } else { + localStorage.removeItem("allowedPathsIssuedAt"); + } + if (Number.isFinite(tokenExpireAt)) { + localStorage.setItem("allowedPathsExpire", String(tokenExpireAt)); + } else { + localStorage.removeItem("allowedPathsExpire"); + } allowedPermissionCodes.value = allowedPermList; window.dispatchEvent(new Event("permissions-updated")); @@ -885,25 +899,55 @@ const handleDisableTwoFactor = async () => { }; const checkLoginStatus = () => { - const storedToken = localStorage.getItem("token"); - if (storedToken) { + const storedToken = localStorage.getItem("token") || ""; + + if (storedToken && !isTokenExpired(storedToken)) { isLoggedIn.value = true; loginType.value = localStorage.getItem("loginType") || "admin"; - syncAllowedPermissions(); - const storedUsername = localStorage.getItem("username"); - if (storedUsername) { - username.value = storedUsername; + + const tokenPayload = decodeJwtPayload(storedToken); + const tokenExpireAt = Number(tokenPayload?.exp); + const cachedAllowedToken = localStorage.getItem("allowedPathsToken") || ""; + const cachedAllowedExpireAt = Number( + localStorage.getItem("allowedPathsExpire"), + ); + const now = Math.floor(Date.now() / 1000); + + const isAllowedTokenMismatch = + cachedAllowedToken.length > 0 && cachedAllowedToken !== storedToken; + const isAllowedCacheExpired = + Number.isFinite(cachedAllowedExpireAt) && cachedAllowedExpireAt <= now; + const isAllowedExpireMismatch = + Number.isFinite(tokenExpireAt) && + Number.isFinite(cachedAllowedExpireAt) && + cachedAllowedExpireAt !== tokenExpireAt; + + if ( + isAllowedTokenMismatch || + isAllowedCacheExpired || + isAllowedExpireMismatch + ) { + clearAllowedPathsCache(); + allowedPermissionCodes.value = []; } else { - username.value = "User"; + syncAllowedPermissions(); } - } else { - isLoggedIn.value = false; - loginType.value = "admin"; - allowedPermissionCodes.value = []; - username.value = ""; - localStorage.removeItem("allowedPathsToken"); - clearRowVersionCache(); + + const storedUsername = localStorage.getItem("username"); + username.value = storedUsername || "User"; + return; } + + isLoggedIn.value = false; + loginType.value = "admin"; + allowedPermissionCodes.value = []; + username.value = ""; + localStorage.removeItem("token"); + localStorage.removeItem("username"); + localStorage.removeItem("account"); + localStorage.removeItem("loginType"); + clearAllowedPathsCache(); + clearRowVersionCache(); }; const logout = async () => { @@ -916,10 +960,7 @@ const logout = async () => { localStorage.removeItem("username"); localStorage.removeItem("account"); localStorage.removeItem("loginType"); - localStorage.removeItem("allowedPaths"); - localStorage.removeItem("allowedMenuKeys"); - localStorage.removeItem("allowedPerms"); - localStorage.removeItem("allowedPathsToken"); + clearAllowedPathsCache(); clearRowVersionCache(); isLoggedIn.value = false; allowedPermissionCodes.value = []; diff --git a/src/router/index.js b/src/router/index.js index d9296e1..5c0f328 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -323,10 +323,16 @@ router.beforeEach((to, from, next) => { const raw = localStorage.getItem("allowedPaths"); const currentToken = localStorage.getItem("token") || ""; const allowedPathsToken = localStorage.getItem("allowedPathsToken") || ""; + const allowedPathsExpire = Number( + localStorage.getItem("allowedPathsExpire"), + ); + const now = Math.floor(Date.now() / 1000); const hasAllowedPathsCache = raw !== null && allowedPathsToken.length > 0 && - allowedPathsToken === currentToken; + allowedPathsToken === currentToken && + Number.isFinite(allowedPathsExpire) && + allowedPathsExpire > now; const parsed = raw ? JSON.parse(raw) : []; const allowedPaths = Array.isArray(parsed) ? parsed : []; diff --git a/src/utils/auth.js b/src/utils/auth.js index fb3a271..993c4bf 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -1,15 +1,14 @@ -import { jwtDecode } from "jwt-decode"; import router from "@/router"; import { showErrorNotification } from "@/utils/index"; import i18n from "@/i18n"; import { signOut } from "@/api/basicapi"; import { clearRowVersionCache } from "@/api/baseapi"; +import { decodeJwtPayload, isTokenExpired } from "@/utils/jwt"; export function redirectToLogin( message = i18n.global.t("message.loginExpired"), clearStorage = false, ) { - // 只有在明确指定需要清除存储时才清除 if (clearStorage) { localStorage.removeItem("token"); localStorage.removeItem("username"); @@ -22,14 +21,11 @@ export function redirectToLogin( } } -// 处理登出 export async function handleLogout() { try { const token = localStorage.getItem("token"); if (token) { - // 调用登出接口 await signOut(); - // 清理本地存储 localStorage.removeItem("token"); localStorage.removeItem("username"); localStorage.removeItem("account"); @@ -37,8 +33,9 @@ export async function handleLogout() { localStorage.removeItem("allowedPaths"); localStorage.removeItem("allowedMenuKeys"); localStorage.removeItem("allowedPathsToken"); + localStorage.removeItem("allowedPathsExpire"); + localStorage.removeItem("allowedPathsIssuedAt"); clearRowVersionCache(); - // 重定向到登录页 router.push("/signin"); } } catch (error) { @@ -53,22 +50,15 @@ export function checkTokenValidity(redirect = false) { return false; } - try { - const decodedToken = jwtDecode(token); - const currentTime = Math.floor(Date.now() / 1000); - - // 检查 token 是否快要过期(比如还有5分钟过期) - const expiresIn = decodedToken.exp - currentTime; - const isNearExpiration = expiresIn < 300; // 5分钟 = 300秒 - - if (decodedToken.exp < currentTime || isNearExpiration) { - // token 已过期或即将过期 - return false; - } + const decodedToken = decodeJwtPayload(token); + const expiration = Number(decodedToken?.exp); + if (!decodedToken || !Number.isFinite(expiration)) { + return false; + } - return true; - } catch (error) { - // token 解析失败 + if (isTokenExpired(token, 300)) { return false; } + + return true; } diff --git a/src/utils/jwt.js b/src/utils/jwt.js new file mode 100644 index 0000000..2d35289 --- /dev/null +++ b/src/utils/jwt.js @@ -0,0 +1,89 @@ +import { jwtDecode } from "jwt-decode"; + +const IDENTITY_FIELDS_BY_LOGIN_TYPE = { + admin: ["sub", "nameid", "UserNumber", "userNumber", "Account", "account"], + employee: [ + "sub", + "nameid", + "EmployeeId", + "employeeId", + "UserNumber", + "userNumber", + "Account", + "account", + ], + customer: ["sub", "nameid", "CustomerId", "customerId", "Account", "account"], +}; + +const COMMON_IDENTITY_FIELDS = [ + "sub", + "nameid", + "UserNumber", + "userNumber", + "EmployeeId", + "employeeId", + "Account", + "account", +]; + +const normalizeIdentity = (value) => { + if (value === null || value === undefined) { + return ""; + } + + const text = String(value).trim(); + return text.length > 0 ? text : ""; +}; + +const pickIdentity = (payload, keys) => { + for (const key of keys) { + const identity = normalizeIdentity(payload?.[key]); + if (identity) { + return identity; + } + } + return ""; +}; + +export const decodeJwtPayload = (token) => { + const normalizedToken = typeof token === "string" ? token.trim() : ""; + if (!normalizedToken) { + return null; + } + + try { + return jwtDecode(normalizedToken); + } catch (error) { + return null; + } +}; + +export const getTokenExpiration = (token) => { + const payload = decodeJwtPayload(token); + const exp = Number(payload?.exp); + return Number.isFinite(exp) ? exp : null; +}; + +export const isTokenExpired = (token, minRemainingSeconds = 0) => { + const expiration = getTokenExpiration(token); + if (!Number.isFinite(expiration)) { + return true; + } + + const now = Math.floor(Date.now() / 1000); + return expiration - now <= Number(minRemainingSeconds || 0); +}; + +export const getUserIdentity = (loginType, token, fallbackIdentity = "") => { + const payload = decodeJwtPayload(token); + if (!payload) { + return normalizeIdentity(fallbackIdentity) || null; + } + + const preferredFields = IDENTITY_FIELDS_BY_LOGIN_TYPE[loginType] || []; + const identity = + pickIdentity(payload, preferredFields) || + pickIdentity(payload, COMMON_IDENTITY_FIELDS); + + return identity || normalizeIdentity(fallbackIdentity) || null; +}; diff --git a/src/views/SignInView.vue b/src/views/SignInView.vue index e8f4a40..9732c15 100644 --- a/src/views/SignInView.vue +++ b/src/views/SignInView.vue @@ -205,6 +205,8 @@ const clearPermissionCache = () => { localStorage.removeItem("allowedMenuKeys"); localStorage.removeItem("allowedPerms"); localStorage.removeItem("allowedPathsToken"); + localStorage.removeItem("allowedPathsExpire"); + localStorage.removeItem("allowedPathsIssuedAt"); }; const persistLoginData = async (userData, loginType) => { -- Gitee