diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 9416ff31..7cbef659 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -3852,7 +3852,10 @@ const ensureUserWorkspace = async (db: D1Database, userId: string, username: str const existing = await db.prepare( `SELECT workspace_id, role FROM workspace_members WHERE user_id = ? LIMIT 1` ).bind(userId).first<{ workspace_id: string; role: "owner" | "member" }>(); - if (existing) return { workspaceId: existing.workspace_id, role: existing.role }; + if (existing) { + await ensureWorkspaceTemplateSeed(db, existing.workspace_id); + return { workspaceId: existing.workspace_id, role: existing.role }; + } const defaultOwner = await db.prepare( `SELECT user_id FROM workspace_members WHERE workspace_id = ? LIMIT 1` @@ -3864,7 +3867,10 @@ const ensureUserWorkspace = async (db: D1Database, userId: string, username: str const claimed = await db.prepare( `SELECT workspace_id, role FROM workspace_members WHERE user_id = ? LIMIT 1` ).bind(userId).first<{ workspace_id: string; role: "owner" | "member" }>(); - if (claimed) return { workspaceId: claimed.workspace_id, role: claimed.role }; + if (claimed) { + await ensureWorkspaceTemplateSeed(db, claimed.workspace_id); + return { workspaceId: claimed.workspace_id, role: claimed.role }; + } } const workspaceId = createId("ws"); @@ -3880,6 +3886,7 @@ const ensureUserWorkspace = async (db: D1Database, userId: string, username: str VALUES (?, ?, NULL, ?, ?, 'notebook', ?, ?, ?, ?)` ).bind(notebook.id, workspaceId, notebook.name, notebook.slug, notebook.color, notebook.sortOrder, now, now)), ]); + await ensureWorkspaceTemplateSeed(db, workspaceId); return { workspaceId, role: "member" as const }; }; @@ -3891,6 +3898,30 @@ const createDefaultNotebookRows = (workspaceId: string, _now: string) => [ { id: `${workspaceId}_personal`, name: "生活个人", slug: "personal-life", color: "#ea580c", sortOrder: 50 }, ]; +const ensureWorkspaceTemplateSeed = async (db: D1Database, workspaceId: string) => { + const now = isoNow(); + const templateId = `${workspaceId}_template_project_weekly`; + const contentMarkdown = "## 本周进展\n\n- \n\n## 关键成果\n\n- \n\n## 风险与阻塞\n\n- \n\n## 下周计划\n\n- [ ] \n\n## 需要协助\n\n- "; + const contentJson = markdownToDoc(contentMarkdown); + + await db.prepare( + `INSERT OR IGNORE INTO memo_templates ( + id, workspace_id, name, description, title, content_json, content_markdown, tags_json, created_at, updated_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` + ).bind( + templateId, + workspaceId, + "项目周报模板", + "每周同步项目进展、风险与下一步计划", + "项目周报|第 {{周次}} 周", + JSON.stringify(contentJson), + contentMarkdown, + JSON.stringify(["项目管理", "周报"]), + now, + now, + ).run(); +}; + const createSession = async (c: AppContext, user: UserRow, requestedDeviceId?: string) => { const token = randomToken(SESSION_TOKEN_BYTES); const id = createId("sess"); diff --git a/migrations/0017_seed_default_templates.sql b/migrations/0017_seed_default_templates.sql new file mode 100644 index 00000000..53244e26 --- /dev/null +++ b/migrations/0017_seed_default_templates.sql @@ -0,0 +1,31 @@ +PRAGMA foreign_keys = ON; + +-- Replace the original oversized demo template with a compact, reusable example. +DELETE FROM memo_templates +WHERE name = '产品周报模板' + AND description = '用于每周产品进展记录'; + +DELETE FROM memo_templates +WHERE name = '项目周报模板' + AND description = '每周同步项目进展、风险与下一步计划'; + +INSERT OR IGNORE INTO memo_templates ( + id, + workspace_id, + name, + description, + title, + content_json, + content_markdown, + tags_json +) +SELECT + id || '_template_project_weekly', + id, + '项目周报模板', + '每周同步项目进展、风险与下一步计划', + '项目周报|第 {{周次}} 周', + '{"type":"doc","content":[{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"本周进展"}]},{"type":"paragraph"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"关键成果"}]},{"type":"paragraph"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"风险与阻塞"}]},{"type":"paragraph"},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"下周计划"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph"}]}]},{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"需要协助"}]},{"type":"paragraph"}]}', + '## 本周进展\n\n- \n\n## 关键成果\n\n- \n\n## 风险与阻塞\n\n- \n\n## 下周计划\n\n- [ ] \n\n## 需要协助\n\n- ', + '["项目管理","周报"]' +FROM workspaces;