V3.2 送达者=用户 + 用户邮箱必填

- users 表新增 email 列:所有用户(含 admin)必须有邮箱,新建/编辑用户强制校验
- 项目送达者从'邮箱字符串'改为'绑定用户(deliver_user_id)':创建项目必须选择平台用户
- 送达通知实时读取用户最新邮箱:用户改邮箱 → 其送达的所有项目自动跟随,无需改项目
- 项目进行中可随时更换送达者用户(编辑项目 → 送达者下拉)
- 迁移:存量用户自动补 username@tphai.com 默认邮箱;旧项目按 deliver_email 匹配回填 deliver_user_id
- 新增 /api/users 轻量用户列表接口(登录即可,供选送达者);deliver_email 降级为快照缓存
- 前端:项目表单送达者改为用户下拉选择;用户管理增加邮箱列;交付页显示送达者用户名+邮箱
This commit is contained in:
2026-08-13 16:21:35 +08:00
parent 1f37344d03
commit 8be01b5af7
6 changed files with 173 additions and 57 deletions
+19 -1
View File
@@ -16,7 +16,8 @@ CREATE TABLE IF NOT EXISTS projects (
acceptance_criteria TEXT DEFAULT '',
status TEXT DEFAULT 'active', -- planning/active/done/archived
budget_limit REAL DEFAULT 0, -- 项目预算上限(元),0=不限
deliver_email TEXT DEFAULT '', -- 送达者(人)邮箱,新建项目必填
deliver_user_id INTEGER, -- 送达者用户 id(users.id),实时取该用户邮箱
deliver_email TEXT DEFAULT '', -- 送达者邮箱快照(兼容/展示,发送时以用户最新邮箱为准)
deliver_type TEXT DEFAULT 'web', -- 交付物类型 web=网页 / file=文件包
deliver_note TEXT DEFAULT '', -- 交付说明
workspace_dir TEXT DEFAULT '', -- 项目工作目录(相对 data/ 的目录名)
@@ -241,6 +242,7 @@ CREATE TABLE IF NOT EXISTS users (
username TEXT NOT NULL UNIQUE,
password_hash TEXT DEFAULT '',
display_name TEXT DEFAULT '',
email TEXT DEFAULT '', -- 用户邮箱(必填,送达/通知用)
role TEXT DEFAULT 'member', -- admin / member / auditor
source TEXT DEFAULT 'local', -- local / oidc / ldap
status TEXT DEFAULT 'active', -- active / disabled
@@ -391,6 +393,22 @@ def _migrate():
):
if col not in pcols:
conn.execute(ddl)
# V3.2projects 送达者改为用户 id(实时取邮箱)
if 'deliver_user_id' not in pcols:
conn.execute('ALTER TABLE projects ADD COLUMN deliver_user_id INTEGER')
# V3.2:users 邮箱列 + 存量用户默认邮箱 + 旧项目按邮箱回填送达者用户
ucols = {r['name'] for r in conn.execute('PRAGMA table_info(users)')}
if 'email' not in ucols:
conn.execute("ALTER TABLE users ADD COLUMN email TEXT DEFAULT ''")
for r in conn.execute('SELECT id, username, email FROM users WHERE email IS NULL OR email=\'\''):
conn.execute('UPDATE users SET email=? WHERE id=?',
(f'{r["username"]}@tphai.com', r['id']))
# 旧项目:按 deliver_email 匹配用户回填 deliver_user_id
for r in conn.execute("SELECT id, deliver_email FROM projects WHERE (deliver_user_id IS NULL OR deliver_user_id=0) "
"AND deliver_email IS NOT NULL AND deliver_email != ''"):
u = conn.execute('SELECT id FROM users WHERE email=?', (r['deliver_email'],)).fetchone()
if u:
conn.execute('UPDATE projects SET deliver_user_id=? WHERE id=?', (u['id'], r['id']))
# V3:老项目补齐工作目录名
for r in conn.execute("SELECT id, workspace_dir FROM projects WHERE workspace_dir IS NULL OR workspace_dir=''"):
conn.execute('UPDATE projects SET workspace_dir=? WHERE id=?',