Files
knowledge-governance/internal/qaopsmirror/master.go
T
姚章浩 87f97a2f9b
build / build (push) Successful in 1m7s
feat(qaops): 完成详情下拉与每周自动保存草稿
详情使用共享主表字典,稀疏修改所选字段并保留原始问答及旧复核审计。
月周统计提供文本和下拉双入口;每租户每周一份持久草稿,按技能六节双语模板真实预填。
加入幂等自动保存、冲突保留、未知响应重试、切周及离开保护和schema58非破坏降级保护。

验证:完整make verify、隔离PostgreSQL全mirror竞态回归、真实恢复库浏览器验收通过。
浏览器实测字段精确读回、月周双输入、模板预填、MD/CSV、自动保存、冲突、失败重试与API重启恢复。
未连接或改写DobotAI生产源库,未运行付费模型;提交时尚未部署。
2026-10-20 05:44:02 +08:00

64 lines
3.1 KiB
Go

package qaopsmirror
import (
"context"
"knowledge-governance/internal/dobotaiops"
"knowledge-governance/internal/qaopsfields"
"knowledge-governance/internal/qaopsquality"
"strings"
)
func (s *Store) ReadMasterDashboard(ctx context.Context, q dobotaiops.RecordQuery) (Dashboard, error) {
return s.readDashboard(ctx, q, true)
}
func (s *Store) MasterQualityStore() *qaopsquality.Store {
return qaopsquality.NewStore(s.pool, s.tenant+"::master")
}
const masterBaseSQL = `WITH records AS (SELECT id,asked_at,question||E'\n'||chinese_question||E'\n'||COALESCE(ai_fields->>'question_chinese','') AS question,status,identity,quality_hash,jsonb_set(payload,'{master_fields}',effective_fields)||jsonb_build_object('record_origin',origin,'background_tasks',background_tasks,'field_edit_revision',field_edit_revision) AS payload FROM qa_ops_master_read_model WHERE tenant_key=$1)`
var masterMetadataBase = strings.NewReplacer("qa_ops_mirror_records", "qa_ops_master_read_model", "h.tenant_key=m.tenant_key", "h.tenant_key=m.tenant_key||'::master'", "m.question", "(m.question||E'\\n'||m.chinese_question||E'\\n'||COALESCE(m.ai_fields->>'question_chinese','')) AS question").Replace(localMetadataBase)
var masterSummarySQL = masterMetadataBase + ` SELECT count(*),'{}'::text,COALESCE(jsonb_agg(DISTINCT identity),'[]'::jsonb)::text,COALESCE(jsonb_agg(jsonb_build_object('id',id,'input_hash',quality_hash,'marker',marker,'source',source_coverage)),'[]'::jsonb)::text FROM records WHERE $5::text IS NOT NULL AND `
var masterQualityScopeSQL = masterMetadataBase + ` SELECT id,quality_hash,marker,source_coverage::text FROM records WHERE $5::text IS NOT NULL AND `
func (s *Store) ListMasterRecords(ctx context.Context, q dobotaiops.RecordQuery) (dobotaiops.RecordPage, error) {
var revision int64
p, e := s.repositoryFor(&revision, true).ListRecords(ctx, q)
p.LocalRevision = revision
if e == nil {
for i := range p.Items {
projectLocalMaster(&p.Items[i])
}
}
p.Columns = []string{"question_chinese", "answer", "coverage", "is_correct", "product_category", "problem_type", "root_cause", "asked_at", "asker", "question", "language", "trigger_person", "department", "region", "feedback"}
return p, e
}
func (s *Store) ReadMasterQualityScope(ctx context.Context, q dobotaiops.RecordQuery) (dobotaiops.QualityScope, error) {
return s.repositoryFor(nil, true).ReadQualityScope(ctx, q)
}
func (s *Store) GetMasterRecord(ctx context.Context, tenant, id string) (dobotaiops.Record, error) {
item, err := s.repositoryFor(nil, true).GetRecord(ctx, tenant, id)
if err == nil {
projectLocalMaster(&item)
}
return item, err
}
func projectLocalMaster(item *dobotaiops.Record) {
fields := make(map[string]string, len(item.MasterFields)+2)
for key, value := range item.MasterFields {
fields[key] = value
}
code := qaopsfields.DetectLanguage(item.Question)
if strings.TrimSpace(fields["language"]) == "" {
fields["language"] = qaopsfields.LanguageName(code)
}
if strings.TrimSpace(fields["question_chinese"]) == "" && code == "zh" {
fields["question_chinese"] = item.Question
}
item.MasterFields = fields
item.Coverage = dobotaiops.CheckMasterCoverage(item.Answer, true)
}