Browse Source

新增截止日期

master v1.0.1
lxb 2 months ago
parent
commit
27845b38aa
  1. 121
      README.md
  2. 122
      app.py

121
README.md

@ -11,6 +11,127 @@
pyinstaller --onefile --windowed --name TaskManager app.py pyinstaller --onefile --windowed --name TaskManager app.py
``` ```
当前python环境的conda listL
```
# Name Version Build Channel
altgraph 0.17.5 pypi_0 pypi
anaconda-anon-usage 0.7.4 pyhb46e38b_100
anaconda-auth 0.10.0 py313haa95532_1
anaconda-cli-base 0.6.0 py313haa95532_0
anaconda_powershell_prompt 1.1.0 haa95532_1
anaconda_prompt 1.1.0 haa95532_1
annotated-types 0.6.0 py313haa95532_1
archspec 0.2.5 pyhd3eb1b0_0
babel 2.17.0 pypi_0 pypi
boltons 25.0.0 py313haa95532_0
brotlicffi 1.0.9.2 py313h885b0b7_2
bzip2 1.0.8 h2bbff1b_6
ca-certificates 2025.11.4 haa95532_0
certifi 2025.10.5 py313haa95532_0
cffi 2.0.0 py313h02ab6af_1
charset-normalizer 3.4.4 py313haa95532_0
click 8.1.8 py313haa95532_0
colorama 0.4.6 py313haa95532_0
conda 25.9.1 py313haa95532_0
conda-anaconda-telemetry 0.3.0 pyhd3eb1b0_1
conda-anaconda-tos 0.2.2 py313haa95532_1
conda-content-trust 0.2.0 py313haa95532_1
conda-libmamba-solver 25.4.0 pyhdf14ebd_1
conda-package-handling 2.4.0 py313haa95532_1
conda-package-streaming 0.12.0 py313haa95532_1
cpp-expected 1.1.0 h214f63a_0
cryptography 46.0.3 py313habbc9f9_0
customtkinter 5.2.2 pypi_0 pypi
darkdetect 0.8.0 pypi_0 pypi
distro 1.9.0 py313haa95532_0
expat 2.7.3 h9214b88_0
fmt 11.2.0 h58b7f6e_0
frozendict 2.4.6 py313h02ab6af_0
idna 3.11 py313haa95532_0
jaraco.classes 3.4.0 py313haa95532_0
jaraco.context 6.0.0 py313haa95532_0
jaraco.functools 4.1.0 py313haa95532_0
jsonpatch 1.33 py313haa95532_1
jsonpointer 3.0.0 py313haa95532_0
keyring 25.6.0 py313haa95532_0
libarchive 3.8.2 h6c023e8_0
libcurl 8.16.0 h97e0424_0
libffi 3.4.4 hd77b12b_1
libiconv 1.16 h2bbff1b_3
libmamba 2.3.2 h7d9f7df_0
libmambapy 2.3.2 py313h5078c03_0
libmpdec 4.0.0 h827c3e9_0
libsolv 0.7.30 h23a355e_2
libssh2 1.11.1 h2addb87_0
libxml2 2.13.9 h6201b9f_0
libzlib 1.3.1 h02ab6af_0
lz4-c 1.9.4 h2bbff1b_1
markdown-it-py 4.0.0 py313haa95532_0
mdurl 0.1.2 py313haa95532_0
menuinst 2.4.1 py313h885b0b7_1
more-itertools 10.8.0 py313haa95532_0
nlohmann_json 3.11.2 h6c2663c_0
openssl 3.0.18 h543e019_0
packaging 25.0 py313haa95532_1
pcre2 10.46 h5740b90_0
pefile 2024.8.26 pypi_0 pypi
pillow 12.0.0 pypi_0 pypi
pip 25.2 pyhc872135_1
pkce 1.0.3 py313haa95532_0
platformdirs 4.5.0 py313haa95532_0
pluggy 1.5.0 py313haa95532_0
pybind11-abi 5 hd3eb1b0_0
pycosat 0.6.6 py313h827c3e9_2
pycparser 2.23 py313haa95532_0
pydantic 2.12.3 py313haa95532_1
pydantic-core 2.41.4 py313h114bc41_0
pydantic-settings 2.10.1 py313haa95532_0
pygments 2.19.2 py313haa95532_0
pyinstaller 6.17.0 pypi_0 pypi
pyinstaller-hooks-contrib 2025.10 pypi_0 pypi
pyjwt 2.10.1 py313haa95532_0
pysocks 1.7.1 py313haa95532_1
python 3.13.9 h260b955_100_cp313
python-dotenv 1.1.0 py313haa95532_0
python_abi 3.13 1_cp313
pywin32-ctypes 0.2.2 py313haa95532_0
readchar 4.2.1 py313haa95532_0
reproc 14.2.4 hd77b12b_2
reproc-cpp 14.2.4 hd77b12b_2
requests 2.32.5 py313haa95532_1
rich 14.2.0 py313haa95532_0
ruamel.yaml 0.18.16 py313hb9a58be_0
ruamel.yaml.clib 0.2.14 py313hb9a58be_0
semver 3.0.4 py313haa95532_0
setuptools 80.9.0 py313haa95532_0
shellingham 1.5.4 py313haa95532_0
simdjson 3.10.1 h214f63a_0
sqlite 3.51.0 hda9a48d_0
tk 8.6.15 hf199647_0
tkcalendar 1.6.1 pypi_0 pypi
tksheet 7.5.19 pypi_0 pypi
tomli 2.2.1 py313haa95532_0
tqdm 4.67.1 py313h4442805_1
truststore 0.10.1 py313haa95532_1
typer 0.17.4 py313haa95532_0
typing-extensions 4.15.0 py313haa95532_0
typing-inspection 0.4.2 py313haa95532_0
typing_extensions 4.15.0 py313haa95532_0
tzdata 2025b h04d1e81_0
ucrt 10.0.22621.0 haa95532_0
urllib3 2.5.0 py313haa95532_0
vc 14.3 h2df5915_10
vc14_runtime 14.44.35208 h4927774_10
vs2015_runtime 14.44.35208 ha6b5a95_10
wheel 0.45.1 py313haa95532_0
win_inet_pton 1.1.0 py313haa95532_1
xz 5.6.4 h4754444_1
yaml-cpp 0.8.0 hd77b12b_1
zlib 1.3.1 h02ab6af_0
zstandard 0.24.0 py313he335c29_0
zstd 1.5.7 h56299aa_0
```
**主要功能:** **主要功能:**
1. 添加任务(可设置 类型、优先级、状态、链接、备注等信息) 1. 添加任务(可设置 类型、优先级、状态、链接、备注等信息)
2. 可筛选、排序,并且可以保存为模板快速应用 2. 可筛选、排序,并且可以保存为模板快速应用

