diff --git a/.prettierignore b/.prettierignore index ad0c04318..fa1323d73 100644 --- a/.prettierignore +++ b/.prettierignore @@ -23,4 +23,7 @@ shrinkwrap.json # Build outputs dist -lib \ No newline at end of file +lib + +# Skill templates (contain placeholder syntax that formatters break) +skills/vtable-development-assistant/template/ \ No newline at end of file diff --git a/skills/vtable-development-assistant/SKILL.md b/skills/vtable-development-assistant/SKILL.md index f40f836cb..82dfa18a5 100644 --- a/skills/vtable-development-assistant/SKILL.md +++ b/skills/vtable-development-assistant/SKILL.md @@ -37,7 +37,7 @@ references/ | 属性、property | `references/knowledge/06-api-properties.md` | | 事件、on、监听、click、scroll | `references/knowledge/07-events.md` → `references/type/event-types.md` | | 维度、dimension、指标、indicator | `references/knowledge/08-pivot-dimensions.md` → `references/type/pivot-types.md` | -| 数据、records、dataSource | `references/knowledge/09-data-binding.md` | +| 数据、records、dataSource | `references/knowledge/09-data-bindingd.md` | | 交互、选择、hover、编辑、拖拽、排序 | `references/knowledge/10-interaction.md` | | 最佳实践、模式、怎么做 | `references/knowledge/11-common-patterns.md` → `references/examples/` | @@ -51,3 +51,36 @@ references/ 6. **销毁表格必须调用 `tableInstance.release()`** 7. 透视表数据分析需要配置 `dataConfig` 中的 `aggregationRules` 8. 自定义布局优先推荐 JSX 方案(`customLayout`),低级需求用 `customRender` + +## 脚本生成强制规则 + +- 所有输出必须通过脚本生成 HTML,不允许手写 HTML 或仅输出片段 +- 诊断场景使用 `scripts/generate_diagnosis_html.py` +- 生成/编辑场景使用 `scripts/generate_demo_html.py` +- 输出必须包含脚本命令与生成文件路径,确保可复现 +- 未输出脚本命令与文件路径时,必须补齐后再回答 +- 输入代码不得包含 `import` / `export`,需先移除再写入 spec.js 或 config.js +- 禁止创建或覆盖 `scripts/` 下脚本文件,必须直接调用已有脚本 + +**绝对路径调用示例**: + +```bash +python3 scripts/generate_demo_html.py --spec-file spec.js --output output/demo.html +``` + +**环境无关调用说明**: + +- 在任意目录运行脚本时,脚本会基于自身位置定位模板 +- 不需要使用绝对路径 + +**示例(诊断)**: + +```bash +python3 scripts/generate_diagnosis_html.py --config-file config.js --output output/diagnosis.html +``` + +**示例(生成/编辑)**: + +```bash +python3 scripts/generate_demo_html.py --spec-file spec.js --output output/demo.html +``` diff --git a/skills/vtable-development-assistant/scripts/generate_demo_html.py b/skills/vtable-development-assistant/scripts/generate_demo_html.py new file mode 100644 index 000000000..773f57082 --- /dev/null +++ b/skills/vtable-development-assistant/scripts/generate_demo_html.py @@ -0,0 +1,61 @@ +from pathlib import Path +import argparse + + +def escape_js_string(value: str) -> str: + return ( + value.replace("\\", "\\\\") + .replace("`", "\\`") + .replace("${", "\\${") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t") + ) + + +def main(): + parser = argparse.ArgumentParser(description="Generate VTable demo HTML") + parser.add_argument("--title", default="VTable 表格示例") + parser.add_argument("--desc", default="基于需求生成的可运行表格配置") + parser.add_argument("--feature", default="补充主要功能说明") + parser.add_argument("--tips", default="补充编辑提示") + parser.add_argument("--spec-file") + parser.add_argument("--output", default="output/demo.html") + args = parser.parse_args() + + template_path = Path(__file__).resolve().parent.parent / "template" / "demo.html" + if not template_path.exists(): + raise FileNotFoundError(f"模板不存在: {template_path}") + + if args.spec_file: + spec_path = Path(args.spec_file) + if not spec_path.exists(): + raise FileNotFoundError(f"配置文件不存在: {spec_path}") + spec_code = spec_path.read_text(encoding="utf-8") + else: + spec_code = """const tableInstance = new VTable.ListTable({ + container: document.getElementById('container'), + records: [{ name: "张三", age: 25 }], + columns: [ + { field: "name", title: "姓名", width: 100 }, + { field: "age", title: "年龄", width: 80 } + ], + width: 600, + height: 400 +});""" + + html = template_path.read_text(encoding="utf-8") + html = html.replace("{{REPORT_TITLE}}", args.title) + html = html.replace("{{REPORT_DESC}}", args.desc) + html = html.replace("{{FEATURE_DESC}}", args.feature) + html = html.replace("{{EDIT_TIPS}}", args.tips) + html = html.replace("{{INITIAL_CODE}}", escape_js_string(spec_code.strip())) + + output_path = Path(args.output) + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(html, encoding="utf-8") + print(f"生成完成: {output_path.resolve()}") + + +if __name__ == "__main__": + main() diff --git a/skills/vtable-development-assistant/scripts/generate_diagnosis_html.py b/skills/vtable-development-assistant/scripts/generate_diagnosis_html.py new file mode 100644 index 000000000..a1ad895d8 --- /dev/null +++ b/skills/vtable-development-assistant/scripts/generate_diagnosis_html.py @@ -0,0 +1,74 @@ +from pathlib import Path +import argparse + + +def main(): + parser = argparse.ArgumentParser(description="Generate VTable diagnosis HTML") + parser.add_argument("--title", default="VTable 问题诊断报告") + parser.add_argument("--desc", default="基于用户配置的诊断与修复结果") + parser.add_argument("--config-file") + parser.add_argument("--output", default="output/diagnosis.html") + args = parser.parse_args() + + template_path = Path(__file__).resolve().parent.parent / "template" / "diagnosis.html" + if not template_path.exists(): + raise FileNotFoundError(f"模板不存在: {template_path}") + + if args.config_file: + config_path = Path(args.config_file) + if not config_path.exists(): + raise FileNotFoundError(f"配置文件不存在: {config_path}") + config_block = config_path.read_text(encoding="utf-8") + else: + config_block = """const problemReview = { + specCode: `const tableInstance = new VTable.ListTable({ + container: document.getElementById('container'), + records: [{ name: "张三", age: 25 }], + columns: [ + { field: "name", title: "姓名", width: 100 }, + { field: "age", title: "年龄", width: 80 } + ], + width: 600, + height: 400 +});` +}; + +const diagnosis = { + problem: "示例问题描述", + cause: "示例原因分析", + suggestion: "示例修复建议" +}; + +const solutions = [ + { + title: "示例修复方案", + description: "修复方案描述", + specCode: `const tableInstance = new VTable.ListTable({ + container: document.getElementById('container'), + records: [{ name: "张三", age: 25 }], + columns: [ + { field: "name", title: "姓名", width: 120 }, + { field: "age", title: "年龄", width: 80 } + ], + width: 600, + height: 400 +});` + } +];""" + + html = template_path.read_text(encoding="utf-8") + if "{{CONFIG_BLOCK}}" not in html: + raise ValueError("模板缺少 CONFIG_BLOCK 占位符") + + html = html.replace("{{REPORT_TITLE}}", args.title) + html = html.replace("{{REPORT_DESC}}", args.desc) + html = html.replace("{{CONFIG_BLOCK}}", config_block) + + output_path = Path(args.output) + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(html, encoding="utf-8") + print(f"生成完成: {output_path.resolve()}") + + +if __name__ == "__main__": + main() diff --git a/skills/vtable-development-assistant/template/demo.html b/skills/vtable-development-assistant/template/demo.html new file mode 100644 index 000000000..e566a6c17 --- /dev/null +++ b/skills/vtable-development-assistant/template/demo.html @@ -0,0 +1,286 @@ + + +
+ + +{{REPORT_DESC}}
+{{FEATURE_DESC}}
+{{EDIT_TIPS}}
+{{REPORT_DESC}}
+