项目管理界面:照 dsh-task-board 模式新建(目标=项目 · 只读复用现有看板 · 端口20100)

用户逐字:「不动现有任务会话看板 不是让你整体搬是照的他的模式做一个 项目管理的界面
          来管理 执行任务,目标等于项目」

- 新增 交付物/项目管理界面/{project-board.py,.html,-launch.py}
- 映射:目标→项目、任务类别→工作流、台账条目→卡片、会话→可跳转
- 数据源=现有看板已算好的 /board.json(⛔ 不重算、⛔ 不直读台账)
- 列=机制真实四态(待执行/执行中/有阻碍/已完成),⛔ 不硬套它那五列
- 现有看板 20099 / board.py / board.html 零改动
- 坑:pythonw.exe 下 sys.stdout is None ⇒ print/flush 崩(终端好、计划任务死)⇒ 加 _say() 兜
This commit is contained in:
admin committed 2026-10-06 08:23:15 +08:00
1 parent 87a9c97b54
commit 1b68b1ac3f
4 files changed
+651

No files matched your search

@@ -0,0 +1,58 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""项目管理界面的**启动器**(计划任务动作指向它,⛔ 不许直起 `project-board.py`)。
## 为什么必须有这一层(同族 P0-73/74)
· 计划任务的**动作没有 env 字段** ⇒ 变量只能在**进程内**设;
· 直接用 `python.exe` 起 ⇒ 控制台程序 ⇒ 计划任务**每次触发闪一个黑窗口**;
· 直起业务脚本 ⇒ 将来加变量/判活时**没有落点**,只能再开第二条旁路(闪黑窗的真因)。
## 本启动器做什么
① 设好编码与上游地址(⛔ 不依赖宿主 env);
② 调 `project-board.py --serve 20100`;
③ **判活**:端口已在听 ⇒ 直接退出 0(⛔ 不重复起第二实例)。
⚠️ 必须用 `pythonw.exe` 跑本文件(无控制台 ⇒ 不闪窗)。
"""
from __future__ import annotations
import os
import socket
import sys
import runpy
PORT = int(os.environ.get("DSH_PROJECT_BOARD_PORT") or "20100")
HERE = os.path.dirname(os.path.abspath(__file__))
TARGET = os.path.join(HERE, "project-board.py")
# ── 变量只在这里设(计划任务动作没有 env 字段)──
os.environ.setdefault("PYTHONIOENCODING", "utf-8")
os.environ.setdefault("DSH_PROJECT_BOARD_UPSTREAM", "http://127.0.0.1:20099/board.json")
def port_listening(port: int) -> bool:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(0.4)
try:
return s.connect_ex(("127.0.0.1", port)) == 0
finally:
s.close()
def main() -> int:
if port_listening(PORT):
return 0 # 已在跑 ⇒ 静默退出(⛔ 不起第二实例)
sys.argv = [TARGET, "--serve", str(PORT)]
try:
runpy.run_path(TARGET, run_name="__main__")
except SystemExit:
raise
except Exception:
return 1
return 0
if __name__ == "__main__":
sys.exit(main())