Files
piano-plan/docs/FRONTEND_ARCH.md
hmo e50a9207b4 feat: v1.4.0 - 典型方案采纳、推荐方案列表、审计字段、导航优化
- 添加典型方案采纳功能 (POST /api/plans/<id>/adopt)
- 添加推荐方案列表 (GET /api/students/<id>/recommended-plans)
- PracticePlan 新增 created_by/updated_by/updated_at 审计字段
- 方案编辑/详情页导航优化 (bfcache 处理、pageshow 事件)
- 方案列表支持删除功能
- 学员列表'暂无方案/问题'样式统一
- 更新文档:问题文件已废弃(迁移到数据库)
- 更新部署脚本和验证清单
2026-04-27 02:01:22 +08:00

283 lines
8.8 KiB
Markdown
Raw Permalink 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.
# 前端架构规范
> 本文档定义钢琴练习方案系统的模板架构设计,作为前端开发的遵循规范。
## 1. 模板架构
### 1.1 继承模式
所有业务页面必须继承自 `base.html`
```
base.html (基础模板)
├── index.html (学员管理)
├── home.html (默认首页)
├── student.html (学员详情)
├── plan_edit.html (方案编辑)
├── settings.html (问题配置)
├── classes.html (班级管理)
├── users.html (用户管理)
├── templates.html (模板管理)
└── api_settings.html (API设置)
```
### 1.2 base.html 结构
`base.html` 统一管理以下公共部分:
| 部分 | 说明 |
|------|------|
| CDN 引入 | Bootstrap 5.3, Bootstrap Icons, EasyMDE, Tabulator |
| 基础 CSS | body, sidebar, main-content, card 样式 |
| 移动端响应式 | 汉堡菜单、侧边栏展开/收起 |
| 顶部导航栏 | 移动端显示(固定在顶部) |
| 侧边栏结构 | 桌面端显示 |
| 公共 JS | toggleMobileNav, logout, showChangePasswordModal |
| 修改密码弹窗 | 统一放在 base 中 |
### 1.3 Jinja2 Blocks
| Block 名称 | 位置 | 用途 |
|------------|------|------|
| `title` | `<head><title>` | 页面标题 |
| `extra_css` | `<head>` 末尾 | 额外 CSS(如 CDN 样式链接) |
| `page_css` | `<style>` 末尾 | 页面特定 CSS |
| `sidebar_nav` | 侧边栏 `<nav>` 内 | 导航链接 |
| `content` | 主内容区 | 页面主要内容 HTML |
| `extra_js` | `</body>` 前 | 额外 JS(如 CDN 脚本、页面业务逻辑) |
## 2. 新页面创建规范
### 2.1 最小模板示例
```html
{% extends "base.html" %}
{% block title %}页面标题 - 钢琴练习方案系统{% endblock %}
{% block page_css %}
<style>
/* 仅放置页面特有的 CSS */
</style>
{% endblock %}
{% block sidebar_nav %}
<!-- 复制 base.html 的导航结构,根据当前页面的 active 状态调整 -->
<a class="nav-link" href="/">
<i class="bi bi-people"></i> 学员管理
</a>
<!-- ... 其他链接 ... -->
{% endblock %}
{% block content %}
<!-- 页面主要内容 HTML -->
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/xxx/xxx.min.js"></script>
<script>
// 页面业务逻辑 JS
</script>
{% endblock %}
```
### 2.2 侧边栏导航 active 状态
当前页面对应的链接需要添加 `active` class
```html
<a class="nav-link active" href="/settings">
<i class="bi bi-gear"></i> 问题配置
</a>
```
### 2.3 用户信息显示
base.html 在移动端和桌面端都有用户信息占位符,页面 JS 需要在 DOMContentLoaded 中设置:
```javascript
document.addEventListener('DOMContentLoaded', function() {
fetch('/api/check-login').then(r => r.json()).then(data => {
const userDisplay = data.username + ' (' + (data.role === 'admin' ? '管理员' : '普通用户') + ')';
document.getElementById('currentUserDisplay').textContent = userDisplay;
const mobileDisplay = document.getElementById('mobileUserDisplay');
if (mobileDisplay) mobileDisplay.textContent = userDisplay;
});
});
```
## 3. 移动端响应式设计
### 3.1 断点
| 断点 | 屏幕宽度 | 布局 |
|------|----------|------|
| 桌面端 | ≥ 768px | 侧边栏固定在左侧,主内容区在右侧 |
| 移动端 | < 768px | 顶部导航栏 + 隐藏侧边栏(汉堡按钮展开) |
### 3.2 CSS 规范
所有移动端样式统一写在 `base.html``@media (max-width: 767.98px)` 块中,各页面不需要重复定义。
侧边栏移动端样式(base.html):
```css
/* 移动端响应式 */
@media (max-width: 767.98px) {
.sidebar {
position: fixed;
top: 60px; /* 向下偏移,避免被顶部导航栏挡住 */
left: 0;
width: 100%;
min-height: auto;
max-height: calc(100vh - 60px); /* 最大高度为屏幕高度减去导航栏 */
z-index: 1040;
overflow-y: auto;
transform: translateY(-100%); /* 默认隐藏 */
transition: transform 0.3s ease;
}
.sidebar.collapsed {
transform: translateY(-100%); /* 隐藏状态 */
}
.sidebar:not(.collapsed) {
transform: translateY(0); /* 显示状态 */
}
.main-content {
margin-top: 60px;
padding: 10px;
}
.mobile-nav-toggle {
display: flex !important;
}
}
```
### 3.3 移动端导航栏 HTMLbase.html
```html
<nav class="mobile-nav-toggle navbar navbar-dark bg-dark d-flex d-md-none"
style="position:fixed;top:0;left:0;right:0;z-index:1050;padding:10px;">
<div class="container-fluid d-flex justify-content-between align-items-center">
<div>
<span class="navbar-brand mb-0"><i class="bi bi-music-note-beamed"></i> 钢琴方案</span>
<small id="mobileUserDisplay" class="d-block text-white-50" style="font-size:10px;"></small>
</div>
<button class="btn btn-outline-light btn-sm" onclick="toggleMobileNav()">
<i class="bi bi-list"></i>
</button>
</div>
</nav>
```
**注意**
- `mobile-nav-toggle` 类控制显示/隐藏(桌面端隐藏,移动端显示)
- `z-index: 1050` 确保在侧边栏之上(侧边栏是 1040)
## 4. JavaScript 规范
### 4.1 公共函数(base.html 提供)
| 函数 | 用途 |
|------|------|
| `toggleMobileNav()` | 切换侧边栏展开/收起 |
| `logout()` | 退出登录 |
| `showChangePasswordModal()` | 显示修改密码弹窗 |
### 4.2 页面 JS 放置
- 公共函数(如 `showToast`)放在 `extra_js` block 中
- 页面初始化逻辑放在 `document.addEventListener('DOMContentLoaded', ...)`
- 业务函数在 `extra_js` block 中定义
### 4.3 修改密码
base.html 已包含修改密码弹窗 HTML 和 JS。各页面不需要重复定义 `showChangePasswordModal()` 和相关 DOM 绑定。
## 5. 避免重复代码
### 5.1 禁止重复的内容
以下内容**禁止**在各页面模板中重复定义:
- `<head>` 标签内容(meta, title, CDN 链接)
- 基础 CSSbody, sidebar, card 等)
- 移动端响应式 CSS
- 移动端顶部导航栏 HTML
- 侧边栏 HTML 结构
- Bootstrap JS CDN
- `toggleMobileNav()`, `logout()`, `showChangePasswordModal()` 函数
- 修改密码弹窗 HTML 和 JS
### 5.2 正确做法
| 如果需要... | 应该... |
|-------------|---------|
| 页面特定 CSS | 在 `{% block page_css %}` 中添加 |
| 额外 JS 库 | 在 `{% block extra_js %}` 开头引入 |
| 页面业务逻辑 | 在 `{% block extra_js %}` 中定义 |
| 导航 active 状态 | 在 `{% block sidebar_nav %}` 中设置 |
## 6. 文件结构
```
app/templates/
├── base.html # 基础模板(核心,统一侧边栏)
├── index.html # 学员管理
├── home.html # 默认首页(统计信息)
├── student.html # 学员详情(URL导航)
├── plan_edit.html # 方案编辑(URL导航)
├── settings.html # 问题配置
├── classes.html # 班级管理
├── users.html # 用户管理
├── templates.html # 模板管理
├── api_settings.html # API设置
├── login.html # 登录页(独立,无侧边栏)
├── setup.html # 初始化页(独立)
└── wechat_card.html # 微信卡片(独立)
```
> 注意:`login.html`、`setup.html`、`wechat_card.html` 是独立页面,不继承 base.html。
## 7. URL 导航模式
系统支持两种导航模式:
| 模式 | 说明 | 示例 |
|------|------|------|
| SPA 模式 | 点击学员卡片弹窗查看详情 | 原 index.html 模式 |
| URL 模式 | 通过 URL 直接访问 | `/student/<id>`, `/plan/<id>/edit` |
推荐使用 URL 模式,便于分享和书签。
## 8. 更新日志
| 日期 | 版本 | 变更内容 |
|------|------|----------|
| 2026-04-21 | v1.0 | 初始文档,定义 base.html 模板继承模式 |
| 2026-04-23 | v1.1 | 添加 URL 导航模式说明;新增 home.html, student.html, plan_edit.html |
| 2026-04-27 | v1.2 | 方案编辑/详情页导航优化:bfcache 处理、pageshow 事件、sessionStorage 标记 |
## 9. 方案编辑页面导航
### 9.1 编辑流程
```
学员详情/方案列表 → 方案详情 → 编辑 → 保存 → 返回方案详情/学员详情/方案列表
```
### 9.2 导航实现
| 操作 | 实现方式 |
|------|----------|
| 保存后返回 | `history.back()` 返回上一页(编辑页),浏览器从 bfcache 恢复方案详情页 |
| 方案详情加载 | `pageshow` 事件检测 bfcache 恢复,自动调用 `loadPlan()` 刷新数据 |
| 返回按钮 | `history.back()` 返回上一页 |
### 9.3 sessionStorage 标记
| 标记 | 用途 |
|------|------|
| `plan_detail_referrer` | 记录方案详情页的来源(student/plans),编辑保存后用于决定跳转目标 |
| `needs_refresh_recommended` | 标记需要刷新推荐方案列表 |
| `plans_needs_refresh` | 标记需要刷新方案列表页 |