登录模块审核

This commit is contained in:
Shen Wei
2026-04-30 18:40:55 +08:00
parent 4030a91100
commit 57600598ac
34 changed files with 2544 additions and 2431 deletions

View File

@@ -0,0 +1,247 @@
<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280">
<title>Fonrey 登录管理 · 设置新密码</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
50: '#F0FDFA', 100: '#CCFBF1', 200: '#99F6E4',
500: '#14B8A6', 600: '#0F766E', 700: '#115E59', 800: '#134E4A'
},
neutral: {
50: '#F8FAFC', 100: '#F1F5F9', 200: '#E2E8F0', 300: '#CBD5E1',
400: '#94A3B8', 500: '#64748B', 600: '#475569', 700: '#334155',
800: '#1E293B', 900: '#0F172A'
},
success: { 50: '#F0FDF4', 600: '#16A34A' },
warning: { 50: '#FFFBEB', 600: '#D97706' },
danger: { 50: '#FEF2F2', 600: '#DC2626' }
}
}
}
}
</script>
<style>
[x-cloak] { display: none !important; }
</style>
</head>
<body class="min-h-screen bg-neutral-50 font-sans text-sm text-neutral-700 antialiased" x-data="passwordResetPage()" x-init="init()">
<div class="fixed inset-0 -z-10">
<div class="absolute inset-y-0 left-0 w-[56%] bg-gradient-to-br from-primary-800 via-primary-700 to-primary-600"></div>
<div class="absolute -top-16 -left-24 w-96 h-96 rounded-full bg-white/10 blur-2xl"></div>
<div class="absolute bottom-0 left-1/3 w-80 h-80 rounded-full bg-primary-200/15 blur-2xl"></div>
</div>
<main class="mx-auto max-w-[1440px] min-h-screen grid grid-cols-12">
<section class="col-span-7 px-12 py-12 text-white flex flex-col justify-between">
<div>
<div class="inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-white/10 border border-white/20">
<div class="w-7 h-7 rounded-md bg-primary-500/90 flex items-center justify-center text-white font-semibold">F</div>
<span class="text-base font-semibold">Fonrey 房睿</span>
</div>
<h1 class="mt-8 text-4xl font-semibold leading-tight" x-text="pageTitle"></h1>
<p class="mt-4 text-primary-100 text-base leading-7 max-w-xl" x-text="pageDesc"></p>
</div>
<div class="grid grid-cols-2 gap-4 max-w-2xl">
<div class="rounded-lg border border-white/20 bg-white/10 p-4">
<div class="text-xs text-primary-100">密码规则</div>
<div class="mt-1 text-xl font-semibold">至少 8 位,含字母+数字</div>
</div>
<div class="rounded-lg border border-white/20 bg-white/10 p-4">
<div class="text-xs text-primary-100">当前模式</div>
<div class="mt-1 text-xl font-semibold" x-text="mode === 'initial' ? '首次登录强制修改' : '找回密码重置'"></div>
</div>
</div>
</section>
<section class="col-span-5 px-10 py-10 flex items-center justify-center">
<div class="w-full max-w-md rounded-xl bg-white border border-neutral-200 shadow-lg p-6">
<h2 class="text-xl font-semibold text-neutral-800" x-text="pageTitle"></h2>
<p class="mt-2 text-sm text-neutral-500" x-text="pageDesc"></p>
<form class="mt-5 space-y-4" @submit.prevent="submitReset">
<div class="space-y-1">
<label for="new-password" class="block text-sm font-medium text-neutral-700">新密码<span class="text-danger-600">*</span></label>
<div class="relative">
<input
id="new-password"
:type="newPasswordVisible ? 'text' : 'password'"
x-model="newPassword"
@input="validatePassword"
placeholder="请输入新密码"
class="block w-full px-3 py-2 pr-10 text-sm rounded-md border border-neutral-300 placeholder:text-neutral-400 focus:outline-none focus:border-primary-600 focus:ring-2 focus:ring-primary-600/20"
:disabled="submitting"
>
<button type="button" @click="newPasswordVisible=!newPasswordVisible" class="absolute right-2 top-1/2 -translate-y-1/2 p-1 text-neutral-500 hover:text-neutral-700" aria-label="显示或隐藏新密码">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.644C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.009 9.963 7.178.07.207.07.431 0 .638C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.009-9.964-7.178Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>
</button>
</div>
<p x-show="newPasswordError" x-text="newPasswordError" class="text-xs text-danger-600"></p>
</div>
<div class="space-y-1">
<label for="confirm-password" class="block text-sm font-medium text-neutral-700">确认新密码<span class="text-danger-600">*</span></label>
<div class="relative">
<input
id="confirm-password"
:type="confirmPasswordVisible ? 'text' : 'password'"
x-model="confirmPassword"
@input="validatePassword"
placeholder="请再次输入新密码"
class="block w-full px-3 py-2 pr-10 text-sm rounded-md border border-neutral-300 placeholder:text-neutral-400 focus:outline-none focus:border-primary-600 focus:ring-2 focus:ring-primary-600/20"
:disabled="submitting"
>
<button type="button" @click="confirmPasswordVisible=!confirmPasswordVisible" class="absolute right-2 top-1/2 -translate-y-1/2 p-1 text-neutral-500 hover:text-neutral-700" aria-label="显示或隐藏确认密码">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.644C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.009 9.963 7.178.07.207.07.431 0 .638C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.009-9.964-7.178Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>
</button>
</div>
<p x-show="confirmPasswordError" x-text="confirmPasswordError" class="text-xs text-danger-600"></p>
</div>
<div class="rounded-lg border border-neutral-200 bg-neutral-50 p-3 space-y-2">
<p class="text-xs font-medium text-neutral-700">密码强度校验</p>
<div class="text-xs flex items-center gap-2" :class="rules.minLength ? 'text-success-600' : 'text-neutral-500'">
<span x-text="rules.minLength ? '✓' : '✗'"></span>
<span>长度至少 8 位</span>
</div>
<div class="text-xs flex items-center gap-2" :class="rules.hasLetter ? 'text-success-600' : 'text-neutral-500'">
<span x-text="rules.hasLetter ? '✓' : '✗'"></span>
<span>包含字母</span>
</div>
<div class="text-xs flex items-center gap-2" :class="rules.hasNumber ? 'text-success-600' : 'text-neutral-500'">
<span x-text="rules.hasNumber ? '✓' : '✗'"></span>
<span>包含数字</span>
</div>
</div>
<template x-if="globalError">
<div class="rounded-md border border-danger-600/30 bg-danger-50 px-3 py-2 text-xs text-danger-600" x-text="globalError"></div>
</template>
<template x-if="successMessage">
<div class="rounded-md border border-success-600/30 bg-success-50 px-3 py-2 text-xs text-success-600" x-text="successMessage"></div>
</template>
<button
type="submit"
class="inline-flex w-full items-center justify-center gap-1.5 px-4 py-2 text-sm font-medium rounded-md bg-primary-600 text-white hover:bg-primary-700 active:bg-primary-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-600/40 disabled:opacity-50 disabled:cursor-not-allowed"
:disabled="submitting"
x-text="submitting ? '提交中…' : submitText"
></button>
</form>
<div class="mt-4 text-xs text-neutral-500" x-show="mode === 'recover'">
<a href="./登录_账号密码_UI.html" class="text-primary-600 hover:underline">返回登录页</a>
</div>
</div>
</section>
</main>
<script>
function passwordResetPage() {
return {
mode: 'recover', // initial | recover
pageTitle: '',
pageDesc: '',
submitText: '',
newPassword: '',
confirmPassword: '',
newPasswordVisible: false,
confirmPasswordVisible: false,
newPasswordError: '',
confirmPasswordError: '',
globalError: '',
successMessage: '',
submitting: false,
rules: {
minLength: false,
hasLetter: false,
hasNumber: false
},
init() {
const params = new URLSearchParams(window.location.search)
this.mode = params.get('mode') === 'initial' ? 'initial' : 'recover'
if (this.mode === 'initial') {
this.pageTitle = '欢迎使用 Fonrey请先设置您的登录密码'
this.pageDesc = '您当前使用的是初始密码,为保障账号安全,请立即设置新密码后开始使用'
this.submitText = '确认并进入系统'
} else {
this.pageTitle = '重置您的登录密码'
this.pageDesc = '请输入您的新密码,设置完成后请使用新密码重新登录'
this.submitText = '确认重置密码'
}
},
validatePassword() {
this.newPasswordError = ''
this.confirmPasswordError = ''
this.globalError = ''
this.rules.minLength = this.newPassword.length >= 8
this.rules.hasLetter = /[A-Za-z]/.test(this.newPassword)
this.rules.hasNumber = /\d/.test(this.newPassword)
if (this.confirmPassword && this.newPassword !== this.confirmPassword) {
this.confirmPasswordError = '两次输入密码不一致'
}
},
submitReset() {
this.successMessage = ''
this.globalError = ''
this.validatePassword()
if (!this.newPassword) {
this.newPasswordError = '请输入新密码'
return
}
if (!this.rules.minLength || !this.rules.hasLetter || !this.rules.hasNumber) {
this.globalError = '密码强度不足,请满足全部规则后再提交'
return
}
if (!this.confirmPassword) {
this.confirmPasswordError = '请再次输入新密码'
return
}
if (this.newPassword !== this.confirmPassword) {
this.confirmPasswordError = '两次输入密码不一致'
return
}
this.submitting = true
setTimeout(() => {
this.submitting = false
if (this.mode === 'initial') {
this.successMessage = '密码设置成功,正在进入系统…'
setTimeout(() => {
window.location.href = './房源列表_UI.html?from=reset&mode=initial&status=success'
}, 700)
return
}
this.successMessage = '密码已重置,请使用新密码登录'
setTimeout(() => {
window.location.href = './登录_账号密码_UI.html?reason=password_reset_success'
}, 900)
}, 800)
}
}
}
</script>
</body>
</html>