feat: Banner UI美化 & 新增文章/公告/图库/媒体管理等功能

- Banner: Ken Burns缩放动效、左右导航箭头、进度条指示器、hover暂停、暗角遮罩、shimmer按钮动画
- 新增文章管理(CRUD)与公开文章页
- 新增Banner/Gallery图片管理API
- 新增媒体管理页面
- 新增更新日志页面
- 新增页面访问追踪
- 新增Markdown渲染组件
- .gitignore排除.cursor目录

Made-with: Cursor
This commit is contained in:
rucky
2026-03-25 09:17:35 +08:00
parent 241a76caeb
commit bf92a69332
66 changed files with 5241 additions and 155 deletions

641
API.md Normal file
View File

@@ -0,0 +1,641 @@
# Nanami Web API 文档
Base URL: `https://nui.rucky.cn`
---
## 目录
- [公开接口](#公开接口)
- [服务器时间](#服务器时间)
- [检查更新](#检查更新)
- [启动器最新版本](#启动器最新版本)
- [软件版本下载](#软件版本下载)
- [插件列表](#插件列表)
- [插件详情](#插件详情)
- [插件版本下载](#插件版本下载)
- [Banner 列表](#banner-列表)
- [画廊图片列表](#画廊图片列表)
- [管理接口(需认证)](#管理接口需认证)
- [软件管理](#软件管理)
- [软件版本管理](#软件版本管理)
- [插件管理](#插件管理)
- [插件版本发布](#插件版本发布)
- [Banner 管理](#banner-管理)
- [画廊管理](#画廊管理)
- [文件上传](#文件上传)
- [修改密码](#修改密码)
---
## 公开接口
### 服务器时间
获取服务器当前时间。
```
GET /api/server-time
```
**响应示例:**
```json
{
"timestamp": 1710748800000,
"iso": "2026-03-18T08:00:00.000Z",
"timezone": "Asia/Shanghai"
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `timestamp` | `number` | Unix 毫秒时间戳 |
| `iso` | `string` | ISO 8601 格式时间 |
| `timezone` | `string` | 服务器时区 |
---
### 检查更新
客户端检查软件是否有新版本可用。
```
GET /api/software/check-update?slug={slug}&versionCode={versionCode}
```
**查询参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `slug` | 是 | 软件标识符,如 `nanami-launcher` |
| `versionCode` | 否 | 当前客户端版本号(整数),默认 `0` |
**响应示例:**
```json
{
"hasUpdate": true,
"forceUpdate": false,
"latest": {
"version": "0.8.15",
"versionCode": 815,
"changelog": "修复了若干问题...",
"downloadUrl": "https://cdn.example.com/launcher-setup.exe",
"fileSize": 52428800,
"minVersion": "0.7.0",
"createdAt": "2026-03-15T10:00:00.000Z"
}
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `hasUpdate` | `boolean` | 是否有新版本 |
| `forceUpdate` | `boolean` | 是否需要强制更新 |
| `latest.version` | `string` | 最新版本号 |
| `latest.versionCode` | `number` | 最新版本编码 |
| `latest.changelog` | `string` | 更新日志 |
| `latest.downloadUrl` | `string` | 下载地址 |
| `latest.fileSize` | `number` | 文件大小(字节) |
| `latest.minVersion` | `string\|null` | 最低兼容版本 |
| `latest.createdAt` | `string` | 发布时间 |
---
### 启动器最新版本
获取启动器最新版本信息或直接下载。
#### 获取信息
```
GET /api/software/latest?info=1
```
添加 `&track=1` 可同时记录一次下载计数。
**响应示例:**
```json
{
"available": true,
"version": "0.8.15",
"versionCode": 815,
"changelog": "更新内容...",
"fileSize": 52428800,
"createdAt": "2026-03-15T10:00:00.000Z",
"downloadUrl": "https://cdn.example.com/launcher-setup.exe",
"downloadType": "url"
}
```
当无可用版本时返回:
```json
{ "available": false }
```
#### 直接下载
```
GET /api/software/latest
```
- 外部链接类型302 重定向到外部 URL
- 本地文件类型:返回文件流
- 自动记录下载次数
---
### 软件版本下载
按版本 ID 下载特定版本。
```
GET /api/software/download/{id}
```
**路径参数:**
| 参数 | 说明 |
|------|------|
| `id` | 软件版本 ID |
- 外部链接类型302 重定向
- 本地文件类型:返回文件流(`application/octet-stream`
- 自动记录下载次数
**错误响应:**
| 状态码 | 说明 |
|--------|------|
| `404` | 版本不存在或文件不存在 |
---
### 插件列表
获取已发布的插件列表。
```
GET /api/addons
```
**查询参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `category` | 否 | 按分类筛选 |
| `search` | 否 | 按名称/简介搜索(模糊匹配) |
| `published` | 否 | 默认 `true`,设为 `false` 查询所有 |
**响应示例:**
```json
[
{
"id": "clxx...",
"name": "插件名",
"slug": "addon-slug",
"summary": "插件简介",
"description": "详细描述...",
"iconUrl": "/uploads/icon.png",
"category": "ui",
"published": true,
"totalDownloads": 1024,
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-03-01T00:00:00.000Z",
"releases": [{ "...最新版本..." }],
"_count": { "releases": 5 }
}
]
```
---
### 插件详情
获取单个插件详细信息,包含所有版本和截图。
```
GET /api/addons/{id}
```
**路径参数:** `id` 可以是插件 ID 或 slug。
**响应:** 插件完整信息,含 `releases`(按时间倒序)和 `screenshots`(按排序序号)。
---
### 插件版本下载
```
GET /api/download/{id}
```
**路径参数:**
| 参数 | 说明 |
|------|------|
| `id` | Release 版本 ID |
- 自动增加 Release 和 Addon 的下载计数
- 外部链接类型302 重定向
- 本地文件类型:返回文件流
---
### Banner 列表
```
GET /api/banners
```
**查询参数:**
| 参数 | 说明 |
|------|------|
| `enabled` | 设为 `1` 仅返回已启用的 Banner |
**响应示例:**
```json
[
{
"id": "clxx...",
"imageUrl": "/banners/banner_1.png",
"sortOrder": 0,
"enabled": true,
"createdAt": "2026-01-01T00:00:00.000Z"
}
]
```
---
### 画廊图片列表
```
GET /api/gallery
```
**查询参数:**
| 参数 | 说明 |
|------|------|
| `enabled` | 设为 `1` 仅返回已启用的图片 |
**响应示例:**
```json
[
{
"id": "clxx...",
"imageUrl": "/views/view_1.png",
"title": "主界面",
"sortOrder": 0,
"enabled": true,
"createdAt": "2026-01-01T00:00:00.000Z"
}
]
```
---
## 管理接口(需认证)
以下接口需要管理员登录后的 Session 认证。未认证请求返回 `401 Unauthorized`
### 软件管理
#### 获取软件列表
```
GET /api/software
```
返回所有软件及其最新版本和版本数量。
#### 创建软件
```
POST /api/software
Content-Type: application/json
{
"name": "Nanami Launcher",
"slug": "nanami-launcher",
"description": "启动器描述"
}
```
| 字段 | 必填 | 说明 |
|------|------|------|
| `name` | 是 | 软件名称 |
| `slug` | 是 | 唯一标识符 |
| `description` | 否 | 描述 |
#### 获取软件详情
```
GET /api/software/{id}
```
`id` 可以是软件 ID 或 slug返回软件信息及所有版本。
#### 更新软件
```
PUT /api/software/{id}
Content-Type: application/json
{
"name": "新名称",
"slug": "new-slug",
"description": "新描述"
}
```
#### 删除软件
```
DELETE /api/software/{id}
```
---
### 软件版本管理
#### 创建新版本
```
POST /api/software/{id}/versions
Content-Type: application/json
{
"version": "1.0.0",
"versionCode": 100,
"changelog": "首次发布",
"downloadType": "url",
"externalUrl": "https://cdn.example.com/file.exe",
"fileSize": 52428800,
"forceUpdate": false,
"minVersion": null
}
```
| 字段 | 必填 | 类型 | 说明 |
|------|------|------|------|
| `version` | 是 | `string` | 版本号 |
| `versionCode` | 是 | `number` | 版本编码(用于比较) |
| `changelog` | 否 | `string` | 更新日志 |
| `downloadType` | 否 | `string` | `"local"``"url"`,默认 `"local"` |
| `filePath` | 否 | `string` | 本地文件路径 |
| `externalUrl` | 否 | `string` | 外部下载链接 |
| `fileSize` | 否 | `number` | 文件大小(字节) |
| `forceUpdate` | 否 | `boolean` | 是否强制更新 |
| `minVersion` | 否 | `string` | 最低兼容版本 |
新版本自动设为 `isLatest: true`,之前的最新版本会被取消。
#### 更新版本
```
PUT /api/software/versions/{versionId}
Content-Type: application/json
{
"version": "1.0.1",
"changelog": "修复问题",
"isLatest": true
}
```
所有字段均为可选,仅更新传入的字段。设置 `isLatest: true` 时自动取消其他版本的最新标记。
#### 删除版本
```
DELETE /api/software/versions/{versionId}
```
---
### 插件管理
#### 创建插件
```
POST /api/addons
Content-Type: application/json
{
"name": "插件名",
"slug": "addon-slug",
"summary": "简介",
"description": "详细描述",
"iconUrl": "/uploads/icon.png",
"category": "ui"
}
```
| 字段 | 必填 | 说明 |
|------|------|------|
| `name` | 是 | 插件名称 |
| `slug` | 是 | 唯一标识符 |
| `summary` | 是 | 简短描述 |
| `description` | 否 | 详细描述 |
| `iconUrl` | 否 | 图标 URL |
| `category` | 否 | 分类,默认 `"general"` |
#### 更新插件
```
PUT /api/addons/{id}
Content-Type: application/json
{
"name": "新名称",
"published": true
}
```
#### 删除插件
```
DELETE /api/addons/{id}
```
---
### 插件版本发布
```
POST /api/releases
Content-Type: application/json
{
"addonId": "插件ID",
"version": "1.0.0",
"changelog": "首次发布",
"downloadType": "url",
"externalUrl": "https://cdn.example.com/addon.zip",
"gameVersion": "11.1.0"
}
```
| 字段 | 必填 | 说明 |
|------|------|------|
| `addonId` | 是 | 所属插件 ID |
| `version` | 是 | 版本号 |
| `changelog` | 否 | 更新日志 |
| `downloadType` | 否 | `"local"``"url"` |
| `filePath` | 否 | 本地文件路径 |
| `externalUrl` | 否 | 外部链接(`downloadType``"url"` 时必填) |
| `gameVersion` | 否 | 适配的游戏版本 |
#### 获取版本列表
```
GET /api/releases?addonId={addonId}
```
---
### Banner 管理
#### 创建 Banner
```
POST /api/banners
Content-Type: application/json
{
"imageUrl": "/uploads/banner.png",
"sortOrder": 0,
"enabled": true
}
```
#### 更新 Banner
```
PUT /api/banners/{id}
Content-Type: application/json
{
"sortOrder": 1,
"enabled": false
}
```
#### 删除 Banner
```
DELETE /api/banners/{id}
```
---
### 画廊管理
#### 创建画廊图片
```
POST /api/gallery
Content-Type: application/json
{
"imageUrl": "/uploads/screenshot.png",
"title": "主界面截图",
"sortOrder": 0,
"enabled": true
}
```
#### 更新画廊图片
```
PUT /api/gallery/{id}
Content-Type: application/json
{
"title": "新标题",
"sortOrder": 2,
"enabled": true
}
```
#### 删除画廊图片
```
DELETE /api/gallery/{id}
```
---
### 文件上传
上传文件到服务器。
```
POST /api/upload
Content-Type: multipart/form-data
file: (二进制文件)
```
**响应示例:**
```json
{
"filePath": "/uploads/1710748800000-image.png",
"originalName": "image.png",
"size": 204800
}
```
返回的 `filePath` 可用于其他接口的 `imageUrl``filePath` 等字段。
---
### 修改密码
```
POST /api/admin/change-password
Content-Type: application/json
{
"currentPassword": "当前密码",
"newPassword": "新密码≥6位"
}
```
**错误响应:**
| 状态码 | 说明 |
|--------|------|
| `400` | 参数缺失或新密码过短 |
| `403` | 当前密码错误 |
| `404` | 用户不存在 |
---
## 通用错误格式
所有 API 错误均以 JSON 格式返回:
```json
{
"error": "错误描述信息"
}
```
| 状态码 | 说明 |
|--------|------|
| `400` | 请求参数错误 |
| `401` | 未认证 |
| `404` | 资源不存在 |
| `409` | 资源冲突(如 slug 重复) |
| `500` | 服务器内部错误 |