Files
knowledge-governance/internal/httpapi/qa_master.go
姚章浩 4a2b2b7d84
build / build (push) Successful in 1m5s
feat(qaops): 增加部门树区域统计与父子联选
区域配置入口改为区域统计,五列表按当前通讯录整支人员去重;调岗依当前归属、零分母未知、最近真实提问时间和父行收起不重算。仅读治理正式总表,后台单并发/请求合并/60秒缓存,目录与配置版本隔离,客户端失败不伪零。

保留区域自定义目录与预览/双版本锁保存,父部门勾选联选全后代,取消子支清除祖先整支选择,避免隐式覆盖未选子级;允许删除无引用区域,已有引用不静默孤立。统计页与设置共享选择,统计支持累计与北京时间自然月;不新增迁移,不改DobotAI生产、代理、原问答、历史趋势或已有AI任务。

验证已执行:完整make verify退出0,705 Go/340前端通过、120项声明的可选集成跳过且必需0跳过;镜像全量隔离PG race退出0;新增去重/调岗/空分母、后台缓存/并发、HTTP授权/严格请求、真PG目录与配置失效、树选择/收起、五列与删除保护均先红后绿。旧导航测试按新名称更新后全量通过。上线前治理库备份与真实恢复72表/29张QA内容哈希一致,匹配独立主密钥受限备份。

当前尚待精确SHA CI、同镜像真实数据浏览器与正式读回,不把源码验证称为已上线。公司真实区域映射不在本轮擅改;只在隔离库验证保存。
2026-10-19 19:01:36 +08:00

66 lines
2.3 KiB
Go

package httpapi
import (
"context"
"knowledge-governance/internal/dobotaiops"
"knowledge-governance/internal/qaopsquality"
"net/http"
"strings"
)
func masterNoStore(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/v1/qa-ops/master/") || strings.HasPrefix(r.URL.Path, "/api/v1/qa-ops/departments/") {
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("Pragma", "no-cache")
}
next.ServeHTTP(w, r)
})
}
// Master reads and reviews own their state; no source client is accepted as fallback.
type qaMasterStore interface {
ListMasterRecords(context.Context, dobotaiops.RecordQuery) (dobotaiops.RecordPage, error)
GetMasterRecord(context.Context, string, string) (dobotaiops.Record, error)
ReadMasterQualityScope(context.Context, dobotaiops.RecordQuery) (dobotaiops.QualityScope, error)
MasterQualityStore() *qaopsquality.Store
}
type qaMasterReader struct {
QAOpsReader
master qaMasterStore
}
func (s qaMasterReader) ListRecords(ctx context.Context, q dobotaiops.RecordQuery) (dobotaiops.RecordPage, error) {
return s.master.ListMasterRecords(ctx, q)
}
func (s qaMasterReader) GetRecord(ctx context.Context, tenant, id string) (dobotaiops.Record, error) {
return s.master.GetMasterRecord(ctx, tenant, id)
}
func (s qaMasterReader) ReadQualityScope(ctx context.Context, q dobotaiops.RecordQuery) (dobotaiops.QualityScope, error) {
return s.master.ReadMasterQualityScope(ctx, q)
}
func (s qaMasterReader) ReadStoredQuality(ctx context.Context, keys []dobotaiops.QualityKey) (map[string]qaopsquality.View, error) {
if reader, ok := s.master.(interface {
ReadMasterQualityViews(context.Context, []dobotaiops.QualityKey) (map[string]qaopsquality.View, error)
}); ok {
return reader.ReadMasterQualityViews(ctx, keys)
}
return s.master.MasterQualityStore().ReadViews(ctx, keys)
}
func withQAMaster(w http.ResponseWriter, r *http.Request, c Config, handler func(http.ResponseWriter, *http.Request, Config)) {
if !authorizeQAOps(w, r) {
return
}
master, ok := c.QAOps.(qaMasterStore)
if !ok {
qaOpsError(w, dobotaiops.ErrUnavailable)
return
}
c.QAOps = qaMasterReader{QAOpsReader: c.QAOps, master: master}
c.QAQuality = master.MasterQualityStore()
if master.MasterQualityStore() == nil {
c.QAQuality = nil
}
handler(w, r, c)
}