Merge d9eccc4f3d into 10ac766489
This commit is contained in:
commit
787f4c31f4
|
|
@ -56,7 +56,8 @@
|
|||
"vue3-text-clamp": "^0.1.1",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vuex": "^4.0.0-0",
|
||||
"xlsx": "^0.18.5"
|
||||
"xlsx": "^0.18.5",
|
||||
"@zxcvbn-ts/core": "^3.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.3.0",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ dependencies:
|
|||
'@wangeditor/editor-for-vue':
|
||||
specifier: ^5.1.12
|
||||
version: 5.1.12(@wangeditor/editor@5.1.23)(vue@3.3.13)
|
||||
'@zxcvbn-ts/core':
|
||||
specifier: ^3.0.4
|
||||
version: 3.0.4
|
||||
axios:
|
||||
specifier: ^0.27.2
|
||||
version: 0.27.2
|
||||
|
|
@ -204,7 +207,7 @@ devDependencies:
|
|||
version: 0.7.3(vite@3.2.7)(vue@3.3.13)
|
||||
vite:
|
||||
specifier: ^3.0.0
|
||||
version: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||
version: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
||||
vite-plugin-compression:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(vite@3.2.7)
|
||||
|
|
@ -400,7 +403,7 @@ packages:
|
|||
lodash.merge: 4.6.2
|
||||
lodash.uniq: 4.5.0
|
||||
resolve-from: 5.0.0
|
||||
ts-node: 10.9.2(@types/node@20.5.1)(typescript@4.9.5)
|
||||
ts-node: 10.9.2(@types/node@18.19.3)(typescript@4.9.5)
|
||||
typescript: 4.9.5
|
||||
transitivePeerDependencies:
|
||||
- '@swc/core'
|
||||
|
|
@ -776,7 +779,6 @@ packages:
|
|||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@types/node@20.10.5:
|
||||
resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==}
|
||||
|
|
@ -1124,7 +1126,7 @@ packages:
|
|||
vite: ^3.0.0
|
||||
vue: ^3.2.25
|
||||
dependencies:
|
||||
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
||||
vue: 3.3.13(typescript@4.9.5)
|
||||
dev: true
|
||||
|
||||
|
|
@ -1465,6 +1467,12 @@ packages:
|
|||
snabbdom: 3.5.1
|
||||
dev: false
|
||||
|
||||
/@zxcvbn-ts/core@3.0.4:
|
||||
resolution: {integrity: sha512-aQeiT0F09FuJaAqNrxynlAwZ2mW/1MdXakKWNmGM1Qp/VaY6CnB/GfnMS2T8gB2231Esp1/maCWd8vTG4OuShw==}
|
||||
dependencies:
|
||||
fastest-levenshtein: 1.0.16
|
||||
dev: false
|
||||
|
||||
/JSONStream@1.3.5:
|
||||
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
|
||||
hasBin: true
|
||||
|
|
@ -2353,7 +2361,7 @@ packages:
|
|||
dependencies:
|
||||
'@types/node': 20.5.1
|
||||
cosmiconfig: 8.3.6(typescript@4.9.5)
|
||||
ts-node: 10.9.2(@types/node@20.5.1)(typescript@4.9.5)
|
||||
ts-node: 10.9.2(@types/node@18.19.3)(typescript@4.9.5)
|
||||
typescript: 4.9.5
|
||||
dev: true
|
||||
|
||||
|
|
@ -3438,6 +3446,11 @@ packages:
|
|||
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
|
||||
dev: true
|
||||
|
||||
/fastest-levenshtein@1.0.16:
|
||||
resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==}
|
||||
engines: {node: '>= 4.9.1'}
|
||||
dev: false
|
||||
|
||||
/fastq@1.16.0:
|
||||
resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==}
|
||||
dependencies:
|
||||
|
|
@ -6675,7 +6688,7 @@ packages:
|
|||
typescript: 4.9.5
|
||||
dev: true
|
||||
|
||||
/ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5):
|
||||
/ts-node@10.9.2(@types/node@18.19.3)(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
|
|
@ -6694,7 +6707,7 @@ packages:
|
|||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/node': 20.5.1
|
||||
'@types/node': 18.19.3
|
||||
acorn: 8.11.2
|
||||
acorn-walk: 8.3.1
|
||||
arg: 4.1.3
|
||||
|
|
@ -6940,7 +6953,7 @@ packages:
|
|||
dependencies:
|
||||
acorn: 8.11.2
|
||||
chokidar: 3.5.3
|
||||
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.4.6
|
||||
dev: true
|
||||
|
|
@ -6964,7 +6977,7 @@ packages:
|
|||
dependencies:
|
||||
acorn: 8.11.2
|
||||
chokidar: 3.5.3
|
||||
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.4.6
|
||||
dev: true
|
||||
|
|
@ -7138,7 +7151,7 @@ packages:
|
|||
chalk: 4.1.2
|
||||
debug: 4.3.4(supports-color@9.4.0)
|
||||
fs-extra: 10.1.0
|
||||
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
|
@ -7155,7 +7168,7 @@ packages:
|
|||
fs-extra: 10.1.0
|
||||
magic-string: 0.25.9
|
||||
pathe: 0.2.0
|
||||
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
||||
dev: true
|
||||
|
||||
/vite-plugin-svg-icons@2.0.1(vite@3.2.7):
|
||||
|
|
@ -7171,7 +7184,7 @@ packages:
|
|||
pathe: 0.2.0
|
||||
svg-baker: 1.7.0
|
||||
svgo: 2.8.0
|
||||
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
|
@ -7183,10 +7196,10 @@ packages:
|
|||
dependencies:
|
||||
'@vue/compiler-sfc': 3.3.13
|
||||
magic-string: 0.25.9
|
||||
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
||||
dev: true
|
||||
|
||||
/vite@3.2.7(@types/node@20.5.1)(sass@1.69.5):
|
||||
/vite@3.2.7(@types/node@18.19.3)(sass@1.69.5):
|
||||
resolution: {integrity: sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
|
|
@ -7211,7 +7224,7 @@ packages:
|
|||
terser:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/node': 20.5.1
|
||||
'@types/node': 18.19.3
|
||||
esbuild: 0.15.18
|
||||
postcss: 8.4.32
|
||||
resolve: 1.22.8
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
.inputStrength {
|
||||
width: 100%;
|
||||
:deep(.#{'el'}-input__clear) {
|
||||
margin-left: 5px;
|
||||
}
|
||||
&-input {
|
||||
&_icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&-line {
|
||||
background-color: var(--el-text-color-disabled);
|
||||
border-radius: var(--el-border-radius-base);
|
||||
position: relative;
|
||||
margin-bottom: 6px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 10px;
|
||||
height: 6px;
|
||||
&::before,
|
||||
&::after {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
display: block;
|
||||
width: 20%;
|
||||
height: inherit;
|
||||
background-color: transparent;
|
||||
border-color: var(--el-color-white);
|
||||
border-style: solid;
|
||||
border-width: 0 5px;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&::before {
|
||||
left: 20%;
|
||||
}
|
||||
|
||||
&::after {
|
||||
right: 20%;
|
||||
}
|
||||
|
||||
&_visual {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: inherit;
|
||||
background-color: transparent;
|
||||
border-radius: inherit;
|
||||
transition: width 0.5s ease-in-out, background 0.25s;
|
||||
|
||||
&[data-score='0'] {
|
||||
width: 20%;
|
||||
background-color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
&[data-score='1'] {
|
||||
width: 40%;
|
||||
background-color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
&[data-score='2'] {
|
||||
width: 60%;
|
||||
background-color: var(--el-color-warning);
|
||||
}
|
||||
|
||||
&[data-score='3'] {
|
||||
width: 80%;
|
||||
background-color: var(--el-color-success);
|
||||
}
|
||||
|
||||
&[data-score='4'] {
|
||||
width: 100%;
|
||||
background-color: var(--el-color-success);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<template>
|
||||
<div class="inputStrength">
|
||||
<el-input v-model="inputValue" placeholder="请输入密码" :type="textType" v-bind="$attrs" class="inputStrength-input">
|
||||
<template #suffix>
|
||||
<div class="inputStrength-input_icon" @click="changeTextType">
|
||||
<svg-icon :icon-class="passwordType ? 'eye' : 'eye-open'" />
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<div v-if="strength" class="inputStrength-line">
|
||||
<div class="inputStrength-line_visual" :data-score="getPasswordStrength"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch, unref, ref, computed, PropType } from 'vue'
|
||||
import type { ZxcvbnResult } from '@zxcvbn-ts/core'
|
||||
import { zxcvbn } from '@zxcvbn-ts/core'
|
||||
|
||||
const props = defineProps({
|
||||
// 是否显示强度
|
||||
strength: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
modelValue: {
|
||||
type: String as PropType<string>,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const emits = defineEmits(['update:modelValue'])
|
||||
|
||||
// 输入框的值
|
||||
const inputValue = ref(props.modelValue)
|
||||
|
||||
//输入框类型,默认密码态
|
||||
const textType = ref<'password' | 'text'>('password')
|
||||
|
||||
//切换输入框类型
|
||||
const changeTextType = () => {
|
||||
textType.value = unref(textType) === 'text' ? 'password' : 'text'
|
||||
}
|
||||
//切换icon
|
||||
const passwordType = computed(() => unref(textType) === 'password')
|
||||
|
||||
// 计算密码强度
|
||||
const getPasswordStrength = computed(() => {
|
||||
const value = unref(inputValue)
|
||||
const zxcvbnRef = zxcvbn(inputValue.value) as ZxcvbnResult
|
||||
return value ? zxcvbnRef.score : -1
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: string) => {
|
||||
if (val === unref(inputValue)) return
|
||||
inputValue.value = val
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => inputValue.value,
|
||||
(val: string) => {
|
||||
emits('update:modelValue', val)
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
|
|
@ -1,14 +1,17 @@
|
|||
<template>
|
||||
<el-dialog v-model="dialogVisible" title="修改密码" width="40%">
|
||||
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm" :size="formSize">
|
||||
<el-form-item label="姓名">
|
||||
<el-form-item label="用户名称">
|
||||
<el-input v-model="ruleForm.name" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="旧的密码" prop="password">
|
||||
<el-input v-model="ruleForm.password" type="password"></el-input>
|
||||
<el-form-item label="旧密码" prop="oldPassword">
|
||||
<inputStrength v-model="ruleForm.oldPassword" placeholder="请输入旧密码"></inputStrength>
|
||||
</el-form-item>
|
||||
<el-form-item label="新的密码" prop="configPassword">
|
||||
<el-input v-model="ruleForm.configPassword" type="password"></el-input>
|
||||
<el-form-item label="新密码" prop="newPassword">
|
||||
<inputStrength v-model="ruleForm.newPassword" strength placeholder="请输入新密码"></inputStrength>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword">
|
||||
<inputStrength v-model="ruleForm.confirmPassword" strength placeholder="请确认新密码"></inputStrength>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
|
|
@ -21,8 +24,10 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineExpose, reactive } from 'vue'
|
||||
import { ref, computed, defineExpose, reactive } from 'vue'
|
||||
import type { ElForm } from 'element-plus'
|
||||
import inputStrength from '@/components/InputStrength/index.vue'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
const UserStore = useUserStore()
|
||||
|
|
@ -34,21 +39,37 @@
|
|||
}
|
||||
type FormInstance = InstanceType<typeof ElForm>
|
||||
|
||||
const userInfo = computed(() => UserStore.userInfo)
|
||||
|
||||
const formSize = ref('')
|
||||
const ruleFormRef = ref<FormInstance>()
|
||||
const ruleForm = reactive({
|
||||
name: UserStore.userInfo.username,
|
||||
password: UserStore.userInfo.password,
|
||||
configPassword: '',
|
||||
name: userInfo.value?.username,
|
||||
oldPassword: userInfo.value?.password,
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
})
|
||||
|
||||
//确认密码输入值的一致性校验
|
||||
const equalToPassword = (_rule, value, callback) => {
|
||||
ruleForm.newPassword !== value ? callback(new Error('两次输入密码不一致')) : callback()
|
||||
}
|
||||
const rules = reactive({
|
||||
configPassword: [
|
||||
newPassword: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入新的密码',
|
||||
message: '请输入新密码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
confirmPassword: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入确认密码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
{ required: true, validator: equalToPassword, trigger: 'blur' },
|
||||
],
|
||||
})
|
||||
const submitForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
|
|
|||
|
|
@ -103,6 +103,12 @@ const othersRouter = [
|
|||
name: 'text-clamp',
|
||||
meta: { title: '多行文本省略', icon: 'MenuIcon' },
|
||||
},
|
||||
{
|
||||
path: '/other/pass-strength',
|
||||
component: () => import('@/views/other/passStrength/index.vue'),
|
||||
name: 'pass-strength',
|
||||
meta: { title: '密码强度校验', icon: 'MenuIcon' },
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<PageWrapLayout class="components-container">
|
||||
<div class="m-pass-strength">
|
||||
<el-card style="margin-bottom: 10px">
|
||||
<template #header>
|
||||
<span>密码强度示例</span>
|
||||
</template>
|
||||
<el-form :model="ruleForm" label-width="120px">
|
||||
<el-form-item label="新的密码" prop="newPassword">
|
||||
<inputStrength v-model="ruleForm.newPassword" strength placeholder="请输入新密码"></inputStrength>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword">
|
||||
<inputStrength v-model="ruleForm.confirmPassword" strength placeholder="请确认新密码"></inputStrength>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-descriptions title="配置项" :column="1" border class="descriptions">
|
||||
<el-descriptions-item label="strength"> 是否显示密码强度,默认为 false </el-descriptions-item>
|
||||
<el-descriptions-item label="value"> 双向绑定的 value 值,使用示例:v-model='passValue' </el-descriptions-item>
|
||||
<el-descriptions-item label="常见场景">
|
||||
<el-tag type="info">修改密码</el-tag> <el-tag type="info">用户注册</el-tag></el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item label="参考地址">
|
||||
<a href="https://github.com/zxcvbn-ts/zxcvbn" target="_blank">https://github.com/zxcvbn-ts/zxcvbn</a>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</PageWrapLayout>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import inputStrength from '@/components/InputStrength/index.vue'
|
||||
const ruleForm = reactive({
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.m-pass-strength {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.descriptions {
|
||||
margin-top: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue