新增管理登录页面
This commit is contained in:
@@ -0,0 +1,561 @@
|
||||
{{-- 文件功能:站长隐藏登录页 --}}
|
||||
@php
|
||||
$systemName = \App\Models\SysParam::where('alias', 'sys_name')->value('body') ?? '和平聊吧';
|
||||
@endphp
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>站长后台入口 - {{ $systemName }}</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700;900&family=Noto+Serif+SC:wght@700;900&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg: #fafaf9;
|
||||
--paper: #f5f1e8;
|
||||
--ink: #0c0a09;
|
||||
--ink-soft: #57534e;
|
||||
--ink-faint: #a8a29e;
|
||||
--line: #d6d3d1;
|
||||
--line-strong: #1c1917;
|
||||
--panel: #111111;
|
||||
--panel-soft: #1f1f1f;
|
||||
--gold: #a16207;
|
||||
--gold-soft: #f4d9a8;
|
||||
--danger: #b91c1c;
|
||||
--danger-bg: #fef2f2;
|
||||
--success: #166534;
|
||||
--success-bg: #f0fdf4;
|
||||
--shadow: 0 28px 90px rgba(12, 10, 9, 0.12);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "DM Sans", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
color: var(--ink);
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(161, 98, 7, 0.08), transparent 18%),
|
||||
linear-gradient(180deg, #fcfbf8 0%, #f7f4ee 100%);
|
||||
}
|
||||
|
||||
.shell {
|
||||
width: min(1380px, calc(100% - 32px));
|
||||
margin: 16px auto;
|
||||
min-height: calc(100vh - 32px);
|
||||
border: 1px solid var(--line-strong);
|
||||
background: var(--bg);
|
||||
box-shadow: var(--shadow);
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.1fr) minmax(420px, 0.9fr);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.shell::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 18px;
|
||||
border: 1px solid rgba(28, 25, 23, 0.08);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding: 38px 42px 34px;
|
||||
border-right: 1px solid var(--line-strong);
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
gap: 30px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(161, 98, 7, 0.03), transparent 26%),
|
||||
linear-gradient(90deg, transparent 0, transparent calc(100% - 1px), rgba(28, 25, 23, 0.04) calc(100% - 1px));
|
||||
}
|
||||
|
||||
.topbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding-bottom: 18px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 16px;
|
||||
border: 1px solid var(--line-strong);
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.24em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.eyebrow::before {
|
||||
content: "";
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: var(--gold);
|
||||
}
|
||||
|
||||
.system-name {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.18em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ink-soft);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.hero-main {
|
||||
display: grid;
|
||||
align-content: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.kicker {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.28em;
|
||||
text-transform: uppercase;
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
font-size: clamp(4rem, 10vw, 8.8rem);
|
||||
line-height: 0.88;
|
||||
letter-spacing: -0.06em;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.title-accent {
|
||||
display: block;
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.lead {
|
||||
max-width: 620px;
|
||||
margin: 0;
|
||||
color: var(--ink-soft);
|
||||
font-size: 18px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.rule {
|
||||
width: 92px;
|
||||
height: 6px;
|
||||
background: var(--line-strong);
|
||||
}
|
||||
|
||||
.hero-meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
border-top: 1px solid var(--line);
|
||||
padding-top: 22px;
|
||||
}
|
||||
|
||||
.meta-card {
|
||||
padding: 20px 18px;
|
||||
background: var(--paper);
|
||||
border: 1px solid var(--line);
|
||||
min-height: 152px;
|
||||
}
|
||||
|
||||
.meta-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.22em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
|
||||
.meta-value {
|
||||
margin-top: 14px;
|
||||
font-size: clamp(1.9rem, 3vw, 3.2rem);
|
||||
line-height: 0.95;
|
||||
font-weight: 900;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.meta-copy {
|
||||
margin-top: 12px;
|
||||
color: var(--ink-soft);
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: var(--panel);
|
||||
color: #fff;
|
||||
padding: 26px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.panel-card {
|
||||
width: min(100%, 470px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.015)),
|
||||
var(--panel);
|
||||
padding: 28px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.panel-card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 14px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.panel-top {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 26px;
|
||||
}
|
||||
|
||||
.panel-kicker {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.22em;
|
||||
text-transform: uppercase;
|
||||
color: var(--gold-soft);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
margin: 10px 0 8px;
|
||||
font-family: "Noto Serif SC", serif;
|
||||
font-size: 34px;
|
||||
line-height: 1.12;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.panel-copy {
|
||||
margin: 0;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
font-size: 15px;
|
||||
line-height: 1.85;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.18em;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.form {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.field {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.field label {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.06em;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
}
|
||||
|
||||
.field input {
|
||||
width: 100%;
|
||||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: #fff;
|
||||
padding: 16px 18px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
outline: none;
|
||||
transition: border-color .2s ease, background-color .2s ease, box-shadow .2s ease;
|
||||
}
|
||||
|
||||
.field input::placeholder {
|
||||
color: rgba(255, 255, 255, 0.36);
|
||||
}
|
||||
|
||||
.field input:focus {
|
||||
border-color: rgba(244, 217, 168, 0.9);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 0 0 3px rgba(161, 98, 7, 0.22);
|
||||
}
|
||||
|
||||
.captcha-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 148px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.captcha-image {
|
||||
width: 100%;
|
||||
height: 56px;
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 14px 16px;
|
||||
border: 1px solid;
|
||||
font-size: 14px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.message-success {
|
||||
border-color: rgba(34, 197, 94, 0.34);
|
||||
background: rgba(22, 101, 52, 0.18);
|
||||
color: #dcfce7;
|
||||
}
|
||||
|
||||
.message-error {
|
||||
border-color: rgba(248, 113, 113, 0.34);
|
||||
background: rgba(127, 29, 29, 0.16);
|
||||
color: #fecaca;
|
||||
}
|
||||
|
||||
.submit {
|
||||
width: 100%;
|
||||
border: 1px solid var(--gold);
|
||||
background: linear-gradient(180deg, #d5a548 0%, #a16207 100%);
|
||||
color: #fff;
|
||||
padding: 17px 18px;
|
||||
font-size: 15px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
transition: transform .2s ease, filter .2s ease, box-shadow .2s ease;
|
||||
box-shadow: 0 18px 28px rgba(161, 98, 7, 0.2);
|
||||
}
|
||||
|
||||
.submit:hover {
|
||||
transform: translateY(-2px);
|
||||
filter: saturate(1.03);
|
||||
box-shadow: 0 22px 34px rgba(161, 98, 7, 0.28);
|
||||
}
|
||||
|
||||
.helper {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||
color: rgba(255, 255, 255, 0.56);
|
||||
font-size: 13px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.helper strong {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1080px) {
|
||||
.shell {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.hero {
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid var(--line-strong);
|
||||
}
|
||||
|
||||
.hero-meta {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.shell {
|
||||
width: min(100%, calc(100% - 18px));
|
||||
margin: 9px auto;
|
||||
min-height: calc(100vh - 18px);
|
||||
}
|
||||
|
||||
.shell::before {
|
||||
inset: 10px;
|
||||
}
|
||||
|
||||
.hero,
|
||||
.panel {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.hero-main {
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: clamp(3rem, 20vw, 4.8rem);
|
||||
}
|
||||
|
||||
.panel-card {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.panel-top,
|
||||
.captcha-row {
|
||||
grid-template-columns: 1fr;
|
||||
display: grid;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="shell">
|
||||
<section class="hero">
|
||||
<header class="topbar">
|
||||
<div class="eyebrow">Hidden Admin Entry</div>
|
||||
<div class="system-name">{{ $systemName }}</div>
|
||||
</header>
|
||||
|
||||
<div class="hero-main">
|
||||
<div class="kicker">Trust / Authority / Private Access</div>
|
||||
<h1 class="title">
|
||||
Owner
|
||||
<span class="title-accent">Console</span>
|
||||
</h1>
|
||||
<div class="rule" aria-hidden="true"></div>
|
||||
<p class="lead">
|
||||
这是一个独立于聊天室首页的后台登录入口。这里只做站长控制台访问,不承载普通用户登录,不会在登录成功后打开聊天室页面。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="hero-meta">
|
||||
<article class="meta-card">
|
||||
<div class="meta-label">入口后缀</div>
|
||||
<div class="meta-value">{{ $loginSuffix }}</div>
|
||||
<div class="meta-copy">保留隐藏后缀,不在首页暴露。这个入口只用于后台控制台访问。</div>
|
||||
</article>
|
||||
|
||||
<article class="meta-card">
|
||||
<div class="meta-label">权限约束</div>
|
||||
<div class="meta-value">id=1</div>
|
||||
<div class="meta-copy">只有站长主账号可以从这里登录,其他账号即使密码正确也会被拒绝。</div>
|
||||
</article>
|
||||
|
||||
<article class="meta-card">
|
||||
<div class="meta-label">登录去向</div>
|
||||
<div class="meta-value">Admin</div>
|
||||
<div class="meta-copy">验证通过后直接进入后台首页,不跳聊天室大厅,不走“登录即注册”。</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-card">
|
||||
<div class="panel-top">
|
||||
<div>
|
||||
<div class="panel-kicker">Owner Authentication</div>
|
||||
<h2 class="panel-title">登录后台控制台</h2>
|
||||
<p class="panel-copy">输入站长账号、密码和验证码后进入后台。</p>
|
||||
</div>
|
||||
<div class="status-tag">Restricted</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('admin.login.store') }}" class="form">
|
||||
@csrf
|
||||
|
||||
<div class="field">
|
||||
<label for="username">站长账号</label>
|
||||
<input id="username" name="username" type="text" value="{{ old('username') }}"
|
||||
placeholder="请输入 id=1 对应的用户名" autocomplete="username" autofocus required>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="password">登录密码</label>
|
||||
<input id="password" name="password" type="password" placeholder="请输入站长密码"
|
||||
autocomplete="current-password" required>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="captcha">验证码</label>
|
||||
<div class="captcha-row">
|
||||
<input id="captcha" name="captcha" type="text" placeholder="输入验证码" required>
|
||||
<img src="/captcha/default?{{ mt_rand() }}" alt="站长登录验证码" id="captcha-img" class="captcha-image"
|
||||
onclick="refreshCaptcha()" title="点击刷新验证码">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (session('success'))
|
||||
<div class="message message-success" role="status" aria-live="polite">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="message message-error" role="alert" aria-live="assertive">
|
||||
<ul style="margin: 0; padding-left: 18px;">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<button type="submit" class="submit">进入后台控制台</button>
|
||||
</form>
|
||||
|
||||
<div class="helper">
|
||||
<strong>提示:</strong>点击右侧验证码图片可刷新。如果页面仍显示旧样式,直接强制刷新浏览器缓存即可。
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 刷新验证码图片,避免浏览器缓存旧图。
|
||||
*/
|
||||
function refreshCaptcha() {
|
||||
document.getElementById('captcha-img').src = '/captcha/default?' + Math.random();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user