122
app.py

@ -1,5 +1,6 @@
import os import os
import json import json
import math
import sqlite3 import sqlite3
import webbrowser import webbrowser
from datetime import datetime, date, timezone from datetime import datetime, date, timezone
@ -12,7 +13,7 @@ from tkcalendar import Calendar
# ----------------------- CONFIG ----------------------- # ----------------------- CONFIG -----------------------
# region 配置 # region 配置
VERSION = "v1.0.0" VERSION = "v1.0.1"
DB_PATH = "tasks.db" # 数据库文件路径 DB_PATH = "tasks.db" # 数据库文件路径
TEMPLATES_PATH = "templates.json" # 检索模板文件路径 TEMPLATES_PATH = "templates.json" # 检索模板文件路径
@ -91,6 +92,7 @@ COLUMNS = [
("type", "类型"), ("type", "类型"),
("status", "状态"), ("status", "状态"),
("priority", "优先级"), ("priority", "优先级"),
("deadline", "截止日期"),
("composite", "综合优先级"), ("composite", "综合优先级"),
("title", "标题"), ("title", "标题"),
("brief", "简介"), ("brief", "简介"),
@ -115,6 +117,19 @@ COL_START_DATE = COL_INDEX.get("start_date")
COL_LINKS_COUNT = COL_INDEX.get("links_count") COL_LINKS_COUNT = COL_INDEX.get("links_count")
COL_NOTES = COL_INDEX.get("notes") COL_NOTES = COL_INDEX.get("notes")
COL_COMPOSITE = COL_INDEX.get("composite") COL_COMPOSITE = COL_INDEX.get("composite")
COL_DEADLINE = COL_INDEX.get("deadline")
# 截止日期颜色,距离截止日期的时间小于哪个值就是哪个颜色
DEADLINE_COLOR = [
(0, "#fb0000"),
(1, "#ff6f22"),
(2, "#ff904b"),
(3, "#b2ff77"),
(4, "#73bc75"),
(10, "#83d6ff"),
(15, "#bdd8e9"),
(30, "#ffffff"),
]
# endregion # endregion
@ -141,6 +156,7 @@ class TaskDB:
type TEXT, type TEXT,
status TEXT, status TEXT,
start_date TEXT, start_date TEXT,
deadline TEXT,
links TEXT, links TEXT,
notes TEXT, notes TEXT,
updated_at TEXT updated_at TEXT
@ -178,6 +194,8 @@ class TaskDB:
adds.append(("status", "TEXT")) adds.append(("status", "TEXT"))
if "start_date" not in cols: if "start_date" not in cols:
adds.append(("start_date", "TEXT")) adds.append(("start_date", "TEXT"))
if "deadline" not in cols:
adds.append(("deadline", "TEXT"))
if "links" not in cols: if "links" not in cols:
adds.append(("links", "TEXT")) adds.append(("links", "TEXT"))
if "notes" not in cols: if "notes" not in cols:
@ -224,8 +242,8 @@ class TaskDB:
now = datetime.now(timezone.utc).isoformat() now = datetime.now(timezone.utc).isoformat()
cur = self.conn.cursor() cur = self.conn.cursor()
cur.execute(""" cur.execute("""
INSERT INTO tasks (title, brief, description, priority, type, status, start_date, links, notes, updated_at) INSERT INTO tasks (title, brief, description, priority, type, status, start_date, deadline, links, notes, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", ( """, (
task.get("title", ""), task.get("title", ""),
task.get("brief", ""), task.get("brief", ""),
@ -234,6 +252,7 @@ class TaskDB:
task.get("type"), task.get("type"),
task.get("status"), task.get("status"),
task.get("start_date"), task.get("start_date"),
task.get("deadline"),
json.dumps(task.get("links", []), ensure_ascii=False), json.dumps(task.get("links", []), ensure_ascii=False),
task.get("notes", ""), task.get("notes", ""),
now now
@ -244,7 +263,7 @@ class TaskDB:
def update_task(self, tid: int, task: dict): def update_task(self, tid: int, task: dict):
now = datetime.now(timezone.utc).isoformat() now = datetime.now(timezone.utc).isoformat()
self.conn.execute(""" self.conn.execute("""
UPDATE tasks SET title=?, brief=?, description=?, priority=?, type=?, status=?, start_date=?, links=?, notes=?, updated_at=? UPDATE tasks SET title=?, brief=?, description=?, priority=?, type=?, status=?, start_date=?, deadline=?, links=?, notes=?, updated_at=?
WHERE sid=? WHERE sid=?
""", ( """, (
task.get("title", ""), task.get("title", ""),
@ -254,6 +273,7 @@ class TaskDB:
task.get("type"), task.get("type"),
task.get("status"), task.get("status"),
task.get("start_date"), task.get("start_date"),
task.get("deadline"),
json.dumps(task.get("links", []), ensure_ascii=False), json.dumps(task.get("links", []), ensure_ascii=False),
task.get("notes", ""), task.get("notes", ""),
now, now,
@ -363,24 +383,37 @@ def compute_composite_score(task_row: dict) -> float:
Compute composite priority score using COMPOSITE_WEIGHTS. Compute composite priority score using COMPOSITE_WEIGHTS.
Higher number => more urgent. Higher number => more urgent.
""" """
# 读取数据 # 任务开始以来的天数
start_date = task_row.get("start_date") start_date = task_row.get("start_date")
days = 0 days_from_start = 0
try: try:
if start_date: if start_date:
dt = datetime.fromisoformat(start_date) dt = datetime.fromisoformat(start_date)
# convert to local naive days # convert to local naive days
days = (datetime.now(dt.tzinfo or timezone.utc).date() - dt.date()).days days_from_start = (datetime.now(dt.tzinfo or timezone.utc).date() - dt.date()).days
if days < 0: if days_from_start < 0:
days = 0 days_from_start = 0
except Exception:
days_from_start = 0
# 距离截止日期的时间
deadline = task_row.get("deadline")
have_deadline = False
days_to_deadline = 0
try:
if deadline:
dt_deadline = datetime.fromisoformat(deadline)
days_to_deadline = (dt_deadline.date() - datetime.now(dt_deadline.tzinfo or timezone.utc).date()).days
have_deadline = True
except Exception: except Exception:
days = 0 have_deadline = False
d_score = COMPOSITE_WEIGHTS.get("age_factor", 0.1) * days + 1 # 各种因素分数
ddl_score = 1 + math.exp(-(0.3 + days_to_deadline / 3.0)) if have_deadline else 0.8
d_score = COMPOSITE_WEIGHTS.get("age_factor", 0.1) * days_from_start + 1
p_score = COMPOSITE_WEIGHTS["priority"].get(task_row.get("priority"), 1.0) p_score = COMPOSITE_WEIGHTS["priority"].get(task_row.get("priority"), 1.0)
t_score = COMPOSITE_WEIGHTS["type"].get(task_row.get("type"), 1.0) t_score = COMPOSITE_WEIGHTS["type"].get(task_row.get("type"), 1.0)
s_score = COMPOSITE_WEIGHTS["status"].get(task_row.get("status"), 1.0) s_score = COMPOSITE_WEIGHTS["status"].get(task_row.get("status"), 1.0)
# 计算综合优先级分数 # 计算综合优先级分数
score = p_score * t_score * s_score * d_score score = p_score * t_score * s_score * d_score * ddl_score
return round(float(score), 6) return round(float(score), 6)
@ -401,6 +434,7 @@ class TaskEditor(ctk.CTkToplevel):
self.title_var = ctk.StringVar() self.title_var = ctk.StringVar()
self.brief_var = ctk.StringVar() self.brief_var = ctk.StringVar()
self.start_var = ctk.StringVar(value=date.today().isoformat()) self.start_var = ctk.StringVar(value=date.today().isoformat())
self.deadline_var = ctk.StringVar(value="")
self.priority_var = ctk.StringVar() self.priority_var = ctk.StringVar()
self.type_var = ctk.StringVar() self.type_var = ctk.StringVar()
self.status_var = ctk.StringVar() self.status_var = ctk.StringVar()
@ -446,33 +480,37 @@ class TaskEditor(ctk.CTkToplevel):
ctk.CTkLabel(frm, text="Start Date (YYYY-MM-DD)").grid(row=8, column=0, columnspan=3, sticky="w", padx=pad, pady=(10,0)) ctk.CTkLabel(frm, text="Start Date (YYYY-MM-DD)").grid(row=8, column=0, columnspan=3, sticky="w", padx=pad, pady=(10,0))
ctk.CTkEntry(frm, textvariable=self.start_var).grid(row=9, column=0, columnspan=3, sticky="ew", padx=pad) ctk.CTkEntry(frm, textvariable=self.start_var).grid(row=9, column=0, columnspan=3, sticky="ew", padx=pad)
# deadline
ctk.CTkLabel(frm, text="Deadline (YYYY-MM-DD)").grid(row=10, column=0, columnspan=3, sticky="w", padx=pad, pady=(10,0))
ctk.CTkEntry(frm, textvariable=self.deadline_var).grid(row=11, column=0, columnspan=3, sticky="ew", padx=pad)
# links # links
ctk.CTkLabel(frm, text="Links (one per line)").grid(row=10, column=0, columnspan=3, sticky="w", padx=pad, pady=(10,0)) ctk.CTkLabel(frm, text="Links (one per line)").grid(row=12, column=0, columnspan=3, sticky="w", padx=pad, pady=(10,0))
self.links_text = ctk.CTkTextbox(frm, height=80) self.links_text = ctk.CTkTextbox(frm, height=80)
self.links_text.grid(row=11, column=0, columnspan=3, sticky="nsew", padx=pad) self.links_text.grid(row=13, column=0, columnspan=3, sticky="nsew", padx=pad)
# logs (processed dates) # logs (processed dates)
ctk.CTkLabel(frm, text="Processed Dates (handling records)").grid(row=12, column=0, columnspan=3, sticky="w", padx=pad, pady=(10,0)) ctk.CTkLabel(frm, text="Processed Dates (handling records)").grid(row=14, column=0, columnspan=3, sticky="w", padx=pad, pady=(10,0))
logs_frame = ctk.CTkFrame(frm) logs_frame = ctk.CTkFrame(frm)
logs_frame.grid(row=13, column=0, columnspan=3, sticky="ew", padx=pad, pady=(4,0)) logs_frame.grid(row=15, column=0, columnspan=3, sticky="ew", padx=pad, pady=(4,0))
ctk.CTkButton(logs_frame, text="Mark Today", width=120, command=self._mark_today).pack(side="left", padx=6, pady=6) ctk.CTkButton(logs_frame, text="Mark Today", width=120, command=self._mark_today).pack(side="left", padx=6, pady=6)
ctk.CTkButton(logs_frame, text="Add Date...", width=120, command=self._add_date_dialog).pack(side="left", padx=6, pady=6) ctk.CTkButton(logs_frame, text="Add Date...", width=120, command=self._add_date_dialog).pack(side="left", padx=6, pady=6)
ctk.CTkButton(logs_frame, text="Remove Selected", fg_color="#cc4444", hover_color="#aa3333", command=self._remove_selected_date).pack(side="right", padx=6, pady=6) ctk.CTkButton(logs_frame, text="Remove Selected", fg_color="#cc4444", hover_color="#aa3333", command=self._remove_selected_date).pack(side="right", padx=6, pady=6)
# list widget for logs (tk Listbox embedded) # list widget for logs (tk Listbox embedded)
self.logs_listbox = tk.Listbox(frm, height=5) self.logs_listbox = tk.Listbox(frm, height=5)
self.logs_listbox.grid(row=14, column=0, columnspan=3, sticky="nsew", padx=pad, pady=(4,0)) self.logs_listbox.grid(row=16, column=0, columnspan=3, sticky="nsew", padx=pad, pady=(4,0))
# buttons # buttons
btn_row = ctk.CTkFrame(frm) btn_row = ctk.CTkFrame(frm)
btn_row.grid(row=15, column=0, columnspan=3, pady=(12,6)) btn_row.grid(row=17, column=0, columnspan=3, pady=(12,6))
ctk.CTkButton(btn_row, text="Save", command=self._save).pack(side="left", padx=8) ctk.CTkButton(btn_row, text="Save", command=self._save).pack(side="left", padx=8)
ctk.CTkButton(btn_row, text="Cancel", fg_color="#888", hover_color="#666", command=self.destroy).pack(side="left", padx=8) ctk.CTkButton(btn_row, text="Cancel", fg_color="#888", hover_color="#666", command=self.destroy).pack(side="left", padx=8)
# grid weights # grid weights
frm.grid_rowconfigure(5, weight=1) frm.grid_rowconfigure(5, weight=1)
frm.grid_rowconfigure(11, weight=0) frm.grid_rowconfigure(13, weight=0)
frm.grid_rowconfigure(14, weight=0) frm.grid_rowconfigure(16, weight=0)
frm.grid_columnconfigure(0, weight=1) frm.grid_columnconfigure(0, weight=1)
frm.grid_columnconfigure(1, weight=1) frm.grid_columnconfigure(1, weight=1)
frm.grid_columnconfigure(2, weight=1) frm.grid_columnconfigure(2, weight=1)
@ -489,6 +527,7 @@ class TaskEditor(ctk.CTkToplevel):
self.type_cb.set(row.get("type") or "") self.type_cb.set(row.get("type") or "")
self.status_cb.set(row.get("status") or "") self.status_cb.set(row.get("status") or "")
self.start_var.set(row.get("start_date") or "") self.start_var.set(row.get("start_date") or "")
self.deadline_var.set(row.get("deadline") or "")
links = json.loads(row.get("links") or "[]") links = json.loads(row.get("links") or "[]")
self.links_text.delete("1.0", "end"); self.links_text.insert("1.0", "\n".join(links)) self.links_text.delete("1.0", "end"); self.links_text.insert("1.0", "\n".join(links))
# logs # logs
@ -556,6 +595,7 @@ class TaskEditor(ctk.CTkToplevel):
"type": self.type_cb.get() or None, "type": self.type_cb.get() or None,
"status": self.status_cb.get() or None, "status": self.status_cb.get() or None,
"start_date": self.start_var.get().strip() or date.today().isoformat(), "start_date": self.start_var.get().strip() or date.today().isoformat(),
"deadline": self.deadline_var.get().strip() or "",
"links": links, "links": links,
"processed_dates": getattr(self, "_logs", []) "processed_dates": getattr(self, "_logs", [])
} }
@ -575,6 +615,7 @@ class TaskEditor(ctk.CTkToplevel):
"type": data["type"], "type": data["type"],
"status": data["status"], "status": data["status"],
"start_date": data["start_date"], "start_date": data["start_date"],
"deadline": data["deadline"],
"links": data["links"], "links": data["links"],
"notes": data["notes"] "notes": data["notes"]
}) })
@ -595,6 +636,7 @@ class TaskEditor(ctk.CTkToplevel):
"type": data["type"], "type": data["type"],
"status": data["status"], "status": data["status"],
"start_date": data["start_date"], "start_date": data["start_date"],
"deadline": data["deadline"],
"links": data["links"], "links": data["links"],
"notes": data["notes"], "notes": data["notes"],
}) })
@ -725,7 +767,7 @@ class TaskManagerApp(ctk.CTk):
# 指定列居中 # 指定列居中
align_center_cols = [] align_center_cols = []
for i, (key, _) in enumerate(COLUMNS): for i, (key, _) in enumerate(COLUMNS):
if key in ('sid', 'priority', 'type', 'status', 'start_date', 'processed_today', 'last_processed', 'links_count', 'composite'): if key in ('sid', 'priority', 'type', 'status', 'start_date', 'processed_today', 'last_processed', 'links_count', 'composite', 'deadline'):
align_center_cols.append(i) align_center_cols.append(i)
self.sheet.align_columns(columns=align_center_cols, align="center") self.sheet.align_columns(columns=align_center_cols, align="center")
@ -758,6 +800,20 @@ class TaskManagerApp(ctk.CTk):
elif col == "processed_today": elif col == "processed_today":
today_iso = date.today().isoformat() today_iso = date.today().isoformat()
rows.sort(key=lambda r: (today_iso in self.db.get_logs_for_task(r["sid"])), reverse=not self.order_asc) rows.sort(key=lambda r: (today_iso in self.db.get_logs_for_task(r["sid"])), reverse=not self.order_asc)
elif col == "deadline":
# Treat empty/null deadlines as greater than any date so they appear last when sorting ascending
def _deadline_key(r):
d = r.get("deadline")
if not d:
# missing deadline -> mark as 'empty' (1) and None for tie
return (1, None)
try:
dt = datetime.fromisoformat(d)
return (0, dt)
except Exception:
# fallback to string compare (ISO-like strings sort correctly)
return (0, d)
rows.sort(key=_deadline_key, reverse=not self.order_asc)
else: else:
rows.sort(key=lambda r: r.get(col) or "", reverse=not self.order_asc) rows.sort(key=lambda r: r.get(col) or "", reverse=not self.order_asc)
@ -801,6 +857,8 @@ class TaskManagerApp(ctk.CTk):
row.append(r.get("last_processed") or "") row.append(r.get("last_processed") or "")
elif key == "start_date": elif key == "start_date":
row.append(r.get("start_date") or "") row.append(r.get("start_date") or "")
elif key == "deadline":
row.append(r.get("deadline") or "")
elif key == "links_count": elif key == "links_count":
row.append(str(links_count)) row.append(str(links_count))
elif key == "notes": elif key == "notes":
@ -857,6 +915,7 @@ class TaskManagerApp(ctk.CTk):
for r_idx, tid in enumerate(self.displayed_sids): for r_idx, tid in enumerate(self.displayed_sids):
task = self.db.get_task(tid) task = self.db.get_task(tid)
pr = task.get("priority"); ty = task.get("type"); st = task.get("status") pr = task.get("priority"); ty = task.get("type"); st = task.get("status")
ddl = task.get("deadline")
# check if processed today using processed_map # check if processed today using processed_map
processed = processed_map.get(tid, False) processed = processed_map.get(tid, False)
if pr and pr in PRIORITY_DISPLAY: if pr and pr in PRIORITY_DISPLAY:
@ -877,6 +936,27 @@ class TaskManagerApp(ctk.CTk):
except Exception: except Exception:
try: self.sheet.set_cell_bg(r_idx,COL_STATUS,bg) try: self.sheet.set_cell_bg(r_idx,COL_STATUS,bg)
except Exception: pass except Exception: pass
if ddl:
try:
dt_deadline = datetime.fromisoformat(ddl)
days_to_deadline = (dt_deadline.date() - datetime.now(dt_deadline.tzinfo or timezone.utc).date()).days
for (d, c) in DEADLINE_COLOR:
if days_to_deadline <= d:
bg = c
try: self.sheet.highlight_cells(row=r_idx, column=COL_DEADLINE, bg=bg)
except Exception:
try: self.sheet.set_cell_bg(r_idx,COL_DEADLINE,bg)
except Exception: pass
break
except Exception:
pass
else:
# 取最后一个颜色
bg = DEADLINE_COLOR[-1][1]
try: self.sheet.highlight_cells(row=r_idx, column=COL_DEADLINE, bg=bg)
except Exception:
try: self.sheet.set_cell_bg(r_idx,COL_DEADLINE,bg)
except Exception: pass
# processed today column: use COL_PROCESSED_TODAY constant # processed today column: use COL_PROCESSED_TODAY constant
if processed: if processed:
bg = PROCESSED_DISPLAY["yes"]["bg"] bg = PROCESSED_DISPLAY["yes"]["bg"]

Loading…
Cancel
Save