Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/FiDA_Front
This commit is contained in:
@@ -13,10 +13,16 @@
|
|||||||
>
|
>
|
||||||
<svg-icon :name="v.icon" :size="v.iconSize" />
|
<svg-icon :name="v.icon" :size="v.iconSize" />
|
||||||
</span>
|
</span>
|
||||||
<span class="more" v-if="v.child" @click="onClickMore(v)">
|
<span class="more" v-if="v.child" @click="onClickMore(v)" :bind-id="v.name">
|
||||||
<svg-icon name="dc-down_arrow2" size="7" />
|
<svg-icon name="dc-down_arrow2" size="7" />
|
||||||
</span>
|
</span>
|
||||||
<div v-if="v.child" class="child" v-show="v.showChild">
|
<div
|
||||||
|
v-if="v.child"
|
||||||
|
class="child"
|
||||||
|
v-show="v.showChild"
|
||||||
|
:bind-id="v.name"
|
||||||
|
v-clidk-besides="() => (v.showChild = false)"
|
||||||
|
>
|
||||||
<div v-for="(v_, i_) in v.child" :key="i_" @click="onClickTool(v_, v)">
|
<div v-for="(v_, i_) in v.child" :key="i_" @click="onClickTool(v_, v)">
|
||||||
<span v-show="tool === v_.name" class="dui">
|
<span v-show="tool === v_.name" class="dui">
|
||||||
<svg-icon name="dc-dui" size="9" />
|
<svg-icon name="dc-dui" size="9" />
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="depth-select">
|
<div class="depth-select">
|
||||||
<el-select :model-value="modelValue" @change="onChange" v-bind="attrs">
|
<el-select :model-value="modelValue" @change="onChange" v-bind="attrs">
|
||||||
<el-option v-for="v in list" :key="v.value" :label="v.label" :value="v.value" />
|
<el-option
|
||||||
|
v-for="v in list"
|
||||||
|
:key="v.value"
|
||||||
|
:label="v.label"
|
||||||
|
:value="v.value"
|
||||||
|
:disabled="modelValue === v.value"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -22,6 +28,7 @@
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.depth-select {
|
.depth-select {
|
||||||
&:deep(.el-select) {
|
&:deep(.el-select) {
|
||||||
|
--el-input-text-color: #000;
|
||||||
--el-select-input-font-size: 1.2rem;
|
--el-select-input-font-size: 1.2rem;
|
||||||
.el-select__wrapper {
|
.el-select__wrapper {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
@@ -46,6 +53,11 @@
|
|||||||
height: 3rem;
|
height: 3rem;
|
||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
|
color: #000;
|
||||||
|
font-weight: 400;
|
||||||
|
&.is-disabled {
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,8 +199,8 @@ export class AISelectboxToolManager {
|
|||||||
if (!this.isDragging) return;
|
if (!this.isDragging) return;
|
||||||
this.isDragging = false;
|
this.isDragging = false;
|
||||||
const object = this.indicatorObject.toJSON("evented")
|
const object = this.indicatorObject.toJSON("evented")
|
||||||
// if (object.width === 0) object.width = 100
|
if (object.width === 0 || object.height === 0) return
|
||||||
// if (object.height === 0) object.height = 100
|
|
||||||
this.clearIndicatorObject()
|
this.clearIndicatorObject()
|
||||||
this.canvasManager.canvas.renderAll()
|
this.canvasManager.canvas.renderAll()
|
||||||
|
|
||||||
|
|||||||
27
src/directives/clidk-besides.js
Normal file
27
src/directives/clidk-besides.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// 点击外部区域触发事件
|
||||||
|
// 用法:v-clidk-besides="() => {}"
|
||||||
|
// 说明:点击外部区域触发事件,不包括点击元素本身
|
||||||
|
// 注意:点击元素本身或者属性bind-id相同元素不会触发事件
|
||||||
|
export default {
|
||||||
|
name: 'clidk-besides',
|
||||||
|
mounted(el, binding) {
|
||||||
|
console.log("mounted", el, binding);
|
||||||
|
const call = binding.value
|
||||||
|
const id = el.getAttribute("bind-id");
|
||||||
|
window.addEventListener("touchstart", fun, true);
|
||||||
|
window.addEventListener("mousedown", fun, true);
|
||||||
|
function fun(e) {
|
||||||
|
var k = true;
|
||||||
|
iterator(e.target);
|
||||||
|
if (k) call && call();
|
||||||
|
function iterator(el) {
|
||||||
|
if (!el || el.nodeName == "#document") return;
|
||||||
|
if (el.getAttribute("bind-id") == id) {
|
||||||
|
k = false;
|
||||||
|
} else {
|
||||||
|
iterator(el.parentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { Directive } from 'vue'
|
|
||||||
/**
|
/**
|
||||||
* 多行文本省略指令(悬浮显示完整内容)
|
* 多行文本省略指令(悬浮显示完整内容)
|
||||||
* @directive v-ellipsis
|
* @directive v-ellipsis
|
||||||
* @param {number} [value=3] - 超过value行数时显示省略号,不传参数默认为3
|
* @param {number} [value=3] - 超过value行数时显示省略号,不传参数默认为3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const applyStyles = (el: HTMLElement, binding: any) => {
|
const applyStyles = (el, binding) => {
|
||||||
const lines = typeof binding.value === 'number' && binding.value > 0 ? binding.value : 3
|
const lines = typeof binding.value === 'number' && binding.value > 0 ? binding.value : 3
|
||||||
|
|
||||||
el.style.display = '-webkit-box'
|
el.style.display = '-webkit-box'
|
||||||
@@ -16,7 +15,7 @@ const applyStyles = (el: HTMLElement, binding: any) => {
|
|||||||
el.style.maxHeight = `${lines}lh`
|
el.style.maxHeight = `${lines}lh`
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkTruncated = (el: HTMLElement) => {
|
const checkTruncated = (el) => {
|
||||||
const isTruncated = el.scrollHeight > el.clientHeight + 1
|
const isTruncated = el.scrollHeight > el.clientHeight + 1
|
||||||
if (isTruncated) {
|
if (isTruncated) {
|
||||||
el.title = el.textContent?.trim() || ''
|
el.title = el.textContent?.trim() || ''
|
||||||
@@ -25,14 +24,15 @@ const checkTruncated = (el: HTMLElement) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const vEllipsis: Directive<HTMLElement> = {
|
export default {
|
||||||
|
name: 'ellipsis',
|
||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
applyStyles(el, binding)
|
applyStyles(el, binding)
|
||||||
checkTruncated(el)
|
checkTruncated(el)
|
||||||
|
|
||||||
const ro = new ResizeObserver(() => checkTruncated(el))
|
const ro = new ResizeObserver(() => checkTruncated(el))
|
||||||
ro.observe(el)
|
ro.observe(el);
|
||||||
;(el as any)._ellipsisObserver = ro
|
el._ellipsisObserver = ro
|
||||||
},
|
},
|
||||||
|
|
||||||
updated(el, binding) {
|
updated(el, binding) {
|
||||||
@@ -41,12 +41,10 @@ const vEllipsis: Directive<HTMLElement> = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
unmounted(el) {
|
unmounted(el) {
|
||||||
const ro = (el as any)._ellipsisObserver
|
const ro = el._ellipsisObserver
|
||||||
if (ro) {
|
if (ro) {
|
||||||
ro.disconnect()
|
ro.disconnect()
|
||||||
delete (el as any)._ellipsisObserver
|
delete el._ellipsisObserver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default vEllipsis
|
|
||||||
9
src/directives/index.js
Normal file
9
src/directives/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export default {
|
||||||
|
install(app) {
|
||||||
|
const directivesList = import.meta.glob('./*.js', { eager: true });
|
||||||
|
// 遍历指令文件实现自动注册
|
||||||
|
Object.keys(directivesList).forEach(key => {
|
||||||
|
app.directive(directivesList[key].default.name, directivesList[key].default);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
16
src/directives/loadimg.js
Normal file
16
src/directives/loadimg.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// 加载图片
|
||||||
|
export default {
|
||||||
|
name: 'loadimg',
|
||||||
|
mounted(el, binding) {
|
||||||
|
const src = binding.value
|
||||||
|
if (el.src === src) return
|
||||||
|
const img = new Image()
|
||||||
|
img.src = src
|
||||||
|
img.onload = () => {
|
||||||
|
el.src = src
|
||||||
|
}
|
||||||
|
img.onerror = () => {
|
||||||
|
console.log('图片加载失败:', src)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -15,6 +15,8 @@ export default {
|
|||||||
forgotPassword: 'Forget password?',
|
forgotPassword: 'Forget password?',
|
||||||
pleaseInputName: 'Please input the name',
|
pleaseInputName: 'Please input the name',
|
||||||
nameLengthError: 'Name length must be between {min} and {max} characters',
|
nameLengthError: 'Name length must be between {min} and {max} characters',
|
||||||
|
passwordSpecial:'Must contain special characters',
|
||||||
|
passwordCase:'Mix of uppercase, lowercase and numbers',
|
||||||
pleaseInputEmail: 'Please input the email',
|
pleaseInputEmail: 'Please input the email',
|
||||||
emailFormatError: 'Please input the email again',
|
emailFormatError: 'Please input the email again',
|
||||||
pleaseInputPassword: 'Please input the password',
|
pleaseInputPassword: 'Please input the password',
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ export default {
|
|||||||
forgotPassword: '忘记密码?',
|
forgotPassword: '忘记密码?',
|
||||||
pleaseInputName: '请输入姓名',
|
pleaseInputName: '请输入姓名',
|
||||||
nameLengthError: '姓名长度必须在 {min} 到 {max} 个字符之间',
|
nameLengthError: '姓名长度必须在 {min} 到 {max} 个字符之间',
|
||||||
|
passwordSpecial:'必须包含特殊符号',
|
||||||
|
passwordCase:'大小写字母与数字混合组合',
|
||||||
pleaseInputEmail: '请输入邮箱',
|
pleaseInputEmail: '请输入邮箱',
|
||||||
emailFormatError: '请输入正确的邮箱',
|
emailFormatError: '请输入正确的邮箱',
|
||||||
pleaseInputPassword: '请输入密码',
|
pleaseInputPassword: '请输入密码',
|
||||||
|
|||||||
20
src/main.ts
20
src/main.ts
@@ -7,6 +7,7 @@ import 'normalize.css'
|
|||||||
import './assets/css/style.css'
|
import './assets/css/style.css'
|
||||||
import SvgIcon from "@/components/SvgIcon/index.vue";
|
import SvgIcon from "@/components/SvgIcon/index.vue";
|
||||||
import "virtual:svg-icons-register";
|
import "virtual:svg-icons-register";
|
||||||
|
import directives from "./directives/index.js";
|
||||||
|
|
||||||
import i18n from "./lang/index";
|
import i18n from "./lang/index";
|
||||||
import flexible from "./utils/flexible.js";
|
import flexible from "./utils/flexible.js";
|
||||||
@@ -17,32 +18,15 @@ import 'element-plus/dist/index.css'
|
|||||||
|
|
||||||
import ignoredWarning from './ignoredWarning'
|
import ignoredWarning from './ignoredWarning'
|
||||||
|
|
||||||
import vEllipsis from './utils/ellispsis'
|
|
||||||
|
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
ignoredWarning(app)
|
ignoredWarning(app)
|
||||||
app.directive('ellipsis', vEllipsis)
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
.use(directives)
|
||||||
.use(ElementPlus)
|
.use(ElementPlus)
|
||||||
.use(store)
|
.use(store)
|
||||||
.component("SvgIcon", SvgIcon)
|
.component("SvgIcon", SvgIcon)
|
||||||
.use(i18n)
|
.use(i18n)
|
||||||
.mount('#app')
|
.mount('#app')
|
||||||
|
|
||||||
const vLoadimg = (el, binding) => {
|
|
||||||
const src = binding.value
|
|
||||||
if (el.src === src) return
|
|
||||||
const img = new Image()
|
|
||||||
img.src = src
|
|
||||||
img.onload = () => {
|
|
||||||
el.src = src
|
|
||||||
}
|
|
||||||
img.onerror = () => {
|
|
||||||
console.log('图片加载失败:', src)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 注册
|
|
||||||
app.directive('loadimg', vLoadimg)
|
|
||||||
flexible();
|
flexible();
|
||||||
|
|
||||||
|
|||||||
@@ -126,8 +126,23 @@
|
|||||||
.retrieve-password > .right > .box:deep(.el-form) .el-form-item,
|
.retrieve-password > .right > .box:deep(.el-form) .el-form-item,
|
||||||
.register > .right > .box:deep(.el-form) .el-form-item,
|
.register > .right > .box:deep(.el-form) .el-form-item,
|
||||||
.login > .right > .box:deep(.el-form) .el-form-item {
|
.login > .right > .box:deep(.el-form) .el-form-item {
|
||||||
|
position: relative;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
.retrieve-password > .right > .box:deep(.el-form) .el-form-item__content,
|
||||||
|
.register > .right > .box:deep(.el-form) .el-form-item__content,
|
||||||
|
.login > .right > .box:deep(.el-form) .el-form-item__content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.retrieve-password > .right > .box:deep(.el-form) .password-tip,
|
||||||
|
.register > .right > .box:deep(.el-form) .password-tip,
|
||||||
|
.login > .right > .box:deep(.el-form) .password-tip {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
top: -1rem;
|
||||||
|
right: 0;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
.retrieve-password > .right > .box:deep(.el-form) .el-form-item__label,
|
.retrieve-password > .right > .box:deep(.el-form) .el-form-item__label,
|
||||||
.register > .right > .box:deep(.el-form) .el-form-item__label,
|
.register > .right > .box:deep(.el-form) .el-form-item__label,
|
||||||
.login > .right > .box:deep(.el-form) .el-form-item__label {
|
.login > .right > .box:deep(.el-form) .el-form-item__label {
|
||||||
|
|||||||
@@ -107,9 +107,22 @@
|
|||||||
font-family: Regular;
|
font-family: Regular;
|
||||||
|
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
|
position: relative;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-form-item__content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-tip {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
top: -1rem;
|
||||||
|
right: 0;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
.el-form-item__label {
|
.el-form-item__label {
|
||||||
color: #252727;
|
color: #252727;
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
|
|||||||
@@ -67,15 +67,17 @@
|
|||||||
import { Login } from '@/api/user'
|
import { Login } from '@/api/user'
|
||||||
import { computed, reactive, ref } from 'vue'
|
import { computed, reactive, ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { validateEmail, validatePass, validatePrivacy } from './tools'
|
import { validateEmail, validatePassLength, validatePrivacy } from './tools'
|
||||||
import OtherLogin from './other-login.vue'
|
import OtherLogin from './other-login.vue'
|
||||||
import VisibleCode from './visible-code.vue'
|
import VisibleCode from './visible-code.vue'
|
||||||
import { useUserInfoStore } from '@/stores'
|
import { useUserInfoStore } from '@/stores'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
const { t } = useI18n()
|
||||||
const userInfoStore = useUserInfoStore()
|
const userInfoStore = useUserInfoStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const ruleForm = reactive({
|
const ruleForm = reactive({
|
||||||
email: [{ validator: validateEmail, trigger: 'blur' }],
|
email: [{ validator: validateEmail, trigger: 'change' }],
|
||||||
password: [{ validator: validatePass, trigger: 'blur' }],
|
password: [{ validator: validatePassLength, trigger: 'change' }],
|
||||||
privacy: [{ validator: validatePrivacy, trigger: 'change' }]
|
privacy: [{ validator: validatePrivacy, trigger: 'change' }]
|
||||||
})
|
})
|
||||||
const isVisible = ref(false)
|
const isVisible = ref(false)
|
||||||
|
|||||||
60
src/views/login/password-tip.vue
Normal file
60
src/views/login/password-tip.vue
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="password-tip">
|
||||||
|
<div>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold v-if="validateLength(value)" />
|
||||||
|
<Select v-else />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ $t('Login.passwordLengthError', { min: 6, max: 20 }) }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold v-if="validateSpecial(value)" />
|
||||||
|
<Select v-else />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ $t('Login.passwordSpecial') }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold v-if="validateCase(value)" />
|
||||||
|
<Select v-else />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ $t('Login.passwordCase') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, reactive, ref } from 'vue'
|
||||||
|
import { Select, CloseBold } from '@element-plus/icons-vue'
|
||||||
|
import { validateLength, validateSpecial, validateCase } from './tools'
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.password-tip {
|
||||||
|
background: #404040;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 2rem;
|
||||||
|
line-height: normal;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
> .el-icon {
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -24,12 +24,15 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('Login.password')" prop="password">
|
<el-form-item :label="$t('Login.password')" prop="password">
|
||||||
|
<password-tip :value="formData.password" v-show="showPasswordTip" />
|
||||||
<el-input
|
<el-input
|
||||||
name="password"
|
name="password"
|
||||||
v-model="formData.password"
|
v-model="formData.password"
|
||||||
:placeholder="$t('Login.enterPassword')"
|
:placeholder="$t('Login.enterPassword')"
|
||||||
type="password"
|
type="password"
|
||||||
show-password
|
show-password
|
||||||
|
@blur="showPasswordTip = false"
|
||||||
|
@focus="showPasswordTip = true"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('Login.email')" prop="email">
|
<el-form-item :label="$t('Login.email')" prop="email">
|
||||||
@@ -73,16 +76,18 @@
|
|||||||
import { validateName, validateEmail, validatePass, validatePrivacy } from './tools'
|
import { validateName, validateEmail, validatePass, validatePrivacy } from './tools'
|
||||||
import OtherLogin from './other-login.vue'
|
import OtherLogin from './other-login.vue'
|
||||||
import VisibleCode from './visible-code.vue'
|
import VisibleCode from './visible-code.vue'
|
||||||
|
import PasswordTip from './password-tip.vue'
|
||||||
import { useUserInfoStore } from '@/stores'
|
import { useUserInfoStore } from '@/stores'
|
||||||
const userInfoStore = useUserInfoStore()
|
const userInfoStore = useUserInfoStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const ruleForm = reactive({
|
const ruleForm = reactive({
|
||||||
name: [{ validator: validateName, trigger: 'blur' }],
|
name: [{ validator: validateName, trigger: 'change' }],
|
||||||
email: [{ validator: validateEmail, trigger: 'blur' }],
|
email: [{ validator: validateEmail, trigger: 'change' }],
|
||||||
password: [{ validator: validatePass, trigger: 'blur' }],
|
password: [{ validator: validatePass, trigger: 'change' }],
|
||||||
privacy: [{ validator: validatePrivacy, trigger: 'change' }]
|
privacy: [{ validator: validatePrivacy, trigger: 'change' }]
|
||||||
})
|
})
|
||||||
const isVisible = ref(false)
|
const isVisible = ref(false)
|
||||||
|
const showPasswordTip = ref(false)
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
|
|||||||
@@ -23,12 +23,15 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('Login.password')" prop="password">
|
<el-form-item :label="$t('Login.password')" prop="password">
|
||||||
|
<password-tip :value="formData.password" v-show="showPasswordTip" />
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.password"
|
v-model="formData.password"
|
||||||
:placeholder="$t('Login.enterPassword')"
|
:placeholder="$t('Login.enterPassword')"
|
||||||
type="password"
|
type="password"
|
||||||
show-password
|
show-password
|
||||||
name="password"
|
name="password"
|
||||||
|
@blur="showPasswordTip = false"
|
||||||
|
@focus="showPasswordTip = true"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<br />
|
<br />
|
||||||
@@ -61,14 +64,16 @@
|
|||||||
import { validateEmail, validatePass } from './tools'
|
import { validateEmail, validatePass } from './tools'
|
||||||
import OtherLogin from './other-login.vue'
|
import OtherLogin from './other-login.vue'
|
||||||
import VisibleCode from './visible-code.vue'
|
import VisibleCode from './visible-code.vue'
|
||||||
|
import PasswordTip from './password-tip.vue'
|
||||||
import { useUserInfoStore } from '@/stores'
|
import { useUserInfoStore } from '@/stores'
|
||||||
const userInfoStore = useUserInfoStore()
|
const userInfoStore = useUserInfoStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const ruleForm = reactive({
|
const ruleForm = reactive({
|
||||||
email: [{ validator: validateEmail, trigger: 'blur' }],
|
email: [{ validator: validateEmail, trigger: 'change' }],
|
||||||
password: [{ validator: validatePass, trigger: 'blur' }]
|
password: [{ validator: validatePass, trigger: 'change' }]
|
||||||
})
|
})
|
||||||
const isVisible = ref(false)
|
const isVisible = ref(false)
|
||||||
|
const showPasswordTip = ref(false)
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
email: '',
|
email: '',
|
||||||
password: ''
|
password: ''
|
||||||
|
|||||||
@@ -19,11 +19,28 @@ export const validateEmail = (rule, value, callback) => {
|
|||||||
}
|
}
|
||||||
callback(str ? new Error(str) : undefined)
|
callback(str ? new Error(str) : undefined)
|
||||||
}
|
}
|
||||||
|
// 检查长度
|
||||||
|
export const validateLength = (v, min = 6, max = 20) => (v.length < 6 || v.length > 20);
|
||||||
|
//检查特殊字符
|
||||||
|
export const validateSpecial = (v) => (!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(v));
|
||||||
|
//检查大小写字母和数字
|
||||||
|
export const validateCase = (v) => (!/[a-z]/.test(v) || !/[A-Z]/.test(v) || !/\d/.test(v));
|
||||||
|
// 检查密码
|
||||||
export const validatePass = (rule, value, callback) => {
|
export const validatePass = (rule, value, callback) => {
|
||||||
var str = ''
|
var str = ''
|
||||||
if (!value) {
|
if (validateLength(value)) {
|
||||||
str = t('Login.pleaseInputPassword')
|
str = t('Login.passwordLengthError', { min: 6, max: 20 })
|
||||||
} else if (value.length < 6 || value.length > 20) {
|
} else if (validateSpecial(value)) {
|
||||||
|
str = t('Login.passwordSpecial')
|
||||||
|
} else if (validateCase(value)) {
|
||||||
|
str = t('Login.passwordCase')
|
||||||
|
}
|
||||||
|
callback(str ? new Error(str) : undefined)
|
||||||
|
}
|
||||||
|
// 检查密码长度
|
||||||
|
export const validatePassLength = (rule, value, callback) => {
|
||||||
|
var str = ''
|
||||||
|
if (validateLength(value)) {
|
||||||
str = t('Login.passwordLengthError', { min: 6, max: 20 })
|
str = t('Login.passwordLengthError', { min: 6, max: 20 })
|
||||||
}
|
}
|
||||||
callback(str ? new Error(str) : undefined)
|
callback(str ? new Error(str) : undefined)
|
||||||
|
|||||||
@@ -160,6 +160,8 @@
|
|||||||
color: #252727;
|
color: #252727;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
> .btns {
|
> .btns {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 8rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -305,7 +307,7 @@
|
|||||||
height: 72.6rem;
|
height: 72.6rem;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
transform: translateX(-50%) translateY(80%);
|
transform: translateX(-50%) translateY(70%);
|
||||||
> div.bg-1 {
|
> div.bg-1 {
|
||||||
width: 48.4rem;
|
width: 48.4rem;
|
||||||
height: 57.2rem;
|
height: 57.2rem;
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 1.6rem;
|
border-radius: 1.6rem;
|
||||||
|
box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
> .active {
|
> .active {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
Reference in New Issue
Block a user