git-analytics-cli 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl
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.
- generate_report.py +226 -1130
- git_analytics.py +4 -4
- {git_analytics_cli-0.1.2.dist-info → git_analytics_cli-0.1.4.dist-info}/METADATA +3 -3
- git_analytics_cli-0.1.4.dist-info/RECORD +11 -0
- git_analytics_cli-0.1.2.dist-info/RECORD +0 -11
- {git_analytics_cli-0.1.2.data → git_analytics_cli-0.1.4.data}/data/share/git-analytics/share-card.html +0 -0
- {git_analytics_cli-0.1.2.dist-info → git_analytics_cli-0.1.4.dist-info}/WHEEL +0 -0
- {git_analytics_cli-0.1.2.dist-info → git_analytics_cli-0.1.4.dist-info}/entry_points.txt +0 -0
- {git_analytics_cli-0.1.2.dist-info → git_analytics_cli-0.1.4.dist-info}/licenses/LICENSE +0 -0
- {git_analytics_cli-0.1.2.dist-info → git_analytics_cli-0.1.4.dist-info}/top_level.txt +0 -0
generate_report.py
CHANGED
|
@@ -135,6 +135,12 @@ body {
|
|
|
135
135
|
.rank-commits { font-size: 1em; font-weight: 700; color: #0969da; }
|
|
136
136
|
|
|
137
137
|
/* 建议 */
|
|
138
|
+
.sug-tabs { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
|
|
139
|
+
.sug-tab { padding: 8px 16px; border: 1px solid #d0d7de; border-radius: 20px; background: #f6f8fa; color: #656d76; font-size: 0.85em; cursor: pointer; transition: all 0.2s; }
|
|
140
|
+
.sug-tab:hover { background: #eaeef2; color: #1f2328; }
|
|
141
|
+
.sug-tab.active { background: #0969da; color: #fff; border-color: #0969da; }
|
|
142
|
+
.sug-panel { display: none; }
|
|
143
|
+
.sug-panel.active { display: block; }
|
|
138
144
|
.sug-item { display: flex; gap: 12px; margin-bottom: 10px; padding: 12px 14px; background: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; }
|
|
139
145
|
.sug-num { width: 20px; height: 20px; background: #1a7f37; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.7em; font-weight: 700; flex-shrink: 0; }
|
|
140
146
|
.sug-text { font-size: 0.9em; color: #1f2328; }
|
|
@@ -754,7 +760,16 @@ def _build_eng_insight(health):
|
|
|
754
760
|
|
|
755
761
|
|
|
756
762
|
def _build_suggestions_html(habit_score, health, data):
|
|
757
|
-
|
|
763
|
+
# 分类建议结构
|
|
764
|
+
categories = {
|
|
765
|
+
'commit': {'name': '提交习惯', 'icon': '📝', 'items': []},
|
|
766
|
+
'test': {'name': '测试质量', 'icon': '✅', 'items': []},
|
|
767
|
+
'doc': {'name': '文档维护', 'icon': '📚', 'items': []},
|
|
768
|
+
'schedule': {'name': '作息健康', 'icon': '⏰', 'items': []},
|
|
769
|
+
'project': {'name': '项目管理', 'icon': '🎯', 'items': []},
|
|
770
|
+
'ai': {'name': 'AI 协作', 'icon': '🤖', 'items': []},
|
|
771
|
+
}
|
|
772
|
+
|
|
758
773
|
summary = data.get('summary', {})
|
|
759
774
|
ai = data.get('ai_signals', {})
|
|
760
775
|
avg_daily = summary.get('avg_commits_per_day', 0)
|
|
@@ -765,503 +780,109 @@ def _build_suggestions_html(habit_score, health, data):
|
|
|
765
780
|
total_commits = summary.get('total_commits', 0)
|
|
766
781
|
total_active_days = summary.get('total_active_days', 0)
|
|
767
782
|
total_projects = summary.get('total_projects', 0)
|
|
783
|
+
projects = data.get('projects', [])
|
|
768
784
|
|
|
769
785
|
# ============================================================
|
|
770
|
-
#
|
|
786
|
+
# 提交习惯 (最多 6 条)
|
|
771
787
|
# ============================================================
|
|
772
|
-
if habit_score['schedule'] < 10:
|
|
773
|
-
suggestions.append("改善作息规律:作息得分仅 {}/20,夜间和周末提交较多".format(habit_score['schedule']))
|
|
774
|
-
if habit_score['focus'] < 10:
|
|
775
|
-
suggestions.append("提升专注度:项目聚焦得分仅 {}/15,建议减少同时维护的项目数".format(habit_score['focus']))
|
|
776
788
|
if habit_score['granularity'] < 15:
|
|
777
|
-
|
|
789
|
+
categories['commit']['items'].append("优化提交粒度:粒度得分仅 {}/40,建议保持稳定的提交频率".format(habit_score['granularity']))
|
|
790
|
+
if avg_daily < 1:
|
|
791
|
+
categories['commit']['items'].append("提高提交频率:日均仅 {:.1f} 次提交,建议小步快跑、勤提交".format(avg_daily))
|
|
792
|
+
elif avg_daily > 8:
|
|
793
|
+
categories['commit']['items'].append("优化提交粒度:日均 {:.1f} 次提交偏多,考虑合并相关改动".format(avg_daily))
|
|
794
|
+
if health['low_info_ratio'] > 15:
|
|
795
|
+
categories['commit']['items'].append("优化 Commit Message:{:.0f}% 的提交缺少描述,建议使用 Conventional Commits 规范".format(health['low_info_ratio']))
|
|
796
|
+
elif health['low_info_ratio'] > 5:
|
|
797
|
+
categories['commit']['items'].append("完善提交描述:部分 commit 信息过于简略,建议写清楚改动原因")
|
|
798
|
+
if total_commits > 0:
|
|
799
|
+
other_c = commit_types.get('other', 0)
|
|
800
|
+
other_pct = other_c / total_commits * 100
|
|
801
|
+
if other_pct > 30:
|
|
802
|
+
categories['commit']['items'].append("提交分类不清:{:.0f}% 归为 other,建议使用 feat/fix/refactor 等标准类型".format(other_pct))
|
|
803
|
+
if total_active_days > 0 and total_commits > 0:
|
|
804
|
+
commits_per_active_day = total_commits / total_active_days
|
|
805
|
+
if commits_per_active_day > 10:
|
|
806
|
+
categories['commit']['items'].append("控制单日提交量:活跃日均提交 {:.0f} 次,建议拆分为更小的改动".format(commits_per_active_day))
|
|
807
|
+
|
|
808
|
+
# 正面反馈
|
|
809
|
+
if health['low_info_ratio'] < 3:
|
|
810
|
+
categories['commit']['items'].append("Commit 质量高:{:.0f}% 的提交有详细描述,继续保持!".format(100 - health['low_info_ratio']))
|
|
811
|
+
if avg_daily >= 2 and avg_daily <= 5:
|
|
812
|
+
categories['commit']['items'].append("提交频率适中:日均 {:.1f} 次提交,节奏良好".format(avg_daily))
|
|
778
813
|
|
|
779
814
|
# ============================================================
|
|
780
|
-
#
|
|
815
|
+
# 测试质量 (最多 5 条)
|
|
781
816
|
# ============================================================
|
|
782
817
|
if habit_score['test_awareness'] < 10:
|
|
783
|
-
|
|
818
|
+
categories['test']['items'].append("提高测试意识:尝试为每个新功能编写测试用例,目标覆盖率 10%+")
|
|
784
819
|
elif health['test_ratio'] < 8:
|
|
785
|
-
|
|
820
|
+
categories['test']['items'].append("增加测试投入:当前测试文件占比仅 {:.0f}%,建议补充单元测试".format(health['test_ratio']))
|
|
821
|
+
if total_commits > 0:
|
|
822
|
+
test_count = commit_types.get('test', 0)
|
|
823
|
+
if test_count / total_commits < 0.05 and total_commits > 50:
|
|
824
|
+
categories['test']['items'].append("增加测试提交:测试相关提交仅占 {:.0f}%,建议为新功能编写测试".format(test_count / total_commits * 100))
|
|
825
|
+
if health['fix_ratio'] > 20:
|
|
826
|
+
categories['test']['items'].append("提升代码质量:Bug 修复占比 {:.0f}%,建议加强测试和 Code Review".format(health['fix_ratio']))
|
|
827
|
+
|
|
828
|
+
# 正面反馈
|
|
786
829
|
if health['test_ratio'] >= 30:
|
|
787
|
-
|
|
830
|
+
categories['test']['items'].append("测试做得好:测试文件占比 {:.0f}%,继续保持!".format(health['test_ratio']))
|
|
788
831
|
|
|
789
832
|
# ============================================================
|
|
790
|
-
#
|
|
833
|
+
# 文档维护 (最多 5 条)
|
|
791
834
|
# ============================================================
|
|
792
835
|
if habit_score['doc_awareness'] < 10:
|
|
793
|
-
|
|
836
|
+
categories['doc']['items'].append("增加文档投入:定期更新 README 和 API 文档")
|
|
794
837
|
elif health['doc_ratio'] < 5:
|
|
795
|
-
|
|
838
|
+
categories['doc']['items'].append("完善文档:文档变更占比 {:.0f}%,重要功能应有文档说明".format(health['doc_ratio']))
|
|
839
|
+
if total_commits > 0:
|
|
840
|
+
docs_count = commit_types.get('docs', 0)
|
|
841
|
+
if docs_count / total_commits < 0.05 and total_commits > 50:
|
|
842
|
+
categories['doc']['items'].append("增加文档提交:文档相关提交仅占 {:.0f}%,建议及时更新文档".format(docs_count / total_commits * 100))
|
|
843
|
+
|
|
844
|
+
# 正面反馈
|
|
796
845
|
if health['doc_ratio'] >= 15:
|
|
797
|
-
|
|
846
|
+
categories['doc']['items'].append("文档做得好:文档变更占比 {:.0f}%,继续保持!".format(health['doc_ratio']))
|
|
798
847
|
|
|
799
848
|
# ============================================================
|
|
800
|
-
#
|
|
849
|
+
# 作息健康 (最多 5 条)
|
|
801
850
|
# ============================================================
|
|
851
|
+
if habit_score['schedule'] < 10:
|
|
852
|
+
categories['schedule']['items'].append("改善作息规律:作息得分仅 {}/20,夜间和周末提交较多".format(habit_score['schedule']))
|
|
802
853
|
if health['night_ratio'] > 25:
|
|
803
|
-
|
|
854
|
+
categories['schedule']['items'].append("注意作息健康:夜间提交占比 {:.0f}%,建议调整为白天工作".format(health['night_ratio']))
|
|
804
855
|
if health['weekend_ratio'] > 25:
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
# ============================================================
|
|
808
|
-
# 5. 深夜提交
|
|
809
|
-
# ============================================================
|
|
856
|
+
categories['schedule']['items'].append("平衡工作生活:周末提交占比 {:.0f}%,注意适当休息".format(health['weekend_ratio']))
|
|
810
857
|
if hourly:
|
|
811
|
-
late_night = sum(hourly[0:6])
|
|
858
|
+
late_night = sum(hourly[0:6])
|
|
812
859
|
total = sum(hourly)
|
|
813
860
|
if total > 0 and late_night / total > 0.15:
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
# ============================================================
|
|
817
|
-
# 6. Commit 质量
|
|
818
|
-
# ============================================================
|
|
819
|
-
if health['low_info_ratio'] > 15:
|
|
820
|
-
suggestions.append("优化 Commit Message:{:.0f}% 的提交缺少描述,建议使用 Conventional Commits 规范".format(health['low_info_ratio']))
|
|
821
|
-
elif health['low_info_ratio'] > 5:
|
|
822
|
-
suggestions.append("完善提交描述:部分 commit 信息过于简略,建议写清楚改动原因")
|
|
823
|
-
if health['low_info_ratio'] < 3:
|
|
824
|
-
suggestions.append("Commit 质量高:{:.0f}% 的提交有详细描述,继续保持!".format(100 - health['low_info_ratio']))
|
|
825
|
-
|
|
826
|
-
# ============================================================
|
|
827
|
-
# 7. 项目聚焦
|
|
828
|
-
# ============================================================
|
|
829
|
-
focus_index = data.get('focus_index', 100)
|
|
830
|
-
if focus_index < 60:
|
|
831
|
-
suggestions.append("提高项目聚焦度:精力较分散,建议集中精力在 1-2 个核心项目上")
|
|
832
|
-
|
|
833
|
-
# ============================================================
|
|
834
|
-
# 8. 提交粒度
|
|
835
|
-
# ============================================================
|
|
836
|
-
if avg_daily < 1:
|
|
837
|
-
suggestions.append("提高提交频率:日均仅 {:.1f} 次提交,建议小步快跑、勤提交".format(avg_daily))
|
|
838
|
-
elif avg_daily > 8:
|
|
839
|
-
suggestions.append("优化提交粒度:日均 {:.1f} 次提交偏多,考虑合并相关改动".format(avg_daily))
|
|
840
|
-
elif avg_daily >= 2 and avg_daily <= 5:
|
|
841
|
-
suggestions.append("提交频率适中:日均 {:.1f} 次提交,节奏良好".format(avg_daily))
|
|
842
|
-
|
|
843
|
-
# ============================================================
|
|
844
|
-
# 9. 代码质量
|
|
845
|
-
# ============================================================
|
|
846
|
-
if health['fix_ratio'] > 20:
|
|
847
|
-
suggestions.append("提升代码质量:Bug 修复占比 {:.0f}%,建议加强测试和 Code Review".format(health['fix_ratio']))
|
|
848
|
-
elif health['fix_ratio'] < 5 and total_commits > 50:
|
|
849
|
-
suggestions.append("Bug 很少:Bug 修复仅占 {:.0f}%,代码质量不错".format(health['fix_ratio']))
|
|
850
|
-
if health['refactor_ratio'] < 10 and health['feat_ratio'] > 50:
|
|
851
|
-
suggestions.append("关注技术债:功能开发占比高但重构不足,建议定期安排重构时间")
|
|
852
|
-
if health['refactor_ratio'] >= 10:
|
|
853
|
-
suggestions.append("重构做得好:重构占比 {:.0f}%,代码质量持续改善".format(health['refactor_ratio']))
|
|
854
|
-
|
|
855
|
-
# ============================================================
|
|
856
|
-
# 10. AI 使用
|
|
857
|
-
# ============================================================
|
|
858
|
-
ai_ratio = ai.get('ai_commit_ratio', 0)
|
|
859
|
-
if ai_ratio > 40:
|
|
860
|
-
suggestions.append("善用 AI:AI 占比超过 40%,建议仔细审查 AI 生成的代码")
|
|
861
|
-
elif ai_ratio > 0 and ai_ratio < 15:
|
|
862
|
-
suggestions.append("探索 AI 工具:当前 AI 使用率 {:.0f}%,可尝试 Copilot/Cursor 提升效率".format(ai_ratio))
|
|
863
|
-
if ai_ratio >= 20 and ai_ratio <= 40:
|
|
864
|
-
suggestions.append("AI 使用适中:AI 占比 {:.0f}%,人机协作良好".format(ai_ratio))
|
|
865
|
-
|
|
866
|
-
# AI 工具多样性
|
|
867
|
-
ai_tools = ai.get('tools', {})
|
|
868
|
-
if len(ai_tools) >= 3:
|
|
869
|
-
suggestions.append("AI 工具多样化:使用了 {} 种 AI 工具,建议固定 1-2 种核心工具".format(len(ai_tools)))
|
|
870
|
-
|
|
871
|
-
# ============================================================
|
|
872
|
-
# 11. 提交时间规律
|
|
873
|
-
# ============================================================
|
|
861
|
+
categories['schedule']['items'].append("减少深夜编码:凌晨 0-6 点提交占比 {:.0f}%,长期熬夜影响代码质量".format(late_night / total * 100))
|
|
874
862
|
if peak_hours:
|
|
875
863
|
if 22 in peak_hours or 23 in peak_hours:
|
|
876
|
-
|
|
877
|
-
if 6 in peak_hours or 7 in peak_hours:
|
|
878
|
-
suggestions.append("利用晨间高效期:早上 6-7 点是你最活跃的时段,适合处理复杂任务")
|
|
879
|
-
|
|
880
|
-
# ============================================================
|
|
881
|
-
# 12. 最活跃星期
|
|
882
|
-
# ============================================================
|
|
883
|
-
peak_weekdays = data.get('peak_weekdays', [])
|
|
884
|
-
if peak_weekdays:
|
|
885
|
-
weekend_days = [d for d in peak_weekdays if d in ['周六', '周日']]
|
|
886
|
-
if len(weekend_days) >= 2:
|
|
887
|
-
suggestions.append("调整工作节奏:最活跃的 3 天中有 {} 天是周末,建议以工作日为主".format(len(weekend_days)))
|
|
864
|
+
categories['schedule']['items'].append("调整工作节奏:深夜是你最活跃的时段,建议将核心工作移到白天")
|
|
888
865
|
|
|
889
|
-
#
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
if avg_daily > 5:
|
|
893
|
-
suggestions.append("注意工作强度:日均 {:.1f} 次提交,注意劳逸结合避免倦怠".format(avg_daily))
|
|
866
|
+
# 正面反馈
|
|
867
|
+
if health['night_ratio'] < 15 and health['weekend_ratio'] < 15:
|
|
868
|
+
categories['schedule']['items'].append("工作生活平衡:夜间和周末提交都很少,作息健康")
|
|
894
869
|
|
|
895
870
|
# ============================================================
|
|
896
|
-
#
|
|
871
|
+
# 项目管理 (最多 6 条)
|
|
897
872
|
# ============================================================
|
|
873
|
+
if habit_score['focus'] < 10:
|
|
874
|
+
categories['project']['items'].append("提升专注度:项目聚焦得分仅 {}/15,建议减少同时维护的项目数".format(habit_score['focus']))
|
|
875
|
+
focus_index = data.get('focus_index', 100)
|
|
876
|
+
if focus_index < 60:
|
|
877
|
+
categories['project']['items'].append("提高项目聚焦度:精力较分散,建议集中精力在 1-2 个核心项目上")
|
|
898
878
|
if total_projects > 15:
|
|
899
|
-
|
|
900
|
-
elif total_projects <= 3 and total_commits > 100:
|
|
901
|
-
suggestions.append("项目聚焦度高:仅维护 {} 个项目,精力集中".format(total_projects))
|
|
902
|
-
|
|
903
|
-
# ============================================================
|
|
904
|
-
# 15. 活跃度
|
|
905
|
-
# ============================================================
|
|
906
|
-
if total_active_days > 0 and avg_daily > 0:
|
|
907
|
-
active_rate = min(total_active_days / 365 * 100, 100)
|
|
908
|
-
if active_rate < 30:
|
|
909
|
-
suggestions.append("保持持续性:活跃天数 {} 天,建议养成每天提交的习惯".format(total_active_days))
|
|
910
|
-
elif active_rate > 70:
|
|
911
|
-
suggestions.append("活跃度高:{} 天有提交, coding 习惯良好".format(total_active_days))
|
|
912
|
-
|
|
913
|
-
# ============================================================
|
|
914
|
-
# 16. Commit 类型分布
|
|
915
|
-
# ============================================================
|
|
916
|
-
if total_commits > 0:
|
|
917
|
-
feat_count = commit_types.get('feat', 0)
|
|
918
|
-
test_count = commit_types.get('test', 0)
|
|
919
|
-
docs_count = commit_types.get('docs', 0)
|
|
920
|
-
refactor_count = commit_types.get('refactor', 0)
|
|
921
|
-
fix_count = commit_types.get('fix', 0)
|
|
922
|
-
other_count = commit_types.get('other', 0)
|
|
923
|
-
chore_count = commit_types.get('chore', 0)
|
|
924
|
-
|
|
925
|
-
# 测试提交比例
|
|
926
|
-
if test_count / total_commits < 0.05 and total_commits > 50:
|
|
927
|
-
suggestions.append("增加测试提交:测试相关提交仅占 {:.0f}%,建议为新功能编写测试".format(test_count / total_commits * 100))
|
|
928
|
-
elif test_count / total_commits >= 0.15:
|
|
929
|
-
suggestions.append("测试提交充足:测试占比 {:.0f}%,质量意识强".format(test_count / total_commits * 100))
|
|
930
|
-
|
|
931
|
-
# 文档提交比例
|
|
932
|
-
if docs_count / total_commits < 0.05 and total_commits > 50:
|
|
933
|
-
suggestions.append("增加文档提交:文档相关提交仅占 {:.0f}%,建议及时更新文档".format(docs_count / total_commits * 100))
|
|
934
|
-
elif docs_count / total_commits >= 0.15:
|
|
935
|
-
suggestions.append("文档提交充足:文档占比 {:.0f}%,文档维护良好".format(docs_count / total_commits * 100))
|
|
936
|
-
|
|
937
|
-
# 重构提交比例
|
|
938
|
-
if refactor_count / total_commits < 0.03 and feat_count / total_commits > 0.3:
|
|
939
|
-
suggestions.append("定期重构:重构提交仅占 {:.0f}%,功能开发占比高,建议安排重构时间".format(refactor_count / total_commits * 100))
|
|
940
|
-
|
|
941
|
-
# other 类型提交比例
|
|
942
|
-
if other_count / total_commits > 0.25:
|
|
943
|
-
suggestions.append("规范 Commit 类型:{:.0f}% 的提交被归为 other,建议使用 feat/fix/refactor 等标准类型".format(other_count / total_commits * 100))
|
|
944
|
-
|
|
945
|
-
# chore 类型提交比例
|
|
946
|
-
if chore_count / total_commits > 0.15:
|
|
947
|
-
suggestions.append("自动化琐事:chore 类型提交占比 {:.0f}%,考虑用脚本或 CI 自动化".format(chore_count / total_commits * 100))
|
|
948
|
-
|
|
949
|
-
# 功能开发占比
|
|
950
|
-
if feat_count / total_commits > 0.4:
|
|
951
|
-
suggestions.append("功能开发为主:feat 占比 {:.0f}%,注意平衡新功能与维护".format(feat_count / total_commits * 100))
|
|
952
|
-
|
|
953
|
-
# Bug 修复占比
|
|
954
|
-
if fix_count / total_commits > 0.2:
|
|
955
|
-
suggestions.append("Bug 修复较多:fix 占比 {:.0f}%,建议加强测试预防".format(fix_count / total_commits * 100))
|
|
956
|
-
|
|
957
|
-
# ============================================================
|
|
958
|
-
# 17. 语言多样性
|
|
959
|
-
# ============================================================
|
|
960
|
-
projects = data.get('projects', [])
|
|
961
|
-
if projects:
|
|
962
|
-
lang_set = set()
|
|
963
|
-
for p in projects:
|
|
964
|
-
if isinstance(p, dict):
|
|
965
|
-
lang = p.get('language', '')
|
|
966
|
-
if lang and lang != 'Other':
|
|
967
|
-
lang_set.add(lang)
|
|
968
|
-
if len(lang_set) == 1:
|
|
969
|
-
suggestions.append("拓展技术栈:当前只使用 {} 语言,建议学习其他语言拓宽视野".format(list(lang_set)[0]))
|
|
970
|
-
elif len(lang_set) >= 5:
|
|
971
|
-
suggestions.append("聚焦核心技术:同时使用 {} 种语言,建议深耕 1-2 种核心语言".format(len(lang_set)))
|
|
972
|
-
|
|
973
|
-
# ============================================================
|
|
974
|
-
# 18. 提交频率波动
|
|
975
|
-
# ============================================================
|
|
976
|
-
if hourly:
|
|
977
|
-
max_hour = max(hourly)
|
|
978
|
-
min_hour = min(hourly)
|
|
979
|
-
if max_hour > 0 and min_hour / max_hour < 0.1:
|
|
980
|
-
suggestions.append("平衡提交时间:提交集中在特定时段,建议分散到全天各时段")
|
|
981
|
-
|
|
982
|
-
# ============================================================
|
|
983
|
-
# 19. 提交连续性
|
|
984
|
-
# ============================================================
|
|
985
|
-
if total_active_days > 0 and total_commits > 0:
|
|
986
|
-
commits_per_active_day = total_commits / total_active_days
|
|
987
|
-
if commits_per_active_day > 10:
|
|
988
|
-
suggestions.append("控制单日提交量:活跃日均提交 {:.0f} 次,建议拆分为更小的改动".format(commits_per_active_day))
|
|
989
|
-
|
|
990
|
-
# ============================================================
|
|
991
|
-
# 20. 提交间隔
|
|
992
|
-
# ============================================================
|
|
993
|
-
if total_active_days > 0 and total_commits > 0:
|
|
994
|
-
avg_interval = 24 * total_active_days / total_commits
|
|
995
|
-
if avg_interval < 1:
|
|
996
|
-
suggestions.append("降低提交频率:平均 {:.0f} 分钟一次提交,考虑合并相关改动".format(avg_interval * 60))
|
|
997
|
-
|
|
998
|
-
# ============================================================
|
|
999
|
-
# 21. 工作节奏一致性
|
|
1000
|
-
# ============================================================
|
|
1001
|
-
if hourly:
|
|
1002
|
-
total = sum(hourly)
|
|
1003
|
-
if total > 0:
|
|
1004
|
-
# 计算工作时间(9-18点)vs 非工作时间
|
|
1005
|
-
work_hours = sum(hourly[9:18])
|
|
1006
|
-
work_ratio = work_hours / total
|
|
1007
|
-
if work_ratio > 0.6:
|
|
1008
|
-
suggestions.append("工作节奏规律:{:.0f}% 的提交在工作时间,作息健康".format(work_ratio * 100))
|
|
1009
|
-
elif work_ratio < 0.3:
|
|
1010
|
-
suggestions.append("工作时间不规律:仅 {:.0f}% 的提交在工作时间,建议调整".format(work_ratio * 100))
|
|
1011
|
-
|
|
1012
|
-
# ============================================================
|
|
1013
|
-
# 22. 项目活跃度
|
|
1014
|
-
# ============================================================
|
|
879
|
+
categories['project']['items'].append("精简项目数量:同时维护 {} 个项目,建议聚焦核心项目提升效率".format(total_projects))
|
|
1015
880
|
if projects and total_commits > 0:
|
|
1016
881
|
active_projects = sum(1 for p in projects if isinstance(p, dict) and p.get('commits', 0) > 10)
|
|
1017
882
|
if active_projects <= 2 and total_projects > 5:
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
# 23. 提交消息长度
|
|
1022
|
-
# ============================================================
|
|
1023
|
-
if health['low_info_ratio'] < 5 and total_commits > 100:
|
|
1024
|
-
suggestions.append("提交消息质量高:{:.0f}% 的提交有详细描述,代码可维护性强".format(100 - health['low_info_ratio']))
|
|
1025
|
-
|
|
1026
|
-
# ============================================================
|
|
1027
|
-
# 24. 代码变更规模
|
|
1028
|
-
# ============================================================
|
|
1029
|
-
if total_commits > 0 and total_active_days > 0:
|
|
1030
|
-
avg_changes_per_commit = total_commits / total_active_days # 粗略估计
|
|
1031
|
-
if avg_changes_per_commit > 5:
|
|
1032
|
-
suggestions.append("单次提交较大:建议拆分为更小的提交,便于 Code Review")
|
|
1033
|
-
|
|
1034
|
-
# ============================================================
|
|
1035
|
-
# 25. 技术债务
|
|
1036
|
-
# ============================================================
|
|
1037
|
-
if health['refactor_ratio'] < 5 and health['feat_ratio'] > 40 and total_commits > 100:
|
|
1038
|
-
suggestions.append("技术债积累:重构仅占 {:.0f}%,建议定期安排重构时间".format(health['refactor_ratio']))
|
|
1039
|
-
|
|
1040
|
-
# ============================================================
|
|
1041
|
-
# 26. 测试覆盖趋势
|
|
1042
|
-
# ============================================================
|
|
1043
|
-
if health['test_ratio'] >= 20:
|
|
1044
|
-
suggestions.append("测试覆盖良好:测试文件占比 {:.0f}%,代码质量有保障".format(health['test_ratio']))
|
|
1045
|
-
|
|
1046
|
-
# ============================================================
|
|
1047
|
-
# 27. 文档覆盖趋势
|
|
1048
|
-
# ============================================================
|
|
1049
|
-
if health['doc_ratio'] >= 10:
|
|
1050
|
-
suggestions.append("文档覆盖良好:文档变更占比 {:.0f}%,项目可维护性强".format(health['doc_ratio']))
|
|
1051
|
-
|
|
1052
|
-
# ============================================================
|
|
1053
|
-
# 28. AI 协作深度
|
|
1054
|
-
# ============================================================
|
|
1055
|
-
ai_influence = ai.get('ai_influence_score', 0)
|
|
1056
|
-
if ai_influence > 70:
|
|
1057
|
-
suggestions.append("AI 深度协作:AI 影响分 {},建议定期审查 AI 生成的代码".format(ai_influence))
|
|
1058
|
-
elif ai_influence > 0 and ai_influence < 30:
|
|
1059
|
-
suggestions.append("AI 使用较少:AI 影响分 {},可尝试更多 AI 工具提升效率".format(ai_influence))
|
|
1060
|
-
|
|
1061
|
-
# ============================================================
|
|
1062
|
-
# 29. 工作生活平衡
|
|
1063
|
-
# ============================================================
|
|
1064
|
-
if health['night_ratio'] < 15 and health['weekend_ratio'] < 15:
|
|
1065
|
-
suggestions.append("工作生活平衡:夜间和周末提交都很少,作息健康")
|
|
1066
|
-
|
|
1067
|
-
# ============================================================
|
|
1068
|
-
# 30. 代码稳定性
|
|
1069
|
-
# ============================================================
|
|
1070
|
-
if health['fix_ratio'] < 5 and health['refactor_ratio'] < 5 and total_commits > 100:
|
|
1071
|
-
suggestions.append("代码稳定:Bug 修复和重构都很少,代码质量稳定")
|
|
1072
|
-
|
|
1073
|
-
# ============================================================
|
|
1074
|
-
# 31. 提交频率波动(小时级别)
|
|
1075
|
-
# ============================================================
|
|
1076
|
-
if hourly and len(hourly) == 24:
|
|
1077
|
-
# 计算变异系数
|
|
1078
|
-
import statistics
|
|
1079
|
-
mean_val = statistics.mean(hourly)
|
|
1080
|
-
if mean_val > 0:
|
|
1081
|
-
cv = statistics.stdev(hourly) / mean_val
|
|
1082
|
-
if cv > 1.5:
|
|
1083
|
-
suggestions.append("提交时间波动大:建议保持更稳定的工作节奏")
|
|
1084
|
-
|
|
1085
|
-
# ============================================================
|
|
1086
|
-
# 32. 项目集中度
|
|
1087
|
-
# ============================================================
|
|
1088
|
-
if projects and total_commits > 0:
|
|
1089
|
-
# 计算 HHI 指数(赫芬达尔指数)
|
|
1090
|
-
shares = [p.get('commits', 0) / total_commits for p in projects if isinstance(p, dict)]
|
|
1091
|
-
hhi = sum(s ** 2 for s in shares)
|
|
1092
|
-
if hhi < 0.1:
|
|
1093
|
-
suggestions.append("项目分散:提交分布均匀,建议聚焦核心项目")
|
|
1094
|
-
elif hhi > 0.5:
|
|
1095
|
-
suggestions.append("项目集中:大部分提交集中在少数项目,精力分配合理")
|
|
1096
|
-
|
|
1097
|
-
# ============================================================
|
|
1098
|
-
# 33. 周末提交模式
|
|
1099
|
-
# ============================================================
|
|
1100
|
-
if weekly:
|
|
1101
|
-
sat = weekly.get('周六', 0) if isinstance(weekly, dict) else (weekly[5] if len(weekly) > 5 else 0)
|
|
1102
|
-
sun = weekly.get('周日', 0) if isinstance(weekly, dict) else (weekly[6] if len(weekly) > 6 else 0)
|
|
1103
|
-
total_weekly = sum(weekly.values()) if isinstance(weekly, dict) else sum(weekly)
|
|
1104
|
-
if total_weekly > 0:
|
|
1105
|
-
sat_ratio = sat / total_weekly * 100
|
|
1106
|
-
sun_ratio = sun / total_weekly * 100
|
|
1107
|
-
if sat_ratio > 20 and sun_ratio < 5:
|
|
1108
|
-
suggestions.append("周六活跃:周六提交占比 {:.0f}%,周日较少,节奏不错".format(sat_ratio))
|
|
1109
|
-
elif sun_ratio > 20 and sat_ratio < 5:
|
|
1110
|
-
suggestions.append("周日活跃:周日提交占比 {:.0f}%,建议利用周六提前完成".format(sun_ratio))
|
|
1111
|
-
|
|
1112
|
-
# ============================================================
|
|
1113
|
-
# 34. 提交分布集中度
|
|
1114
|
-
# ============================================================
|
|
1115
|
-
if hourly and len(hourly) == 24:
|
|
1116
|
-
total = sum(hourly)
|
|
1117
|
-
if total > 0:
|
|
1118
|
-
top3_hours = sorted(range(24), key=lambda i: hourly[i], reverse=True)[:3]
|
|
1119
|
-
top3_ratio = sum(hourly[h] for h in top3_hours) / total * 100
|
|
1120
|
-
if top3_ratio > 50:
|
|
1121
|
-
suggestions.append("提交高度集中:最活跃的 3 小时占 {:.0f}% 提交,建议更均匀分布".format(top3_ratio))
|
|
1122
|
-
elif top3_ratio < 25:
|
|
1123
|
-
suggestions.append("提交分布均匀:各时段提交较分散,时间管理良好")
|
|
1124
|
-
|
|
1125
|
-
# ============================================================
|
|
1126
|
-
# 35. 测试与功能平衡
|
|
1127
|
-
# ============================================================
|
|
1128
|
-
if total_commits > 0:
|
|
1129
|
-
feat_count = commit_types.get('feat', 0)
|
|
1130
|
-
test_count = commit_types.get('test', 0)
|
|
1131
|
-
if feat_count > 0:
|
|
1132
|
-
test_feat_ratio = test_count / feat_count
|
|
1133
|
-
if test_feat_ratio < 0.3 and feat_count > 20:
|
|
1134
|
-
suggestions.append("测试跟不上功能:每 {} 个功能提交才对应 1 个测试提交,建议提高测试比例".format(int(1 / test_feat_ratio) if test_feat_ratio > 0 else "∞"))
|
|
1135
|
-
elif test_feat_ratio >= 0.8:
|
|
1136
|
-
suggestions.append("测试与功能同步:测试/功能比 {:.1f},质量意识强".format(test_feat_ratio))
|
|
1137
|
-
|
|
1138
|
-
# ============================================================
|
|
1139
|
-
# 36. 提交历史跨度
|
|
1140
|
-
# ============================================================
|
|
1141
|
-
if total_active_days > 0:
|
|
1142
|
-
if total_active_days > 300:
|
|
1143
|
-
suggestions.append("开发持续性强:活跃 {} 天,长期坚持 coding".format(total_active_days))
|
|
1144
|
-
elif total_active_days < 30 and total_commits > 50:
|
|
1145
|
-
suggestions.append("开发集中在短期:仅 {} 天活跃但有 {} 次提交,建议保持持续性".format(total_active_days, total_commits))
|
|
1146
|
-
|
|
1147
|
-
# ============================================================
|
|
1148
|
-
# 37. 工作日偏好
|
|
1149
|
-
# ============================================================
|
|
1150
|
-
if weekly:
|
|
1151
|
-
if isinstance(weekly, dict):
|
|
1152
|
-
max_day = max(weekly, key=weekly.get)
|
|
1153
|
-
min_day = min(weekly, key=weekly.get)
|
|
1154
|
-
max_val = weekly[max_day]
|
|
1155
|
-
min_val = weekly[min_day]
|
|
1156
|
-
total_weekly = sum(weekly.values())
|
|
1157
|
-
if total_weekly > 0 and max_val > 0:
|
|
1158
|
-
day_ratio = max_val / total_weekly * 100
|
|
1159
|
-
if day_ratio > 25:
|
|
1160
|
-
suggestions.append("工作日偏好明显:{} 占 {:.0f}% 提交,是最活跃的一天".format(max_day, day_ratio))
|
|
1161
|
-
|
|
1162
|
-
# ============================================================
|
|
1163
|
-
# 38. 提交时间分布
|
|
1164
|
-
# ============================================================
|
|
1165
|
-
if hourly and len(hourly) == 24:
|
|
1166
|
-
# 计算高峰时段
|
|
1167
|
-
max_val = max(hourly)
|
|
1168
|
-
peak_hours_list = [i for i, v in enumerate(hourly) if v > max_val * 0.8]
|
|
1169
|
-
if len(peak_hours_list) <= 3:
|
|
1170
|
-
suggestions.append("提交时间集中:高峰时段集中在 {} 点,建议分散到其他时段".format(', '.join([str(h) for h in peak_hours_list])))
|
|
1171
|
-
|
|
1172
|
-
# ============================================================
|
|
1173
|
-
# 39. 项目提交分布
|
|
1174
|
-
# ============================================================
|
|
1175
|
-
if projects and total_commits > 0:
|
|
1176
|
-
# 计算项目提交分布的熵
|
|
1177
|
-
import math
|
|
1178
|
-
shares = [p.get('commits', 0) / total_commits for p in projects if isinstance(p, dict) and p.get('commits', 0) > 0]
|
|
1179
|
-
entropy = -sum(s * math.log2(s) for s in shares if s > 0)
|
|
1180
|
-
max_entropy = math.log2(len(shares)) if len(shares) > 1 else 1
|
|
1181
|
-
if max_entropy > 0:
|
|
1182
|
-
normalized_entropy = entropy / max_entropy
|
|
1183
|
-
if normalized_entropy > 0.8:
|
|
1184
|
-
suggestions.append("项目分布均匀:提交分散在多个项目,建议聚焦核心项目")
|
|
1185
|
-
elif normalized_entropy < 0.3:
|
|
1186
|
-
suggestions.append("项目分布集中:大部分提交集中在少数项目,精力分配合理")
|
|
1187
|
-
|
|
1188
|
-
# ============================================================
|
|
1189
|
-
# 40. 开发习惯总结
|
|
1190
|
-
# ============================================================
|
|
1191
|
-
if habit_score['total'] >= 80:
|
|
1192
|
-
suggestions.append("开发习惯优秀:总分 {} 分,继续保持!".format(habit_score['total']))
|
|
1193
|
-
elif habit_score['total'] >= 60:
|
|
1194
|
-
suggestions.append("开发习惯良好:总分 {} 分,还有提升空间".format(habit_score['total']))
|
|
1195
|
-
|
|
1196
|
-
# ============================================================
|
|
1197
|
-
# 41. 项目类型多样性
|
|
1198
|
-
# ============================================================
|
|
1199
|
-
if projects and len(projects) > 0:
|
|
1200
|
-
# 计算项目提交分布的基尼系数
|
|
1201
|
-
commits_list = sorted([p.get('commits', 0) for p in projects if isinstance(p, dict)])
|
|
1202
|
-
n = len(commits_list)
|
|
1203
|
-
if n > 0 and sum(commits_list) > 0:
|
|
1204
|
-
cumulative = 0
|
|
1205
|
-
gini_sum = 0
|
|
1206
|
-
for i, c in enumerate(commits_list):
|
|
1207
|
-
cumulative += c
|
|
1208
|
-
gini_sum += (2 * (i + 1) - n - 1) * c
|
|
1209
|
-
gini = gini_sum / (n * sum(commits_list))
|
|
1210
|
-
if gini > 0.6:
|
|
1211
|
-
suggestions.append("项目分布不均:基尼系数 {:.2f},建议更均匀地分配精力".format(gini))
|
|
1212
|
-
elif gini < 0.2:
|
|
1213
|
-
suggestions.append("项目分布均匀:基尼系数 {:.2f},精力分配合理".format(gini))
|
|
1214
|
-
|
|
1215
|
-
# ============================================================
|
|
1216
|
-
# 42. 提交频率稳定性
|
|
1217
|
-
# ============================================================
|
|
1218
|
-
if hourly and len(hourly) == 24:
|
|
1219
|
-
# 计算提交时间的峰度
|
|
1220
|
-
mean_val = statistics.mean(hourly)
|
|
1221
|
-
if mean_val > 0 and len(hourly) > 3:
|
|
1222
|
-
variance = statistics.variance(hourly)
|
|
1223
|
-
if variance > 0:
|
|
1224
|
-
# 简化的峰度计算
|
|
1225
|
-
skewness = sum((x - mean_val) ** 3 for x in hourly) / (len(hourly) * (variance ** 1.5))
|
|
1226
|
-
if abs(skewness) > 1:
|
|
1227
|
-
suggestions.append("提交时间分布偏斜:建议保持更规律的工作节奏")
|
|
1228
|
-
|
|
1229
|
-
# ============================================================
|
|
1230
|
-
# 43. 项目活跃周期
|
|
1231
|
-
# ============================================================
|
|
1232
|
-
if projects and total_commits > 0:
|
|
1233
|
-
# 计算项目活跃周期(最近一次提交的时间)
|
|
1234
|
-
recent_projects = 0
|
|
1235
|
-
for p in projects:
|
|
1236
|
-
if isinstance(p, dict):
|
|
1237
|
-
last_commit = p.get('last_commit', '')
|
|
1238
|
-
if last_commit and '2026' in last_commit:
|
|
1239
|
-
recent_projects += 1
|
|
1240
|
-
if recent_projects <= 3 and total_projects > 10:
|
|
1241
|
-
suggestions.append("活跃项目少:{} 个项目中仅 {} 个最近有提交,建议清理不活跃项目".format(total_projects, recent_projects))
|
|
1242
|
-
|
|
1243
|
-
# ============================================================
|
|
1244
|
-
# 44. 提交频率建议
|
|
1245
|
-
# ============================================================
|
|
1246
|
-
if avg_daily > 0:
|
|
1247
|
-
if avg_daily < 0.5:
|
|
1248
|
-
suggestions.append("提交频率低:日均 {:.1f} 次提交,建议更频繁地提交代码".format(avg_daily))
|
|
1249
|
-
elif avg_daily > 5:
|
|
1250
|
-
suggestions.append("提交频率高:日均 {:.1f} 次提交,注意保持代码质量".format(avg_daily))
|
|
1251
|
-
|
|
1252
|
-
# ============================================================
|
|
1253
|
-
# 45. 开发效率
|
|
1254
|
-
# ============================================================
|
|
1255
|
-
if total_commits > 0 and total_active_days > 0:
|
|
1256
|
-
efficiency = total_commits / total_active_days
|
|
1257
|
-
if efficiency > 5:
|
|
1258
|
-
suggestions.append("开发效率高:每次活跃日平均 {:.0f} 次提交,产出稳定".format(efficiency))
|
|
1259
|
-
elif efficiency < 2:
|
|
1260
|
-
suggestions.append("开发效率待提升:每次活跃日平均 {:.0f} 次提交,建议提高效率".format(efficiency))
|
|
1261
|
-
|
|
1262
|
-
# ============================================================
|
|
1263
|
-
# 46. 功能 vs 维护平衡
|
|
1264
|
-
# ============================================================
|
|
883
|
+
categories['project']['items'].append("项目活跃度不均:{} 个项目中仅 {} 个活跃,建议清理不活跃项目".format(total_projects, active_projects))
|
|
884
|
+
if health['refactor_ratio'] < 10 and health['feat_ratio'] > 50:
|
|
885
|
+
categories['project']['items'].append("关注技术债:功能开发占比高但重构不足,建议定期安排重构时间")
|
|
1265
886
|
if total_commits > 0:
|
|
1266
887
|
feat_c = commit_types.get('feat', 0)
|
|
1267
888
|
fix_c = commit_types.get('fix', 0)
|
|
@@ -1270,174 +891,55 @@ def _build_suggestions_html(habit_score, health, data):
|
|
|
1270
891
|
if feat_c > 0 and maintenance > 0:
|
|
1271
892
|
ratio = feat_c / maintenance
|
|
1272
893
|
if ratio > 5:
|
|
1273
|
-
|
|
1274
|
-
elif ratio < 1:
|
|
1275
|
-
suggestions.append("维护为主:维护提交多于功能,代码在持续改善")
|
|
1276
|
-
|
|
1277
|
-
# ============================================================
|
|
1278
|
-
# 47. 项目状态分布
|
|
1279
|
-
# ============================================================
|
|
1280
|
-
if projects and total_projects > 3:
|
|
1281
|
-
active = sum(1 for p in projects if isinstance(p, dict) and p.get('commits', 0) > 10)
|
|
1282
|
-
inactive = total_projects - active
|
|
1283
|
-
if inactive > total_projects * 0.6:
|
|
1284
|
-
suggestions.append("不活跃项目多:{} 个项目中 {} 个提交不足 10 次,建议归档".format(total_projects, inactive))
|
|
1285
|
-
|
|
1286
|
-
# ============================================================
|
|
1287
|
-
# 48. 提交密度变化
|
|
1288
|
-
# ============================================================
|
|
1289
|
-
if hourly and len(hourly) == 24:
|
|
1290
|
-
total = sum(hourly)
|
|
1291
|
-
if total > 0:
|
|
1292
|
-
# 计算高密度时段(>平均值2倍)
|
|
1293
|
-
avg_per_hour = total / 24
|
|
1294
|
-
high_density_hours = [h for h in range(24) if hourly[h] > avg_per_hour * 2]
|
|
1295
|
-
if len(high_density_hours) <= 2 and len(high_density_hours) > 0:
|
|
1296
|
-
suggestions.append("编码时段集中:高峰仅在 {} 点,建议适当分散".format(', '.join(str(h) for h in high_density_hours)))
|
|
1297
|
-
|
|
1298
|
-
# ============================================================
|
|
1299
|
-
# 49. 周内提交均匀度
|
|
1300
|
-
# ============================================================
|
|
1301
|
-
if weekly and isinstance(weekly, dict) and len(weekly) == 7:
|
|
1302
|
-
values = list(weekly.values())
|
|
1303
|
-
total = sum(values)
|
|
1304
|
-
if total > 0:
|
|
1305
|
-
avg_per_day = total / 7
|
|
1306
|
-
variance = sum((v - avg_per_day) ** 2 for v in values) / 7
|
|
1307
|
-
if avg_per_day > 0:
|
|
1308
|
-
cv = (variance ** 0.5) / avg_per_day
|
|
1309
|
-
if cv > 0.8:
|
|
1310
|
-
suggestions.append("周内提交不均:各天差异大,建议保持更稳定的周节奏")
|
|
1311
|
-
|
|
1312
|
-
# ============================================================
|
|
1313
|
-
# 50. 功能开发占比
|
|
1314
|
-
# ============================================================
|
|
1315
|
-
if total_commits > 0:
|
|
1316
|
-
feat_c = commit_types.get('feat', 0)
|
|
1317
|
-
feat_pct = feat_c / total_commits * 100
|
|
1318
|
-
if feat_pct > 60:
|
|
1319
|
-
suggestions.append("功能开发为主:feat 占 {:.0f}%,建议平衡新功能与质量保障".format(feat_pct))
|
|
1320
|
-
elif feat_pct < 10 and total_commits > 50:
|
|
1321
|
-
suggestions.append("功能开发少:feat 仅占 {:.0f}%,开发以维护为主".format(feat_pct))
|
|
1322
|
-
|
|
1323
|
-
# ============================================================
|
|
1324
|
-
# 51. Chore 类型分析
|
|
1325
|
-
# ============================================================
|
|
1326
|
-
if total_commits > 0:
|
|
1327
|
-
chore_c = commit_types.get('chore', 0)
|
|
1328
|
-
chore_pct = chore_c / total_commits * 100
|
|
1329
|
-
if chore_pct > 20:
|
|
1330
|
-
suggestions.append("琐事较多:chore 占 {:.0f}%,建议用自动化脚本减少重复工作".format(chore_pct))
|
|
894
|
+
categories['project']['items'].append("功能远超维护:功能/维护比 {:.1f}:1,注意技术债积累".format(ratio))
|
|
1331
895
|
|
|
1332
|
-
#
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
if
|
|
1336
|
-
|
|
1337
|
-
suggestions.append("长期开发者:活跃超过 {} 天,积累了丰富的开发经验".format(total_active_days))
|
|
1338
|
-
|
|
1339
|
-
# ============================================================
|
|
1340
|
-
# 53. 最热门项目贡献
|
|
1341
|
-
# ============================================================
|
|
1342
|
-
if projects and total_commits > 0 and len(projects) > 1:
|
|
1343
|
-
max_commits = max(p.get('commits', 0) for p in projects if isinstance(p, dict))
|
|
1344
|
-
top_ratio = max_commits / total_commits * 100
|
|
1345
|
-
if top_ratio > 60:
|
|
1346
|
-
suggestions.append("单项目主导:最热门项目占 {:.0f}% 提交,精力高度集中".format(top_ratio))
|
|
1347
|
-
elif top_ratio < 20:
|
|
1348
|
-
suggestions.append("精力分散:最热门项目仅占 {:.0f}% 提交,建议聚焦核心项目".format(top_ratio))
|
|
896
|
+
# 正面反馈
|
|
897
|
+
if total_projects <= 3 and total_commits > 100:
|
|
898
|
+
categories['project']['items'].append("项目聚焦度高:仅维护 {} 个项目,精力集中".format(total_projects))
|
|
899
|
+
if health['refactor_ratio'] >= 10:
|
|
900
|
+
categories['project']['items'].append("重构做得好:重构占比 {:.0f}%,代码质量持续改善".format(health['refactor_ratio']))
|
|
1349
901
|
|
|
1350
902
|
# ============================================================
|
|
1351
|
-
#
|
|
903
|
+
# AI 协作 (最多 4 条)
|
|
1352
904
|
# ============================================================
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
905
|
+
ai_ratio = ai.get('ai_commit_ratio', 0)
|
|
906
|
+
if ai_ratio > 40:
|
|
907
|
+
categories['ai']['items'].append("善用 AI:AI 占比超过 40%,建议仔细审查 AI 生成的代码")
|
|
908
|
+
elif ai_ratio > 0 and ai_ratio < 15:
|
|
909
|
+
categories['ai']['items'].append("探索 AI 工具:当前 AI 使用率 {:.0f}%,可尝试 Copilot/Cursor 提升效率".format(ai_ratio))
|
|
910
|
+
ai_influence = ai.get('ai_influence_score', 0)
|
|
911
|
+
if ai_influence > 70:
|
|
912
|
+
categories['ai']['items'].append("AI 深度协作:AI 影响分 {},建议定期审查 AI 生成的代码".format(ai_influence))
|
|
913
|
+
ai_tools = ai.get('tools', {})
|
|
914
|
+
if len(ai_tools) >= 3:
|
|
915
|
+
categories['ai']['items'].append("AI 工具多样化:使用了 {} 种 AI 工具,建议固定 1-2 种核心工具".format(len(ai_tools)))
|
|
1362
916
|
|
|
1363
|
-
#
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
if hourly and len(hourly) == 24:
|
|
1367
|
-
total = sum(hourly)
|
|
1368
|
-
if total > 0:
|
|
1369
|
-
morning = sum(hourly[5:9]) # 5-8点
|
|
1370
|
-
night = sum(hourly[22:24]) + sum(hourly[0:2]) # 22-1点
|
|
1371
|
-
if morning > night * 2 and morning > 0:
|
|
1372
|
-
suggestions.append("早起型开发者:早晨提交多于深夜,作息健康")
|
|
1373
|
-
elif night > morning * 2 and night > 0:
|
|
1374
|
-
suggestions.append("夜猫子型开发者:深夜提交多于早晨,建议调整作息")
|
|
917
|
+
# 正面反馈
|
|
918
|
+
if ai_ratio >= 20 and ai_ratio <= 40:
|
|
919
|
+
categories['ai']['items'].append("AI 使用适中:AI 占比 {:.0f}%,人机协作良好".format(ai_ratio))
|
|
1375
920
|
|
|
1376
921
|
# ============================================================
|
|
1377
|
-
#
|
|
922
|
+
# 构建 HTML(带 tab 切换)
|
|
1378
923
|
# ============================================================
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
if commits_per_day >= 2 and commits_per_day <= 6:
|
|
1382
|
-
suggestions.append("提交节奏稳定:活跃日均 {:.1f} 次提交,节奏适中".format(commits_per_day))
|
|
924
|
+
# 过滤空分类
|
|
925
|
+
active_cats = [(k, v) for k, v in categories.items() if v['items']]
|
|
1383
926
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
# ============================================================
|
|
1387
|
-
if projects:
|
|
1388
|
-
lang_project_count = {}
|
|
1389
|
-
for p in projects:
|
|
1390
|
-
if isinstance(p, dict):
|
|
1391
|
-
lang = p.get('language', '')
|
|
1392
|
-
if lang and lang != 'Other':
|
|
1393
|
-
lang_project_count[lang] = lang_project_count.get(lang, 0) + 1
|
|
1394
|
-
if len(lang_project_count) >= 3:
|
|
1395
|
-
top_lang = max(lang_project_count, key=lang_project_count.get)
|
|
1396
|
-
suggestions.append("多语言开发者:使用 {} 种语言,{} 项目最多".format(len(lang_project_count), top_lang))
|
|
927
|
+
if not active_cats:
|
|
928
|
+
return '<div class="sug-item"><div class="sug-text">继续保持良好的开发习惯!各项指标都很健康</div></div>'
|
|
1397
929
|
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
other_pct = other_c / total_commits * 100
|
|
1404
|
-
if other_pct > 30:
|
|
1405
|
-
suggestions.append("提交分类不清:{:.0f}% 归为 other,建议使用标准 commit 类型".format(other_pct))
|
|
1406
|
-
elif other_pct < 10 and total_commits > 50:
|
|
1407
|
-
suggestions.append("提交分类规范:other 仅占 {:.0f}%,类型使用清晰".format(other_pct))
|
|
930
|
+
html = '<div class="sug-tabs">'
|
|
931
|
+
for i, (cat_key, cat) in enumerate(active_cats):
|
|
932
|
+
active_class = ' active' if i == 0 else ''
|
|
933
|
+
html += f'<button class="sug-tab{active_class}" data-cat="{cat_key}">{cat["icon"]} {cat["name"]} ({len(cat["items"])})</button>'
|
|
934
|
+
html += '</div>'
|
|
1408
935
|
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
if feat_c > 0 and fix_c > 0:
|
|
1416
|
-
feat_fix_ratio = feat_c / fix_c
|
|
1417
|
-
if feat_fix_ratio > 4:
|
|
1418
|
-
suggestions.append("功能驱动:功能/修复比 {:.1f}:1,开发节奏快".format(feat_fix_ratio))
|
|
1419
|
-
elif feat_fix_ratio < 1:
|
|
1420
|
-
suggestions.append("修复驱动:修复多于新功能,建议分析根本原因")
|
|
936
|
+
for i, (cat_key, cat) in enumerate(active_cats):
|
|
937
|
+
active_class = ' active' if i == 0 else ''
|
|
938
|
+
html += f'<div class="sug-panel{active_class}" data-cat="{cat_key}">'
|
|
939
|
+
for j, item in enumerate(cat['items'], 1):
|
|
940
|
+
html += f'<div class="sug-item"><div class="sug-num">{j}</div><div class="sug-text">{item}</div></div>'
|
|
941
|
+
html += '</div>'
|
|
1421
942
|
|
|
1422
|
-
# ============================================================
|
|
1423
|
-
# 60. 项目维护活跃度
|
|
1424
|
-
# ============================================================
|
|
1425
|
-
if projects and total_commits > 0:
|
|
1426
|
-
well_maintained = sum(1 for p in projects if isinstance(p, dict) and p.get('commits', 0) > 30)
|
|
1427
|
-
if well_maintained >= 3:
|
|
1428
|
-
suggestions.append("多项目深耕:{} 个项目提交超过 30 次,项目管理能力强".format(well_maintained))
|
|
1429
|
-
|
|
1430
|
-
# === 默认 ===
|
|
1431
|
-
if not suggestions:
|
|
1432
|
-
suggestions.append("继续保持良好的开发习惯!各项指标都很健康")
|
|
1433
|
-
|
|
1434
|
-
html = ""
|
|
1435
|
-
for i, s in enumerate(suggestions, 1):
|
|
1436
|
-
html += f'''
|
|
1437
|
-
<div class="sug-item">
|
|
1438
|
-
<div class="sug-num">{i}</div>
|
|
1439
|
-
<div class="sug-text">{s}</div>
|
|
1440
|
-
</div>'''
|
|
1441
943
|
return html
|
|
1442
944
|
|
|
1443
945
|
|
|
@@ -1993,10 +1495,10 @@ def _build_js(all_commits_json, project_names_json, project_meta_json,
|
|
|
1993
1495
|
// 更新 Habit Score
|
|
1994
1496
|
// ============================================================
|
|
1995
1497
|
function updateHabitScore(agg) {{
|
|
1996
|
-
const granularity = Math.round(Math.min(
|
|
1498
|
+
const granularity = Math.round(Math.min(40, agg.avgPerDay / 4.5 * 40));
|
|
1997
1499
|
const schedule = Math.round(Math.min(20, Math.max(0, (1 - agg.nightRatio / 0.4)) * 20));
|
|
1998
1500
|
const focusScore = Math.round(Math.min(15, agg.focusIndex / 0.7 * 15));
|
|
1999
|
-
const testAwareness = Math.round(Math.min(
|
|
1501
|
+
const testAwareness = Math.round(Math.min(10, agg.testRatio / 0.15 * 10));
|
|
2000
1502
|
const docAwareness = Math.round(Math.min(15, agg.docRatio / 0.10 * 15));
|
|
2001
1503
|
const totalScore = granularity + testAwareness + docAwareness + schedule + focusScore;
|
|
2002
1504
|
agg.habitScore = {{totalScore, granularity, testAwareness, docAwareness, schedule, focusScore}};
|
|
@@ -2007,8 +1509,8 @@ def _build_js(all_commits_json, project_names_json, project_meta_json,
|
|
|
2007
1509
|
document.getElementById('scoreLabel').textContent = `/ 100 · ${{getScoreLabel(totalScore)}}`;
|
|
2008
1510
|
|
|
2009
1511
|
const scoreDims = [
|
|
2010
|
-
['提交粒度', granularity,
|
|
2011
|
-
['测试意识', testAwareness,
|
|
1512
|
+
['提交粒度', granularity, 40],
|
|
1513
|
+
['测试意识', testAwareness, 10],
|
|
2012
1514
|
['文档意识', docAwareness, 15],
|
|
2013
1515
|
['作息规律', schedule, 20],
|
|
2014
1516
|
['项目聚焦', focusScore, 15],
|
|
@@ -2336,7 +1838,15 @@ def _build_js(all_commits_json, project_names_json, project_meta_json,
|
|
|
2336
1838
|
// 更新建议
|
|
2337
1839
|
// ============================================================
|
|
2338
1840
|
function updateSuggestions(agg) {{
|
|
2339
|
-
const
|
|
1841
|
+
const categories = {{
|
|
1842
|
+
'commit': {{name: '提交习惯', icon: '📝', items: []}},
|
|
1843
|
+
'test': {{name: '测试质量', icon: '✅', items: []}},
|
|
1844
|
+
'doc': {{name: '文档维护', icon: '📚', items: []}},
|
|
1845
|
+
'schedule': {{name: '作息健康', icon: '⏰', items: []}},
|
|
1846
|
+
'project': {{name: '项目管理', icon: '🎯', items: []}},
|
|
1847
|
+
'ai': {{name: 'AI 协作', icon: '🤖', items: []}},
|
|
1848
|
+
}};
|
|
1849
|
+
|
|
2340
1850
|
const avgDaily = agg.avgPerDay || 0;
|
|
2341
1851
|
const aiRatio = agg.aiCommitRatio || 0;
|
|
2342
1852
|
const hourly = agg.hourly || [];
|
|
@@ -2344,398 +1854,84 @@ def _build_js(all_commits_json, project_names_json, project_meta_json,
|
|
|
2344
1854
|
const weekdayNames = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
|
2345
1855
|
|
|
2346
1856
|
// ============================================================
|
|
2347
|
-
//
|
|
2348
|
-
// ============================================================
|
|
2349
|
-
if (agg.habitScore.schedule < 10) suggestions.push(`改善作息规律:作息得分仅 ${{agg.habitScore.schedule}}/20,夜间和周末提交较多`);
|
|
2350
|
-
if (agg.habitScore.focus < 10) suggestions.push(`提升专注度:项目聚焦得分仅 ${{agg.habitScore.focus}}/15,建议减少同时维护的项目数`);
|
|
2351
|
-
if (agg.habitScore.granularity < 15) suggestions.push(`优化提交粒度:粒度得分仅 ${{agg.habitScore.granularity}}/30,建议保持稳定的提交频率`);
|
|
2352
|
-
|
|
2353
|
-
// ============================================================
|
|
2354
|
-
// 2. 测试相关
|
|
2355
|
-
// ============================================================
|
|
2356
|
-
if (agg.habitScore.testAwareness < 10) suggestions.push('提高测试意识:尝试为每个新功能编写测试用例,目标覆盖率 10%+');
|
|
2357
|
-
else if (agg.testRatio < 0.08) suggestions.push(`增加测试投入:当前测试文件占比仅 ${{(agg.testRatio*100).toFixed(0)}}%,建议补充单元测试`);
|
|
2358
|
-
if (agg.testRatio >= 0.30) suggestions.push(`测试做得好:测试文件占比 ${{(agg.testRatio*100).toFixed(0)}}%,继续保持!`);
|
|
2359
|
-
|
|
2360
|
-
// ============================================================
|
|
2361
|
-
// 3. 文档相关
|
|
2362
|
-
// ============================================================
|
|
2363
|
-
if (agg.habitScore.docAwareness < 10) suggestions.push('增加文档投入:定期更新 README 和 API 文档');
|
|
2364
|
-
else if (agg.docRatio < 0.05) suggestions.push(`完善文档:文档变更占比 ${{(agg.docRatio*100).toFixed(0)}}%,重要功能应有文档说明`);
|
|
2365
|
-
if (agg.docRatio >= 0.15) suggestions.push(`文档做得好:文档变更占比 ${{(agg.docRatio*100).toFixed(0)}}%,继续保持!`);
|
|
2366
|
-
|
|
2367
|
-
// ============================================================
|
|
2368
|
-
// 4. 作息相关
|
|
2369
|
-
// ============================================================
|
|
2370
|
-
if (agg.nightRatio > 0.25) suggestions.push(`注意作息健康:夜间提交占比 ${{(agg.nightRatio*100).toFixed(0)}}%,建议调整为白天工作`);
|
|
2371
|
-
if (agg.weekendRatio > 0.25) suggestions.push(`平衡工作生活:周末提交占比 ${{(agg.weekendRatio*100).toFixed(0)}}%,注意适当休息`);
|
|
2372
|
-
|
|
2373
|
-
// ============================================================
|
|
2374
|
-
// 5. 深夜提交
|
|
2375
|
-
// ============================================================
|
|
2376
|
-
if (hourly.length === 24) {{
|
|
2377
|
-
const lateNight = hourly.slice(0, 6).reduce((a, b) => a + b, 0);
|
|
2378
|
-
const total = hourly.reduce((a, b) => a + b, 0);
|
|
2379
|
-
if (total > 0 && lateNight / total > 0.15) {{
|
|
2380
|
-
suggestions.push(`减少深夜编码:凌晨 0-6 点提交占比 ${{(lateNight/total*100).toFixed(0)}}%,长期熬夜影响代码质量`);
|
|
2381
|
-
}}
|
|
2382
|
-
}}
|
|
2383
|
-
|
|
2384
|
-
// ============================================================
|
|
2385
|
-
// 6. Commit 质量
|
|
2386
|
-
// ============================================================
|
|
2387
|
-
if (agg.lowInfoRatio > 0.15) suggestions.push(`优化 Commit Message:${{(agg.lowInfoRatio*100).toFixed(0)}}% 的提交缺少描述,建议使用 Conventional Commits 规范`);
|
|
2388
|
-
else if (agg.lowInfoRatio > 0.05) suggestions.push('完善提交描述:部分 commit 信息过于简略,建议写清楚改动原因');
|
|
2389
|
-
if (agg.lowInfoRatio < 0.03) suggestions.push(`Commit 质量高:${{((1-agg.lowInfoRatio)*100).toFixed(0)}}% 的提交有详细描述,继续保持!`);
|
|
2390
|
-
|
|
2391
|
-
// ============================================================
|
|
2392
|
-
// 7. 项目聚焦
|
|
1857
|
+
// 提交习惯 (最多 6 条)
|
|
2393
1858
|
// ============================================================
|
|
2394
|
-
if (agg.
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
if (
|
|
2400
|
-
else if (avgDaily > 8) suggestions.push(`优化提交粒度:日均 ${{avgDaily.toFixed(1)}} 次提交偏多,考虑合并相关改动`);
|
|
2401
|
-
else if (avgDaily >= 2 && avgDaily <= 5) suggestions.push(`提交频率适中:日均 ${{avgDaily.toFixed(1)}} 次提交,节奏良好`);
|
|
2402
|
-
|
|
2403
|
-
// ============================================================
|
|
2404
|
-
// 9. 代码质量
|
|
2405
|
-
// ============================================================
|
|
2406
|
-
if (agg.fixRatio > 0.20) suggestions.push(`提升代码质量:Bug 修复占比 ${{(agg.fixRatio*100).toFixed(0)}}%,建议加强测试和 Code Review`);
|
|
2407
|
-
else if (agg.fixRatio < 0.05 && agg.total > 50) suggestions.push(`Bug 很少:Bug 修复仅占 ${{(agg.fixRatio*100).toFixed(0)}}%,代码质量不错`);
|
|
2408
|
-
if (agg.refactorRatio < 0.10 && agg.featRatio > 0.50) suggestions.push('关注技术债:功能开发占比高但重构不足,建议定期安排重构时间');
|
|
2409
|
-
if (agg.refactorRatio >= 0.10) suggestions.push(`重构做得好:重构占比 ${{(agg.refactorRatio*100).toFixed(0)}}%,代码质量持续改善`);
|
|
2410
|
-
|
|
2411
|
-
// ============================================================
|
|
2412
|
-
// 10. AI 使用
|
|
2413
|
-
// ============================================================
|
|
2414
|
-
if (aiRatio > 0.40) suggestions.push('善用 AI:AI 占比超过 40%,建议仔细审查 AI 生成的代码');
|
|
2415
|
-
else if (aiRatio > 0 && aiRatio < 0.15) suggestions.push(`探索 AI 工具:当前 AI 使用率 ${{(aiRatio*100).toFixed(0)}}%,可尝试 Copilot/Cursor 提升效率`);
|
|
2416
|
-
if (aiRatio >= 0.20 && aiRatio <= 0.40) suggestions.push(`AI 使用适中:AI 占比 ${{(aiRatio*100).toFixed(0)}}%,人机协作良好`);
|
|
2417
|
-
|
|
2418
|
-
// ============================================================
|
|
2419
|
-
// 11. 最活跃星期
|
|
2420
|
-
// ============================================================
|
|
2421
|
-
const peakWeekdays = agg.weekly.map((v, i) => ({{v, i}})).sort((a, b) => b.v - a.v).slice(0, 3).map(x => weekdayNames[x.i]);
|
|
2422
|
-
const weekendDays = peakWeekdays.filter(d => d === '周六' || d === '周日');
|
|
2423
|
-
if (weekendDays.length >= 2) suggestions.push(`调整工作节奏:最活跃的 3 天中有 ${{weekendDays.length}} 天是周末,建议以工作日为主`);
|
|
2424
|
-
|
|
2425
|
-
// ============================================================
|
|
2426
|
-
// 12. 工作强度
|
|
2427
|
-
// ============================================================
|
|
2428
|
-
if (avgDaily > 5) suggestions.push(`注意工作强度:日均 ${{avgDaily.toFixed(1)}} 次提交,注意劳逸结合避免倦怠`);
|
|
2429
|
-
|
|
2430
|
-
// ============================================================
|
|
2431
|
-
// 13. 项目数量
|
|
2432
|
-
// ============================================================
|
|
2433
|
-
if (totalProjects > 15) suggestions.push(`精简项目数量:同时维护 ${{totalProjects}} 个项目,建议聚焦核心项目提升效率`);
|
|
2434
|
-
else if (totalProjects <= 3 && agg.total > 100) suggestions.push(`项目聚焦度高:仅维护 ${{totalProjects}} 个项目,精力集中`);
|
|
2435
|
-
|
|
2436
|
-
// ============================================================
|
|
2437
|
-
// 14. 活跃度
|
|
2438
|
-
// ============================================================
|
|
2439
|
-
if (agg.activeDays > 0 && avgDaily > 0) {{
|
|
2440
|
-
const activeRate = Math.min(agg.activeDays / 365 * 100, 100);
|
|
2441
|
-
if (activeRate < 30) suggestions.push(`保持持续性:活跃天数 ${{agg.activeDays}} 天,建议养成每天提交的习惯`);
|
|
2442
|
-
else if (activeRate > 70) suggestions.push(`活跃度高:${{agg.activeDays}} 天有提交, coding 习惯良好`);
|
|
2443
|
-
}}
|
|
2444
|
-
|
|
2445
|
-
// ============================================================
|
|
2446
|
-
// 15. Commit 类型分布
|
|
2447
|
-
// ============================================================
|
|
2448
|
-
if (agg.total > 50) {{
|
|
2449
|
-
const testRatio = (agg.types.test || 0) / agg.total;
|
|
2450
|
-
const docsRatio = (agg.types.docs || 0) / agg.total;
|
|
2451
|
-
const refactorRatio = (agg.types.refactor || 0) / agg.total;
|
|
1859
|
+
if (agg.habitScore.granularity < 15) categories.commit.items.push(`优化提交粒度:粒度得分仅 ${{agg.habitScore.granularity}}/40,建议保持稳定的提交频率`);
|
|
1860
|
+
if (avgDaily < 1) categories.commit.items.push(`提高提交频率:日均仅 ${{avgDaily.toFixed(1)}} 次提交,建议小步快跑、勤提交`);
|
|
1861
|
+
else if (avgDaily > 8) categories.commit.items.push(`优化提交粒度:日均 ${{avgDaily.toFixed(1)}} 次提交偏多,考虑合并相关改动`);
|
|
1862
|
+
if (agg.lowInfoRatio > 0.15) categories.commit.items.push(`优化 Commit Message:${{(agg.lowInfoRatio*100).toFixed(0)}}% 的提交缺少描述,建议使用 Conventional Commits 规范`);
|
|
1863
|
+
else if (agg.lowInfoRatio > 0.05) categories.commit.items.push('完善提交描述:部分 commit 信息过于简略,建议写清楚改动原因');
|
|
1864
|
+
if (agg.total > 0) {{
|
|
2452
1865
|
const otherRatio = (agg.types.other || 0) / agg.total;
|
|
2453
|
-
|
|
2454
|
-
const featRatio = (agg.types.feat || 0) / agg.total;
|
|
2455
|
-
const fixRatio = (agg.types.fix || 0) / agg.total;
|
|
2456
|
-
|
|
2457
|
-
if (testRatio < 0.05) suggestions.push(`增加测试提交:测试相关提交仅占 ${{(testRatio*100).toFixed(0)}}%,建议为新功能编写测试`);
|
|
2458
|
-
else if (testRatio >= 0.15) suggestions.push(`测试提交充足:测试占比 ${{(testRatio*100).toFixed(0)}}%,质量意识强`);
|
|
2459
|
-
if (docsRatio < 0.05) suggestions.push(`增加文档提交:文档相关提交仅占 ${{(docsRatio*100).toFixed(0)}}%,建议及时更新文档`);
|
|
2460
|
-
else if (docsRatio >= 0.15) suggestions.push(`文档提交充足:文档占比 ${{(docsRatio*100).toFixed(0)}}%,文档维护良好`);
|
|
2461
|
-
if (refactorRatio < 0.03 && agg.featRatio > 0.30) suggestions.push(`定期重构:重构提交仅占 ${{(refactorRatio*100).toFixed(0)}}%,功能开发占比高,建议安排重构时间`);
|
|
2462
|
-
if (otherRatio > 0.25) suggestions.push(`规范 Commit 类型:${{(otherRatio*100).toFixed(0)}}% 的提交被归为 other,建议使用 feat/fix/refactor 等标准类型`);
|
|
2463
|
-
if (choreRatio > 0.15) suggestions.push(`自动化琐事:chore 类型提交占比 ${{(choreRatio*100).toFixed(0)}}%,考虑用脚本或 CI 自动化`);
|
|
2464
|
-
if (featRatio > 0.40) suggestions.push(`功能开发为主:feat 占比 ${{(featRatio*100).toFixed(0)}}%,注意平衡新功能与维护`);
|
|
2465
|
-
if (fixRatio > 0.20) suggestions.push(`Bug 修复较多:fix 占比 ${{(fixRatio*100).toFixed(0)}}%,建议加强测试预防`);
|
|
2466
|
-
}}
|
|
2467
|
-
|
|
2468
|
-
// ============================================================
|
|
2469
|
-
// 16. 语言多样性
|
|
2470
|
-
// ============================================================
|
|
2471
|
-
const langSet = new Set(Object.values(agg.languageCounts).map((_, i) => Object.keys(agg.languageCounts)[i]).filter(l => l && l !== 'Other'));
|
|
2472
|
-
if (langSet.size === 1) suggestions.push(`拓展技术栈:当前只使用 ${{[...langSet][0]}} 语言,建议学习其他语言拓宽视野`);
|
|
2473
|
-
else if (langSet.size >= 5) suggestions.push(`聚焦核心技术:同时使用 ${{langSet.size}} 种语言,建议深耕 1-2 种核心语言`);
|
|
2474
|
-
|
|
2475
|
-
// ============================================================
|
|
2476
|
-
// 17. 提交频率波动
|
|
2477
|
-
// ============================================================
|
|
2478
|
-
if (hourly.length === 24) {{
|
|
2479
|
-
const maxHour = Math.max(...hourly);
|
|
2480
|
-
const minHour = Math.min(...hourly);
|
|
2481
|
-
if (maxHour > 0 && minHour / maxHour < 0.1) suggestions.push('平衡提交时间:提交集中在特定时段,建议分散到全天各时段');
|
|
1866
|
+
if (otherRatio > 0.25) categories.commit.items.push(`提交分类不清:${{(otherRatio*100).toFixed(0)}}% 归为 other,建议使用 feat/fix/refactor 等标准类型`);
|
|
2482
1867
|
}}
|
|
2483
|
-
|
|
2484
|
-
// ============================================================
|
|
2485
|
-
// 18. 提交连续性
|
|
2486
|
-
// ============================================================
|
|
2487
1868
|
if (agg.activeDays > 0 && agg.total > 0) {{
|
|
2488
1869
|
const commitsPerActiveDay = agg.total / agg.activeDays;
|
|
2489
|
-
if (commitsPerActiveDay > 10)
|
|
2490
|
-
}}
|
|
2491
|
-
|
|
2492
|
-
// ============================================================
|
|
2493
|
-
// 19. 提交间隔
|
|
2494
|
-
// ============================================================
|
|
2495
|
-
if (agg.activeDays > 0 && agg.total > 0) {{
|
|
2496
|
-
const avgInterval = 24 * agg.activeDays / agg.total;
|
|
2497
|
-
if (avgInterval < 1) suggestions.push(`降低提交频率:平均 ${{(avgInterval * 60).toFixed(0)}} 分钟一次提交,考虑合并相关改动`);
|
|
1870
|
+
if (commitsPerActiveDay > 10) categories.commit.items.push(`控制单日提交量:活跃日均提交 ${{commitsPerActiveDay.toFixed(0)}} 次,建议拆分为更小的改动`);
|
|
2498
1871
|
}}
|
|
2499
1872
|
|
|
2500
|
-
//
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
if (hourly.length === 24) {{
|
|
2504
|
-
const total = hourly.reduce((a, b) => a + b, 0);
|
|
2505
|
-
if (total > 0) {{
|
|
2506
|
-
const workHours = hourly.slice(9, 18).reduce((a, b) => a + b, 0);
|
|
2507
|
-
const workRatio = workHours / total;
|
|
2508
|
-
if (workRatio > 0.6) suggestions.push(`工作节奏规律:${{(workRatio*100).toFixed(0)}}% 的提交在工作时间,作息健康`);
|
|
2509
|
-
else if (workRatio < 0.3) suggestions.push(`工作时间不规律:仅 ${{(workRatio*100).toFixed(0)}}% 的提交在工作时间,建议调整`);
|
|
2510
|
-
}}
|
|
2511
|
-
}}
|
|
1873
|
+
// 正面反馈
|
|
1874
|
+
if (agg.lowInfoRatio < 0.03) categories.commit.items.push(`Commit 质量高:${{((1-agg.lowInfoRatio)*100).toFixed(0)}}% 的提交有详细描述,继续保持!`);
|
|
1875
|
+
if (avgDaily >= 2 && avgDaily <= 5) categories.commit.items.push(`提交频率适中:日均 ${{avgDaily.toFixed(1)}} 次提交,节奏良好`);
|
|
2512
1876
|
|
|
2513
1877
|
// ============================================================
|
|
2514
|
-
//
|
|
1878
|
+
// 测试质量 (最多 5 条)
|
|
2515
1879
|
// ============================================================
|
|
2516
|
-
if (
|
|
2517
|
-
|
|
2518
|
-
|
|
1880
|
+
if (agg.habitScore.testAwareness < 10) categories.test.items.push('提高测试意识:尝试为每个新功能编写测试用例,目标覆盖率 10%+');
|
|
1881
|
+
else if (agg.testRatio < 0.08) categories.test.items.push(`增加测试投入:当前测试文件占比仅 ${{(agg.testRatio*100).toFixed(0)}}%,建议补充单元测试`);
|
|
1882
|
+
if (agg.total > 50) {{
|
|
1883
|
+
const testRatio = (agg.types.test || 0) / agg.total;
|
|
1884
|
+
if (testRatio < 0.05) categories.test.items.push(`增加测试提交:测试相关提交仅占 ${{(testRatio*100).toFixed(0)}}%,建议为新功能编写测试`);
|
|
2519
1885
|
}}
|
|
1886
|
+
if (agg.fixRatio > 0.20) categories.test.items.push(`提升代码质量:Bug 修复占比 ${{(agg.fixRatio*100).toFixed(0)}}%,建议加强测试和 Code Review`);
|
|
2520
1887
|
|
|
2521
|
-
//
|
|
2522
|
-
|
|
2523
|
-
// ============================================================
|
|
2524
|
-
if (agg.testRatio >= 0.20) suggestions.push(`测试覆盖良好:测试文件占比 ${{(agg.testRatio*100).toFixed(0)}}%,代码质量有保障`);
|
|
2525
|
-
|
|
2526
|
-
// ============================================================
|
|
2527
|
-
// 23. 文档覆盖趋势
|
|
2528
|
-
// ============================================================
|
|
2529
|
-
if (agg.docRatio >= 0.10) suggestions.push(`文档覆盖良好:文档变更占比 ${{(agg.docRatio*100).toFixed(0)}}%,项目可维护性强`);
|
|
1888
|
+
// 正面反馈
|
|
1889
|
+
if (agg.testRatio >= 0.30) categories.test.items.push(`测试做得好:测试文件占比 ${{(agg.testRatio*100).toFixed(0)}}%,继续保持!`);
|
|
2530
1890
|
|
|
2531
1891
|
// ============================================================
|
|
2532
|
-
//
|
|
2533
|
-
// ============================================================
|
|
2534
|
-
if (agg.nightRatio < 0.15 && agg.weekendRatio < 0.15) suggestions.push('工作生活平衡:夜间和周末提交都很少,作息健康');
|
|
2535
|
-
|
|
1892
|
+
// 文档维护 (最多 5 条)
|
|
2536
1893
|
// ============================================================
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
if (agg.
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
// 26. AI 工具多样性
|
|
2543
|
-
// ============================================================
|
|
2544
|
-
// 注:JS 端暂无 ai.tools 数据,跳过
|
|
2545
|
-
|
|
2546
|
-
// ============================================================
|
|
2547
|
-
// 27. AI 协作深度
|
|
2548
|
-
// ============================================================
|
|
2549
|
-
// 注:JS 端暂无 ai.ai_influence_score 数据,跳过
|
|
2550
|
-
|
|
2551
|
-
// ============================================================
|
|
2552
|
-
// 28. 提交消息长度
|
|
2553
|
-
// ============================================================
|
|
2554
|
-
if (agg.lowInfoRatio < 0.05 && agg.total > 100) suggestions.push(`提交消息质量高:${{((1-agg.lowInfoRatio)*100).toFixed(0)}}% 的提交有详细描述,代码可维护性强`);
|
|
2555
|
-
|
|
2556
|
-
// ============================================================
|
|
2557
|
-
// 29. 代码变更规模
|
|
2558
|
-
// ============================================================
|
|
2559
|
-
if (agg.total > 0 && agg.activeDays > 0) {{
|
|
2560
|
-
const avgChangesPerCommit = agg.total / agg.activeDays;
|
|
2561
|
-
if (avgChangesPerCommit > 5) suggestions.push('单次提交较大:建议拆分为更小的提交,便于 Code Review');
|
|
1894
|
+
if (agg.habitScore.docAwareness < 10) categories.doc.items.push('增加文档投入:定期更新 README 和 API 文档');
|
|
1895
|
+
else if (agg.docRatio < 0.05) categories.doc.items.push(`完善文档:文档变更占比 ${{(agg.docRatio*100).toFixed(0)}}%,重要功能应有文档说明`);
|
|
1896
|
+
if (agg.total > 50) {{
|
|
1897
|
+
const docsRatio = (agg.types.docs || 0) / agg.total;
|
|
1898
|
+
if (docsRatio < 0.05) categories.doc.items.push(`增加文档提交:文档相关提交仅占 ${{(docsRatio*100).toFixed(0)}}%,建议及时更新文档`);
|
|
2562
1899
|
}}
|
|
2563
1900
|
|
|
2564
|
-
//
|
|
2565
|
-
|
|
2566
|
-
// ============================================================
|
|
2567
|
-
if (agg.refactorRatio < 0.05 && agg.featRatio > 0.40 && agg.total > 100) suggestions.push(`技术债积累:重构仅占 ${{(agg.refactorRatio*100).toFixed(0)}}%,建议定期安排重构时间`);
|
|
1901
|
+
// 正面反馈
|
|
1902
|
+
if (agg.docRatio >= 0.15) categories.doc.items.push(`文档做得好:文档变更占比 ${{(agg.docRatio*100).toFixed(0)}}%,继续保持!`);
|
|
2568
1903
|
|
|
2569
1904
|
// ============================================================
|
|
2570
|
-
//
|
|
2571
|
-
// ============================================================
|
|
2572
|
-
if (hourly.length === 24) {{
|
|
2573
|
-
const mean = hourly.reduce((a, b) => a + b, 0) / 24;
|
|
2574
|
-
if (mean > 0) {{
|
|
2575
|
-
const variance = hourly.reduce((a, b) => a + (b - mean) ** 2, 0) / 24;
|
|
2576
|
-
const cv = Math.sqrt(variance) / mean;
|
|
2577
|
-
if (cv > 1.5) suggestions.push('提交时间波动大:建议保持更稳定的工作节奏');
|
|
2578
|
-
}}
|
|
2579
|
-
}}
|
|
2580
|
-
|
|
2581
|
-
// ============================================================
|
|
2582
|
-
// 32. 项目集中度
|
|
2583
|
-
// ============================================================
|
|
2584
|
-
if (totalProjects > 0 && agg.total > 0) {{
|
|
2585
|
-
const shares = Object.values(agg.projectCounts).map(c => c / agg.total);
|
|
2586
|
-
const hhi = shares.reduce((a, b) => a + b * b, 0);
|
|
2587
|
-
if (hhi < 0.1) suggestions.push('项目分散:提交分布均匀,建议聚焦核心项目');
|
|
2588
|
-
else if (hhi > 0.5) suggestions.push('项目集中:大部分提交集中在少数项目,精力分配合理');
|
|
2589
|
-
}}
|
|
2590
|
-
|
|
2591
|
-
// ============================================================
|
|
2592
|
-
// 33. 周末提交模式
|
|
2593
|
-
// ============================================================
|
|
2594
|
-
if (agg.weekly.length === 7) {{
|
|
2595
|
-
const sat = agg.weekly[5] || 0;
|
|
2596
|
-
const sun = agg.weekly[6] || 0;
|
|
2597
|
-
const totalWeekly = agg.weekly.reduce((a, b) => a + b, 0);
|
|
2598
|
-
if (totalWeekly > 0) {{
|
|
2599
|
-
const satRatio = sat / totalWeekly * 100;
|
|
2600
|
-
const sunRatio = sun / totalWeekly * 100;
|
|
2601
|
-
if (satRatio > 20 && sunRatio < 5) suggestions.push(`周六活跃:周六提交占比 ${{satRatio.toFixed(0)}}%,周日较少,节奏不错`);
|
|
2602
|
-
else if (sunRatio > 20 && satRatio < 5) suggestions.push(`周日活跃:周日提交占比 ${{sunRatio.toFixed(0)}}%,建议利用周六提前完成`);
|
|
2603
|
-
}}
|
|
2604
|
-
}}
|
|
2605
|
-
|
|
2606
|
-
// ============================================================
|
|
2607
|
-
// 34. 提交分布集中度
|
|
1905
|
+
// 作息健康 (最多 5 条)
|
|
2608
1906
|
// ============================================================
|
|
1907
|
+
if (agg.habitScore.schedule < 10) categories.schedule.items.push(`改善作息规律:作息得分仅 ${{agg.habitScore.schedule}}/20,夜间和周末提交较多`);
|
|
1908
|
+
if (agg.nightRatio > 0.25) categories.schedule.items.push(`注意作息健康:夜间提交占比 ${{(agg.nightRatio*100).toFixed(0)}}%,建议调整为白天工作`);
|
|
1909
|
+
if (agg.weekendRatio > 0.25) categories.schedule.items.push(`平衡工作生活:周末提交占比 ${{(agg.weekendRatio*100).toFixed(0)}}%,注意适当休息`);
|
|
2609
1910
|
if (hourly.length === 24) {{
|
|
1911
|
+
const lateNight = hourly.slice(0, 6).reduce((a, b) => a + b, 0);
|
|
2610
1912
|
const total = hourly.reduce((a, b) => a + b, 0);
|
|
2611
|
-
if (total > 0) {{
|
|
2612
|
-
const sorted = hourly.map((v, i) => ({{v, i}})).sort((a, b) => b.v - a.v).slice(0, 3);
|
|
2613
|
-
const top3Ratio = sorted.reduce((a, x) => a + x.v, 0) / total * 100;
|
|
2614
|
-
if (top3Ratio > 50) suggestions.push(`提交高度集中:最活跃的 3 小时占 ${{top3Ratio.toFixed(0)}}% 提交,建议更均匀分布`);
|
|
2615
|
-
else if (top3Ratio < 25) suggestions.push('提交分布均匀:各时段提交较分散,时间管理良好');
|
|
2616
|
-
}}
|
|
2617
|
-
}}
|
|
2618
|
-
|
|
2619
|
-
// ============================================================
|
|
2620
|
-
// 35. 测试与功能平衡
|
|
2621
|
-
// ============================================================
|
|
2622
|
-
if (agg.total > 0) {{
|
|
2623
|
-
const featCount = agg.types.feat || 0;
|
|
2624
|
-
const testCount = agg.types.test || 0;
|
|
2625
|
-
if (featCount > 0) {{
|
|
2626
|
-
const testFeatRatio = testCount / featCount;
|
|
2627
|
-
if (testFeatRatio < 0.3 && featCount > 20) suggestions.push(`测试跟不上功能:每 ${{Math.round(1/testFeatRatio)}} 个功能提交才对应 1 个测试提交,建议提高测试比例`);
|
|
2628
|
-
else if (testFeatRatio >= 0.8) suggestions.push(`测试与功能同步:测试/功能比 ${{testFeatRatio.toFixed(1)}},质量意识强`);
|
|
2629
|
-
}}
|
|
2630
|
-
}}
|
|
2631
|
-
|
|
2632
|
-
// ============================================================
|
|
2633
|
-
// 36. 提交历史跨度
|
|
2634
|
-
// ============================================================
|
|
2635
|
-
if (agg.activeDays > 0) {{
|
|
2636
|
-
if (agg.activeDays > 300) suggestions.push(`开发持续性强:活跃 ${{agg.activeDays}} 天,长期坚持 coding`);
|
|
2637
|
-
else if (agg.activeDays < 30 && agg.total > 50) suggestions.push(`开发集中在短期:仅 ${{agg.activeDays}} 天活跃但有 ${{agg.total}} 次提交,建议保持持续性`);
|
|
1913
|
+
if (total > 0 && lateNight / total > 0.15) categories.schedule.items.push(`减少深夜编码:凌晨 0-6 点提交占比 ${{(lateNight/total*100).toFixed(0)}}%,长期熬夜影响代码质量`);
|
|
2638
1914
|
}}
|
|
2639
|
-
|
|
2640
|
-
// ============================================================
|
|
2641
|
-
// 37. 工作日偏好
|
|
2642
|
-
// ============================================================
|
|
2643
1915
|
if (agg.weekly.length === 7) {{
|
|
2644
|
-
const
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
const dayRatio = agg.weekly[maxIdx] / totalWeekly * 100;
|
|
2648
|
-
if (dayRatio > 25) suggestions.push(`工作日偏好明显:${{weekdayNames[maxIdx]}} 占 ${{dayRatio.toFixed(0)}}% 提交,是最活跃的一天`);
|
|
2649
|
-
}}
|
|
2650
|
-
}}
|
|
2651
|
-
|
|
2652
|
-
// ============================================================
|
|
2653
|
-
// 38. 提交时间分布
|
|
2654
|
-
// ============================================================
|
|
2655
|
-
if (hourly.length === 24) {{
|
|
2656
|
-
const maxVal = Math.max(...hourly);
|
|
2657
|
-
const peakHoursList = hourly.map((v, i) => ({{v, i}})).filter(x => x.v > maxVal * 0.8).map(x => x.i);
|
|
2658
|
-
if (peakHoursList.length <= 3) suggestions.push(`提交时间集中:高峰时段集中在 ${{peakHoursList.join(', ')}} 点,建议分散到其他时段`);
|
|
2659
|
-
}}
|
|
2660
|
-
|
|
2661
|
-
// ============================================================
|
|
2662
|
-
// 39. 项目提交分布
|
|
2663
|
-
// ============================================================
|
|
2664
|
-
if (totalProjects > 0 && agg.total > 0) {{
|
|
2665
|
-
const shares = Object.values(agg.projectCounts).map(c => c / agg.total).filter(s => s > 0);
|
|
2666
|
-
const entropy = -shares.reduce((a, b) => a + b * Math.log2(b), 0);
|
|
2667
|
-
const maxEntropy = Math.log2(shares.length);
|
|
2668
|
-
if (maxEntropy > 0) {{
|
|
2669
|
-
const normalizedEntropy = entropy / maxEntropy;
|
|
2670
|
-
if (normalizedEntropy > 0.8) suggestions.push('项目分布均匀:提交分散在多个项目,建议聚焦核心项目');
|
|
2671
|
-
else if (normalizedEntropy < 0.3) suggestions.push('项目分布集中:大部分提交集中在少数项目,精力分配合理');
|
|
2672
|
-
}}
|
|
1916
|
+
const peakWeekdays = agg.weekly.map((v, i) => ({{v, i}})).sort((a, b) => b.v - a.v).slice(0, 3).map(x => weekdayNames[x.i]);
|
|
1917
|
+
const weekendDays = peakWeekdays.filter(d => d === '周六' || d === '周日');
|
|
1918
|
+
if (weekendDays.length >= 2) categories.schedule.items.push(`调整工作节奏:最活跃的 3 天中有 ${{weekendDays.length}} 天是周末,建议以工作日为主`);
|
|
2673
1919
|
}}
|
|
2674
1920
|
|
|
2675
|
-
//
|
|
2676
|
-
|
|
2677
|
-
// ============================================================
|
|
2678
|
-
if (agg.habitScore.total >= 80) suggestions.push(`开发习惯优秀:总分 ${{agg.habitScore.total}} 分,继续保持!`);
|
|
2679
|
-
else if (agg.habitScore.total >= 60) suggestions.push(`开发习惯良好:总分 ${{agg.habitScore.total}} 分,还有提升空间`);
|
|
1921
|
+
// 正面反馈
|
|
1922
|
+
if (agg.nightRatio < 0.15 && agg.weekendRatio < 0.15) categories.schedule.items.push('工作生活平衡:夜间和周末提交都很少,作息健康');
|
|
2680
1923
|
|
|
2681
1924
|
// ============================================================
|
|
2682
|
-
//
|
|
1925
|
+
// 项目管理 (最多 6 条)
|
|
2683
1926
|
// ============================================================
|
|
2684
|
-
if (
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
for (let i = 0; i < n; i++) {{
|
|
2691
|
-
cumulative += commitsList[i];
|
|
2692
|
-
giniSum += (2 * (i + 1) - n - 1) * commitsList[i];
|
|
2693
|
-
}}
|
|
2694
|
-
const gini = giniSum / (n * agg.total);
|
|
2695
|
-
if (gini > 0.6) suggestions.push(`项目分布不均:基尼系数 ${{gini.toFixed(2)}},建议更均匀地分配精力`);
|
|
2696
|
-
else if (gini < 0.2) suggestions.push(`项目分布均匀:基尼系数 ${{gini.toFixed(2)}},精力分配合理`);
|
|
2697
|
-
}}
|
|
2698
|
-
}}
|
|
2699
|
-
|
|
2700
|
-
// ============================================================
|
|
2701
|
-
// 42. 提交频率稳定性
|
|
2702
|
-
// ============================================================
|
|
2703
|
-
if (hourly.length === 24) {{
|
|
2704
|
-
const mean = hourly.reduce((a, b) => a + b, 0) / 24;
|
|
2705
|
-
if (mean > 0) {{
|
|
2706
|
-
const variance = hourly.reduce((a, b) => a + (b - mean) ** 2, 0) / 24;
|
|
2707
|
-
if (variance > 0) {{
|
|
2708
|
-
const skewness = hourly.reduce((a, b) => a + (b - mean) ** 3, 0) / (24 * (variance ** 1.5));
|
|
2709
|
-
if (Math.abs(skewness) > 1) suggestions.push('提交时间分布偏斜:建议保持更规律的工作节奏');
|
|
2710
|
-
}}
|
|
2711
|
-
}}
|
|
2712
|
-
}}
|
|
2713
|
-
|
|
2714
|
-
// ============================================================
|
|
2715
|
-
// 43. 项目活跃周期
|
|
2716
|
-
// ============================================================
|
|
2717
|
-
// 注:JS 端暂无 projects 数据,跳过
|
|
2718
|
-
|
|
2719
|
-
// ============================================================
|
|
2720
|
-
// 44. 提交频率建议
|
|
2721
|
-
// ============================================================
|
|
2722
|
-
if (avgDaily > 0) {{
|
|
2723
|
-
if (avgDaily < 0.5) suggestions.push(`提交频率低:日均 ${{avgDaily.toFixed(1)}} 次提交,建议更频繁地提交代码`);
|
|
2724
|
-
else if (avgDaily > 5) suggestions.push(`提交频率高:日均 ${{avgDaily.toFixed(1)}} 次提交,注意保持代码质量`);
|
|
2725
|
-
}}
|
|
2726
|
-
|
|
2727
|
-
// ============================================================
|
|
2728
|
-
// 45. 开发效率
|
|
2729
|
-
// ============================================================
|
|
2730
|
-
if (agg.total > 0 && agg.activeDays > 0) {{
|
|
2731
|
-
const efficiency = agg.total / agg.activeDays;
|
|
2732
|
-
if (efficiency > 5) suggestions.push(`开发效率高:每次活跃日平均 ${{efficiency.toFixed(0)}} 次提交,产出稳定`);
|
|
2733
|
-
else if (efficiency < 2) suggestions.push(`开发效率待提升:每次活跃日平均 ${{efficiency.toFixed(0)}} 次提交,建议提高效率`);
|
|
1927
|
+
if (agg.habitScore.focus < 10) categories.project.items.push(`提升专注度:项目聚焦得分仅 ${{agg.habitScore.focus}}/15,建议减少同时维护的项目数`);
|
|
1928
|
+
if (agg.focusIndex < 0.60) categories.project.items.push('提高项目聚焦度:精力较分散,建议集中精力在 1-2 个核心项目上');
|
|
1929
|
+
if (totalProjects > 15) categories.project.items.push(`精简项目数量:同时维护 ${{totalProjects}} 个项目,建议聚焦核心项目提升效率`);
|
|
1930
|
+
if (totalProjects > 5 && agg.total > 0) {{
|
|
1931
|
+
const activeProjects = Object.values(agg.projectCounts).filter(c => c > 10).length;
|
|
1932
|
+
if (activeProjects <= 2) categories.project.items.push(`项目活跃度不均:${{totalProjects}} 个项目中仅 ${{activeProjects}} 个活跃,建议清理不活跃项目`);
|
|
2734
1933
|
}}
|
|
2735
|
-
|
|
2736
|
-
// ============================================================
|
|
2737
|
-
// 46. 功能 vs 维护平衡
|
|
2738
|
-
// ============================================================
|
|
1934
|
+
if (agg.refactorRatio < 0.10 && agg.featRatio > 0.50) categories.project.items.push('关注技术债:功能开发占比高但重构不足,建议定期安排重构时间');
|
|
2739
1935
|
if (agg.total > 0) {{
|
|
2740
1936
|
const featC = agg.types.feat || 0;
|
|
2741
1937
|
const fixC = agg.types.fix || 0;
|
|
@@ -2743,163 +1939,63 @@ def _build_js(all_commits_json, project_names_json, project_meta_json,
|
|
|
2743
1939
|
const maintenance = fixC + refactorC;
|
|
2744
1940
|
if (featC > 0 && maintenance > 0) {{
|
|
2745
1941
|
const ratio = featC / maintenance;
|
|
2746
|
-
if (ratio > 5)
|
|
2747
|
-
else if (ratio < 1) suggestions.push('维护为主:维护提交多于功能,代码在持续改善');
|
|
1942
|
+
if (ratio > 5) categories.project.items.push(`功能远超维护:功能/维护比 ${{ratio.toFixed(1)}}:1,注意技术债积累`);
|
|
2748
1943
|
}}
|
|
2749
1944
|
}}
|
|
2750
1945
|
|
|
2751
|
-
//
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
if (totalProjects > 3 && agg.total > 0) {{
|
|
2755
|
-
const active = Object.values(agg.projectCounts).filter(c => c > 10).length;
|
|
2756
|
-
const inactive = totalProjects - active;
|
|
2757
|
-
if (inactive > totalProjects * 0.6) suggestions.push(`不活跃项目多:${{totalProjects}} 个项目中 ${{inactive}} 个提交不足 10 次,建议归档`);
|
|
2758
|
-
}}
|
|
1946
|
+
// 正面反馈
|
|
1947
|
+
if (totalProjects <= 3 && agg.total > 100) categories.project.items.push(`项目聚焦度高:仅维护 ${{totalProjects}} 个项目,精力集中`);
|
|
1948
|
+
if (agg.refactorRatio >= 0.10) categories.project.items.push(`重构做得好:重构占比 ${{(agg.refactorRatio*100).toFixed(0)}}%,代码质量持续改善`);
|
|
2759
1949
|
|
|
2760
1950
|
// ============================================================
|
|
2761
|
-
//
|
|
1951
|
+
// AI 协作 (最多 4 条)
|
|
2762
1952
|
// ============================================================
|
|
2763
|
-
if (
|
|
2764
|
-
|
|
2765
|
-
if (total > 0) {{
|
|
2766
|
-
const avgPerHour = total / 24;
|
|
2767
|
-
const highDensityHours = hourly.map((v, i) => ({{v, i}})).filter(x => x.v > avgPerHour * 2).map(x => x.i);
|
|
2768
|
-
if (highDensityHours.length <= 2 && highDensityHours.length > 0) suggestions.push(`编码时段集中:高峰仅在 ${{highDensityHours.join(', ')}} 点,建议适当分散`);
|
|
2769
|
-
}}
|
|
2770
|
-
}}
|
|
1953
|
+
if (aiRatio > 0.40) categories.ai.items.push('善用 AI:AI 占比超过 40%,建议仔细审查 AI 生成的代码');
|
|
1954
|
+
else if (aiRatio > 0 && aiRatio < 0.15) categories.ai.items.push(`探索 AI 工具:当前 AI 使用率 ${{(aiRatio*100).toFixed(0)}}%,可尝试 Copilot/Cursor 提升效率`);
|
|
2771
1955
|
|
|
2772
|
-
//
|
|
2773
|
-
|
|
2774
|
-
// ============================================================
|
|
2775
|
-
if (agg.weekly.length === 7) {{
|
|
2776
|
-
const totalWeekly = agg.weekly.reduce((a, b) => a + b, 0);
|
|
2777
|
-
if (totalWeekly > 0) {{
|
|
2778
|
-
const avgPerDay = totalWeekly / 7;
|
|
2779
|
-
const variance = agg.weekly.reduce((a, v) => a + (v - avgPerDay) ** 2, 0) / 7;
|
|
2780
|
-
if (avgPerDay > 0) {{
|
|
2781
|
-
const cv = Math.sqrt(variance) / avgPerDay;
|
|
2782
|
-
if (cv > 0.8) suggestions.push('周内提交不均:各天差异大,建议保持更稳定的周节奏');
|
|
2783
|
-
}}
|
|
2784
|
-
}}
|
|
2785
|
-
}}
|
|
2786
|
-
|
|
2787
|
-
// ============================================================
|
|
2788
|
-
// 50. 功能开发占比
|
|
2789
|
-
// ============================================================
|
|
2790
|
-
if (agg.total > 0) {{
|
|
2791
|
-
const featC = agg.types.feat || 0;
|
|
2792
|
-
const featPct = featC / agg.total * 100;
|
|
2793
|
-
if (featPct > 60) suggestions.push(`功能开发为主:feat 占 ${{featPct.toFixed(0)}}%,建议平衡新功能与质量保障`);
|
|
2794
|
-
else if (featPct < 10 && agg.total > 50) suggestions.push(`功能开发少:feat 仅占 ${{featPct.toFixed(0)}}%,开发以维护为主`);
|
|
2795
|
-
}}
|
|
2796
|
-
|
|
2797
|
-
// ============================================================
|
|
2798
|
-
// 51. Chore 类型分析
|
|
2799
|
-
// ============================================================
|
|
2800
|
-
if (agg.total > 0) {{
|
|
2801
|
-
const choreC = agg.types.chore || 0;
|
|
2802
|
-
const chorePct = choreC / agg.total * 100;
|
|
2803
|
-
if (chorePct > 20) suggestions.push(`琐事较多:chore 占 ${{chorePct.toFixed(0)}}%,建议用自动化脚本减少重复工作`);
|
|
2804
|
-
}}
|
|
2805
|
-
|
|
2806
|
-
// ============================================================
|
|
2807
|
-
// 52. 提交历史长度
|
|
2808
|
-
// ============================================================
|
|
2809
|
-
if (agg.activeDays > 200) suggestions.push(`长期开发者:活跃超过 ${{agg.activeDays}} 天,积累了丰富的开发经验`);
|
|
2810
|
-
|
|
2811
|
-
// ============================================================
|
|
2812
|
-
// 53. 最热门项目贡献
|
|
2813
|
-
// ============================================================
|
|
2814
|
-
if (totalProjects > 1 && agg.total > 0) {{
|
|
2815
|
-
const maxCommits = Math.max(...Object.values(agg.projectCounts));
|
|
2816
|
-
const topRatio = maxCommits / agg.total * 100;
|
|
2817
|
-
if (topRatio > 60) suggestions.push(`单项目主导:最热门项目占 ${{topRatio.toFixed(0)}}% 提交,精力高度集中`);
|
|
2818
|
-
else if (topRatio < 20) suggestions.push(`精力分散:最热门项目仅占 ${{topRatio.toFixed(0)}}% 提交,建议聚焦核心项目`);
|
|
2819
|
-
}}
|
|
2820
|
-
|
|
2821
|
-
// ============================================================
|
|
2822
|
-
// 54. 文档与代码比例
|
|
2823
|
-
// ============================================================
|
|
2824
|
-
if (agg.total > 0) {{
|
|
2825
|
-
const docsC = agg.types.docs || 0;
|
|
2826
|
-
const codeC = agg.total - docsC;
|
|
2827
|
-
if (codeC > 0) {{
|
|
2828
|
-
const docCodeRatio = docsC / codeC;
|
|
2829
|
-
if (docCodeRatio > 0.3) suggestions.push(`文档投入高:文档/代码比 ${{docCodeRatio.toFixed(1)}},文档维护良好`);
|
|
2830
|
-
else if (docCodeRatio < 0.05 && agg.total > 50) suggestions.push(`文档投入不足:文档/代码比 ${{docCodeRatio.toFixed(2)}},建议增加文档更新`);
|
|
2831
|
-
}}
|
|
2832
|
-
}}
|
|
2833
|
-
|
|
2834
|
-
// ============================================================
|
|
2835
|
-
// 55. 早起 vs 夜猫子
|
|
2836
|
-
// ============================================================
|
|
2837
|
-
if (hourly.length === 24) {{
|
|
2838
|
-
const total = hourly.reduce((a, b) => a + b, 0);
|
|
2839
|
-
if (total > 0) {{
|
|
2840
|
-
const morning = hourly.slice(5, 9).reduce((a, b) => a + b, 0);
|
|
2841
|
-
const night = hourly.slice(22, 24).reduce((a, b) => a + b, 0) + hourly.slice(0, 2).reduce((a, b) => a + b, 0);
|
|
2842
|
-
if (morning > night * 2 && morning > 0) suggestions.push('早起型开发者:早晨提交多于深夜,作息健康');
|
|
2843
|
-
else if (night > morning * 2 && night > 0) suggestions.push('夜猫子型开发者:深夜提交多于早晨,建议调整作息');
|
|
2844
|
-
}}
|
|
2845
|
-
}}
|
|
2846
|
-
|
|
2847
|
-
// ============================================================
|
|
2848
|
-
// 56. 提交稳定性
|
|
2849
|
-
// ============================================================
|
|
2850
|
-
if (agg.activeDays > 10 && agg.total > 0) {{
|
|
2851
|
-
const commitsPerDay = agg.total / agg.activeDays;
|
|
2852
|
-
if (commitsPerDay >= 2 && commitsPerDay <= 6) suggestions.push(`提交节奏稳定:活跃日均 ${{commitsPerDay.toFixed(1)}} 次提交,节奏适中`);
|
|
2853
|
-
}}
|
|
2854
|
-
|
|
2855
|
-
// ============================================================
|
|
2856
|
-
// 57. 多语言项目管理
|
|
2857
|
-
// ============================================================
|
|
2858
|
-
if (langSet.size >= 3) {{
|
|
2859
|
-
const langCounts = agg.languageCounts;
|
|
2860
|
-
const topLang = Object.keys(langCounts).reduce((a, b) => (langCounts[a] || 0) > (langCounts[b] || 0) ? a : b, Object.keys(langCounts)[0]);
|
|
2861
|
-
suggestions.push(`多语言开发者:使用 ${{langSet.size}} 种语言,${{topLang}} 项目最多`);
|
|
2862
|
-
}}
|
|
1956
|
+
// 正面反馈
|
|
1957
|
+
if (aiRatio >= 0.20 && aiRatio <= 0.40) categories.ai.items.push(`AI 使用适中:AI 占比 ${{(aiRatio*100).toFixed(0)}}%,人机协作良好`);
|
|
2863
1958
|
|
|
2864
1959
|
// ============================================================
|
|
2865
|
-
//
|
|
1960
|
+
// 构建 HTML(带 tab 切换)
|
|
2866
1961
|
// ============================================================
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
const otherPct = otherC / agg.total * 100;
|
|
2870
|
-
if (otherPct > 30) suggestions.push(`提交分类不清:${{otherPct.toFixed(0)}}% 归为 other,建议使用标准 commit 类型`);
|
|
2871
|
-
else if (otherPct < 10 && agg.total > 50) suggestions.push(`提交分类规范:other 仅占 ${{otherPct.toFixed(0)}}%,类型使用清晰`);
|
|
2872
|
-
}}
|
|
1962
|
+
const activeCats = Object.entries(categories).filter(([k, v]) => v.items.length > 0);
|
|
1963
|
+
let html = '';
|
|
2873
1964
|
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
1965
|
+
if (activeCats.length === 0) {{
|
|
1966
|
+
html = '<div class="sug-item"><div class="sug-text">继续保持良好的开发习惯!各项指标都很健康</div></div>';
|
|
1967
|
+
}} else {{
|
|
1968
|
+
// Tab 按钮
|
|
1969
|
+
html += '<div class="sug-tabs">';
|
|
1970
|
+
activeCats.forEach(([key, cat], i) => {{
|
|
1971
|
+
const activeClass = i === 0 ? ' active' : '';
|
|
1972
|
+
html += `<button class="sug-tab${{activeClass}}" data-cat="${{key}}">${{cat.icon}} ${{cat.name}} (${{cat.items.length}})</button>`;
|
|
1973
|
+
}});
|
|
1974
|
+
html += '</div>';
|
|
1975
|
+
|
|
1976
|
+
// Tab 内容
|
|
1977
|
+
activeCats.forEach(([key, cat], i) => {{
|
|
1978
|
+
const activeClass = i === 0 ? ' active' : '';
|
|
1979
|
+
html += `<div class="sug-panel${{activeClass}}" data-cat="${{key}}">`;
|
|
1980
|
+
cat.items.forEach((item, j) => {{
|
|
1981
|
+
html += `<div class="sug-item"><div class="sug-num">${{j + 1}}</div><div class="sug-text">${{item}}</div></div>`;
|
|
1982
|
+
}});
|
|
1983
|
+
html += '</div>';
|
|
1984
|
+
}});
|
|
2893
1985
|
}}
|
|
2894
1986
|
|
|
2895
|
-
|
|
2896
|
-
if (!suggestions.length) suggestions.push('继续保持良好的开发习惯!各项指标都很健康');
|
|
1987
|
+
document.getElementById('suggestions').innerHTML = html;
|
|
2897
1988
|
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
1989
|
+
// 绑定 tab 切换事件
|
|
1990
|
+
document.querySelectorAll('.sug-tab').forEach(tab => {{
|
|
1991
|
+
tab.addEventListener('click', () => {{
|
|
1992
|
+
const cat = tab.dataset.cat;
|
|
1993
|
+
document.querySelectorAll('.sug-tab').forEach(t => t.classList.remove('active'));
|
|
1994
|
+
document.querySelectorAll('.sug-panel').forEach(p => p.classList.remove('active'));
|
|
1995
|
+
tab.classList.add('active');
|
|
1996
|
+
document.querySelector(`.sug-panel[data-cat="${{cat}}"]`).classList.add('active');
|
|
1997
|
+
}});
|
|
1998
|
+
}});
|
|
2903
1999
|
}}
|
|
2904
2000
|
|
|
2905
2001
|
// ============================================================
|