feat: register

This commit is contained in:
KUN1007 2023-09-22 00:54:05 +08:00
parent a51761f8f4
commit cc909e30ff
9 changed files with 180 additions and 118 deletions

View file

@ -12,7 +12,6 @@ export interface RegisterRequestData {
email: string email: string
password: string password: string
code: string code: string
ip?: string
} }
// 发送验证码请求数据格式 // 发送验证码请求数据格式

View file

@ -1,27 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
// 使 // 使
import { useKUNGalgameMessageStore } from '@/store/modules/message' import { useKUNGalgameMessageStore } from '@/store/modules/message'
const info = useKUNGalgameMessageStore() const info = useKUNGalgameMessageStore()
// //
const props = defineProps(['send']) const props = defineProps<{
email: string
isSendCode: boolean
}>()
const isSending = ref(false) const isSending = ref(false)
const countdown = ref(0) const countdown = ref(0)
const register = () => {
// TODO:
info.info(
'验证码已发送,您可以在邮箱中查看,注意查看垃圾邮件,如果未收到邮件,您可以在 30 秒后尝试重新发送邮箱验证码'
)
}
const sendCode = () => { const sendCode = () => {
// //
if (!props.send) { if (!props.isSendCode) {
return return
} }
@ -37,7 +34,12 @@ const sendCode = () => {
} }
}, 1000) }, 1000)
register() //
useKUNGalgameUserStore().sendCode(props.email)
info.info(
'验证码已发送,您可以在邮箱中查看,注意查看垃圾邮件,如果未收到邮件,您可以在 30 秒后尝试重新发送邮箱验证码'
)
} }
} }
</script> </script>

View file

