87f97a2f9b
build / build (push) Successful in 1m7s
详情使用共享主表字典,稀疏修改所选字段并保留原始问答及旧复核审计。 月周统计提供文本和下拉双入口;每租户每周一份持久草稿,按技能六节双语模板真实预填。 加入幂等自动保存、冲突保留、未知响应重试、切周及离开保护和schema58非破坏降级保护。 验证:完整make verify、隔离PostgreSQL全mirror竞态回归、真实恢复库浏览器验收通过。 浏览器实测字段精确读回、月周双输入、模板预填、MD/CSV、自动保存、冲突、失败重试与API重启恢复。 未连接或改写DobotAI生产源库,未运行付费模型;提交时尚未部署。
64 lines
3.1 KiB
Go
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)
|
|
}
|