Merge branch 'main' into material-ui
This commit is contained in:
commit
644652324f
|
|
@ -7,10 +7,15 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ThemePicker from "@/components/ThemePicker";
|
import ThemePicker from "@/components/ThemePicker";
|
||||||
|
import { mapActions } from 'vuex'
|
||||||
|
import { get } from '@/utils/config'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: { ThemePicker },
|
components: { ThemePicker },
|
||||||
|
created() {
|
||||||
|
get();
|
||||||
|
},
|
||||||
metaInfo() {
|
metaInfo() {
|
||||||
return {
|
return {
|
||||||
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
|
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 获取系统配置
|
||||||
|
export const getConfig = () => {
|
||||||
|
return request({
|
||||||
|
url: '/auth/getConfig',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -182,7 +182,6 @@ export default {
|
||||||
"updateCrontabValue", name, value, from;
|
"updateCrontabValue", name, value, from;
|
||||||
this.crontabValueObj[name] = value;
|
this.crontabValueObj[name] = value;
|
||||||
if (from && from !== name) {
|
if (from && from !== name) {
|
||||||
console.log(`来自组件 ${from} 改变了 ${name} ${value}`);
|
|
||||||
this.changeRadio(name, value);
|
this.changeRadio(name, value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
18
src/main.js
18
src/main.js
|
|
@ -16,21 +16,21 @@ import { download } from '@/utils/request'
|
||||||
|
|
||||||
import './assets/icons' // icon
|
import './assets/icons' // icon
|
||||||
import './permission' // permission control
|
import './permission' // permission control
|
||||||
import { getDicts } from "@/api/system/dict/data";
|
import { getDicts } from '@/api/system/dict/data'
|
||||||
import { getConfigKey } from "@/api/system/config";
|
import { getConfigKey } from '@/api/system/config'
|
||||||
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/bonus";
|
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from '@/utils/bonus'
|
||||||
// 分页组件
|
// 分页组件
|
||||||
import Pagination from "@/components/Pagination";
|
import Pagination from '@/components/Pagination'
|
||||||
// 自定义表格工具组件
|
// 自定义表格工具组件
|
||||||
import RightToolbar from "@/components/RightToolbar"
|
import RightToolbar from '@/components/RightToolbar'
|
||||||
// 富文本组件
|
// 富文本组件
|
||||||
import Editor from "@/components/Editor"
|
import Editor from '@/components/Editor'
|
||||||
// 文件上传组件
|
// 文件上传组件
|
||||||
import FileUpload from "@/components/FileUpload"
|
import FileUpload from '@/components/FileUpload'
|
||||||
// 图片上传组件
|
// 图片上传组件
|
||||||
import ImageUpload from "@/components/ImageUpload"
|
import ImageUpload from '@/components/ImageUpload'
|
||||||
// 图片预览组件
|
// 图片预览组件
|
||||||
import ImagePreview from "@/components/ImagePreview"
|
import ImagePreview from '@/components/ImagePreview'
|
||||||
// 字典标签组件
|
// 字典标签组件
|
||||||
import DictTag from '@/components/DictTag'
|
import DictTag from '@/components/DictTag'
|
||||||
// 头部标签组件
|
// 头部标签组件
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ const whiteList = ['/login', '/register']
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
if (getToken()) {
|
if (getToken()) {
|
||||||
console.log(getToken())
|
|
||||||
to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
|
to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
|
||||||
/* has token*/
|
/* has token*/
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ const getters = {
|
||||||
roles: state => state.user.roles,
|
roles: state => state.user.roles,
|
||||||
permissions: state => state.user.permissions,
|
permissions: state => state.user.permissions,
|
||||||
permission_routes: state => state.permission.routes,
|
permission_routes: state => state.permission.routes,
|
||||||
topbarRouters:state => state.permission.topbarRouters,
|
topbarRouters: state => state.permission.topbarRouters,
|
||||||
defaultRoutes:state => state.permission.defaultRoutes,
|
defaultRoutes: state => state.permission.defaultRoutes,
|
||||||
sidebarRouters:state => state.permission.sidebarRouters,
|
sidebarRouters: state => state.permission.sidebarRouters
|
||||||
}
|
}
|
||||||
export default getters
|
export default getters
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import tagsView from './modules/tagsView'
|
||||||
import permission from './modules/permission'
|
import permission from './modules/permission'
|
||||||
import settings from './modules/settings'
|
import settings from './modules/settings'
|
||||||
import getters from './getters'
|
import getters from './getters'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,6 @@ export function handleTree(data, id, parentId, children) {
|
||||||
* @param {*} params 参数
|
* @param {*} params 参数
|
||||||
*/
|
*/
|
||||||
export function tansParams(params) {
|
export function tansParams(params) {
|
||||||
console.log(params)
|
|
||||||
let result = ''
|
let result = ''
|
||||||
for (const propName of Object.keys(params)) {
|
for (const propName of Object.keys(params)) {
|
||||||
const value = params[propName]
|
const value = params[propName]
|
||||||
|
|
@ -226,7 +225,6 @@ export function tansParams(params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(result)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.CLOSE, // 手机号验证码登录(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.CLOSE, // 手机号注册(true:开启,false:关闭)
|
|
||||||
EMAIL_REGISTER: DATA_SETTINGS.CLOSE // 邮箱注册(true:开启,false:关闭)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置设置
|
|
||||||
const CONFIG = {
|
|
||||||
STRENGTH: STRENGTH_LEVELS.STRONG,//密码强度配置
|
|
||||||
IS_OPEN_REGISTER: REGISTER_CONFIG.PHONE_REGISTER || REGISTER_CONFIG.EMAIL_REGISTER, // 是否开启注册
|
|
||||||
IS_CODE_LOGIN: LOGIN_CONFIG.EMAIL_LOGIN || LOGIN_CONFIG.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.PHONE_LOGIN) loginOptions.push('手机号')
|
|
||||||
if (LOGIN_CONFIG.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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ export const options = {
|
||||||
* 字典请求,方法签名为function(dictMeta: DictMeta): Promise
|
* 字典请求,方法签名为function(dictMeta: DictMeta): Promise
|
||||||
*/
|
*/
|
||||||
request: (dictMeta) => {
|
request: (dictMeta) => {
|
||||||
console.log(`load dict ${dictMeta.type}`)
|
|
||||||
return Promise.resolve([])
|
return Promise.resolve([])
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
// src/config/passwordConfig.js
|
|
||||||
export default {
|
|
||||||
minLength: 8, // 密码最小长度
|
|
||||||
maxLength: 16, // 密码最大长度
|
|
||||||
requireUpperCase: true, // 是否需要大写字母
|
|
||||||
requireLowerCase: true, // 是否需要小写字母
|
|
||||||
requireDigit: true, // 是否需要数字
|
|
||||||
requireSpecialChar: true, // 是否需要特殊字符
|
|
||||||
weakPasswords: [ "111", "888", "123", "234", "345", "456", "567", "678", "789", "1234",
|
|
||||||
"2345", "3456", "4567", "5678", "6789", "abc", "abcd", "abcde", "abcdef", "abcdefg",
|
|
||||||
"qwe", "qwer", "qwert", "qwerty", "asdf", "asdfg", "asdfgh", "password", "passw0rd",
|
|
||||||
"letmein", "welcome", "admin", "user", "test", "pass", "root", "login"], // 弱密码列表
|
|
||||||
restrictConsecutiveChars: true, // 是否限制连续字符
|
|
||||||
maxConsecutiveChars: 2, // 最大连续字符数
|
|
||||||
excludeUsernameInPassword: true, // 是否不允许密码包含用户名
|
|
||||||
passwordHistoryLimit: 5 // 历史密码限制条数
|
|
||||||
}
|
|
||||||
|
|
@ -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,12 +65,12 @@ 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)
|
||||||
config.data = data
|
config.data = data
|
||||||
}
|
}
|
||||||
// 加密数据
|
// 加密数据
|
||||||
if (CONFIG.dataSettings.encryptRequest && encryptRequest) {
|
if (systemConfig.requestConfig.encryptRequest && encryptRequest) {
|
||||||
config.data = encryptCBC(data)
|
config.data = encryptCBC(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,10 +100,8 @@ service.interceptors.request.use(config => {
|
||||||
|
|
||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
service.interceptors.response.use(res => {
|
service.interceptors.response.use(res => {
|
||||||
console.log(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
|
||||||
|
|
@ -159,7 +142,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,6 +1,4 @@
|
||||||
import { CONFIG } from '@/utils/configure'
|
const systemConfig = JSON.parse(localStorage.getItem('systemConfig'));
|
||||||
import passwordConfig from '@/utils/passwordConfig'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
|
|
@ -92,71 +90,12 @@ export function validPwd(value) {
|
||||||
return reg.test(value)
|
return reg.test(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 弱:长度至少为8个字符。
|
|
||||||
* 一般:长度至少为8个字符,并包含至少一种字符类型。
|
|
||||||
* 强:长度至少为8个字符,并包含至少两种字符类型。
|
|
||||||
* 非常强:长度至少为8个字符,并包含所有四种字符类型。
|
|
||||||
* @param rule
|
|
||||||
* @param value
|
|
||||||
* @param callback
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function validatePassword(rule, value, callback) {
|
|
||||||
if (!value) {
|
|
||||||
return callback(new Error('请输入密码'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const lengthRegex = /^.{8,20}$/
|
|
||||||
const uppercaseRegex = /[A-Z]/
|
|
||||||
const lowercaseRegex = /[a-z]/
|
|
||||||
const digitRegex = /\d/
|
|
||||||
const specialCharRegex = /[!@#$%^&*(),.?":{}|<>]/
|
|
||||||
|
|
||||||
if (!lengthRegex.test(value)) {
|
|
||||||
return callback(new Error('密码长度必须为8到20位'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const checks = [
|
|
||||||
{ regex: uppercaseRegex, message: '必须包含至少一个大写字母' },
|
|
||||||
{ regex: lowercaseRegex, message: '必须包含至少一个小写字母' },
|
|
||||||
{ regex: digitRegex, message: '必须包含至少一个数字' },
|
|
||||||
{ regex: specialCharRegex, message: '必须包含至少一个特殊字符' }
|
|
||||||
]
|
|
||||||
|
|
||||||
let passedChecks = checks.filter(check => check.regex.test(value)).length
|
|
||||||
|
|
||||||
let requiredChecks
|
|
||||||
switch (CONFIG.STRENGTH) {
|
|
||||||
case 'weak':
|
|
||||||
requiredChecks = 1
|
|
||||||
break
|
|
||||||
case 'medium':
|
|
||||||
requiredChecks = 2
|
|
||||||
break
|
|
||||||
case 'strong':
|
|
||||||
requiredChecks = 3
|
|
||||||
break
|
|
||||||
case 'very-strong':
|
|
||||||
requiredChecks = 4
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return callback(new Error('请选择有效的密码强度'))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passedChecks < requiredChecks) {
|
|
||||||
return callback(new Error(`密码至少包含 ${requiredChecks} 类字符(大写字母,小写字母,数字,特殊字符)`))
|
|
||||||
}
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
|
|
||||||
export function validateNewPassword(rule, value, callback) {
|
export function validateNewPassword(rule, value, callback) {
|
||||||
// 使用配置文件中的策略进行验证
|
// 使用配置文件中的策略进行验证
|
||||||
|
|
||||||
// 1. 检查密码长度
|
// 1. 检查密码长度
|
||||||
if (value.length < passwordConfig.minLength || value.length > passwordConfig.maxLength) {
|
if (value.length < systemConfig.passwordConfig.minLength || value.length > systemConfig.passwordConfig.maxLength) {
|
||||||
callback(new Error('密码长度应为' + passwordConfig.minLength + '至' + passwordConfig.maxLength + '位!'))
|
callback(new Error('密码长度应为' + systemConfig.passwordConfig.minLength + '至' + systemConfig.passwordConfig.maxLength + '位!'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,24 +105,24 @@ export function validateNewPassword(rule, value, callback) {
|
||||||
const hasDigit = /\d/.test(value)
|
const hasDigit = /\d/.test(value)
|
||||||
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(value)
|
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(value)
|
||||||
|
|
||||||
if (passwordConfig.requireUpperCase && !hasUpperCase) {
|
if (systemConfig.passwordConfig.requireUpperCase && !hasUpperCase) {
|
||||||
callback(new Error('密码必须包含大写字母!'))
|
callback(new Error('密码必须包含大写字母!'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (passwordConfig.requireLowerCase && !hasLowerCase) {
|
if (systemConfig.passwordConfig.requireLowerCase && !hasLowerCase) {
|
||||||
callback(new Error('密码必须包含小写字母!'))
|
callback(new Error('密码必须包含小写字母!'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (passwordConfig.requireDigit && !hasDigit) {
|
if (systemConfig.passwordConfig.requireDigit && !hasDigit) {
|
||||||
callback(new Error('密码必须包含数字!'))
|
callback(new Error('密码必须包含数字!'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (passwordConfig.requireSpecialChar && !hasSpecialChar) {
|
if (systemConfig.passwordConfig.requireSpecialChar && !hasSpecialChar) {
|
||||||
callback(new Error('密码必须包含特殊字符!'))
|
callback(new Error('密码必须包含特殊字符!'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 3. 检查是否包含弱密码
|
// 3. 检查是否包含弱密码
|
||||||
for (const weakPwd of passwordConfig.weakPasswords) {
|
for (const weakPwd of systemConfig.passwordConfig.weakPasswords) {
|
||||||
// 将密码和弱密码都转换为小写进行比较
|
// 将密码和弱密码都转换为小写进行比较
|
||||||
if (value.toLowerCase().includes(weakPwd.toLowerCase())) {
|
if (value.toLowerCase().includes(weakPwd.toLowerCase())) {
|
||||||
callback(new Error(`密码包含常见的弱密码片段: ${weakPwd}`))
|
callback(new Error(`密码包含常见的弱密码片段: ${weakPwd}`))
|
||||||
|
|
@ -191,8 +130,8 @@ export function validateNewPassword(rule, value, callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 4. 检查是否包含超过规定数量的连续字符
|
// 4. 检查是否包含超过规定数量的连续字符
|
||||||
if (passwordConfig.restrictConsecutiveChars && containsConsecutiveCharacters(value, passwordConfig.maxConsecutiveChars)) {
|
if (systemConfig.passwordConfig.restrictConsecutiveChars && containsConsecutiveCharacters(value, systemConfig.passwordConfig.maxConsecutiveChars)) {
|
||||||
callback(new Error(`密码不能包含超过${passwordConfig.maxConsecutiveChars}位连续字符!`))
|
callback(new Error(`密码不能包含超过${systemConfig.passwordConfig.maxConsecutiveChars}位连续字符!`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
callback() // 验证成功
|
callback() // 验证成功
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,8 @@ export default {
|
||||||
return {
|
return {
|
||||||
codeUrl: "",
|
codeUrl: "",
|
||||||
loginForm: {
|
loginForm: {
|
||||||
username: "admin",
|
username: "",
|
||||||
password: "admin123",
|
password: "",
|
||||||
rememberMe: false,
|
rememberMe: false,
|
||||||
code: "",
|
code: "",
|
||||||
uuid: ""
|
uuid: ""
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -151,11 +151,10 @@
|
||||||
<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',
|
||||||
|
|
@ -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
|
||||||
|
|
@ -307,7 +307,6 @@ export default {
|
||||||
this.loginForm.mobile = this.loginForm.username
|
this.loginForm.mobile = this.loginForm.username
|
||||||
this.$store.dispatch('GetPhoneCode', this.loginForm)
|
this.$store.dispatch('GetPhoneCode', this.loginForm)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
console.log(res)
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.loginForm.phoneUuid = res.data
|
this.loginForm.phoneUuid = res.data
|
||||||
this.$message.success('验证码发送成功')
|
this.$message.success('验证码发送成功')
|
||||||
|
|
@ -339,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)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item prop="mobile">
|
<el-form-item prop="mobile">
|
||||||
<el-input v-model="registerForm.mobile" type="text" auto-complete="off" placeholder="请输入手机号/邮箱">
|
<el-input v-model="registerForm.mobile" type="text" auto-complete="off"
|
||||||
|
:placeholder="`请输入${config.registersConfig.phoneRegisters ? '手机号' : ''}${config.registersConfig.emailRegisters ? '/邮箱' : ''}`">
|
||||||
<svg-icon slot="prefix" icon-class="phone" class="el-input__icon input-icon"/>
|
<svg-icon slot="prefix" icon-class="phone" class="el-input__icon input-icon"/>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -99,15 +100,21 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getCodeImg, register } from '@/api/login'
|
import { getCodeImg, register } from '@/api/login'
|
||||||
import { validateNewPassword, validatePassword } from '@/utils/validate'
|
import { validateNewPassword } from '@/utils/validate'
|
||||||
import { CONFIG, REGISTER_CONFIG } from '@/utils/configure'
|
import { decryptCBC } from '@/utils/aescbc'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Register',
|
name: 'Register',
|
||||||
computed: {
|
computed: {
|
||||||
LOGIN() {
|
LOGIN() {
|
||||||
return LOGIN
|
return LOGIN
|
||||||
}
|
},
|
||||||
|
config() {
|
||||||
|
return JSON.parse(localStorage.getItem('systemConfig')) || {registersConfig: {
|
||||||
|
phoneRegisters: true,
|
||||||
|
emailRegisters: true
|
||||||
|
}}; // 获取 JSON 对象
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
// 验证姓名是否符合要求
|
// 验证姓名是否符合要求
|
||||||
|
|
@ -144,6 +151,7 @@ export default {
|
||||||
nickName: '',
|
nickName: '',
|
||||||
code: '',
|
code: '',
|
||||||
uuid: '',
|
uuid: '',
|
||||||
|
phoneUuid: '',
|
||||||
mobileCodeType: 'REGISTER'
|
mobileCodeType: 'REGISTER'
|
||||||
},
|
},
|
||||||
registerRules: {
|
registerRules: {
|
||||||
|
|
@ -168,6 +176,7 @@ export default {
|
||||||
captchaEnabled: true
|
captchaEnabled: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.getCode()
|
this.getCode()
|
||||||
},
|
},
|
||||||
|
|
@ -209,20 +218,22 @@ export default {
|
||||||
|
|
||||||
// 发送验证码
|
// 发送验证码
|
||||||
sendCode() {
|
sendCode() {
|
||||||
|
|
||||||
if (!this.registerForm.mobile) {
|
if (!this.registerForm.mobile) {
|
||||||
this.$message.error('请先填写手机号')
|
this.$message.error('请先填写手机号')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$store.dispatch('GetPhoneCode', this.registerForm)
|
this.$store.dispatch('GetPhoneCode', this.registerForm)
|
||||||
.then(() => {
|
.then(res => {
|
||||||
|
if (!res.hasOwnProperty('code')) {
|
||||||
|
res = JSON.parse(decryptCBC(res))
|
||||||
|
}
|
||||||
|
this.loginForm.phoneUuid = res.data
|
||||||
this.isSendingCode = true
|
this.isSendingCode = true
|
||||||
this.countdown = 60
|
this.countdown = 60
|
||||||
const timer = setInterval(() => {
|
const timer = setInterval(() => {
|
||||||
this.countdown -= 1
|
this.countdown -= 1
|
||||||
if (this.countdown <= 0) {
|
if (this.countdown <= 0) {
|
||||||
clearInterval(timer)
|
clearInterval(timer)
|
||||||
/* this.isSendingCode = false */
|
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
v-hasPermi="['system:dept:add']"
|
v-hasPermi="['system:dept:add']"
|
||||||
>新增</el-button>
|
>新增</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="CONFIG.IS_ADD_ROOT_COMPANY ? true : scope.row.parentId != 0"
|
v-if="config.isAddRootCompany? true : scope.row.parentId != 0"
|
||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
icon="el-icon-delete"
|
icon="el-icon-delete"
|
||||||
|
|
@ -106,7 +106,7 @@
|
||||||
v-model="form.parentId"
|
v-model="form.parentId"
|
||||||
:options="deptOptions"
|
:options="deptOptions"
|
||||||
:normalizer="normalizer"
|
:normalizer="normalizer"
|
||||||
:placeholder="CONFIG.IS_ADD_ROOT_COMPANY ? '选择上级部门,如果不选择则创建顶级部门' : '选择上级部门'"
|
:placeholder="config.isAddRootCompany ? '选择上级部门,如果不选择则创建顶级部门' : '选择上级部门'"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
@ -166,13 +166,12 @@
|
||||||
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept";
|
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept";
|
||||||
import Treeselect from "@riophae/vue-treeselect";
|
import Treeselect from "@riophae/vue-treeselect";
|
||||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||||
import {CONFIG} from "@/utils/configure";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Dept",
|
name: "Dept",
|
||||||
computed: {
|
computed: {
|
||||||
CONFIG() {
|
config() {
|
||||||
return CONFIG
|
return JSON.parse(localStorage.getItem('systemConfig')); // 获取 JSON 对象
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dicts: ['sys_normal_disable'],
|
dicts: ['sys_normal_disable'],
|
||||||
|
|
@ -204,7 +203,7 @@ export default {
|
||||||
form: {},
|
form: {},
|
||||||
// 表单校验
|
// 表单校验
|
||||||
rules: {
|
rules: {
|
||||||
parentId: CONFIG.IS_ADD_ROOT_COMPANY ? [] : [{ required: true, message: "上级部门不能为空", trigger: "blur" } ] ,
|
parentId: this.config.isAddRootCompany ? [] : [{ required: true, message: "上级部门不能为空", trigger: "blur" } ] ,
|
||||||
deptName: [
|
deptName: [
|
||||||
{ required: true, message: "部门名称不能为空", trigger: "blur" }
|
{ required: true, message: "部门名称不能为空", trigger: "blur" }
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||||
<el-form-item label="字典名称" prop="dictName">
|
<el-form-item label="字典名称" prop="dictName">
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,6 @@
|
||||||
}
|
}
|
||||||
return obj
|
return obj
|
||||||
});
|
});
|
||||||
console.log(this.echartData)
|
|
||||||
this.getInitData()
|
this.getInitData()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -420,7 +420,6 @@ export default {
|
||||||
},
|
},
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
handleAdd(row) {
|
handleAdd(row) {
|
||||||
console.log();
|
|
||||||
this.reset();
|
this.reset();
|
||||||
this.getTreeselect();
|
this.getTreeselect();
|
||||||
if (row != null && row.menuId) {
|
if (row != null && row.menuId) {
|
||||||
|
|
@ -447,7 +446,6 @@ export default {
|
||||||
getMenu(row.menuId).then(response => {
|
getMenu(row.menuId).then(response => {
|
||||||
this.form = response.data;
|
this.form = response.data;
|
||||||
const systemType = response.data.systemType
|
const systemType = response.data.systemType
|
||||||
// console.log("********************** systemType:" + systemType)
|
|
||||||
if (systemType) {
|
if (systemType) {
|
||||||
this.systemType = systemType.split(',')
|
this.systemType = systemType.split(',')
|
||||||
}
|
}
|
||||||
|
|
@ -459,7 +457,7 @@ export default {
|
||||||
submitForm: function() {
|
submitForm: function() {
|
||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
this.form.systemType = this.systemType.toString()
|
this.form.systemType = this.systemType.toString()
|
||||||
// console.log("********************** this.form.systemType:" + this.form.systemType)
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.menuId != undefined) {
|
if (this.form.menuId != undefined) {
|
||||||
updateMenu(this.form).then(response => {
|
updateMenu(this.form).then(response => {
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,11 @@
|
||||||
></el-switch>
|
></el-switch>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="审批状态" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{scope.row.approvalStatus==0?"未审批":"已审批" }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
|
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
|
|
@ -305,9 +310,7 @@ import {
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
import Treeselect from '@riophae/vue-treeselect'
|
import Treeselect from '@riophae/vue-treeselect'
|
||||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||||
import { validPwd, validatePassword, validateNewPassword } from '@/utils/validate'
|
import {validateNewPassword } from '@/utils/validate'
|
||||||
import { hashWithSM3AndSalt } from '@/utils/sm'
|
|
||||||
import passwordConfig from '@/utils/passwordConfig'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'User',
|
name: 'User',
|
||||||
|
|
@ -439,14 +442,6 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* 表单用户密码自定义校验 */
|
|
||||||
validatePwd(rule, value, callback) {
|
|
||||||
if (validPwd(value)) {
|
|
||||||
callback()
|
|
||||||
} else {
|
|
||||||
callback(new Error('密码规则为:至少一个字母,一个数字和一个特殊字符'))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/* 表单登录权限自定义校验 */
|
/* 表单登录权限自定义校验 */
|
||||||
validateLoginType(rule, value, callback) {
|
validateLoginType(rule, value, callback) {
|
||||||
if (this.loginTypeArr.length > 0) {
|
if (this.loginTypeArr.length > 0) {
|
||||||
|
|
@ -460,7 +455,6 @@ export default {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
|
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
|
||||||
this.userList = response.rows
|
this.userList = response.rows
|
||||||
console.log(this.userList)
|
|
||||||
this.total = response.total
|
this.total = response.total
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
|
|
@ -469,7 +463,6 @@ export default {
|
||||||
/** 查询部门下拉树结构 */
|
/** 查询部门下拉树结构 */
|
||||||
getDeptTree() {
|
getDeptTree() {
|
||||||
deptTreeSelect().then(response => {
|
deptTreeSelect().then(response => {
|
||||||
console.log(response.data)
|
|
||||||
this.deptOptions = this.filterTree(response.data)
|
this.deptOptions = this.filterTree(response.data)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -496,7 +489,6 @@ export default {
|
||||||
//用户审批状态修改
|
//用户审批状态修改
|
||||||
handleApprovalStatus(row) {
|
handleApprovalStatus(row) {
|
||||||
this.$modal.confirm('确认要审批' + row.userName + '"用户吗?').then(function() {
|
this.$modal.confirm('确认要审批' + row.userName + '"用户吗?').then(function() {
|
||||||
console.log({ userId: row.userId })
|
|
||||||
return approvalStatus({ userId: row.userId })
|
return approvalStatus({ userId: row.userId })
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$modal.msgSuccess('审批成功')
|
this.$modal.msgSuccess('审批成功')
|
||||||
|
|
@ -617,10 +609,14 @@ export default {
|
||||||
inputErrorMessage: '用户密码长度必须介于 8 和 16 之间',
|
inputErrorMessage: '用户密码长度必须介于 8 和 16 之间',
|
||||||
inputValidator: (value) => {
|
inputValidator: (value) => {
|
||||||
// 调用 validateNewPassword 校验
|
// 调用 validateNewPassword 校验
|
||||||
const errorMessage = this.validateNewPasswordForPrompt(row.userName, value)
|
const errorMessage=function(error) {
|
||||||
if (errorMessage) {
|
if (error) {
|
||||||
return errorMessage // 返回错误信息进行提示
|
return error.message;
|
||||||
|
} else {
|
||||||
|
console.log('验证通过');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
validateNewPassword(null, value, errorMessage);
|
||||||
}
|
}
|
||||||
}).then(({ value }) => {
|
}).then(({ value }) => {
|
||||||
resetUserPwd(row.userId, value).then(response => {
|
resetUserPwd(row.userId, value).then(response => {
|
||||||
|
|
@ -697,127 +693,6 @@ export default {
|
||||||
// 提交上传文件
|
// 提交上传文件
|
||||||
submitFileForm() {
|
submitFileForm() {
|
||||||
this.$refs.upload.submit()
|
this.$refs.upload.submit()
|
||||||
},
|
|
||||||
validateNewPasswordForPrompt(username, newPassword) {
|
|
||||||
// 1. 检查密码长度
|
|
||||||
if (newPassword.length < passwordConfig.minLength || newPassword.length > passwordConfig.maxLength) {
|
|
||||||
return '密码长度应为' + passwordConfig.minLength + '至' + passwordConfig.maxLength + '位!'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 检查密码复杂度
|
|
||||||
const hasUpperCase = /[A-Z]/.test(newPassword)
|
|
||||||
const hasLowerCase = /[a-z]/.test(newPassword)
|
|
||||||
const hasDigit = /\d/.test(newPassword)
|
|
||||||
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(newPassword)
|
|
||||||
|
|
||||||
if (passwordConfig.requireUpperCase && !hasUpperCase) {
|
|
||||||
return '密码必须包含大写字母!'
|
|
||||||
}
|
|
||||||
if (passwordConfig.requireLowerCase && !hasLowerCase) {
|
|
||||||
return '密码必须包含小写字母!'
|
|
||||||
}
|
|
||||||
if (passwordConfig.requireDigit && !hasDigit) {
|
|
||||||
return '密码必须包含数字!'
|
|
||||||
}
|
|
||||||
if (passwordConfig.requireSpecialChar && !hasSpecialChar) {
|
|
||||||
return '密码必须包含特殊字符!'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 检查是否包含弱密码
|
|
||||||
for (const weakPwd of passwordConfig.weakPasswords) {
|
|
||||||
if (newPassword.includes(weakPwd)) {
|
|
||||||
return `密码包含常见的弱密码片段: ${weakPwd}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 检查是否包含超过规定数量的连续字符
|
|
||||||
if (passwordConfig.restrictConsecutiveChars && this.containsConsecutiveCharacters(newPassword, passwordConfig.maxConsecutiveChars)) {
|
|
||||||
return `密码不能包含超过${passwordConfig.maxConsecutiveChars}位连续字符!`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. 检查密码中是否包含用户名
|
|
||||||
if (passwordConfig.excludeUsernameInPassword && newPassword.includes(username)) {
|
|
||||||
return '密码不能包含账号!'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. 新密码通过所有校验,返回空表示通过校验
|
|
||||||
return null
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 检查密码中是否包含超过 n 个连续相同字符、连续递增/递减的数字或字母(不区分大小写)
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { updateUserPwd } from "@/api/system/user";
|
import { updateUserPwd } from "@/api/system/user";
|
||||||
import { validateNewPassword, validatePassword } from '@/utils/validate'
|
import { validateNewPassword } from '@/utils/validate'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue