From 647d92f532f10df0cf5ef76e0223d28c6e174292 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 7 May 2026 16:05:44 +0800 Subject: [PATCH] =?UTF-8?q?proposal+ppt:=20=E8=B7=AF=E5=BE=84=E7=94=A8=20,=20=E8=A1=A5=20spec=5Flock=20=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E4=B8=8E=20--spec=20=E8=A6=86=E7=9B=96=E5=BA=A6=E6=A3=80?= =?UTF-8?q?=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按代码评审建议改的 5 项: 1. 所有脚本/资源路径改成相对 (load_skill 头里的绝对路径), 不再假设 cwd 是 zcbot 仓库根。proposal+ppt 的 SKILL.md / icons.md / INDEX.md 都改了。 2. quality_check.py REQUIRED_SECTIONS 给 key_rd 补上 11_team / 12_budget / 13_appendix —— 之前模板有但检查没到, 缺团队/预算/附件 也会显示结构完整。 3. 新增 templates/spec_lock.md, 把"八条对齐"固化成可复制字段 (含考核指标矩阵表 + TODO 列表 + 引文清单), 阶段二/三都从这里读。 4. quality_check.py 加 --spec 选项, 解析 spec 中的 考核指标矩阵, 关键词模糊匹配 sections, 提示哪些指南指标在正文 未充分覆盖。SKILL.md 阶段三命令同步。 5. SKILL.md 新增"阶段零: 摄取素材", 用 run_python + pypdf/python-docx/ openpyxl 把 PDF/DOCX/XLSX 转成 source/*.md, 不再要新脚本。同时 把 spec_lock 字段引用改写到模板。 顺带: - proposal SKILL.md 明确 7 类基金里只有 3 类 (key_rd/major_project/ nsfc_joint_fund) 有完整章节模板, 其它 4 类复用骨架, 差异查 fund_types.md - ppt SKILL.md 阶段三命令路径错误 (python scripts/quality_check.py) 顺带修了 --- skills/ppt/SKILL.md | 6 +- skills/ppt/assets/icons/INDEX.md | 8 +- skills/ppt/references/icons.md | 16 ++-- skills/proposal/SKILL.md | 77 ++++++++++++------- skills/proposal/scripts/quality_check.py | 80 ++++++++++++++++++-- skills/proposal/templates/spec_lock.md | 94 ++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 46 deletions(-) create mode 100644 skills/proposal/templates/spec_lock.md diff --git a/skills/ppt/SKILL.md b/skills/ppt/SKILL.md index a00b495..41191e8 100644 --- a/skills/ppt/SKILL.md +++ b/skills/ppt/SKILL.md @@ -57,8 +57,8 @@ description: 生成 PowerPoint 演示文稿 (.pptx)。当用户要求做汇报 P 每页前 **必须 read 一次 `spec_lock.md`**,只用里面定的颜色/字体/图标 —— **不允许凭记忆或临时发挥**。这条规则是为了对抗长 deck 中的上下文漂移。 每页流程: -1. 读 `spec_lock.md` (即使刚读过) -2. **图标先于版式**: 这一页要用什么概念图标? 先 `glob skills/ppt/assets/icons/` 看本地有没有,没有就 `python skills/ppt/scripts/fetch_icon.py --set tabler --color C00000 --size 128 -o skills/ppt/assets/icons/...` 拉一个;`add_picture` 嵌入。**几何形状(圆点/徽章/装饰线)不算图标,走 layouts.md helper 即可** +1. 读 `/spec_lock.md` (即使刚读过) +2. **图标先于版式**: 这一页要用什么概念图标? 先 `glob /assets/icons/` 看本地有没有 (`` 是 `load_skill` 头里的绝对路径),没有就 `python /scripts/fetch_icon.py --set tabler --color C00000 --size 128 -o /assets/icons/...` 拉一个;`add_picture` 嵌入。**几何形状(圆点/徽章/装饰线)不算图标,走 layouts.md helper 即可** 3. 写一个 `run_python` block,用 python-pptx 添加这一页 (载入已有 .pptx → append slide → save) 4. 报这一页:版式、标题、要点条数、用了哪些图标 5. 用户确认 / 微调后再下一页 @@ -70,7 +70,7 @@ description: 生成 PowerPoint 演示文稿 (.pptx)。当用户要求做汇报 P ### 阶段三: 验收 ```bash -python scripts/quality_check.py --spec spec_lock.md +python /scripts/quality_check.py / --spec /spec_lock.md ``` 不通过的项,回头 edit 对应页。 diff --git a/skills/ppt/assets/icons/INDEX.md b/skills/ppt/assets/icons/INDEX.md index 9c91261..4c67d54 100644 --- a/skills/ppt/assets/icons/INDEX.md +++ b/skills/ppt/assets/icons/INDEX.md @@ -16,23 +16,23 @@ 按下面 3 行命令拉取首批最常用 18 个,够覆盖 80% 商务汇报场景: ```bash -ICONS_DIR=skills/ppt/assets/icons +ICONS_DIR=/assets/icons # 来自 load_skill 头 # 战略 / 目标 / 启动 for n in target rocket flag bulb; do - python skills/ppt/scripts/fetch_icon.py $n --set tabler --color C00000 --size 128 \ + python /scripts/fetch_icon.py $n --set tabler --color C00000 --size 128 \ -o "$ICONS_DIR/tabler_${n}_C00000_128.png" done # 数据 / 趋势 / 报表 for n in chart-bar chart-line trending-up calculator; do - python skills/ppt/scripts/fetch_icon.py $n --set tabler --color C00000 --size 128 \ + python /scripts/fetch_icon.py $n --set tabler --color C00000 --size 128 \ -o "$ICONS_DIR/tabler_${n}_C00000_128.png" done # 团队 / 流程 / 时间 for n in users settings calendar clock check shield-check arrow-right alert-triangle currency-yuan circle-check; do - python skills/ppt/scripts/fetch_icon.py $n --set tabler --color C00000 --size 128 \ + python /scripts/fetch_icon.py $n --set tabler --color C00000 --size 128 \ -o "$ICONS_DIR/tabler_${n}_C00000_128.png" done ``` diff --git a/skills/ppt/references/icons.md b/skills/ppt/references/icons.md index 7c642eb..81557a4 100644 --- a/skills/ppt/references/icons.md +++ b/skills/ppt/references/icons.md @@ -14,7 +14,7 @@ ## §A. Iconify 个性化图标 (本地缓存 + 网络拉取) ### A1. 本地库 -路径: `skills/ppt/assets/icons/`,详见 [INDEX.md](../assets/icons/INDEX.md)。 +路径: `/assets/icons/`,详见 [INDEX.md](../assets/icons/INDEX.md)。 命名规约: `___.png`(如 `tabler_rocket_C00000_128.png`) **用之前先 `glob` 检查本地有没有**,有就直接 `add_picture`,免去网络往返。 @@ -22,12 +22,12 @@ ### A2. fetch_icon.py 拉新图标 ```bash # 主红色 128px PNG (推荐) -python skills/ppt/scripts/fetch_icon.py rocket --set tabler --color C00000 \ - --size 128 -o skills/ppt/assets/icons/tabler_rocket_C00000_128.png +python /scripts/fetch_icon.py rocket --set tabler --color C00000 \ + --size 128 -o /assets/icons/tabler_rocket_C00000_128.png # 强调色金黄 -python skills/ppt/scripts/fetch_icon.py target --set tabler --color FFC107 \ - --size 128 -o skills/ppt/assets/icons/tabler_target_FFC107_128.png +python /scripts/fetch_icon.py target --set tabler --color FFC107 \ + --size 128 -o /assets/icons/tabler_target_FFC107_128.png ``` `--set` 默认 `tabler`(4500+ 商务图标,MIT)。其它选 `lucide / heroicons / material-symbols / carbon / fluent / mdi`。**整 deck 只用一个 set**。 @@ -37,7 +37,7 @@ PNG 转换需 `pip install cairosvg`(推荐)或 `pip install svglib`。没装也 ### A3. 嵌入幻灯片 ```python slide.shapes.add_picture( - "skills/ppt/assets/icons/tabler_rocket_C00000_128.png", + "/assets/icons/tabler_rocket_C00000_128.png", Inches(1.0), Inches(2.5), width=Inches(0.8), # 装饰图标 0.5-1.5 in;别超 2 in ) @@ -53,7 +53,7 @@ slide.shapes.add_picture( ```python from pptx.util import Inches, Pt stages = ["调研","设计","开发","测试","上线"] -icon_path = "skills/ppt/assets/icons/tabler_chevron-right_C00000_64.png" +icon_path = "/assets/icons/tabler_chevron-right_C00000_64.png" for i, label in enumerate(stages): x = 0.7 + i * 2.4 add_textbox(slide, x, 3.7, 1.8, 0.5, label, 16, bold=True, @@ -79,7 +79,7 @@ Iconify 都没合适的时候用。避 emoji,用单色符号: ```bash # 强调色对号 96px → PNG -python scripts/render_icon.py "✓" --color "#C00000" --size 96 -o slides/check.png +python /scripts/render_icon.py "✓" --color "#C00000" --size 96 -o /slides/check.png ``` ## §C. 硬规则 diff --git a/skills/proposal/SKILL.md b/skills/proposal/SKILL.md index d649e95..67061e9 100644 --- a/skills/proposal/SKILL.md +++ b/skills/proposal/SKILL.md @@ -8,37 +8,62 @@ description: 撰写中国科研项目申报书 / 课题任务书 (国家重点 把课题信息变成可提交的申报书 .docx。**先定基金类型 → 八条对齐 → 逐章起草 → 验收渲染** —— 不要一口气出全文。 ## 资源 -- `references/fund_types.md` —— 6 类基金的章节骨架 + 字数预算 + 必填表格 (always read) -- `references/review_redlines.md` —— 评审雷区与不可考核词清单 -- `references/citation_gbt7714.md` —— GB/T 7714 顺序编码制 + 文献真实性铁律 -- `references/budget_rules.md` —— 间接费用台阶 + B1-B4 表 -- `templates/{key_rd,major_project,nsfc_joint_fund}.md` —— 章节骨架 (复制到 sections/ 填空) -- `scripts/render_docx.py` —— md→docx,自动加目录、解析 `**bold**`/`*italic*`/`` `code` ``、列表分行 -- `scripts/word_count.py` —— 章节字数 vs 预算 -- `scripts/quality_check.py` —— 结构完整性 / 假大空话术 / 占位符未替换扫描 + +下面所有路径都相对 **``** —— `load_skill` 返回头里的 `[skill=proposal, dir=<绝对路径>]`,用这个绝对路径拼脚本/资源,不要假设 cwd。 + +- `/references/fund_types.md` —— 6 类基金的章节骨架 + 字数预算 + 必填表格 (always read) +- `/references/review_redlines.md` —— 评审雷区与不可考核词清单 +- `/references/citation_gbt7714.md` —— GB/T 7714 顺序编码制 + 文献真实性铁律 +- `/references/budget_rules.md` —— 间接费用台阶 + B1-B4 表 +- `/templates/spec_lock.md` —— 阶段一八条对齐的固定字段模板 (复制到 `/spec_lock.md`) +- `/templates/{key_rd,major_project,nsfc_joint_fund}.md` —— **有完整章节模板**的 3 类基金;其它 4 类 (`nsfc_general` / `nsfc_youth` / `provincial` / `enterprise`) 复用 `nsfc_joint_fund` 或 `key_rd` 骨架,差异看 `fund_types.md` § 4-6 +- `/scripts/render_docx.py` —— md→docx,自动加目录、解析 `**bold**`/`*italic*`/`` `code` ``、列表分行 +- `/scripts/word_count.py` —— 章节字数 vs 预算 +- `/scripts/quality_check.py` —— 结构完整性 / 假大空话术 / 占位符未替换 / 指南覆盖度 (--spec 选项) + +## 阶段零: 摄取素材 (有 PDF/DOCX 时才走) + +用户给指南 PDF / 团队介绍 DOCX / 预算 XLSX → 先转成 `/source/.md`,后续阶段一才能读。用 `run_python` 即可,不需要新工具: + +```python +# PDF (指南文件) +from pypdf import PdfReader +text = "\n\n".join(p.extract_text() or "" for p in PdfReader(pdf_path).pages) +Path("/source/guide.md").write_text(text, encoding="utf-8") + +# DOCX (团队/前期成果) +from docx import Document +doc = Document(docx_path) +md = "\n".join(p.text for p in doc.paragraphs if p.text.strip()) +# 表格 +for t in doc.tables: + for row in t.rows: md += "\n| " + " | ".join(c.text.strip() for c in row.cells) + " |" + +# XLSX (预算) +from openpyxl import load_workbook +wb = load_workbook(xlsx_path) +for ws in wb.worksheets: + for row in ws.iter_rows(values_only=True): print(row) +``` + +转完后 spec_lock 阶段直接 `read /source/*.md` 拿事实,不要凭印象写。 ## 阶段一: 八条对齐 -产物 `spec_lock.md` —— 申报书"宪法",阶段二每章前都要重读。 +产物 `/spec_lock.md` —— 申报书"宪法",阶段二每章前都要重读。 -**先读 `references/fund_types.md` 选基金类型**(章节、字数、表格各不相同),按下表给用户预览,⛔ **BLOCKING:用户确认后才进阶段二**。 +1. **复制模板**: `read /templates/spec_lock.md` → `write /spec_lock.md` +2. **先读 `/references/fund_types.md` 选基金类型**(章节、字数、表格各不相同) +3. 按 spec_lock.md 字段填,给用户预览 +4. ⛔ **BLOCKING:用户确认后才进阶段二** -| # | 项 | 默认/示例 | -|---|----|---------| -| 1 | 基金类型 | `key_rd` 重点研发 / `major_project` 重大专项 / `nsfc_joint_fund` 联合基金 / `nsfc_general` 面上 / `nsfc_youth` 青年 / `provincial` 省基金 / `enterprise` 横向 | -| 2 | 指南方向 | **一字不改**抄指南。无指南的(青年)填研究方向 | -| 3 | 关键科学/技术问题 | 1-2 个,与指南对齐;**问题 ≠ 任务** | -| 4 | 创新点 | ≤3 条,每条 ≤500 字。**小而尖** | -| 5 | 研究内容骨架 | 5-8 个研究模块 (重点研发要分课题) | -| 6 | 申报/牵头单位 + 团队 | 含主要参与单位与负责人 (空缺填 ``) | -| 7 | 考核指标 | 量化、可考核、覆盖指南。形式: 软件 N 个 / 平台 N 个 / 专利 N 项 / 标准 N 项 | -| 8 | 经费预算 | 总额 + 中央财政 + 自筹 + 其他渠道 (查 `budget_rules.md`) | +字段清单见 `/templates/spec_lock.md` (基金类型 / 指南方向 / 关键科学技术问题 / 创新点 / 研究内容骨架 / 团队 / 考核指标矩阵 / 经费预算 / TODO 列表)。 ## 阶段二: 逐章起草 每章流程: -1. 读 `spec_lock.md` 与 `references/fund_types.md` 拿本章字数预算与必填要素 -2. 复制 `templates/.md` 对应小节到 `sections/NN_xxx.md`,填空 +1. 读 `/spec_lock.md` 与 `/references/fund_types.md` 拿本章字数预算与必填要素 +2. 复制 `/templates/.md` 对应小节到 `/sections/NN_xxx.md`,填空 3. 报告: 章节名 / 实际字数 / 字数预算 / 与指南对齐情况 4. ⛔ **BLOCKING:停下来等用户明确反馈** ("OK"、"下一章"、"继续") 后才进下一章。"看起来不错"、沉默、追问都不算确认 —— 主动问"这一章可以了吗?要改哪里?" @@ -49,12 +74,12 @@ description: 撰写中国科研项目申报书 / 课题任务书 (国家重点 ## 阶段三: 验收 + 渲染 ```bash -python skills/proposal/scripts/word_count.py /sections/ --fund-type key_rd -python skills/proposal/scripts/quality_check.py /sections/ --fund-type key_rd -python skills/proposal/scripts/render_docx.py /sections/ --fund-type key_rd -o /.docx +python /scripts/word_count.py /sections/ --fund-type key_rd +python /scripts/quality_check.py /sections/ --fund-type key_rd --spec /spec_lock.md +python /scripts/render_docx.py /sections/ --fund-type key_rd -o /.docx ``` -不通过的项,回头 edit 对应章节。 +`--spec` 让质量检查交叉对照 spec_lock,提示哪些指南考核指标在 sections 里没出现。不通过的项,回头 edit 对应章节。 ## 工作目录 diff --git a/skills/proposal/scripts/quality_check.py b/skills/proposal/scripts/quality_check.py index 972b5c0..71345ba 100644 --- a/skills/proposal/scripts/quality_check.py +++ b/skills/proposal/scripts/quality_check.py @@ -22,6 +22,7 @@ REQUIRED_SECTIONS: dict[str, list[str]] = { "00_basic_info", "01_summary", "02_background", "03_objectives", "04_content", "05_decomposition", "06_innovation", "07_benefit", "08_basis", "09_schedule", "10_organization", + "11_team", "12_budget", "13_appendix", ], "major_project": [ "00_basic_info", "01_objectives", "02_content", "03_innovation", @@ -87,10 +88,62 @@ def check_placeholders(text: str, file_label: str) -> list[str]: return issues +def parse_spec_metrics(spec_path: Path) -> list[str]: + """从 spec_lock.md 的"7. 考核指标矩阵"段抽出"指南考核指标"那列。 + + 寻找形如 `| 1 | 指南指标 | ... |` 的表行(序号 = 数字),取第 2 列。 + 返回每条指南指标的关键短语列表 (用于在 sections 中模糊匹配)。 + """ + if not spec_path.exists(): + return [] + txt = spec_path.read_text(encoding="utf-8") + # 截取 "考核指标矩阵" 段到下一节标题 + m = re.search(r"考核指标矩阵.*?(?=\n##\s|\Z)", txt, re.DOTALL) + if not m: + return [] + block = m.group(0) + out: list[str] = [] + for line in block.splitlines(): + if not line.strip().startswith("|"): + continue + cells = [c.strip() for c in line.strip().strip("|").split("|")] + if len(cells) < 3: + continue + # 表头行 / 分隔行 跳过 + if not cells[0].isdigit(): + continue + guide_metric = cells[1] + if guide_metric and not guide_metric.startswith(" list[str]: + """每条指南考核指标必须在某个章节里以**关键词**形式出现 (>=2 个核心词命中)。""" + metrics = parse_spec_metrics(spec_path) + if not metrics: + return [] + # 把 sections 全文拼起来 + full = "\n".join(f.read_text(encoding="utf-8") for f in sections_dir.glob("*.md")) + issues = [] + for metric in metrics: + # 提关键词: 取长度 >=2 的中文片段 / 数字 / 字母组合 + tokens = re.findall(r"[一-鿿]{2,}|[A-Za-z][\w]*|\d+\.?\d*", metric) + if not tokens: + continue + hits = sum(1 for t in tokens if t in full) + # 至少命中 2 个 token, 且至少 30% 的 token 出现 + if hits < 2 or hits / len(tokens) < 0.3: + issues.append(f"指南指标可能未在正文覆盖: '{metric[:50]}...' (命中 {hits}/{len(tokens)} 关键词)") + return issues + + def main() -> None: ap = argparse.ArgumentParser(description="申报书质量检查") ap.add_argument("sections_dir", type=Path) ap.add_argument("--fund-type", required=True, choices=list(REQUIRED_SECTIONS.keys())) + ap.add_argument("--spec", type=Path, default=None, + help="spec_lock.md 路径; 提供后会做指南考核指标覆盖度检查") ap.add_argument("--strict", action="store_true", help="严格模式: 任何检查项失败均退出 1") args = ap.parse_args() @@ -99,7 +152,7 @@ def main() -> None: print(f"[ERR] {args.sections_dir} not a directory", file=sys.stderr) sys.exit(2) - print(f"\n[质量检查]申报书质量检查 ({args.fund_type})\n") + print(f"\n[质量检查] fund_type={args.fund_type}\n") all_issues: list[str] = [] @@ -113,7 +166,7 @@ def main() -> None: else: print("[OK] 结构完整") - # 2-4. 内容 + # 2-4. 内容 (假大空 / 不可考核词 / 占位符) files = sorted(args.sections_dir.glob("*.md")) print(f"\n共 {len(files)} 个章节, 逐章扫描...\n") for f in files: @@ -128,13 +181,30 @@ def main() -> None: print(f" -{s.split('] ', 1)[1]}") all_issues.extend(sub_issues) + # 5. 指南覆盖度 (--spec 提供时) + if args.spec: + if not args.spec.exists(): + print(f"\n[ERR] spec 文件不存在: {args.spec}") + all_issues.append("spec 文件不存在") + else: + print(f"\n[指南覆盖度] 对照 {args.spec.name}") + cov_issues = check_spec_coverage(args.sections_dir, args.spec) + if cov_issues: + print("[WARN] 部分指南指标可能在正文未充分覆盖:") + for s in cov_issues: + print(f" -{s}") + all_issues.extend(cov_issues) + else: + print("[OK] 指南考核指标在正文均有体现") + print("\n" + "=" * 60) if all_issues: print(f"[WARN] 共发现 {len(all_issues)} 个问题。") print("\n建议:") - print(" - 假大空词组 → 换成具体数字 / 对比") - print(" - 不可考核词 → 量化指标 (TPS / 准确率 / 万元 / N 篇)") - print(" - 占位符未替换 → 找用户提供真实数据 / 替换 ") + print(" - 假大空词组 -> 换成具体数字 / 对比") + print(" - 不可考核词 -> 量化指标 (TPS / 准确率 / 万元 / N 篇)") + print(" - 占位符未替换 -> 找用户提供真实数据 / 替换 ") + print(" - 未覆盖指南指标 -> 在对应章节明确写出该指标的实现方式") if args.strict: sys.exit(1) else: diff --git a/skills/proposal/templates/spec_lock.md b/skills/proposal/templates/spec_lock.md new file mode 100644 index 0000000..a56a030 --- /dev/null +++ b/skills/proposal/templates/spec_lock.md @@ -0,0 +1,94 @@ +# 申报书 spec_lock + +> 阶段一产物。**写定后不再改**,阶段二每章前都要 read。`` 是占位符,需要用户明确填值;不要硬编。 + +## 1. 基金类型 + +`` (key_rd / major_project / nsfc_joint_fund / nsfc_general / nsfc_youth / provincial / enterprise) + +对应资助强度: `` 万元 / `` 年 + +## 2. 指南方向 + +> **一字不改**抄指南文本。无指南 (青年/横向) 填研究方向。 + +``` + +``` + +## 3. 关键科学问题 / 关键技术问题 + +(1-2 个,与指南对齐;**问题 ≠ 任务**) + +- 关键问题 1: `` +- 关键问题 2: `` + +## 4. 创新点 + +(≤3 条,每条 ≤500 字。三特征公式: 基本形态 + 前沿性 + 知识产权特征) + +- 创新点 1: `` +- 创新点 2: `` +- 创新点 3: `` + +## 5. 研究内容骨架 / 课题分解 + +| # | 名称 | 牵头单位 | 关键技术 | 经费占比 | +|---|---|---|---|---| +| 1 | `` | `` | `` | XX% | +| 2 | `` | `` | `` | XX% | +| ... | + +(重点研发/重大专项必须分课题,通常 4-6 个;NSFC 面上/青年填 3-5 项研究内容即可) + +## 6. 团队 + +### 牵头单位 +`` —— `` + +### 项目/课题负责人 +`` —— 在本项目中承担 `` + +### 主要参与单位 (按重要性) +- `` — 定位 + 在本项目中承担 X +- `` — ... + +## 7. 考核指标矩阵 ← 阶段三 quality_check 会读这一节 + +> 一行一条指南指标。**指南那栏字面抄,不能改写**;本项目那栏可超出,不能低于。 + +| # | 指南考核指标 (字面抄) | 本项目考核指标 (量化) | 评测方式 | 验收交付物 | +|---|---|---|---|---| +| 1 | `` | `` | CNAS/CMA / 测试大纲 / 应用示范报告 | `` | +| 2 | `` | `` | `` | `` | +| ... | + +## 8. 经费预算 + +| 科目 | 金额 (万元) | 备注 | +|---|---|---| +| 中央财政 | `` | | +| 直接费用 - 设备费 | `` | 50 万以上需 B3 表 | +| 直接费用 - 业务费 | `` | | +| 直接费用 - 劳务费 | `` | 仅给临时聘用 | +| 间接费用 | `` | 台阶: ≤500 万≤30% / 500-1000≤25% / >1000≤20% | +| 自筹 / 其他 | `` | 应用示范类常需 ≥1:1 配套 | +| **合计** | `` | 与指南资助量级匹配 | + +## 9. TODO 列表 + +> 阶段一过程中冒出来的"等用户提供"事项。阶段二每章开头扫一眼;阶段三 quality_check 会扫余留的 ``。 + +- [ ] `` +- [ ] `` +- [ ] `` + +## 10. 引文清单 (用户提供) + +> 编造文献是学术不端。引文必须用户给清单 — 这里粘 BibTeX/EndNote/纯文本均可,阶段三按 GB/T 7714 排版。 + +``` +[1] +[2] +... +```