You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6.1 KiB

广播系统软件架构文档

1. 架构目标

构建一个基于 Tauri v2 的桌面广播显示系统,满足以下架构目标:

  • 支持固定窗口行为(无边框、左上角定位、启动即开)
  • 支持 5000px 标尺在任意屏宽下的稳定分段显示
  • 支持子元素跨段连续渲染
  • 保持模块边界清晰,便于后续扩展(动态数据、渲染升级)

2. 总体架构

采用“宿主层 + 前端应用层 + 渲染域层”的分层结构:

  • 宿主层Tauri Runtime
    • 负责窗口生命周期、屏幕信息读取、系统能力接入
  • 前端应用层Vue Application
    • 负责状态管理、分段计算、组件编排
  • 渲染域层Ruler Rendering Domain
    • 负责刻度绘制、切片映射、子元素裁剪与连续性

架构原则:

  • 计算与渲染分离:算法在 composables/services,界面在 components/views
  • 数据驱动:通过状态变化触发渲染,不在组件中写复杂业务判断
  • 可替换渲染:先 DOM后续可平滑迁移到 Canvas

3. 逻辑视图(模块划分)

建议目录结构:

broadcast-client/
  src/
    main.ts
    App.vue
    views/
      BroadcastView.vue
    components/
      RulerCanvas.vue
      RulerSegment.vue
      RulerTicks.vue
      SegmentChildren.vue
    composables/
      useScreenInfo.ts
      useSegmentLayout.ts
      useRulerTicks.ts
    services/
      segmentService.ts
      childSliceService.ts
    models/
      ruler.ts
      segment.ts
      child.ts
    utils/
      math.ts
  src-tauri/
    tauri.conf.json
    src/
      lib.rs

模块职责:

  • useScreenInfo读取并维护当前主屏宽度、DPI 信息
  • segmentService:计算段数量、每段映射关系
  • useRulerTicks:生成 10/100 刻度数据
  • childSliceService:计算子元素在每段的可见切片
  • RulerSegment:单段渲染容器(裁剪窗口)
  • SegmentChildren:渲染跨段子元素切片

4. 关键数据模型

type TickType = "minor" | "major";

interface Tick {
  x: number;
  type: TickType;
  label?: string;
}

interface Segment {
  index: number;
  sourceX: number;
  sliceWidth: number;
  top: number;
  height: number; // 固定 64
}

interface ChildElement {
  id: string;
  left: number;
  width: number;
  top: number;
  height: number;
  zIndex?: number;
  className?: string;
}

interface ChildSlice {
  childId: string;
  segmentIndex: number;
  renderLeft: number;
  renderTop: number;
  renderWidth: number;
  renderHeight: number;
  clipOffset: number;
}

设计说明:

  • Segment 只描述“段映射”,不关心具体 UI。
  • ChildSlice 是“子元素在某段中的投影结果”,用于直接渲染。
  • 所有坐标统一使用同一逻辑坐标系(以 5000px 主轴为基准)。

5. 运行时流程(时序)

启动流程:

  1. Tauri 启动并创建窗口(无边框,位置 (0,0))。
  2. 前端初始化,读取屏幕宽度 screenWidth
  3. 计算 segments = ceil(5000 / screenWidth)
  4. 生成刻度数据 ticks,构建段列表 segmentList
  5. 渲染每段:段容器裁剪 + 虚拟标尺偏移显示。
  6. 若存在子元素,计算 ChildSlice[] 并叠加渲染。

更新流程(屏宽变化):

  1. 监听窗口尺寸/屏幕变化事件。
  2. 重新计算 segmentListChildSlice[]
  3. 增量更新视图(避免全量销毁重建)。

6. 关键算法设计

6.1 分段算法

  • 输入:TOTAL_WIDTH=5000, screenWidth, SEGMENT_HEIGHT=64
  • 输出:Segment[]
  • 复杂度:O(n)n = segmentCount

核心规则:

  • segmentCount = ceil(5000 / screenWidth)
  • 每段 sourceX = i * screenWidth
  • sliceWidth = min(screenWidth, 5000 - sourceX)

6.2 子元素切片算法

  • 输入:ChildElement[], Segment[]
  • 输出:ChildSlice[]
  • 复杂度:O(m * n)(可按区间优化)

相交判定:

  • 仅当子元素区间与段区间重叠时生成切片
  • 切片宽度为区间交集长度
  • 渲染左偏移为交集起点相对段起点

7. 部署视图

单机本地部署:

  • 可执行文件Tauri 打包产物)
  • 前端静态资源内嵌
  • 无外部服务依赖

跨平台建议:

  • Windows 为主目标平台
  • 后续可扩展到 Linux/macOS保持 API 使用跨平台)

8. 非功能架构设计

8.1 性能

  • 预计算与缓存刻度数据
  • 分段与切片计算函数纯函数化,便于 memoization
  • 控制组件重渲染范围(按段粒度更新)

8.2 可维护性

  • 算法层独立文件,配套单元测试
  • 组件职责单一,避免“巨型组件”
  • 使用 TypeScript 类型约束输入输出

8.3 兼容性

  • 适配不同分辨率,屏宽变化自动重算
  • 高 DPI 场景下进行像素对齐优化

9. 异常与容错架构

  • 屏幕宽度读取失败:降级默认值(如 1920
  • 输入数据异常(负宽度、越界坐标):统一在 service 层校正/裁剪
  • 渲染失败保护:关键计算异常时记录日志并回退最小可用视图

10. 安全与边界

当前系统以本地渲染为主,安全关注点较轻,建议:

  • 最小化 Tauri 权限配置
  • 不暴露不必要的系统 API
  • 对未来外部输入(若接入)进行 schema 校验

11. 测试架构

测试分层:

  • 单元测试:segmentServicechildSliceService
  • 组件测试:RulerSegmentSegmentChildren
  • 集成测试:启动后窗口行为与全链路渲染

关键断言:

  • 分段数量与位置正确
  • 末段宽度裁剪正确
  • 子元素跨段连续且无视觉跳变
  • 大小刻度在每段中对齐正确

12. 可扩展路线

  • 渲染升级DOM -> Canvas/WebGL
  • 数据升级:静态子元素 -> 实时广播内容流
  • 交互升级:缩放、定位、标记线、主题切换
  • 多屏支持:副屏渲染与窗口同步控制

13. 架构决策记录ADR 简版)

  • ADR-001采用 Tauri v2 作为宿主框架(轻量、跨平台)
  • ADR-002采用 Vue3 + TS 作为前端基础(可维护、类型安全)
  • ADR-003先采用 DOM 裁剪方案(交付快、调试友好),保留 Canvas 替换能力
  • ADR-004分段按屏宽计算并纵向堆叠严格满足需求中的显示规则