From 9cd63c90c91b1d76afdd3900de44de395f1b7814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E9=B9=8F?= <2916022834@qq.com> Date: Tue, 21 Apr 2026 15:57:59 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 4 +- src/assets/icons/back.svg | 3 + src/assets/icons/close.svg | 3 + src/assets/icons/logout.svg | 4 + src/assets/icons/my_wardrobe.svg | 3 + src/assets/icons/notifications.svg | 9 + src/assets/icons/settings.svg | 9 + src/assets/icons/warning.svg | 5 + src/assets/images/login/bg.jpg | Bin 0 -> 1077326 bytes src/assets/images/login/google.png | Bin 0 -> 1474 bytes src/assets/images/login/wechat.png | Bin 0 -> 2059 bytes src/assets/images/profile-content-bg.jpg | Bin 0 -> 32209 bytes src/components/input-code.vue | 109 +++++++++++ src/lang/en.ts | 37 +++- src/lang/zh-cn.ts | 38 +++- src/utils/tools.ts | 13 +- src/views/login/css/style.css | 130 +++++++++++++ src/views/login/email-verify.vue | 143 +++++++++++++++ src/views/login/index.vue | 117 ++++++++++++ src/views/login/less/style.less | 120 ++++++++++++ src/views/login/login-dialog.vue | 224 +++++++++++++++++++++++ src/views/login/login.vue | 75 ++++++++ src/views/login/other-login.vue | 83 +++++++++ src/views/login/password-tip.vue | 60 ++++++ src/views/login/register.vue | 85 +++++++++ src/views/login/retrieve-password.vue | 120 ++++++++++++ src/views/login/tools.js | 54 ++++++ src/views/main-header.vue | 126 ++++++++++++- 28 files changed, 1568 insertions(+), 6 deletions(-) create mode 100644 src/assets/icons/back.svg create mode 100644 src/assets/icons/close.svg create mode 100644 src/assets/icons/logout.svg create mode 100644 src/assets/icons/my_wardrobe.svg create mode 100644 src/assets/icons/notifications.svg create mode 100644 src/assets/icons/settings.svg create mode 100644 src/assets/icons/warning.svg create mode 100644 src/assets/images/login/bg.jpg create mode 100644 src/assets/images/login/google.png create mode 100644 src/assets/images/login/wechat.png create mode 100644 src/assets/images/profile-content-bg.jpg create mode 100644 src/components/input-code.vue create mode 100644 src/views/login/css/style.css create mode 100644 src/views/login/email-verify.vue create mode 100644 src/views/login/index.vue create mode 100644 src/views/login/less/style.less create mode 100644 src/views/login/login-dialog.vue create mode 100644 src/views/login/login.vue create mode 100644 src/views/login/other-login.vue create mode 100644 src/views/login/password-tip.vue create mode 100644 src/views/login/register.vue create mode 100644 src/views/login/retrieve-password.vue create mode 100644 src/views/login/tools.js diff --git a/src/App.vue b/src/App.vue index 4dcaae4..ffa4d86 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,13 +1,15 @@ + + diff --git a/src/lang/en.ts b/src/lang/en.ts index a0b49e0..42fe27c 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -2,5 +2,40 @@ export default { Login: { login: 'Log in', register: 'Register', - } + loginTo: 'Log on to FiDA', + loginTitle: 'A multi-agent canvas for rapid, trend driven design iteration.', + name: 'Name', + email: 'Email', + password: 'Password', + enterName: 'Enter your name', + enterEmail: 'Enter your email', + enterPassword: 'Enter your password', + forgotPassword: 'Forget password?', + pleaseInputName: 'Please input the name', + 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', + emailFormatError: 'Please input the email again', + pleaseInputPassword: 'Please input the password', + passwordLengthError: 'Password length must be between {min} and {max} characters', + pleaseTermsPolicy: 'Please agree to the Terms, Policy and Fees', + agreeTermsPolicy: + 'I agree to the Terms, Policy and Fees.', + noAccountToSignUp: `Don't have an account? Sign up`, + signUpFor: 'Sign up for FiDA', + registerTip: 'A multi-agent canvas for rapid, trend driven design iteration.', + havenAccountToLogin: `Already have an account? Log in`, + verifyEmail: 'Verify your email address', + verifyCodeHasSent: 'A verification code has been sent to
{email}', + verify: 'Verify', + resendCode: 'Resend Code', + resendCodeIn: 'Resend Code in {time}', + orContinueWith: 'or continue with', + googleLogin: 'Sign in with Google', + wechatLogin: 'Sign in with Wechat', + indexTip: 'A multi-agent canvas for rapid, trend driven design iteration.', + sendCodeError: 'Send code error', + retrievePassword: 'Retrieve password' + }, } diff --git a/src/lang/zh-cn.ts b/src/lang/zh-cn.ts index a3dc01a..1afe79a 100644 --- a/src/lang/zh-cn.ts +++ b/src/lang/zh-cn.ts @@ -2,5 +2,41 @@ export default { Login: { login: '登录', register: '注册', - } + signUp: '注册', + loginTo: '登录到 FiDA条款、政策 和费用。', + noAccountToSignUp: `还没有账号? 注册`, + signUpFor: '注册账号', + registerTip: '一个多智能体画布,用于快速、趋势驱动的设计迭代。', + havenAccountToLogin: `已经有账号? 登录`, + verifyEmail: '验证您的邮箱地址', + verifyCodeHasSent: '已发送验证码到
{email}', + verifyCode: '请输入验证码', + verify: '验证', + resendCode: '重新发送验证码', + resendCodeIn: '重新发送验证码倒计时 {time}', + orContinueWith: '或者使用', + googleLogin: '使用 Google 登录', + wechatLogin: '使用微信登录', + indexTip: '一个多智能体画布,用于快速、趋势驱动的设计迭代。', + sendCodeError: '发送验证码失败', + retrievePassword: '找回密码' + }, } diff --git a/src/utils/tools.ts b/src/utils/tools.ts index eac100e..69403ed 100644 --- a/src/utils/tools.ts +++ b/src/utils/tools.ts @@ -183,4 +183,15 @@ export async function shareImageToWhatsapp (url: string){ const whatsappLink = `https://api.whatsapp.com/send/?text=${encodeURIComponent(message)}` window.open(whatsappLink, '_blank') } -} \ No newline at end of file +} + +/** + * 倒计时 + * @param time 倒计时时间,单位秒 + * @returns 倒计时字符串,格式为 mm:ss +*/ +export function CountDown(time: number) { + const mm = String(Math.floor(time / 60)).padStart(2, '0'); + const ss = String(time % 60).padStart(2, '0'); + return `${mm}:${ss}`; +} diff --git a/src/views/login/css/style.css b/src/views/login/css/style.css new file mode 100644 index 0000000..d2a446c --- /dev/null +++ b/src/views/login/css/style.css @@ -0,0 +1,130 @@ +.retrieve-password, +.register, +.login { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + margin-top: 2rem; +} +.retrieve-password:deep(.el-form), +.register:deep(.el-form), +.login:deep(.el-form) { + width: 100%; +} +.retrieve-password:deep(.el-form) .el-form-item, +.register:deep(.el-form) .el-form-item, +.login:deep(.el-form) .el-form-item { + position: relative; + margin-bottom: 1.6rem; +} +.retrieve-password:deep(.el-form) .el-form-item__content, +.register:deep(.el-form) .el-form-item__content, +.login:deep(.el-form) .el-form-item__content { + position: relative; +} +.retrieve-password:deep(.el-form) .el-form-item__label, +.register:deep(.el-form) .el-form-item__label, +.login:deep(.el-form) .el-form-item__label { + color: #232323; + font-size: 1.2rem; + margin-bottom: 0.8rem; + line-height: 1.5rem; +} +.retrieve-password:deep(.el-form) .el-input, +.register:deep(.el-form) .el-input, +.login:deep(.el-form) .el-input { + --el-input-height: 3.4rem; + --el-input-border-radius: 0; + --el-input-text-color: #232323; + --el-border-color: #C4C4C4; + font-size: 1.4rem; +} +.retrieve-password:deep(.el-form) .el-input::placeholder, +.register:deep(.el-form) .el-input::placeholder, +.login:deep(.el-form) .el-input::placeholder { + color: #9F9F9F; +} +.retrieve-password:deep(.el-form) .password-tip, +.register:deep(.el-form) .password-tip, +.login:deep(.el-form) .password-tip { + position: absolute; + z-index: 10; + top: -1rem; + right: 0; + transform: translateY(-100%); +} +.retrieve-password:deep(.el-form) .password-warning, +.register:deep(.el-form) .password-warning, +.login:deep(.el-form) .password-warning { + --el-checkbox-height: auto; + margin-top: -0.6rem; + margin-bottom: 1.6rem; + display: flex; + align-items: center; +} +.retrieve-password:deep(.el-form) .password-warning > .icon, +.register:deep(.el-form) .password-warning > .icon, +.login:deep(.el-form) .password-warning > .icon { + width: 1.4rem; + height: 1.4rem; + margin-right: 0.8rem; +} +.retrieve-password:deep(.el-form) .password-warning > .label, +.register:deep(.el-form) .password-warning > .label, +.login:deep(.el-form) .password-warning > .label { + font-family: KaiseiOpti-Regular; + font-size: 1rem; + color: #9F9F9F; +} +.retrieve-password:deep(.el-form) .forgotPassword, +.register:deep(.el-form) .forgotPassword, +.login:deep(.el-form) .forgotPassword { + margin-top: -0.8rem; + margin-bottom: 5rem; + font-size: 1.1rem; + text-align: right; + color: #666666; + cursor: pointer; + text-decoration: underline; + font-family: KaiseiOpti-Regular; +} +.retrieve-password:deep(.el-form) .el-form-item__error, +.register:deep(.el-form) .el-form-item__error, +.login:deep(.el-form) .el-form-item__error { + padding-top: 1px; + font-size: 1rem; +} +.retrieve-password:deep(.el-form) .submit, +.register:deep(.el-form) .submit, +.login:deep(.el-form) .submit { + width: 100%; + height: 4rem; + font-size: 1.36rem; +} +.retrieve-password:deep(.el-form) .privacy, +.register:deep(.el-form) .privacy, +.login:deep(.el-form) .privacy { + margin-top: -0.6rem; + --el-checkbox-height: auto; +} +.retrieve-password:deep(.el-form) .privacy .el-checkbox__label, +.register:deep(.el-form) .privacy .el-checkbox__label, +.login:deep(.el-form) .privacy .el-checkbox__label { + font-size: 1.1rem; + color: #666666; + font-family: KaiseiOpti-Regular; +} +.retrieve-password:deep(.el-form) .privacy .el-checkbox__label > div > span, +.register:deep(.el-form) .privacy .el-checkbox__label > div > span, +.login:deep(.el-form) .privacy .el-checkbox__label > div > span { + font-family: KaiseiOpti-Bold; + text-decoration: underline; + cursor: pointer; + color: #232323; +} +.retrieve-password > .other-login, +.register > .other-login, +.login > .other-login { + margin-top: 4rem; +} diff --git a/src/views/login/email-verify.vue b/src/views/login/email-verify.vue new file mode 100644 index 0000000..e402574 --- /dev/null +++ b/src/views/login/email-verify.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 0000000..b6df949 --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/src/views/login/less/style.less b/src/views/login/less/style.less new file mode 100644 index 0000000..bac666c --- /dev/null +++ b/src/views/login/less/style.less @@ -0,0 +1,120 @@ +.retrieve-password, +.register, +.login { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + margin-top: 2rem; + + &:deep(.el-form) { + width: 100%; + + .el-form-item { + position: relative; + margin-bottom: 1.6rem; + } + + .el-form-item__content { + position: relative; + } + + + .el-form-item__label { + color: #232323; + font-size: 1.2rem; + margin-bottom: 0.8rem; + line-height: 1.5rem; + } + + .el-input { + --el-input-height: 3.4rem; + --el-input-border-radius: 0; + --el-input-text-color: #232323; + --el-border-color: #C4C4C4; + font-size: 1.4rem; + + &::placeholder { + color: #9F9F9F; + } + } + + .password-tip { + position: absolute; + z-index: 10; + top: -1rem; + right: 0; + transform: translateY(-100%); + } + + .password-warning { + --el-checkbox-height: auto; + margin-top: -0.6rem; + margin-bottom: 1.6rem; + display: flex; + align-items: center; + + >.icon { + width: 1.4rem; + height: 1.4rem; + margin-right: 0.8rem; + } + + >.label { + font-family: KaiseiOpti-Regular; + font-size: 1rem; + color: #9F9F9F; + } + } + + .forgotPassword { + margin-top: -0.8rem; + margin-bottom: 5rem; + font-size: 1.1rem; + text-align: right; + color: #666666; + cursor: pointer; + text-decoration: underline; + font-family: KaiseiOpti-Regular; + } + + + .el-form-item__error { + padding-top: 1px; + font-size: 1rem; + } + + + .submit { + width: 100%; + height: 4rem; + font-size: 1.36rem; + } + + .privacy { + margin-top: -0.6rem; + --el-checkbox-height: auto; + + .el-checkbox__label { + font-size: 1.1rem; + color: #666666; + font-family: KaiseiOpti-Regular; + + >div { + >span { + font-family: KaiseiOpti-Bold; + text-decoration: underline; + cursor: pointer; + color: #232323; + } + } + } + } + + } + + >.other-login { + margin-top: 4rem; + } + +} \ No newline at end of file diff --git a/src/views/login/login-dialog.vue b/src/views/login/login-dialog.vue new file mode 100644 index 0000000..6bafe45 --- /dev/null +++ b/src/views/login/login-dialog.vue @@ -0,0 +1,224 @@ + + + + + diff --git a/src/views/login/login.vue b/src/views/login/login.vue new file mode 100644 index 0000000..87f251e --- /dev/null +++ b/src/views/login/login.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/views/login/other-login.vue b/src/views/login/other-login.vue new file mode 100644 index 0000000..b9d795c --- /dev/null +++ b/src/views/login/other-login.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/src/views/login/password-tip.vue b/src/views/login/password-tip.vue new file mode 100644 index 0000000..0ca3f14 --- /dev/null +++ b/src/views/login/password-tip.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/src/views/login/register.vue b/src/views/login/register.vue new file mode 100644 index 0000000..4f0dabe --- /dev/null +++ b/src/views/login/register.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/src/views/login/retrieve-password.vue b/src/views/login/retrieve-password.vue new file mode 100644 index 0000000..1f65234 --- /dev/null +++ b/src/views/login/retrieve-password.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/src/views/login/tools.js b/src/views/login/tools.js new file mode 100644 index 0000000..b89ba0d --- /dev/null +++ b/src/views/login/tools.js @@ -0,0 +1,54 @@ +import i18n from '@/lang' +const t = i18n.global.t +export const validateName = (rule, value, callback) => { + var str = "" + if (!value) { + str = t('Login.pleaseInputName') + } else if (value.length < 2 || value.length > 20) { + str = t('Login.nameLengthError', { min: 2, max: 20 }) + } + callback(str ? new Error(str) : undefined) +} +export const validateEmail = (rule, value, callback) => { + const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?$/ + var str = '' + if (!value) { + str = t('Login.pleaseInputEmail') + } else if (!emailRegex.test(value)) { + str = t('Login.emailFormatError') + } + 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 (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) +} +export const validatePrivacy = (rule, value, callback) => { + if (!value) { + callback(new Error(t('Login.pleaseTermsPolicy'))) + } else { + callback() + } +} \ No newline at end of file diff --git a/src/views/main-header.vue b/src/views/main-header.vue index f8c15d5..70880bd 100644 --- a/src/views/main-header.vue +++ b/src/views/main-header.vue @@ -24,8 +24,44 @@ > -
Login
-
+
Login
+ + + + @@ -33,6 +69,7 @@