573 lines
27 KiB
Markdown
573 lines
27 KiB
Markdown
# Design Document
|
||
|
||
## Overview
|
||
|
||
本设计文档描述"内容与辅助"模块从老项目(PHP ThinkPHP + Layui)迁移到新项目(ASP.NET Core + Vue 3 + Element Plus)的技术设计方案。该模块包含三个子模块:单页管理(Danye)、悬浮球配置(FloatBall)、福利屋入口(WelfareHouse)。
|
||
|
||
## Architecture
|
||
|
||
### 系统架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 前端 (Vue 3 + Element Plus) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ views/business/ │
|
||
│ ├── danye/ # 单页管理页面 │
|
||
│ │ ├── list.vue # 单页列表 │
|
||
│ │ └── components/ # 组件 │
|
||
│ ├── floatball/ # 悬浮球配置页面 │
|
||
│ │ ├── list.vue # 悬浮球列表 │
|
||
│ │ └── components/ # 组件 │
|
||
│ └── welfarehouse/ # 福利屋入口页面 │
|
||
│ ├── list.vue # 福利屋列表 │
|
||
│ └── components/ # 组件 │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ api/business/ │
|
||
│ ├── danye.ts # 单页API │
|
||
│ ├── floatball.ts # 悬浮球API │
|
||
│ └── welfarehouse.ts # 福利屋API │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 后端 (ASP.NET Core) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ HoneyBox.Admin.Business/ │
|
||
│ ├── Controllers/ │
|
||
│ │ ├── DanyeController.cs │
|
||
│ │ ├── FloatBallController.cs │
|
||
│ │ └── WelfareHouseController.cs │
|
||
│ ├── Services/ │
|
||
│ │ ├── DanyeService.cs │
|
||
│ │ ├── FloatBallService.cs │
|
||
│ │ └── WelfareHouseService.cs │
|
||
│ └── Models/ │
|
||
│ ├── Danye/ │
|
||
│ ├── FloatBall/ │
|
||
│ └── WelfareHouse/ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 数据库 (SQL Server) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ ├── danye # 单页内容表 (已存在) │
|
||
│ ├── float_ball_config # 悬浮球配置表 (已存在) │
|
||
│ └── welfare_house # 福利屋配置表 (已存在) │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 数据库实体(已存在)
|
||
|
||
#### Danye 实体
|
||
```csharp
|
||
public class Danye
|
||
{
|
||
public int Id { get; set; }
|
||
public string Title { get; set; }
|
||
public string Content { get; set; }
|
||
public int UpdateTime { get; set; }
|
||
public byte Status { get; set; }
|
||
public byte IsImageOptimizer { get; set; }
|
||
}
|
||
```
|
||
|
||
#### FloatBallConfig 实体
|
||
```csharp
|
||
public class FloatBallConfig
|
||
{
|
||
public int Id { get; set; }
|
||
public byte Status { get; set; }
|
||
public byte Type { get; set; } // 1展示图片 2跳转页面
|
||
public string Image { get; set; }
|
||
public string LinkUrl { get; set; }
|
||
public string PositionX { get; set; }
|
||
public string PositionY { get; set; }
|
||
public string Width { get; set; }
|
||
public string Height { get; set; }
|
||
public byte Effect { get; set; } // 0无 1缩放动画
|
||
public string? Title { get; set; }
|
||
public string? ImageDetails { get; set; }
|
||
public string? ImageBj { get; set; }
|
||
public string? ImageDetailsX { get; set; }
|
||
public string? ImageDetailsY { get; set; }
|
||
public string? ImageDetailsW { get; set; }
|
||
public string? ImageDetailsH { get; set; }
|
||
public DateTime CreatedAt { get; set; }
|
||
public DateTime UpdatedAt { get; set; }
|
||
}
|
||
```
|
||
|
||
#### WelfareHouse 实体
|
||
```csharp
|
||
public class WelfareHouse
|
||
{
|
||
public int Id { get; set; }
|
||
public string Name { get; set; }
|
||
public string Image { get; set; }
|
||
public string Url { get; set; }
|
||
public int Sort { get; set; }
|
||
public byte Status { get; set; }
|
||
public int? CreateTime { get; set; }
|
||
public int? UpdateTime { get; set; }
|
||
}
|
||
```
|
||
|
||
## Components
|
||
|
||
### 后端组件
|
||
|
||
#### 1. DanyeController
|
||
- `GET /api/business/danye` - 获取单页列表
|
||
- `GET /api/business/danye/{id}` - 获取单页详情
|
||
- `PUT /api/business/danye/{id}` - 更新单页内容
|
||
- `PUT /api/business/danye/{id}/image-optimizer` - 切换图片优化状态
|
||
|
||
#### 2. FloatBallController
|
||
- `GET /api/business/floatball` - 获取悬浮球列表(分页)
|
||
- `GET /api/business/floatball/{id}` - 获取悬浮球详情
|
||
- `POST /api/business/floatball` - 新增悬浮球
|
||
- `PUT /api/business/floatball/{id}` - 更新悬浮球
|
||
- `DELETE /api/business/floatball/{id}` - 删除悬浮球
|
||
- `PUT /api/business/floatball/{id}/status` - 切换状态
|
||
|
||
#### 3. WelfareHouseController
|
||
- `GET /api/business/welfarehouse` - 获取福利屋列表(分页)
|
||
- `GET /api/business/welfarehouse/{id}` - 获取福利屋详情
|
||
- `POST /api/business/welfarehouse` - 新增福利屋入口
|
||
- `PUT /api/business/welfarehouse/{id}` - 更新福利屋入口
|
||
- `DELETE /api/business/welfarehouse/{id}` - 删除福利屋入口
|
||
- `PUT /api/business/welfarehouse/{id}/status` - 切换状态
|
||
|
||
### 前端组件
|
||
|
||
#### 1. 单页管理模块
|
||
- `DanyeList.vue` - 单页列表页面
|
||
- `DanyeTable.vue` - 单页表格组件
|
||
- `DanyeFormDialog.vue` - 单页编辑弹窗(含富文本编辑器)
|
||
|
||
#### 2. 悬浮球配置模块
|
||
- `FloatBallList.vue` - 悬浮球列表页面
|
||
- `FloatBallTable.vue` - 悬浮球表格组件
|
||
- `FloatBallFormDialog.vue` - 悬浮球表单弹窗
|
||
|
||
#### 3. 福利屋入口模块
|
||
- `WelfareHouseList.vue` - 福利屋列表页面
|
||
- `WelfareHouseTable.vue` - 福利屋表格组件
|
||
- `WelfareHouseFormDialog.vue` - 福利屋表单弹窗
|
||
|
||
## Data Models
|
||
|
||
### 后端 Models
|
||
|
||
#### Danye Models
|
||
```csharp
|
||
// 列表响应
|
||
public class DanyeResponse
|
||
{
|
||
public int Id { get; set; }
|
||
public string Title { get; set; }
|
||
public bool IsImageOptimizer { get; set; }
|
||
public DateTime UpdateTime { get; set; }
|
||
}
|
||
|
||
// 详情响应
|
||
public class DanyeDetailResponse
|
||
{
|
||
public int Id { get; set; }
|
||
public string Title { get; set; }
|
||
public string Content { get; set; }
|
||
public bool IsImageOptimizer { get; set; }
|
||
}
|
||
|
||
// 更新请求
|
||
public class DanyeUpdateRequest
|
||
{
|
||
public string? Title { get; set; }
|
||
public string Content { get; set; }
|
||
}
|
||
```
|
||
|
||
#### FloatBall Models
|
||
```csharp
|
||
// 列表请求
|
||
public class FloatBallListRequest
|
||
{
|
||
public int Page { get; set; } = 1;
|
||
public int PageSize { get; set; } = 10;
|
||
}
|
||
|
||
// 响应
|
||
public class FloatBallResponse
|
||
{
|
||
public int Id { get; set; }
|
||
public string? Title { get; set; }
|
||
public int Type { get; set; }
|
||
public string Image { get; set; }
|
||
public string? ImageBj { get; set; }
|
||
public string? ImageDetails { get; set; }
|
||
public string LinkUrl { get; set; }
|
||
public string PositionX { get; set; }
|
||
public string PositionY { get; set; }
|
||
public string Width { get; set; }
|
||
public string Height { get; set; }
|
||
public string? ImageDetailsX { get; set; }
|
||
public string? ImageDetailsY { get; set; }
|
||
public string? ImageDetailsW { get; set; }
|
||
public string? ImageDetailsH { get; set; }
|
||
public int Effect { get; set; }
|
||
public int Status { get; set; }
|
||
public DateTime CreatedAt { get; set; }
|
||
}
|
||
|
||
// 创建/更新请求
|
||
public class FloatBallCreateRequest
|
||
{
|
||
public string? Title { get; set; }
|
||
public int Type { get; set; }
|
||
public string Image { get; set; }
|
||
public string? ImageBj { get; set; }
|
||
public string? ImageDetails { get; set; }
|
||
public string? LinkUrl { get; set; }
|
||
public string PositionX { get; set; }
|
||
public string PositionY { get; set; }
|
||
public string Width { get; set; }
|
||
public string Height { get; set; }
|
||
public string? ImageDetailsX { get; set; }
|
||
public string? ImageDetailsY { get; set; }
|
||
public string? ImageDetailsW { get; set; }
|
||
public string? ImageDetailsH { get; set; }
|
||
public int Effect { get; set; }
|
||
public int Status { get; set; } = 1;
|
||
}
|
||
```
|
||
|
||
#### WelfareHouse Models
|
||
```csharp
|
||
// 列表请求
|
||
public class WelfareHouseListRequest
|
||
{
|
||
public int Page { get; set; } = 1;
|
||
public int PageSize { get; set; } = 10;
|
||
}
|
||
|
||
// 响应
|
||
public class WelfareHouseResponse
|
||
{
|
||
public int Id { get; set; }
|
||
public string Name { get; set; }
|
||
public string Image { get; set; }
|
||
public string Url { get; set; }
|
||
public int Sort { get; set; }
|
||
public int Status { get; set; }
|
||
public DateTime? CreateTime { get; set; }
|
||
}
|
||
|
||
// 创建/更新请求
|
||
public class WelfareHouseCreateRequest
|
||
{
|
||
public string Name { get; set; }
|
||
public string Image { get; set; }
|
||
public string Url { get; set; }
|
||
public int Sort { get; set; }
|
||
public int Status { get; set; } = 1;
|
||
}
|
||
```
|
||
|
||
### 前端 TypeScript 接口
|
||
|
||
```typescript
|
||
// Danye
|
||
interface DanyeResponse {
|
||
id: number
|
||
title: string
|
||
isImageOptimizer: boolean
|
||
updateTime: string
|
||
}
|
||
|
||
interface DanyeDetailResponse {
|
||
id: number
|
||
title: string
|
||
content: string
|
||
isImageOptimizer: boolean
|
||
}
|
||
|
||
interface DanyeUpdateRequest {
|
||
title?: string
|
||
content: string
|
||
}
|
||
|
||
// FloatBall
|
||
interface FloatBallListRequest {
|
||
page: number
|
||
pageSize: number
|
||
}
|
||
|
||
interface FloatBallResponse {
|
||
id: number
|
||
title?: string
|
||
type: number
|
||
image: string
|
||
imageBj?: string
|
||
imageDetails?: string
|
||
linkUrl: string
|
||
positionX: string
|
||
positionY: string
|
||
width: string
|
||
height: string
|
||
imageDetailsX?: string
|
||
imageDetailsY?: string
|
||
imageDetailsW?: string
|
||
imageDetailsH?: string
|
||
effect: number
|
||
status: number
|
||
createdAt: string
|
||
}
|
||
|
||
interface FloatBallCreateRequest {
|
||
title?: string
|
||
type: number
|
||
image: string
|
||
imageBj?: string
|
||
imageDetails?: string
|
||
linkUrl?: string
|
||
positionX: string
|
||
positionY: string
|
||
width: string
|
||
height: string
|
||
imageDetailsX?: string
|
||
imageDetailsY?: string
|
||
imageDetailsW?: string
|
||
imageDetailsH?: string
|
||
effect: number
|
||
status?: number
|
||
}
|
||
|
||
// WelfareHouse
|
||
interface WelfareHouseListRequest {
|
||
page: number
|
||
pageSize: number
|
||
}
|
||
|
||
interface WelfareHouseResponse {
|
||
id: number
|
||
name: string
|
||
image: string
|
||
url: string
|
||
sort: number
|
||
status: number
|
||
createTime?: string
|
||
}
|
||
|
||
interface WelfareHouseCreateRequest {
|
||
name: string
|
||
image: string
|
||
url: string
|
||
sort: number
|
||
status?: number
|
||
}
|
||
```
|
||
|
||
## API Design
|
||
|
||
### 单页管理 API
|
||
|
||
| 方法 | 路径 | 描述 | 请求体 | 响应 |
|
||
|------|------|------|--------|------|
|
||
| GET | /api/business/danye | 获取单页列表 | - | `ApiResponse<List<DanyeResponse>>` |
|
||
| GET | /api/business/danye/{id} | 获取单页详情 | - | `ApiResponse<DanyeDetailResponse>` |
|
||
| PUT | /api/business/danye/{id} | 更新单页内容 | `DanyeUpdateRequest` | `ApiResponse<bool>` |
|
||
| PUT | /api/business/danye/{id}/image-optimizer | 切换图片优化 | `{ isImageOptimizer: bool }` | `ApiResponse<bool>` |
|
||
|
||
### 悬浮球配置 API
|
||
|
||
| 方法 | 路径 | 描述 | 请求体 | 响应 |
|
||
|------|------|------|--------|------|
|
||
| GET | /api/business/floatball | 获取悬浮球列表 | Query: page, pageSize | `PagedResponse<FloatBallResponse>` |
|
||
| GET | /api/business/floatball/{id} | 获取悬浮球详情 | - | `ApiResponse<FloatBallResponse>` |
|
||
| POST | /api/business/floatball | 新增悬浮球 | `FloatBallCreateRequest` | `ApiResponse<int>` |
|
||
| PUT | /api/business/floatball/{id} | 更新悬浮球 | `FloatBallCreateRequest` | `ApiResponse<bool>` |
|
||
| DELETE | /api/business/floatball/{id} | 删除悬浮球 | - | `ApiResponse<bool>` |
|
||
| PUT | /api/business/floatball/{id}/status | 切换状态 | `{ status: int }` | `ApiResponse<bool>` |
|
||
|
||
### 福利屋入口 API
|
||
|
||
| 方法 | 路径 | 描述 | 请求体 | 响应 |
|
||
|------|------|------|--------|------|
|
||
| GET | /api/business/welfarehouse | 获取福利屋列表 | Query: page, pageSize | `PagedResponse<WelfareHouseResponse>` |
|
||
| GET | /api/business/welfarehouse/{id} | 获取福利屋详情 | - | `ApiResponse<WelfareHouseResponse>` |
|
||
| POST | /api/business/welfarehouse | 新增福利屋入口 | `WelfareHouseCreateRequest` | `ApiResponse<int>` |
|
||
| PUT | /api/business/welfarehouse/{id} | 更新福利屋入口 | `WelfareHouseCreateRequest` | `ApiResponse<bool>` |
|
||
| DELETE | /api/business/welfarehouse/{id} | 删除福利屋入口 | - | `ApiResponse<bool>` |
|
||
| PUT | /api/business/welfarehouse/{id}/status | 切换状态 | `{ status: int }` | `ApiResponse<bool>` |
|
||
|
||
## UI Design
|
||
|
||
### 单页管理页面
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 单页管理 │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||
│ │ ID │ 标题 │ 图片优化 │ 更新时间 │ 操作 │ │
|
||
│ ├────┼────────────────────────┼─────────┼───────────┼───────┤ │
|
||
│ │ 1 │ 关于我们 │ [开关] │ 2026-01-18│ [编辑]│ │
|
||
│ │ 2 │ 用户协议 │ [开关] │ 2026-01-18│ [编辑]│ │
|
||
│ │ 3 │ 隐私政策 │ [开关] │ 2026-01-18│ [编辑]│ │
|
||
│ └─────────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 单页编辑弹窗
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 编辑单页 [X] │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 标题: [关于我们________________] (ID 2-20 不可编辑) │
|
||
│ │
|
||
│ 内容: │
|
||
│ ┌─────────────────────────────────────────────────────────────┐│
|
||
│ │ [B] [I] [U] [图片] [链接] ... ││
|
||
│ ├─────────────────────────────────────────────────────────────┤│
|
||
│ │ ││
|
||
│ │ 富文本编辑区域 ││
|
||
│ │ ││
|
||
│ └─────────────────────────────────────────────────────────────┘│
|
||
│ │
|
||
│ [取消] [保存] │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 悬浮球列表页面
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 悬浮球配置 [+ 新增] │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||
│ │ ID │ 标题 │ 图片 │ 背景图 │ 详情图 │ 类型 │ 链接 │ 位置 │ ... │ │
|
||
│ ├────┼─────┼─────┼───────┼───────┼─────┼─────┼─────┼─────┤ │
|
||
│ │ 1 │ 活动 │ [img]│ [img] │ [img] │ 跳转 │ /act│ 10,20│ ... │ │
|
||
│ │ 2 │ 客服 │ [img]│ - │ - │ 展示 │ - │ 10,80│ ... │ │
|
||
│ └─────────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 共 2 条 < 1 > │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 悬浮球表单弹窗
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 新增悬浮球 [X] │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 标题: [____________________] │
|
||
│ │
|
||
│ 类型: (●) 展示图片 ( ) 跳转页面 │
|
||
│ │
|
||
│ 悬浮球图片: [上传] [预览] │
|
||
│ 背景图片: [上传] [预览] │
|
||
│ 详情图片: [上传] [预览] │
|
||
│ │
|
||
│ 跳转链接: [____________________] (类型为跳转时显示) │
|
||
│ │
|
||
│ 位置设置: │
|
||
│ X: [____] Y: [____] │
|
||
│ │
|
||
│ 尺寸设置: │
|
||
│ 宽: [____] 高: [____] │
|
||
│ │
|
||
│ 详情图位置: │
|
||
│ X: [____] Y: [____] 宽: [____] 高: [____] │
|
||
│ │
|
||
│ 特效: [无特效 ▼] │
|
||
│ 状态: [开关] │
|
||
│ │
|
||
│ [取消] [保存] │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 福利屋入口列表页面
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 福利屋入口 [+ 新增] │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||
│ │ ID │ 名称 │ 图片 │ 链接 │ 排序 │ 状态 │ 创建时间 │ 操作│
|
||
│ ├────┼─────────┼──────┼──────────┼─────┼─────┼─────────┼─────┤ │
|
||
│ │ 1 │ 签到有礼 │ [img] │ /sign │ 1 │ [开关]│ 01-18 │ [编辑][删除]│
|
||
│ │ 2 │ 新人福利 │ [img] │ /newbie │ 2 │ [开关]│ 01-18 │ [编辑][删除]│
|
||
│ └─────────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 共 2 条 < 1 > │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 福利屋入口表单弹窗
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 新增福利屋入口 [X] │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 名称: [____________________] * │
|
||
│ │
|
||
│ 图片: [上传] [预览] * │
|
||
│ │
|
||
│ 跳转链接: [____________________] * │
|
||
│ │
|
||
│ 排序: [____] * │
|
||
│ │
|
||
│ 状态: [开关] │
|
||
│ │
|
||
│ [取消] [保存] │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## Security Considerations
|
||
|
||
1. **权限控制**: 所有 API 需要验证管理员登录状态和权限
|
||
2. **输入验证**: 后端对所有输入进行验证,防止 XSS 和 SQL 注入
|
||
3. **富文本安全**: 富文本内容需要进行 HTML 净化处理
|
||
4. **图片上传**: 验证图片类型和大小,防止恶意文件上传
|
||
|
||
## Performance Considerations
|
||
|
||
1. **分页加载**: 悬浮球和福利屋列表使用分页加载
|
||
2. **图片懒加载**: 表格中的图片使用懒加载
|
||
3. **富文本编辑器**: 按需加载富文本编辑器组件
|
||
|
||
## Testing Strategy
|
||
|
||
1. **单元测试**: 后端 Service 层单元测试
|
||
2. **API 测试**: 使用 Swagger 测试 API 接口
|
||
3. **前端组件测试**: Vue 组件单元测试
|
||
4. **属性测试**: 验证搜索、分页、表单验证等通用属性
|
||
|
||
## Dependencies
|
||
|
||
### 后端依赖
|
||
- Entity Framework Core (已有)
|
||
- Mapster (已有)
|
||
|
||
### 前端依赖
|
||
- Element Plus (已有)
|
||
- WangEditor 或 TinyMCE (富文本编辑器,需确认项目中使用的编辑器)
|
||
- Vue Router (已有)
|
||
|
||
## References
|
||
|
||
- Requirements: `.kiro/specs/content-auxiliary-frontend/requirements.md`
|
||
- PHP 参考代码: `server/php/app/admin/controller/Danye.php`
|
||
- PHP 参考代码: `server/php/app/admin/controller/FloatBall.php`
|
||
- PHP 参考代码: `server/php/app/admin/controller/WelfareHouse.php`
|
||
- 实体定义: `server/HoneyBox/src/HoneyBox.Model/Entities/Danye.cs`
|
||
- 实体定义: `server/HoneyBox/src/HoneyBox.Model/Entities/FloatBallConfig.cs`
|
||
- 实体定义: `server/HoneyBox/src/HoneyBox.Model/Entities/WelfareHouse.cs`
|