18 KiB
Design Document
Overview
随工水印相机 2.0 系统升级设计,主要包含四个核心模块:
- 图片上传改造 - 将图片存储从服务器本地迁移到腾讯云 COS,实现客户端直传
- 数据导出 API - 提供分页查询接口供 CS 客户端调用
- CS 客户端 - Windows 桌面应用,实现本地 Excel 导出
- 历史数据迁移 - 将服务器本地图片迁移到 COS
Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ System Architecture │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ UniApp │ │ CS Client │ │ 腾讯云 COS │ │
│ │ (Mobile) │ │ (Windows) │ │ (ap-shanghai) │ │
│ └──────┬───────┘ └──────┬───────┘ └────────────┬─────────────┘ │
│ │ │ │ │
│ │ 1.获取预签名URL │ │ │
│ ├────────────────────┼──────────────────────────┤ │
│ │ │ │ │
│ │ 2.直传图片 ────────┼──────────────────────────► │
│ │ │ │ │
│ │ 3.保存记录 │ 4.查询/导出 │ │
│ ├────────────────────┼──────────────────────────┤ │
│ │ │ │ │
│ ▼ ▼ │ │
│ ┌──────────────────────────────────────────────────────┤ │
│ │ .NET API Server │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ CosService │ │ WorkRecord │ │ Migration │ │ │
│ │ │ │ │ Service │ │ Service │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ SQL Server │ │
│ │ Database │ │
│ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Components and Interfaces
1. COS Service (后端)
负责腾讯云 COS 相关操作,包括生成预签名 URL 和临时密钥。
public interface ICosService
{
/// <summary>
/// 生成批量上传预签名URL
/// </summary>
/// <param name="request">上传请求参数</param>
/// <returns>预签名URL列表</returns>
CosUploadUrlsResponse GetUploadUrls(CosUploadUrlsRequest request);
/// <summary>
/// 获取临时密钥(用于迁移)
/// </summary>
/// <returns>临时密钥信息</returns>
CosTempCredentials GetTempCredentials();
}
2. COS Controller (后端)
提供 COS 相关的 HTTP 接口。
[Route("api/cos")]
public class CosController : BaseController
{
/// <summary>
/// 获取上传预签名URL
/// POST /api/cos/getUploadUrls
/// </summary>
Task<IActionResult> GetUploadUrls([FromBody] CosUploadUrlsRequest request);
/// <summary>
/// 获取临时密钥
/// GET /api/cos/getTempCredentials
/// </summary>
Task<IActionResult> GetTempCredentials();
}
3. WorkRecord V3 接口 (后端)
新增支持 COS URL 的工作记录保存接口。
/// <summary>
/// 添加工作记录(COS直传 v3)
/// POST /addworkrecordv3
/// </summary>
Task<IActionResult> AddCamWorkRecordV3([FromBody] CamRecordWorkV3Dto parm);
4. Export API (后端)
提供数据导出查询接口。
[Route("api/workrecord/export")]
public class WorkRecordExportController : BaseController
{
/// <summary>
/// 分页查询工作记录(导出用)
/// GET /api/workrecord/export/list
/// </summary>
Task<IActionResult> GetExportList([FromQuery] WorkRecordExportQueryDto query);
}
5. Migration API (后端)
提供历史数据迁移相关接口。
[Route("api/workrecord/migration")]
public class WorkRecordMigrationController : BaseController
{
/// <summary>
/// 获取待迁移记录列表
/// GET /api/workrecord/migration/list
/// </summary>
Task<IActionResult> GetMigrationList([FromQuery] MigrationQueryDto query);
/// <summary>
/// 更新迁移后的URL
/// POST /api/workrecord/migration/update
/// </summary>
Task<IActionResult> UpdateMigrationUrls([FromBody] MigrationUpdateDto dto);
}
6. CS Client Architecture
┌─────────────────────────────────────────────────────────────────┐
│ CS Client (WinForms) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ MainForm │ │ MigrationForm │ │ LoginForm │ │
│ │ (导出界面) │ │ (迁移界面) │ │ (登录界面) │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Services Layer │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │
│ │ │ ApiService │ │ CosService │ │ ExcelService │ │ │
│ │ │ (HTTP调用) │ │ (COS上传) │ │ (Excel生成) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Data Models
1. COS 上传请求/响应 DTO
/// <summary>
/// COS上传URL请求
/// </summary>
public class CosUploadUrlsRequest
{
public DateTime RecordTime { get; set; }
public string DeptName { get; set; }
public string Content { get; set; }
public List<string> Workers { get; set; }
public string FileExt { get; set; } = ".jpg";
public int ImageCount { get; set; }
}
/// <summary>
/// COS上传URL响应
/// </summary>
public class CosUploadUrlsResponse
{
public List<CosImageUploadInfo> Images { get; set; }
}
/// <summary>
/// 单张图片上传信息
/// </summary>
public class CosImageUploadInfo
{
public string ImageId { get; set; }
public string FileName { get; set; }
public CosUploadUrls UploadUrls { get; set; }
public string AccessUrl { get; set; }
}
/// <summary>
/// 各分类目录的上传URL
/// </summary>
public class CosUploadUrls
{
public string Daily { get; set; }
public Dictionary<string, string> Workers { get; set; }
public string Content { get; set; }
public string Dept { get; set; }
}
2. 工作记录 V3 DTO
/// <summary>
/// 工作记录V3请求(COS直传)
/// </summary>
public class CamRecordWorkV3Dto
{
public int? Id { get; set; }
public string DeptName { get; set; }
public DateTime? RecordTime { get; set; }
public string Longitude { get; set; }
public string Latitude { get; set; }
public string Address { get; set; }
public string Content { get; set; }
public string StatusName { get; set; }
public string Remarks { get; set; }
public List<string> Workers { get; set; }
/// <summary>
/// COS图片URL列表(替代Base64)
/// </summary>
public List<string> ImageUrls { get; set; }
}
3. 导出查询 DTO
/// <summary>
/// 导出查询请求
/// </summary>
public class WorkRecordExportQueryDto
{
public int PageNum { get; set; } = 1;
public int PageSize { get; set; } = 50;
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string DeptName { get; set; }
public string WorkerName { get; set; }
public string Content { get; set; }
}
/// <summary>
/// 导出记录响应
/// </summary>
public class WorkRecordExportDto
{
public int Id { get; set; }
public string DeptName { get; set; }
public DateTime? RecordTime { get; set; }
public string Longitude { get; set; }
public string Latitude { get; set; }
public string Address { get; set; }
public string Content { get; set; }
public string StatusName { get; set; }
public List<string> Workers { get; set; }
public List<string> Images { get; set; }
public DateTime? CreateTime { get; set; }
public DateTime? UpdateTime { get; set; }
}
4. 迁移相关 DTO
/// <summary>
/// 迁移查询请求
/// </summary>
public class MigrationQueryDto
{
public int PageNum { get; set; } = 1;
public int PageSize { get; set; } = 50;
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public int? Status { get; set; } // 0-未迁移 1-已迁移 2-失败
}
/// <summary>
/// 迁移记录响应
/// </summary>
public class MigrationRecordDto
{
public int Id { get; set; }
public DateTime? RecordTime { get; set; }
public string DeptName { get; set; }
public string Content { get; set; }
public int ImageCount { get; set; }
public List<MigrationImageDto> Images { get; set; }
public int MigrationStatus { get; set; }
}
/// <summary>
/// 迁移URL更新请求
/// </summary>
public class MigrationUpdateDto
{
public int RecordId { get; set; }
public List<MigrationUrlPair> ImageUrls { get; set; }
}
public class MigrationUrlPair
{
public string OldUrl { get; set; }
public string NewUrl { get; set; }
}
COS Configuration
腾讯云 COS 配置将存储在 appsettings.json 中:
{
"TencentCOS": {
"AppId": "1308826010",
"Region": "ap-shanghai",
"SecretId": "AKIDVyMfzKZdZP8zkNyOdsFuSsBJDB7EScs0",
"SecretKey": "89GWr7JPWYTL8ueHlAYowGZnvzKZjqs9",
"BucketName": "miaoyu",
"DomainUrl": "https://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com",
"MaxSize": 100,
"DurationSecond": 600,
"Prefixes": "workfiles"
}
}
COS Directory Structure
保持与现有本地存储一致的目录结构:
/workfiles/{yyyyMM}/{yyyyMMdd}/
├── 当日照片/{timestamp}_{random}.jpg
├── 参与人员/{人员姓名}/{timestamp}_{random}.jpg
├── 工作内容/{工作内容}/{timestamp}_{random}.jpg
└── 部门/{部门名称}/{timestamp}_{random}.jpg
Correctness Properties
A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.
Property 1: Pre-signed URL Generation Completeness
For any valid upload request with N images and M workers, the API SHALL return exactly N image entries, each containing:
- 1 daily photo URL
- M worker directory URLs (one per worker)
- 1 content directory URL
- 1 department directory URL
- All URLs following the pattern
/workfiles/{yyyyMM}/{yyyyMMdd}/{category}/{subcategory}/{timestamp}_{random}.{ext}
Validates: Requirements 1.1, 1.2, 1.4, 1.5
Property 2: COS URL Validation
For any URL submitted to the V3 interface, the system SHALL accept only URLs matching the COS domain pattern https://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com/workfiles/... and reject all other URLs.
Validates: Requirements 3.3
Property 3: V3 Record Save Integrity
For any valid V3 save request with N image URLs, the system SHALL:
- Create exactly one work record in database
- Store all N image URLs in the image table
- Return the created record ID and image count = N
Validates: Requirements 3.1, 3.4
Property 4: Export Pagination Consistency
For any export query with total N records and page size P, iterating through all ceil(N/P) pages SHALL return exactly N unique records with no duplicates or missing entries. Page size SHALL be capped at 50 regardless of requested value.
Validates: Requirements 4.1, 4.2, 4.4
Property 5: Export Filter Accuracy
For any export query with filters (date range, department, worker, content), all returned records SHALL match ALL specified filter criteria.
Validates: Requirements 4.3
Property 6: Migration List Filter
For any migration list query with status filter, all returned records SHALL have the specified migration status (0-unmigrated, 1-migrated, 2-failed).
Validates: Requirements 10.1, 10.2
Property 7: Migration URL Update Integrity
For any migration update request with N URL pairs, the system SHALL:
- Validate all new URLs are valid COS URLs
- Update all N URLs atomically (all succeed or all fail)
- Preserve the mapping between old and new URLs
Validates: Requirements 10.3, 10.4
Error Handling
API Error Responses
| 错误码 | 说明 | 处理方式 |
|---|---|---|
| 400 | 参数错误 | 返回具体错误字段 |
| 401 | 未授权 | 要求重新登录 |
| 403 | 无权限 | 提示权限不足 |
| 500 | 服务器错误 | 记录日志,返回友好提示 |
COS 上传错误处理
- 预签名 URL 过期 - 客户端重新获取 URL
- 上传失败 - 客户端重试最多 3 次
- 部分上传成功 - 记录失败的目录,允许重试
CS 客户端错误处理
- 网络超时 - 自动重试,显示重试进度
- 下载失败 - 跳过失败图片,记录日志
- Excel 生成失败 - 保存已下载数据,允许重新生成
Testing Strategy
Unit Tests
使用 xUnit 进行单元测试:
-
CosService Tests
- 测试预签名 URL 生成逻辑
- 测试目录路径生成
- 测试文件名生成
-
WorkRecordService Tests
- 测试 V3 接口数据保存
- 测试查询过滤逻辑
- 测试分页逻辑
-
MigrationService Tests
- 测试迁移状态判断
- 测试 URL 更新逻辑
Property-Based Tests
使用 FsCheck 进行属性测试:
-
Property 1: Pre-signed URL Generation Completeness
- 生成随机的上传请求参数
- 验证返回的 URL 数量和结构
-
Property 4: Pagination Consistency
- 生成随机数量的测试数据
- 验证分页遍历的完整性
Integration Tests
-
COS 集成测试
- 测试实际上传到 COS
- 测试预签名 URL 有效性
-
API 集成测试
- 测试完整的上传流程
- 测试导出 API 响应
CS Client Tests
-
API 调用测试
- Mock API 响应测试
- 错误处理测试
-
Excel 生成测试
- 测试 Excel 格式正确性
- 测试图片嵌入功能