Files
BYW-VoiceHub/app/pages/forgot-password.vue
T
Henry_Du cccaf36990 feat(brand): 站点品牌名统一为「宝一外校园点歌系统」
站长要求全站一致(小程序端已单独提交)。本次只改**用户可见文案与默认值**:

- 服务端默认值/兜底:system-settings-defaults、admin/system-settings(GET/POST)、
  site-config.get、utils/siteUtils —— 原来是 'VoiceHub' / '校园广播站点歌系统'
- 用户可见通知文案:MeoW 绑定验证码与标题、MeoW 测试通知、微信订阅测试通知
- 2FA 应用名(authenticator.keyuri)、WebAuthn rpName(出现在系统密钥弹窗里)
- 网页版界面:首页副标题、后台侧栏品牌名、登录/注册/找回/改密标题与文案、
  年度回顾(IntroSlide / ShareCard / 页面标题)、用户教程、通知发送预览、
  API 密钥与数据库导入说明、酷狗 sidecar 说明、打印页脚与歌单卡片页脚、Logo alt

**刻意不动**:localStorage/sessionStorage 的 `voicehub_*` 键、`voicehub:` 前缀的
STORAGE_KEY 与缓存/Redis 前缀、`window.voiceHubPlayer` 之类代码标识、MeoW 的
User-Agent、以及上游项目链接 `github.com/laoshuikaixue/VoiceHub`(那是对原项目的署名)。

注意:站点名**数据**(systemSettings.siteTitle)仍是你后台里设置的「宝一外校园点歌」,
代码只保证默认值与文案一致;要让全站显示完整名称,请在后台「站点配置 → 站点标题」
改成「宝一外校园点歌系统」。
2026-09-30 20:24:55 +08:00

270 lines
6.0 KiB
Vue
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.
<template>
<div class="auth-layout">
<div class="auth-container">
<div class="form-section">
<div class="form-header">
<div class="logo-row">
<img
:src="brandLogoSrc"
alt="Brand Logo"
class="brand-logo-center"
width="96"
height="96"
decoding="async"
fetchpriority="high"
>
<div v-if="schoolLogoHomeUrl && schoolLogoHomeUrl.trim()" class="logo-divider" />
<img
v-if="schoolLogoHomeUrl && schoolLogoHomeUrl.trim()"
:src="schoolLogoHomeUrl"
alt="学校Logo"
class="school-logo"
width="160"
height="160"
decoding="async"
fetchpriority="high"
>
</div>
<h1 class="form-title">宝一外校园点歌系统</h1>
<div class="header-divider" />
</div>
<div class="forgot-password-form">
<div class="page-intro">
<h2 class="page-heading">找回密码</h2>
<p class="page-subtitle">请联系管理员重置您的账号密码</p>
</div>
<div class="contact-card">
<div class="contact-card-icon">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<div class="contact-card-body">
<h3>联系管理员</h3>
<p>为保障账号安全,系统暂未开放自助密码找回。请通过以下方式联系管理员进行密码重置:</p>
<ul class="contact-tips">
<li>站内联系:登录有管理员权限的账号</li>
<li>线下联系:前往广播站办公室或指导老师</li>
<li>邮件联系:如有公开的管理员邮箱</li>
</ul>
</div>
</div>
<div class="form-actions">
<NuxtLink to="/login" class="back-to-login-btn">
返回登录
</NuxtLink>
</div>
</div>
</div>
</div>
<SiteFooter />
</div>
</template>
<script setup>
import { onMounted, computed } from 'vue'
import logo from '~~/public/images/logo.png'
const { siteTitle, initSiteConfig, schoolLogoHomeUrl } = useSiteConfig()
const brandLogoSrc = computed(() => {
return logo
})
onMounted(async () => {
await initSiteConfig()
if (typeof document !== 'undefined' && siteTitle.value) {
document.title = `找回密码 | ${siteTitle.value}`
}
})
</script>
<style scoped>
.auth-layout {
min-height: 100vh;
background: var(--bg-primary);
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding: 20px;
}
.auth-container {
width: 100%;
max-width: 520px;
background: var(--bg-secondary);
border-radius: var(--radius-2xl);
border: 1px solid var(--border-primary);
box-shadow: var(--shadow-lg);
overflow: hidden;
margin: auto 0;
margin-bottom: 40px;
}
.form-section {
padding: 40px 32px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: var(--bg-secondary);
}
.form-header {
text-align: center;
margin-bottom: 24px;
width: 100%;
}
.logo-row {
display: flex;
align-items: center;
justify-content: center;
gap: 24px;
margin-bottom: 12px;
}
.logo-divider {
width: 1px;
height: 96px;
background: var(--border-secondary);
}
.brand-logo-center {
width: 96px;
height: 96px;
object-fit: contain;
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.15));
}
.school-logo {
width: 160px;
height: 160px;
object-fit: contain;
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.15));
}
.form-title {
font-size: 24px;
font-weight: var(--font-bold);
margin: 0;
color: var(--text-primary);
}
.header-divider {
height: 1px;
background: var(--border-secondary);
margin: 14px auto 0;
width: 100%;
}
.forgot-password-form {
width: 100%;
max-width: 400px;
}
.page-intro {
text-align: center;
margin-bottom: 28px;
}
.page-heading {
font-size: 28px;
font-weight: var(--font-bold);
color: var(--text-primary);
margin: 0 0 8px 0;
}
.page-subtitle {
font-size: 14px;
color: var(--text-tertiary);
margin: 0;
}
.contact-card {
display: flex;
gap: 16px;
padding: 24px;
background: var(--bg-tertiary);
border: 1px solid var(--border-secondary);
border-radius: var(--radius-lg);
margin-bottom: 28px;
}
.contact-card-icon {
width: 40px;
height: 40px;
border-radius: 12px;
background: rgba(59, 130, 246, 0.12);
color: var(--primary);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.contact-card-icon svg {
width: 20px;
height: 20px;
}
.contact-card-body h3 {
font-size: 16px;
font-weight: var(--font-semibold);
color: var(--text-primary);
margin: 0 0 8px 0;
}
.contact-card-body p {
font-size: 14px;
color: var(--text-secondary);
margin: 0 0 12px 0;
line-height: 1.6;
}
.contact-tips {
margin: 0;
padding-left: 18px;
color: var(--text-secondary);
font-size: 13px;
line-height: 1.9;
}
.form-actions {
display: flex;
flex-direction: column;
gap: 12px;
}
.back-to-login-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 14px;
background: var(--btn-primary-bg);
color: var(--btn-primary-text);
border: 1px solid var(--btn-primary-border);
border-radius: var(--radius-lg);
font-size: 16px;
font-weight: var(--font-semibold);
text-decoration: none;
transition: all 0.2s ease;
}
.back-to-login-btn:hover {
background: var(--btn-primary-hover);
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
@media (max-width: 768px) {
.auth-layout { padding: 10px; }
.auth-container { border-radius: 16px; }
.form-section { padding: 30px 20px; }
.contact-card { padding: 18px; gap: 12px; }
}
</style>