Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/FiDA_Front

This commit is contained in:
2026-03-31 15:53:10 +08:00
19 changed files with 221 additions and 45 deletions

View File

@@ -126,8 +126,23 @@
.retrieve-password > .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 {
position: relative;
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,
.register > .right > .box:deep(.el-form) .el-form-item__label,
.login > .right > .box:deep(.el-form) .el-form-item__label {

View File

@@ -107,9 +107,22 @@
font-family: Regular;
.el-form-item {
position: relative;
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 {
color: #252727;
font-size: 1.8rem;

View File

@@ -67,15 +67,17 @@
import { Login } from '@/api/user'
import { computed, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { validateEmail, validatePass, validatePrivacy } from './tools'
import { validateEmail, validatePassLength, validatePrivacy } from './tools'
import OtherLogin from './other-login.vue'
import VisibleCode from './visible-code.vue'
import { useUserInfoStore } from '@/stores'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const userInfoStore = useUserInfoStore()
const router = useRouter()
const ruleForm = reactive({
email: [{ validator: validateEmail, trigger: 'blur' }],
password: [{ validator: validatePass, trigger: 'blur' }],
email: [{ validator: validateEmail, trigger: 'change' }],
password: [{ validator: validatePassLength, trigger: 'change' }],
privacy: [{ validator: validatePrivacy, trigger: 'change' }]
})
const isVisible = ref(false)

View 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>

View File

@@ -24,12 +24,15 @@
/>
</el-form-item>
<el-form-item :label="$t('Login.password')" prop="password">
<password-tip :value="formData.password" v-show="showPasswordTip" />
<el-input
name="password"
v-model="formData.password"
:placeholder="$t('Login.enterPassword')"
type="password"
show-password
@blur="showPasswordTip = false"
@focus="showPasswordTip = true"
/>
</el-form-item>
<el-form-item :label="$t('Login.email')" prop="email">
@@ -73,16 +76,18 @@
import { validateName, validateEmail, validatePass, validatePrivacy } from './tools'
import OtherLogin from './other-login.vue'
import VisibleCode from './visible-code.vue'
import PasswordTip from './password-tip.vue'
import { useUserInfoStore } from '@/stores'
const userInfoStore = useUserInfoStore()
const router = useRouter()
const ruleForm = reactive({
name: [{ validator: validateName, trigger: 'blur' }],
email: [{ validator: validateEmail, trigger: 'blur' }],
password: [{ validator: validatePass, trigger: 'blur' }],
name: [{ validator: validateName, trigger: 'change' }],
email: [{ validator: validateEmail, trigger: 'change' }],
password: [{ validator: validatePass, trigger: 'change' }],
privacy: [{ validator: validatePrivacy, trigger: 'change' }]
})
const isVisible = ref(false)
const showPasswordTip = ref(false)
const formData = reactive({
name: '',
email: '',

View File

@@ -23,12 +23,15 @@
/>
</el-form-item>
<el-form-item :label="$t('Login.password')" prop="password">
<password-tip :value="formData.password" v-show="showPasswordTip" />
<el-input
v-model="formData.password"
:placeholder="$t('Login.enterPassword')"
type="password"
show-password
name="password"
@blur="showPasswordTip = false"
@focus="showPasswordTip = true"
/>
</el-form-item>
<br />
@@ -61,14 +64,16 @@
import { validateEmail, validatePass } from './tools'
import OtherLogin from './other-login.vue'
import VisibleCode from './visible-code.vue'
import PasswordTip from './password-tip.vue'
import { useUserInfoStore } from '@/stores'
const userInfoStore = useUserInfoStore()
const router = useRouter()
const ruleForm = reactive({
email: [{ validator: validateEmail, trigger: 'blur' }],
password: [{ validator: validatePass, trigger: 'blur' }]
email: [{ validator: validateEmail, trigger: 'change' }],
password: [{ validator: validatePass, trigger: 'change' }]
})
const isVisible = ref(false)
const showPasswordTip = ref(false)
const formData = reactive({
email: '',
password: ''

View File

@@ -19,11 +19,28 @@ export const validateEmail = (rule, value, callback) => {
}
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) => {
var str = ''
if (!value) {
str = t('Login.pleaseInputPassword')
} else if (value.length < 6 || value.length > 20) {
if (validateLength(value)) {
str = t('Login.passwordLengthError', { min: 6, max: 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 })
}
callback(str ? new Error(str) : undefined)

View File

@@ -160,6 +160,8 @@
color: #252727;
text-align: center;
> .btns {
position: fixed;
bottom: 8rem;
width: 100%;
display: flex;
align-items: center;
@@ -305,7 +307,7 @@
height: 72.6rem;
left: 50%;
bottom: 0;
transform: translateX(-50%) translateY(80%);
transform: translateX(-50%) translateY(70%);
> div.bg-1 {
width: 48.4rem;
height: 57.2rem;

View File

@@ -78,6 +78,7 @@
width: 100%;
height: 100%;
border-radius: 1.6rem;
box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.1);
}
> .active {
position: absolute;