diff --git a/src/api/administratorapi.js b/src/api/administratorapi.js index c64ebd5cfbbab18c1af9e84631b4db6617c69ce2..9e802a652a2b3ce9321f9df5f4e78f1edf7fa944 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 ab9bec9969359fa5fba8a960c86569765b99d239..1edd1627d16447668721b249b6f77b61bb0f0a27 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 9389e980db0421428af58c7274dd6827daab0a04..02b77311bca45b850c9e7a134541bb117773ede9 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 8e327bdb64185b37f02ee7172b894e1ba67f0387..bfcc637aa224d32a2cd34a62ecc233e716f4d618 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 e45e1fcb61be7182d2317103972e76feb7aa344f..5cf821d401baa0a878233d6891077e731a30c803 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 2bfdfa84f988e3acc31f312999ac09ba320c1d6e..23b207e926740847e122ba365f625881714d17a8 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 5ccd0f68b59269fb453f5e4b776c3dff0f4469ef..9e184d1e0edb56e42410fece797aed58fd940524 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 7e9445f8c4cabbcbb5579138ceb0f5f52773ac6b..5a28df8ae1f2757d1df567cb39d79b235eef5472 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 74910e16db319c10f758933633269a4cc7098b54..85bb05aac6c4f0e137679b91118db8b117770743 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 060545a433fe638a4aca844e6c510695a27dc894..0193b64be5c83abc3c9a61bab8f39b7960d2b4f2 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 6de5c87b11ff225c376e5788a6344f85a4ea12d2..d34d977cf53d89597343fee0a116a7b174c8d093 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 3aaa475d91d3804297cd732fb11d8e272f181cfc..09456d9e147f4a09091801327f4f59bfbb88127f 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 3d568c492651ae980ac66670faf13047375f6341..a55e940c0e68d3756815a84963fe715930c84d43 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 f7228aa57afed6fdbee274cc60d59cb3f3ca106e..ec1db7df7e28d616be4e29a9f90342178e8db09b 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 79051291669c26c2b56de63d3f0aaa5541c17e53..afa796ef1bceb68e94ee7e77c4fce5970b7c6b5a 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 14926a281f6c7488fde8dfc162305a4624287f87..b1215f36831c49418a9849f567c5635b07027e06 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 f2f05db24afc7014a878f605fc135574564ca9fa..300db812979012439690f789a4ad5cd484d88d9f 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 712c7c79c959706b4138d7ac4896f3087af79a95..fbe53442c528f0d0f41dbc173479d4a7d5400c54 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 e32787aceab8cae7430cdcfd10ecb25e6bb39c05..01fd8a42e4247cfa995afd7de425d43c47c9f529 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 66c88d60245cb58a0981398667e057da166ace60..f4bbecaf4ccbada17e5f51f5425cea2dc279f42f 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 e4f0501773cef2f3f47da979be62fefdc819d295..0a6992128c2669843875d5f394902ebc2785c1d1 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 224502c94a5531e4b94995cf5398602f731ab761..845a6fe031542bee48827201127c9c034b599a0b 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 9276f06c4a3010ce33cfb914de3f7293fa062475..cfa5093c267b3de1d5fe4e920194e2ff5bba9f2f 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 30e2b60138fc1f989a6523f01c0938d6bfe4c1f9..945322a9a6769cde07b469e0f19dd96f3f61a84e 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 4bf02c285b3b31baa9413ebeaa1f357b8cd8f829..f1821a56bb4b8b6d023204d76e996cd65fab7149 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 b3e8aef21c676d03dc3cf3d70620fa0a0db26c03..4818ea6ce498715b8365f2acb7f74f98f7ffe170 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 0bddc3dbe422b2e9eb08c0d6d4ad794fd239cc85..82a300c7bd6e0db863071b24d5b83314d2ca3b62 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 78a435676205ae625589a0defaad9f21cb164df8..68fae87966738caee5d34bc1c6bcca98570efe97 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 f2424d5e6cf266122d3ce0cb9320bf3aecebc40d..f70d57aa6714d80cb7ad4ba7c63a59670d952572 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 b5794b2ab7789ff7a75697cb726ec10c85d0084b..a40412b818840e24898d9baef8e331c5956741e5 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 526143818c86a380740993536a67c8b354bba6bb..3f3df4f2669dec8bc13aa72f6ff9db30551eb7f5 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 d96e262590d543d915a2da7d5e39df324b3243d4..8a072aebeca5447de53161d629d56fe4f734eee7 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 dd2ecece4f57ee5fdc8329e6b48a64dd2a266aaa..d75993cd2ab531c2e16d3fe36bb30901944fbcfd 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 0000000000000000000000000000000000000000..fdb5bf6a27c05ff8ff16becbd76c056c01a5b020 --- /dev/null +++ b/src/config/apiEndpoints.js @@ -0,0 +1,117 @@ +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: Object.freeze({ ...ROUTES, ...LEGACY_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/config/apiRoutes.json b/src/config/apiRoutes.json new file mode 100644 index 0000000000000000000000000000000000000000..67b0a60c204ca6ac414a24a968ab123572735711 --- /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/directives/permission.js b/src/directives/permission.js index d05c1cc2a2cda6c6eef122d5005f6c2c77657994..9d3bce3928bb4a76900bfffcbc5c46d7ea02b8d6 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/i18n.js b/src/i18n.js index d32a238533579e0a95a93e76651d456abeaa36ae..bc6d3f40f88f8f37be56e26363f70a2d8c66e882 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 323e4a368f7d5623506f82fd9626cc5879e7558f..f920faa4f8e9fda7aa7e2b65f5c6259cd1545a46 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -244,9 +244,22 @@ import { formatDateTime, showErrorNotification, showSuccessNotification, + showWarningNotification, } 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, @@ -268,6 +281,7 @@ import { getServerVersion, } from "../api/basicapi"; import { clearRowVersionCache } from "@/api/baseapi"; +import { decodeJwtPayload, getUserIdentity, isTokenExpired } from "@/utils/jwt"; const serverVersion = ref(""); @@ -427,6 +441,84 @@ 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 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 () => { + 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 identity = getUserIdentity( + loginType.value, + localStorage.getItem("token") || "", + localStorage.getItem("account") || "", + ); + + if (!identity) { + showWarningNotification(getPermissionErrorMessage()); + 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 = () => { allowedPermissionCodes.value = parseStoredAllowedPermissions(); }; @@ -512,15 +604,45 @@ 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)); + + 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")); + + 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; @@ -582,7 +704,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"; @@ -590,9 +717,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 () => { @@ -602,9 +734,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")); @@ -768,24 +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 = ""; - 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 () => { @@ -798,9 +960,7 @@ const logout = async () => { localStorage.removeItem("username"); localStorage.removeItem("account"); localStorage.removeItem("loginType"); - localStorage.removeItem("allowedPaths"); - localStorage.removeItem("allowedMenuKeys"); - localStorage.removeItem("allowedPerms"); + clearAllowedPathsCache(); clearRowVersionCache(); isLoggedIn.value = false; allowedPermissionCodes.value = []; diff --git a/src/router/index.js b/src/router/index.js index 9d66eee8fb9bfc5a2335a035daa8f9436be55251..5c0f3285c04f7a57255df9faa2312961b7970412 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,31 @@ 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 && + Number.isFinite(allowedPathsExpire) && + allowedPathsExpire > now; 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 +358,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 c2d6195c551b5cbf3ed368fe450fe9cdfdc58f02..993c4bf9f9a2da7df5b9379b22c0b18a910823e0 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,22 +21,21 @@ 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"); localStorage.removeItem("allowedPerms"); localStorage.removeItem("allowedPaths"); localStorage.removeItem("allowedMenuKeys"); + localStorage.removeItem("allowedPathsToken"); + localStorage.removeItem("allowedPathsExpire"); + localStorage.removeItem("allowedPathsIssuedAt"); clearRowVersionCache(); - // 重定向到登录页 router.push("/signin"); } } catch (error) { @@ -52,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 0000000000000000000000000000000000000000..2d35289e2002f2edd9b51c52b30220071dc229e5 --- /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/utils/permission.js b/src/utils/permission.js index fc1bff84a5ebe0d69d6847c54979dcdc6f352904..090da8b29b5d7f036f89f17d4b82040ae0909d9e 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 faca434ff90f7a91e300a605e1cd8892f1b9c1ae..9732c156341112b7fe2d3250614b7274a44acd8e 100644 --- a/src/views/SignInView.vue +++ b/src/views/SignInView.vue @@ -200,7 +200,17 @@ const clearTwoFactorChallenge = () => { pendingLoginContext.value = null; }; +const clearPermissionCache = () => { + localStorage.removeItem("allowedPaths"); + localStorage.removeItem("allowedMenuKeys"); + localStorage.removeItem("allowedPerms"); + localStorage.removeItem("allowedPathsToken"); + localStorage.removeItem("allowedPathsExpire"); + localStorage.removeItem("allowedPathsIssuedAt"); +}; + const persistLoginData = async (userData, loginType) => { + clearPermissionCache(); clearRowVersionCache(); localStorage.setItem("token", userData.UserToken); localStorage.setItem( diff --git a/src/views/dashboard/DashboardView.vue b/src/views/dashboard/DashboardView.vue index bc64a515f2f3d396dd56a536014f13594a884166..bf20c7c0eddcc21b1a36c6e35a9bc4e29821e7e6 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 0000000000000000000000000000000000000000..0c2cabc140c2ba00ab077729c0f82bc794640d36 --- /dev/null +++ b/src/views/home/HomeView.vue @@ -0,0 +1,20 @@ + + + + {{ $t("message.welcome") }} + {{ username }} + + + + + + + diff --git a/src/views/systemmanagement/RoleManagementView.vue b/src/views/systemmanagement/RoleManagementView.vue index bb53526973ff51c13e83b091a51186c73f50f063..c862162e8165ad519157d479d1ae74e1d22834ea 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)); @@ -820,6 +825,7 @@ const handleRolePermSave = async () => { if (res && res.Success) { showSuccessNotification(t("message.updateSuccess")); rolePermModalVisible.value = false; + refreshCurrentSessionPermissions(); } else { showErrorNotification(res?.Message || t("message.operationFailed")); } @@ -1191,6 +1197,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 b8683e21d37bb6118a570f91d26d180f85affa1b..d316275e355e085dbbf168abecf6f7737cef1a3c 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")); }
{{ $t("message.welcome") }}
{{ username }}