226d47a72d
build / build (push) Successful in 1m13s
仅删除周报说明段及模板占位,保留自然月规则、指标数值和来源审计。 历史已保存周报不因模板变更自动改写,保留中英文各六节。 验证:移除说明断言先红后绿,自然月指标/来源及历史证据保留测试通过,完整门禁与原生备份恢复通过。
188 lines
6.5 KiB
Go
188 lines
6.5 KiB
Go
package qaopsmirror
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"knowledge-governance/internal/dobotaiops"
|
|
"math"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func weeklyMarkdownCell(value string) string {
|
|
return strings.NewReplacer("&", "&", "<", "<", ">", ">", "\\", "\\\\", "*", "\\*", "_", "\\_", "[", "\\[", "]", "\\]", "|", "\\|", "`", "\\`", "\r", " ", "\n", " ").Replace(value)
|
|
}
|
|
func weeklyPercent(value *float64) string {
|
|
if value == nil {
|
|
return "—"
|
|
}
|
|
return fmt.Sprintf("%.2f%%", *value)
|
|
}
|
|
func weeklyNumber(value *float64) string {
|
|
if value == nil {
|
|
return "—"
|
|
}
|
|
return fmt.Sprintf("%.2f", *value)
|
|
}
|
|
func validWeeklyValue(v *float64, percent bool) bool {
|
|
return v == nil || (!math.IsNaN(*v) && !math.IsInf(*v, 0) && *v >= 0 && (!percent || *v <= 100))
|
|
}
|
|
func weeklyRegionRanking(regions []DashboardRegion, coverage, english bool) string {
|
|
rows := append([]DashboardRegion(nil), regions...)
|
|
metric := func(r DashboardRegion) *float64 {
|
|
if coverage {
|
|
return r.UsageCoverage.Percent
|
|
}
|
|
return r.Frequency
|
|
}
|
|
sort.SliceStable(rows, func(i, j int) bool {
|
|
a, b := metric(rows[i]), metric(rows[j])
|
|
if a == nil {
|
|
return false
|
|
}
|
|
if b == nil {
|
|
return true
|
|
}
|
|
if *a == *b {
|
|
return rows[i].ID < rows[j].ID
|
|
}
|
|
return *a > *b
|
|
})
|
|
values := make([]string, 0, len(rows))
|
|
for i, r := range rows {
|
|
name := r.Name
|
|
if english {
|
|
if translated := map[string]string{"国内工业": "China Industrial", "America": "Americas", "APAC": "APAC", "EMEA": "EMEA"}[name]; translated != "" {
|
|
name = translated
|
|
}
|
|
}
|
|
value := weeklyNumber(metric(r))
|
|
if coverage {
|
|
value = weeklyPercent(metric(r))
|
|
}
|
|
values = append(values, fmt.Sprintf("%d. %s: %s", i+1, weeklyMarkdownCell(name), value))
|
|
}
|
|
if len(values) == 0 {
|
|
return "—"
|
|
}
|
|
return strings.Join(values, "\n")
|
|
}
|
|
func renderWeeklyTemplate(week string, data Dashboard, now time.Time) (string, json.RawMessage, error) {
|
|
start, end, err := weeklyDraftBounds(week, now)
|
|
if err != nil || !data.Start.Equal(start) || !data.End.Equal(end) || data.TotalIssues < 0 || data.NewThisWeek < 0 || data.NewThisWeek > data.TotalIssues || data.MonthStart.IsZero() {
|
|
return "", nil, dobotaiops.ErrInvalidQuery
|
|
}
|
|
coverage, accuracy := data.Quality.Rates.Coverage.Percent, data.Quality.Rates.Correctness.Percent
|
|
qualitySource := "live-week"
|
|
qualitySourceWeekKey := ""
|
|
for _, f := range data.FrozenWeeks {
|
|
if f.WeekStart.Equal(start) && f.FrozenAt != nil {
|
|
coverage, accuracy = f.Coverage.Percent, f.Correctness.Percent
|
|
qualitySource = "frozen-week"
|
|
}
|
|
}
|
|
for _, p := range data.ReportedWeeks {
|
|
if p.WeekStart.Equal(start) && p.WeekEnd.Equal(start.AddDate(0, 0, 7)) && !p.WeekEnd.After(end) {
|
|
c, a := p.CoveragePercent, p.CorrectnessPercent
|
|
coverage, accuracy = &c, &a
|
|
qualitySource = "reported-history"
|
|
qualitySourceWeekKey = p.Week
|
|
}
|
|
}
|
|
if data.QualityPeriod != nil || data.MonthlyQuality != nil {
|
|
period, rates := data.QualityPeriod, data.MonthlyQuality
|
|
if period == nil || rates == nil || period.Source != dashboardMonthlySource || period.PolicyVersion != dashboardMonthlyPolicy || rates.Records < 0 {
|
|
return "", nil, dobotaiops.ErrInvalidQuery
|
|
}
|
|
wantStart, wantEnd := dashboardQualityMonth(start, end, period.CalculatedAt)
|
|
if !period.Start.Equal(wantStart) || !period.CutoffAt.Equal(wantEnd) || period.Month != wantStart.Format("2006-01") {
|
|
return "", nil, dobotaiops.ErrInvalidQuery
|
|
}
|
|
coverage, accuracy = rates.Coverage.Percent, rates.Correctness.Percent
|
|
qualitySource, qualitySourceWeekKey = dashboardMonthlySource, ""
|
|
}
|
|
if !validWeeklyValue(coverage, true) || !validWeeklyValue(accuracy, true) {
|
|
return "", nil, dobotaiops.ErrInvalidQuery
|
|
}
|
|
for _, r := range data.Regions {
|
|
if !validWeeklyValue(r.Frequency, false) || !validWeeklyValue(r.UsageCoverage.Percent, true) {
|
|
return "", nil, dobotaiops.ErrInvalidQuery
|
|
}
|
|
}
|
|
month := data.MonthStart.In(dashboardLocation)
|
|
replacements := []string{
|
|
"{{YEAR}}", week[:4], "{{WEEK}}", week[6:],
|
|
"{{TOTAL_QUESTIONS}}", fmt.Sprint(data.TotalIssues), "{{NEW_THIS_WEEK}}", fmt.Sprint(data.NewThisWeek),
|
|
"{{COVERAGE_RATE}}", weeklyPercent(coverage), "{{ACCURACY_RATE}}", weeklyPercent(accuracy),
|
|
"{{MONTH_EN}}", month.Format("January 2006"), "{{MONTH_ZH}}", fmt.Sprintf("%d年%d月", month.Year(), month.Month()),
|
|
"{{AVERAGE_USAGE_RANKING_EN}}", weeklyRegionRanking(data.Regions, false, true), "{{AVERAGE_USAGE_RANKING_ZH}}", weeklyRegionRanking(data.Regions, false, false),
|
|
"{{USAGE_COVERAGE_RANKING_EN}}", weeklyRegionRanking(data.Regions, true, true), "{{USAGE_COVERAGE_RANKING_ZH}}", weeklyRegionRanking(data.Regions, true, false),
|
|
"{{WEEKLY_HIGHLIGHTS_EN}}", "[To be completed]", "{{NEXT_WEEK_PRIORITIES_EN}}", "[To be completed]",
|
|
"{{WEEKLY_HIGHLIGHTS_ZH}}", "[待填写]", "{{NEXT_WEEK_PRIORITIES_ZH}}", "[待填写]"}
|
|
markdown := strings.NewReplacer(replacements...).Replace(weeklySkillTemplate)
|
|
seed, _ := json.Marshal(map[string]any{"template_version": "dobot-weekly-six-sections-v1", "week": week, "start": start, "end": end, "generated_at": now, "source": "governance-master", "local_revision": data.LocalRevision, "source_observed_at": data.AsOf, "organization": data.Organization, "quality_source": qualitySource, "quality_source_week_key": qualitySourceWeekKey, "quality_period": data.QualityPeriod, "quality_counts": data.MonthlyQuality, "total_issues": data.TotalIssues, "new_this_week": data.NewThisWeek, "coverage_percent": coverage, "correctness_percent": accuracy, "month": month.Format("2006-01"), "regions": data.Regions})
|
|
return markdown, seed, nil
|
|
}
|
|
|
|
const weeklySkillTemplate = `# Knowledge Base Weekly Report - {{YEAR}} WK{{WEEK}}
|
|
|
|
## 1. Weekly Summary
|
|
|
|
Total Questions: {{TOTAL_QUESTIONS}}
|
|
|
|
New This Week: {{NEW_THIS_WEEK}}
|
|
|
|
## 2. Key Metrics
|
|
|
|
Coverage Rate: {{COVERAGE_RATE}}
|
|
|
|
Accuracy Rate: {{ACCURACY_RATE}}
|
|
|
|
## 3. {{MONTH_EN}} Regional Average Usage Ranking
|
|
|
|
{{AVERAGE_USAGE_RANKING_EN}}
|
|
|
|
## 4. {{MONTH_EN}} Regional Usage Coverage Ranking
|
|
|
|
{{USAGE_COVERAGE_RANKING_EN}}
|
|
|
|
## 5. Weekly Highlights
|
|
|
|
{{WEEKLY_HIGHLIGHTS_EN}}
|
|
|
|
## 6. Next Week Priorities
|
|
|
|
{{NEXT_WEEK_PRIORITIES_EN}}
|
|
|
|
# 知识库周报 - {{YEAR}}年第{{WEEK}}周
|
|
|
|
## 一、本周概况
|
|
|
|
问题总数:{{TOTAL_QUESTIONS}}
|
|
|
|
本周新增:{{NEW_THIS_WEEK}}
|
|
|
|
## 二、核心指标
|
|
|
|
覆盖率:{{COVERAGE_RATE}}
|
|
|
|
正确率:{{ACCURACY_RATE}}
|
|
|
|
## 三、{{MONTH_ZH}}区域人均使用次数排名
|
|
|
|
{{AVERAGE_USAGE_RANKING_ZH}}
|
|
|
|
## 四、{{MONTH_ZH}}区域使用覆盖率排名
|
|
|
|
{{USAGE_COVERAGE_RANKING_ZH}}
|
|
|
|
## 五、本周重点
|
|
|
|
{{WEEKLY_HIGHLIGHTS_ZH}}
|
|
|
|
## 六、下周重点
|
|
|
|
{{NEXT_WEEK_PRIORITIES_ZH}}
|
|
`
|