feat: 实现v1.2.0云同步与实体重构核心功能

1.  重构用户与任务实体:UserEntity实现IUser<Guid>,TaskEntity继承ABP风格FullAuditedEntityWithUser,主键从int改为Guid
2.  新增云同步代理系统:嵌入式WebServer支持CloudSyncProxy转发云同步请求,新增配置API与持久化
3.  完善前端适配:新增Guid工具函数,更新任务类型定义与API交互逻辑,调整云同步设置弹窗适配本地代理
4.  文档与配置优化:更新文档结构,新增部署文档、版本记录,统一各项目配置项
5.  补充测试与迁移:新增单元测试,更新EF Core数据库迁移快照
This commit is contained in:
ShaoHua
2026-06-14 04:51:22 +08:00
parent d81aa06681
commit 14868c45c7
51 changed files with 4368 additions and 449 deletions
@@ -22,14 +22,17 @@ public class TaskRepository : ITaskRepository
}
/// <summary>
/// 获取所有任务。
/// 获取所有任务(本地用户),平面加载以支持任意深度树构建
/// 不再使用 Include(t => t.SubTasks) 因为 EF Core 无法递归加载未知深度的子任务;
/// 树的构建交由 <see cref="TaskService.GetAllTasksAsync"/> 通过 parentTaskId 在内存中完成。
/// </summary>
/// <returns>包含所有任务实体的列表。</returns>
/// <returns>包含所有任务实体的平面列表。</returns>
public async Task<List<TaskEntity>> GetAllAsync()
{
return await _context.Tasks
.AsNoTracking()
.Where(t => t.UserId == TodoUserIds.LocalUserId)
.Include(t => t.SubTasks)
.OrderByDescending(t => t.CreationTime)
.ToListAsync();
}
@@ -38,7 +41,7 @@ public class TaskRepository : ITaskRepository
/// </summary>
/// <param name="id">任务 ID。</param>
/// <returns>匹配的任务实体;如果不存在则返回 null。</returns>
public async Task<TaskEntity?> GetByIdAsync(int id)
public async Task<TaskEntity?> GetByIdAsync(Guid id)
{
return await _context.Tasks
.Include(t => t.SubTasks)
@@ -53,7 +56,7 @@ public class TaskRepository : ITaskRepository
{
return await _context.Tasks
.Where(t => t.UserId == TodoUserIds.LocalUserId && !t.IsCompleted)
.OrderByDescending(t => t.CreatedAt)
.OrderByDescending(t => t.CreationTime)
.ToListAsync();
}
@@ -65,7 +68,7 @@ public class TaskRepository : ITaskRepository
{
return await _context.Tasks
.Where(t => t.UserId == TodoUserIds.LocalUserId && t.IsCompleted)
.OrderByDescending(t => t.UpdatedAt)
.OrderByDescending(t => t.LastModificationTime)
.ToListAsync();
}
@@ -77,6 +80,12 @@ public class TaskRepository : ITaskRepository
public async Task<TaskEntity> AddAsync(TaskEntity taskEntity)
{
taskEntity.UserId = TodoUserIds.LocalUserId;
if (taskEntity.Id == Guid.Empty)
{
taskEntity.Id = Guid.NewGuid();
}
taskEntity.CreationTime = DateTime.UtcNow;
taskEntity.CreatorId = taskEntity.UserId;
_context.Tasks.Add(taskEntity);
await _context.SaveChangesAsync();
return taskEntity;
@@ -89,18 +98,18 @@ public class TaskRepository : ITaskRepository
/// <returns>更新后的任务实体。</returns>
public async Task<TaskEntity> UpdateAsync(TaskEntity taskEntity)
{
taskEntity.UpdatedAt = DateTime.UtcNow;
taskEntity.LastModificationTime = DateTime.UtcNow;
taskEntity.LastModifierId = taskEntity.UserId;
_context.Tasks.Update(taskEntity);
await _context.SaveChangesAsync();
return taskEntity;
}
/// <summary>
/// 根据 ID 删除任务。
/// 根据 ID 删除任务(物理删除)
/// </summary>
/// <param name="id">要删除的任务 ID。</param>
/// <returns>表示删除操作的任务。</returns>
public async Task DeleteAsync(int id)
public async Task DeleteAsync(Guid id)
{
var task = await _context.Tasks.FirstOrDefaultAsync(t => t.Id == id && t.UserId == TodoUserIds.LocalUserId);
if (task != null)
@@ -115,11 +124,11 @@ public class TaskRepository : ITaskRepository
/// </summary>
/// <param name="parentTaskId">父任务 ID。</param>
/// <returns>子任务实体的列表。</returns>
public async Task<List<TaskEntity>> GetSubTasksAsync(int parentTaskId)
public async Task<List<TaskEntity>> GetSubTasksAsync(Guid parentTaskId)
{
return await _context.Tasks
.Where(t => t.UserId == TodoUserIds.LocalUserId && t.ParentTaskId == parentTaskId)
.OrderByDescending(t => t.CreatedAt)
.OrderByDescending(t => t.CreationTime)
.ToListAsync();
}
}
}