人脸识别与大模型问答
This commit is contained in:
parent
ef3f33d33b
commit
c92315c26c
|
|
@ -8,10 +8,14 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import largeScreenHeader from "@/components/LargeScreen/index.vue";
|
import largeScreenHeader from "@/components/LargeScreen/index.vue";
|
||||||
|
import {get} from "@/utils/config";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: {largeScreenHeader},
|
components: {largeScreenHeader},
|
||||||
|
created() {
|
||||||
|
get();
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// 判断是否需要隐藏 header
|
// 判断是否需要隐藏 header
|
||||||
shouldHideHeader() {
|
shouldHideHeader() {
|
||||||
|
|
@ -29,3 +33,8 @@ export default {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
#app .theme-picker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 获取系统配置
|
||||||
|
export const getConfig = () => {
|
||||||
|
return request({
|
||||||
|
url: '/auth/getConfig',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -232,3 +232,17 @@ aside {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-menu {
|
||||||
|
background-color: #081036;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu--horizontal .el-menu .el-menu-item, .el-menu--horizontal .el-menu .el-submenu__title {
|
||||||
|
background-color: #081036;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu--horizontal > .el-submenu .el-submenu__title:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import * as CryptoJS from 'crypto-js'
|
import * as CryptoJS from 'crypto-js'
|
||||||
const cbc_key = CryptoJS.enc.Utf8.parse('zhgd@bonus@zhgd@bonus@1234567890')
|
import { AES_CONFIG } from './configure'
|
||||||
const cbc_iv = CryptoJS.enc.Utf8.parse('1234567812345678')
|
const cbc_key = CryptoJS.enc.Utf8.parse(AES_CONFIG.AES_KEY)
|
||||||
|
const cbc_iv = CryptoJS.enc.Utf8.parse(AES_CONFIG.AES_IV)
|
||||||
/**
|
/**
|
||||||
* 加解密开关
|
* 加解密开关
|
||||||
* 默认参数需要加密
|
* 默认参数需要加密
|
||||||
|
|
@ -18,9 +19,6 @@ const encryptEnabled= false;
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export const encryptCBC = function(word) {
|
export const encryptCBC = function(word) {
|
||||||
if(!encryptEnabled){
|
|
||||||
return word;
|
|
||||||
}
|
|
||||||
const srcs = CryptoJS.enc.Utf8.parse(word)
|
const srcs = CryptoJS.enc.Utf8.parse(word)
|
||||||
const encrypted = CryptoJS.AES.encrypt(srcs, cbc_key, {
|
const encrypted = CryptoJS.AES.encrypt(srcs, cbc_key, {
|
||||||
iv: cbc_iv,
|
iv: cbc_iv,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { getConfig } from '@/api/config';
|
||||||
|
export function get() {
|
||||||
|
getConfig()
|
||||||
|
.then(response => {
|
||||||
|
localStorage.setItem('systemConfig', JSON.stringify(response.data));
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Failed to fetch config:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,3 @@
|
||||||
// 密码强度级别常量
|
|
||||||
const STRENGTH_LEVELS = {
|
|
||||||
WEAK: 'weak', // 弱:一类字符
|
|
||||||
MEDIUM: 'medium', // 中:两类字符
|
|
||||||
STRONG: 'strong', // 强:三类字符
|
|
||||||
VERY_STRONG: 'very-strong' // 非常强:四类字符
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数据设置常量
|
|
||||||
const DATA_SETTINGS = {
|
|
||||||
OPEN: true, // 开启
|
|
||||||
CLOSE: false // 关闭
|
|
||||||
}
|
|
||||||
|
|
||||||
// SM 配置
|
// SM 配置
|
||||||
const SM_CONFIG = {
|
const SM_CONFIG = {
|
||||||
SALT: '2cc0c5f9f1749f1632efa9f63e902323', // SM3 盐值(16 字节)
|
SALT: '2cc0c5f9f1749f1632efa9f63e902323', // SM3 盐值(16 字节)
|
||||||
|
|
@ -19,67 +5,12 @@ const SM_CONFIG = {
|
||||||
SM2_PUBLIC_KEY: 'your-public-key', // SM2 公钥
|
SM2_PUBLIC_KEY: 'your-public-key', // SM2 公钥
|
||||||
SM2_PRIVATE_KEY: 'your-private-key' // SM2 私钥
|
SM2_PRIVATE_KEY: 'your-private-key' // SM2 私钥
|
||||||
}
|
}
|
||||||
|
|
||||||
// AES 配置
|
// AES 配置
|
||||||
const AES_CONFIG = {
|
const AES_CONFIG = {
|
||||||
AES_KEY: 'zhgd@bonus@zhgd@bonus@1234567890', // AES key值
|
AES_KEY: 'zhgd@bonus@zhgd@bonus@1234567890', // AES key值
|
||||||
AES_IV: '1234567812345678' // AES 偏移量
|
AES_IV: '1234567812345678' // AES 偏移量
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录配置
|
|
||||||
const LOGIN_CONFIG = {
|
|
||||||
CODE_PHONE_LOGIN: DATA_SETTINGS.OPEN, // 手机号验证码登录(true:开启,false:关闭)
|
|
||||||
CODE_EMAIL_LOGIN: DATA_SETTINGS.OPEN,// 邮箱验证码登录(true:开启,false:关闭)
|
|
||||||
PHONE_LOGIN: DATA_SETTINGS.OPEN, // 手机号密码登录(true:开启,false:关闭)
|
|
||||||
EMAIL_LOGIN: DATA_SETTINGS.OPEN // 邮箱密码登录(true:开启,false:关闭)
|
|
||||||
}
|
|
||||||
//注册配置
|
|
||||||
const REGISTER_CONFIG = {
|
|
||||||
PHONE_REGISTER: DATA_SETTINGS.OPEN, // 手机号注册(true:开启,false:关闭)
|
|
||||||
EMAIL_REGISTER: DATA_SETTINGS.OPEN // 邮箱注册(true:开启,false:关闭)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置设置
|
|
||||||
const CONFIG = {
|
|
||||||
STRENGTH: STRENGTH_LEVELS.STRONG,//密码强度配置
|
|
||||||
IS_OPEN_REGISTER: REGISTER_CONFIG.PHONE_REGISTER || REGISTER_CONFIG.EMAIL_REGISTER, // 是否开启注册
|
|
||||||
IS_CODE_LOGIN: LOGIN_CONFIG.CODE_EMAIL_LOGIN || LOGIN_CONFIG.CODE_PHONE_LOGIN, // 是否开启短信登录
|
|
||||||
// 数据设置
|
|
||||||
dataSettings: {
|
|
||||||
integrityCheck: DATA_SETTINGS.CLOSE, // 数据完整性校验(true:开启,false:关闭)
|
|
||||||
encryptRequest: DATA_SETTINGS.CLOSE, // 数据传输加密(true:开启,false:关闭)
|
|
||||||
encryptResponse: DATA_SETTINGS.CLOSE, // 数据返回解密(true:开启,false:关闭)
|
|
||||||
},
|
|
||||||
// 增加配置以支持增加根节点公司的添加和删除功能,added by weiweiwang,2024/9/12
|
|
||||||
IS_ADD_ROOT_COMPANY: DATA_SETTINGS.OPEN,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取占位符文本的函数
|
|
||||||
// 获取占位符文本的函数
|
|
||||||
function getPlaceholderText() {
|
|
||||||
const loginOptions = []
|
|
||||||
if (LOGIN_CONFIG.PHONE_LOGIN) loginOptions.push('手机号')
|
|
||||||
if (LOGIN_CONFIG.EMAIL_LOGIN) loginOptions.push('邮箱')
|
|
||||||
return `用户名${loginOptions.length ? '/' + loginOptions.join('/') : ''}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取占位符文本的函数
|
|
||||||
// 获取占位符文本的函数
|
|
||||||
function getCodePlaceholderText() {
|
|
||||||
const loginOptions = []
|
|
||||||
if (LOGIN_CONFIG.CODE_PHONE_LOGIN) loginOptions.push('手机号')
|
|
||||||
if (LOGIN_CONFIG.CODE_EMAIL_LOGIN) loginOptions.push('邮箱')
|
|
||||||
return loginOptions.length ? loginOptions.join('/') : ''
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
STRENGTH_LEVELS,
|
|
||||||
DATA_SETTINGS,
|
|
||||||
CONFIG,
|
|
||||||
SM_CONFIG,
|
SM_CONFIG,
|
||||||
AES_CONFIG,
|
AES_CONFIG,
|
||||||
LOGIN_CONFIG,
|
|
||||||
REGISTER_CONFIG,
|
|
||||||
getPlaceholderText,
|
|
||||||
getCodePlaceholderText
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ import { tansParams, blobValidate } from '@/utils/bonus'
|
||||||
import cache from '@/plugins/cache'
|
import cache from '@/plugins/cache'
|
||||||
import { saveAs } from 'file-saver'
|
import { saveAs } from 'file-saver'
|
||||||
import { encryptCBC, decryptCBC } from '@/utils/aescbc'
|
import { encryptCBC, decryptCBC } from '@/utils/aescbc'
|
||||||
import { CONFIG } from '@/utils/configure'
|
|
||||||
import { hashWithSM3AndSalt } from '@/utils/sm'
|
import { hashWithSM3AndSalt } from '@/utils/sm'
|
||||||
|
const systemConfig = JSON.parse(localStorage.getItem('systemConfig')) || {
|
||||||
//let token = localStorage.getItem("tokens");
|
requestConfig: { encryptRequest: false, checkIntegrity: false, encryptResponse: false }
|
||||||
|
};
|
||||||
|
|
||||||
let downloadLoadingInstance
|
let downloadLoadingInstance
|
||||||
// 是否显示重新登录
|
// 是否显示重新登录
|
||||||
|
|
@ -40,11 +40,11 @@ service.interceptors.request.use(config => {
|
||||||
|
|
||||||
// 设置请求头
|
// 设置请求头
|
||||||
//入参加密
|
//入参加密
|
||||||
config.headers['encryptRequest'] = CONFIG.dataSettings.encryptRequest && encryptRequest ? 'true' : 'false'
|
config.headers['encryptRequest'] = systemConfig.requestConfig.encryptRequest && encryptRequest ? 'true' : 'false'
|
||||||
// 数据完整性校验
|
// 数据完整性校验
|
||||||
config.headers['checkIntegrity'] = CONFIG.dataSettings.integrityCheck && checkIntegrity ? 'true' : 'false'
|
config.headers['checkIntegrity'] = systemConfig.requestConfig.checkIntegrity && checkIntegrity ? 'true' : 'false'
|
||||||
//回参是否加密
|
//回参是否加密
|
||||||
config.headers['encryptResponse'] = CONFIG.dataSettings.encryptResponse && encryptResponse ? 'true' : 'false'
|
config.headers['encryptResponse'] = systemConfig.requestConfig.encryptResponse && encryptResponse ? 'true' : 'false'
|
||||||
|
|
||||||
const isRepeatSubmit = repeatSubmit
|
const isRepeatSubmit = repeatSubmit
|
||||||
// 处理 Token
|
// 处理 Token
|
||||||
|
|
@ -52,21 +52,6 @@ service.interceptors.request.use(config => {
|
||||||
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义 token
|
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义 token
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 处理 GET 请求
|
|
||||||
// if (config.method === 'get' && config.params) {
|
|
||||||
// let params = tansParams(config.params).slice(0, -1)
|
|
||||||
// // 数据完整性校验
|
|
||||||
// if (CONFIG.dataSettings.integrityCheck && checkIntegrity) {
|
|
||||||
// config.headers['Params-Hash'] = hashWithSM3AndSalt(params)
|
|
||||||
// }
|
|
||||||
// // 加密参数
|
|
||||||
// if (CONFIG.dataSettings.encryptRequest && encryptRequest) {
|
|
||||||
// params = encryptCBC(params)
|
|
||||||
// }
|
|
||||||
// config.url = `${config.url}?${params}`
|
|
||||||
// config.params = {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
// get请求映射params参数
|
// get请求映射params参数
|
||||||
if (config.method === 'get' && config.params) {
|
if (config.method === 'get' && config.params) {
|
||||||
let url = config.url + '?' + tansParams(config.params);
|
let url = config.url + '?' + tansParams(config.params);
|
||||||
|
|
@ -80,13 +65,15 @@ service.interceptors.request.use(config => {
|
||||||
let contentType = config.headers['Content-Type']
|
let contentType = config.headers['Content-Type']
|
||||||
if (contentType.includes('application/json') && typeof data !== 'undefined') {
|
if (contentType.includes('application/json') && typeof data !== 'undefined') {
|
||||||
// 数据完整性校验
|
// 数据完整性校验
|
||||||
if (CONFIG.dataSettings.integrityCheck && checkIntegrity) {
|
if (systemConfig.requestConfig.checkIntegrity && checkIntegrity) {
|
||||||
config.headers['Params-Hash'] = hashWithSM3AndSalt(data)
|
config.headers['Params-Hash'] = hashWithSM3AndSalt(data)
|
||||||
|
console.log(hashWithSM3AndSalt(data))
|
||||||
config.data = data
|
config.data = data
|
||||||
}
|
}
|
||||||
// 加密数据
|
// 加密数据
|
||||||
if (CONFIG.dataSettings.encryptRequest && encryptRequest) {
|
if (systemConfig.requestConfig.encryptRequest && encryptRequest) {
|
||||||
config.data = encryptCBC(data)
|
config.data = encryptCBC(data)
|
||||||
|
console.log(encryptCBC(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 检查请求数据大小
|
// 检查请求数据大小
|
||||||
|
|
@ -117,7 +104,6 @@ service.interceptors.request.use(config => {
|
||||||
service.interceptors.response.use(res => {
|
service.interceptors.response.use(res => {
|
||||||
if (res.headers.encryptresponse && !res.data.hasOwnProperty('code')) {
|
if (res.headers.encryptresponse && !res.data.hasOwnProperty('code')) {
|
||||||
res.data = JSON.parse(decryptCBC(res.data))
|
res.data = JSON.parse(decryptCBC(res.data))
|
||||||
console.log(res.data)
|
|
||||||
}
|
}
|
||||||
// 未设置状态码则默认成功状态
|
// 未设置状态码则默认成功状态
|
||||||
const code = res.data.code || 200
|
const code = res.data.code || 200
|
||||||
|
|
@ -137,7 +123,7 @@ service.interceptors.response.use(res => {
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
isRelogin.show = false
|
isRelogin.show = false
|
||||||
store.dispatch('LogOut').then(() => {
|
store.dispatch('LogOut').then(() => {
|
||||||
location.href = '/login'
|
location.href = '/index'
|
||||||
})
|
})
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
isRelogin.show = false
|
isRelogin.show = false
|
||||||
|
|
@ -158,7 +144,6 @@ service.interceptors.response.use(res => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log('err' + error)
|
|
||||||
let { message } = error
|
let { message } = error
|
||||||
if (message == 'Network Error') {
|
if (message == 'Network Error') {
|
||||||
message = '后端接口连接异常'
|
message = '后端接口连接异常'
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,43 @@
|
||||||
// src/utils/encryption.js
|
// src/utils/encryption.js
|
||||||
import sm2 from 'sm-crypto/src/sm2'
|
import { sm2, sm3, sm4 } from 'sm-crypto'
|
||||||
import sm3 from 'sm-crypto/src/sm3'
|
// 配置项,例如盐值、SM2 公私钥、SM4 密钥
|
||||||
import sm4 from 'sm-crypto/src/sm4'
|
import { SM_CONFIG } from './configure'
|
||||||
|
|
||||||
// 示例密钥对,实际使用中需要从安全来源获取
|
|
||||||
const privateKey = 'your-private-key'
|
|
||||||
const publicKey = 'your-public-key'
|
|
||||||
// 生成随机盐值(16 字节)
|
|
||||||
const salt = '2cc0c5f9f1749f1632efa9f63e902323'
|
|
||||||
const sm4Key = 'your-sm4-key' // SM4 对称密钥,需要为 128 比特 (16 字节)
|
|
||||||
|
|
||||||
// SM2 加密
|
|
||||||
export function encryptSM2(data) {
|
|
||||||
// 使用公钥对数据进行加密
|
|
||||||
return sm2.doEncrypt(data, publicKey, 1) // 1 表示 C1C3C2 加密模式
|
|
||||||
}
|
|
||||||
|
|
||||||
// SM2 解密
|
|
||||||
export function decryptSM2(data) {
|
|
||||||
// 使用私钥对数据进行解密
|
|
||||||
return sm2.doDecrypt(data, privateKey, 1) // 1 表示 C1C3C2 加密模式
|
|
||||||
}
|
|
||||||
|
|
||||||
// SM3 哈希
|
// SM3 哈希
|
||||||
export function hashSM3(data) {
|
export function hashSM3(text) {
|
||||||
// 对数据进行哈希计算
|
// 对数据进行哈希计算
|
||||||
return sm3(data)
|
return sm3(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 SM3 进行哈希并加入盐值
|
// 使用 SM3 进行哈希并加入盐值
|
||||||
export function hashWithSM3AndSalt(text) {
|
export function hashWithSM3AndSalt(text) {
|
||||||
// 将文本和盐值拼接在一起
|
// 将文本和盐值拼接在一起
|
||||||
const textWithSalt = salt + text
|
const textWithSalt = SM_CONFIG.SALT + text
|
||||||
// 使用 SM3 进行哈希
|
// 使用 SM3 进行哈希
|
||||||
return hashSM3(textWithSalt)
|
return hashSM3(textWithSalt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SM2 加密
|
||||||
|
export function encryptWithSM2(text) {
|
||||||
|
// SM2 公钥加密
|
||||||
|
return sm2.doEncrypt(text, SM_CONFIG.SM2_PUBLIC_KEY)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SM2 解密
|
||||||
|
export function decryptWithSM2(encryptedText) {
|
||||||
|
// SM2 私钥解密
|
||||||
|
return sm2.doDecrypt(encryptedText, SM_CONFIG.SM2_PRIVATE_KEY)
|
||||||
|
}
|
||||||
|
|
||||||
// SM4 加密
|
// SM4 加密
|
||||||
export function encryptSM4(data) {
|
export function encryptWithSM4(text) {
|
||||||
// 使用对称密钥对数据进行加密
|
// SM4 对称加密,ECB 模式
|
||||||
const sm4Instance = new sm4()
|
return sm4.encrypt(text, SM_CONFIG.SM4_KEY)
|
||||||
return sm4Instance.encrypt(data, sm4Key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SM4 解密
|
// SM4 解密
|
||||||
export function decryptSM4(data) {
|
export function decryptWithSM4(encryptedText) {
|
||||||
// 使用对称密钥对数据进行解密
|
// SM4 对称解密,ECB 模式
|
||||||
const sm4Instance = new sm4()
|
return sm4.decrypt(encryptedText, SM_CONFIG.SM4_KEY)
|
||||||
return sm4Instance.decrypt(data, sm4Key)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
const systemConfig = JSON.parse(localStorage.getItem('systemConfig'));
|
||||||
/**
|
/**
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
|
|
@ -65,7 +66,7 @@ export function validEmail(email) {
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
export function isString(str) {
|
export function isString(str) {
|
||||||
return typeof str === 'string' || str instanceof String;
|
return typeof str === 'string' || str instanceof String
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -78,3 +79,139 @@ export function isArray(arg) {
|
||||||
}
|
}
|
||||||
return Array.isArray(arg)
|
return Array.isArray(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码的正则表达式 最少8个字符,最多20个字符,至少一个字母,一个数字和一个特殊字符:
|
||||||
|
* @param {string} password
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function validPwd(value) {
|
||||||
|
const reg = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,20}$/
|
||||||
|
return reg.test(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateNewPassword(rule, value, callback) {
|
||||||
|
// 使用配置文件中的策略进行验证
|
||||||
|
|
||||||
|
// 1. 检查密码长度
|
||||||
|
if (value.length < systemConfig.passwordConfig.minLength || value.length > systemConfig.passwordConfig.maxLength) {
|
||||||
|
callback(new Error('密码长度应为' + systemConfig.passwordConfig.minLength + '至' + systemConfig.passwordConfig.maxLength + '位!'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 检查密码复杂度
|
||||||
|
const hasUpperCase = /[A-Z]/.test(value)
|
||||||
|
const hasLowerCase = /[a-z]/.test(value)
|
||||||
|
const hasDigit = /\d/.test(value)
|
||||||
|
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(value)
|
||||||
|
|
||||||
|
if (systemConfig.passwordConfig.requireUpperCase && !hasUpperCase) {
|
||||||
|
callback(new Error('密码必须包含大写字母!'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (systemConfig.passwordConfig.requireLowerCase && !hasLowerCase) {
|
||||||
|
callback(new Error('密码必须包含小写字母!'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (systemConfig.passwordConfig.requireDigit && !hasDigit) {
|
||||||
|
callback(new Error('密码必须包含数字!'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (systemConfig.passwordConfig.requireSpecialChar && !hasSpecialChar) {
|
||||||
|
callback(new Error('密码必须包含特殊字符!'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 3. 检查是否包含弱密码
|
||||||
|
for (const weakPwd of systemConfig.passwordConfig.weakPasswords) {
|
||||||
|
// 将密码和弱密码都转换为小写进行比较
|
||||||
|
if (value.toLowerCase().includes(weakPwd.toLowerCase())) {
|
||||||
|
callback(new Error(`密码包含常见的弱密码片段: ${weakPwd}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 4. 检查是否包含超过规定数量的连续字符
|
||||||
|
if (systemConfig.passwordConfig.restrictConsecutiveChars && containsConsecutiveCharacters(value, systemConfig.passwordConfig.maxConsecutiveChars)) {
|
||||||
|
callback(new Error(`密码不能包含超过${systemConfig.passwordConfig.maxConsecutiveChars}位连续字符!`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback() // 验证成功
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查密码中是否包含超过 n 个连续相同字符、连续递增/递减的数字或字母(不区分大小写)
|
||||||
|
*/
|
||||||
|
function containsConsecutiveCharacters(password, n) {
|
||||||
|
// 检查连续相同字符
|
||||||
|
n = n + 1; // 允许最多 n 个连续字符
|
||||||
|
for (let i = 0; i <= password.length - n; i++) {
|
||||||
|
let consecutiveSameChar = true;
|
||||||
|
for (let j = 1; j < n; j++) {
|
||||||
|
if (password[i + j] !== password[i]) {
|
||||||
|
consecutiveSameChar = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (consecutiveSameChar) {
|
||||||
|
return true; // 包含超过 n 个连续相同字符
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查连续递增或递减的数字
|
||||||
|
for (let i = 0; i <= password.length - n; i++) {
|
||||||
|
let consecutiveIncreasing = true;
|
||||||
|
let consecutiveDecreasing = true;
|
||||||
|
for (let j = 1; j < n; j++) {
|
||||||
|
const currentChar = password[i];
|
||||||
|
const nextChar = password[i + j];
|
||||||
|
|
||||||
|
// 检查数字递增或递减
|
||||||
|
if (/\d/.test(currentChar) && /\d/.test(nextChar)) {
|
||||||
|
if (nextChar.charCodeAt(0) !== currentChar.charCodeAt(0) + j) {
|
||||||
|
consecutiveIncreasing = false;
|
||||||
|
}
|
||||||
|
if (nextChar.charCodeAt(0) !== currentChar.charCodeAt(0) - j) {
|
||||||
|
consecutiveDecreasing = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
consecutiveIncreasing = false;
|
||||||
|
consecutiveDecreasing = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (consecutiveIncreasing || consecutiveDecreasing) {
|
||||||
|
return true; // 包含超过 n 个递增或递减的连续数字
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查连续递增或递减的字母(不区分大小写)
|
||||||
|
for (let i = 0; i <= password.length - n; i++) {
|
||||||
|
let consecutiveIncreasing = true;
|
||||||
|
let consecutiveDecreasing = true;
|
||||||
|
for (let j = 1; j < n; j++) {
|
||||||
|
const currentChar = password[i].toLowerCase(); // 转为小写
|
||||||
|
const nextChar = password[i + j].toLowerCase(); // 转为小写
|
||||||
|
|
||||||
|
// 检查字母递增或递减
|
||||||
|
if (/[a-zA-Z]/.test(currentChar) && /[a-zA-Z]/.test(nextChar)) {
|
||||||
|
if (nextChar.charCodeAt(0) !== currentChar.charCodeAt(0) + j) {
|
||||||
|
consecutiveIncreasing = false;
|
||||||
|
}
|
||||||
|
if (nextChar.charCodeAt(0) !== currentChar.charCodeAt(0) - j) {
|
||||||
|
consecutiveDecreasing = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
consecutiveIncreasing = false;
|
||||||
|
consecutiveDecreasing = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (consecutiveIncreasing || consecutiveDecreasing) {
|
||||||
|
return true; // 包含超过 n 个递增或递减的连续字母
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不包含连续相同字符、数字或字母序列
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
<div style="width: 100%;height: 100%;border:2px solid #597DFC;border-radius: 5% 5% 0 0;">
|
<div style="width: 100%;height: 100%;border:2px solid #597DFC;border-radius: 5% 5% 0 0;">
|
||||||
<div class="top" style="height:80%">
|
<div class="top" style="height:80%">
|
||||||
<img :src="'https://largesrevice.oss-cn-beijing.aliyuncs.com/'+item.fileAddress"
|
<img :src="'https://largesrevice.oss-cn-beijing.aliyuncs.com/'+item.fileAddress"
|
||||||
style="width: 100%;height: 100%;position: absolute;left: 0; border-radius: 5% 5% 0 0;" alt=""/>
|
style="width: 100%;height: 100%;position: absolute;left: 0; border-radius: 5% 5% 0 0;object-fit: contain;background-color: #000" alt=""/>
|
||||||
<el-checkbox v-model="item.checked"
|
<el-checkbox v-model="item.checked"
|
||||||
style="margin-right: 5%;color: #FFFFFF;position: absolute;left: 1%;opacity: 1;padding: 2%;z-index: 99999"></el-checkbox>
|
style="margin-right: 5%;color: #FFFFFF;position: absolute;left: 1%;opacity: 1;padding: 2%;z-index: 99999"></el-checkbox>
|
||||||
<div v-show="item.showClose"
|
<div v-show="item.showClose"
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
<el-table-column label="模型文件" min-width="100" align="center">
|
<el-table-column label="模型文件" min-width="100" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button v-show="scope.row.modelAddress" size="mini" type="text"
|
<el-button v-show="scope.row.modelAddress" size="mini" type="text"
|
||||||
@click="downloadFile('https://largesrevice.oss-cn-beijing.aliyuncs.com/'+(scope.row.modelAddress ? scope.row.modelAddress.split(':')[1] : ''),'')">
|
@click="downloadFile('https://largesrevice.oss-cn-beijing.aliyuncs.com/'+(scope.row.modelAddress ? scope.row.modelAddress.split(':')[1] : ''),scope.row.modelAddress ? scope.row.modelAddress.split(':')[0] : '')">
|
||||||
下载
|
下载
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
<el-table-column label="使用手册" min-width="100" align="center">
|
<el-table-column label="使用手册" min-width="100" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button v-show="scope.row.userGuide" size="mini" type="text"
|
<el-button v-show="scope.row.userGuide" size="mini" type="text"
|
||||||
@click="downloadFile('https://largesrevice.oss-cn-beijing.aliyuncs.com/'+(scope.row.userGuide ? scope.row.userGuide.split(':')[1] : ''),'')">
|
@click="downloadFile('https://largesrevice.oss-cn-beijing.aliyuncs.com/'+(scope.row.userGuide ? scope.row.userGuide.split(':')[1] : ''),scope.row.userGuide ? scope.row.userGuide.split(':')[0] : '')">
|
||||||
下载
|
下载
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- <el-button size="mini" type="text" @click="downloadFile('https://largesrevice.oss-cn-beijing.aliyuncs.com/'+scope.row.userGuide,'')">查看</el-button>-->
|
<!-- <el-button size="mini" type="text" @click="downloadFile('https://largesrevice.oss-cn-beijing.aliyuncs.com/'+scope.row.userGuide,'')">查看</el-button>-->
|
||||||
|
|
@ -370,7 +370,6 @@ export default {
|
||||||
}
|
}
|
||||||
formData.delete("modelFile")
|
formData.delete("modelFile")
|
||||||
formData.delete("userGuideFile")
|
formData.delete("userGuideFile")
|
||||||
console.log(formData);
|
|
||||||
Object.values(this.fileModelList).forEach((item) => {
|
Object.values(this.fileModelList).forEach((item) => {
|
||||||
formData.append("modelFile", item.raw)
|
formData.append("modelFile", item.raw)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
v-model="loginForm.username"
|
v-model="loginForm.username"
|
||||||
type="text"
|
type="text"
|
||||||
auto-complete="off"
|
auto-complete="off"
|
||||||
:placeholder="placeholderText()"
|
:placeholder="`用户名${config.loginConfig.phonePassword ? '/手机号' : ''}${config.loginConfig.emailPassword ? '/邮箱' : ''}`"
|
||||||
>
|
>
|
||||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
|
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
v-model="loginForm.mobile"
|
v-model="loginForm.mobile"
|
||||||
type="text"
|
type="text"
|
||||||
auto-complete="off"
|
auto-complete="off"
|
||||||
:placeholder="placeholderCodeText()"
|
:placeholder="`${config.loginConfig.phoneCode ? '手机号' : '/'}${config.loginConfig.emailCode ? '邮箱' : ''}`"
|
||||||
>
|
>
|
||||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
|
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
@ -98,10 +98,10 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
<div class="login-form-center">
|
<div class="login-form-center">
|
||||||
<el-link v-if="CONFIG.IS_CODE_LOGIN" @click="toggleLoginMethod">
|
<el-link v-if="config.loginConfig.emailCode ||config.loginConfig.phoneCode " @click="toggleLoginMethod">
|
||||||
{{ loginMethod === 'password' ? '短信登录' : '密码登录' }}
|
{{ loginMethod === 'password' ? '短信登录' : '密码登录' }}
|
||||||
</el-link>
|
</el-link>
|
||||||
<router-link v-if="CONFIG.IS_OPEN_REGISTER" to="/register">
|
<router-link v-if="config.registersConfig.emailRegisters || config.registersConfig.phoneRegisters" to="/register">
|
||||||
<el-link>注册账号</el-link>
|
<el-link>注册账号</el-link>
|
||||||
</router-link>
|
</router-link>
|
||||||
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||||||
|
|
@ -149,13 +149,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {getCodeImg} from '@/api/login'
|
import { getCodeImg } from '@/api/login'
|
||||||
import Cookies from 'js-cookie'
|
import Cookies from 'js-cookie'
|
||||||
import {encrypt, decrypt} from '@/utils/jsencrypt'
|
import { decrypt, encrypt } from '@/utils/jsencrypt'
|
||||||
import dingding from '@/assets/images/dingding.svg'
|
import dingding from '@/assets/images/dingding.svg'
|
||||||
import wx from '@/assets/images/wx.svg'
|
import wx from '@/assets/images/wx.svg'
|
||||||
import qq from '@/assets/images/QQ.svg'
|
import qq from '@/assets/images/QQ.svg'
|
||||||
import {getPlaceholderText, getCodePlaceholderText, CONFIG} from '@/utils/configure'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Login',
|
name: 'Login',
|
||||||
|
|
@ -179,13 +178,13 @@ export default {
|
||||||
mobileCodeType: 'LOGIN'
|
mobileCodeType: 'LOGIN'
|
||||||
},
|
},
|
||||||
passwordLoginRules: {
|
passwordLoginRules: {
|
||||||
username: [{required: true, trigger: 'blur', message: '请输入您的账号'}],
|
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||||
password: [{required: true, trigger: 'blur', message: '请输入您的密码'}],
|
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||||
code: [{required: true, trigger: 'change', message: '请输入验证码'}]
|
code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
|
||||||
},
|
},
|
||||||
mobileLoginRules: {
|
mobileLoginRules: {
|
||||||
mobile: [{required: true, trigger: 'blur', message: '请输入您的手机号'}],
|
mobile: [{ required: true, trigger: 'blur', message: '请输入您的手机号' }],
|
||||||
verificationCode: [{required: true, trigger: 'blur', message: '请输入验证码'}]
|
verificationCode: [{ required: true, trigger: 'blur', message: '请输入验证码' }]
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
captchaEnabled: true,
|
captchaEnabled: true,
|
||||||
|
|
@ -198,8 +197,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
CONFIG() {
|
config() {
|
||||||
return CONFIG
|
return JSON.parse(localStorage.getItem('systemConfig')) || {loginConfig:{
|
||||||
|
phonePassword: true,
|
||||||
|
emailPassword: true,
|
||||||
|
phoneCode: false,
|
||||||
|
emailCode: false
|
||||||
|
},registersConfig: {
|
||||||
|
phoneRegisters: true,
|
||||||
|
emailRegisters: true
|
||||||
|
}}; // 获取 JSON 对象
|
||||||
},
|
},
|
||||||
loginRules() {
|
loginRules() {
|
||||||
return this.loginMethod === 'password' ? this.passwordLoginRules : this.mobileLoginRules
|
return this.loginMethod === 'password' ? this.passwordLoginRules : this.mobileLoginRules
|
||||||
|
|
@ -218,16 +225,9 @@ export default {
|
||||||
this.getCookie()
|
this.getCookie()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
placeholderCodeText() {
|
|
||||||
return getCodePlaceholderText()
|
|
||||||
},
|
|
||||||
placeholderText() {
|
|
||||||
return getPlaceholderText()
|
|
||||||
},
|
|
||||||
getCode() {
|
getCode() {
|
||||||
getCodeImg().then(res => {
|
getCodeImg().then(res => {
|
||||||
this.captchaEnabled = res.captchaEnabled !== undefined ? res.captchaEnabled : true
|
this.captchaEnabled = res.captchaEnabled !== undefined ? res.captchaEnabled : true
|
||||||
console.log(this.captchaEnabled)
|
|
||||||
if (this.captchaEnabled) {
|
if (this.captchaEnabled) {
|
||||||
this.codeUrl = 'data:image/gif;base64,' + res.img
|
this.codeUrl = 'data:image/gif;base64,' + res.img
|
||||||
this.loginForm.uuid = res.uuid
|
this.loginForm.uuid = res.uuid
|
||||||
|
|
@ -338,7 +338,7 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!this.loginForm.mobile) {
|
if (!this.loginForm.mobile) {
|
||||||
this.$message.error('请先填写' + getCodePlaceholderText())
|
this.$message.error('请先填写' + this.config.loginConfig.phoneCode ? '手机号' : '/' + this.config.loginConfig.emailCode ? '邮箱' : '')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$store.dispatch('GetPhoneCode', this.loginForm)
|
this.$store.dispatch('GetPhoneCode', this.loginForm)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue