Skip to Content
Week 11📋 Week 11 阶段检查

Week 11 - 阶段检查

这一页用来确认 Week 11 是否真正掌握:权限能限制动作,审计能追踪操作,导入能解释错误,后台任务能显示进度,设置能保存恢复,RC 能按清单交付。

本周学习地图

阶段先掌握什么最终能写什么
权限角色、权限点、服务层检查能限制关键动作
审计操作人、动作、结果、时间能追踪成功和失败
导入导出行级校验、错误报告能解释导入失败原因
后台任务进度、取消、恢复状态能处理耗时操作
设置默认值、保存、加载能保存用户偏好
RC发布候选、验收清单能进入发布前检查

本周自测项目:商品管理增强版

在 Week 10 MVP 上继续加功能,至少包含:

  • Viewer 不能删除商品,Admin 可以删除。
  • 新增、编辑、删除都写审计日志。
  • CSV 导入能输出成功行和失败行。
  • 导入过程显示进度并支持取消。
  • 设置页能保存默认分类或数据目录。
  • 生成 RC 检查清单。

过关标准:能证明项目不是只能演示主流程,错误流程也能处理。

上位机阶段验收:现场交付功能完善

本周目标: 增加权限、审计、点位批量导入、稳定重连、设置和发布候选版。

必须亲手完成:

  1. 三种角色权限在界面和服务层都生效
  2. 关键修改留下前后值审计
  3. 断网后显示离线,恢复后自动重连

过关标准: 使用测试账号和故障演练逐项验收,并留下日志、截图和检查表。

不要只看答案。新建一个空项目重做一次,运行成功后再故意改坏一处并自己排错。

本周流程图

用户执行操作 -> PermissionService 检查权限 -> Service 执行业务规则 -> AuditLog 记录成功或失败 -> 导入导出按行返回结果 -> BackgroundTask 显示进度并支持取消 -> Settings 保存和恢复偏好 -> RC 清单判断是否能发布

前半部分:本周原理地图

Week 11 的主线是:

给商品管理项目补上可靠性能力,让它不只是能用,还能控制、追踪、恢复、验收和交付。

能力地图

能力解决的问题最小判断
权限谁能执行关键动作Viewer 不能删,Admin 能删
审计谁做过什么成功和失败都能查到记录
导入导出数据怎么进出系统成功行导入,错误行有原因
后台任务耗时任务不阻塞界面有进度、能取消、能恢复状态
设置偏好用户配置能保存默认值、保存、加载、恢复默认
发布候选交付前能验收README、CHANGELOG、清单齐全

本周通过线

达到下面这些,Week 11 才算过关:

  1. 能写出角色和权限表。
  2. 能在服务层检查权限。
  3. 能写审计日志字段:用户、动作、对象、时间、结果。
  4. 能导入 CSV,并记录错误行。
  5. 能导出成功数据。
  6. 能写后台任务的进度和取消。
  7. 能把设置保存为 JSON 并恢复默认。
  8. 能写发布候选清单。

Week 11 必须会用的操作

主题必须会的写法
角色enum Role、Viewer、Editor、Admin
权限CanDeleteHashSet<string>、权限名常量
审计AuditEntry、用户、动作、目标、时间、结果
CSV 导入ReadAllLinesSplitTrimTryParse、错误行
CSV 导出string.JoinWriteAllLines
后台任务async TaskCancellationTokenSourceProgressIsBusy
设置AppSettings、JSON、默认值、Normalize
发布候选restorebuildtestpublish、README、CHANGELOG

下半部分:阶段检查完整答案

下面这份程序把 Week 11 的关键能力压缩成一个可运行检查。

它会检查:

  • 权限拒绝和权限成功。
  • 审计记录。
  • CSV 导入成功和失败。
  • 设置非法值回退。
  • 后台任务进度。
  • 发布候选检查项。

检查题:Program.cs

