Skip to content

gong-web/Task-Forge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Task Forge — 本地优先任务管理系统

Python PyQt6 SQLAlchemy SQLite

Platform License Views Task Fields Regression Architecture


Task Forge 是一款基于 PyQt6 · SQLAlchemy · SQLite 的本地优先(Local-First)单体桌面任务管理系统。
数据主权、离线可用、历史可追溯三项特性收敛于一个零部署桌面单体内,
为个人知识工作者提供完整的任务生命周期管理能力。


功能演示

今日视图 · 任务树

今日视图演示

默认启动视图。forced_visible_ids 确保子任务在受限过滤视图中创建后仍可见。逾期任务红色高亮,今日到期橙色提示。

任务编辑器 · 上下文注入

任务编辑器演示

set_context() 三模式注入(独立新建 / 编辑已有 / 创建子任务),sync_reminder_constraints() 实时校验 $t{remind} \leq t_{due}$,payload() 统一输出。

父子 DAG · 自动归档联动

父子联动演示

全部子节点完成时 _refresh_parent_chain() 自动归档父节点并写入 completed_atreminder_sent 字段隔离,父节点刷新不干扰已调度的提醒。

甘特图 · 时间轴进度可视化

甘特图演示

GanttTimeline.paintEvent() 完全自绘。父子任务缩进 18px,百分比进度条实时渲染,数据源 gantt_entries() 与 Task ORM 字段严格一致。

看板 · 分析 Hub

看板分析演示

HubView 双标签页:KanbanBoard 四列泳道(待办 / 进行中 / 审核中 / 已完成)+ AdvancedAnalyticsView AI 能力维度分数条与 AI 深度洞察结构化卡片。

提醒调度 · 防重复弹窗

提醒弹窗演示

Single-shot 定时器 + reminder_sent 防重复互斥锁 + postpone_reminder() 延期补偿,每个提醒只响一次,延期后解锁重新调度。

日历 · 月度任务分布

日历视图演示

月度网格视图,任务密度色块可视化。按月翻页,点击日期格聚焦当日任务列表。

导入导出 · 数据安全

导入导出演示

三格式导出(JSON 全量 / CSV 电子表格 / Markdown 周报),import_data() 含结构校验与 ID 映射恢复。冷启动自动备份 .db → .db.bak

专注计时器 · tracked_minutes

专注计时器演示

选中任务后启动专注计时,暂停 / 恢复 / 结束后自动累加 tracked_minutes,与分析 Hub 的效率偏差 $T_{actual} - \hat{T}$ 数据直接打通。

主题切换 · 三套视觉风格

主题切换演示

深色 / 浅色 / 日出橙三套完整主题,全局 QSS 切换 + StarryDialogShell.set_backdrop_pixmap() 弹窗背景继承,保证所有页面主题一致性。

[!NOTE] README 依赖的演示素材(GIF / PNG)统一放置于 docs/demo/。本地录制操作步骤见 docs/GIF录制操作步骤.md

截图素材与 README 依赖映射

docs/demo/ 中已补齐 README 当前使用的全部演示素材,来源于 screenshot/

README 引用文件 来源素材
01-today-view.png 今日任务.png
02-create-task.gif 创建任务.gif
03-parent-child-dag.gif 子任务全部完成父任务自动完成.gif
04-gantt-view.png 甘特图时间轴.png
05-calendar-view.gif 日历使用.gif
06-kanban-board.gif 工作台任务查阅.gif
08-reminder-dialog.gif 任务提醒.gif
10-export-import.gif 数据持久化展示.gif
12-theme-settings.gif 主题切换.gif
14-focus-timer.gif 专注计时.gif

其余补充素材(如 AI深度分析.gif按日期筛选任务.gif背景图片切换.gif 等)也已同步到 docs/demo/,便于后续继续扩展 README 演示内容。


快速开始

安装与启动

① 安装依赖
pip install -r requirements.txt
② 启动应用
python src/main.py
③ 运行回归测试
python tests/editor_regression_suite.py

首次启动自动化流程

首次启动无需手动干预,系统自动完成:

步骤 函数 说明
_configure_qt_font_directory() Qt 字体路径注入
load_config() 加载 app_config.json + 日志
DB() ORM 初始化 + _ensure_schema() 自动迁移
seed_database_if_empty(db) 演示数据植入(幂等)
get_theme_profile() 读取主题配置
apply_theme(...) 全局样式装配
MainWindow().showMaximized() 主窗口上屏(默认 today 视图)
app.exec() 进入 Qt 事件循环

系统架构总览

