diff --git a/package.json b/package.json index b7a876a..22f32a6 100644 --- a/package.json +++ b/package.json @@ -1,147 +1,148 @@ -{ - "name": "ant-design-pro", - "version": "6.0.0", - "private": true, - "description": "An out-of-box UI solution for enterprise applications", - "scripts": { - "dev": "npm run start:dev", - "build": "max build", - "deploy": "npm run build && npm run gh-pages", - "preview": "npm run build && max preview --port 8000", - "serve": "umi-serve", - "start": "cross-env UMI_ENV=dev max dev", - "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev", - "start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev", - "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev", - "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev", - "test": "jest", - "test:coverage": "npm run jest -- --coverage", - "test:update": "npm run jest -- -u", - "docker-hub:build": "docker build -f Dockerfile.hub -t ant-design-pro ./", - "docker-prod:build": "docker-compose -f ./docker/docker-compose.yml build", - "docker-prod:dev": "docker-compose -f ./docker/docker-compose.yml up", - "docker:build": "docker-compose -f ./docker/docker-compose.dev.yml build", - "docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up", - "docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro", - "docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro", - "analyze": "cross-env ANALYZE=1 max build", - "gh-pages": "gh-pages -d dist", - "i18n-remove": "pro i18n-remove --locale=zh-CN --write", - "postinstall": "max setup", - "jest": "jest", - "lint": "npm run lint:js && npm run lint:prettier && npm run tsc", - "lint-staged": "lint-staged", - "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ", - "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src ", - "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src", - "lint:prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\" --end-of-line auto", - "openapi": "max openapi", - "prepare": "cd .. && husky install", - "prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\"", - "tsc": "tsc --noEmit", - "record": "cross-env NODE_ENV=development REACT_APP_ENV=test max record --scene=login" - }, - "lint-staged": { - "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js", - "**/*.{js,jsx,tsx,ts,less,md,json}": [ - "prettier --write" - ] - }, - "browserslist": [ - "> 1%", - "last 2 versions", - "not ie <= 10" - ], - "dependencies": { - "@amap/amap-jsapi-loader": "^1.0.1", - "@ant-design/charts": "^2.3.0", - "@ant-design/icons": "^5.5.0", - "@ant-design/maps": "^1.0.0", - "@ant-design/plots": "^2.3.2", - "@ant-design/pro-components": "^2.8.7", - "@ant-design/use-emotion-css": "1.0.4", - "@testing-library/dom": "^10.4.0", - "@umijs/route-utils": "^4.0.1", - "ant-design-pro": "file:", - "antd": "^5.21.1", - "antd-style": "^3.6.2", - "classnames": "^2.5.1", - "dayjs": "^1.11.13", - "echarts": "^5.6.0", - "fabric": "^6.4.0", - "highlight.js": "^11.10.0", - "lodash": "^4.17.21", - "moment": "^2.30.1", - "omit.js": "^2.0.2", - "query-string": "^9.1.0", - "rc-menu": "^9.15.0", - "rc-util": "^5.43.0", - "react": "^18.3.0", - "react-cropper": "^2.3.3", - "react-dev-inspector": "^2.0.1", - "react-dom": "^18.3.0", - "react-helmet-async": "^2.0.0", - "react-highlight": "^0.15.0" - }, - "devDependencies": { - "@ant-design/pro-cli": "^3.3.0", - "@testing-library/react": "^16.0.1", - "@types/classnames": "^2.3.1", - "@types/express": "^4.17.21", - "@types/history": "^4.7.11", - "@types/jest": "^29.5.12", - "@types/lodash": "^4.17.4", - "@types/react": "^18.3.0", - "@types/react-dom": "^18.3.0", - "@types/react-helmet": "^6.1.11", - "@umijs/fabric": "^2.14.1", - "@umijs/lint": "^4.2.9", - "@umijs/max": "^4.2.9", - "cross-env": "^7.0.3", - "eslint": "^9.11.0", - "express": "^4.21.0", - "gh-pages": "^6.1.0", - "husky": "^9.1.3", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "lint-staged": "^15.2.0", - "mockjs": "^1.1.0", - "prettier": "^3.3.0", - "swagger-ui-dist": "^5.17.14", - "ts-node": "^10.9.1", - "typescript": "^5.6.2", - "umi-presets-pro": "^2.0.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "create-umi": { - "ignoreScript": [ - "docker*", - "functions*", - "site", - "generateMock" - ], - "ignoreDependencies": [ - "netlify*", - "serverless" - ], - "ignore": [ - ".dockerignore", - ".git", - ".github", - ".gitpod.yml", - "CODE_OF_CONDUCT.md", - "Dockerfile", - "Dockerfile.*", - "lambda", - "LICENSE", - "netlify.toml", - "README.*.md", - "azure-pipelines.yml", - "docker", - "CNAME", - "create-umi" - ] - } -} +{ + "name": "ant-design-pro", + "version": "6.0.0", + "private": true, + "description": "An out-of-box UI solution for enterprise applications", + "scripts": { + "dev": "npm run start:dev", + "build": "max build", + "deploy": "npm run build && npm run gh-pages", + "preview": "npm run build && max preview --port 8000", + "serve": "umi-serve", + "start": "cross-env UMI_ENV=dev max dev", + "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev", + "start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev", + "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev", + "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev", + "test": "jest", + "test:coverage": "npm run jest -- --coverage", + "test:update": "npm run jest -- -u", + "docker-hub:build": "docker build -f Dockerfile.hub -t ant-design-pro ./", + "docker-prod:build": "docker-compose -f ./docker/docker-compose.yml build", + "docker-prod:dev": "docker-compose -f ./docker/docker-compose.yml up", + "docker:build": "docker-compose -f ./docker/docker-compose.dev.yml build", + "docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up", + "docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro", + "docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro", + "analyze": "cross-env ANALYZE=1 max build", + "gh-pages": "gh-pages -d dist", + "i18n-remove": "pro i18n-remove --locale=zh-CN --write", + "postinstall": "max setup", + "jest": "jest", + "lint": "npm run lint:js && npm run lint:prettier && npm run tsc", + "lint-staged": "lint-staged", + "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ", + "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src ", + "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src", + "lint:prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\" --end-of-line auto", + "openapi": "max openapi", + "prepare": "cd .. && husky install", + "prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\"", + "tsc": "tsc --noEmit", + "record": "cross-env NODE_ENV=development REACT_APP_ENV=test max record --scene=login" + }, + "lint-staged": { + "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js", + "**/*.{js,jsx,tsx,ts,less,md,json}": [ + "prettier --write" + ] + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 10" + ], + "dependencies": { + "@amap/amap-jsapi-loader": "^1.0.1", + "@ant-design/charts": "^2.3.0", + "@ant-design/icons": "^5.5.0", + "@ant-design/maps": "^1.0.0", + "@ant-design/plots": "^2.3.2", + "@ant-design/pro-components": "^2.8.7", + "@ant-design/use-emotion-css": "1.0.4", + "@testing-library/dom": "^10.4.0", + "@umijs/route-utils": "^4.0.1", + "ant-design-pro": "file:", + "antd": "^5.21.1", + "antd-style": "^3.6.2", + "classnames": "^2.5.1", + "dayjs": "^1.11.13", + "echarts": "^5.6.0", + "fabric": "^6.4.0", + "highlight.js": "^11.10.0", + "lodash": "^4.17.21", + "moment": "^2.30.1", + "omit.js": "^2.0.2", + "query-string": "^9.1.0", + "rc-menu": "^9.15.0", + "rc-util": "^5.43.0", + "react": "^18.3.0", + "react-cropper": "^2.3.3", + "react-dev-inspector": "^2.0.1", + "react-dom": "^18.3.0", + "react-helmet-async": "^2.0.0", + "react-highlight": "^0.15.0", + "sm-crypto": "^0.3.13" + }, + "devDependencies": { + "@ant-design/pro-cli": "^3.3.0", + "@testing-library/react": "^16.0.1", + "@types/classnames": "^2.3.1", + "@types/express": "^4.17.21", + "@types/history": "^4.7.11", + "@types/jest": "^29.5.12", + "@types/lodash": "^4.17.4", + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@types/react-helmet": "^6.1.11", + "@umijs/fabric": "^2.14.1", + "@umijs/lint": "^4.2.9", + "@umijs/max": "^4.2.9", + "cross-env": "^7.0.3", + "eslint": "^9.11.0", + "express": "^4.21.0", + "gh-pages": "^6.1.0", + "husky": "^9.1.3", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "lint-staged": "^15.2.0", + "mockjs": "^1.1.0", + "prettier": "^3.3.0", + "swagger-ui-dist": "^5.17.14", + "ts-node": "^10.9.1", + "typescript": "^5.6.2", + "umi-presets-pro": "^2.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "create-umi": { + "ignoreScript": [ + "docker*", + "functions*", + "site", + "generateMock" + ], + "ignoreDependencies": [ + "netlify*", + "serverless" + ], + "ignore": [ + ".dockerignore", + ".git", + ".github", + ".gitpod.yml", + "CODE_OF_CONDUCT.md", + "Dockerfile", + "Dockerfile.*", + "lambda", + "LICENSE", + "netlify.toml", + "README.*.md", + "azure-pipelines.yml", + "docker", + "CNAME", + "create-umi" + ] + } +} diff --git a/src/app.tsx b/src/app.tsx index 3b854bf..f793938 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -17,6 +17,7 @@ import { import { PageEnum } from './enums/pagesEnums'; import { stringify } from 'querystring'; import { message } from 'antd'; +import { encrypt, decrypt, needEncrypt } from '@/utils/encrypt'; const isDev = process.env.NODE_ENV === 'development'; const loginOut = async () => { @@ -217,18 +218,20 @@ export async function render(oldRender: () => void) { const checkRegion = 5 * 60 * 1000; export const request = { ...errorConfig, - // baseURL: process.env.NODE_ENV === 'development' ? '' : 'https://qd.zhaopinzao8dian.com/api', + baseURL: process.env.NODE_ENV === 'development' ? '' : 'https://qd.zhaopinzao8dian.com/api', // baseURL: 'http://39.98.44.136:8080', - baseURL: - process.env.NODE_ENV === 'development' - ? 'http://10.213.6.207:19010' - : 'http://10.213.6.207:19010/api', + // baseURL: + // process.env.NODE_ENV === 'development' + // ? 'http://10.213.6.207:19010' + // : 'http://10.213.6.207:19010/api', requestInterceptors: [ - (url: any, options: { headers: any }) => { - const headers = options.headers ? options.headers : []; + (url: any, options: { headers: any; data?: any; params?: any; method?: string }) => { + const headers = options.headers ? options.headers : {}; console.log('request ====>:', url); const authHeader = headers['Authorization']; const isToken = headers['isToken']; + + // 处理认证token if (!authHeader && isToken !== false) { const expireTime = getTokenExpireTime(); if (expireTime) { @@ -248,18 +251,82 @@ export const request = { clearSessionToken(); } } + + // 处理SM4加密 - 根据config的isEncrypt来判断 + if (needEncrypt(options)) { + console.log('进行SM4加密处理'); + + let requestData = options.data; + let requestParams = options.params; + + // 加密请求数据 + if (requestData && Object.keys(requestData).length > 0) { + const jsonData = JSON.stringify(requestData); + const encryptedBody = encrypt(jsonData); + requestData = { + encrypted: true, + encryptedData: encryptedBody, + timestamp: Date.now(), + }; + } + + // 加密查询参数 + if (requestParams && Object.keys(requestParams).length > 0) { + const jsonParams = JSON.stringify(requestParams); + const encryptedParams = encrypt(jsonParams); + requestParams = { + encrypted: true, + encryptedData: encryptedParams, + timestamp: Date.now(), + }; + } + + // 添加加密标识头 + headers['X-Encrypted'] = 'true'; + + return { + url, + options: { + ...options, + headers, + data: requestData, + params: requestParams, + }, + }; + } + + // 处理开发环境API路径 if (process.env.NODE_ENV !== 'development') { if (url.startsWith('/api')) { url = url.replace(/^\/api/, ''); } } - return { url, options }; + + return { url, options: { ...options, headers } }; }, ], responseInterceptors: [ (response) => { // 不再需要异步处理读取返回体内容,可直接在data中读出,部分字段可在 config 中找到 const { data = {} as any, config } = response; + + // 检查是否需要解密 + const isEncrypted = data.encrypted; + + if (isEncrypted && data.encryptedData) { + console.log('进行SM4解密处理'); + try { + // 解密响应数据 + const decryptedData = decrypt(data.encryptedData); + response.data = + typeof decryptedData === 'string' ? JSON.parse(decryptedData) : decryptedData; + } catch (error) { + console.error('响应解密失败:', error); + // 如果解密失败,保持原始数据 + } + } + + // 处理业务状态码 switch (data.code) { case 401: loginOut(); @@ -268,8 +335,7 @@ export const request = { if (data.code !== 200 && data.msg) { message.info(data.msg); } - // console.log('data: ', data) - // console.log('config: ', config) + return response; }, ], diff --git a/src/services/mobileusers/list.ts b/src/services/mobileusers/list.ts index e40590b..39e51dc 100644 --- a/src/services/mobileusers/list.ts +++ b/src/services/mobileusers/list.ts @@ -5,6 +5,7 @@ export async function getCmsAppUserList(params?: API.MobileUser.ListParams) { return request(`/api/cms/appUser/list`, { method: 'GET', params: params, + isEncrypt: true, }); } diff --git a/src/services/resumeLibrary/resumeList.ts b/src/services/resumeLibrary/resumeList.ts index a82a9f4..61d44b1 100644 --- a/src/services/resumeLibrary/resumeList.ts +++ b/src/services/resumeLibrary/resumeList.ts @@ -4,11 +4,13 @@ export async function getResumeList(params?: API.AppUser.ListParams) { return request(`/api/cms/appUser/getResumeList`, { method: 'GET', params: params, + isEncrypt: true, }); } export async function getResumeDetail(userId: string) { return request(`/api/cms/appUser/getResumeDetail/${userId}`, { method: 'GET', + isEncrypt: true, }); } diff --git a/src/services/system/auth.ts b/src/services/system/auth.ts index b757618..ab64ec4 100644 --- a/src/services/system/auth.ts +++ b/src/services/system/auth.ts @@ -22,6 +22,7 @@ export async function login(body: API.LoginParams, options?: Record 'Content-Type': 'application/json', }, data: body, + isEncrypt: true, ...(options || {}), }); } diff --git a/src/services/system/user.ts b/src/services/system/user.ts index da997bf..637f305 100644 --- a/src/services/system/user.ts +++ b/src/services/system/user.ts @@ -4,14 +4,18 @@ import { DataNode } from 'antd/es/tree'; import { downLoadXlsx } from '@/utils/downloadfile'; // 查询用户信息列表 -export async function getUserList(params?: API.System.UserListParams, options?: { [key: string]: any }) { +export async function getUserList( + params?: API.System.UserListParams, + options?: { [key: string]: any }, +) { return request('/api/system/user/list', { method: 'GET', headers: { 'Content-Type': 'application/json;charset=UTF-8', }, params, - ...(options || {}) + isEncrypt: true, + ...(options || {}), }); } @@ -19,7 +23,7 @@ export async function getUserList(params?: API.System.UserListParams, options?: export function getUser(userId: number, options?: { [key: string]: any }) { return request(`/api/system/user/${userId}`, { method: 'GET', - ...(options || {}) + ...(options || {}), }); } @@ -31,7 +35,8 @@ export async function addUser(params: API.System.User, options?: { [key: string] 'Content-Type': 'application/json;charset=UTF-8', }, data: params, - ...(options || {}) + isEncrypt: true, + ...(options || {}), }); } @@ -43,7 +48,7 @@ export async function updateUser(params: API.System.User, options?: { [key: stri 'Content-Type': 'application/json;charset=UTF-8', }, data: params, - ...(options || {}) + ...(options || {}), }); } @@ -51,7 +56,7 @@ export async function updateUser(params: API.System.User, options?: { [key: stri export async function removeUser(ids: string, options?: { [key: string]: any }) { return request(`/api/system/user/${ids}`, { method: 'DELETE', - ...(options || {}) + ...(options || {}), }); } @@ -64,74 +69,73 @@ export function exportUser(params?: API.System.UserListParams, options?: { [key: export function changeUserStatus(userId: number, status: string) { const data = { userId, - status - } + status, + }; return request('/api/system/user/changeStatus', { method: 'put', - data: data - }) + data: data, + }); } // 查询用户个人信息 export function getUserProfile() { return request('/api/system/user/profile', { - method: 'get' - }) + method: 'get', + }); } export function updateUserProfile(data: API.CurrentUser) { return request('/api/system/user/profile', { method: 'put', - data: data - }) + data: data, + }); } // 用户密码重置 export function resetUserPwd(userId: number, password: string) { const data = { userId, - password - } + password, + }; return request('/api/system/user/resetPwd', { method: 'put', - data: data - }) + data: data, + }); } // 用户t个人密码重置 export function updateUserPwd(oldPassword: string, newPassword: string) { const data = { oldPassword, - newPassword - } + newPassword, + }; return request('/api/system/user/profile/updatePwd', { method: 'put', - params: data - }) + params: data, + }); } // 用户头像上传 export function uploadAvatar(data: any) { return request('/api/system/user/profile/avatar', { method: 'post', - data: data - }) + data: data, + }); } - // 查询授权角色 export function getAuthRole(userId: number) { return request('/system/user/authRole/' + userId, { - method: 'get' - }) + method: 'get', + }); } // 保存授权角色 export function updateAuthRole(data: Record) { return request('/system/user/authRole', { method: 'put', - params: data - }) + params: data, + }); } // 获取数据列表 diff --git a/src/utils/encrypt.ts b/src/utils/encrypt.ts new file mode 100644 index 0000000..3a1022f --- /dev/null +++ b/src/utils/encrypt.ts @@ -0,0 +1,47 @@ +import { sm4 } from 'sm-crypto'; + +const pwdKey = '86C63180C1306ABC4D8F989E0A0BC9F3'; // 32位十六进制密钥,与移动端一致 + +/** + * 加密文本 + * @param text 待加密文本 + */ +export function encrypt(text: any): string { + if (typeof text !== 'string') { + text = JSON.stringify(text); + } + return sm4.encrypt(text, pwdKey, { + output: 'string', + padding: 'pkcs#5', + }); +} + +/** + * 解密密文 + * @param text 待解密密文 + */ +export function decrypt(text: string): any { + try { + const decrypted = sm4.decrypt(text, pwdKey, { + output: 'string', + padding: 'pkcs#5', + }); + + // 尝试解析为JSON,如果不是JSON则直接返回字符串 + try { + return JSON.parse(decrypted); + } catch { + return decrypted; + } + } catch (error) { + console.error('SM4解密失败:', error); + return text; // 解密失败返回原文本 + } +} + +/** + * 判断是否需要加密处理 + */ +export function needEncrypt(options: any): boolean { + return options?.isEncrypt === true; +}