@ -27,6 +27,7 @@ interface UserState {
export const useKUNGalgameUserStore = defineStore({ export const useKUNGalgameUserStore = defineStore({
id: 'kungalgamer', id: 'kungalgamer',
persist: true, persist: true,
// TODO: token 放在 cookie 中,这里临时存放一下
state: (): UserState => ({ state: (): UserState => ({
uid: 0, uid: 0,
name: '', name: '',
@ -68,8 +69,9 @@ export const useKUNGalgameUserStore = defineStore({
}) })
}, },
// 发送验证码 // 发送验证码
sendCode(request: VerificationCodeMailRequestData): Promise<void> { sendCode(email: string): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const request: VerificationCodeMailRequestData = { email }
sendVerificationCodeMailApi(request) sendVerificationCodeMailApi(request)
.then((res) => { .then((res) => {
resolve(res) resolve(res)

View file

@ -93,7 +93,6 @@ const handleLogin = () => {
if (res.code === 200) { if (res.code === 200) {
router.push('/') router.push('/')
info.info(tm('AlertInfo.login.success')) info.info(tm('AlertInfo.login.success'))
} else {
} }
}) })
} }
@ -103,7 +102,7 @@ const handleLogin = () => {
<!-- 登陆 --> <!-- 登陆 -->
<div class="login"> <div class="login">
<Capture @validate="handleVerify" :isShowValidate="isShowValidate" /> <Capture @validate="handleVerify" :isShowValidate="isShowValidate" />
<form class="form" @submit.prevent="handleLogin"> <div class="form">
<h2 class="title">{{ $tm('login.loginTitle') }}</h2> <h2 class="title">{{ $tm('login.loginTitle') }}</h2>
<input <input
v-model="loginForm.name" v-model="loginForm.name"
@ -117,14 +116,18 @@ const handleLogin = () => {
:placeholder="($tm('login.loginPassword') as string)" :placeholder="($tm('login.loginPassword') as string)"
class="input" class="input"
/> />
<!-- 忘记密码 -->
<span class="forget">{{ $tm('login.forget') }}</span> <span class="forget">{{ $tm('login.forget') }}</span>
<span @click="isShowValidate = true" class="capture">{{ <span @click="isShowValidate = true" class="capture">{{
$tm('login.capture') $tm('login.capture')
}}</span> }}</span>
<button class="btn" type="submit">
<!-- 点击登录 -->
<button @click="handleLogin" class="btn" type="submit">
{{ $tm('login.loginTitle') }} {{ $tm('login.loginTitle') }}
</button> </button>
</form> </div>
</div> </div>
</template> </template>
@ -146,7 +149,7 @@ const handleLogin = () => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
padding: 0 3rem; padding: 0 50px;
height: 100%; height: 100%;
text-align: center; text-align: center;
} }
@ -155,7 +158,7 @@ const handleLogin = () => {
.title { .title {
font-weight: 300; font-weight: 300;
font-weight: bold; font-weight: bold;
margin-bottom: 1.25rem; margin-bottom: 20px;
color: var(--kungalgame-font-color-2); color: var(--kungalgame-font-color-2);
} }
@ -163,8 +166,8 @@ const handleLogin = () => {
border: none; border: none;
outline: none; outline: none;
border-bottom: 1.5px solid var(--kungalgame-blue-0); border-bottom: 1.5px solid var(--kungalgame-blue-0);
padding: 0.9rem 0.9rem; padding: 15px;
margin: 0.5rem 0; margin: 7px 0;
width: 100%; width: 100%;
background-color: var(--kungalgame-white); background-color: var(--kungalgame-white);
color: var(--kungalgame-font-color-3); color: var(--kungalgame-font-color-3);
@ -190,18 +193,17 @@ const handleLogin = () => {
.btn { .btn {
position: absolute; position: absolute;
margin-top: 1.5rem; bottom: 10%;
bottom: 7%;
border-radius: 50px; border-radius: 50px;
background-color: var(--kungalgame-trans-white-5); background-color: var(--kungalgame-trans-white-5);
border: 1px solid var(--kungalgame-blue-4); border: 1px solid var(--kungalgame-blue-4);
color: var(--kungalgame-blue-4); color: var(--kungalgame-blue-4);
cursor: pointer; cursor: pointer;
font-size: 0.9em; font-size: 15px;
letter-spacing: 0.1rem; letter-spacing: 2px;
padding: 0.6rem 4rem; padding: 7px 50px;
text-transform: uppercase; text-transform: uppercase;
transition: transform 80ms ease-in; transition: all 0.2s;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
} }

View file

@ -3,9 +3,9 @@
--> -->
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
// //
import message from '@/components/alert/Message' import message from '@/components/alert/Message'
import { useKUNGalgameMessageStore } from '@/store/modules/message'
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer' import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
import { import {
isValidEmail, isValidEmail,
@ -16,37 +16,36 @@ import {
import Code from '@/components/verification-code/Code.vue' import Code from '@/components/verification-code/Code.vue'
import Capture from '@/components/capture/Capture.vue' import Capture from '@/components/capture/Capture.vue'
const info = useKUNGalgameMessageStore() const router = useRouter()
const isShowValidate = ref(false)
const isCapturePass = ref(false)import { useI18n } from 'vue-i18n'
const isCaptureComplete = ref(false) const isCaptureComplete = ref(false)
const isSendCode = ref(false) const isSendCode = ref(false)
const registerForm = reactive({ import { registerFormItem } from './registerForm'
username: '',
const registerForm = reactive<Record<string, string>>({
name: '',
email: '', email: '',
password: '', password: '',
code: '', code: '',
}) })
// //
const handleCapture = (result: boolean) => { const handleVerify = (result: boolean) => {
if (result) { if (result) {
isShowValidate.value = false
message( message(
'Human-machine identity verification successful', 'Human-machine identity verification successful',
'人机验证通过', '人机验证通过',
'success' 'success'
) )
isCapturePass.value = true
isCaptureComplete.value = true isCaptureComplete.value = true
} else {
isCapturePass.value = false
} }
} }
// //
const isEmptyInput = () => { const isEmptyInput = () => {
if (!registerForm.username.trim()) { if (!registerForm.name.trim()) {
message('Username cannot be empty!', '用户名不可为空!', 'warn') message('Username cannot be empty!', '用户名不可为空!', 'warn')
return false return false
} else if (!registerForm.email.trim()) { } else if (!registerForm.email.trim()) {
@ -65,7 +64,7 @@ const isValidInput = (): boolean => {
if (!isEmptyInput()) { if (!isEmptyInput()) {
return false return false
} }
if (!isValidName(registerForm.username)) { if (!isValidName(registerForm.name)) {
message('Invalid username format!', '非法的用户名格式!', 'warn') message('Invalid username format!', '非法的用户名格式!', 'warn')
return false return false
} }
@ -80,15 +79,22 @@ const isValidInput = (): boolean => {
return true return true
} }
//
const handleSendCode = () => { const handleSendCode = () => {
// //
if (!isValidInput()) { if (!isValidInput()) {
return return
} }
//
if (!isCaptureComplete.value) { if (!isCaptureComplete.value) {
//
isShowValidate.value = true
return return
} }
//
isSendCode.value = true
} }
const handleRegister = () => { const handleRegister = () => {
@ -101,55 +107,70 @@ const handleRegister = () => {
} }
if (!isValidMailConfirmCode(registerForm.code)) { if (!isValidMailConfirmCode(registerForm.code)) {
info.info('非法的邮箱验证码') message('Invalid email verification code.', '邮箱验证码错误!', 'warn')
return 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> </script>
<template> <template>
<!-- 注册 --> <!-- 注册 -->
<div class="register"> <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> <h2 class="title">注册</h2>
<div class="container" v-for="item in registerFormItem" :key="item.index">
<input <input
v-model="registerForm.username" v-model="registerForm[item.value]"
type="text" :type="item.type"
placeholder="用户名" :placeholder="item.placeholder"
class="input" :class="item.class"
/> />
<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> </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"> <span class="user-agreement">
点击注册表示您已经同意我们的 点击注册表示您已经同意我们的
<router-link to="/licence"><span>用户协议</span></router-link> <router-link to="/licence"><span>用户协议</span></router-link>
<router-link to="/privacy"><span>隐私政策</span></router-link> <router-link to="/privacy"><span>隐私政策</span></router-link>
</span> </span>
</form> </div>
</div> </div>
</template> </template>
@ -168,10 +189,15 @@ const handleRegister = () => {
.title { .title {
font-weight: 300; font-weight: 300;
font-weight: bold; font-weight: bold;
margin-bottom: 1.25rem; margin-bottom: 20px;
color: var(--kungalgame-font-color-2); color: var(--kungalgame-font-color-2);
} }
.container {
width: 100%;
position: relative;
}
/* 表单的设置 */ /* 表单的设置 */
.form { .form {
background-color: var(--kungalgame-white); background-color: var(--kungalgame-white);
@ -179,17 +205,17 @@ const handleRegister = () => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
padding: 0 3rem; padding: 0 50px;
height: 100%; height: 100%;
text-align: center;
} }
//
.input { .input {
border: none; border: none;
outline: none; outline: none;
border-bottom: 1.5px solid var(--kungalgame-blue-0); border-bottom: 1.5px solid var(--kungalgame-blue-0);
padding: 0.9rem 0.9rem; padding: 15px;
margin: 0.5rem 0; margin: 7px 0;
width: 100%; width: 100%;
background-color: var(--kungalgame-white); background-color: var(--kungalgame-white);
color: var(--kungalgame-font-color-3); color: var(--kungalgame-font-color-3);
@ -199,55 +225,48 @@ const handleRegister = () => {
transition: 0.2s linear; transition: 0.2s linear;
} }
.mail-confirm { .code {
position: absolute; position: absolute;
padding: 5px; bottom: 120px;
height: 30px; right: 50px;
bottom: 24%;
right: 15%;
}
.mail-confirm:hover {
color: var(--kungalgame-blue-4);
} }
/* 用户协议 */ /* 用户协议 */
.user-agreement { .user-agreement {
position: absolute; position: absolute;
bottom: 2%; bottom: 3%;
font-size: x-small; font-size: x-small;
color: var(--kungalgame-font-color-1); color: var(--kungalgame-font-color-1);
text-decoration: none; text-decoration: none;
} span {
.user-agreement span {
color: var(--kungalgame-red-4); color: var(--kungalgame-red-4);
font-style: oblique; font-style: oblique;
}
} }
.btn { .btn {
position: absolute; position: absolute;
bottom: 7%; bottom: 10%;
border-radius: 50px; border-radius: 50px;
background-color: var(--kungalgame-trans-white-5); background-color: var(--kungalgame-trans-white-5);
border: 1px solid var(--kungalgame-blue-4); border: 1px solid var(--kungalgame-blue-4);
color: var(--kungalgame-blue-4); color: var(--kungalgame-blue-4);
cursor: pointer; cursor: pointer;
font-size: 0.9em; font-size: 15px;
letter-spacing: 0.1rem; letter-spacing: 2px;
padding: 0.6rem 4rem; padding: 7px 50px;
text-transform: uppercase; text-transform: uppercase;
transition: transform 80ms ease-in; transition: all 0.2s;
margin-top: 30px; margin-top: 30px;
} &:hover {
.btn:hover {
background-color: var(--kungalgame-blue-4); background-color: var(--kungalgame-blue-4);
color: var(--kungalgame-white); color: var(--kungalgame-white);
} }
&:active {
.btn:active {
transform: scale(0.95); transform: scale(0.95);
} }
&:focus {
.btn:focus {
outline: none; outline: none;
}
} }
</style> </style>

View 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',
},
]

View file

@ -9,7 +9,7 @@ import 'dayjs/locale/en' // 导入英文语言包
import { useKUNGalgameSettingsStore } from '@/store/modules/settings' import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
const { time } = defineProps<{ const props = defineProps<{
time?: number time?: number
}>() }>()
@ -19,8 +19,8 @@ const { showKUNGalgameLanguage } = storeToRefs(settingsStore)
// 使 // 使
dayjs.locale('en') dayjs.locale('en')
const formattedCNDate = dayjs(time).format('YYYY年MM月DD日-HH:mm:ss 发布') const formattedCNDate = dayjs(props.time).format('YYYY年MM月DD日-HH:mm:ss 发布')
const formattedENDate = dayjs(time).format('MMMM D, YYYY - h:mm:ss A') const formattedENDate = dayjs(props.time).format('MMMM D, YYYY - h:mm:ss A')
const loliTime = computed(() => { const loliTime = computed(() => {
if (showKUNGalgameLanguage.value === 'en') { if (showKUNGalgameLanguage.value === 'en') {

View file

@ -15,7 +15,7 @@ import { storeToRefs } from 'pinia'
const { name, uid } = storeToRefs(useKUNGalgameUserStore()) const { name, uid } = storeToRefs(useKUNGalgameUserStore())
// props // props
const { tid, rid, to_user } = defineProps<{ const props = defineProps<{
tid: number tid: number
rid: number rid: number
to_user: { to_user: {
@ -48,10 +48,10 @@ const handleInputComment = () => {
// //
const saveComment = () => { const saveComment = () => {
commentDraft.value.tid = tid commentDraft.value.tid = props.tid
commentDraft.value.rid = rid commentDraft.value.rid = props.rid
commentDraft.value.c_uid = uid.value 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 commentDraft.value.content = commentValue.value
} }

View file

@ -13,7 +13,7 @@ import { useKUNGalgameTopicStore } from '@/store/modules/topic'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
const { commentDraft } = storeToRefs(useKUNGalgameTopicStore()) const { commentDraft } = storeToRefs(useKUNGalgameTopicStore())
const { tid, rid, toUser } = defineProps<{ const props = defineProps<{
tid: number tid: number
rid: number rid: number
toUser: { toUser: {
@ -41,10 +41,10 @@ const getCommentEmits = (newComment: TopicComment) => {
onMounted(async () => { onMounted(async () => {
// //
toUserInfo.name = toUser.name toUserInfo.name = props.toUser.name
toUserInfo.uid = toUser.uid 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 toUserInfo.uid = uid
// //
commentDraft.value.isShowCommentPanelRid = rid commentDraft.value.isShowCommentPanelRid = props.rid
} }
</script> </script>