五层架构

Task Forge — 五层架构
表现层 src/ui/ · 25+ UI 模块 · PyQt6 组件树 · 主题装配 · 视觉资产
交互层 MainWindow.py · 事件路由 · switch_view() · refresh_everything() · 提醒调度
领域层 task_composer.py · 规则装配 · payload() 验证 · 时间约束联动
数据层 DB.py · Task.py · Note.py · SQLAlchemy ORM · _ensure_schema · SSOT 唯一写入
资源层 src/assets/ · 图标 / 主题 / 声效 · 三套配色 · 背景图管理

单向数据流

单向数据流 — Task Forge System
表现层 · PyQt6 · 25+ UI 模块
TodayView | PlanView | TaskTree | HubView | GanttView | Calendar
↓ UI 事件(点击 / 勾选 / 输入)
交互层 · MainWindow
switch_view()    refresh_everything()    check_reminders()
↓ 领域规则 · 编辑器装配 · 提醒调度
领域层
规则 · 约束
状态验证
TaskEditorView
set_context()
payload() 装配
提醒调度引擎
Single-shot Timer
reminder_sent 锁
↓ DB API Call
数据层 · DB.py (SSOT · SQLAlchemy Session)
create_task | update_task | toggle_task | _refresh_parent_chain | gantt_entries | personal_analytics_snapshot
↓ → refresh_everything() 广播
SQLite · data/task_forge.db + .db.bak(冷启动备份)

Tip

refresh_everything()唯一重绘入口。所有视图均通过此函数获取最新状态,彻底消除「界面先变、落盘失败」的 State Drift 竞态问题。

核心函数锚点

核心函数调用关系
上游触发
switch_view(mode) — 视图路由

_refresh_tree() — 任务树重建

check_reminders() — 提醒轮询
refresh_everything()
MainWindow.py · 唯一重绘入口
下游写入(DB.py)
create_task(payload)

update_task(id, payload)

_refresh_parent_chain() — DAG 同步

目录结构

Task-Forge/
├─ README.md                         # 项目说明(课程要求)
├─ requirements.txt                  # 依赖列表(课程要求)
├─ src/                              # 源代码(课程要求)
│  ├─ main.py
│  ├─ MainWindow.py
│  ├─ DB.py
│  ├─ Task.py
│  ├─ Note.py
│  ├─ runtime_support.py
│  ├─ assets/
│  └─ ui/
├─ data/                             # 数据文件(课程要求)
│  ├─ app_config.json
│  ├─ categories.json
│  ├─ demo_data.json
│  └─ task_forge.db.bak
├─ docs/                             # AI 使用说明文档(课程要求)
│  ├─ AI使用说明.tex
│  ├─ AI使用说明.pdf
│  ├─ AI使用说明.md
│  ├─ fonts/                         # README/TeX 需要的本地字体
│  │  ├─ NotoSansSC-VF.ttf
│  │  └─ NotoSerifSC-VF.ttf
│  └─ demo/
├─ tests/                            # 回归测试(扩展内容)
├─ scripts/                          # 工具脚本(扩展内容)
└─ screenshot/                       # 演示录屏素材(扩展内容)

Note

为保证 README 表格和 docs/AI使用说明.tex 在不同机器上的中文排版一致性,项目已将所需字体放入 docs/fonts/。若本机已安装同名字体,系统会优先使用本机字体。


数据模型

Task 实体(19 字段)

定义于 src/Task.py,SQLAlchemy 2.0 DeclarativeBase 风格,自引用 DAG 外键。

字段 SQLAlchemy 类型 约束 语义说明
id Integer PK · AutoIncrement 全局唯一标识符
title String(120) NOT NULL 任务标题
category String(60) default="学习" 一级分类标签
tags Text default="" 多标签文本(空格分隔)
priority String(10) 枚举:高 / 中 / 低 任务优先级
due_at DateTime Nullable · Index 截止时间 $t_{\text{due}}$
remind_at DateTime Nullable 提醒时间 $t_{\text{remind}}$,约束 $t_{\text{remind}} \leq t_{\text{due}}$
progress Integer default=0 完成度 $P \in [0, 100]$
estimated_minutes Integer default=0 预估投入时长 $\hat{T}$
tracked_minutes Integer default=0 实际累计投入 $T_{\text{actual}}$
recurrence_rule String(20) default="不重复" 循环规则(每天 / 每周 / 自定义)
completed Boolean default=False 任务完成态标志
completed_at DateTime Nullable 完成时间戳,归档时写入
reminder_sent Boolean default=False 防重复互斥锁,弹窗展示后置 True
sort_order Integer default=0 同级任务排序权重
parent_id Integer FK(self) · Nullable · CASCADE 父任务引用,构成 DAG
created_at DateTime default=now 创建时间戳
updated_at DateTime onupdate=now 最后修改时间戳
description Text default="" 任务详情说明

