From f006ca5a2b950815fc471e9d4e4705b718bcba4f Mon Sep 17 00:00:00 2001 From: Teo <2642673902@qq.com> Date: Tue, 9 Sep 2025 14:45:43 +0800 Subject: [PATCH] 1 --- .env.development | 5 +- .env.production | 2 +- src/api/login.ts | 6 +- src/utils/request-go.ts | 287 +++++++++++++++--- .../landTransferLedger/index.vue | 5 + 5 files changed, 265 insertions(+), 40 deletions(-) diff --git a/.env.development b/.env.development index 339c4ab..e9d12d1 100644 --- a/.env.development +++ b/.env.development @@ -5,10 +5,11 @@ VITE_APP_TITLE = 煤科建管平台 VITE_APP_ENV = 'development' # 开发环境 -VITE_APP_BASE_API = 'http://192.168.110.209:8899' +VITE_APP_BASE_API = 'http://192.168.110.149:8899' # VITE_APP_BASE_API = 'http://58.17.134.85:8899' # GO开发环境 -VITE_APP_BASE_API_GO = 'http://192.168.110.188:8919' +VITE_APP_BASE_API_GO = 'http://xny.yj-3d.com:7464' +# VITE_APP_BASE_API_GO = 'http://192.168.110.188:8919' # 无人机接口地址 diff --git a/.env.production b/.env.production index 9ccb1f8..58af0c1 100644 --- a/.env.production +++ b/.env.production @@ -15,7 +15,7 @@ VITE_APP_SNAILJOB_ADMIN = '/snail-job' # 生产环境 # GO生产环境 -VITE_APP_BASE_API_GO = 'http://58.17.134.85:7363' +VITE_APP_BASE_API_GO = 'http://58.17.134.85:7464' VITE_APP_BASE_API = 'http://xny.yj-3d.com:8899' # 是否在打包时开启压缩,支持 gzip 和 brotli diff --git a/src/api/login.ts b/src/api/login.ts index 8ef5161..ad6715f 100644 --- a/src/api/login.ts +++ b/src/api/login.ts @@ -129,10 +129,10 @@ export function getGoToken(): AxiosPromise { data: { status: 'yjdsj', verifyCode: '1111', + // username: 'admin', + // password: 'zmkg@2023A' username: 'admin', - password: 'zmkg@2023A' - // username: 'admin1', - // password: 'zmkg@2023C' + password: 'zmkg@2023C' } }); } diff --git a/src/utils/request-go.ts b/src/utils/request-go.ts index 70e529e..7bc0667 100644 --- a/src/utils/request-go.ts +++ b/src/utils/request-go.ts @@ -1,51 +1,270 @@ import $cache from '@/plugins/cache'; +import useUserStore from '@/store/modules/user'; import request from '@/utils/request'; - +import axios from 'axios'; +import sign from '@/utils/sign.js'; +import CryptoJS from 'crypto-js'; /** * 包装 request 请求,统一使用 Go 服务地址作为 baseURL * @param config 原始请求配置 */ const BASE_GO_URL = import.meta.env.VITE_APP_BASE_API_GO; +const token = $cache.local.get('goToken'); interface RequestGo extends Function { (config: any): Promise; download?: (url: string, params: any, filename: string) => void; } -const requestGo: RequestGo = (config: any) => { - return request({ - baseURL: BASE_GO_URL, - ...config, - headers: { - 'Authorization': `Bearer ${$cache.local.get('goToken') || ''}` +// 加密密钥 +const corySecretKey = 'happyCoryOrTieHanHan202410151415'; + +// 配置新建一个 axios 实例 +const service = axios.create({ + baseURL: BASE_GO_URL as any, + timeout: 120000, + headers: { 'Content-Type': 'application/json' } +}); + +// 不需要修改项目id的接口数组 +const whiteUrl = [ + '/api/wxApplet/wxApplet/sysProjectTeam/list', + '/api/wxApplet/wxApplet/sysProjectTeam/add', + '/api/wxApplet/wxApplet/sysProjectTeam/edit', + '/api/v1/test/testFollowInfo/add', + '/api/wxApplet/wxApplet/busConstructionUser/changePay', + // 获取项目资料文件夹 + '/api/v1/system/documentData/treeStructureData', + '/api/v1/system/busConstructionUser/exportSalary', + '/api/v1/system/busSalaryDetails/list', + '/api/v1/system/ys7Devices/add', + '/api/v1/system/ys7Devices/edit', + '/api/v1/system/subProject/add', + '/api/v1/system/subProject/edit', + '/api/v1/system/subProject/list', + '/api/v1/system/workStatus/getTree', + '/api/v1/system/sysProjectIntroduce/list', + '/api/v1/system/sysProjectIntroduce/add', + '/api/v1/system/sysProjectIntroduce/edit', + '/video/hat/manage/api/v1/video/device/list', + '/video/hat/manage/api/v1/video/project/bind', + '/api/v1/system/notifications/publish', + '/api/v1/system/notifications/list', + '/api/v1/system/notifications/edit', + '/webodm/api/v1/taskCreate', + '/webodm/api/v1/taskProcess', + '/webodm/api/v1/download', + '/api/v1/system/manageTaskRecord/upDataResource', + '/api/v1/system/ys7Devices/list', + '/api/v1/system/busFolderFile/add', + '/api/v1/system/manageTaskRecordResource/voluntarilyReq', + '/api/v1/system/busAttendanceMachine/edit', + '/api/v1/system/qianqiFangzhen/add', + '/api/v1/system/qianqiNibianqi/add' +]; + +const exceptionStr = '/api/v1/test/'; // /api/v1/test/*接口拦截 + +// 添加请求拦截器 +service.interceptors.request.use( + (config: any) => { + // 在发送请求之前做些什么 token + if (token) { + config.headers = config.headers || {}; + (config.headers as any)['Authorization'] = `Bearer ${token}`; } - }); -}; + const stores = useUserStore(); + if (!whiteUrl.includes(config.url) && !config.url.includes(exceptionStr)) { + if (config.params && Reflect.has(config.params, 'projectId')) { + config.params.projectId = stores.selectedProject.goId; + } + // 处理FormData中的projectId + if (config.data instanceof FormData && config.data.has('projectId')) { + config.data.set('projectId', stores.selectedProject.goId); + } + } + let dataInfoReq = {}; + if (config.method === 'get' || config.method === 'delete') { + config.params = config.params || {}; + dataInfoReq = JSON.parse(JSON.stringify(config.params)); + const encryptedParam = encryptAES256(JSON.stringify(dataInfoReq), corySecretKey); + if ($cache.local.get('i18n') != null) { + config.params = { coryKey: encryptedParam, corySimplifiedToTraditional: $cache.local.get('i18n') }; + } else { + config.params = { coryKey: encryptedParam }; + } + } else { + // 处理FormData类型 + if (config.data instanceof FormData) { + // 将FormData转换为普通对象 + dataInfoReq = Object.fromEntries(config.data.entries()); + // 重新创建一个新的FormData实例 + const newFormData = new FormData(); + const encryptedData = encryptAES256(JSON.stringify(dataInfoReq), corySecretKey); -requestGo.download = function (url: string, params: any, filename: string, method: 'post' | 'get' = 'post') { - return request({ - url, - method: method, - baseURL: BASE_GO_URL, - data: method === 'post' ? params : undefined, - params: method === 'get' ? params : undefined, - headers: { - 'Authorization': `Bearer ${$cache.local.get('goToken') || ''}` - }, - responseType: 'blob' - }).then((response) => { - // ✅ 只取 response.data - const blob = new Blob([response.data]); - const link = document.createElement('a'); - link.style.display = 'none'; - link.href = URL.createObjectURL(blob); - link.setAttribute('download', filename); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - URL.revokeObjectURL(link.href); - }); -}; + newFormData.append('coryKey', encryptedData); + if ($cache.local.get('i18n') != null) { + newFormData.append('corySimplifiedToTraditional', $cache.local.get('i18n')); + } -export default requestGo; + // 如果有文件,需要重新添加 + for (let [key, value] of config.data.entries()) { + if (value instanceof File) { + newFormData.append(key, value); + } + } + + config.data = newFormData; + // 设置Content-Type为undefined,让浏览器自动设置boundary + config.headers['Content-Type'] = undefined; + } else { + dataInfoReq = config.data; + const encryptedData = encryptAES256(JSON.stringify(dataInfoReq), corySecretKey); + if ($cache.local.get('i18n') != null) { + config.data = { coryKey: encryptedData, corySimplifiedToTraditional: $cache.local.get('i18n') }; + } else { + config.data = { coryKey: encryptedData }; + } + } + } + + const { timestamp, nonce, sign: signature } = sign(dataInfoReq); + config.headers.timestamp = timestamp; + config.headers.nonce = nonce; + config.headers.sign = signature; + + return config; + }, + (error) => { + // 对请求错误做些什么 + return Promise.reject(error); + } +); +// 添加响应拦截器 +service.interceptors.response.use( + (response) => { + // 对响应数据进行解密操作 + try { + // 处理特殊情况:data为空值或不需要解密的情况 + if (response.data.data === null || response.data.data === '' || response.data.data === undefined) { + return response.data; + } + + // 检查响应数据格式 + if (typeof response.data.data !== 'string') { + // 尝试将非字符串数据转换为字符串 + try { + response.data.data = JSON.stringify(response.data.data); + } catch (convertError) { + throw new Error('响应数据格式不正确,无法转换为字符串'); + } + } + // 执行解密 + const decryptedData = decryptAES256(response.data.data, corySecretKey); + // 正确处理解密后的数据 + if (decryptedData && typeof decryptedData === 'object') { + // 保持response.data的结构不变,只替换data字段的内容 + response.data = { + ...response.data, + data: decryptedData + }; + } else { + // 如果解密后的数据不是对象,可能需要特殊处理 + response.data.data = decryptedData; + } + if (response.data.code !== 0) { + ElMessage.error(response.data.message); + } + return response.data; + } catch (decryptError) { + // 提供更友好的错误信息 + if (decryptError.message.includes('无效的Base64格式')) { + ElMessage.error('数据格式错误:接收到无效的加密数据'); + } else { + ElMessage.error('数据解密失败,请联系管理员'); + } + + return Promise.reject(decryptError); + } + }, + (error) => { + // 对响应错误做点什么 + if (error.message.indexOf('timeout') !== -1) { + ElMessage.error('网络超时'); + } else if (error.message === 'Network Error') { + ElMessage.error('网络连接错误'); + } else { + console.log(error, '网络错误'); + + if (error.response.data) ElMessage.error(error.response.statusText); + else { + ElMessage.error('接口路径找不到'); + console.log(error, '接口路径找不到'); + } + } + return Promise.reject(error); + } +); + +// 加密函数 +function encryptAES256(plainText: string, key: string): string | null { + try { + const parsedKey = CryptoJS.enc.Utf8.parse(key); + const iv = CryptoJS.lib.WordArray.random(16); + const plainTextWordArray = CryptoJS.enc.Utf8.parse(plainText); + const encrypted = CryptoJS.AES.encrypt(plainTextWordArray, parsedKey, { + iv: iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7 + }); + const encryptedData = iv.concat(encrypted.ciphertext); + return encryptedData.toString(CryptoJS.enc.Base64); + } catch (err) { + console.error('Encryption error:', err.message); + return null; + } +} + +// 增强的解密函数,处理各种输入情况 +function decryptAES256(encryptedData: string, key: string): any { + // eslint-disable-next-line no-useless-catch + try { + // 检查输入是否为有效的Base64字符串 + if (!/^[A-Za-z0-9+/=]+$/.test(encryptedData)) { + // 尝试对非标准Base64字符串进行处理 + // 移除可能的前缀 + const cleanData = encryptedData.replace(/^data:.*?;base64,/, '').replace(/\s/g, ''); // 移除空格 + + if (!/^[A-Za-z0-9+/=]+$/.test(cleanData)) { + throw new Error('无效的Base64格式'); + } + + return decryptAES256(cleanData, key); + } + + const decodedData = CryptoJS.enc.Base64.parse(encryptedData); + const iv = CryptoJS.lib.WordArray.create(decodedData.words.slice(0, 4)); + const encryptedText = CryptoJS.lib.WordArray.create(decodedData.words.slice(4)); + const parsedKey = CryptoJS.enc.Utf8.parse(key); + + const decrypted = CryptoJS.AES.decrypt({ ciphertext: encryptedText }, parsedKey, { + iv: iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7 + }); + + const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8); + + // 尝试解析为JSON + try { + return JSON.parse(decryptedStr); + } catch (jsonError) { + return decryptedStr; + } + } catch (err) { + throw err; + } +} +// 导出 axios 实例 +export default service; diff --git a/src/views/project/landTransfer/BusinessLedger/landTransferLedger/index.vue b/src/views/project/landTransfer/BusinessLedger/landTransferLedger/index.vue index 019a32e..71eef7a 100644 --- a/src/views/project/landTransfer/BusinessLedger/landTransferLedger/index.vue +++ b/src/views/project/landTransfer/BusinessLedger/landTransferLedger/index.vue @@ -1089,6 +1089,11 @@ const submitForm = () => { proxy?.$modal.msgSuccess('操作成功'); dialog.visible = false; await getList(); + } catch (error) { + console.error('操作失败:', error); + proxy?.$modal.msgError('操作失败,请重试'); + } finally { + buttonLoading.value = false; } }); };