103 lines
3.2 KiB
Vue
103 lines
3.2 KiB
Vue
<script setup lang="ts">
|
||
import { ElMessage } from 'element-plus'
|
||
import { onMounted, reactive, ref } from 'vue'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
|
||
import { getRealnameStatus, startRealname, type RealnameStatus } from '@/api/realname'
|
||
import { useSessionStore } from '@/stores/session'
|
||
import { realnameStatusLabel } from '@/utils/statusLabels'
|
||
import { formatDateTime } from '@/utils/time'
|
||
|
||
const session = useSessionStore()
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
const loading = ref(false)
|
||
const status = ref<RealnameStatus | null>(null)
|
||
const form = reactive({
|
||
name: '',
|
||
idNo: '',
|
||
})
|
||
|
||
onMounted(loadStatus)
|
||
|
||
function redirectAfterVerified() {
|
||
const redirect = typeof route.query.redirect === 'string' ? route.query.redirect : ''
|
||
if (redirect) {
|
||
router.replace(redirect)
|
||
}
|
||
}
|
||
|
||
async function loadStatus() {
|
||
if (!session.token) return
|
||
try {
|
||
status.value = await getRealnameStatus()
|
||
if (status.value.status === 'verified') {
|
||
await session.loadMe()
|
||
redirectAfterVerified()
|
||
}
|
||
} catch {
|
||
status.value = null
|
||
}
|
||
}
|
||
|
||
async function handleSubmit() {
|
||
if (!form.name.trim()) {
|
||
ElMessage.warning('请输入真实姓名')
|
||
return
|
||
}
|
||
if (!form.idNo.trim() || form.idNo.length < 15) {
|
||
ElMessage.warning('请输入有效的证件号')
|
||
return
|
||
}
|
||
loading.value = true
|
||
try {
|
||
status.value = await startRealname(form.name, form.idNo)
|
||
await session.loadMe()
|
||
ElMessage.success('实名认证已通过')
|
||
redirectAfterVerified()
|
||
} catch (error) {
|
||
ElMessage.error(readError(error, '实名认证失败'))
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
function readError(error: unknown, fallback: string) {
|
||
if (typeof error === 'object' && error && 'response' in error) {
|
||
const response = (error as { response?: { data?: { message?: string } } }).response
|
||
return response?.data?.message || fallback
|
||
}
|
||
return fallback
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<section class="page">
|
||
<div class="page-header">
|
||
<p class="eyebrow">Realname</p>
|
||
<h1>实名认证</h1>
|
||
<p>号主发布前必须完成实名认证。当前是开发态 mock 认证,提交合法姓名和身份证号会直接通过。</p>
|
||
</div>
|
||
|
||
<el-alert v-if="!session.token" class="notice" type="warning" :closable="false" title="请先登录后再实名认证" />
|
||
|
||
<div v-if="status" class="status-panel">
|
||
<span>当前状态</span>
|
||
<strong>{{ realnameStatusLabel(status.status) }}</strong>
|
||
<p v-if="status.masked_name">姓名:{{ status.masked_name }}</p>
|
||
<p v-if="status.masked_id_no">证件号:{{ status.masked_id_no }}</p>
|
||
<p v-if="status.verified_at">通过时间:{{ formatDateTime(status.verified_at) }}</p>
|
||
</div>
|
||
|
||
<el-form class="login-form" label-position="top">
|
||
<el-form-item label="姓名">
|
||
<el-input v-model="form.name" placeholder="请输入真实姓名" />
|
||
</el-form-item>
|
||
<el-form-item label="身份证号">
|
||
<el-input v-model="form.idNo" maxlength="18" placeholder="请输入 18 位身份证号" />
|
||
</el-form-item>
|
||
<el-button type="primary" :disabled="!session.token" :loading="loading" @click="handleSubmit">提交认证</el-button>
|
||
</el-form>
|
||
</section>
|
||
</template>
|