v1.0.1: 课程成绩异常诊断与报告生成 - 初版骨架

基于匠厂 skill-template 主仓 v1.0.108 派生的业务技能。

核心业务:
- 教师在教务系统录完成绩后自动触发
- 统计指标计算 + 三种异常模式识别(高分低能 / 两极分化 / 挂科异常)
- 生成三段式 AI 评语(总体 / 问题 / 建议)

输出形态:
- HTML 报告(含统计表 + 正态分布图 + AI 评语)
- 高风险课程自动标记 + 异常预警通知

预期提效:教师撰写成绩分析报告的时间从半天 → 10 分钟。

业务行生命周期:无(一次性报告存档,不重复处理)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-09-14 12:19:12 +08:00
commit 1d20cfa708
21 changed files with 1482 additions and 0 deletions

123
assets/actions.json Normal file
View File

@@ -0,0 +1,123 @@
{
"schemaVersion": 1,
"skill": "analyze-grade-distribution-aa",
"actions": [
{
"id": "health",
"label": "运行检查",
"description": "检查技能运行环境、教务系统 API 连通性、历史成绩库完整性。",
"placements": ["skill-detail", "agent"],
"executionProfile": "sync",
"entrypoint": {
"type": "cli",
"command": "health",
"args": []
}
},
{
"id": "version",
"label": "查看版本",
"description": "返回技能版本和机器标识。",
"placements": ["skill-detail"],
"executionProfile": "sync",
"entrypoint": {
"type": "cli",
"command": "version",
"args": []
}
},
{
"id": "config-path",
"label": "查看配置位置",
"description": "返回技能配置文件位置。",
"placements": ["skill-detail"],
"executionProfile": "sync",
"entrypoint": {
"type": "cli",
"command": "config-path",
"args": []
}
},
{
"id": "analyze-grade-distribution",
"label": "分析这份成绩",
"description": "对指定课程的成绩执行统计指标计算 + 三种异常模式识别 + AI 三段式评语生成,10~30 秒内返回报告。",
"placements": ["row", "agent"],
"executionProfile": "sync",
"bind": {
"tables": ["课程成绩"],
"selectionMode": "required",
"labelColumn": "课程名称"
},
"entrypoint": {
"type": "cli",
"command": "analyze-grade-distribution",
"args": ["--course-id", "{row.课程ID}"]
}
},
{
"id": "batch-analyze-courses",
"label": "批量分析本学期",
"description": "批量分析某学期所有课程的成绩,按顺序逐门执行并汇总结果。",
"placements": ["toolbar", "agent"],
"executionProfile": "async",
"bind": {
"tables": ["课程成绩"]
},
"entrypoint": {
"type": "cli",
"command": "batch-analyze-courses",
"args": ["--semester-id", "{form.semester_id}"]
}
},
{
"id": "render-html",
"label": "查看分析报告",
"description": "渲染指定分析报告的 HTML 页面,宿主 iframe 预览。",
"placements": ["row", "skill-detail", "agent"],
"executionProfile": "sync",
"bind": {
"tables": ["分析报告"],
"selectionMode": "required",
"labelColumn": "课程名称"
},
"entrypoint": {
"type": "cli",
"command": "render-html",
"args": ["--report-id", "{row.报告ID}"]
}
},
{
"id": "flag-high-risk-course",
"label": "标记为高风险课程",
"description": "手动将某门课程标记为高风险课程,推送通知给教学督导与学院教学副院长。",
"placements": ["row"],
"executionProfile": "sync",
"bind": {
"tables": ["分析报告"],
"selectionMode": "required",
"labelColumn": "课程名称"
},
"entrypoint": {
"type": "cli",
"command": "flag-high-risk-course",
"args": ["--report-id", "{row.报告ID}"]
}
},
{
"id": "sync-historical-grades",
"label": "同步历史成绩",
"description": "从教务系统重新拉取历史成绩数据。占位 Action,cron 启用后由定时调度。",
"placements": ["cron", "agent", "toolbar"],
"executionProfile": "async",
"bind": {
"tables": ["历史成绩"]
},
"entrypoint": {
"type": "cli",
"command": "sync-historical-grades",
"args": []
}
}
]
}

View File

