1
This commit is contained in:
@ -129,10 +129,10 @@ export function getGoToken(): AxiosPromise<any> {
|
||||
data: {
|
||||
status: 'yjdsj',
|
||||
verifyCode: '1111',
|
||||
// username: 'admin',
|
||||
// password: 'zmkg@2023A'
|
||||
username: 'admin',
|
||||
password: 'zmkg@2023A'
|
||||
// username: 'admin1',
|
||||
// password: 'zmkg@2023C'
|
||||
password: 'zmkg@2023C'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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<any>;
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
Reference in New Issue
Block a user