feat: update
This commit is contained in:
@@ -1,145 +1,101 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
|
||||
import { message } from 'antd'
|
||||
/** @format */
|
||||
|
||||
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
|
||||
import { message } from "antd";
|
||||
|
||||
class Request {
|
||||
private instance: AxiosInstance | undefined
|
||||
private instance: AxiosInstance | undefined;
|
||||
|
||||
constructor(config: AxiosRequestConfig) {
|
||||
this.instance = axios.create(config)
|
||||
// 全局请求拦截
|
||||
this.instance.interceptors.request.use(
|
||||
(config) => {
|
||||
return config
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
constructor(config: AxiosRequestConfig) {
|
||||
this.instance = axios.create(config);
|
||||
// 全局请求拦截
|
||||
this.instance.interceptors.request.use(
|
||||
(config) => {
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
// 全局响应拦截
|
||||
this.instance.interceptors.response.use(
|
||||
(res) => {
|
||||
// if (res.data.code && res.data.code !== 200) {
|
||||
// message.error(res.data.message).then()
|
||||
// return Promise.reject(res.data)
|
||||
// }
|
||||
return res.data
|
||||
},
|
||||
(error) => {
|
||||
const { response } = error
|
||||
if (response) {
|
||||
this.handleCode(response.status)
|
||||
}
|
||||
if (!window.navigator.onLine) {
|
||||
message.error('网络连接失败')
|
||||
// return router.push({
|
||||
// path: '/404',
|
||||
// })
|
||||
return Promise.reject(error)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
handleCode(code: number): void {
|
||||
switch (code) {
|
||||
case 400:
|
||||
message.error('请求错误(400)')
|
||||
break
|
||||
case 401:
|
||||
message.error('未授权,请重新登录(401)')
|
||||
break
|
||||
case 403:
|
||||
message.error('拒绝访问(403)')
|
||||
break
|
||||
case 404:
|
||||
message.error('请求出错(404)')
|
||||
break
|
||||
case 408:
|
||||
message.error('请求超时(408)')
|
||||
break
|
||||
case 500:
|
||||
message.error('服务器错误(500)')
|
||||
break
|
||||
case 501:
|
||||
message.error('服务未实现(501)')
|
||||
break
|
||||
case 502:
|
||||
message.error('网络错误(502)')
|
||||
break
|
||||
case 503:
|
||||
message.error('服务不可用(503)')
|
||||
break
|
||||
case 504:
|
||||
message.error('网络超时(504)')
|
||||
break
|
||||
case 505:
|
||||
message.error('HTTP版本不受支持(505)')
|
||||
break
|
||||
default:
|
||||
message.error(`连接出错(${code})!`)
|
||||
break
|
||||
}
|
||||
}
|
||||
request<T>(config: AxiosRequestConfig<T>): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.instance
|
||||
?.request<any, T>(config)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
// 全局响应拦截
|
||||
this.instance.interceptors.response.use(
|
||||
(res) => {
|
||||
// if (res.data.code && res.data.code !== 200) {
|
||||
// message.error(res.data.message).then()
|
||||
// return Promise.reject(res.data)
|
||||
// }
|
||||
return res.data;
|
||||
},
|
||||
(error) => {
|
||||
const { response } = error;
|
||||
if (response) {
|
||||
this.handleCode(response.status);
|
||||
}
|
||||
if (!window.navigator.onLine) {
|
||||
message.error("网络连接失败");
|
||||
// return router.push({
|
||||
// path: '/404',
|
||||
// })
|
||||
return Promise.reject(error);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
get(url: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
?.get(url)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
handleCode(code: number): void {
|
||||
switch (code) {
|
||||
case 400:
|
||||
message.error("请求错误(400)").then();
|
||||
break;
|
||||
case 401:
|
||||
message.error("未授权,请重新登录(401)").then();
|
||||
break;
|
||||
case 403:
|
||||
message.error("拒绝访问(403)").then();
|
||||
break;
|
||||
case 404:
|
||||
message.error("请求出错(404)").then();
|
||||
break;
|
||||
case 408:
|
||||
message.error("请求超时(408)").then();
|
||||
break;
|
||||
case 500:
|
||||
message.error("服务器错误(500)").then();
|
||||
break;
|
||||
case 501:
|
||||
message.error("服务未实现(501)").then();
|
||||
break;
|
||||
case 502:
|
||||
message.error("网络错误(502)").then();
|
||||
break;
|
||||
case 503:
|
||||
message.error("服务不可用(503)").then();
|
||||
break;
|
||||
case 504:
|
||||
message.error("网络超时(504)").then();
|
||||
break;
|
||||
case 505:
|
||||
message.error("HTTP版本不受支持(505)").then();
|
||||
break;
|
||||
default:
|
||||
message.error(`连接出错(${code})!`).then();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
post(url: string, data = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
?.post(url, data)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
put(url: string, data = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
?.put(url, data)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
delete(url: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
?.delete(url)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
request<T>(config: AxiosRequestConfig<T>): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.instance
|
||||
?.request<any, T>(config)
|
||||
.then((res) => {
|
||||
resolve(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
export default Request
|
||||
|
||||
export default Request;
|
||||
|
@@ -1,14 +1,16 @@
|
||||
import Request from './request'
|
||||
import { handleLocalforage } from '@/utils/localforage'
|
||||
/** @format */
|
||||
|
||||
const token = String(handleLocalforage.getItem('token'))
|
||||
import Request from "./request";
|
||||
import { handleLocalforage } from "@/utils/localforage";
|
||||
|
||||
const token = String(handleLocalforage.getItem("token"));
|
||||
const web: Request = new Request({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||
headers: {
|
||||
// 'Content-Type': 'application/json;charset=utf-8',
|
||||
// Accept: 'application/json',
|
||||
Authorization: token,
|
||||
},
|
||||
})
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||
headers: {
|
||||
// 'Content-Type': 'application/json;charset=utf-8',
|
||||
// Accept: 'application/json',
|
||||
Authorization: token,
|
||||
},
|
||||
});
|
||||
|
||||
export default web
|
||||
export default web;
|
||||
|
@@ -1,85 +1,91 @@
|
||||
/** 配置 */
|
||||
/**
|
||||
* 配置
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
interface Options {
|
||||
/** key前缀 */
|
||||
prefix?: string
|
||||
/** key前缀 */
|
||||
prefix?: string;
|
||||
}
|
||||
|
||||
/** 默认配置 */
|
||||
const defaultOptions: Options = {
|
||||
prefix: '',
|
||||
}
|
||||
prefix: "",
|
||||
};
|
||||
|
||||
class CookieStorage {
|
||||
private prefix: string
|
||||
private prefix: string;
|
||||
|
||||
constructor(options: Options = defaultOptions) {
|
||||
const { prefix } = options
|
||||
this.prefix = prefix ?? ''
|
||||
}
|
||||
constructor(options: Options = defaultOptions) {
|
||||
const { prefix } = options;
|
||||
this.prefix = prefix ?? "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 设置cookie
|
||||
* @param {string} key 键
|
||||
* @param {any} value 值
|
||||
* @param {number} expires 过期时间s毫秒,不传默认2年有效
|
||||
* @Date: 2023-05-17 18:10:34
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public setItem(key: string, value: string | number, expires?: number): void {
|
||||
const timestamp = Date.now()
|
||||
if (typeof expires === 'number') {
|
||||
expires = timestamp + expires
|
||||
} else {
|
||||
expires = timestamp + 2 * 365 * 24 * 60 * 60 * 1000
|
||||
}
|
||||
document.cookie = `${this.prefix}${key}=${value};expires=${new Date(expires).toUTCString()}`
|
||||
}
|
||||
/**
|
||||
* @description: 设置cookie
|
||||
* @param {string} key 键
|
||||
* @param {any} value 值
|
||||
* @param {number} expires 过期时间s毫秒,不传默认2年有效
|
||||
* @Date: 2023-05-17 18:10:34
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public setItem(key: string, value: string | number, expires?: number): void {
|
||||
const timestamp = Date.now();
|
||||
if (typeof expires === "number") {
|
||||
expires = timestamp + expires;
|
||||
} else {
|
||||
expires = timestamp + 2 * 365 * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
document.cookie = `${this.prefix}${key}=${value};expires=${new Date(expires).toUTCString()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取cookie
|
||||
* @param {string} key 键
|
||||
* @Date: 2023-05-17 18:31:50
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public getItem(key: string): string | undefined {
|
||||
const cookies = document.cookie.split('; ')
|
||||
let val: string | undefined = undefined
|
||||
cookies.find((item) => {
|
||||
const [k, v] = item.split('=')
|
||||
if (k === `${this.prefix}${key}`) {
|
||||
val = v
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
/**
|
||||
* @description: 获取cookie
|
||||
* @param {string} key 键
|
||||
* @Date: 2023-05-17 18:31:50
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public getItem(key: string): string | undefined {
|
||||
const cookies = document.cookie.split("; ");
|
||||
let val: string | undefined = undefined;
|
||||
cookies.find((item) => {
|
||||
const [k, v] = item.split("=");
|
||||
if (k === `${this.prefix}${key}`) {
|
||||
val = v;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return val
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 删除指定key的cookie
|
||||
* @param {string} key 键
|
||||
* @Date: 2023-05-17 18:32:56
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public removeItem(key: string): void {
|
||||
this.setItem(key, '', -1)
|
||||
}
|
||||
/**
|
||||
* @description: 删除指定key的cookie
|
||||
* @param {string} key 键
|
||||
* @Date: 2023-05-17 18:32:56
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public removeItem(key: string): void {
|
||||
this.setItem(key, "", -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 清空所有cookie
|
||||
* @Date: 2023-05-17 23:13:04
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public clear(): void {
|
||||
const cookies = document.cookie.split('; ')
|
||||
cookies.forEach((item) => {
|
||||
const [k] = item.split('=')
|
||||
this.removeItem(k)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description: 清空所有cookie
|
||||
* @Date: 2023-05-17 23:13:04
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public clear(): void {
|
||||
const cookies = document.cookie.split("; ");
|
||||
cookies.forEach((item) => {
|
||||
const [k] = item.split("=");
|
||||
this.removeItem(k);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const cookieStorage = new CookieStorage()
|
||||
const cookieStorage = new CookieStorage();
|
||||
|
||||
export default cookieStorage
|
||||
export { CookieStorage }
|
||||
export default cookieStorage;
|
||||
export { CookieStorage };
|
||||
|
@@ -1,169 +1,173 @@
|
||||
import JSEncrypt from 'jsencrypt'
|
||||
import CryptoJS from 'crypto-js'
|
||||
/** @format */
|
||||
|
||||
import JSEncrypt from "jsencrypt";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
// 加密
|
||||
export function rsaEncrypt(Str: string, afterPublicKey: string) {
|
||||
const encryptor = new JSEncrypt()
|
||||
encryptor.setPublicKey(afterPublicKey) // 设置公钥
|
||||
return encryptor.encrypt(Str) // 对数据进行加密
|
||||
const encryptor = new JSEncrypt();
|
||||
encryptor.setPublicKey(afterPublicKey); // 设置公钥
|
||||
return encryptor.encrypt(Str); // 对数据进行加密
|
||||
}
|
||||
|
||||
// 解密
|
||||
export function rsaDecrypt(Str: string, frontPrivateKey: string) {
|
||||
const encryptor = new JSEncrypt()
|
||||
encryptor.setPrivateKey(frontPrivateKey) // 设置私钥
|
||||
return encryptor.decrypt(Str) // 对数据进行解密
|
||||
const encryptor = new JSEncrypt();
|
||||
encryptor.setPrivateKey(frontPrivateKey); // 设置私钥
|
||||
return encryptor.decrypt(Str); // 对数据进行解密
|
||||
}
|
||||
|
||||
export function aesEncrypt(aeskey: string, Str: string) {
|
||||
// 设置一个默认值,如果第二个参数为空采用默认值,不为空则采用新设置的密钥
|
||||
const key = CryptoJS.enc.Utf8.parse(aeskey)
|
||||
const srcs = CryptoJS.enc.Utf8.parse(Str)
|
||||
const encrypted = CryptoJS.AES.encrypt(srcs, key, {
|
||||
// 切记 需要和后端算法模式一致
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
// 设置一个默认值,如果第二个参数为空采用默认值,不为空则采用新设置的密钥
|
||||
const key = CryptoJS.enc.Utf8.parse(aeskey);
|
||||
const srcs = CryptoJS.enc.Utf8.parse(Str);
|
||||
const encrypted = CryptoJS.AES.encrypt(srcs, key, {
|
||||
// 切记 需要和后端算法模式一致
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
});
|
||||
|
||||
return encrypted.toString()
|
||||
return encrypted.toString();
|
||||
}
|
||||
|
||||
export function aesDecrypt(aeskey: string, Str: string) {
|
||||
const key = CryptoJS.enc.Utf8.parse(aeskey)
|
||||
const decrypt = CryptoJS.AES.decrypt(Str, key, {
|
||||
// 切记 需要和后端算法模式一致
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
return CryptoJS.enc.Utf8.stringify(decrypt).toString()
|
||||
const key = CryptoJS.enc.Utf8.parse(aeskey);
|
||||
const decrypt = CryptoJS.AES.decrypt(Str, key, {
|
||||
// 切记 需要和后端算法模式一致
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
});
|
||||
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取16位随机码AES
|
||||
* @returns {string}
|
||||
*/
|
||||
export function get16RandomNum() {
|
||||
const chars = [
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
]
|
||||
let nums = ''
|
||||
//这个地方切记要选择16位,因为美国对密钥长度有限制,选择32位的话加解密会报错,需要根据jdk版本去修改相关jar包,有点恼火,选择16位就不用处理。
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const id = parseInt(String(Math.random() * 61))
|
||||
nums += chars[id]
|
||||
}
|
||||
return nums
|
||||
const chars = [
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
];
|
||||
let nums = "";
|
||||
//这个地方切记要选择16位,因为美国对密钥长度有限制,选择32位的话加解密会报错,需要根据jdk版本去修改相关jar包,有点恼火,选择16位就不用处理。
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const id = parseInt(String(Math.random() * 61));
|
||||
nums += chars[id];
|
||||
}
|
||||
return nums;
|
||||
}
|
||||
|
||||
//获取rsa密钥对
|
||||
export function getRsaKeys() {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.crypto.subtle
|
||||
.generateKey(
|
||||
{
|
||||
name: 'RSA-OAEP',
|
||||
modulusLength: 2048, //can be 1024, 2048, or 4096
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||
hash: { name: 'SHA-512' }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
},
|
||||
true, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
['encrypt', 'decrypt'], //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
|
||||
)
|
||||
.then(function (key) {
|
||||
window.crypto.subtle
|
||||
.exportKey('pkcs8', key.privateKey)
|
||||
.then(function (keydata1) {
|
||||
window.crypto.subtle
|
||||
.exportKey('spki', key.publicKey)
|
||||
.then(function (keydata2) {
|
||||
const privateKey = RSA2text(keydata1, 1)
|
||||
return new Promise((resolve, reject) => {
|
||||
window.crypto.subtle
|
||||
.generateKey(
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
modulusLength: 2048, //can be 1024, 2048, or 4096
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||
hash: { name: "SHA-512" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
},
|
||||
true, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
["encrypt", "decrypt"], //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
|
||||
)
|
||||
.then(function (key) {
|
||||
window.crypto.subtle
|
||||
.exportKey("pkcs8", key.privateKey)
|
||||
.then(function (keydata1) {
|
||||
window.crypto.subtle
|
||||
.exportKey("spki", key.publicKey)
|
||||
.then(function (keydata2) {
|
||||
const privateKey = RSA2text(keydata1, 1);
|
||||
|
||||
const publicKey = RSA2text(keydata2)
|
||||
const publicKey = RSA2text(keydata2);
|
||||
|
||||
resolve({ privateKey, publicKey })
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
resolve({ privateKey, publicKey });
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function RSA2text(buffer: any, _isPrivate: number = 0) {
|
||||
let binary = ''
|
||||
const bytes = new Uint8Array(buffer)
|
||||
const len = bytes.byteLength
|
||||
for (let i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i])
|
||||
}
|
||||
const base64 = window.btoa(binary)
|
||||
const text = base64.replace(/[^\x00-\xff]/g, '$&\x01').replace(/.{64}\x01?/g, '$&\n')
|
||||
let binary = "";
|
||||
const bytes = new Uint8Array(buffer);
|
||||
const len = bytes.byteLength;
|
||||
for (let i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
const base64 = window.btoa(binary);
|
||||
const text = base64.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{64}\x01?/g, "$&\n");
|
||||
|
||||
return text
|
||||
return text;
|
||||
}
|
||||
|
@@ -1,102 +1,104 @@
|
||||
import { encrypt, decrypt } from './encry'
|
||||
import { globalConfig } from './interface'
|
||||
/** @format */
|
||||
|
||||
import { encrypt, decrypt } from "./encry";
|
||||
import { globalConfig } from "./interface";
|
||||
|
||||
const config: globalConfig = {
|
||||
type: 'localStorage', //存储类型,localStorage | sessionStorage
|
||||
prefix: 'schisandra_', //版本号
|
||||
expire: 24 * 60, //过期时间,默认为一天,单位为分钟
|
||||
isEncrypt: true, //支持加密、解密数据处理
|
||||
}
|
||||
type: "localStorage", //存储类型,localStorage | sessionStorage
|
||||
prefix: "schisandra_", //版本号
|
||||
expire: 24 * 60, //过期时间,默认为一天,单位为分钟
|
||||
isEncrypt: true, //支持加密、解密数据处理
|
||||
};
|
||||
|
||||
const setStorage = (key: string, value: any, expire: number = 24 * 60): boolean => {
|
||||
//设定值
|
||||
if (value === '' || value === null || value === undefined) {
|
||||
//空值重置
|
||||
value = null
|
||||
}
|
||||
if (isNaN(expire) || expire < 0) {
|
||||
//过期时间值合理性判断
|
||||
throw new Error('Expire must be a number')
|
||||
}
|
||||
const data = {
|
||||
value, //存储值
|
||||
time: Date.now(), //存储日期
|
||||
expire: Date.now() + 1000 * 60 * expire, //过期时间
|
||||
}
|
||||
//是否需要加密,判断装载加密数据或原数据
|
||||
window[config.type].setItem(
|
||||
autoAddPreFix(key),
|
||||
config.isEncrypt ? encrypt(JSON.stringify(data)) : JSON.stringify(data),
|
||||
)
|
||||
return true
|
||||
}
|
||||
//设定值
|
||||
if (value === "" || value === null || value === undefined) {
|
||||
//空值重置
|
||||
value = null;
|
||||
}
|
||||
if (isNaN(expire) || expire < 0) {
|
||||
//过期时间值合理性判断
|
||||
throw new Error("Expire must be a number");
|
||||
}
|
||||
const data = {
|
||||
value, //存储值
|
||||
time: Date.now(), //存储日期
|
||||
expire: Date.now() + 1000 * 60 * expire, //过期时间
|
||||
};
|
||||
//是否需要加密,判断装载加密数据或原数据
|
||||
window[config.type].setItem(
|
||||
autoAddPreFix(key),
|
||||
config.isEncrypt ? encrypt(JSON.stringify(data)) : JSON.stringify(data),
|
||||
);
|
||||
return true;
|
||||
};
|
||||
|
||||
const getStorageFromKey = (key: string) => {
|
||||
//获取指定值
|
||||
if (config.prefix) {
|
||||
key = autoAddPreFix(key)
|
||||
}
|
||||
if (!window[config.type].getItem(key)) {
|
||||
//不存在判断
|
||||
return null
|
||||
}
|
||||
//获取指定值
|
||||
if (config.prefix) {
|
||||
key = autoAddPreFix(key);
|
||||
}
|
||||
if (!window[config.type].getItem(key)) {
|
||||
//不存在判断
|
||||
return null;
|
||||
}
|
||||
|
||||
const storageVal = config.isEncrypt
|
||||
? JSON.parse(decrypt(window[config.type].getItem(key) as string))
|
||||
: JSON.parse(window[config.type].getItem(key) as string)
|
||||
const now = Date.now()
|
||||
if (now >= storageVal.expire) {
|
||||
//过期销毁
|
||||
removeStorageFromKey(key)
|
||||
return null
|
||||
//不过期回值
|
||||
} else {
|
||||
return storageVal.value
|
||||
}
|
||||
}
|
||||
const storageVal = config.isEncrypt
|
||||
? JSON.parse(decrypt(window[config.type].getItem(key) as string))
|
||||
: JSON.parse(window[config.type].getItem(key) as string);
|
||||
const now = Date.now();
|
||||
if (now >= storageVal.expire) {
|
||||
//过期销毁
|
||||
removeStorageFromKey(key);
|
||||
return null;
|
||||
//不过期回值
|
||||
} else {
|
||||
return storageVal.value;
|
||||
}
|
||||
};
|
||||
const getAllStorage = () => {
|
||||
//获取所有值
|
||||
const storageList: any = {}
|
||||
const keys = Object.keys(window[config.type])
|
||||
keys.forEach((key) => {
|
||||
const value = getStorageFromKey(autoRemovePreFix(key))
|
||||
if (value !== null) {
|
||||
//如果值没有过期,加入到列表中
|
||||
storageList[autoRemovePreFix(key)] = value
|
||||
}
|
||||
})
|
||||
return storageList
|
||||
}
|
||||
//获取所有值
|
||||
const storageList: any = {};
|
||||
const keys = Object.keys(window[config.type]);
|
||||
keys.forEach((key) => {
|
||||
const value = getStorageFromKey(autoRemovePreFix(key));
|
||||
if (value !== null) {
|
||||
//如果值没有过期,加入到列表中
|
||||
storageList[autoRemovePreFix(key)] = value;
|
||||
}
|
||||
});
|
||||
return storageList;
|
||||
};
|
||||
const getStorageLength = () => {
|
||||
//获取值列表长度
|
||||
return window[config.type].length
|
||||
}
|
||||
//获取值列表长度
|
||||
return window[config.type].length;
|
||||
};
|
||||
const removeStorageFromKey = (key: string) => {
|
||||
//删除值
|
||||
if (config.prefix) {
|
||||
key = autoAddPreFix(key)
|
||||
}
|
||||
window[config.type].removeItem(key)
|
||||
}
|
||||
//删除值
|
||||
if (config.prefix) {
|
||||
key = autoAddPreFix(key);
|
||||
}
|
||||
window[config.type].removeItem(key);
|
||||
};
|
||||
const clearStorage = () => {
|
||||
window[config.type].clear()
|
||||
}
|
||||
window[config.type].clear();
|
||||
};
|
||||
const autoAddPreFix = (key: string) => {
|
||||
//添加前缀,保持唯一性
|
||||
const prefix = config.prefix || ''
|
||||
return `${prefix}_${key}`
|
||||
}
|
||||
//添加前缀,保持唯一性
|
||||
const prefix = config.prefix || "";
|
||||
return `${prefix}_${key}`;
|
||||
};
|
||||
const autoRemovePreFix = (key: string) => {
|
||||
//删除前缀,进行增删改查
|
||||
const lineIndex = config.prefix.length + 1
|
||||
return key.substr(lineIndex)
|
||||
}
|
||||
//删除前缀,进行增删改查
|
||||
const lineIndex = config.prefix.length + 1;
|
||||
return key.substr(lineIndex);
|
||||
};
|
||||
|
||||
export {
|
||||
setStorage,
|
||||
getStorageFromKey,
|
||||
getAllStorage,
|
||||
getStorageLength,
|
||||
removeStorageFromKey,
|
||||
clearStorage,
|
||||
}
|
||||
setStorage,
|
||||
getStorageFromKey,
|
||||
getAllStorage,
|
||||
getStorageLength,
|
||||
removeStorageFromKey,
|
||||
clearStorage,
|
||||
};
|
||||
|
@@ -1,37 +1,39 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
/** @format */
|
||||
|
||||
const SECRET_KEY = CryptoJS.enc.Utf8.parse('3333e6e143439161') //十六位十六进制数作为密钥
|
||||
const SECRET_IV = CryptoJS.enc.Utf8.parse('e3bbe7e3ba84431a') //十六位十六进制数作为密钥偏移量
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
const SECRET_KEY = CryptoJS.enc.Utf8.parse("3333e6e143439161"); //十六位十六进制数作为密钥
|
||||
const SECRET_IV = CryptoJS.enc.Utf8.parse("e3bbe7e3ba84431a"); //十六位十六进制数作为密钥偏移量
|
||||
|
||||
const encrypt = (data: object | string): string => {
|
||||
//加密
|
||||
if (typeof data === 'object') {
|
||||
try {
|
||||
data = JSON.stringify(data)
|
||||
} catch (e) {
|
||||
throw new Error('encrypt error' + e)
|
||||
}
|
||||
}
|
||||
const dataHex = CryptoJS.enc.Utf8.parse(data)
|
||||
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
return encrypted.ciphertext.toString()
|
||||
}
|
||||
//加密
|
||||
if (typeof data === "object") {
|
||||
try {
|
||||
data = JSON.stringify(data);
|
||||
} catch (e) {
|
||||
throw new Error("encrypt error" + e);
|
||||
}
|
||||
}
|
||||
const dataHex = CryptoJS.enc.Utf8.parse(data);
|
||||
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
});
|
||||
return encrypted.ciphertext.toString();
|
||||
};
|
||||
|
||||
const decrypt = (data: string) => {
|
||||
//解密
|
||||
const encryptedHexStr = CryptoJS.enc.Hex.parse(data)
|
||||
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr)
|
||||
const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
|
||||
return decryptedStr.toString()
|
||||
}
|
||||
//解密
|
||||
const encryptedHexStr = CryptoJS.enc.Hex.parse(data);
|
||||
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);
|
||||
const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
});
|
||||
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
|
||||
return decryptedStr.toString();
|
||||
};
|
||||
|
||||
export { encrypt, decrypt }
|
||||
export { encrypt, decrypt };
|
||||
|
@@ -1,8 +1,10 @@
|
||||
/** @format */
|
||||
|
||||
interface globalConfig {
|
||||
type: 'localStorage' | 'sessionStorage'
|
||||
prefix: string
|
||||
expire: number
|
||||
isEncrypt: boolean
|
||||
type: "localStorage" | "sessionStorage";
|
||||
prefix: string;
|
||||
expire: number;
|
||||
isEncrypt: boolean;
|
||||
}
|
||||
|
||||
export type { globalConfig }
|
||||
export type { globalConfig };
|
||||
|
@@ -1,74 +1,76 @@
|
||||
import localforage from 'localforage'
|
||||
import CryptoJS from 'crypto-js'
|
||||
/** @format */
|
||||
|
||||
const SECRET_KEY = CryptoJS.enc.Utf8.parse('3333e6e143439161') //十六位十六进制数作为密钥
|
||||
const SECRET_IV = CryptoJS.enc.Utf8.parse('e3bbe7e3ba84431a') //十六位十六进制数作为密钥偏移量
|
||||
import localforage from "localforage";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
const SECRET_KEY = CryptoJS.enc.Utf8.parse("3333e6e143439161"); //十六位十六进制数作为密钥
|
||||
const SECRET_IV = CryptoJS.enc.Utf8.parse("e3bbe7e3ba84431a"); //十六位十六进制数作为密钥偏移量
|
||||
/**
|
||||
* 加密
|
||||
* @param data
|
||||
* @param output
|
||||
*/
|
||||
export const encrypt = (data: string, output?: any) => {
|
||||
const dataHex = CryptoJS.enc.Utf8.parse(data)
|
||||
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
return encrypted.ciphertext.toString(output)
|
||||
}
|
||||
const dataHex = CryptoJS.enc.Utf8.parse(data);
|
||||
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
});
|
||||
return encrypted.ciphertext.toString(output);
|
||||
};
|
||||
|
||||
/**
|
||||
* 解密
|
||||
* @param data
|
||||
*/
|
||||
export const decrypt = (data: string | null) => {
|
||||
if (data === null) {
|
||||
return
|
||||
}
|
||||
const encryptedHex = CryptoJS.enc.Hex.parse(data)
|
||||
const encryptedHexStr = CryptoJS.enc.Base64.stringify(encryptedHex)
|
||||
const decrypted = CryptoJS.AES.decrypt(encryptedHexStr, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8)
|
||||
return decryptedStr.toString()
|
||||
}
|
||||
if (data === null) {
|
||||
return;
|
||||
}
|
||||
const encryptedHex = CryptoJS.enc.Hex.parse(data);
|
||||
const encryptedHexStr = CryptoJS.enc.Base64.stringify(encryptedHex);
|
||||
const decrypted = CryptoJS.AES.decrypt(encryptedHexStr, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
});
|
||||
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
|
||||
return decryptedStr.toString();
|
||||
};
|
||||
|
||||
export const handleLocalforage = {
|
||||
config: async (options?: LocalForageOptions) => localforage.config(options || {}),
|
||||
setItem: async (key: string, value: string): Promise<void> => {
|
||||
await localforage.setItem(key, encrypt(value))
|
||||
},
|
||||
getItem: async function getItem<T>(key: string): Promise<T | string | null> {
|
||||
try {
|
||||
const value: any = decrypt(await localforage.getItem(key)) as any
|
||||
// 如果值是 undefined,返回 null
|
||||
if (value === undefined) {
|
||||
return null
|
||||
}
|
||||
// 如果值是 T 类型,直接返回
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
return value as T
|
||||
}
|
||||
// 如果值是 string 类型,直接返回
|
||||
return value as string
|
||||
} catch (error) {
|
||||
console.error('Error retrieving data from localforage:', error)
|
||||
return null
|
||||
}
|
||||
},
|
||||
removeItem: async (key: string): Promise<void> => {
|
||||
await localforage.removeItem(key)
|
||||
},
|
||||
clear: async () => {
|
||||
return await localforage.clear()
|
||||
},
|
||||
createInstance: async (name: string) => {
|
||||
return localforage.createInstance({
|
||||
name,
|
||||
})
|
||||
},
|
||||
}
|
||||
config: async (options?: LocalForageOptions) => localforage.config(options || {}),
|
||||
setItem: async (key: string, value: string): Promise<void> => {
|
||||
await localforage.setItem(key, encrypt(value));
|
||||
},
|
||||
getItem: async function getItem<T>(key: string): Promise<T | string | null> {
|
||||
try {
|
||||
const value: any = decrypt(await localforage.getItem(key)) as any;
|
||||
// 如果值是 undefined,返回 null
|
||||
if (value === undefined) {
|
||||
return null;
|
||||
}
|
||||
// 如果值是 T 类型,直接返回
|
||||
if (typeof value === "object" && value !== null) {
|
||||
return value as T;
|
||||
}
|
||||
// 如果值是 string 类型,直接返回
|
||||
return value as string;
|
||||
} catch (error) {
|
||||
console.error("Error retrieving data from localforage:", error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
removeItem: async (key: string): Promise<void> => {
|
||||
await localforage.removeItem(key);
|
||||
},
|
||||
clear: async () => {
|
||||
return await localforage.clear();
|
||||
},
|
||||
createInstance: async (name: string) => {
|
||||
return localforage.createInstance({
|
||||
name,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import { MobXProviderContext } from 'mobx-react'
|
||||
import { useContext } from 'react'
|
||||
import { RootStore } from '@/store'
|
||||
/** @format */
|
||||
|
||||
import { MobXProviderContext } from "mobx-react";
|
||||
import { useContext } from "react";
|
||||
import { RootStore } from "@/store";
|
||||
|
||||
// 根据RootStore来实现参数的自动获取和返回值的自动推导
|
||||
function useStore<T extends typeof RootStore, V extends keyof T>(name: V): T[V] {
|
||||
const store = useContext(MobXProviderContext) as T
|
||||
return store[name]
|
||||
const store = useContext(MobXProviderContext) as T;
|
||||
return store[name];
|
||||
}
|
||||
|
||||
export default useStore
|
||||
export default useStore;
|
||||
|
Reference in New Issue
Block a user