skill-forge-hub 1.0.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.en.md +19 -0
- package/CHANGELOG.md +19 -0
- package/README.en.md +20 -7
- package/README.md +20 -7
- package/SKILLS_CATALOG.md +119 -0
- package/annual-report/SKILL.md +13 -3
- package/annual-report/resources/disk-and-html.md +1 -0
- package/annual-report/resources/reference.html +3 -3
- package/annual-report/resources/skillforge-guide.html +409 -0
- package/annual-report/resources/skillforge-guide.txt +132 -0
- package/annual-report/user-config.md +1 -1
- package/article-to-html/SKILL.md +13 -1
- package/article-to-html/resources/skillforge-guide.html +409 -0
- package/article-to-html/resources/skillforge-guide.txt +132 -0
- package/article-to-html/user-config.md +1 -1
- package/cli.js +60 -19
- package/commit-heatmap/SKILL.md +70 -0
- package/commit-heatmap/resources/collect.md +22 -0
- package/commit-heatmap/resources/generate.md +15 -0
- package/commit-heatmap/resources/html-rules.md +21 -0
- package/commit-heatmap/resources/reference.html +228 -0
- package/commit-heatmap/resources/skillforge-guide.html +409 -0
- package/commit-heatmap/resources/skillforge-guide.txt +132 -0
- package/commit-heatmap/resources/usage-guide.md +23 -0
- package/commit-heatmap/user-config.md +12 -0
- package/daily-report/SKILL.md +12 -2
- package/daily-report/resources/disk-and-html.md +1 -1
- package/daily-report/resources/reference.html +1 -1
- package/daily-report/resources/skillforge-guide.html +409 -0
- package/daily-report/resources/skillforge-guide.txt +132 -0
- package/daily-report/user-config.md +1 -1
- package/data-prepper/SKILL.md +54 -0
- package/data-prepper/resources/clean-rules.md +18 -0
- package/data-prepper/resources/overview.md +17 -0
- package/data-prepper/resources/read-data.md +13 -0
- package/data-prepper/resources/skillforge-guide.html +409 -0
- package/data-prepper/resources/skillforge-guide.txt +132 -0
- package/data-prepper/resources/usage-guide.md +24 -0
- package/data-prepper/user-config.md +11 -0
- package/decision-log/SKILL.md +53 -0
- package/decision-log/resources/index.md +21 -0
- package/decision-log/resources/record.md +19 -0
- package/decision-log/resources/skillforge-guide.html +409 -0
- package/decision-log/resources/skillforge-guide.txt +132 -0
- package/decision-log/resources/usage-guide.md +23 -0
- package/decision-log/user-config.md +9 -0
- package/deck-stage/SKILL.md +14 -11
- package/deck-stage/resources/cover-template.html +1 -1
- package/deck-stage/resources/skillforge-guide.html +409 -0
- package/deck-stage/resources/skillforge-guide.txt +132 -0
- package/docs/architecture.en.md +2 -1
- package/docs/architecture.md +2 -1
- package/docs/articles/ai-daily-report-correct-pose.md +39 -0
- package/docs/articles/ai-prompt-management-skill-pouch.md +37 -0
- package/docs/directory-submission.md +106 -0
- package/docs/install.en.md +57 -1
- package/docs/install.md +57 -1
- package/docs/usage-examples.en.md +50 -0
- package/docs/usage-examples.md +50 -0
- package/magic-deck/SKILL.md +15 -6
- package/magic-deck/resources/deck-spec.md +1 -1
- package/magic-deck/resources/reference.html +1 -1
- package/magic-deck/resources/skillforge-guide.html +409 -0
- package/magic-deck/resources/skillforge-guide.txt +132 -0
- package/magic-deck/user-config.md +1 -1
- package/meeting-minutes/SKILL.md +11 -1
- package/meeting-minutes/resources/disk-and-html.md +1 -0
- package/meeting-minutes/resources/reference.html +1 -1
- package/meeting-minutes/resources/skillforge-guide.html +409 -0
- package/meeting-minutes/resources/skillforge-guide.txt +132 -0
- package/meeting-minutes/user-config.md +1 -1
- package/meta-forge/SKILL.md +13 -3
- package/meta-forge/resources/forge-rules.md +4 -1
- package/meta-forge/resources/skillforge-guide.html +409 -0
- package/meta-forge/resources/skillforge-guide.txt +132 -0
- package/meta-forge/user-config.md +1 -1
- package/monthly-report/SKILL.md +11 -1
- package/monthly-report/resources/disk-and-html.md +1 -0
- package/monthly-report/resources/reference.html +1 -1
- package/monthly-report/resources/skillforge-guide.html +409 -0
- package/monthly-report/resources/skillforge-guide.txt +132 -0
- package/monthly-report/user-config.md +1 -1
- package/one-pager/SKILL.md +83 -0
- package/one-pager/resources/content.md +18 -0
- package/one-pager/resources/design-process.md +117 -0
- package/one-pager/resources/generate.md +28 -0
- package/one-pager/resources/html-rules.md +66 -0
- package/one-pager/resources/reference.html +1290 -0
- package/one-pager/resources/skillforge-guide.html +409 -0
- package/one-pager/resources/skillforge-guide.txt +132 -0
- package/one-pager/resources/usage-guide.md +37 -0
- package/one-pager/resources/user-template-example.html +63 -0
- package/one-pager/user-config.md +14 -0
- package/package.json +12 -2
- package/prompt-pouch/SKILL.md +16 -16
- package/prompt-pouch/resources/reference.html +181 -43
- package/prompt-pouch/resources/skillforge-guide.html +409 -0
- package/prompt-pouch/resources/skillforge-guide.txt +132 -0
- package/prompt-pouch/resources/usage-guide.md +3 -3
- package/quarterly-report/SKILL.md +11 -1
- package/quarterly-report/resources/disk-and-html.md +1 -0
- package/quarterly-report/resources/reference.html +1 -1
- package/quarterly-report/resources/skillforge-guide.html +409 -0
- package/quarterly-report/resources/skillforge-guide.txt +132 -0
- package/quarterly-report/user-config.md +1 -1
- package/release-notes/SKILL.md +54 -0
- package/release-notes/resources/collect.md +17 -0
- package/release-notes/resources/publish-checklist.md +11 -0
- package/release-notes/resources/skillforge-guide.html +409 -0
- package/release-notes/resources/skillforge-guide.txt +132 -0
- package/release-notes/resources/usage-guide.md +25 -0
- package/release-notes/resources/write.md +27 -0
- package/release-notes/user-config.md +15 -0
- package/skill-doctor/SKILL.md +53 -0
- package/skill-doctor/resources/checks.md +27 -0
- package/skill-doctor/resources/report.md +26 -0
- package/skill-doctor/resources/skillforge-guide.html +409 -0
- package/skill-doctor/resources/skillforge-guide.txt +132 -0
- package/skill-doctor/resources/usage-guide.md +22 -0
- package/skill-doctor/user-config.md +9 -0
- package/spec-doc2spec/SKILL.md +13 -9
- package/spec-doc2spec/resources/skillforge-guide.html +409 -0
- package/spec-doc2spec/resources/skillforge-guide.txt +132 -0
- package/spec-doc2spec/user-config.md +1 -1
- package/spec-spec2doc/SKILL.md +13 -12
- package/spec-spec2doc/resources/skillforge-guide.html +409 -0
- package/spec-spec2doc/resources/skillforge-guide.txt +132 -0
- package/spec-spec2doc/user-config.md +1 -1
- package/team-report-collector/SKILL.md +70 -0
- package/team-report-collector/resources/collect.md +23 -0
- package/team-report-collector/resources/generate.md +14 -0
- package/team-report-collector/resources/html-rules.md +22 -0
- package/team-report-collector/resources/reference.html +384 -0
- package/team-report-collector/resources/skillforge-guide.html +409 -0
- package/team-report-collector/resources/skillforge-guide.txt +132 -0
- package/team-report-collector/resources/usage-guide.md +25 -0
- package/team-report-collector/user-config.md +12 -0
- package/template/SKILL.md +2 -2
- package/template/user-config.md +1 -1
- package/twin-docs/SKILL.md +53 -0
- package/twin-docs/resources/glossary.md +12 -0
- package/twin-docs/resources/skillforge-guide.html +409 -0
- package/twin-docs/resources/skillforge-guide.txt +132 -0
- package/twin-docs/resources/sync-check.md +15 -0
- package/twin-docs/resources/translate.md +20 -0
- package/twin-docs/resources/usage-guide.md +24 -0
- package/twin-docs/user-config.md +11 -0
- package/weekly-report/SKILL.md +12 -2
- package/weekly-report/resources/disk-and-html.md +1 -1
- package/weekly-report/resources/reference.html +1 -1
- package/weekly-report/resources/skillforge-guide.html +409 -0
- package/weekly-report/resources/skillforge-guide.txt +132 -0
- package/weekly-report/user-config.md +1 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: team-report-collector
|
|
3
|
+
description: 把团队成员日报(今日进展/明日计划/风险阻塞)收集汇总为本地 HTML 收集台与数据文件:单文件离线可用的收集页(表单填写 + localStorage 记忆草稿 + 导出/导入 JSON)、reports.json 数据真相源、按日期分组的汇总 md。当用户请求收日报、团队日报收集、汇总成员日报、日报收集台、收集周报时使用。
|
|
4
|
+
allowed-tools: Bash, Read, Write
|
|
5
|
+
disable-model-invocation: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 团队日报收集(team-report-collector)
|
|
9
|
+
|
|
10
|
+
团队负责人的日报收集台:成员日报口述/文件进 → 汇总去重 → reports.json 数据真相源 + 单文件收集台 HTML + 汇总 md 三件套落盘。
|
|
11
|
+
|
|
12
|
+
## 生成流程
|
|
13
|
+
|
|
14
|
+
0. **读用户配置**(TEAM/TITLE/DIR/OPEN_HTML/THEME/REPORT_DATE)→ 先 Read 同目录 `user-config.md`
|
|
15
|
+
1. **收集数据**(成员日报口述 + 文件批量 + 页面导出 json 导入,合并去重)→ 读 `resources/collect.md`
|
|
16
|
+
2. **生成产物**(reports.json + 收集台 HTML + 汇总 md,先 Read reference.html 骨架替换数据)→ 读 `resources/generate.md` 与 `resources/html-rules.md` 两份
|
|
17
|
+
2.5 **交付前自检**(硬门禁不可跳过):HTML 文件写好后——
|
|
18
|
+
- 挂 pageerror 监听用 Chrome headless 访问页面(零容忍报错)→ 截全页 PNG Read 自查:标题卡、表单卡、汇总列表卡齐全,条目渲染无溢出、无豆腐块缺字
|
|
19
|
+
- 任何报错或视觉问题:修 HTML → 重检;全绿才进第 3 步
|
|
20
|
+
3. **使用咨询**(用户只问「日报收集怎么用」等用法、未要求收集)→ 读 `resources/usage-guide.md`,将其内容原样输出(首行标题改为「团队日报收集使用指南」),不收集、不落盘、不开浏览器
|
|
21
|
+
|
|
22
|
+
## ⚙️ 配置与自定义
|
|
23
|
+
|
|
24
|
+
**执行本 skill 前必须先 Read 同目录 `user-config.md`**:默认配置(TEAM/TITLE/DIR/OPEN_HTML/THEME/REPORT_DATE)都在该文件中,以它为准。升级技能时 user-config.md 不会被覆盖,你的修改永久保留;官方更新配置时另存 `user-config.upstream.md` 对照文件,可按需手动合并新配置点。
|
|
25
|
+
|
|
26
|
+
- **THEME**:收集台页面主题,tech 深蓝科技(默认)/ biz 浅色商务 / mono IDEA 黑亮 / light IDEA 白亮 / warm 温暖渐变;生成时写 `<html data-theme="THEME值">` 定默认,页面右下角换肤坞五色点随点随换(localStorage 记忆,键按页内嵌唯一 ID 隔离、多份产物互不串台、改名/移动目录记忆不丢;生成时头部写 `<meta name="trc-id" content="<UUID>">`,每次 crypto.randomUUID() 生成标准 UUID v4(8-4-4-4-12 十六进制,禁止手写变体、禁止沿用占位与旧值);落盘写文件前顺扫落盘目录下本技能命名的 html,读各文件 id meta 查重,撞号重掷至不重复)
|
|
27
|
+
|
|
28
|
+
## 配置版本机制(升级保护)
|
|
29
|
+
|
|
30
|
+
本 skill 当前配置版本为 `1`(对应 user-config.md 中的 `CONFIG_VERSION`)。执行时若发现 user-config.md 的 CONFIG_VERSION 与本节声明不一致:
|
|
31
|
+
|
|
32
|
+
1. 先将旧 user-config.md 备份为 `user-config.bak-<时间戳>.md`(同目录,绝不删除旧值)
|
|
33
|
+
2. 按本节「配置升级规则」迁移字段:新增字段补默认值、改名字段按映射改写、删除字段的值保留在备份中并在对话提示用户手动确认
|
|
34
|
+
3. 更新 CONFIG_VERSION 为当前版本
|
|
35
|
+
4. 对话中明确告知用户「检测到配置版本从 X 升级到 Y,旧配置已备份至 <路径>」
|
|
36
|
+
|
|
37
|
+
升级本 skill 时,配置结构如有变化必须同步更新本节的当前版本号与迁移说明;禁止在未声明版本变更的情况下静默修改配置语义。
|
|
38
|
+
## 文档同步自检纪律(维护者必读)
|
|
39
|
+
|
|
40
|
+
修改本 skill 任一文件(SKILL.md / user-config.md / resources/*)后,必须 grep 全文核对相关关键词在各文件间一致(字段名 / 流程节点 / 模板名改名时新旧词全仓核对,旧词零残留才算完成)。
|
|
41
|
+
## 🔧 报修处理流程(用户报页面问题时)
|
|
42
|
+
|
|
43
|
+
用户说「这个页面效果不对 / 布局乱了 / 有 UI 问题 / 样式错了 / 交互坏了」(常附截图或指出具体现象)→ 按以下流程处理,不以「重新生成一份」敷衍:
|
|
44
|
+
|
|
45
|
+
1. **立标准**:先 Read 本 skill 目录 `resources/reference.html`——它就是设计标准答案(布局/配色/交互全在代码里)
|
|
46
|
+
2. **找问题**:Read 用户那份问题 html 文件,与 reference 逐处比对(结构顺序 / CSS 变量 / 关键类名 / 交互 JS),定位跑偏处;用户给了截图则按截图现象反查
|
|
47
|
+
3. **修复**:以 reference 为准修复那份 html(只修跑偏处,不动正确内容;reference 与 html 不一致时以 reference 为准)
|
|
48
|
+
4. **自证**:Chrome headless 访问修复后页面截全页 PNG,Read 自查修复点恢复标准效果
|
|
49
|
+
5. **汇报**:一句话说清问题根因 + 修复了什么 + 附截图;若根因在 reference.html 自身,顺修 reference.html 对应处并在汇报中说明「参考模板已同步修正」
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## 产物升级(回炉)
|
|
53
|
+
|
|
54
|
+
生成 HTML 时头部写版本戳 `<meta name="sf-template" content="team-report-collector@1">`(模板升级时递增 @N 并同步 reference.html 与本文档)。用户说「升级旧收集台/回炉」时:扫落盘目录读版本戳筛旧版(无版本戳或缺少 `<meta name="trc-id">` 稳定 ID 的产物视为 v0 最旧版,一并进清单)→ 列清单(文件/旧版本)→ AskUserQuestion 选全部或部分 → 逐份升级:浅升级(仅 CSS/JS 变化)对旧页替换 `<style>` 块与交互脚本、正文原样保留;深升级(DOM 结构变化)从同目录 reports.json 数据按当前 reference.html 重建,先备份旧版 `.bak-时间戳`,重建必须沿用原页 trc-id meta 值(换 ID = 页面运行时收集的本地数据失联)→ 报告三段式:✅ 已升级清单 / ⚠️ 手改保留说明 / 🟡 失败项原因。模板改动分级:业务改动、数据格式改动、页面改动任一发生即模板升级,版本戳 +1 并同步 reference.html 与本文档;纯措辞润色不 bump。每次生成 HTML 时顺扫落盘目录读版本戳:发现旧版产物主动告知用户「说『把我旧收集台都升级成新样式』即可一键升级」。
|
|
55
|
+
|
|
56
|
+
## 规则速览
|
|
57
|
+
|
|
58
|
+
- 数据真相源:reports.json 为唯一真相源(字段 name/date/progress/plan/risk),md 与 html 都从它重建;页面运行时的新增/修改存 localStorage(键 `trc:<ID>-reports`,内嵌 ID 命名空间,多份产物互不串台),导出 JSON 后才并入真相源
|
|
59
|
+
- 汇总去重:同一成员同一天多条日报合并为一条(进展/计划拼接,风险合并);日期统一 YYYY-MM-DD
|
|
60
|
+
- 落盘完成后对话必须报告落盘位置:完整路径清单(reports.json + html + md),并注明 html 是否已在浏览器打开
|
|
61
|
+
- 脱敏纪律:页面演示数据与文档示例零真实身份(示例成员用张工/李工等通用占位),页脚署名固定 GENERATED BY AI TEAM
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 🔍 SkillForge 使用指引(整体咨询时触发)
|
|
66
|
+
|
|
67
|
+
当用户询问 **SkillForge 本身**(不是单个技能用法)——「skillforge 怎么用 / 使用说明 / 使用指引 / 是什么」「技能怎么安装 / 怎么升级 / 装了哪些技能 / 技能清单」「skill-forge ls / init / update 等命令怎么用」「技能安装器 / 技能锻造坊」等(中英文、近似说法均可,关键词可自由扩展):
|
|
68
|
+
1. Read 同目录 `resources/skillforge-guide.txt` 全文,按其内容整理回答(命令与参数以 txt 为准,勿自行编造)
|
|
69
|
+
2. 用系统命令打开同目录 `resources/skillforge-guide.html`(macOS `open`,Windows `start`),让用户在浏览器看排版版
|
|
70
|
+
3. 用户只问单个技能怎么用时(如「日报怎么用」)不触发本指引,走本技能的使用说明
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 收集数据(阶段 1)
|
|
2
|
+
|
|
3
|
+
## 数据来源(三种,可混用)
|
|
4
|
+
|
|
5
|
+
1. **口述**:用户直接说「张三:今日做了 A,明日做 B,无风险」「李四的日报:…」→ 逐人整理为字段
|
|
6
|
+
2. **文件批量**:用户给 md/txt/csv/xlsx 文件(每位成员一段/一行)→ Read/解析后按人拆条;csv/xlsx 表头需含 成员/日期/进展/计划/风险 任几列,缺失列留空
|
|
7
|
+
3. **页面导出导入**:用户在收集台页面填完点「导出 JSON」得到 reports.json → 用户发回该文件时以它为准合并(同成员同日期覆盖旧值)
|
|
8
|
+
|
|
9
|
+
## 字段规范
|
|
10
|
+
|
|
11
|
+
| 字段 | 说明 |
|
|
12
|
+
|:---|:---|
|
|
13
|
+
| name | 成员名(显示用) |
|
|
14
|
+
| date | 日报日期 YYYY-MM-DD(缺省用 REPORT_DATE 或今天) |
|
|
15
|
+
| progress | 今日进展(做了什么) |
|
|
16
|
+
| plan | 明日计划(准备做什么) |
|
|
17
|
+
| risk | 风险阻塞(无则空字符串,不写「无」之外的套话) |
|
|
18
|
+
|
|
19
|
+
## 合并去重
|
|
20
|
+
|
|
21
|
+
- 同一成员(name)+ 同一天(date)多条 → 合并:progress 以「;」拼接、plan 同样拼接、risk 合并去重
|
|
22
|
+
- 日期统一 YYYY-MM-DD;成员名保留用户原话写法(不擅自改花名/英文名)
|
|
23
|
+
- 收集结果清单(成员数 / 日报条数 / 缺报成员提示——TEAM 只影响标题不影响名单,名单以本次收集实际成员为准)展示给用户确认后进阶段 2
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# 生成产物(阶段 2)
|
|
2
|
+
|
|
3
|
+
## 三件套(全部落盘到 DIR)
|
|
4
|
+
|
|
5
|
+
1. **reports.json**(数据真相源):数组结构 `[{"name":"张工","date":"2026-11-12","progress":"…","plan":"…","risk":""}]`;每次生成整体重写该文件,页面导出的更新以它为准合并
|
|
6
|
+
2. **team-report.html**(收集台):先 Read `resources/reference.html` 全文,以其为骨架模板逐处替换数据——①头部 meta:`sf-template` 版本戳保持当前模板版本、`trc-id` 换成新 UUID(crypto.randomUUID() 标准 v4,落盘前顺扫落盘目录下本技能命名的 html 读 id meta 查重,撞号重掷)②`<title>` 与头部标题卡文字换成 TITLE ③`window.TRC_DATA = [...]` 初始数据数组换成本次收集结果(JSON 序列化,注意转义引号)④日期徽章换成 REPORT_DATE。其余(CSS/JS/结构)一律不许动;样式参数解释与禁止项见 `resources/html-rules.md`
|
|
7
|
+
3. **summary.md**(汇总):按日期分组的 Markdown 汇总——`## 2026-11-12(N 人已报)` 下每位成员一段(进展/计划/风险三行),末尾「风险集中项」小节聚合非空 risk 条目;对话中照常输出汇总正文
|
|
8
|
+
|
|
9
|
+
## 落盘纪律
|
|
10
|
+
|
|
11
|
+
- 文件名:`team-report.html` + `reports.json` + `summary.md`(同目录并存,目录已存在直接复用,只覆盖本清单内同名文件)
|
|
12
|
+
- OPEN_HTML: true 且落盘了 html 时自动打开浏览器(macOS:open <html文件>;Windows PowerShell:Start-Process <html文件>)
|
|
13
|
+
- **落盘完成后对话报告落盘位置**:完整路径清单(三件套),并注明 html 是否已在浏览器打开
|
|
14
|
+
- 同一目录重复生成时:以最新收集数据为准重写三件套;页面里用户新增但未导出的本地数据无法读取,提示用户「先导出 JSON 再发我,我帮你并入」
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
> ⛔ **Reference 铁律(最高优先)**:本目录 `reference.html` 是定稿样式源码。生成 HTML 时必须先 Read `resources/reference.html` 与本文件两份,以 reference.html 为骨架模板逐处替换数据(标题/日期徽章/TRC_DATA 数组/trc-id UUID),本文件的描述是参数解释、变体规则与禁止项;两者冲突时**以 reference.html 为准**。修改本 skill 的 HTML 效果时,必须同步更新 `resources/reference.html` 与本文档的对应描述,禁止只改一处。
|
|
2
|
+
|
|
3
|
+
# 收集台 HTML 版式(五主题令牌 + 科技感背景层,与日报/周报同体系)
|
|
4
|
+
|
|
5
|
+
## 版式总览
|
|
6
|
+
|
|
7
|
+
- 五主题令牌:tech(深蓝科技,默认)/ biz(浅色商务)/ mono(IDEA 黑亮)/ light(IDEA 白亮)/ warm(温暖渐变),色值与 daily-report 同一套 12 核心契约(另含收集台扩展 --panel2 列表条目底、--input-bg 表单输入底);`html[data-theme]` 运行时切换;右下角换肤坞五色点随点随换、localStorage 记忆(键 `trc:<ID>-theme`,ID = 页内嵌 trc-id meta,多份产物互不串台、改名/移动目录记忆不丢)
|
|
8
|
+
- 字体全用系统本地字体栈(ui-monospace/'SF Mono'/SFMono-Regular/Menlo/Consolas/system-ui,品牌字体 PingFang/YaHei/apple-system 零出现),禁止 CDN、@import、外链 CSS/JS/图片/网络字体——页面离线双击可开
|
|
9
|
+
- 三张卡:标题卡(团队名 + 日期徽章 + 统计三数:成员数/日报条数/风险条数)+ 表单卡(姓名/日期/进展/计划/风险五字段 + 保存按钮)+ 汇总列表卡(按日期分组的成员条目 + 导出 JSON / 导入 JSON 按钮)
|
|
10
|
+
- 多文件隔离(必植):头部写 `<meta name="trc-id" content="<UUID>">`(crypto.randomUUID() 标准 UUID v4);localStorage 键一律 `trc:<ID>-xxx`(xxx 为具体用途后缀 theme/reports),禁止裸通用键名;页面 JS 启动时校验 id meta——非法或缺失(占位残留/手写变体/误沿用旧值)时按路径键(`'sf-heal:' + location.pathname`)自愈为 crypto.randomUUID() 标准 v4 并回写 meta,console.warn 显性报警;路径键持久化保证同文件跨打开稳定复用;合法 UUID 原样放行
|
|
11
|
+
- 版本戳:`<meta name="sf-template" content="team-report-collector@1">`(模板升级递增 @N)
|
|
12
|
+
- 入场动画:三张卡错峰上浮淡入(标题 0s/表单 0.13s/列表 0.26s);卡片入场动画 fill-mode 必须用 backwards 严禁 both(both 使动画结束帧覆盖 hover transform);滚动入场用 IntersectionObserver + 2s 兜底 setTimeout 强制全显(headless 截图 / 打印预览 / PDF 导出环境卡片不得永久隐藏)
|
|
13
|
+
- 科技感背景层四件套(与日报/周报同款):SVG 微噪点(opacity .04,mono 退隐)+ 60px 网格底纹 + 星点(biz/light/warm 退隐 .28、mono 灰白化)+ 全屏扫描线 + 循环光带;容器 .wrap 宽 clamp(640px, 60%, 1200px)(移动端 100%);卡片面板实色 + 8px 水平条纹 + 上下高光线 + 圆角 6px + 卡阴影;头部卡含光晕呼吸(.card-glow)与四边扫描线(.scanline-el);标题渐变文字(--title-grad)+ 光晕
|
|
14
|
+
- ?shot 截图模式:页面 JS 检测 location.search 含 shot 时给 html 挂 data-shot 属性(CSS 关闭入场动画直接终态,headless 虚拟时间下动画帧不推进会停在初始帧导致截图空白)、强制全部卡片 opacity 1、隐藏换肤坞,body 四周 padding 统一 40px,供主体内容截图
|
|
15
|
+
- 页脚 10px muted 文字,署名固定 GENERATED BY AI TEAM(禁止真实团队名/项目名)
|
|
16
|
+
|
|
17
|
+
## 数据流(TRC_DATA)
|
|
18
|
+
|
|
19
|
+
- `window.TRC_DATA`:生成时内嵌的初始数据数组(字段 name/date/progress/plan/risk,JSON 序列化注意转义);页面启动时优先读 localStorage `trc:<ID>-reports`,有则覆盖初始数组展示
|
|
20
|
+
- 页面「保存」:表单提交 → 追加/合并进本地数组(同 name+date 合并)→ 写 localStorage
|
|
21
|
+
- 「导出 JSON」:Blob 下载 reports.json(含本地最新数据);「导入 JSON」:file input 读 json 合并进本地数组
|
|
22
|
+
- 渲染:按 date 分组倒序、组内按 name 排序;每条显示进展/计划/风险三行(风险空则不显该行),风险行强调色标
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN" data-theme="tech">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<meta name="sf-template" content="team-report-collector@1">
|
|
7
|
+
<meta name="trc-id" content="REF-TRC-0000">
|
|
8
|
+
<title>示例团队日报收集台</title>
|
|
9
|
+
<style>
|
|
10
|
+
/* ═══ 五主题令牌:与 daily-report 同一套 12 核心契约(--bg/--bg2/--panel/--panel-solid/--card-shadow/--text/--muted/--accent/--accent2/--border/--glow/--glow-soft)+ 收集台扩展(--panel2/--input-bg);html[data-theme] 运行时切换,THEME 生成时定默认 ═══ */
|
|
11
|
+
:root, [data-theme="tech"]{
|
|
12
|
+
--bg:#0a1929; --bg2:#071525; --panel:rgba(11,30,55,.9); --panel-solid:#0b1e37;
|
|
13
|
+
--panel2:#0d2236; --input-bg:rgba(2,12,27,.85);
|
|
14
|
+
--card-shadow:0 1px 0 rgba(255,255,255,.05) inset, 0 12px 32px rgba(1,6,16,.5), 0 0 24px rgba(14,165,233,.15);
|
|
15
|
+
--text:#bae6fd; --muted:#5b7fa5; --accent:#0ea5e9; --accent2:#14b8a6;
|
|
16
|
+
--border:rgba(14,165,233,.18); --glow:rgba(14,165,233,.35); --glow-soft:rgba(14,165,233,.15);
|
|
17
|
+
--title-grad:linear-gradient(90deg,#7dd3fc,#0ea5e9 45%,#818cf8);
|
|
18
|
+
--tag-bg:rgba(14,165,233,.12);
|
|
19
|
+
--scan:rgba(0,240,255,.2); --scan-dim:rgba(0,240,255,.05);
|
|
20
|
+
--green:#14b8a6; --orange:#f97316; --rose:#f43f5e;
|
|
21
|
+
}
|
|
22
|
+
[data-theme="biz"]{
|
|
23
|
+
--bg:#e8ecf5; --bg2:#dde3ef; --panel:rgba(255,255,255,.97); --panel-solid:#ffffff;
|
|
24
|
+
--panel2:#f1f5f9; --input-bg:#f8fafc;
|
|
25
|
+
--card-shadow:0 1px 2px rgba(15,23,42,.05), 0 10px 28px rgba(15,23,42,.12);
|
|
26
|
+
--text:#1e293b; --muted:#64748b; --accent:#2563eb; --accent2:#0891b2;
|
|
27
|
+
--border:rgba(37,99,235,.14); --glow:rgba(37,99,235,.18); --glow-soft:rgba(37,99,235,.12);
|
|
28
|
+
--title-grad:linear-gradient(90deg,#1e40af,#2563eb 55%,#0891b2);
|
|
29
|
+
--tag-bg:rgba(37,99,235,.08);
|
|
30
|
+
--scan:rgba(37,99,235,.14); --scan-dim:rgba(37,99,235,.04);
|
|
31
|
+
--green:#0d9488; --orange:#ea580c; --rose:#e11d48;
|
|
32
|
+
}
|
|
33
|
+
[data-theme="mono"]{ /* IDEA 黑亮:JetBrains New UI Dark 官方(编辑区 #1e1f22 + 面板 #2b2d30 + 描边 #3c3f41) */
|
|
34
|
+
--bg:#1e1f22; --bg2:#2b2d30; --panel:rgba(43,45,48,.95); --panel-solid:#2b2d30;
|
|
35
|
+
--panel2:#34373a; --input-bg:#26282b;
|
|
36
|
+
--card-shadow:0 1px 0 rgba(255,255,255,.06) inset, 0 12px 32px rgba(0,0,0,.5), 0 0 24px rgba(53,116,240,.16);
|
|
37
|
+
--text:#dfe1e5; --muted:#9aa0a6; --accent:#3574f0; --accent2:#5e9aff;
|
|
38
|
+
--border:rgba(53,116,240,.26); --glow:rgba(53,116,240,.3); --glow-soft:rgba(53,116,240,.13);
|
|
39
|
+
--title-grad:linear-gradient(90deg,#dfe1e5,#5e9aff 50%,#3574f0);
|
|
40
|
+
--tag-bg:rgba(53,116,240,.13);
|
|
41
|
+
--scan:rgba(223,225,229,.18); --scan-dim:rgba(223,225,229,.07);
|
|
42
|
+
--green:#4da36b; --orange:#d09645; --rose:#d85f73;
|
|
43
|
+
}
|
|
44
|
+
[data-theme="light"]{ /* IDEA 白亮:IntelliJ Light 官方(白编辑区 + 浅灰面板 #f2f2f2 + IDEA 蓝 #2675bf) */
|
|
45
|
+
--bg:#ffffff; --bg2:#f2f2f2; --panel:rgba(255,255,255,.98); --panel-solid:#ffffff;
|
|
46
|
+
--panel2:#f2f2f2; --input-bg:#ffffff;
|
|
47
|
+
--card-shadow:0 1px 2px rgba(30,31,34,.06), 0 10px 28px rgba(30,31,34,.12);
|
|
48
|
+
--text:#1e1f22; --muted:#6e7781; --accent:#2675bf; --accent2:#4a9be0;
|
|
49
|
+
--border:rgba(38,117,191,.18); --glow:rgba(38,117,191,.2); --glow-soft:rgba(38,117,191,.1);
|
|
50
|
+
--title-grad:linear-gradient(90deg,#1e5f9f,#2675bf 55%,#4a9be0);
|
|
51
|
+
--tag-bg:rgba(38,117,191,.08);
|
|
52
|
+
--scan:rgba(38,117,191,.12); --scan-dim:rgba(38,117,191,.04);
|
|
53
|
+
--green:#2f8a5b; --orange:#d97706; --rose:#d6336c;
|
|
54
|
+
}
|
|
55
|
+
[data-theme="warm"]{
|
|
56
|
+
--bg:#f7ebd9; --bg2:#efe0c8; --panel:rgba(255,250,243,.97); --panel-solid:#fffaf3;
|
|
57
|
+
--panel2:#f5ead7; --input-bg:#fffbf4;
|
|
58
|
+
--card-shadow:0 1px 2px rgba(120,72,24,.07), 0 10px 28px rgba(120,72,24,.13);
|
|
59
|
+
--text:#43301f; --muted:#8a7565; --accent:#d97706; --accent2:#ea580c;
|
|
60
|
+
--border:rgba(217,119,6,.18); --glow:rgba(217,119,6,.22); --glow-soft:rgba(217,119,6,.14);
|
|
61
|
+
--title-grad:linear-gradient(90deg,#b45309,#d97706 50%,#ea580c);
|
|
62
|
+
--tag-bg:rgba(217,119,6,.08);
|
|
63
|
+
--scan:rgba(217,119,6,.16); --scan-dim:rgba(217,119,6,.04);
|
|
64
|
+
--green:#3f8f4f; --orange:#c2410c; --rose:#be123c;
|
|
65
|
+
}
|
|
66
|
+
/* 浅色主题下星点氛围自然退隐 */
|
|
67
|
+
[data-theme="biz"] .stars, [data-theme="light"] .stars, [data-theme="warm"] .stars{ opacity:.28; }
|
|
68
|
+
/* mono 黑亮下氛围换装:星点改中性灰白,噪点层同退(不泛蓝) */
|
|
69
|
+
[data-theme="mono"] .stars{ background-image:
|
|
70
|
+
radial-gradient(1px 1px at 12% 18%, rgba(223,225,229,.32), transparent),
|
|
71
|
+
radial-gradient(1px 1px at 28% 64%, rgba(223,225,229,.28), transparent),
|
|
72
|
+
radial-gradient(1.5px 1.5px at 41% 32%, rgba(223,225,229,.26), transparent),
|
|
73
|
+
radial-gradient(1px 1px at 56% 78%, rgba(223,225,229,.24), transparent),
|
|
74
|
+
radial-gradient(1px 1px at 67% 12%, rgba(223,225,229,.26), transparent),
|
|
75
|
+
radial-gradient(1.5px 1.5px at 79% 52%, rgba(223,225,229,.28), transparent),
|
|
76
|
+
radial-gradient(1px 1px at 88% 86%, rgba(223,225,229,.3), transparent),
|
|
77
|
+
radial-gradient(1px 1px at 93% 24%, rgba(223,225,229,.3), transparent); }
|
|
78
|
+
[data-theme="mono"] body::before{ display:none; }
|
|
79
|
+
|
|
80
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
81
|
+
html,body{background:var(--bg)}
|
|
82
|
+
body{
|
|
83
|
+
color:var(--text); font-family:ui-monospace,'SF Mono',SFMono-Regular,Menlo,Consolas,system-ui,sans-serif;
|
|
84
|
+
min-height:100vh; padding:40px 20px; position:relative; overflow-x:hidden;
|
|
85
|
+
}
|
|
86
|
+
body::before{
|
|
87
|
+
content:''; position:fixed; inset:0; z-index:0; pointer-events:none; opacity:.04;
|
|
88
|
+
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
|
89
|
+
}
|
|
90
|
+
.grid-pattern{
|
|
91
|
+
position:fixed; inset:0; z-index:0; pointer-events:none;
|
|
92
|
+
background-image:linear-gradient(var(--scan-dim) 1px, transparent 1px),linear-gradient(90deg, var(--scan-dim) 1px, transparent 1px);
|
|
93
|
+
background-size:60px 60px;
|
|
94
|
+
}
|
|
95
|
+
.stars{
|
|
96
|
+
position:fixed; inset:0; z-index:0; pointer-events:none;
|
|
97
|
+
background-image:
|
|
98
|
+
radial-gradient(1px 1px at 12% 18%, rgba(255,255,255,.38), transparent),
|
|
99
|
+
radial-gradient(1px 1px at 28% 64%, rgba(0,240,255,.48), transparent),
|
|
100
|
+
radial-gradient(1.5px 1.5px at 41% 32%, rgba(255,255,255,.3), transparent),
|
|
101
|
+
radial-gradient(1px 1px at 56% 78%, rgba(168,85,247,.4), transparent),
|
|
102
|
+
radial-gradient(1px 1px at 67% 12%, rgba(0,255,136,.4), transparent),
|
|
103
|
+
radial-gradient(1.5px 1.5px at 79% 52%, rgba(0,240,255,.45), transparent),
|
|
104
|
+
radial-gradient(1px 1px at 88% 86%, rgba(255,255,255,.34), transparent),
|
|
105
|
+
radial-gradient(1px 1px at 93% 24%, rgba(0,240,255,.5), transparent);
|
|
106
|
+
}
|
|
107
|
+
.scanlines{
|
|
108
|
+
position:fixed; inset:0; z-index:999; pointer-events:none;
|
|
109
|
+
background:repeating-linear-gradient(0deg, transparent 0 2px, var(--scan-dim) 2px 4px);
|
|
110
|
+
}
|
|
111
|
+
.scanband{
|
|
112
|
+
position:fixed; left:0; right:0; height:150px; z-index:998; pointer-events:none;
|
|
113
|
+
background:linear-gradient(180deg, transparent, var(--scan-dim) 50%, transparent);
|
|
114
|
+
animation:scanMove 11s linear infinite;
|
|
115
|
+
}
|
|
116
|
+
@keyframes scanMove{ from{top:-22%;} to{top:112%;} }
|
|
117
|
+
.wrap{width:clamp(640px,60%,1200px);margin:0 auto;position:relative;z-index:1}
|
|
118
|
+
.card{
|
|
119
|
+
position:relative; background:var(--panel-solid);
|
|
120
|
+
background-image:repeating-linear-gradient(180deg, rgba(255,255,255,.012) 0 1px, transparent 1px 8px);
|
|
121
|
+
border-top:1px solid var(--border); border-bottom:1px solid var(--border);
|
|
122
|
+
border-radius:6px; padding:24px; margin-bottom:18px; overflow:hidden;
|
|
123
|
+
box-shadow:var(--card-shadow);
|
|
124
|
+
animation:riseIn .5s ease backwards;
|
|
125
|
+
}
|
|
126
|
+
@keyframes riseIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
|
|
127
|
+
.header-card{animation-delay:0s}
|
|
128
|
+
.form-card{animation-delay:.13s}
|
|
129
|
+
.list-card{animation-delay:.26s}
|
|
130
|
+
.card-glow{
|
|
131
|
+
position:absolute; inset:0; pointer-events:none; transform-origin:top center;
|
|
132
|
+
background:radial-gradient(ellipse at 50% 10%, var(--glow), transparent 70%);
|
|
133
|
+
opacity:.5; animation:cardGlow 3s ease-in-out infinite;
|
|
134
|
+
}
|
|
135
|
+
@keyframes cardGlow{ 0%,100%{opacity:.5; transform:scale(1);} 50%{opacity:1; transform:scale(1.6);} }
|
|
136
|
+
.scanline-el{ position:absolute; pointer-events:none; z-index:3; }
|
|
137
|
+
.scan-x{ left:0; right:0; height:1px; background:linear-gradient(90deg, transparent, var(--accent), transparent); }
|
|
138
|
+
.scan-y{ top:0; bottom:0; width:1px; background:linear-gradient(180deg, transparent, var(--accent), transparent); }
|
|
139
|
+
.scan-top{ top:0; animation:scanX 3s linear infinite; }
|
|
140
|
+
.scan-right{ right:0; animation:scanY 3s linear infinite; }
|
|
141
|
+
.scan-bottom{ bottom:0; animation:scanXrev 3s linear infinite; }
|
|
142
|
+
.scan-left{ left:0; animation:scanYrev 3s linear infinite; }
|
|
143
|
+
@keyframes scanX{ from{transform:translateX(-100%);} to{transform:translateX(100%);} }
|
|
144
|
+
@keyframes scanXrev{ from{transform:translateX(100%);} to{transform:translateX(-100%);} }
|
|
145
|
+
@keyframes scanY{ from{transform:translateY(-100%);} to{transform:translateY(100%);} }
|
|
146
|
+
@keyframes scanYrev{ from{transform:translateY(100%);} to{transform:translateY(-100%);} }
|
|
147
|
+
.header-card{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:14px}
|
|
148
|
+
.header-card h1{
|
|
149
|
+
position:relative; z-index:2; font-size:22px; font-weight:900; letter-spacing:.5px;
|
|
150
|
+
background:var(--title-grad);
|
|
151
|
+
-webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent;
|
|
152
|
+
text-shadow:0 0 16px var(--glow), 0 0 40px var(--glow-soft);
|
|
153
|
+
}
|
|
154
|
+
.badges{position:relative;z-index:2;display:flex;gap:8px;flex-wrap:wrap}
|
|
155
|
+
.badge{font-size:11.5px;color:var(--muted);background:var(--tag-bg);border:1px solid var(--border);border-radius:20px;padding:4px 12px}
|
|
156
|
+
.stats{position:relative;z-index:2;display:flex;gap:18px;flex-wrap:wrap;margin-top:10px;width:100%}
|
|
157
|
+
.stat{font-size:12px;color:var(--muted)}
|
|
158
|
+
.stat b{color:var(--accent);font-size:18px;margin-right:4px}
|
|
159
|
+
.field{display:flex;flex-direction:column;gap:6px;margin-bottom:14px}
|
|
160
|
+
.field label{font-size:12px;color:var(--muted)}
|
|
161
|
+
.field input,.field textarea{background:var(--input-bg);border:1px solid var(--border);border-radius:6px;color:var(--text);padding:9px 12px;font-size:14px;font-family:inherit;outline:none;transition:border-color .2s ease}
|
|
162
|
+
.field input:focus,.field textarea:focus{border-color:var(--accent)}
|
|
163
|
+
.field textarea{min-height:56px;resize:vertical}
|
|
164
|
+
.row2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
|
165
|
+
.btn{background:linear-gradient(90deg,var(--accent),var(--accent2));color:#fff;border:none;border-radius:6px;padding:10px 22px;font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;transition:transform .15s ease,box-shadow .2s ease;box-shadow:0 0 18px var(--glow)}
|
|
166
|
+
.btn:hover{transform:translateY(-1px)}
|
|
167
|
+
.btn:active{transform:translateY(1px)}
|
|
168
|
+
.btn.ghost{background:transparent;color:var(--accent);border:1px solid var(--border);box-shadow:none}
|
|
169
|
+
.toolbar{display:flex;gap:10px;margin-bottom:16px;flex-wrap:wrap}
|
|
170
|
+
.day-group{margin-bottom:18px}
|
|
171
|
+
.day-title{font-size:13px;color:var(--accent);margin-bottom:10px;display:flex;align-items:center;gap:8px}
|
|
172
|
+
.day-title::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--accent)}
|
|
173
|
+
.item{background:var(--panel2);border:1px solid var(--border);border-radius:8px;padding:14px 16px;margin-bottom:10px;transition:background .2s ease}
|
|
174
|
+
.item:hover{background:var(--tag-bg)}
|
|
175
|
+
.item .who{font-size:14px;font-weight:600;color:var(--text);margin-bottom:8px}
|
|
176
|
+
.item .line{font-size:13px;line-height:1.7;color:var(--text);margin-bottom:3px}
|
|
177
|
+
.item .line span{color:var(--muted);font-size:12px;margin-right:6px}
|
|
178
|
+
.item .line.risk{color:var(--rose)}
|
|
179
|
+
.empty{color:var(--muted);font-size:13px;text-align:center;padding:28px 0}
|
|
180
|
+
footer{text-align:center;color:var(--muted);font-size:10px;margin-top:26px}
|
|
181
|
+
.theme-dock{position:fixed;right:18px;bottom:18px;z-index:1001;display:flex;gap:8px;background:var(--panel-solid);border:1px solid var(--border);border-radius:999px;padding:8px 10px;box-shadow:0 4px 18px rgba(0,0,0,.3)}
|
|
182
|
+
.th-dot{width:22px;height:22px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0;transition:transform .15s ease,border-color .15s ease}
|
|
183
|
+
.th-dot:hover{transform:scale(1.18)}
|
|
184
|
+
.th-dot.on{border-color:var(--text)}
|
|
185
|
+
.th-dot[data-theme="tech"]{background:#0ea5e9}
|
|
186
|
+
.th-dot[data-theme="biz"]{background:#2563eb}
|
|
187
|
+
.th-dot[data-theme="mono"]{background:#1e1f22}
|
|
188
|
+
.th-dot[data-theme="light"]{background:#ffffff}
|
|
189
|
+
.th-dot[data-theme="warm"]{background:#d97706}
|
|
190
|
+
html[data-shot] .card{animation:none!important}
|
|
191
|
+
@media (max-width:680px){body{padding:24px 12px}.wrap{width:100%}.row2{grid-template-columns:1fr}.header-card h1{font-size:18px}}
|
|
192
|
+
@media print{.theme-dock,.btn{display:none}}
|
|
193
|
+
</style>
|
|
194
|
+
</head>
|
|
195
|
+
<body>
|
|
196
|
+
<div class="grid-pattern"></div>
|
|
197
|
+
<div class="stars"></div>
|
|
198
|
+
<div class="scanband"></div>
|
|
199
|
+
<div class="scanlines"></div>
|
|
200
|
+
<div class="wrap">
|
|
201
|
+
<div class="card header-card">
|
|
202
|
+
<div class="card-glow"></div>
|
|
203
|
+
<span class="scanline-el scan-x scan-top"></span>
|
|
204
|
+
<span class="scanline-el scan-y scan-right"></span>
|
|
205
|
+
<span class="scanline-el scan-x scan-bottom"></span>
|
|
206
|
+
<span class="scanline-el scan-y scan-left"></span>
|
|
207
|
+
<h1>示例团队日报收集台</h1>
|
|
208
|
+
<div class="badges">
|
|
209
|
+
<span class="badge">📅 <span id="d-badge">2026-11-12</span></span>
|
|
210
|
+
<span class="badge" id="t-badge">tech</span>
|
|
211
|
+
</div>
|
|
212
|
+
<div class="stats">
|
|
213
|
+
<span class="stat"><b id="s-members">2</b>成员</span>
|
|
214
|
+
<span class="stat"><b id="s-reports">2</b>日报</span>
|
|
215
|
+
<span class="stat"><b id="s-risks">1</b>风险</span>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
<div class="card form-card">
|
|
219
|
+
<div class="row2">
|
|
220
|
+
<div class="field"><label>成员姓名</label><input id="f-name" placeholder="张工"></div>
|
|
221
|
+
<div class="field"><label>日期</label><input id="f-date" type="date"></div>
|
|
222
|
+
</div>
|
|
223
|
+
<div class="field"><label>今日进展</label><textarea id="f-progress" placeholder="完成了什么"></textarea></div>
|
|
224
|
+
<div class="field"><label>明日计划</label><textarea id="f-plan" placeholder="准备做什么"></textarea></div>
|
|
225
|
+
<div class="field"><label>风险阻塞</label><textarea id="f-risk" placeholder="无则留空"></textarea></div>
|
|
226
|
+
<div style="display:flex;gap:10px">
|
|
227
|
+
<button class="btn" id="save-btn">保存日报</button>
|
|
228
|
+
<button class="btn ghost" id="clear-btn">清空表单</button>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
<div class="card list-card">
|
|
232
|
+
<div class="toolbar">
|
|
233
|
+
<button class="btn ghost" id="export-btn">导出 JSON</button>
|
|
234
|
+
<button class="btn ghost" id="import-btn">导入 JSON</button>
|
|
235
|
+
<input type="file" id="import-file" accept=".json" style="display:none">
|
|
236
|
+
</div>
|
|
237
|
+
<div id="list"></div>
|
|
238
|
+
</div>
|
|
239
|
+
<footer>GENERATED BY AI TEAM · 2026-11</footer>
|
|
240
|
+
</div>
|
|
241
|
+
<div class="theme-dock" id="themeDock">
|
|
242
|
+
<button class="th-dot" type="button" data-theme="tech" title="深蓝科技"></button>
|
|
243
|
+
<button class="th-dot" type="button" data-theme="biz" title="浅色商务"></button>
|
|
244
|
+
<button class="th-dot" type="button" data-theme="mono" title="IDEA 黑亮"></button>
|
|
245
|
+
<button class="th-dot" type="button" data-theme="light" title="IDEA 白亮"></button>
|
|
246
|
+
<button class="th-dot" type="button" data-theme="warm" title="温暖渐变"></button>
|
|
247
|
+
</div>
|
|
248
|
+
<script>
|
|
249
|
+
window.TRC_DATA = [
|
|
250
|
+
{"name":"张工","date":"2026-11-12","progress":"完成登录模块接口联调","plan":"补单元测试并提测","risk":"测试环境不稳定"},
|
|
251
|
+
{"name":"李工","date":"2026-11-12","progress":"日报模块前端页面初稿","plan":"接入接口与交互细节","risk":""}
|
|
252
|
+
];
|
|
253
|
+
(function(){
|
|
254
|
+
var KEY = 'sf-heal:' + location.pathname;
|
|
255
|
+
var m = document.querySelector('meta[name="trc-id"]');
|
|
256
|
+
var ok = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(m ? m.content : '');
|
|
257
|
+
var ID;
|
|
258
|
+
if (ok) { ID = m.content; }
|
|
259
|
+
else {
|
|
260
|
+
var v = localStorage.getItem(KEY);
|
|
261
|
+
if (!v) { v = crypto.randomUUID(); localStorage.setItem(KEY, v); }
|
|
262
|
+
ID = v;
|
|
263
|
+
m.setAttribute('content', v);
|
|
264
|
+
console.warn('[trc] 非法 id meta 已自愈为 ' + v);
|
|
265
|
+
}
|
|
266
|
+
var REPORTS_KEY = 'trc:' + ID + '-reports';
|
|
267
|
+
var THEME_KEY = 'trc:' + ID + '-theme';
|
|
268
|
+
var seed = window.TRC_DATA || [];
|
|
269
|
+
var saved = localStorage.getItem(REPORTS_KEY);
|
|
270
|
+
var reports = saved ? JSON.parse(saved) : seed;
|
|
271
|
+
|
|
272
|
+
function esc(s){ return String(s == null ? '' : s).replace(/[&<>"]/g, function(c){ return {'&':'&','<':'<','>':'>','"':'"'}[c]; }); }
|
|
273
|
+
function today(){ var d = new Date(); var p = function(n){ return n < 10 ? '0' + n : n; }; return d.getFullYear() + '-' + p(d.getMonth()+1) + '-' + p(d.getDate()); }
|
|
274
|
+
function persist(){ localStorage.setItem(REPORTS_KEY, JSON.stringify(reports)); }
|
|
275
|
+
function render(){
|
|
276
|
+
var groups = {};
|
|
277
|
+
reports.forEach(function(r){
|
|
278
|
+
(groups[r.date] = groups[r.date] || []).push(r);
|
|
279
|
+
});
|
|
280
|
+
var dates = Object.keys(groups).sort().reverse();
|
|
281
|
+
var html = '';
|
|
282
|
+
if (!dates.length) { html = '<div class="empty">暂无日报,填写表单开始收集</div>'; }
|
|
283
|
+
dates.forEach(function(d){
|
|
284
|
+
html += '<div class="day-group"><div class="day-title">' + esc(d) + ' · ' + groups[d].length + ' 人已报</div>';
|
|
285
|
+
groups[d].forEach(function(r){
|
|
286
|
+
html += '<div class="item"><div class="who">' + esc(r.name) + '</div>';
|
|
287
|
+
if (r.progress) html += '<div class="line"><span>进展</span>' + esc(r.progress) + '</div>';
|
|
288
|
+
if (r.plan) html += '<div class="line"><span>计划</span>' + esc(r.plan) + '</div>';
|
|
289
|
+
if (r.risk) html += '<div class="line risk"><span>风险</span>' + esc(r.risk) + '</div>';
|
|
290
|
+
html += '</div>';
|
|
291
|
+
});
|
|
292
|
+
html += '</div>';
|
|
293
|
+
});
|
|
294
|
+
document.getElementById('list').innerHTML = html;
|
|
295
|
+
var names = {}; var risks = 0;
|
|
296
|
+
reports.forEach(function(r){ names[r.name] = 1; if (r.risk) risks++; });
|
|
297
|
+
document.getElementById('s-members').textContent = Object.keys(names).length;
|
|
298
|
+
document.getElementById('s-reports').textContent = reports.length;
|
|
299
|
+
document.getElementById('s-risks').textContent = risks;
|
|
300
|
+
}
|
|
301
|
+
document.getElementById('save-btn').addEventListener('click', function(){
|
|
302
|
+
var name = document.getElementById('f-name').value.trim();
|
|
303
|
+
var date = document.getElementById('f-date').value || today();
|
|
304
|
+
var progress = document.getElementById('f-progress').value.trim();
|
|
305
|
+
var plan = document.getElementById('f-plan').value.trim();
|
|
306
|
+
var risk = document.getElementById('f-risk').value.trim();
|
|
307
|
+
if (!name) { alert('请填写成员姓名'); return; }
|
|
308
|
+
if (!progress && !plan && !risk) { alert('进展/计划/风险至少填一项'); return; }
|
|
309
|
+
var ex = reports.filter(function(r){ return r.name === name && r.date === date; })[0];
|
|
310
|
+
if (ex) {
|
|
311
|
+
if (progress) ex.progress = ex.progress ? ex.progress + ';' + progress : progress;
|
|
312
|
+
if (plan) ex.plan = ex.plan ? ex.plan + ';' + plan : plan;
|
|
313
|
+
if (risk) ex.risk = ex.risk ? ex.risk + ';' + risk : risk;
|
|
314
|
+
} else {
|
|
315
|
+
reports.push({name:name, date:date, progress:progress, plan:plan, risk:risk});
|
|
316
|
+
}
|
|
317
|
+
persist(); render();
|
|
318
|
+
['f-name','f-progress','f-plan','f-risk'].forEach(function(id){ document.getElementById(id).value = ''; });
|
|
319
|
+
document.getElementById('f-date').value = today();
|
|
320
|
+
});
|
|
321
|
+
document.getElementById('clear-btn').addEventListener('click', function(){
|
|
322
|
+
['f-name','f-progress','f-plan','f-risk'].forEach(function(id){ document.getElementById(id).value = ''; });
|
|
323
|
+
});
|
|
324
|
+
document.getElementById('export-btn').addEventListener('click', function(){
|
|
325
|
+
var blob = new Blob([JSON.stringify(reports, null, 2)], {type:'application/json'});
|
|
326
|
+
var a = document.createElement('a');
|
|
327
|
+
a.href = URL.createObjectURL(blob);
|
|
328
|
+
a.download = 'reports.json';
|
|
329
|
+
a.click();
|
|
330
|
+
URL.revokeObjectURL(a.href);
|
|
331
|
+
});
|
|
332
|
+
document.getElementById('import-btn').addEventListener('click', function(){
|
|
333
|
+
document.getElementById('import-file').click();
|
|
334
|
+
});
|
|
335
|
+
document.getElementById('import-file').addEventListener('change', function(ev){
|
|
336
|
+
var f = ev.target.files[0];
|
|
337
|
+
if (!f) return;
|
|
338
|
+
var rd = new FileReader();
|
|
339
|
+
rd.onload = function(){
|
|
340
|
+
try {
|
|
341
|
+
var arr = JSON.parse(rd.result);
|
|
342
|
+
if (!Array.isArray(arr)) throw new Error('not array');
|
|
343
|
+
arr.forEach(function(r){ reports.push(r); });
|
|
344
|
+
persist(); render();
|
|
345
|
+
} catch(e) { alert('导入失败:不是合法的 reports.json 数组'); }
|
|
346
|
+
};
|
|
347
|
+
rd.readAsText(f);
|
|
348
|
+
});
|
|
349
|
+
/* 主题换肤:五套配色随点随换;记忆上次选择(localStorage,失败静默);?shot 截图模式隐藏坞 */
|
|
350
|
+
var THEMES = ['tech','biz','mono','light','warm'];
|
|
351
|
+
var dock = document.getElementById('themeDock');
|
|
352
|
+
var tBadge = document.getElementById('t-badge');
|
|
353
|
+
function applyTheme(t){
|
|
354
|
+
document.documentElement.setAttribute('data-theme', t);
|
|
355
|
+
try { localStorage.setItem(THEME_KEY, t); } catch(e) {}
|
|
356
|
+
tBadge.textContent = t;
|
|
357
|
+
dock.querySelectorAll('.th-dot').forEach(function(d){ d.classList.toggle('on', d.getAttribute('data-theme') === t); });
|
|
358
|
+
}
|
|
359
|
+
var savedTheme = null;
|
|
360
|
+
try { savedTheme = localStorage.getItem(THEME_KEY); } catch(e) {}
|
|
361
|
+
var initial = (savedTheme && THEMES.indexOf(savedTheme) !== -1) ? savedTheme : 'tech';
|
|
362
|
+
applyTheme(initial);
|
|
363
|
+
dock.querySelectorAll('.th-dot').forEach(function(d){
|
|
364
|
+
d.addEventListener('click', function(){ applyTheme(d.getAttribute('data-theme')); });
|
|
365
|
+
});
|
|
366
|
+
document.getElementById('d-badge').textContent = '2026-11-12';
|
|
367
|
+
if (location.search.indexOf('shot') !== -1) {
|
|
368
|
+
document.documentElement.setAttribute('data-shot', '1');
|
|
369
|
+
document.querySelectorAll('.card').forEach(function(c){ c.style.opacity = '1'; c.style.transform = 'none'; });
|
|
370
|
+
dock.style.display = 'none';
|
|
371
|
+
document.body.style.padding = '40px';
|
|
372
|
+
}
|
|
373
|
+
render();
|
|
374
|
+
if ('IntersectionObserver' in window) {
|
|
375
|
+
var io = new IntersectionObserver(function(es){
|
|
376
|
+
es.forEach(function(e){ if (e.isIntersecting) { e.target.style.opacity = '1'; e.target.style.transform = 'none'; io.unobserve(e.target); } });
|
|
377
|
+
}, {threshold:.1});
|
|
378
|
+
document.querySelectorAll('.card').forEach(function(c){ io.observe(c); });
|
|
379
|
+
setTimeout(function(){ document.querySelectorAll('.card').forEach(function(c){ c.style.opacity = '1'; c.style.transform = 'none'; }); }, 2000);
|
|
380
|
+
}
|
|
381
|
+
})();
|
|
382
|
+
</script>
|
|
383
|
+
</body>
|
|
384
|
+
</html>
|