作品展示页:前端展示 + 后台增删改查

- 新增 projects 表与迁移(唯一 slug 索引)
- 后端:公开 GET /api/projects,后台 GET/POST/PUT/DELETE /api/admin/projects
- 前端:/projects 双虚线边框卡片页(参考 diygod.cc/projects),后台管理页
- 左栏/手机顶栏/后台侧栏均加「作品」入口
- 补充项目 CRUD 单元测试与后台鉴权拦截测试
This commit is contained in:
Sakurasan
2026-09-22 01:47:59 +08:00
parent 2b53eb976b
commit 3238175ef0
14 changed files with 1029 additions and 1 deletions
+30
View File
@@ -52,6 +52,36 @@ type Tag struct {
Count int `json:"count"`
}
// Project is a showcase entry rendered on the public /projects page. It links
// out to an external homepage and (optionally) a source repository.
type Project struct {
ID int64 `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
Summary string `json:"summary"`
CoverURL string `json:"cover_url"`
URL string `json:"url"`
RepoURL string `json:"repo_url"`
Status string `json:"status"`
Position int `json:"position"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// ProjectInput carries the editable fields for a project. A blank Slug or
// Status is filled in by the store (slug from Title, status defaults to
// published) so the admin UI can omit them.
type ProjectInput struct {
Title string `json:"title"`
Slug string `json:"slug"`
Summary string `json:"summary"`
CoverURL string `json:"cover_url"`
URL string `json:"url"`
RepoURL string `json:"repo_url"`
Status string `json:"status"`
Position int `json:"position"`
}
type ArchiveMonth struct {
Month string `json:"month"`
Posts []Post `json:"posts"`