11 changed files with 716 additions and 5 deletions
@ -0,0 +1,5 @@ |
|||||
|
//统一配置 |
||||
|
VITE_APP_PORT = 9998 |
||||
|
VITE_APP_TITLE = '数通智联化工云平台' |
||||
|
VITE_APP_SYSTEM_KEY = 'hengxingaokeApp1' |
||||
|
VITE_APP_CSS_URL = '/public/' |
||||
@ -0,0 +1,102 @@ |
|||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-09 10:57:37 |
||||
|
@ 功能: 封装axios请求 |
||||
|
*/ |
||||
|
import axios, { AxiosError, type InternalAxiosRequestConfig } from 'axios' |
||||
|
import { ElMessage, ElMessageBox } from 'element-plus' |
||||
|
import { generateRandomString } from '@/utils/encryptionAndDecryption/randNumber' |
||||
|
import { sm4DecryptMethod, sm4EncryptMethod } from '@/utils/encryptionAndDecryption/sm4Utils' |
||||
|
import { useUserStore } from '@/stores/user' |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-09 10:58:34 |
||||
|
@ 功能: 创建axios实例 |
||||
|
*/ |
||||
|
const service = axios.create({ |
||||
|
baseURL: import.meta.env.VITE_APP_BASE_API, |
||||
|
timeout: 5000 |
||||
|
}) |
||||
|
|
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-09 11:00:05 |
||||
|
@ 功能: 请求拦截 |
||||
|
*/ |
||||
|
service.interceptors.request.use( |
||||
|
(config: InternalAxiosRequestConfig) => { |
||||
|
const userStore = useUserStore() |
||||
|
// if (config.headers['content-type'] === 'application/json') {
|
||||
|
let { data, headers } = config |
||||
|
console.log('请求拦截----data---1--->', data) |
||||
|
if (userStore.authToken) { |
||||
|
config.headers['Auth-token'] = userStore.authToken |
||||
|
} |
||||
|
//获取16位随机数
|
||||
|
let randomString = generateRandomString(16) |
||||
|
config.headers['Auth-key'] = randomString |
||||
|
if (data) { |
||||
|
// 加密请求数据
|
||||
|
config.data = { |
||||
|
encryptedFile: sm4EncryptMethod(JSON.stringify(data), randomString) |
||||
|
} |
||||
|
} |
||||
|
console.log('请求拦截---------->', randomString) |
||||
|
console.log('请求拦截----headers------>', headers) |
||||
|
console.log('请求拦截----data------>', config.data) |
||||
|
console.log('请求拦截----config------>', config) |
||||
|
// }
|
||||
|
|
||||
|
// console.log('请求拦截----content-type------>', config.headers['Content-Type'])
|
||||
|
// console.log('请求拦截----config------>', config.headers)
|
||||
|
return config |
||||
|
}, |
||||
|
(error: AxiosError) => { |
||||
|
return Promise.reject(error) |
||||
|
} |
||||
|
) |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-09 21:00:20 |
||||
|
@ 备注: 响应拦截 |
||||
|
*/ |
||||
|
service.interceptors.response.use( |
||||
|
response => { |
||||
|
console.log('行营结果---------->', response) |
||||
|
let { data, headers } = response |
||||
|
// console.log('行营结果----data------>', data.data)
|
||||
|
let authKey = headers['auth-key'] |
||||
|
console.log('行营结果----authKey------>', authKey) |
||||
|
// 解密响应数据
|
||||
|
if (authKey) { |
||||
|
let jsonData = sm4DecryptMethod(data.data, authKey) |
||||
|
response.data.data = JSON.parse(jsonData) |
||||
|
} |
||||
|
console.log('行营结果----解密结构------>', headers['auth-key'], response) |
||||
|
return response.data |
||||
|
}, |
||||
|
(error: AxiosError) => { |
||||
|
if (error.response) { |
||||
|
const status = error.response.status |
||||
|
switch (status) { |
||||
|
case 401: |
||||
|
// 处理401错误,例如跳转到登录页
|
||||
|
break |
||||
|
case 403: |
||||
|
// 处理403错误,例如提示无权限
|
||||
|
break |
||||
|
case 404: |
||||
|
// 处理404错误,例如提示资源不存在
|
||||
|
break |
||||
|
case 500: |
||||
|
// 处理500错误,例如提示服务器错误
|
||||
|
break |
||||
|
default: |
||||
|
// 处理其他错误
|
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
return Promise.reject(error) |
||||
|
} |
||||
|
) |
||||
|
export default service |
||||
@ -0,0 +1,63 @@ |
|||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-07 11:07:32 |
||||
|
@ 备注: 创建任意位数的随机字符串 |
||||
|
*/ |
||||
|
const generateRandomString = (length: number = 16): string => { |
||||
|
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' |
||||
|
const array = new Uint8Array(length) |
||||
|
crypto.getRandomValues(array) |
||||
|
return Array.from(array, byte => characters[byte % characters.length]).join('') |
||||
|
// let randomString = '';
|
||||
|
// for (let i = 0; i < length; i++) {
|
||||
|
// const randomIndex = Math.floor(Math.random() * characters.length);
|
||||
|
// randomString += characters.charAt(randomIndex);
|
||||
|
// }
|
||||
|
// return randomString;
|
||||
|
} |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-08 16:15:12 |
||||
|
@ 功能: 获取UUID |
||||
|
*/ |
||||
|
const uuid = () => { |
||||
|
const s: string[] = [] |
||||
|
const hexDigits = '123456789abcdef' |
||||
|
for (let i = 0; i < 36; i++) { |
||||
|
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1) |
||||
|
} |
||||
|
s[14] = '4' // bits 12-15 of the time_hi_and_version field to 0010
|
||||
|
s[19] = hexDigits.substr((parseInt(s[19]!, 16) & 0x3) | 0x8, 1) // bits 6-7 of the clock_seq_hi_and_reserved to 01
|
||||
|
s[8] = s[13] = s[18] = s[23] = '-' |
||||
|
const uuid = s.join('') |
||||
|
return uuid |
||||
|
} |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-08 16:15:48 |
||||
|
@ 功能: 获取简单随机数 |
||||
|
*/ |
||||
|
const randomString = (length: number) => { |
||||
|
var str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' |
||||
|
var result = '' |
||||
|
for (var i = length; i > 0; --i) { |
||||
|
result += str[Math.floor(Math.random() * str.length)] |
||||
|
} |
||||
|
return result |
||||
|
} |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-08 16:16:12 |
||||
|
@ 功能: 中间画线驼峰 |
||||
|
*/ |
||||
|
const toHump = (str: string) => { |
||||
|
if (!str) return str |
||||
|
return str |
||||
|
.replace(/\-(\w)/g, function (all: string, letter: string) { |
||||
|
return letter.toUpperCase() |
||||
|
}) |
||||
|
.replace(/(\s|^)[a-z]/g, function (char: string) { |
||||
|
return char.toUpperCase() |
||||
|
}) |
||||
|
} |
||||
|
export { generateRandomString, uuid, randomString, toHump } |
||||
@ -0,0 +1,7 @@ |
|||||
|
import * as CryptoJS from 'crypto-js' |
||||
|
|
||||
|
const strToHexSub = (str: string): string => { |
||||
|
return CryptoJS.enc.Utf8.parse(str).toString(CryptoJS.enc.Hex) |
||||
|
} |
||||
|
|
||||
|
export { strToHexSub } |
||||
@ -0,0 +1,74 @@ |
|||||
|
import { SM4 as sm4 } from 'gm-crypto' |
||||
|
import * as CryptoJS from 'crypto-js' |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-07 10:26:51 |
||||
|
@ 备注: 将字符串转换成16进制 |
||||
|
*/ |
||||
|
const strToHexMethod = (str: string): string => { |
||||
|
return CryptoJS.enc.Utf8.parse(str).toString(CryptoJS.enc.Hex) |
||||
|
} |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-07 10:29:48 |
||||
|
@ 备注: 判断是不是12位16进制参数 |
||||
|
*/ |
||||
|
const isValidHex32 = (str: string): boolean => { |
||||
|
return /^[0-9a-fA-F]{32}$/.test(str) |
||||
|
} |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-07 10:28:33 |
||||
|
@ 备注: 初始化SM4密钥参数 |
||||
|
*/ |
||||
|
const appSystemKey = strToHexMethod(import.meta.env.VITE_APP_SYSTEM_KEY) |
||||
|
const sm4TokenKey = strToHexMethod(import.meta.env.VITE_APP_SM4_APP_KEY) |
||||
|
|
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-07 10:30:40 |
||||
|
@ 备注: SM4加密方法 |
||||
|
*/ |
||||
|
const sm4EncryptMethod = (data: string, customKey: string): string => { |
||||
|
let ivSetup = sm4TokenKey |
||||
|
if (customKey) { |
||||
|
ivSetup = strToHexMethod(customKey) |
||||
|
if (!isValidHex32(ivSetup)) { |
||||
|
ivSetup = sm4TokenKey |
||||
|
} |
||||
|
} |
||||
|
return sm4.encrypt(data, appSystemKey, { |
||||
|
iv: ivSetup, |
||||
|
mode: sm4.constants.CBC, |
||||
|
inputEncoding: 'utf8', |
||||
|
outputEncoding: 'hex', |
||||
|
padding: 1 |
||||
|
} as never) |
||||
|
} |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-07 10:31:22 |
||||
|
@ 备注: SM4解密方法 |
||||
|
*/ |
||||
|
const sm4DecryptMethod = (data: string, customKey: string): string => { |
||||
|
let ivSetup = sm4TokenKey |
||||
|
if (customKey) { |
||||
|
ivSetup = strToHexMethod(customKey) |
||||
|
if (!isValidHex32(ivSetup)) { |
||||
|
ivSetup = sm4TokenKey |
||||
|
} |
||||
|
} |
||||
|
// console.log('SM4解密方法----解密结构---data--->', data)
|
||||
|
console.log('SM4解密方法----解密结构----customKey-->', customKey) |
||||
|
console.log('SM4解密方法----解密结构--ivSetup---->', ivSetup) |
||||
|
console.log('SM4解密方法----解密结构---sm4TokenKey--->', sm4TokenKey) |
||||
|
console.log('SM4解密方法----解密结构---appSystemKey--->', appSystemKey) |
||||
|
return sm4.decrypt(data, appSystemKey, { |
||||
|
iv: ivSetup, |
||||
|
mode: sm4.constants.CBC, |
||||
|
inputEncoding: 'hex', |
||||
|
outputEncoding: 'utf8', |
||||
|
padding: 1 |
||||
|
} as never) |
||||
|
} |
||||
|
export { sm4EncryptMethod, sm4DecryptMethod } |
||||
@ -0,0 +1,347 @@ |
|||||
|
/** |
||||
|
* 数字 |
||||
|
*/ |
||||
|
const REG_NUMBER: string = '.*\\d+.*' |
||||
|
/** |
||||
|
* 小写字母 |
||||
|
*/ |
||||
|
const REG_UPPERCASE: string = '.*[A-Z]+.*' |
||||
|
/** |
||||
|
* 大写字母 |
||||
|
*/ |
||||
|
const REG_LOWERCASE: string = '.*[a-z]+.*' |
||||
|
/** |
||||
|
* 特殊符号(~!@#$%^&*()_+|<>,.?/:;'[]{}\) |
||||
|
*/ |
||||
|
const REG_SYMBOL: string = '.*[~!@#$%^&*()_+|<>,.?/:;\'\\[\\]{}]+".*' |
||||
|
/** |
||||
|
* 键盘字符表(小写) |
||||
|
* 非shift键盘字符表 |
||||
|
*/ |
||||
|
const CHAR_TABLE1: string[][] = [ |
||||
|
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\0'], |
||||
|
['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\'], |
||||
|
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '\0', '\0'], |
||||
|
['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0'] |
||||
|
] |
||||
|
/** |
||||
|
* shift键盘的字符表 |
||||
|
*/ |
||||
|
const CHAR_TABLE2: string[][] = [ |
||||
|
['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\0'], |
||||
|
['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '|'], |
||||
|
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '"', '\0', '\0'], |
||||
|
['z', 'x', 'c', 'v', 'b', 'n', 'm', '<', '>', '?', '\0', '\0', '\0'] |
||||
|
] |
||||
|
|
||||
|
/** |
||||
|
* 校验密码是否符合条件 |
||||
|
* @param password 密码 |
||||
|
* @param username 用户名 |
||||
|
*/ |
||||
|
export const checkPasswordRule = (password: string, username: string) => { |
||||
|
if (password === '' || password.length < 8 || password.length > 32) { |
||||
|
// console.log("长度小于8,或大于32");
|
||||
|
return '密码长度应大于8小于32' |
||||
|
} |
||||
|
if (password.indexOf(username) !== -1) { |
||||
|
// console.log("包含用户名");
|
||||
|
return '请勿包含用户名' |
||||
|
} |
||||
|
if (isContinuousChar(password)) { |
||||
|
// console.log("包含3个及以上相同或字典连续字符");
|
||||
|
return '请勿包含3个及以上相同或连续的字符' |
||||
|
} |
||||
|
if (isKeyBoardContinuousChar(password)) { |
||||
|
// console.log("包含3个及以上键盘连续字符");
|
||||
|
return '请勿包含3个及以上键盘连续字符' |
||||
|
} |
||||
|
let i: number = 0 |
||||
|
if (password.match(REG_NUMBER)) i++ |
||||
|
if (password.match(REG_LOWERCASE)) i++ |
||||
|
if (password.match(REG_UPPERCASE)) i++ |
||||
|
if (password.match(REG_SYMBOL)) i++ |
||||
|
if (i < 2) { |
||||
|
// console.log(("数字、小写字母、大写字母、特殊字符,至少包含两种"));
|
||||
|
return '数字、小写字母、大写字母、特殊字符,至少包含两种' |
||||
|
} |
||||
|
// console.log(i);
|
||||
|
return '校验通过' |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 是否包含3个及以上相同或字典连续字符 |
||||
|
*/ |
||||
|
const isContinuousChar = (password: string) => { |
||||
|
const chars: string[] = password.split('') |
||||
|
|
||||
|
// 遍历所有可能的三个连续字符组合
|
||||
|
for (let i = 0; i < chars.length - 2; i++) { |
||||
|
// 添加类型断言,确保字符不是undefined
|
||||
|
const char1 = chars[i] as string |
||||
|
const char2 = chars[i + 1] as string |
||||
|
const char3 = chars[i + 2] as string |
||||
|
|
||||
|
// 获取字符的ASCII码
|
||||
|
const n1 = char1.charCodeAt(0) |
||||
|
const n2 = char2.charCodeAt(0) |
||||
|
const n3 = char3.charCodeAt(0) |
||||
|
|
||||
|
// 判断重复字符
|
||||
|
if (n1 === n2 && n1 === n3) { |
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
// 判断连续字符: 正序(如abc)和倒序(如cba)
|
||||
|
if ((n1 + 1 === n2 && n2 + 1 === n3) || (n1 - 1 === n2 && n2 - 1 === n3)) { |
||||
|
return true |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return false |
||||
|
} |
||||
|
/** |
||||
|
* 是否包含3个及以上键盘连续字符 |
||||
|
* @param password 待匹配的字符串 |
||||
|
*/ |
||||
|
const isKeyBoardContinuousChar = (password: string) => { |
||||
|
if (password === '') { |
||||
|
return false |
||||
|
} |
||||
|
//考虑大小写,都转换成小写字母
|
||||
|
const lpStrChars: string[] = password.toLowerCase().split('') |
||||
|
// 获取字符串长度
|
||||
|
const nStrLen: number = lpStrChars.length |
||||
|
// 定义位置数组:row - 行,col - column 列,初始化为-1
|
||||
|
const pRowCharPos: number[] = new Array(nStrLen).fill(-1) |
||||
|
const pColCharPos: number[] = new Array(nStrLen).fill(-1) |
||||
|
|
||||
|
for (let i = 0; i < nStrLen; i++) { |
||||
|
// 添加类型断言,确保字符不是undefined
|
||||
|
const chLower: string = lpStrChars[i] as string |
||||
|
|
||||
|
// 检索在表1中的位置,构建位置数组
|
||||
|
for (let nRowTable1Idx = 0; nRowTable1Idx < 4; nRowTable1Idx++) { |
||||
|
for (let nColTable1Idx = 0; nColTable1Idx < 13; nColTable1Idx++) { |
||||
|
// 获取当前字符,跳过\0字符,使用可选链和空值合并确保类型安全
|
||||
|
const tableChar = CHAR_TABLE1[nRowTable1Idx]?.[nColTable1Idx] ?? '' |
||||
|
if (tableChar && tableChar !== '\0' && chLower === tableChar) { |
||||
|
pRowCharPos[i] = nRowTable1Idx |
||||
|
pColCharPos[i] = nColTable1Idx |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 在表1中没找到,到表二中去找,找到则continue
|
||||
|
// 添加非空检查
|
||||
|
const currentColPos = pColCharPos[i] |
||||
|
if (currentColPos !== undefined && currentColPos >= 0) { |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
// 检索在表2中的位置,构建位置数组
|
||||
|
for (let nRowTable2Idx = 0; nRowTable2Idx < 4; nRowTable2Idx++) { |
||||
|
for (let nColTable2Idx = 0; nColTable2Idx < 13; nColTable2Idx++) { |
||||
|
// 获取当前字符,跳过\0字符,使用可选链和空值合并确保类型安全
|
||||
|
const tableChar = CHAR_TABLE2[nRowTable2Idx]?.[nColTable2Idx] ?? '' |
||||
|
if (tableChar && tableChar !== '\0' && chLower === tableChar) { |
||||
|
pRowCharPos[i] = nRowTable2Idx |
||||
|
pColCharPos[i] = nColTable2Idx |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 匹配坐标连线
|
||||
|
for (let j = 1; j <= nStrLen - 2; j++) { |
||||
|
// 获取当前三个字符的位置,添加类型断言
|
||||
|
const row1 = pRowCharPos[j - 1] as number |
||||
|
const row2 = pRowCharPos[j] as number |
||||
|
const row3 = pRowCharPos[j + 1] as number |
||||
|
const col1 = pColCharPos[j - 1] as number |
||||
|
const col2 = pColCharPos[j] as number |
||||
|
const col3 = pColCharPos[j + 1] as number |
||||
|
|
||||
|
//同一行
|
||||
|
if (row1 === row2 && row2 === row3) { |
||||
|
// 键盘行正向连续(asd)或者键盘行反向连续(dsa)
|
||||
|
if ( |
||||
|
(col1 + 1 === col2 && col2 + 1 === col3) || |
||||
|
(col3 + 1 === col2 && col2 + 1 === col1) |
||||
|
) { |
||||
|
return true |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//同一列
|
||||
|
if (col1 === col2 && col2 === col3) { |
||||
|
//键盘列连续(qaz)或者键盘列反向连续(zaq)
|
||||
|
if ( |
||||
|
(row1 + 1 === row2 && row2 + 1 === row3) || |
||||
|
(row1 - 1 === row2 && row2 - 1 === row3) |
||||
|
) { |
||||
|
return true |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 密码强度校验 |
||||
|
*/ |
||||
|
/** |
||||
|
* 长度 |
||||
|
* @param str |
||||
|
*/ |
||||
|
const length = (str: string) => { |
||||
|
if (str.length < 5) { |
||||
|
return 5 |
||||
|
} else if (str.length < 8) { |
||||
|
return 10 |
||||
|
} else { |
||||
|
return 25 |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* 字母 |
||||
|
* @param str |
||||
|
*/ |
||||
|
const letters = (str: string) => { |
||||
|
let count1 = 0, |
||||
|
count2 = 0 |
||||
|
for (let i = 0; i < str.length; i++) { |
||||
|
if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') { |
||||
|
count1++ |
||||
|
} |
||||
|
if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') { |
||||
|
count2++ |
||||
|
} |
||||
|
} |
||||
|
if (count1 === 0 && count2 === 0) { |
||||
|
return 0 |
||||
|
} |
||||
|
if (count1 !== 0 && count2 !== 0) { |
||||
|
return 20 |
||||
|
} |
||||
|
return 10 |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 数字 |
||||
|
* @param str |
||||
|
*/ |
||||
|
const numbers = (str: string) => { |
||||
|
let count = 0 |
||||
|
for (let i = 0; i < str.length; i++) { |
||||
|
if (str.charAt(i) >= '0' && str.charAt(i) <= '9') { |
||||
|
count++ |
||||
|
} |
||||
|
} |
||||
|
if (count === 0) { |
||||
|
return 0 |
||||
|
} |
||||
|
if (count === 1) { |
||||
|
return 10 |
||||
|
} |
||||
|
return 20 |
||||
|
} |
||||
|
/** |
||||
|
* 符号 |
||||
|
* @param str |
||||
|
*/ |
||||
|
const symbols = (str: string) => { |
||||
|
let count = 0 |
||||
|
for (let i = 0; i < str.length; i++) { |
||||
|
if ( |
||||
|
(str.charCodeAt(i) >= 0x21 && str.charCodeAt(i) <= 0x2f) || |
||||
|
(str.charCodeAt(i) >= 0x3a && str.charCodeAt(i) <= 0x40) || |
||||
|
(str.charCodeAt(i) >= 0x5b && str.charCodeAt(i) <= 0x60) || |
||||
|
(str.charCodeAt(i) >= 0x7b && str.charCodeAt(i) <= 0x7e) |
||||
|
) { |
||||
|
count++ |
||||
|
} |
||||
|
} |
||||
|
if (count === 0) { |
||||
|
return 0 |
||||
|
} |
||||
|
if (count === 1) { |
||||
|
return 10 |
||||
|
} |
||||
|
return 25 |
||||
|
} |
||||
|
/** |
||||
|
* 得分机制 |
||||
|
* @param str |
||||
|
*/ |
||||
|
const rewards = (str: string) => { |
||||
|
let letter = letters(str) //字母
|
||||
|
let number = numbers(str) //数字
|
||||
|
let symbol = symbols(str) //符号
|
||||
|
if (letter > 0 && number > 0 && symbol === 0) { |
||||
|
//字母和数字
|
||||
|
return 2 |
||||
|
} |
||||
|
if (letter === 10 && number > 0 && symbol > 0) { |
||||
|
//字母、数字和符号
|
||||
|
return 3 |
||||
|
} |
||||
|
if (letter === 20 && number > 0 && symbol > 0) { |
||||
|
//大小写字母、数字和符号
|
||||
|
return 5 |
||||
|
} |
||||
|
return 0 |
||||
|
} |
||||
|
/** |
||||
|
* 最终评分 |
||||
|
* @param str |
||||
|
*/ |
||||
|
export const level = (str: string) => { |
||||
|
let lengths = length(str) //长度
|
||||
|
let letter = letters(str) //字母
|
||||
|
let number = numbers(str) //数字
|
||||
|
let symbol = symbols(str) //符号
|
||||
|
let reward = rewards(str) //奖励
|
||||
|
let sum = lengths + letter + number + symbol + reward |
||||
|
console.log(sum) |
||||
|
if (sum >= 80) { |
||||
|
return '非常强' //非常安全
|
||||
|
} else if (sum >= 60) { |
||||
|
return '强' //非常强
|
||||
|
} else if (sum >= 40) { |
||||
|
return '一般' //一般
|
||||
|
} else if (sum >= 25) { |
||||
|
return '弱' //弱
|
||||
|
} else { |
||||
|
return '非常弱' //非常弱
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export const checkPwdRule = (password: string) => { |
||||
|
if (password === '' || password.length < 8 || password.length > 32) { |
||||
|
// console.log("长度小于8,或大于32");
|
||||
|
return '密码长度应大于8小于32' |
||||
|
} |
||||
|
if (isContinuousChar(password)) { |
||||
|
// console.log("包含3个及以上相同或字典连续字符");
|
||||
|
return '请勿包含3个及以上相同或连续的字符' |
||||
|
} |
||||
|
if (isKeyBoardContinuousChar(password)) { |
||||
|
// console.log("包含3个及以上键盘连续字符");
|
||||
|
return '请勿包含3个及以上键盘连续字符' |
||||
|
} |
||||
|
let i: number = 0 |
||||
|
if (password.match(REG_NUMBER)) i++ |
||||
|
if (password.match(REG_LOWERCASE)) i++ |
||||
|
if (password.match(REG_UPPERCASE)) i++ |
||||
|
if (password.match(REG_SYMBOL)) i++ |
||||
|
if (i < 2) { |
||||
|
// console.log(("数字、小写字母、大写字母、特殊字符,至少包含两种"));
|
||||
|
return '数字、小写字母、大写字母、特殊字符,至少包含两种' |
||||
|
} |
||||
|
// console.log(i);
|
||||
|
return '校验通过' |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2026-01-09 15:57:48 |
||||
|
@ 功能: 加载svg文件 |
||||
|
*/ |
||||
|
export const loadSvgFiles = (): string[] => { |
||||
|
const icons = import.meta.glob('../assets/icons/*.svg') |
||||
|
const svgIcons: string[] = [] |
||||
|
for (const icon in icons) { |
||||
|
const iconName = icon.split('assets/icons/')[1].split('.svg')[0] |
||||
|
svgIcons.push(iconName) |
||||
|
} |
||||
|
return svgIcons |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-29 16:00:55 |
||||
|
@ 功能: 路径匹配器 |
||||
|
* @param {string} pattern |
||||
|
* @param {string} path |
||||
|
* @returns {Boolean} |
||||
|
*/ |
||||
|
export const isPathMatch = (pattern: string, path: string): boolean => { |
||||
|
const regexPattern = pattern |
||||
|
.replace(/\//g, '\\/') |
||||
|
.replace(/\*\*/g, '.*') |
||||
|
.replace(/\*/g, '[^\\/]*') |
||||
|
const regex = new RegExp(`^${regexPattern}$`) |
||||
|
return regex.test(path) |
||||
|
} |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-29 16:02:21 |
||||
|
@ 功能: 判断字符串是否为空 |
||||
|
*/ |
||||
|
export const isEmptyString = (str: string): boolean => { |
||||
|
return str.trim().length === 0 |
||||
|
} |
||||
|
/** |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2025-12-29 16:03:14 |
||||
|
@ 功能: 判断url是否是http或https |
||||
|
*/ |
||||
|
export const isHttpOrHttpsUrl = (url: string): boolean => { |
||||
|
return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1 |
||||
|
} |
||||
Loading…
Reference in new issue