一、修「卡片挤到一起去了」(用户 2026-10-06 报) 真因=**嵌套 grid**:renderAll 写 `<div class="cols">` 而容器 `#cols` 本身就带 `class="cols"` ⇒ 内层作为外层一个 grid item 先被压到 `min-width:auto`(399px), 再在 399px 里自己切 4 列 ⇒ 每列 89px、卡片 67px,整块挤在左边一条。 实测:col 89px / card 67px / 页高 3192px ⇒ 修后 card 377px / 页高 1415px。 处置:renderAll 只铺列,⛔ 不再包一层。 二、修「卡片上下之间的距离太远」 grid 默认 `align-items:stretch` ⇒ 12 张卡都在「已完成」、另三列空着却四列等高, 整页虚胖。改 `align-items:start` ⇒ 每列各自撑高。卡片 gap 9→6、padding 10→8、 `.col` 的 `min-height:160px`→0。 三、**工作区 / 目标 两个维度纠偏**(用户纠正:「下拉框是选工作区的 跟目标没关系」) 改前:下拉写「全部(N 个目标)」而 N 取的是 `projects.length`=工作区条数 ⇒ 混了维度。 改后:① 标签「项目」→「工作区」;② 选项文字=**目录名(+目标名)**; ③ 计数=「N 个工作区」;④ 概要条分开报「工作区 3 个 / 其中已登记目标 2 个」; ⑤ 装了机制的工作区**一律列出**(含未登记目标的,用户:「加载机制就可以显示」)。 四、修「显示的是目录名,应该是真正名称」 `name = short or title` ⇒ 登记过 short 的区一律显示短名(`vibe-product`)。 改 `title or short`;都没有 ⇒ 「未登记目标 · <dir>」(⛔ 不再印「(未命名 · …)」—— 用户原话「未命名 看不懂个是什么」)。 ⚠️ 核实过:这不是收工操作的副作用(goal.json 的 title/short 收工前后逐字一致)。 五、卡片信息重排(用户:「工作区名称放到卡片下面」) 末行单列工作区名(等宽字体)+ 本工作区角标;工作区名从 badge 堆里挪出来。 本工作区卡片换色突出:判定来自服务端 `self`(启动器注入 `DSH_PM_BOARD_SELF_WS`=启动器上两级),⛔ 前端不硬编码目录名。 六、修时间戳显示成 `1791957640.7257342` 台账 `t_start`/`t_end` 有两种形态(ISO 串 / **纯数字 Unix 秒**),原 fmtWhen 只认前者, 不匹配就**原样返回** ⇒ 印出一串乱数字。补:纯数字(1e9~4e9)走 Date 转本地时间。 另:A 方案(收工 vibe-product)已执行并取证 —— `--set-life 已完成` 自动调 supervise_stop,pid 432 真退出(tasklist 查无)、日志 35s 增量 0 字节(收工前每 32s +1357B)。
66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
#!/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")
|
||
|
||
# 🔴 「本工作区」=**拥有一这层的那个工作区**(用户 2026-10-06 要:本工作区的卡片换色突出)。
|
||
# ⛔ 不许靠 `Path.cwd()`:计划任务的 **工作目录是 `交付物/项目管理界面`**(实测),
|
||
# 不是工作区根 ⇒ 那样算出来的"本工作区"是错的。
|
||
# 正解=从本文件位置**往上两级**:`<ws>/交付物/项目管理界面/project-board-launch.py`。
|
||
os.environ.setdefault("DSH_PM_BOARD_SELF_WS",
|
||
os.path.dirname(os.path.dirname(HERE)))
|
||
|
||
|
||
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())
|