核心字段形式化语义

父节点进度聚合:

$$P_{\text{parent}} = \begin{cases} 100 & \forall, c \in \text{children}(t),\ c.\text{completed} = \texttt{True} \ \left\lfloor \dfrac{\sum_{c} c.P}{|\text{children}(t)|} \right\rfloor & \text{otherwise} \end{cases}$$

效率偏差(分析 Hub 核心指标):

$$\Delta T = T_{\text{actual}} - \hat{T}$$

截止与提醒时间约束:

$$t_{\text{remind}} \leq t_{\text{due}}$$

_sync_reminder_constraints() 实时校验并自动修正。

Note 实体(6 字段)

字段 类型 约束 说明
id Integer PK 便签唯一 ID
title String default="未命名便签" 便签标题
content Text Nullable 便签正文
pinned Boolean default=False 置顶标志
created_at DateTime default=now 创建时间戳
updated_at DateTime onupdate=now 最后修改时间戳

冷启动迁移策略

DB.py 内建两种零摩擦迁移机制:

  1. _ensure_schema()ALTER TABLE 追加缺失列(tagstracked_minutesprogressrecurrence_rule),无需手动脚本
  2. _resolve_db_path() — 自动升级历史命名 task_studio.db → task_forge.db

核心机制:父子 DAG 联动

内存索引结构

# src/MainWindow.py — 每次 refresh_everything() 后重建
self.task_map:      dict[int, Task]           # O(1) 任务查找
self.children_map:  dict[int, list[Task]]     # 子树枚举与递归计算

DAG 状态转换图

