- Remove extra spaces in CSS property declarations - Consolidate multi-line CSS rules into single lines - Maintain consistent formatting across component styles - Improve readability by removing unnecessary line breaks - Ensure uniform styling structure in scoped CSS blocks
194 lines
5.7 KiB
Vue
194 lines
5.7 KiB
Vue
<script setup lang="ts">
|
||
import { ref, computed } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import { User } from '@element-plus/icons-vue'
|
||
import { authApi } from '../../api/auth'
|
||
import { getOrCreateDeviceId } from '../../utils/deviceId'
|
||
|
||
interface Props {
|
||
modelValue: boolean
|
||
}
|
||
|
||
interface Emits {
|
||
(e: 'update:modelValue', value: boolean): void
|
||
(e: 'loginSuccess', data: { token: string; permissions?: string; expireTime?: string; accountType?: string; deviceTrialExpired?: boolean }): void
|
||
(e: 'backToLogin'): void
|
||
}
|
||
|
||
const props = defineProps<Props>()
|
||
const emit = defineEmits<Emits>()
|
||
|
||
const registerForm = ref({ username: '', password: '', confirmPassword: '' })
|
||
const registerLoading = ref(false)
|
||
const usernameCheckResult = ref<boolean | null>(null)
|
||
|
||
const visible = computed({
|
||
get: () => props.modelValue,
|
||
set: (value) => emit('update:modelValue', value)
|
||
})
|
||
|
||
const canRegister = computed(() => {
|
||
const { username, password, confirmPassword } = registerForm.value
|
||
return username &&
|
||
password.length >= 6 &&
|
||
password === confirmPassword &&
|
||
usernameCheckResult.value === true
|
||
})
|
||
|
||
function filterUsername(value: string) {
|
||
registerForm.value.username = value.replace(/[^a-zA-Z0-9_]/g, '')
|
||
}
|
||
|
||
async function checkUsernameAvailability() {
|
||
if (!registerForm.value.username) {
|
||
usernameCheckResult.value = null
|
||
return
|
||
}
|
||
|
||
try {
|
||
const res: any = await authApi.checkUsername(registerForm.value.username)
|
||
// 后端返回 {code: 200, data: true/false},data 直接是布尔值
|
||
usernameCheckResult.value = res.data
|
||
} catch {
|
||
usernameCheckResult.value = null
|
||
}
|
||
}
|
||
|
||
async function handleRegister() {
|
||
if (!canRegister.value) return
|
||
|
||
registerLoading.value = true
|
||
try {
|
||
// 获取设备ID
|
||
const deviceId = await getOrCreateDeviceId()
|
||
|
||
// 注册账号(传递设备ID用于判断是否赠送VIP)
|
||
const registerRes: any = await authApi.register({
|
||
username: registerForm.value.username,
|
||
password: registerForm.value.password,
|
||
deviceId: deviceId
|
||
})
|
||
|
||
// 显示注册成功提示
|
||
if (registerRes.data.deviceTrialExpired) {
|
||
ElMessage.warning('注册成功!您获得了3天VIP体验,但该设备试用期已过,请更换设备或联系管理员续费')
|
||
} else {
|
||
ElMessage.success('注册成功!您获得了3天VIP体验')
|
||
}
|
||
|
||
// 使用注册返回的token直接登录
|
||
emit('loginSuccess', {
|
||
token: registerRes.data.accessToken || registerRes.data.token,
|
||
permissions: registerRes.data.permissions,
|
||
expireTime: registerRes.data.expireTime,
|
||
accountType: registerRes.data.accountType,
|
||
deviceTrialExpired: registerRes.data.deviceTrialExpired || false
|
||
})
|
||
resetForm()
|
||
} catch (err) {
|
||
ElMessage.error((err as Error).message)
|
||
} finally {
|
||
registerLoading.value = false
|
||
}
|
||
}
|
||
|
||
function cancelRegister() {
|
||
visible.value = false
|
||
resetForm()
|
||
}
|
||
|
||
function resetForm() {
|
||
registerForm.value = { username: '', password: '', confirmPassword: '' }
|
||
usernameCheckResult.value = null
|
||
}
|
||
|
||
function backToLogin() {
|
||
emit('backToLogin')
|
||
resetForm()
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<el-dialog
|
||
title=""
|
||
v-model="visible"
|
||
:close-on-click-modal="false"
|
||
width="380px"
|
||
center
|
||
class="auth-dialog">
|
||
<div style="padding: 20px 0;">
|
||
<div style="text-align: center; margin-bottom: 16px; color: #666;">
|
||
<img src="/icon/image.png" alt="logo" class="auth-logo" />
|
||
</div>
|
||
<div class="auth-title-wrap">
|
||
<h3 class="auth-title">创建账号</h3>
|
||
<p class="auth-subtitle">创建账号以获取完整服务体验</p>
|
||
</div>
|
||
|
||
<el-input
|
||
v-model="registerForm.username"
|
||
placeholder="请输入用户名(字母、数字、下划线)"
|
||
size="large"
|
||
style="margin-bottom: 15px;"
|
||
:disabled="registerLoading"
|
||
@input="filterUsername"
|
||
@blur="checkUsernameAvailability">
|
||
</el-input>
|
||
|
||
<div v-if="usernameCheckResult !== null" style="margin-bottom: 15px; text-align: left;">
|
||
<span v-if="usernameCheckResult" style="color: #67C23A; font-size: 12px;">
|
||
✓ 用户名可用
|
||
</span>
|
||
<span v-else style="color: #F56C6C; font-size: 12px;">
|
||
✗ 用户名已存在
|
||
</span>
|
||
</div>
|
||
|
||
<el-input
|
||
v-model="registerForm.password"
|
||
placeholder="请输入密码(至少6位)"
|
||
type="password"
|
||
size="large"
|
||
style="margin-bottom: 15px;"
|
||
:disabled="registerLoading"
|
||
show-password>
|
||
</el-input>
|
||
|
||
<el-input
|
||
v-model="registerForm.confirmPassword"
|
||
placeholder="请再次输入密码"
|
||
type="password"
|
||
size="large"
|
||
style="margin-bottom: 20px;"
|
||
:disabled="registerLoading"
|
||
show-password>
|
||
</el-input>
|
||
|
||
<div>
|
||
<el-button
|
||
type="primary"
|
||
size="large"
|
||
:loading="registerLoading"
|
||
:disabled="!canRegister || registerLoading"
|
||
@click="handleRegister"
|
||
style="width: 100%;">
|
||
注册
|
||
</el-button>
|
||
</div>
|
||
|
||
<div style="margin-top: 20px; text-align: center;">
|
||
<el-button type="text" @click="backToLogin" :disabled="registerLoading">
|
||
已有账号?返回登录
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
</template>
|
||
<style scoped>
|
||
.auth-logo {width: 160px; height: auto;}
|
||
.auth-dialog {--el-color-primary: #1677FF;}
|
||
.auth-dialog :deep(.el-button--primary) {background-color: #1677FF; border-color: #1677FF;}
|
||
.auth-title-wrap {margin-bottom: 12px;}
|
||
.auth-title {margin: 0; font-size: 18px; font-weight: 700; color: #1f1f1f; text-align: left;}
|
||
.auth-subtitle {margin: 6px 0 0; font-size: 12px; color: #8c8c8c; text-align: left;}
|
||
</style> |