@@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>{{TITLE}}</title>
<style>
/* 数据管理 iframe 预览布局基线 */
html, body {
margin: 0;
padding: 16px;
font-family: -apple-system, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
color: #1f2329;
background: #fafbfc;
line-height: 1.6;
}
.report { max-width: 100%; }
.header {
padding: 20px;
background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);
color: #fff;
border-radius: 8px;
margin-bottom: 16px;
}
.header h1 { margin: 0 0 8px; font-size: 22px; }
.header .meta { color: #ede9fe; font-size: 13px; }
.risk-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
margin-left: 8px;
}
.risk-badge.high { background: #fef2f2; color: #c53030; }
.risk-badge.normal { background: #ecfdf5; color: #059669; }
.section {
padding: 16px 20px;
background: #fff;
border: 1px solid #e5e6eb;
border-radius: 8px;
margin-bottom: 16px;
}
.section h2 { margin: 0 0 12px; font-size: 16px; color: #6d28d9; }
.stat-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 12px;
}
.stat-card {
padding: 12px 16px;
background: #faf5ff;
border: 1px solid #e9d5ff;
border-radius: 8px;
}
.stat-card .label { color: #8b5cf6; font-size: 12px; }
.stat-card .value { font-size: 20px; font-weight: 700; margin-top: 4px; color: #4c1d95; }
.stat-card .unit { font-size: 12px; color: #8b5cf6; margin-left: 4px; }
.distribution {
padding: 16px;
background: #faf5ff;
border: 1px dashed #c4b5fd;
border-radius: 8px;
text-align: center;
color: #6d28d9;
font-style: italic;
margin-top: 8px;
}
.anomaly-list {
list-style: none;
padding: 0;
margin: 0;
}
.anomaly-list li {
padding: 12px 16px;
border-left: 4px solid #cbd5e1;
background: #f8fafc;
border-radius: 4px;
margin-bottom: 8px;
}
.anomaly-list li.high { border-left-color: #c53030; background: #fef2f2; color: #991b1b; }
.anomaly-list li.normal { border-left-color: #059669; background: #ecfdf5; color: #065f46; }
.anomaly-list li strong { display: block; margin-bottom: 4px; }
.comment-block {
padding: 14px 18px;
background: #faf5ff;
border-left: 4px solid #a855f7;
border-radius: 4px;
color: #4c1d95;
margin-bottom: 8px;
white-space: pre-wrap;
}
.comment-block strong { display: block; margin-bottom: 6px; color: #6d28d9; }
.footer { margin-top: 16px; color: #8c959f; font-size: 12px; text-align: right; }
</style>
</head>
<body>
<div class="report">
<div class="header">
<h1>{{TITLE}}<span class="risk-badge {{RISK_CLASS}}">{{RISK_LABEL}}</span></h1>
<div class="meta">报告编号:{{REPORT_ID}} · 课程:{{COURSE_NAME}} · 任课教师:{{TEACHER_NAME}}</div>
<div class="meta">学期:{{SEMESTER}} · 分析完成时间:{{GENERATED_AT}}</div>
</div>
<div class="section">
<h2>统计指标</h2>
<div class="stat-grid">
<div class="stat-card"><div class="label">最高分</div><div class="value">{{MAX_SCORE}}<span class="unit">分</span></div></div>
<div class="stat-card"><div class="label">最低分</div><div class="value">{{MIN_SCORE}}<span class="unit">分</span></div></div>
<div class="stat-card"><div class="label">平均分</div><div class="value">{{AVG_SCORE}}<span class="unit">分</span></div></div>
<div class="stat-card"><div class="label">中位数</div><div class="value">{{MEDIAN_SCORE}}<span class="unit">分</span></div></div>
<div class="stat-card"><div class="label">标准差</div><div class="value">{{STD_SCORE}}</div></div>
<div class="stat-card"><div class="label">及格率</div><div class="value">{{PASS_RATE}}<span class="unit">%</span></div></div>
<div class="stat-card"><div class="label">优秀率</div><div class="value">{{EXCELLENT_RATE}}<span class="unit">%</span></div></div>
<div class="stat-card"><div class="label">学生数</div><div class="value">{{STUDENT_COUNT}}</div></div>
</div>
<div class="distribution">{{DISTRIBUTION_PLACEHOLDER}}</div>
</div>
<div class="section">
<h2>异常模式识别</h2>
<ul class="anomaly-list">
{{ANOMALY_BODY}}
</ul>
</div>
<div class="section">
<h2>AI 评语(草稿,请教师修改后存档)</h2>
<div class="comment-block">
<strong>📊 总体描述</strong>
{{COMMENT_OVERVIEW}}
</div>
<div class="comment-block">
<strong>⚠️ 存在问题</strong>
{{COMMENT_ISSUES}}
</div>
<div class="comment-block">
<strong>💡 改进建议</strong>
{{COMMENT_SUGGESTIONS}}
</div>
</div>
<div class="footer">本报告由「课程成绩异常诊断与报告生成」技能自动生成 · 最终评价权归教学督导与学院</div>
</div>
</body>
</html>