feat: register
This commit is contained in:
parent
a51761f8f4
commit
cc909e30ff
|
@ -12,7 +12,6 @@ export interface RegisterRequestData {
|
|||
email: string
|
||||
password: string
|
||||
code: string
|
||||
ip?: string
|
||||
}
|
||||
|
||||
// 发送验证码请求数据格式
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
|
||||
// 使用全局通知
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
const info = useKUNGalgameMessageStore()
|
||||
|
||||
// 父组件让它发送验证码它再发送
|
||||
const props = defineProps(['send'])
|
||||
const props = defineProps<{
|
||||
email: string
|
||||
isSendCode: boolean
|
||||
}>()
|
||||
|
||||
const isSending = ref(false)
|
||||
|
||||
const countdown = ref(0)
|
||||
|
||||
const register = () => {
|
||||
// TODO: 发送验证码的业务代码
|
||||
|
||||
info.info(
|
||||
'验证码已发送,您可以在邮箱中查看,注意查看垃圾邮件,如果未收到邮件,您可以在 30 秒后尝试重新发送邮箱验证码'
|
||||
)
|
||||
}
|
||||
|
||||
const sendCode = () => {
|
||||
// 如果父组件传值为假直接返回
|
||||
if (!props.send) {
|
||||
if (!props.isSendCode) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -37,7 +34,12 @@ const sendCode = () => {
|
|||
}
|
||||
}, 1000)
|
||||
|
||||
register()
|
||||
// 发送验证码
|
||||
useKUNGalgameUserStore().sendCode(props.email)
|
||||
|
||||
info.info(
|
||||
'验证码已发送,您可以在邮箱中查看,注意查看垃圾邮件,如果未收到邮件,您可以在 30 秒后尝试重新发送邮箱验证码'
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -27,6 +27,7 @@ interface UserState {
|
|||
export const useKUNGalgameUserStore = defineStore({
|
||||
id: 'kungalgamer',
|
||||
persist: true,
|
||||
// TODO: token 放在 cookie 中,这里临时存放一下
|
||||
state: (): UserState => ({
|
||||
uid: 0,
|
||||
name: '',
|
||||
|
@ -68,8 +69,9 @@ export const useKUNGalgameUserStore = defineStore({
|
|||
})
|
||||
},
|
||||
// 发送验证码
|
||||
sendCode(request: VerificationCodeMailRequestData): Promise<void> {
|
||||
sendCode(email: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request: VerificationCodeMailRequestData = { email }
|
||||
sendVerificationCodeMailApi(request)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
|
|
|
@ -93,7 +93,6 @@ const handleLogin = () => {
|
|||
if (res.code === 200) {
|
||||
router.push('/')
|
||||
info.info(tm('AlertInfo.login.success'))
|
||||
} else {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -103,7 +102,7 @@ const handleLogin = () => {
|
|||
<!-- 登陆 -->
|
||||
<div class="login">
|
||||
<Capture @validate="handleVerify" :isShowValidate="isShowValidate" />
|
||||
<form class="form" @submit.prevent="handleLogin">
|
||||
<div class="form">
|
||||
<h2 class="title">{{ $tm('login.loginTitle') }}</h2>
|
||||
<input
|
||||
v-model="loginForm.name"
|
||||
|
@ -117,14 +116,18 @@ const handleLogin = () => {
|
|||
:placeholder="($tm('login.loginPassword') as string)"
|
||||
class="input"
|
||||
/>
|
||||
|
||||
<!-- 忘记密码 -->
|
||||
<span class="forget">{{ $tm('login.forget') }}</span>
|
||||
<span @click="isShowValidate = true" class="capture">{{
|
||||
$tm('login.capture')
|
||||
}}</span>
|
||||
<button class="btn" type="submit">
|
||||
|
||||
<!-- 点击登录 -->
|
||||
<button @click="handleLogin" class="btn" type="submit">
|
||||
{{ $tm('login.loginTitle') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -146,7 +149,7 @@ const handleLogin = () => {
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 0 3rem;
|
||||
padding: 0 50px;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -155,7 +158,7 @@ const handleLogin = () => {
|
|||
.title {
|
||||
font-weight: 300;
|
||||
font-weight: bold;
|
||||
margin-bottom: 1.25rem;
|
||||
margin-bottom: 20px;
|
||||
color: var(--kungalgame-font-color-2);
|
||||
}
|
||||
|
||||
|
@ -163,8 +166,8 @@ const handleLogin = () => {
|
|||
border: none;
|
||||
outline: none;
|
||||
border-bottom: 1.5px solid var(--kungalgame-blue-0);
|
||||
padding: 0.9rem 0.9rem;
|
||||
margin: 0.5rem 0;
|
||||
padding: 15px;
|
||||
margin: 7px 0;
|
||||
width: 100%;
|
||||
background-color: var(--kungalgame-white);
|
||||
color: var(--kungalgame-font-color-3);
|
||||
|
@ -190,18 +193,17 @@ const handleLogin = () => {
|
|||
|
||||
.btn {
|
||||
position: absolute;
|
||||
margin-top: 1.5rem;
|
||||
bottom: 7%;
|
||||
bottom: 10%;
|
||||
border-radius: 50px;
|
||||
background-color: var(--kungalgame-trans-white-5);
|
||||
border: 1px solid var(--kungalgame-blue-4);
|
||||
color: var(--kungalgame-blue-4);
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
letter-spacing: 0.1rem;
|
||||
padding: 0.6rem 4rem;
|
||||
font-size: 15px;
|
||||
letter-spacing: 2px;
|
||||
padding: 7px 50px;
|
||||
text-transform: uppercase;
|
||||
transition: transform 80ms ease-in;
|
||||
transition: all 0.2s;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
-->
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
// 全局消息组件(顶部)
|
||||
import message from '@/components/alert/Message'
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
|
||||
import {
|
||||
isValidEmail,
|
||||
|
@ -16,37 +16,36 @@ import {
|
|||
import Code from '@/components/verification-code/Code.vue'
|
||||
import Capture from '@/components/capture/Capture.vue'
|
||||
|
||||
const info = useKUNGalgameMessageStore()
|
||||
|
||||
const isCapturePass = ref(false)import { useI18n } from 'vue-i18n'
|
||||
const router = useRouter()
|
||||
const isShowValidate = ref(false)
|
||||
const isCaptureComplete = ref(false)
|
||||
const isSendCode = ref(false)
|
||||
|
||||
const registerForm = reactive({
|
||||
username: '',
|
||||
import { registerFormItem } from './registerForm'
|
||||
|
||||
const registerForm = reactive<Record<string, string>>({
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
code: '',
|
||||
})
|
||||
|
||||
// 人机验证
|
||||
const handleCapture = (result: boolean) => {
|
||||
const handleVerify = (result: boolean) => {
|
||||
if (result) {
|
||||
isShowValidate.value = false
|
||||
message(
|
||||
'Human-machine identity verification successful',
|
||||
'人机验证通过',
|
||||
'success'
|
||||
)
|
||||
isCapturePass.value = true
|
||||
isCaptureComplete.value = true
|
||||
} else {
|
||||
isCapturePass.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 验证表单是否为空
|
||||
const isEmptyInput = () => {
|
||||
if (!registerForm.username.trim()) {
|
||||
if (!registerForm.name.trim()) {
|
||||
message('Username cannot be empty!', '用户名不可为空!', 'warn')
|
||||
return false
|
||||
} else if (!registerForm.email.trim()) {
|
||||
|
@ -65,7 +64,7 @@ const isValidInput = (): boolean => {
|
|||
if (!isEmptyInput()) {
|
||||
return false
|
||||
}
|
||||
if (!isValidName(registerForm.username)) {
|
||||
if (!isValidName(registerForm.name)) {
|
||||
message('Invalid username format!', '非法的用户名格式!', 'warn')
|
||||
return false
|
||||
}
|
||||
|
@ -80,15 +79,22 @@ const isValidInput = (): boolean => {
|
|||
return true
|
||||
}
|
||||
|
||||
// 发送验证码
|
||||
const handleSendCode = () => {
|
||||
// 验证码为空
|
||||
// 表单为空
|
||||
if (!isValidInput()) {
|
||||
return
|
||||
}
|
||||
|
||||
// 未完成人机验证
|
||||
if (!isCaptureComplete.value) {
|
||||
// 显示人机验证
|
||||
isShowValidate.value = true
|
||||
return
|
||||
}
|
||||
|
||||
// 标志验证码已发送
|
||||
isSendCode.value = true
|
||||
}
|
||||
|
||||
const handleRegister = () => {
|
||||
|
@ -101,55 +107,70 @@ const handleRegister = () => {
|
|||
}
|
||||
|
||||
if (!isValidMailConfirmCode(registerForm.code)) {
|
||||
info.info('非法的邮箱验证码')
|
||||
message('Invalid email verification code.', '邮箱验证码错误!', 'warn')
|
||||
return
|
||||
}
|
||||
|
||||
// 执行注册逻辑,发送请求,后端校验验证码
|
||||
useKUNGalgameUserStore()
|
||||
.register({
|
||||
name: registerForm.name,
|
||||
email: registerForm.email,
|
||||
password: registerForm.password,
|
||||
code: registerForm.code,
|
||||
})
|
||||
.then((res) => {
|
||||
// 如果请求成功跳转到主页
|
||||
if (res.code === 200) {
|
||||
router.push('/')
|
||||
message('Register successfully!', '注册成功!', 'success')
|
||||
} else {
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 注册 -->
|
||||
<div class="register">
|
||||
<Capture @validate="handleCapture" :isShowValidate="isCapturePass" />
|
||||
<form action="#" class="form" @submit.prevent="handleRegister">
|
||||
<!-- 人机验证 -->
|
||||
<Capture @validate="handleVerify" :isShowValidate="isShowValidate" />
|
||||
|
||||
<!-- 注册表单 -->
|
||||
<div class="form">
|
||||
<!-- 标题 -->
|
||||
<h2 class="title">注册</h2>
|
||||
<input
|
||||
v-model="registerForm.username"
|
||||
type="text"
|
||||
placeholder="用户名"
|
||||
class="input"
|
||||
/>
|
||||
<input
|
||||
v-model="registerForm.email"
|
||||
type="email"
|
||||
placeholder="邮箱"
|
||||
class="input"
|
||||
/>
|
||||
<input
|
||||
v-model="registerForm.password"
|
||||
type="text"
|
||||
placeholder="密码"
|
||||
class="input"
|
||||
/>
|
||||
<input
|
||||
v-model="registerForm.code"
|
||||
type="text"
|
||||
placeholder="邮箱验证码"
|
||||
class="input"
|
||||
/>
|
||||
<div @click="handleSendCode" class="mail-confirm">
|
||||
<Code :send="isSendCode" />
|
||||
|
||||
<div class="container" v-for="item in registerFormItem" :key="item.index">
|
||||
<input
|
||||
v-model="registerForm[item.value]"
|
||||
:type="item.type"
|
||||
:placeholder="item.placeholder"
|
||||
:class="item.class"
|
||||
/>
|
||||
</div>
|
||||
<button class="btn" type="submit">注册</button>
|
||||
|
||||
<Code
|
||||
@click="handleSendCode"
|
||||
class="code"
|
||||
:email="registerForm.email"
|
||||
:isSendCode="isSendCode"
|
||||
/>
|
||||
|
||||
<!-- 注册按钮 -->
|
||||
<button @click="handleRegister" class="btn" type="submit">注册</button>
|
||||
|
||||
<!-- 用户协议提示等 -->
|
||||
<span class="user-agreement">
|
||||
点击注册表示您已经同意我们的
|
||||
<router-link to="/licence"><span>用户协议</span></router-link>
|
||||
和
|
||||
<router-link to="/privacy"><span>隐私政策</span></router-link>
|
||||
</span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -168,10 +189,15 @@ const handleRegister = () => {
|
|||
.title {
|
||||
font-weight: 300;
|
||||
font-weight: bold;
|
||||
margin-bottom: 1.25rem;
|
||||
margin-bottom: 20px;
|
||||
color: var(--kungalgame-font-color-2);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 表单的设置 */
|
||||
.form {
|
||||
background-color: var(--kungalgame-white);
|
||||
|
@ -179,17 +205,17 @@ const handleRegister = () => {
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 0 3rem;
|
||||
padding: 0 50px;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// 输入框
|
||||
.input {
|
||||
border: none;
|
||||
outline: none;
|
||||
border-bottom: 1.5px solid var(--kungalgame-blue-0);
|
||||
padding: 0.9rem 0.9rem;
|
||||
margin: 0.5rem 0;
|
||||
padding: 15px;
|
||||
margin: 7px 0;
|
||||
width: 100%;
|
||||
background-color: var(--kungalgame-white);
|
||||
color: var(--kungalgame-font-color-3);
|
||||
|
@ -199,55 +225,48 @@ const handleRegister = () => {
|
|||
transition: 0.2s linear;
|
||||
}
|
||||
|
||||
.mail-confirm {
|
||||
.code {
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
height: 30px;
|
||||
bottom: 24%;
|
||||
right: 15%;
|
||||
}
|
||||
.mail-confirm:hover {
|
||||
color: var(--kungalgame-blue-4);
|
||||
bottom: 120px;
|
||||
right: 50px;
|
||||
}
|
||||
|
||||
/* 用户协议 */
|
||||
.user-agreement {
|
||||
position: absolute;
|
||||
bottom: 2%;
|
||||
bottom: 3%;
|
||||
font-size: x-small;
|
||||
color: var(--kungalgame-font-color-1);
|
||||
text-decoration: none;
|
||||
}
|
||||
.user-agreement span {
|
||||
color: var(--kungalgame-red-4);
|
||||
font-style: oblique;
|
||||
span {
|
||||
color: var(--kungalgame-red-4);
|
||||
font-style: oblique;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: absolute;
|
||||
bottom: 7%;
|
||||
bottom: 10%;
|
||||
border-radius: 50px;
|
||||
background-color: var(--kungalgame-trans-white-5);
|
||||
border: 1px solid var(--kungalgame-blue-4);
|
||||
color: var(--kungalgame-blue-4);
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
letter-spacing: 0.1rem;
|
||||
padding: 0.6rem 4rem;
|
||||
font-size: 15px;
|
||||
letter-spacing: 2px;
|
||||
padding: 7px 50px;
|
||||
text-transform: uppercase;
|
||||
transition: transform 80ms ease-in;
|
||||
transition: all 0.2s;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.btn:hover {
|
||||
background-color: var(--kungalgame-blue-4);
|
||||
color: var(--kungalgame-white);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.btn:focus {
|
||||
outline: none;
|
||||
&:hover {
|
||||
background-color: var(--kungalgame-blue-4);
|
||||
color: var(--kungalgame-white);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
38
src/views/login/components/registerForm.ts
Normal file
38
src/views/login/components/registerForm.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
interface RegisterFormItem {
|
||||
index: number
|
||||
value: string
|
||||
type: string
|
||||
placeholder: string
|
||||
class: string
|
||||
}
|
||||
|
||||
export const registerFormItem: RegisterFormItem[] = [
|
||||
{
|
||||
index: 1,
|
||||
value: 'name',
|
||||
type: 'text',
|
||||
placeholder: '用户名',
|
||||
class: 'input',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
value: 'email',
|
||||
type: 'email',
|
||||
placeholder: '邮箱',
|
||||
class: 'input',
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
value: 'password',
|
||||
type: 'text',
|
||||
placeholder: '密码',
|
||||
class: 'input',
|
||||
},
|
||||
{
|
||||
index: 4,
|
||||
value: 'code',
|
||||
type: 'text',
|
||||
placeholder: '邮箱验证码',
|
||||
class: 'input',
|
||||
},
|
||||
]
|
|
@ -9,7 +9,7 @@ import 'dayjs/locale/en' // 导入英文语言包
|
|||
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const { time } = defineProps<{
|
||||
const props = defineProps<{
|
||||
time?: number
|
||||
}>()
|
||||
|
||||
|
@ -19,8 +19,8 @@ const { showKUNGalgameLanguage } = storeToRefs(settingsStore)
|
|||
|
||||
// 设置使用英文语言
|
||||
dayjs.locale('en')
|
||||
const formattedCNDate = dayjs(time).format('YYYY年MM月DD日-HH:mm:ss 发布')
|
||||
const formattedENDate = dayjs(time).format('MMMM D, YYYY - h:mm:ss A')
|
||||
const formattedCNDate = dayjs(props.time).format('YYYY年MM月DD日-HH:mm:ss 发布')
|
||||
const formattedENDate = dayjs(props.time).format('MMMM D, YYYY - h:mm:ss A')
|
||||
|
||||
const loliTime = computed(() => {
|
||||
if (showKUNGalgameLanguage.value === 'en') {
|
||||
|
|
|
@ -15,7 +15,7 @@ import { storeToRefs } from 'pinia'
|
|||
const { name, uid } = storeToRefs(useKUNGalgameUserStore())
|
||||
|
||||
// 定于父组件 props
|
||||
const { tid, rid, to_user } = defineProps<{
|
||||
const props = defineProps<{
|
||||
tid: number
|
||||
rid: number
|
||||
to_user: {
|
||||
|
@ -48,10 +48,10 @@ const handleInputComment = () => {
|
|||
|
||||
// 保存评论信息
|
||||
const saveComment = () => {
|
||||
commentDraft.value.tid = tid
|
||||
commentDraft.value.rid = rid
|
||||
commentDraft.value.tid = props.tid
|
||||
commentDraft.value.rid = props.rid
|
||||
commentDraft.value.c_uid = uid.value
|
||||
commentDraft.value.to_uid = to_user.uid
|
||||
commentDraft.value.to_uid = props.to_user.uid
|
||||
commentDraft.value.content = commentValue.value
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
|||
import { storeToRefs } from 'pinia'
|
||||
const { commentDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
const { tid, rid, toUser } = defineProps<{
|
||||
const props = defineProps<{
|
||||
tid: number
|
||||
rid: number
|
||||
toUser: {
|
||||
|
@ -41,10 +41,10 @@ const getCommentEmits = (newComment: TopicComment) => {
|
|||
|
||||
onMounted(async () => {
|
||||
// 将用户信息给回复面板
|
||||
toUserInfo.name = toUser.name
|
||||
toUserInfo.uid = toUser.uid
|
||||
toUserInfo.name = props.toUser.name
|
||||
toUserInfo.uid = props.toUser.uid
|
||||
|
||||
commentsData.value = await getComments(tid, rid)
|
||||
commentsData.value = await getComments(props.tid, props.rid)
|
||||
})
|
||||
|
||||
// 点击回复
|
||||
|
@ -54,7 +54,7 @@ const handleClickReply = (uid: number, name: string) => {
|
|||
toUserInfo.uid = uid
|
||||
|
||||
// 打开回复面板
|
||||
commentDraft.value.isShowCommentPanelRid = rid
|
||||
commentDraft.value.isShowCommentPanelRid = props.rid
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
Loading…
Reference in a new issue