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 @@
+
+
+
+
+
{{ $t('Login.resendCodeIn', { time: timeStr }) }}
+
+ {{ $t('Login.resendCode') }}
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+

+

+
{{ $t('Login.indexTip') }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+ {{ $t('Login.forgotPassword') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
{{ $t('Login.orContinueWith') }}
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+ {{ $t('Login.passwordLengthError', { min: 6, max: 20 }) }}
+
+
+
+
+
+
+ {{ $t('Login.passwordSpecial') }}
+
+
+
+
+
+
+ {{ $t('Login.passwordCase') }}
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ You must satisfy ALL password conditions to register.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+

+

+
+
+
+
+
+
+

+
+ {{ $t('Login.retrievePassword') }}
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ $t('submit')
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@