Skip to content

Commit

Permalink
feat: 完善逻辑
Browse files Browse the repository at this point in the history
  • Loading branch information
Saltro committed Apr 16, 2023
1 parent f28d635 commit 67f4aab
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 22 deletions.
3 changes: 2 additions & 1 deletion components/z-input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ const emit = defineEmits<{
const inputRef = ref<HTMLInputElement | null>(null);
function reportValidity() {
if (inputRef.value) {
inputRef.value.reportValidity();
return inputRef.value.reportValidity();
}
return false;
}
defineExpose({
Expand Down
47 changes: 46 additions & 1 deletion pages/certify-pending.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,56 @@
<page-header image="/image/certify-pending.svg" title="验证邮件已发送" notice="验证邮件已发送至[email protected]" />
<form @submit="submit">
<button>已在邮箱中完成验证</button>
<button class="resend" @click="resend">重新发送邮件</button>
<button class="resend" :disabled="messageTimeout > 0" @click="resend">重新发送邮件{{ messageTimeout > 0 ? ` (${messageTimeout})` : '' }}</button>
</form>
<p class="action"><nuxt-link to="/register">无法访问武大邮箱?</nuxt-link></p>
</template>
<script lang="ts" setup>
const route = useRoute();
const id = route.params.id?.toString() ?? '';
const messageTimeout = ref(0);
function resetTimeout() {
messageTimeout.value = 60;
const intervalId = setInterval(() => {
messageTimeout.value -= 1;
if (messageTimeout.value === 0) {
clearInterval(intervalId);
}
}, 1000);
}
onMounted(() => {
resetTimeout();
});
interface CertifyRes {
is_certified: boolean;
certify_time: string;
}
function submit(e: Event) {
e.preventDefault();
request<CertifyRes>(`/api/users/${id}/certify/`, {
method: 'GET',
}).then((res) => {
if (res.data.is_certified) {
location.href = '/';
}
})
}
interface SendRes {
to: string;
timeout: number;
}
function resend(e: Event) {
e.preventDefault();
request<SendRes>(`/api/users/${id}/certify/`, {
method: 'POST',
}).then(() => {
resetTimeout();
});
}
</script>
<style scoped lang="less">
Expand All @@ -27,6 +66,12 @@ form {
.resend {
background-color: var(--color-button-secondary-bg);
color: var(--color-primary);
transition: color, background-color .3s;
&[disabled] {
color: var(--color-disabled);
background-color: var(--color-disabled-bg);
}
}
.action {
Expand Down
41 changes: 38 additions & 3 deletions pages/certify.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,46 @@
const name = ref('');
const studentId = ref('');
const route = useRoute();
const id = route.query.id?.toString() ?? '';
const router = useRouter();
interface ChangeRes {
id: number;
username: string;
name: string;
phone: string;
student_id: string;
is_certified: boolean;
certify_time: string | null;
update_time: string;
create_time: string;
}
interface SendRes {
to: string;
timeout: number;
}
function submit(e: Event) {
$fetch('/api/users/1/certify/', {
method: 'post',
});
e.preventDefault();
if (id.length === 0) return;
request<ChangeRes>(`/api/users/${id}/`, {
method: 'PATCH',
body: {
name: name.value,
student_id: studentId.value,
}
})
.then(() => {
return request<SendRes>(`/api/users/${id}/certify/`, {
method: 'POST',
});
})
.then(() => {
router.push(`/certify-pending?id=${id}`);
});
}
</script>
<style scoped lang="less">
Expand Down
8 changes: 6 additions & 2 deletions pages/login.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="container">
<page-header />
<page-header :app-logo="appLogo" />
<form @submit="submit">
<z-input v-model="username" label="用户名/手机号/学号" icon="/icon/user.svg" required placeholder="请输入用户名" />
<z-input v-model="password" label="密码" icon="/icon/lock.svg" type="password" required placeholder="请输入密码">
Expand All @@ -17,13 +17,17 @@
const username = ref('');
const password = ref('');
const route = useRoute();
const appName = ref(route.params['app-name']?.toString() ?? '');
const appLogo = ref(route.params['app-logo']?.toString() ?? '');
function submit(e: Event) {
$fetch<ResBody<{ code: string }>>('/api/sso/code/', {
method: 'post',
body: {
username: username.value,
password: password.value,
app: 'team',
app: appName.value,
},
}).then((res) => {
console.log(res.data.code);
Expand Down
29 changes: 22 additions & 7 deletions pages/register.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@
v-model="sms"
label="验证码"
icon="/icon/message.svg"
minlength="6"
maxlength="6"
type="number"
required
pattern="[0-9]+"
placeholder="请输入验证码"
>
<template #extra-input>
Expand All @@ -39,13 +43,15 @@
label="密码"
icon="/icon/lock.svg"
required
type="password"
placeholder="请输入密码"
/>
<z-input
v-model="confirmedPassword"
label="确认密码"
icon="/icon/lock.svg"
required
type="password"
placeholder="请再次输入密码"
:custom-rule="confirmedPasswordRule"
/>
Expand All @@ -55,12 +61,16 @@
</div>
</template>
<script lang="ts" setup>
import ZInput from '@/components/z-input.vue';
const username = ref('');
const phone = ref('');
const sms = ref('');
const password = ref('');
const confirmedPassword = ref('');
const router = useRouter();
interface RegisterRes {
id: number;
username: string;
Expand All @@ -71,32 +81,39 @@ interface RegisterRes {
certify_time: null | string;
update_time: string;
create_time: string;
expire_time: string;
access: string;
refresh: string;
}
function submit(e: Event) {
e.preventDefault();
$fetch<ResBody<RegisterRes>>('/api/users/', {
method: 'post',
method: 'POST',
body: {
username: username.value,
phone: phone.value,
code: sms.value,
password: password.value,
},
}).then((res) => {
console.log(res.data.id);
localStorage.setItem('access', res.data.access);
localStorage.setItem('exp', res.data.expire_time);
localStorage.setItem('refresh', res.data.refresh);
router.push(`/certify?id=${res.data.id}`);
});
e.preventDefault();
}
const phoneInputRef = ref<HTMLInputElement | null>(null);
const phoneInputRef = ref<InstanceType<typeof ZInput> | null>(null);
const messageTimeout = ref(0);
let intervalId = -1;
function sendMessage(e: Event) {
e.preventDefault();
if (!phoneInputRef.value) return;
if (!phoneInputRef.value.reportValidity()) return;
if (messageTimeout.value > 0) return;
$fetch<ResBody<{ status: string }>>('/api/auth/sms/', {
method: 'post',
method: 'POST',
body: {
phone: phone.value,
},
Expand All @@ -108,9 +125,7 @@ function sendMessage(e: Event) {
clearInterval(intervalId);
}
}, 1000);
console.log(res.data.status);
});
e.preventDefault();
}
function confirmedPasswordRule(value: string) {
Expand Down
17 changes: 9 additions & 8 deletions pages/reset.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,48 +46,49 @@
</form>
</template>
<script lang="ts" setup>
const router = useRouter();
const phone = ref('');
const sms = ref('');
const password = ref('');
const confirmedPassword = ref('');
function submit(e: Event) {
e.preventDefault();
$fetch<ResBody<{ status: string }>>('/api/users/reset/', {
method: 'post',
method: 'POST',
body: {
phone: phone.value,
code: sms.value,
password: password.value,
},
}).then((res) => {
console.log(res.data);
}).then(() => {
router.back();
});
e.preventDefault();
}
const phoneInputRef = ref<HTMLInputElement | null>(null);
const messageTimeout = ref(0);
let intervalId = -1;
function sendMessage(e: Event) {
e.preventDefault();
if (!phoneInputRef.value) return;
if (!phoneInputRef.value.reportValidity()) return;
if (messageTimeout.value > 0) return;
$fetch<ResBody<{ status: string }>>('/api/auth/sms/', {
method: 'post',
method: 'POST',
body: {
phone: phone.value,
},
}).then((res) => {
}).then(() => {
messageTimeout.value = 60;
intervalId = setInterval(() => {
messageTimeout.value -= 1;
if (messageTimeout.value === 0) {
clearInterval(intervalId);
}
}, 1000);
console.log(res.data.status);
});
e.preventDefault();
}
function confirmedPasswordRule(value: string) {
Expand Down
41 changes: 41 additions & 0 deletions utils/request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
interface RefreshRes {
access: string;
expire_time: string;
}

interface RequestOptions {
method: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE';
body?: Record<string, string>;
headers?: Record<string, string>;
}

export async function request<T>(url: string, options: RequestOptions) {
let access = localStorage.getItem('access');
const refresh = localStorage.getItem('refresh');
let exp = localStorage.getItem('exp');
if (!access || !exp) return;
if (Date.now() > new Date(exp).getTime()) {
try {
const res = await $fetch<ResBody<RefreshRes>>('/auth/refresh/', {
method: 'POST',
body: {
refresh,
},
});
localStorage.setItem('access', res.data.access);
localStorage.setItem('exp', res.data.expire_time);
access = res.data.access;
} catch (err) {
throw new Error('Refresh expired');
}
}
return $fetch<ResBody<T>>(url, {
...options,
headers: {
Authorization: `Bearer ${access}`,
...options.headers,
},
}).then((res) => {
return res.data;
});
}

0 comments on commit 67f4aab

Please sign in to comment.