Files
nexus/Project/fonrey/UI_DESIGN/登录_重置密码_UI.html
2026-04-30 18:40:55 +08:00

248 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>