_refresh_parent_chain — 状态转换
状态 条件 转换方向
未完成 completed=False → 部分完成(子节点进度 < 100%)
部分完成 progress < 100% → 全部完成(全部子节点 completed=True)
全部完成 all children done → 父节点归档(completed=True,写入 completed_at
回退 任意子节点取消完成 → 强制回退 completed=False,向上递归至树根
隔离约束:reminder_sent 字段不受父节点刷新影响,保持原有锁状态

_refresh_parent_chain 三条不变量

位于 src/DB.py

  1. 全量完成 → 父节点自动 completed=True,写入 completed_at
  2. 任一子节点未完成 → 父节点强制回退 completed=False
  3. 向上递归 直至 parent_id IS NULL(树根)为止

子任务可见性策略

forced_visible_ids 机制解决过滤视图下的可见性断层:

场景 问题 解决方案
today 视图创建子任务 子任务 due_at=None 被过滤隐藏 forced_visible_ids 强制显示
plan 视图创建子任务 父任务在不同日期,子任务被过滤 扩展相关分支临时可见
批量完成后刷新 完成的父任务消失难以确认结果 保留 1 轮渲染周期可见

核心机制:提醒调度引擎

调度时序图

提醒调度时序
提醒定时器
Single-shot
MainWindow DB.py 声音引擎 提醒弹窗
timeout()check_reminders()
② MW → DB: due_reminders(current_time) → 返回待提醒任务列表
③ [存在待提醒任务] → 声音引擎: _play_reminder_sound() → DB: mark_reminders_sent(task_ids) → 弹窗: _show_reminder_dialog(tasks)
④ [用户选择延期] → DB: postpone_reminder(task_id, minutes)(重置 reminder_sent=False
⑤ MW → DB: next_pending_reminder_at() → 定时器: setSingleShot(True); start(delta_ms)

reminder_sent 状态转换矩阵

reminder_sent 字段状态转换
触发条件 变化方向 执行函数
提醒时间到达,弹窗已展示 False → True mark_reminders_sent()
用户修改 remind_at 字段 True → False update_task() 内部重置
任务被标记为完成 False → True _set_completion_state()
用户点击「延期」 True → False postpone_reminder()
父节点刷新(_refresh_parent_chain 无变化(隔离)

Important

架构约束:严禁绕过 SQLAlchemy Session 直接写 task_forge.dbreminder_sent 的原子性完全依赖事务——绕过 ORM 将导致提醒重复触发。


任务编辑器

核心类:TaskEditorViewsrc/ui/task_composer.py

三模式上下文注入

# 独立新建任务
set_context(task=None,  preferred_parent_id=None,  parent_title=None)

# 编辑已有任务(回显全部字段)
set_context(task=task,  preferred_parent_id=None,  parent_title=None)

# 创建子任务(fixed_parent_id 锁定,防止提交时解除父子关系)
set_context(task=None,  preferred_parent_id=pid,   parent_title=title)

提交载荷结构与交互约束

payload() 输出字段与约束
字段 类型
titlestr
priority"高" | "中" | "低"
due_atdatetime | None
remind_atdatetime | None
parent_idint | None
progressint [0, 100]
estimated_minutesint
tags / category / descriptionstr
实时约束函数
_sync_reminder_constraints()
校验 remind_at ≤ due_at,违规自动修正
_sync_due_state()
截止时间控件启用 / 禁用联动
EditorDateTimeField
时 / 分独立滚轮 + 预设时间按钮
StarryTagEditor
流式标签输入,自动去重

多视图体系

11 种视图模式

switch_view(mode) 统一路由 — 11 种视图模式
today
今日聚焦 · 默认启动
plan
未完成计划树
tasktree
全量任务树
completed
已完成任务归档
hub
看板 + 分析 Hub
calendar
月度任务分布
gantt
时间轴进度图(自绘)
settings
设置中心
create
新建任务编辑器
edit
编辑已有任务
detail
任务详情全屏
所有视图均通过 switch_view(mode) 统一路由
MainWindow.py

数据看板与分析

DB 聚合接口

接口 返回描述
dashboard_snapshot() 完成率 / 逾期数 / 本周完成
dashboard_counts() 快速计数(完成/未完成/逾期/今日)
weekly_series() 近 7 天逐日完成趋势
gantt_entries() 起止区间 / 进度 / 优先级 / 完成态
personal_analytics_snapshot() 效率偏差 · 分类分布 · 热力图数组

Hub 视图层次

HubView(QWidget)
└── QTabWidget
    ├── "看板" → KanbanBoard
    │   ├── 待办 | 进行中 | 审核中 | 已完成
    │   └── task_detail_requested = pyqtSignal(int)
    └── "分析" → AdvancedAnalyticsView
        ├── AI 能力维度卡片(7 维度进度条,由 AI ability_profile 驱动)
        └── AI 深度洞察卡片(AICardRenderer 结构化分析文本)
数据分析 Hub 演示

导入导出与数据安全

导出接口总览

export_data()
JSON — 全量任务 + 便签
含 ID 与父子关系保全
export_csv()
CSV — 电子表格格式
Excel / Numbers 兼容
export_week_report()
Markdown — 周报模板
可直接粘贴提交

Caution

import_data() 执行覆盖性导入。操作前请先确认 task_forge.db.bak 时间戳为最新,或手动执行 export_data() 备份当前数据。


质量保障矩阵

编辑器回归套件

tests/editor_regression_suite.py

测试域 核心断言
布局可见性 set_context() 后控件可见
滚动行为 长表单滚动后目标控件仍在可视区
时间约束 remind_at > due_at 时强制修正
进度回显 progress=65payload()["progress"]==65
标签输入 StarryTagEditor 高度规范,重复标签去重
提醒禁用标签 未开启提醒时 remind_disabled_label 可见
子任务预览树 parent_title 注入后预览节点正确展示

主窗口回归套件

tests/mainwindow_regression_suite.py

测试域 核心断言
树勾选完成联动 勾选后 completed 持久化 True
完成庆祝动效 CelebrationOverlay 在完成时触发
单次触发定时器 reminder_timer.isSingleShot()==True
子任务创建可见性 forced_visible_ids 确保创建后可见
父节点提醒不重置 添加子任务不重置父 reminder_sent
提醒轮询路径 声音→弹窗完整顺序验证
Windows 无 Toast _should_show_system_reminder_toast()==False
甘特图进度同步 gantt_entries() 与 ORM 值一致

AI 协作上下文

架构约定(CLAUDE.md 兼容格式)

项目协作约定速查
约定项 说明
启动指令 python src/main.py
质量门禁 python tests/editor_regression_suite.py + mainwindow_regression_suite.py
代码风格 PEP 8 · snake_case pyqtSignal · 类型注解优先
架构约束 禁止 UI 层直接实例化 Session · 所有写操作通过 DB 类接口
依赖管理 新增 PyPI 依赖须同步更新 requirements.txt 并版本锁定
禁止绕过 ORM 直接写 task_forge.db · DAG 一致性和 reminder_sent 原子性依赖 Session
验证数据库迁移健壮性

在缺少 progress 列的旧版数据库上运行 python src/main.py_ensure_schema() 会自动执行 ALTER TABLE tasks ADD COLUMN progress INTEGER DEFAULT 0,应用正常启动。

执行完整回归并解析结果
python tests/editor_regression_suite.py
python tests/mainwindow_regression_suite.py

成功判定:输出包含 editor-regression-suite-passed:Nmainwindow-regression-suite-passed:M


演进路线图

已完成

  • 父子 DAG 递归状态同步
  • reminder_sent 防重复锁 + 延期补偿
  • 编辑器与主窗口双回归套件
  • JSON / CSV / Markdown 三格式导出
  • 甘特图 / 看板 / 分析 Hub 三视图
  • 自动 schema 迁移与历史库兼容
  • 三套主题系统(深色/浅色/日出)
  • 父子层级缩进甘特图自绘
  • 专注计时器 tracked_minutes

近期规划

  • 重复任务规则增强
    • Cron 表达式解析器
    • 本地时区校准与规则预览
  • 提醒中心批量处理 UI
  • 回归脚本分组 + HTML 报告输出
  • 循环任务自动续期展示

中长期规划

  • 插件化扩展点(导入器/统计器)
  • 性能剖析面板(重绘/查询耗时)
  • 基于 $\hat{T}$$T_{\text{actual}}$ 的效率预测模型
  • 分类级别投入热力图
  • CalDAV 日历协议对接
  • 可选轻量局域网 P2P 同步

常见问题

首次启动为什么会有短暂延迟?

启动时 _ensure_schema() 执行 schema 检查,seed_database_if_empty() 在空库情况下植入演示数据。两个操作均为幂等,通常在 1 秒内完成。后续启动仅执行备份操作,速度更快。

提醒没有弹出,可能是什么原因?
  1. 检查任务的 remind_at 是否正确设置(须早于或等于 due_at
  2. 检查 reminder_sent 是否已被设置为 True(通过重新修改 remind_at 来重置)
  3. Windows 平台:系统通知不会触发(设计行为),提醒通过应用内弹窗展示
  4. 确认 settings 视图中提醒声音未被禁用
父任务完成状态为什么没有自动更新?

_refresh_parent_chain 仅在子任务完成状态通过 toggle_task()batch_toggle_tasks() 变化时触发。若通过非标准方式(如直接写数据库)完成子任务,父节点不会自动刷新。请始终通过 DB 类接口操作数据。

如何在演示场景下快速重置到初始状态?
# 关闭应用后执行
Remove-Item data/task_forge.db -Force
# 下次启动 seed_database_if_empty() 将自动植入完整演示数据
python src/main.py

附录

附录 A · 主要入口文件速查

类别 路径 说明
应用启动 src/main.py 8 步启动序列 + 主题装配
主窗口路由 src/MainWindow.py 视图切换 + 提醒调度 + 内存索引重建
数据访问层 src/DB.py 所有数据操作的 SSOT,唯一写入通道
任务 ORM src/Task.py 19 字段 + 自引用 DAG 关系定义
便签 ORM src/Note.py 6 字段便签实体
任务编辑器 src/ui/task_composer.py TaskEditorView + set_context() + payload()
看板与分析 src/ui/hub_view.py HubView · KanbanBoard · AdvancedAnalyticsView
甘特图 src/ui/gantt_view.py GanttView · GanttTimeline.paintEvent()
编辑器回归 tests/editor_regression_suite.py 7 测试域
主窗口回归 tests/mainwindow_regression_suite.py 8 测试域

附录 B · 术语表

术语 含义
Local-First 数据优先驻留本地,操作优先本地生效,离线环境完整可用
SSOT Single Source of Truth,单一事实来源(此处为 DB.py
DAG Directed Acyclic Graph,有向无环图,保证父子任务引用无循环
State Drift 视图状态与持久化状态不一致的竞态现象
Debounce Lock reminder_sent 字段实现的防重复提醒互斥锁
Payload TaskEditorView.payload() 装配的任务数据字典,为 DB API 统一入参
forced_visible_ids 强制可见集合,防止新建子任务在受限过滤视图中消失
Single-shot Timer reminder_timer.setSingleShot(True),到期后不自动重启,精准调度
$\hat{T}$ estimated_minutes,任务预估投入时长
$T_{\text{actual}}$ tracked_minutes,实际累计专注投入时长

Task Forge — 让每一个任务都有完整的生命周期

PyQt6 + SQLAlchemy + SQLite · Local-First · Offline-Complete


Python PyQt6 SQLAlchemy MIT License

About

2026/4/10软件工程

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages