SeatFlow 的 .NET 10 双壳架构、Avalonia 12.1.3 + ReactiveUI/CTK 双范式技术栈、7 页信息架构、关键设计决策和策略管道概念
本页目录
全部文档
架构总览
项目目标
SeatFlow 是一个 .NET 10 跨平台座位编排系统,面向学校、培训机构和企业等需要批量座位安排的场景。系统同时提供桌面与浏览器双壳,核心能力包括:
- 多策略排座管道(固定座位、前排轮换、同桌分组、性别限制、历史防重复等)
- 多种教室布局支持(网格、极坐标、自由点)
- 多数据源导入(CSV、XLSX、JSON)
- 排座结果导出(Excel、CSV、PDF、图片;PDF/图片导出仅桌面可用)
- 历史快照与回滚
- 7 页信息架构:排座工作台(默认入口)、人员管理、会场与布局、策略配置、历史快照、设置、关于
- 桌面与浏览器双壳,共享同一套 UI 与业务逻辑
- 完整的国际化支持(zh-CN/en-US等)
分层架构
采用经典三层架构 + 双平台启动壳,遵循严格的分层依赖原则:
┌────────────────────────────┐ ┌────────────────────────────┐
│ SeatFlow.Desktop │ │ SeatFlow.Browser │
│ 桌面 EXE (SeatFlow) │ │ WASM 静态站 (wwwroot) │
│ Velopack / Watchdog / 单实例│ │ IndexedDB / 控制台日志 │
└──────────────┬─────────────┘ └─────────────┬──────────────┘
└───────────┬───────────────────┘
▼
┌─────────────────────────────────────────────┐
│ Presentation.Avalonia │
│ Avalonia 12.1.3 · ReactiveUI + CTK 双范式 │
│ MainView 共享外壳, 编译绑定, i18n │
│ net10.0;net10.0-browser │
└──────────────────────┬──────────────────────┘
│
┌──────────────────────▼──────────────────────┐
│ Application │
│ IApplicationFacade (外观) │
│ StrategyExecutionPipeline │
│ CommandHistory + DI 容器 │
└──────────────────────┬──────────────────────┘
│
┌─────────────────────┴─────────────────────┐
│ │
┌────────▼──────┐ ┌─────────▼──────┐
│ Core │ │ Infrastructure │
│ │ │ │
│ ┌───────────┐ │ │ Csv/Xlsx/Json │
│ │ Entities │ │ │ Providers │
│ │ Student │ │ │ Exporters │
│ │ Seat │ │ │ Repositories │
│ │ Layout │ │ │ Layouts │
│ ├───────────┤ │ │ MigrationSys │
│ │ Strategies│ │ │ FileSystem / │
│ │ 7 Builtin │ │ │ IndexedDb 存储 │
│ ├───────────┤ │ └────────────────┘
│ │ Domain │ │
│ │ Services │ │
│ ├───────────┤ │
│ │ILocalData │ │
│ │ Store │ │
│ └───────────┘ │
└───────────────┘
各层职责
| 层 | 项目 | 核心职责 |
|---|---|---|
| Core | SeatFlow.Core |
领域实体、策略接口和实现、领域服务、工作区、数据提供者接口、存储抽象 ILocalDataStore |
| Infrastructure | SeatFlow.Infrastructure |
数据提供者实现、导出器、布局构建器、仓库、文件迁移系统、序列化、平台存储实现 |
| Application | SeatFlow.Application |
UI 单一入口(外观)、策略管道执行器、命令模式、DI 注册 |
| Presentation | SeatFlow.Presentation.Avalonia |
共享 UI 类库(桌面 + 浏览器),Avalonia 12.1.3 + ReactiveUI/CTK 双范式,自绘 SeatingCanvas,7 页信息架构 |
| Desktop | SeatFlow.Desktop |
桌面启动壳:自动更新、Watchdog、单实例、文件关联 |
| Browser | SeatFlow.Browser |
浏览器启动壳:WASM 静态站发布 |
依赖关系链
SeatFlow.Desktop SeatFlow.Browser
└───────┬───────────┘
Presentation.Avalonia
└── Application
├── Core
└── Infrastructure
技术栈
| 技术 | 版本 | 用途 |
|---|---|---|
| .NET SDK | 10 | 运行时和 SDK |
| Avalonia UI | 12.1.3 | 跨平台 UI 框架(共享类库与桌面/浏览器壳) |
| Avalonia WebAssembly | 12.1.3 | 浏览器端 UI(net10.0-browser,WebGL/CanvasKit 渲染) |
| CommunityToolkit.Mvvm | 8.4.2 | MVVM 源码生成器([ObservableProperty], [RelayCommand]),ViewModelBase 与存量 VM 的基础 |
| ReactiveUI.Avalonia | 12.1.5 | 响应式 MVVM(ReactiveObject/[Reactive]/ReactiveCommand/WhenAnyValue),与 CTK 双范式共存(ADR-014) |
| Serilog | 4 | 结构化日志(仅桌面写入文件) |
| EPPlus | 8 | XLSX 读写(桌面与浏览器) |
| QuestPDF | — | PDF 导出(仅桌面) |
| Microsoft.Extensions.DependencyInjection | — | DI 容器 |
| xUnit | 3 | 单元测试框架(Core/Application/Infrastructure 为 4.x;Presentation 测试锁 3.2.2) |
| FluentAssertions | — | 测试断言 |
| NSubstitute | — | 模拟框架 |
关键设计决策
项目采用架构决策记录(ADR)系统文档化重大技术决策,位于 docs/adr/ 目录。
ADR 索引
| ADR | 主题 | 关键结论 |
|---|---|---|
| ADR-001 | 选择 Avalonia UI | 跨平台(Windows/macOS/Linux),原生 MVVM,WPF 开发者友好 |
| ADR-002 | MVVM 框架 | CommunityToolkit.Mvvm 源码生成器(部分被 ADR-014 取代:M0 起引入 ReactiveUI 双范式) |
| ADR-003 | 分层架构 | 经典三层结构 |
| ADR-004 | 策略模式 | ISeatingStrategy 作为排座算法通用接口 |
| ADR-005 | 命令模式 | IUndoableCommand + CommandHistory 实现撤销/重做 |
| ADR-006 | 策略管道 | Fill-in-Order 模型,依赖策略在 RandomFill 上下文中执行 |
| ADR-008 | 引导系统示例数据注入 | 纯内存注入,零磁盘痕迹,DispatcherPriority.Background 延迟 |
| ADR-013 | 移除插件系统 | 2.0.0 起移除插件/脚本/能力系统,新策略以内置方式加入 |
| ADR-014 | ReactiveUI 共存与自绘画布 | 引入 ReactiveUI.Avalonia 12.1.5 与 CTK 双范式共存;SeatingCanvas 自绘;IPageLifecycle 与横切服务;Headless UI 测试 |
核心架构模式
- 外观模式:
IApplicationFacade是 UI 层的单一入口点,封装所有业务操作(40+ 方法) - 策略模式:
ISeatingStrategy和IDependentSeatingStrategy定义排座算法接口 - 命令模式:
IUndoableCommand+CommandHistory提供快照式撤销/重做 - 双壳共享:
SeatFlow.Presentation.Avalonia为共享类库,MainView同时由桌面与浏览器单视图承载,平台差异通过接口与条件编译注入 - 自绘画布:
SeatingCanvas : Control以Control.Render统一绘制 Grid/Polar/Freeform 三种布局,几何命中替代逐座位控件(ADR-014) - 依赖注入: Microsoft.Extensions.DependencyInjection 管理组件生命周期
策略管道概念
SeatFlow 的策略管道采用 Fill-in-Order 模型,核心原则:
- 按 Priority 降序执行:Priority 数值越大越先执行,先执行的策略优先挑选空座
- 不存在覆盖语义:先占的座位不会被后执行的策略推翻
- IsFixed 保护:固定座位标记
IsFixed=true,后续GetEmptySeats()自动排除 - 依赖策略:某些策略(DeskMate、GenderRestrictedSeat、NoRepeatDeskMate)不在外部管道执行,而是在 RandomFill 的分配循环中按上下文内部优先级评估
管道执行顺序
独立策略 Priority 降序 →
FixedSeat(100) ← 最先执行:锁定固定座位
FrontRowRotation(50) ← 在非固定空座中填前排
RandomFill(1) ← 兜底填充:
└─ 依赖策略(优先级降序)→
DeskMate(50) ← 检查同桌关系
GenderRestrictedSeat(45) ← 检查性别限制
NoRepeatDeskMate(40) ← 检查历史同桌重复
Defrag(0) ← 碎片整理(默认禁用)
双壳架构
SeatFlow 的 UI 与业务逻辑集中在 SeatFlow.Presentation.Avalonia(共享类库,目标框架 net10.0;net10.0-browser),由两个启动壳承载:
| 壳 | 项目 | 说明 |
|---|---|---|
| 桌面壳 | SeatFlow.Desktop |
输出 EXE 名为 SeatFlow;提供 Velopack 自动更新、Watchdog 看门狗和单实例;PDF/图片导出仅在此可用 |
| 浏览器壳 | SeatFlow.Browser |
net10.0-browser WASM 应用,发布为 wwwroot/ 纯静态文件;数据存储于 IndexedDB,文件选择/下载经 JS 互操作 |
共享 UI 外壳 MainView : UserControl 由桌面 MainWindow : Window 与浏览器单视图(ISingleViewApplicationLifetime.MainView)共同承载。平台相关服务(对话框、文件、日志、存储)由各壳实现,共享层通过接口消费,并通过 BROWSER 条件编译区分浏览器专属代码路径。
共享层内置统一的 7 页信息架构:排座工作台(默认入口)、人员管理、会场与布局、策略配置、历史快照、设置、关于;PageKey.Home 已移除,原「自由点管理」并入「会场与布局」(Grid/Polar/Freeform 三类布局同页编辑)。