using System; using System.Collections.Generic; using System.Linq; var auditLogs = new List<string>(); TryDelete(Role.Viewer, "Alice", auditLogs); TryDelete(Role.Admin, "Cindy", auditLogs); Console.WriteLine("审计日志:"); foreach (string log in auditLogs) { Console.WriteLine(log); } string[] csvLines = { "Id,Name,Price,Stock", "1,Keyboard,199,10", "2,,59,30", "3,Monitor,abc,5", "4,Mouse,59,20" }; ImportSummary importSummary = ImportProducts(csvLines); Console.WriteLine($"导入成功:{importSummary.SuccessCount}"); Console.WriteLine($"导入失败:{importSummary.Errors.Count}"); foreach (string error in importSummary.Errors) { Console.WriteLine(error); } AppSettings settings = NormalizeSettings(new AppSettings("Blue", 999, "")); Console.WriteLine($"设置:Theme={settings.Theme}, PageSize={settings.PageSize}, DataPath={settings.DataPath}"); await RunBackgroundJobAsync(progress => { Console.WriteLine($"后台任务进度:{progress}%"); }); string[] releaseChecklist = { "版本号已更新", "主流程已回归", "README 已写运行方式", "CHANGELOG 已写变更", "已知问题已记录" }; Console.WriteLine("发布候选检查:"); foreach (string item in releaseChecklist) { Console.WriteLine($"[x] {item}"); } void TryDelete(Role role, string user, List<string> audit) { if (role != Role.Admin) { audit.Add($"{DateTimeOffset.UtcNow:HH:mm:ss} {user} Product.Delete denied"); Console.WriteLine($"{user} 没有删除权限。"); return; } audit.Add($"{DateTimeOffset.UtcNow:HH:mm:ss} {user} Product.Delete success"); Console.WriteLine($"{user} 删除成功。"); } ImportSummary ImportProducts(IReadOnlyList<string> lines) { int successCount = 0; var errors = new List<string>(); var usedIds = new HashSet<int>(); for (int index = 1; index < lines.Count; index++) { int lineNumber = index + 1; string line = lines[index]; string[] parts = line.Split(','); if (parts.Length != 4) { errors.Add($"第 {lineNumber} 行:列数必须是 4。"); continue; } if (!int.TryParse(parts[0], out int id)) { errors.Add($"第 {lineNumber} 行:Id 必须是整数。"); continue; } if (!usedIds.Add(id)) { errors.Add($"第 {lineNumber} 行:Id 重复。"); continue; } if (string.IsNullOrWhiteSpace(parts[1])) { errors.Add($"第 {lineNumber} 行:Name 不能为空。"); continue; } if (!decimal.TryParse(parts[2], out decimal price) || price <= 0) { errors.Add($"第 {lineNumber} 行:Price 必须是大于 0 的数字。"); continue; } if (!int.TryParse(parts[3], out int stock) || stock < 0) { errors.Add($"第 {lineNumber} 行:Stock 必须是大于或等于 0 的整数。"); continue; } successCount++; } return new ImportSummary(successCount, errors); } AppSettings NormalizeSettings(AppSettings settings) { string theme = settings.Theme is "Light" or "Dark" ? settings.Theme : "Light"; int pageSize = settings.PageSize is >= 10 and <= 500 ? settings.PageSize : 50; string dataPath = string.IsNullOrWhiteSpace(settings.DataPath) ? "products.json" : settings.DataPath; return new AppSettings(theme, pageSize, dataPath); } async Task RunBackgroundJobAsync(Action<int> reportProgress) { for (int index = 1; index <= 5; index++) { await Task.Delay(80); reportProgress(index * 20); } } public enum Role { Viewer, Admin } public sealed record ImportSummary(int SuccessCount, IReadOnlyList<string> Errors); public sealed record AppSettings(string Theme, int PageSize, string DataPath);

运行命令

dotnet new console -n Week11Checkpoint cd Week11Checkpoint

把上面的代码放进 Program.cs,然后执行:

dotnet run

正确运行结果

Alice 没有删除权限。 Cindy 删除成功。 审计日志: ... 导入成功:2 导入失败:2 第 3 行:Name 不能为空。 第 4 行:Price 必须是大于 0 的数字。 设置:Theme=Light, PageSize=50, DataPath=products.json 后台任务进度:20% 后台任务进度:40% 后台任务进度:60% 后台任务进度:80% 后台任务进度:100% 发布候选检查: [x] 版本号已更新 [x] 主流程已回归 [x] README 已写运行方式 [x] CHANGELOG 已写变更 [x] 已知问题已记录

这份程序检查了什么

检查点合格标准
权限Viewer 被拒绝,Admin 成功
审计denied 和 success 都有记录
导入正确行成功,错误行有原因
设置非法主题、页大小、路径能回退
后台任务进度能到 100
发布候选交付检查项能列出

Avalonia 页面验收

后台任务页面

1. 点击开始后进度条变化。 2. 任务运行时开始按钮禁用。 3. 任务运行时取消按钮启用。 4. 点击取消后任务停止。 5. 完成或取消后界面状态恢复。

设置页面

1. 设置文件不存在时显示默认值。 2. 保存后生成 settings.json。 3. 重新加载能恢复保存值。 4. 非法页大小能提示或回退。 5. 恢复默认能回到 Light、50、products.json。

RC 交付验收

发布候选必须包含:

release-candidate/ app/ README.md CHANGELOG.md KNOWN-ISSUES.md RELEASE-CHECKLIST.md sample-data/

并且:

  1. dotnet build 通过。
  2. dotnet publish -c Release 通过。
  3. 从发布目录能启动。
  4. README 写清运行方式。
  5. CHANGELOG 写清本版变化。
  6. KNOWN-ISSUES 写清已知问题。
  7. RELEASE-CHECKLIST 可以逐项执行。

最终通过标准

这一页通过时,应该能做到:

  1. 运行阶段检查程序,输出和上面一致。
  2. 能说清权限和审计的关系。
  3. 能说清导入错误行为什么不能直接丢掉。
  4. 能说清后台任务的 IsBusyProgress、取消分别解决什么。
  5. 能说清设置默认值和非法值回退。
  6. 能准备一份 RC 交付清单。

Week 11 过关的标准是:项目不只会增删改查,还能限制动作、记录动作、处理外部数据、运行长任务、保存设置,并在交付前按清单验收。