1 changed files with 240 additions and 0 deletions
-
240readme.md
@ -0,0 +1,240 @@ |
|||
# Mach-CMS 前端项目 README(readme-front) |
|||
|
|||
> 仓库:`mach-cms-frontend` | 责任方:Agent2 |
|||
> 状态:开发中 | 当前契约:OpenAPI **v0.3.1**(以 `openapi.yaml` 为准) |
|||
|
|||
--- |
|||
|
|||
## 1. 项目简介 |
|||
|
|||
Mach-CMS 前端是 CMS 的 **Vue 3 + TypeScript** 单页应用,独立仓库,消费后端 `mach-cms-backend` 的 REST API,包含**前台**(文章浏览/搜索/评论/点赞)与**管理后台**(文章/标签/评论/用户管理)两大部分,整体采用**宋韵风格(SongUI)** UI 主题,内置暗色模式。 |
|||
|
|||
前端遵循**契约驱动开发(CDD)**:所有 API 类型与客户端代码由 `openapi.yaml` 经 **OpenAPI Generator** 生成,**禁止手写类型**。 |
|||
|
|||
--- |
|||
|
|||
## 2. 技术栈 |
|||
|
|||
| 技术 | 版本 | 用途 | |
|||
|------|------|------| |
|||
| Vue | 3.5+ | 框架(`<script setup lang="ts">`) | |
|||
| TypeScript | 5.6+ | 严格模式 | |
|||
| Vite | 5.4+ | 构建工具 | |
|||
| Vue Router | 4.5+ | 路由 + 权限守卫 | |
|||
| Pinia | 2.3+ | 状态管理(认证等) | |
|||
| Axios | 1.7+ | HTTP 客户端(统一拦截器) | |
|||
| OpenAPI Generator | 7.6.0 | 从 YAML 生成 TS 类型 + API 客户端(typescript-axios) | |
|||
| Quill.js | 2.0+ | 富文本编辑器(文章编辑) | |
|||
| github-markdown-css | 5.9+ | 文章详情页 GitHub 风格渲染 | |
|||
| DOMPurify | 3.2+ | HTML 过滤,防 XSS | |
|||
| marked / marked-highlight | 18.x / 2.2 | Markdown 渲染(旧文章兼容)+ 代码高亮 | |
|||
| highlight.js | 11.1+ | 代码块语法高亮 | |
|||
| lxgw-wenkai-webfont | 1.7+ | 霞鹜文楷 Web 字体 | |
|||
| SongUI(内置组件) | — | 宋韵设计契约组件(`src/components/Song*` + `song-theme.css`) | |
|||
| Playwright | 1.62+ | 验收测试(`scripts/acceptance/`,devDependency) | |
|||
|
|||
--- |
|||
|
|||
## 3. 项目结构 |
|||
|
|||
``` |
|||
mach-cms-frontend/ |
|||
├── openapitools.json # OpenAPI Generator 配置 |
|||
├── openapi.yaml # API 契约(唯一事实来源) |
|||
├── vite.config.ts # dev proxy / 构建优化 |
|||
├── scripts/acceptance/ # Playwright 验收测试脚本 |
|||
└── src/ |
|||
├── main.ts |
|||
├── App.vue |
|||
├── api/ |
|||
│ └── client.ts # Axios 实例 + 拦截器 + 全部 API 客户端导出(唯一入口) |
|||
├── stores/ |
|||
│ └── auth.ts # Pinia 认证 store |
|||
├── router/ |
|||
│ └── index.ts # 路由 + 守卫(requiresAuth / requiresAdmin)+ SEO |
|||
├── generated/ |
|||
│ └── api/ # ⚠️ 生成代码,禁止手改(单文件输出) |
|||
│ ├── api.ts # 所有 API 类与 TS 类型(合并单文件) |
|||
│ ├── base.ts / configuration.ts / common.ts / index.ts |
|||
│ └── ... |
|||
├── composables/ |
|||
│ ├── useApi.ts # 泛型请求封装(loading / error / 分页) |
|||
│ └── useTheme.ts # 明暗主题切换(localStorage 持久化) |
|||
├── utils/ |
|||
│ ├── markdown.ts # marked + 代码高亮 + DOMPurify 渲染 |
|||
│ ├── readingTime.ts # 阅读时间估计 |
|||
│ └── seo.ts # document.title + OpenGraph meta |
|||
├── styles/ |
|||
│ ├── song-theme.css # SongUI 设计令牌(天青昼 / 黛墨夜) |
|||
│ └── markdown-override.css # 文章渲染样式覆盖 |
|||
├── assets/ |
|||
│ └── markdown-override.css |
|||
├── views/ # 页面组件 |
|||
│ ├── HomeView.vue # 首页 |
|||
│ ├── LoginView.vue # 登录 |
|||
│ ├── RegisterView.vue # 注册 |
|||
│ ├── ArticleDetailView.vue # 文章详情(评论区、Star) |
|||
│ ├── SearchView.vue # 搜索(标签推荐 + 热门文章) |
|||
│ ├── NotFoundView.vue # 404 |
|||
│ └── admin/ |
|||
│ ├── AdminLayout.vue # 管理后台布局(顶部置顶 bar) |
|||
│ ├── ArticleListView.vue # 文章管理表格(图标操作) |
|||
│ ├── ArticleEditorView.vue # 文章编辑(Quill.js + 自动保存) |
|||
│ ├── TagListView.vue # 标签管理 |
|||
│ ├── CommentReviewView.vue # 评论审核(待审核列表) |
|||
│ └── UserListView.vue # 用户管理(角色/状态) |
|||
└── components/ # 通用组件 |
|||
├── ArticleCard.vue |
|||
├── ArticleMetaBar.vue |
|||
├── CommentSection.vue |
|||
├── Pagination.vue |
|||
├── QuillEditor.vue |
|||
├── TagCloud.vue |
|||
└── Song*(SongButton / SongCard / SongInput / SongTag) # SongUI 基础组件 |
|||
``` |
|||
|
|||
> 注:OpenAPI Generator 的 `typescript-axios` 为**单文件输出**(所有类型合并到 `api.ts`),类名为单数(如 `CommentApi` 而非 `CommentsApi`),属生成器正常行为,**禁止手动改类名**。 |
|||
|
|||
--- |
|||
|
|||
## 4. API 客户端(`src/api/client.ts`) |
|||
|
|||
全部实例化于 `client.ts`,`basePath` 固定为 `''`(配合 Vite 代理,避免 `/api/api` 双重前缀): |
|||
|
|||
```ts |
|||
export const publicApi = new PublicApi(config, '', axiosInstance) |
|||
export const authApi = new AuthApi(config, '', axiosInstance) |
|||
export const articleApi = new ArticleApi(config, '', axiosInstance) |
|||
export const articleAdminApi = new ArticleAdminApi(config, '', axiosInstance) |
|||
export const tagApi = new TagApi(config, '', axiosInstance) |
|||
export const tagAdminApi = new TagAdminApi(config, '', axiosInstance) |
|||
export const mediaApi = new MediaApi(config, '', axiosInstance) |
|||
export const searchApi = new SearchApi(config, '', axiosInstance) |
|||
export const commentApi = new CommentApi(config, '', axiosInstance) |
|||
export const commentAdminApi = new CommentAdminApi(config, '', axiosInstance) |
|||
export const userApi = new UserApi(config, '', axiosInstance) |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 5. 路由一览(`src/router/index.ts`) |
|||
|
|||
| 路径 | 组件 | 守卫 | |
|||
|------|------|------| |
|||
| `/` | HomeView | — | |
|||
| `/post/:slug` | ArticleDetailView | — | |
|||
| `/search` | SearchView | — | |
|||
| `/login` / `/register` | LoginView / RegisterView | `guestOnly` | |
|||
| `/admin` | AdminLayout(重定向 `/admin/articles`) | `requiresAuth` | |
|||
| `/admin/articles` | ArticleListView | `requiresAuth` | |
|||
| `/admin/articles/new` `/admin/articles/edit/:id` | ArticleEditorView | `requiresAuth` | |
|||
| `/admin/tags` | TagListView | `requiresAuth` | |
|||
| `/admin/users` | UserListView | `requiresAdmin` | |
|||
| `/admin/comments` | CommentReviewView | `requiresAdmin` | |
|||
| `/:pathMatch(.*)*` | NotFoundView | — | |
|||
|
|||
--- |
|||
|
|||
## 6. 核心功能 |
|||
|
|||
| 区域 | 功能 | |
|||
|------|------| |
|||
| 前台 | 文章列表 / 详情 / 全文搜索 / 标签云 / 热门文章 / 阅读时间估计 | |
|||
| 评论区 | 发表评论(免登录,提交后 PENDING 待审核)、登录态自动填充昵称邮箱(只读)、时间线样式、折叠表单 | |
|||
| Star 点赞 | 文章 / 评论点赞,未登录点击提示并跳登录页 | |
|||
| 认证 | 登录 / 注册 / 登出,Access 过期静默刷新(401 自动 refresh) | |
|||
| 管理后台 | 文章 CRUD + 发布/归档(图标操作)、标签管理、评论审核(通过/驳回/删除)、用户管理(角色/状态)、媒体上传 | |
|||
| 编辑器 | Quill 富文本 + 60s 自动保存 + 离线检测;草稿按 id 加载 | |
|||
| SEO | OpenGraph meta 注入、`document.title` 随路由更新 | |
|||
| 体验 | 宋韵主题、暗色模式、水波纹装饰、GitHub 风格文章渲染、404 页面 | |
|||
|
|||
--- |
|||
|
|||
## 7. 快速开始(本地开发) |
|||
|
|||
```bash |
|||
# 前置:Node.js 20+,后端已启动 |
|||
npm install |
|||
|
|||
# 生成 API 客户端(每次 openapi.yaml 更新后执行) |
|||
npm run api:generate |
|||
|
|||
# 开发启动(默认端口 5173) |
|||
npm run dev |
|||
|
|||
# 构建(vue-tsc 类型检查 + vite build) |
|||
npm run build |
|||
|
|||
# 验收测试(Playwright,需先 npm run build 或 dev) |
|||
node scripts/acceptance/acc_*.cjs |
|||
``` |
|||
|
|||
开发环境通过 Vite 代理请求后端: |
|||
|
|||
```ts |
|||
// vite.config.ts |
|||
server: { |
|||
proxy: { |
|||
'/api': { target: 'http://localhost:9480', changeOrigin: true }, |
|||
'/uploads': { target: 'http://localhost:9480', changeOrigin: true } |
|||
} |
|||
} |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 8. 关键注意事项(红线) |
|||
|
|||
### 8.1 契约驱动纪律 |
|||
|
|||
1. **禁止手写 API 类型**,必须从 `openapi.yaml` 生成(`npm run api:generate`)。 |
|||
2. 后端契约更新后,先 `chore(api-gen): regenerate from openapi.yaml` 再对接。 |
|||
3. **禁止直接 import axios**,统一走 `src/api/client.ts` 导出的实例。 |
|||
|
|||
### 8.2 basePath 纪律(易错点) |
|||
|
|||
生成代码默认带 `/api` 前缀,叠加 Vite 代理会变成 `/api/api/xxx`。**每次重新生成代码后**,检查 `client.ts` 中 API 实例化的 basePath 必须为 `''`(见第 4 节)。 |
|||
|
|||
### 8.3 代码规范 |
|||
|
|||
| # | 规则 | |
|||
|---|------| |
|||
| 1 | 组件统一 `<script setup lang="ts">` | |
|||
| 2 | 异步操作必须 `try/catch`,错误统一 Toast/Notification 提示 | |
|||
| 3 | 路由参数用 `useRoute()`,类型安全 | |
|||
| 4 | 图片上传用 `FormData`,Content-Type 由浏览器自动设置 | |
|||
| 5 | 所有 API 调用带 `loading` 状态(禁用按钮 / 骨架屏 / spinner) | |
|||
| 6 | 渲染用户内容(评论、文章)必须经 DOMPurify 过滤,防 XSS | |
|||
| 7 | 文章内容渲染用 `github-markdown-css` 的 `.markdown-body` 类 | |
|||
| 8 | 标题字体用 `Noto Serif SC`(思源宋体)回退系统宋体 | |
|||
| 9 | 颜色使用 SongUI 设计令牌(`--song-*` 变量),对比度 ≥ 4.5:1 | |
|||
|
|||
### 8.4 Git 规范 |
|||
|
|||
- 直接基于 `main` 开发,commit 后 30 秒内立即 push。 |
|||
- 格式:`type(scope): subject`(Conventional Commits)。 |
|||
- 前端 scope:`page` / `component` / `store` / `api` / `router` / `type` / `asset` / `config` / `contract`。 |
|||
- 提交前必须 `npm run build` 通过,少量多次(单 commit 单意图,文件 ≤ 10)。 |
|||
- 提交顺序:`feat(contract)`(架构方)→ 后端实现 → `chore(api-gen)` → `feat(page/component)`。 |
|||
|
|||
--- |
|||
|
|||
## 9. 与后端联调 |
|||
|
|||
- **契约对账**:以 Swagger UI(`http://localhost:9480/swagger-ui.html`)为准,前后端各自对照 `openapi.yaml` 自查。 |
|||
- **开发代理**:本地前端 → `localhost:9480`;生产经 Nginx `:9434` 反代 `/api/`。 |
|||
- **认证流程**:登录成功后将 access/refresh Token 存入 localStorage,请求拦截器自动携带 `Authorization: Bearer`。 |
|||
- **401 处理**:响应拦截器自动用 refreshToken 换新 accessToken 并重放请求;刷新失败清除 Token 并跳转登录页。 |
|||
- **未登录访问后台**:路由守卫跳转 `/login`;非管理员访问 `/admin/users`、`/admin/comments` 被拦截回 `/admin/articles`。 |
|||
|
|||
--- |
|||
|
|||
## 10. 验收自查 |
|||
|
|||
- [ ] `npm run api:generate` 成功,生成 `src/generated/api/` |
|||
- [ ] `npm run dev` 无 TS 类型错误,`npm run build` 通过 |
|||
- [ ] 能调通 `/api/public/health` |
|||
- [ ] 登录 Token 正确入库(localStorage),401 自动刷新 |
|||
- [ ] 文章列表 / 详情 / 搜索 / 标签云 / 评论区 / Star 全部可用 |
|||
- [ ] 后台文章管理(图标操作)、标签管理、评论审核、用户管理可用 |
|||
- [ ] 未登录访问 `/admin/*` 被守卫拦截跳登录页 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue