diff --git a/docs/02_Architecture/AR09_Object_Naming_Standard.md b/docs/02_Architecture/AR09_Object_Naming_Standard.md index 3d2e459..cb2983a 100644 --- a/docs/02_Architecture/AR09_Object_Naming_Standard.md +++ b/docs/02_Architecture/AR09_Object_Naming_Standard.md @@ -84,6 +84,7 @@ | 连接器 | `connector` | `internal/connector/*` | 外部系统接入 | | 动作 | `action` | `model/action_definition.go` | 技能调用的底层执行单元 | | 任务 | `task` | `model/task_record.go` | 工作实例容器 | +| 数据访问层 | `dal` / `DAO` | `internal/dal/*.go` | 统一的数据访问层:包名 `dal`,每个实体的访问对象叫 `XxxDAO`(`TaskRecordDAO`、`SpecialistDAO`…)。所有 handler 必须经它访问数据,禁止直接调用 `store.DB`。2026-09-19 由 `internal/repository` + `XxxRepo` 更名而来 | ### 3.2 兼容术语(限制使用,禁止扩散) @@ -252,6 +253,8 @@ | `AI` | artificial intelligence | | `OCR` | optical character recognition | | `PPT` / `PDF` | 文件格式 | +| `DAO` | data access object(数据访问对象,见 §3.1) | +| `dal` | data access layer(数据访问层包名,Go 包名一律小写) | | `req` / `res` | 仅限 HTTP 处理函数的局部变量 | 禁止:`usr`、`mgr`、`svc`、`num`、`str`、`val`。(HTTP 处理函数的局部 `req` / `res`、Go 的 `ctx`、局部配置 `cfg` 属公认短名,不算违规。) diff --git a/eai_agentplatform/PROJECT_STATE.md b/eai_agentplatform/PROJECT_STATE.md index 34df104..161652d 100644 --- a/eai_agentplatform/PROJECT_STATE.md +++ b/eai_agentplatform/PROJECT_STATE.md @@ -69,6 +69,8 @@ | D25 | 平台总架构继续采用 6 层,但第 5 层正式升级为 **对象层(Expert / Skill / App)**;新增与“专家 / 技能”并列的第三类一级对象 **App**,其定位是“长程任务运行壳”而非页面或大技能。任务统一定义为“工作实例容器”,可挂载主 `app`、右栏 `expert`、后台 `skill`;消息流降级为对话轨迹,长程状态由 `app_state + app_event + domain_data` 承载。产品一级导航目标态需完整描述为 **新建任务 / 项目 / 专家·技能·连接器 / 长程APP / 知识库 / 后台管理 / 我的**,其中 `知识库` 被确认为组织级默认必装的内建 App,拥有一级直达入口;其它专题型业务主导航后续应优先收敛为 `app` 并归入“长程APP”。文档锚点:`docs/01_System_Overall/SY22_Role_Skill_App_Unified_Task_Architecture.md` | 已定 | | D26 | 路由命名正式拆分为三类以避免混同:`ai_route_*` 专指 AI 模型路由;`object_entry_route` 专指 Expert / Skill / App 等业务对象的进入入口;`page_route` 专指普通页面导航。后端 API、前端对象配置与导航配置均按该口径收口;旧 `route / entry_route` 已降为启动时一次性迁移并随后删除的历史列,不再保留为日常兼容字段。 | 已定 | +| D27 | 后端「仓库层」正式更名为**数据访问层**,英文同步改:包 `internal/repository` → `internal/dal`,类型 `XxxRepo` → `XxxDAO`(`TaskRecordDAO` / `SpecialistDAO`…),日志前缀 `[repository]` → `[dal]`。理由是原名的「仓库」是 repository 的直译,中文里与「代码仓库 / git 仓库」同词,而这一层做的事就是数据访问。命名规范见 AR09 §3.1 / §5.6 | 已定 | + ## 4. 文档索引 | 文档 | 路径 | 说明 | diff --git a/eai_agentplatform/backend-go/cmd/server/main.go b/eai_agentplatform/backend-go/cmd/server/main.go index ca23834..a50e140 100644 --- a/eai_agentplatform/backend-go/cmd/server/main.go +++ b/eai_agentplatform/backend-go/cmd/server/main.go @@ -10,8 +10,8 @@ import ( "eai_agentplatform/backend/internal/api" "eai_agentplatform/backend/internal/auth" "eai_agentplatform/backend/internal/config" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" specialistseeding "eai_agentplatform/backend/internal/specialists/seeding" "eai_agentplatform/backend/internal/store" ) @@ -35,7 +35,7 @@ func main() { if err != nil { log.Fatalf("数据库初始化失败: %v", err) } - repository.SetDB(db) + dal.SetDB(db) if err := store.SeedDefaults(); err != nil { log.Fatalf("种子数据初始化失败: %v", err) } @@ -69,7 +69,7 @@ func backupOnce() { if err != nil { log.Fatalf("数据库初始化失败: %v", err) } - repository.SetDB(db) + dal.SetDB(db) path, err := store.Backup(store.DB, cfg.BackupDir, cfg.BackupKeep, time.Now()) if err != nil { log.Fatalf("备份失败: %v", err) @@ -87,7 +87,7 @@ func resetAdmin(args []string) { if err != nil { log.Fatalf("数据库初始化失败: %v", err) } - repository.SetDB(db) + dal.SetDB(db) hash, err := auth.HashPassword(args[0]) if err != nil { log.Fatalf("密码加密失败: %v", err) diff --git a/eai_agentplatform/backend-go/internal/api/action_definition.go b/eai_agentplatform/backend-go/internal/api/action_definition.go index 2ba7a55..f9b932f 100644 --- a/eai_agentplatform/backend-go/internal/api/action_definition.go +++ b/eai_agentplatform/backend-go/internal/api/action_definition.go @@ -5,17 +5,17 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/jsonutil" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// actionDefinitionRepo 动作定义仓库(便于测试时覆写),包内共享。 -var actionDefinitionRepo repository.ActionDefinitionRepo +// actionDefinitionDAO 动作定义仓库(便于测试时覆写),包内共享。 +var actionDefinitionDAO dal.ActionDefinitionDAO func init() { - actionDefinitionRepo = repository.ActionDefinitionRepo{} + actionDefinitionDAO = dal.ActionDefinitionDAO{} } type actionDefinitionReq struct { @@ -91,7 +91,7 @@ func ListActionDefinitions(c *gin.Context) { if state == "" { state = "active" } - web.OK(c, actionDefinitionRepo.List(state)) + web.OK(c, actionDefinitionDAO.List(state)) } func GetActionDefinitionByKey(c *gin.Context) { @@ -100,7 +100,7 @@ func GetActionDefinitionByKey(c *gin.Context) { web.Fail(c, web.NewBadRequest("action key 不能为空")) return } - item, found := actionDefinitionRepo.GetByKey(key) + item, found := actionDefinitionDAO.GetByKey(key) if !found { web.Fail(c, web.NewNotFoundError("Action 定义不存在")) return @@ -134,7 +134,7 @@ func CreateActionDefinition(c *gin.Context) { State: req.State, SortOrder: req.SortOrder, } - if !actionDefinitionRepo.Insert(&item) { + if !actionDefinitionDAO.Insert(&item) { web.Fail(c, web.NewBadRequest("创建 Action 定义失败")) return } @@ -146,7 +146,7 @@ func UpdateActionDefinition(c *gin.Context) { if !ok { return } - item, found := actionDefinitionRepo.GetByID(id) + item, found := actionDefinitionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("Action 定义不存在")) return @@ -174,7 +174,7 @@ func UpdateActionDefinition(c *gin.Context) { item.OntologyBindingJSON = req.OntologyBindingJSON item.State = req.State item.SortOrder = req.SortOrder - if !actionDefinitionRepo.Update(&item) { + if !actionDefinitionDAO.Update(&item) { web.Fail(c, web.NewBadRequest("更新 Action 定义失败")) return } @@ -186,12 +186,12 @@ func DeleteActionDefinition(c *gin.Context) { if !ok { return } - item, found := actionDefinitionRepo.GetByID(id) + item, found := actionDefinitionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("Action 定义不存在")) return } - if !actionDefinitionRepo.Delete(&item) { + if !actionDefinitionDAO.Delete(&item) { web.Fail(c, web.NewBadRequest("删除 Action 定义失败")) return } diff --git a/eai_agentplatform/backend-go/internal/api/auth.go b/eai_agentplatform/backend-go/internal/api/auth.go index 992ef68..2b19507 100644 --- a/eai_agentplatform/backend-go/internal/api/auth.go +++ b/eai_agentplatform/backend-go/internal/api/auth.go @@ -21,7 +21,7 @@ func Login(c *gin.Context) { return } - user, found := userRepo.GetByUsername(req.Username) + user, found := userDAO.GetByUsername(req.Username) if !found { web.Fail(c, web.NewAuthError("用户名或密码错误")) return diff --git a/eai_agentplatform/backend-go/internal/api/certificate.go b/eai_agentplatform/backend-go/internal/api/certificate.go index 9df40f0..844bd04 100644 --- a/eai_agentplatform/backend-go/internal/api/certificate.go +++ b/eai_agentplatform/backend-go/internal/api/certificate.go @@ -6,17 +6,17 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// certRepo 证书仓库(便于测试时覆写),包内共享。 -var certRepo repository.CertificateRepo +// certDAO 证书仓库(便于测试时覆写),包内共享。 +var certDAO dal.CertificateDAO func init() { - certRepo = repository.CertificateRepo{} + certDAO = dal.CertificateDAO{} } // issueCertificate 正式考试通过后颁发证书(幂等:同一 exam_record 只发一张)。 @@ -24,11 +24,11 @@ func issueCertificate(u *model.User, rec model.ExamRecord) { if u == nil || !rec.Passed { return } - if _, found := certRepo.GetByExamRecord(rec.ID); found { + if _, found := certDAO.GetByExamRecord(rec.ID); found { return } certNo := fmt.Sprintf("BST-%06d", rec.ID) - certRepo.Insert(&model.Certificate{ + certDAO.Insert(&model.Certificate{ UserID: u.ID, ExamRecordID: rec.ID, UserName: u.FullName, ExamName: rec.ExamName, Score: rec.Score, TotalScore: rec.TotalScore, PassScore: rec.PassScore, CertNo: certNo, IssuedAt: time.Now(), @@ -42,7 +42,7 @@ func MyCertificates(c *gin.Context) { web.Fail(c, web.NewAuthError("未登录")) return } - items := certRepo.ListByUser(u.ID) + items := certDAO.ListByUser(u.ID) if items == nil { items = []model.Certificate{} } @@ -56,7 +56,7 @@ func CertificateDetail(c *gin.Context) { if !ok { return } - cert, found := certRepo.GetByID(id) + cert, found := certDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("证书不存在")) return @@ -70,5 +70,5 @@ func CertificateDetail(c *gin.Context) { // AdminCertificates GET /api/system/certificates —— 全员证书(管理员) func AdminCertificates(c *gin.Context) { - web.OK(c, certRepo.ListAll()) + web.OK(c, certDAO.ListAll()) } diff --git a/eai_agentplatform/backend-go/internal/api/company_train.go b/eai_agentplatform/backend-go/internal/api/company_train.go index 7e26c37..f21a1ac 100644 --- a/eai_agentplatform/backend-go/internal/api/company_train.go +++ b/eai_agentplatform/backend-go/internal/api/company_train.go @@ -14,12 +14,12 @@ import ( "eai_agentplatform/backend/internal/web" ) -// 本文件用到的仓库:configRepo 声明在 system.go,mediaRepo 声明在 media.go。 +// 本文件用到的仓库:configDAO 声明在 system.go,mediaDAO 声明在 media.go。 // GetCompanyTrain GET /api/company-train // content 取 system_config(company_intro),medias 取已审批的公司绑定素材 func GetCompanyTrain(c *gin.Context) { - content := configRepo.GetByKey("company_intro") - files := mediaRepo.ListApprovedByBindType("company") + content := configDAO.GetByKey("company_intro") + files := mediaDAO.ListApprovedByBindType("company") type mediaItem struct { ID uint `json:"id"` @@ -100,7 +100,7 @@ func SuggestMaterial(c *gin.Context) { BindType: "none", Remark: remark, } - if !mediaRepo.Insert(&m) { + if !mediaDAO.Insert(&m) { web.Fail(c, web.NewBadRequest("创建素材记录失败")) return } diff --git a/eai_agentplatform/backend-go/internal/api/courses.go b/eai_agentplatform/backend-go/internal/api/courses.go index 129dfd2..22855ac 100644 --- a/eai_agentplatform/backend-go/internal/api/courses.go +++ b/eai_agentplatform/backend-go/internal/api/courses.go @@ -10,7 +10,7 @@ import ( "eai_agentplatform/backend/internal/web" ) -// 本文件的仓库实例:courseRepo 声明在 position.go,mediaRepo 声明在 media.go。 +// 本文件的仓库实例:courseDAO 声明在 position.go,mediaDAO 声明在 media.go。 // courseView 课程详情视图(含绑定产品) func courseView(c *gin.Context, co model.Course) { @@ -32,12 +32,12 @@ func courseView(c *gin.Context, co model.Course) { "updated_at": co.UpdatedAt, } if co.RelatedProductID != nil { - if p, ok := productRepo.GetVisibleByID(*co.RelatedProductID); ok { + if p, ok := productDAO.GetVisibleByID(*co.RelatedProductID); ok { out["product"] = gin.H{"id": p.ID, "code": p.Code, "name": p.Name, "category": p.Category} } } - medias := mediaRepo.ListByBind("course", co.ID) + medias := mediaDAO.ListByBind("course", co.ID) if len(medias) > 0 { items := make([]gin.H, 0, len(medias)) for _, m := range medias { @@ -55,7 +55,7 @@ func courseView(c *gin.Context, co model.Course) { // ListCourses GET /api/courses?category=&status= func ListCourses(c *gin.Context) { - web.OK(c, courseRepo.List(c.Query("category"), c.Query("status"))) + web.OK(c, courseDAO.List(c.Query("category"), c.Query("status"))) } // GetCourse GET /api/courses/{id} @@ -64,7 +64,7 @@ func GetCourse(c *gin.Context) { if !ok { return } - co, found := courseRepo.GetByID(id) + co, found := courseDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("课程不存在")) return @@ -83,14 +83,14 @@ func CreateCourse(c *gin.Context) { web.Fail(c, web.NewBadRequest("编号、名称、分类为必填")) return } - if courseRepo.CountByCode(co.Code, nil) > 0 { + if courseDAO.CountByCode(co.Code, nil) > 0 { web.Fail(c, web.NewConflictError("课程编号已存在")) return } if co.Status == "" { co.Status = "active" } - if !courseRepo.Insert(&co) { + if !courseDAO.Insert(&co) { web.Fail(c, web.NewBadRequest("创建课程失败")) return } @@ -103,7 +103,7 @@ func UpdateCourse(c *gin.Context) { if !ok { return } - co, found := courseRepo.GetByID(id) + co, found := courseDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("课程不存在")) return @@ -122,7 +122,7 @@ func UpdateCourse(c *gin.Context) { } if req.Code != "" && req.Code != co.Code { - if courseRepo.CountByCode(req.Code, &id) > 0 { + if courseDAO.CountByCode(req.Code, &id) > 0 { web.Fail(c, web.NewConflictError("课程编号已存在")) return } @@ -140,7 +140,7 @@ func UpdateCourse(c *gin.Context) { co.RelatedProductID = req.RelatedProductID co.Status = req.Status - if !courseRepo.Update(&co) { + if !courseDAO.Update(&co) { web.Fail(c, web.NewBadRequest("更新课程失败")) return } diff --git a/eai_agentplatform/backend-go/internal/api/department.go b/eai_agentplatform/backend-go/internal/api/department.go index c3a26bb..337271e 100644 --- a/eai_agentplatform/backend-go/internal/api/department.go +++ b/eai_agentplatform/backend-go/internal/api/department.go @@ -7,23 +7,23 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// deptRepo 部门仓库(便于测试时覆写),包内共享。 -var deptRepo repository.DepartmentRepo +// deptDAO 部门仓库(便于测试时覆写),包内共享。 +var deptDAO dal.DepartmentDAO func init() { - deptRepo = repository.DepartmentRepo{} + deptDAO = dal.DepartmentDAO{} } // ListDepartments GET /api/departments?status= —— 部门字典列表(含成员数) func ListDepartments(c *gin.Context) { - items := deptRepo.ListByStatus(c.Query("status")) + items := deptDAO.ListByStatus(c.Query("status")) // 成员数按 user.department 字符串匹配(部门为字典、用户以字符串归属) - users := userRepo.ListEmployees("active") + users := userDAO.ListEmployees("active") nameCount := map[string]int{} for _, u := range users { if strings.TrimSpace(u.Department) != "" { @@ -55,12 +55,12 @@ func CreateDepartment(c *gin.Context) { return } req.Name = strings.TrimSpace(req.Name) - if deptRepo.CountByName(req.Name, nil) > 0 { + if deptDAO.CountByName(req.Name, nil) > 0 { web.Fail(c, web.NewConflictError("部门名称已存在")) return } d := model.Department{Name: req.Name, Description: req.Description, Status: "active"} - if !deptRepo.Insert(&d) { + if !deptDAO.Insert(&d) { web.Fail(c, web.NewBadRequest("创建部门失败")) return } @@ -73,7 +73,7 @@ func UpdateDepartment(c *gin.Context) { if !ok { return } - d, found := deptRepo.GetByID(id) + d, found := deptDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("部门不存在")) return @@ -90,7 +90,7 @@ func UpdateDepartment(c *gin.Context) { req.Name = strings.TrimSpace(req.Name) oldName := d.Name if req.Name != oldName { - if deptRepo.CountByName(req.Name, &id) > 0 { + if deptDAO.CountByName(req.Name, &id) > 0 { web.Fail(c, web.NewConflictError("部门名称已存在")) return } @@ -100,13 +100,13 @@ func UpdateDepartment(c *gin.Context) { if req.Status == "active" || req.Status == "inactive" { d.Status = req.Status } - if !deptRepo.Update(&d) { + if !deptDAO.Update(&d) { web.Fail(c, web.NewBadRequest("更新部门失败")) return } // 改名后同步员工归属,保证按部门统计与展示一致 if req.Name != oldName { - userRepo.RenameDepartment(oldName, req.Name) + userDAO.RenameDepartment(oldName, req.Name) } web.OK(c, d) } @@ -117,16 +117,16 @@ func DeleteDepartment(c *gin.Context) { if !ok { return } - d, found := deptRepo.GetByID(id) + d, found := deptDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("部门不存在")) return } - if n := userRepo.CountActiveByDepartment(d.Name); n > 0 { + if n := userDAO.CountActiveByDepartment(d.Name); n > 0 { web.Fail(c, web.NewConflictError(fmt.Sprintf("该部门下仍有 %d 名员工,请先调整其部门", n))) return } - if !deptRepo.Delete(id) { + if !deptDAO.Delete(id) { web.Fail(c, web.NewBadRequest("删除部门失败")) return } @@ -135,7 +135,7 @@ func DeleteDepartment(c *gin.Context) { // DepartmentStats GET /api/system/department-stats —— 按部门学情聚合 func DepartmentStats(c *gin.Context) { - employees := userRepo.ListEmployees("active") + employees := userDAO.ListEmployees("active") // 每用户聚合:积分 / 考试 / 学习进度 type userAgg struct { @@ -159,7 +159,7 @@ func DepartmentStats(c *gin.Context) { for _, e := range employees { get(e.ID).Points = e.LearningPoints } - recs := examRecordRepo.ListAll() + recs := examRecordDAO.ListAll() for _, r := range recs { a := get(r.UserID) a.FormalCount++ @@ -168,7 +168,7 @@ func DepartmentStats(c *gin.Context) { } a.ScoreSum += r.Score } - lps := learningRepo.ListAll() + lps := learningDAO.ListAll() for _, lp := range lps { a := get(lp.UserID) switch lp.ItemType { diff --git a/eai_agentplatform/backend-go/internal/api/exam.go b/eai_agentplatform/backend-go/internal/api/exam.go index ad3d297..ec6e659 100644 --- a/eai_agentplatform/backend-go/internal/api/exam.go +++ b/eai_agentplatform/backend-go/internal/api/exam.go @@ -14,25 +14,25 @@ import ( "github.com/golang-jwt/jwt/v5" "eai_agentplatform/backend/internal/auth" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) // 考试域仓库,包内共享(知识源摄入也会写题目,见 knowledge.go)。 var ( - mistakeRepo repository.MistakeRecordRepo - questionRepo repository.QuestionRepo - paperRepo repository.ExamPaperRepo - examRecordRepo repository.ExamRecordRepo + mistakeDAO dal.MistakeRecordDAO + questionDAO dal.QuestionDAO + paperDAO dal.ExamPaperDAO + examRecordDAO dal.ExamRecordDAO ) func init() { - mistakeRepo = repository.MistakeRecordRepo{} - questionRepo = repository.QuestionRepo{} - paperRepo = repository.ExamPaperRepo{} - examRecordRepo = repository.ExamRecordRepo{} + mistakeDAO = dal.MistakeRecordDAO{} + questionDAO = dal.QuestionDAO{} + paperDAO = dal.ExamPaperDAO{} + examRecordDAO = dal.ExamRecordDAO{} } // Option 题目选项 @@ -84,7 +84,7 @@ func questionView(q model.Question) gin.H { // ListQuestions GET /api/exam/questions?domain=&status= func ListQuestions(c *gin.Context) { // 管理端题库:status 缺省要看到全部(含已停用),按约定传 "all" - items := questionRepo.List(c.Query("domain"), orDefault(c.Query("status"), "all")) + items := questionDAO.List(c.Query("domain"), orDefault(c.Query("status"), "all")) out := make([]gin.H, 0, len(items)) for _, it := range items { out = append(out, questionView(it)) @@ -119,7 +119,7 @@ func CreateQuestion(c *gin.Context) { Explanation: req.Explanation, Status: "active", } - if !questionRepo.Insert(&q) { + if !questionDAO.Insert(&q) { web.Fail(c, web.NewBadRequest("创建题目失败")) return } @@ -132,7 +132,7 @@ func UpdateQuestion(c *gin.Context) { if !ok { return } - q, found := questionRepo.GetByID(id) + q, found := questionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("题目不存在")) return @@ -159,7 +159,7 @@ func UpdateQuestion(c *gin.Context) { q.Options = string(optsJSON) q.Answer = string(ansJSON) q.Explanation = req.Explanation - if !questionRepo.Update(&q) { + if !questionDAO.Update(&q) { web.Fail(c, web.NewBadRequest("更新题目失败")) return } @@ -172,11 +172,11 @@ func DeleteQuestion(c *gin.Context) { if !ok { return } - if _, found := questionRepo.GetByID(id); !found { + if _, found := questionDAO.GetByID(id); !found { web.Fail(c, web.NewNotFoundError("题目不存在")) return } - if !questionRepo.Delete(id) { + if !questionDAO.Delete(id) { web.Fail(c, web.NewBadRequest("停用题目失败")) return } @@ -187,7 +187,7 @@ func DeleteQuestion(c *gin.Context) { // ListPapers GET /api/exam/papers func ListPapers(c *gin.Context) { - web.OK(c, paperRepo.List()) + web.OK(c, paperDAO.List()) } // CreatePaper POST /api/exam/papers (admin) @@ -208,7 +208,7 @@ func CreatePaper(c *gin.Context) { return } p.Status = "active" - if !paperRepo.Insert(&p) { + if !paperDAO.Insert(&p) { web.Fail(c, web.NewBadRequest("创建考试失败")) return } @@ -221,7 +221,7 @@ func UpdatePaper(c *gin.Context) { if !ok { return } - p, found := paperRepo.GetByID(id) + p, found := paperDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("考试配置不存在")) return @@ -253,7 +253,7 @@ func UpdatePaper(c *gin.Context) { if req.Status != "" { p.Status = req.Status } - if !paperRepo.Update(&p) { + if !paperDAO.Update(&p) { web.Fail(c, web.NewBadRequest("更新考试失败")) return } @@ -266,11 +266,11 @@ func DeletePaper(c *gin.Context) { if !ok { return } - if _, found := paperRepo.GetByID(id); !found { + if _, found := paperDAO.GetByID(id); !found { web.Fail(c, web.NewNotFoundError("考试配置不存在")) return } - if !paperRepo.Delete(id) { + if !paperDAO.Delete(id) { web.Fail(c, web.NewBadRequest("停用考试失败")) return } @@ -282,7 +282,7 @@ func DeletePaper(c *gin.Context) { // ExamList GET /api/exam/list —— 我的考试列表(含完成状态) func ExamList(c *gin.Context) { u := middleware.CurrentUser(c) - items := paperRepo.GetActive() + items := paperDAO.GetActive() type row struct { ID uint `json:"id"` @@ -298,7 +298,7 @@ func ExamList(c *gin.Context) { out := make([]row, 0, len(items)) for _, p := range items { st := "available" - if p.Type == "formal" && u != nil && examRecordRepo.HasTaken(u.ID, p.ID) { + if p.Type == "formal" && u != nil && examRecordDAO.HasTaken(u.ID, p.ID) { st = "completed" } out = append(out, row{ @@ -318,7 +318,7 @@ func ExamCover(c *gin.Context) { return } id := uint(id64) - p, found := paperRepo.GetByID(id) + p, found := paperDAO.GetByID(id) if !found || p.Status != "active" { web.Fail(c, web.NewNotFoundError("考试不存在或已停用")) return @@ -351,18 +351,18 @@ func pickQuestions(p model.ExamPaper) ([]model.Question, error) { var courseIDs []uint if p.PositionID != nil { // 岗位考试:优先蓝图,其次岗位知识映射 - if bps := positionRepo.Blueprints(*p.PositionID); len(bps) > 0 { + if bps := positionDAO.Blueprints(*p.PositionID); len(bps) > 0 { return pickQuestionsByBlueprint(p, bps) } // 岗位考试:圈定岗位应学范围 - domains, courseIDs = positionScope(positionRepo.Knowledge(*p.PositionID)) + domains, courseIDs = positionScope(positionDAO.Knowledge(*p.PositionID)) } else { // 原有逻辑:按 exam_paper.domain 抽题 domains = splitDomains(p.Domain) } var qs []model.Question - if !questionRepo.ActivePool(domains, courseIDs).Order("id ASC").Find(&qs) { + if !questionDAO.ActivePool(domains, courseIDs).Order("id ASC").Find(&qs) { return nil, fmt.Errorf("查询题库失败") } if len(qs) < p.QuestionCount { @@ -377,8 +377,8 @@ func pickQuestions(p model.ExamPaper) ([]model.Question, error) { // pickQuestionsByBlueprint 按岗位考试蓝图逐条抽题:先在岗位应学范围内,再按 (domain, type) 细分抽样。 func pickQuestionsByBlueprint(p model.ExamPaper, bps []model.PositionExamBlueprint) ([]model.Question, error) { // 圈定岗位应学范围(与 P0 岗位知识映射抽题一致) - domains, courseIDs := positionScope(positionRepo.Knowledge(*p.PositionID)) - base := questionRepo.ActivePool(domains, courseIDs) + domains, courseIDs := positionScope(positionDAO.Knowledge(*p.PositionID)) + base := questionDAO.ActivePool(domains, courseIDs) out := make([]model.Question, 0, p.QuestionCount) used := map[uint]bool{} @@ -456,12 +456,12 @@ func validatePaperPosition(c *gin.Context, positionID *uint) bool { if positionID == nil { return true } - pos, found := positionRepo.GetByID(*positionID) + pos, found := positionDAO.GetByID(*positionID) if !found || pos.Status != "active" { web.Fail(c, web.NewBadRequest("关联岗位不存在或已停用")) return false } - if positionRepo.CountKnowledge(*positionID) == 0 { + if positionDAO.CountKnowledge(*positionID) == 0 { web.Fail(c, web.NewBadRequest("岗位考试必须先配置岗位知识映射")) return false } @@ -473,7 +473,7 @@ func validatePaperBlueprintCount(c *gin.Context, p model.ExamPaper) bool { if p.PositionID == nil { return true } - bps := positionRepo.Blueprints(*p.PositionID) + bps := positionDAO.Blueprints(*p.PositionID) if len(bps) == 0 { return true } @@ -509,12 +509,12 @@ func ExamStart(c *gin.Context) { web.Fail(c, web.NewBadRequest("paper_id 必填")) return } - p, found := paperRepo.GetByID(req.PaperID) + p, found := paperDAO.GetByID(req.PaperID) if !found || p.Status != "active" { web.Fail(c, web.NewNotFoundError("考试不存在或已停用")) return } - if p.Type == "formal" && u != nil && examRecordRepo.HasTaken(u.ID, p.ID) { + if p.Type == "formal" && u != nil && examRecordDAO.HasTaken(u.ID, p.ID) { web.Fail(c, web.NewConflictError("已参加过该正式考试")) return } @@ -676,7 +676,7 @@ func ExamSubmit(c *gin.Context) { web.Fail(c, web.NewBadRequest("练习会话无题目")) return } - qs := questionRepo.ListByIDs(ids) + qs := questionDAO.ListByIDs(ids) qmap := make(map[uint]model.Question, len(qs)) for _, q := range qs { qmap[q.ID] = q @@ -755,14 +755,14 @@ func ExamSubmit(c *gin.Context) { return } - p, found := paperRepo.GetByID(uint(pid)) + p, found := paperDAO.GetByID(uint(pid)) if !found { web.Fail(c, web.NewNotFoundError("考试不存在")) return } // 正式考不可重复交卷 - if stype == "formal" && u != nil && examRecordRepo.HasTaken(u.ID, p.ID) { + if stype == "formal" && u != nil && examRecordDAO.HasTaken(u.ID, p.ID) { web.Fail(c, web.NewConflictError("已参加过该正式考试")) return } @@ -772,7 +772,7 @@ func ExamSubmit(c *gin.Context) { web.Fail(c, web.NewBadRequest("考试会话无题目")) return } - questions := questionRepo.ListByIDs(ids) + questions := questionDAO.ListByIDs(ids) qmap := make(map[uint]model.Question, len(questions)) for _, q := range questions { qmap[q.ID] = q @@ -867,7 +867,7 @@ func ExamSubmit(c *gin.Context) { CorrectCount: correctCount, WrongCount: wrongCount, DetailJSON: string(detailJSON), SubmittedAt: time.Now(), } - examRecordRepo.Insert(&rec) + examRecordDAO.Insert(&rec) if passed { awardPoints(u.ID, "formal_pass", ptFormalPass, "paper", p.ID) issueCertificate(u, rec) @@ -897,7 +897,7 @@ func splitIDs(s string) []uint { // ExamRecordList GET /api/exam/record?page=&size= —— 我的考试记录 func ExamRecordList(c *gin.Context) { u := middleware.CurrentUser(c) - items := examRecordRepo.ListByUser(u.ID) + items := examRecordDAO.ListByUser(u.ID) if items == nil { items = []model.ExamRecord{} } @@ -911,7 +911,7 @@ func ExamRecordDetail(c *gin.Context) { if !ok { return } - rec, found := examRecordRepo.GetByID(id) + rec, found := examRecordDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("考试记录不存在")) return @@ -947,7 +947,7 @@ func mistakePayload(userID, questionID uint, source string, q model.Question, us // recordMistake 答错入本:按 (user_id, question_id, source) 去重,再次答错则更新并重置为未掌握。 func recordMistake(userID, questionID uint, q model.Question, userAns any, correct []string, source string) { - mistakeRepo.RecordWrong(mistakePayload(userID, questionID, source, q, userAns, correct)) + mistakeDAO.RecordWrong(mistakePayload(userID, questionID, source, q, userAns, correct)) } // mistakeView 错题出参(answer 反序列化,便于前端直接展示) @@ -967,7 +967,7 @@ type mistakeView struct { // MyMistakes GET /api/exam/mistakes —— 我的错题本 func MyMistakes(c *gin.Context) { u := middleware.CurrentUser(c) - items := mistakeRepo.ListByUser(u.ID) + items := mistakeDAO.ListByUser(u.ID) out := make([]mistakeView, 0, len(items)) for _, it := range items { var userAns any @@ -994,7 +994,7 @@ func ResolveMistake(c *gin.Context) { if !ok { return } - rec, found := mistakeRepo.GetByID(id) + rec, found := mistakeDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("错题记录不存在")) return @@ -1013,7 +1013,7 @@ func ResolveMistake(c *gin.Context) { } wasResolved := rec.Resolved rec.Resolved = target - if !mistakeRepo.Update(&rec) { + if !mistakeDAO.Update(&rec) { web.Fail(c, web.NewBadRequest("更新错题状态失败")) return } @@ -1037,7 +1037,7 @@ func MistakePractice(c *gin.Context) { } _ = c.ShouldBindJSON(&req) - recs := mistakeRepo.ListForPractice(u.ID, req.Source, req.OnlyUnresolved) + recs := mistakeDAO.ListForPractice(u.ID, req.Source, req.OnlyUnresolved) if len(recs) == 0 { web.Fail(c, web.NewBadRequest("暂无可重练的错题")) return @@ -1050,7 +1050,7 @@ func MistakePractice(c *gin.Context) { ids = dedupeUints(ids) // 剔除已停用/删除的题目,仅下发可作答题目 - questions := questionRepo.ListActiveByIDs(ids) + questions := questionDAO.ListActiveByIDs(ids) if len(questions) == 0 { web.Fail(c, web.NewBadRequest("错题对应题目已失效,暂无可重练题目")) return @@ -1101,11 +1101,11 @@ func MistakePractice(c *gin.Context) { // touchMistakeOnPractice 错题重练判分后同步错题状态:答对置为已掌握(加积分),答错重置为未掌握。 func touchMistakeOnPractice(userID, questionID uint, q model.Question, userAns any, correct []string, resolved bool) { payload := mistakePayload(userID, questionID, "", q, userAns, correct) - flipped, touched := mistakeRepo.TouchOnPractice(payload, resolved) + flipped, touched := mistakeDAO.TouchOnPractice(payload, resolved) if !touched { // 防御性兜底:理论上重练题目均来自错题本,这里创建一条 payload.Source = "re_practice" - mistakeRepo.RecordWrong(payload) + mistakeDAO.RecordWrong(payload) return } // 仅在「未掌握 → 已掌握」时加分,避免反复重练刷分 diff --git a/eai_agentplatform/backend-go/internal/api/knowledge.go b/eai_agentplatform/backend-go/internal/api/knowledge.go index b7658e8..4277d2d 100644 --- a/eai_agentplatform/backend-go/internal/api/knowledge.go +++ b/eai_agentplatform/backend-go/internal/api/knowledge.go @@ -11,17 +11,17 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// sourceRepo 知识源仓库(便于测试时覆写),包内共享。 -var sourceRepo repository.KnowledgeSourceRepo +// sourceDAO 知识源仓库(便于测试时覆写),包内共享。 +var sourceDAO dal.KnowledgeSourceDAO func init() { - sourceRepo = repository.KnowledgeSourceRepo{} + sourceDAO = dal.KnowledgeSourceDAO{} } // ============ 扫描 ============ @@ -51,7 +51,7 @@ func KnowledgeScan(c *gin.Context) { continue // 非知识源文档,跳过 } - if existing, found := sourceRepo.GetByFilePath(e.Name()); found { + if existing, found := sourceDAO.GetByFilePath(e.Name()); found { results = append(results, gin.H{"file_path": e.Name(), "status": "skipped", "title": existing.Title}) continue } @@ -64,7 +64,7 @@ func KnowledgeScan(c *gin.Context) { AuditStatus: "pending", KnowledgeSpaceKey: ensureKnowledgeSpaceKeyOrDefault(orDefault(fm["knowledge_space_key"], inferKnowledgeSpaceKey(parseTitle(string(data)), fm["domain"], fm["category"]+" "+e.Name()))), } - if !sourceRepo.Insert(&src) { + if !sourceDAO.Insert(&src) { results = append(results, gin.H{"file_path": e.Name(), "status": "error", "title": src.Title}) continue } @@ -83,7 +83,7 @@ func KnowledgeAuditList(c *gin.Context) { if size < 1 || size > 100 { size = 20 } - total, items := sourceRepo.ListForAudit( + total, items := sourceDAO.ListForAudit( c.Query("status"), sanitizeSpaceKey(c.Query("knowledge_space_key")), page, size) web.OK(c, gin.H{"total": total, "items": items}) } @@ -95,7 +95,7 @@ func KnowledgeAudit(c *gin.Context) { if !ok { return } - src, found := sourceRepo.GetByID(id) + src, found := sourceDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("知识源不存在")) return @@ -126,7 +126,7 @@ func KnowledgeAudit(c *gin.Context) { src.AuditAt = &now src.RejectReason = "" src.Ingested = true - if !sourceRepo.Update(&src) { + if !sourceDAO.Update(&src) { web.Fail(c, web.NewBadRequest("审批失败")) return } @@ -144,7 +144,7 @@ func KnowledgeAudit(c *gin.Context) { src.RejectReason = req.RejectReason src.AuditBy = &auditBy src.AuditAt = &now - if !sourceRepo.Update(&src) { + if !sourceDAO.Update(&src) { web.Fail(c, web.NewBadRequest("审批失败")) return } @@ -160,7 +160,7 @@ func KnowledgeStatus(c *gin.Context) { if !ok { return } - src, found := sourceRepo.GetByID(id) + src, found := sourceDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("知识源不存在")) return @@ -335,12 +335,12 @@ func ingestSource(src *model.KnowledgeSource) ([3]int, error) { ReportRules: kv["report_rules"], Status: "active", } - if existing, found := productRepo.GetByCode(p.Code); found { + if existing, found := productDAO.GetByCode(p.Code); found { p.ID = existing.ID p.CreatedAt = existing.CreatedAt // Save 整字段覆盖,不回填会把创建时间写成零值 - productRepo.Update(&p) + productDAO.Update(&p) } else { - productRepo.Insert(&p) + productDAO.Insert(&p) } counts[0]++ } @@ -351,7 +351,7 @@ func ingestSource(src *model.KnowledgeSource) ([3]int, error) { if text == "" { continue } - chunkRepo.Insert(&model.KnowledgeChunk{ + chunkDAO.Insert(&model.KnowledgeChunk{ KnowledgeSourceID: &src.ID, SourceType: "md", SourceID: strconv.FormatUint(uint64(src.ID), 10), @@ -383,7 +383,7 @@ func ingestSource(src *model.KnowledgeSource) ([3]int, error) { Explanation: kv["explanation"], Status: "active", } - questionRepo.Insert(&q) + questionDAO.Insert(&q) counts[2]++ } diff --git a/eai_agentplatform/backend-go/internal/api/knowledge_faq.go b/eai_agentplatform/backend-go/internal/api/knowledge_faq.go index a26672b..1708647 100644 --- a/eai_agentplatform/backend-go/internal/api/knowledge_faq.go +++ b/eai_agentplatform/backend-go/internal/api/knowledge_faq.go @@ -7,16 +7,16 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// faqRepo FAQ 仓库(便于测试时覆写),包内共享。 -var faqRepo repository.KnowledgeFAQRepo +// faqDAO FAQ 仓库(便于测试时覆写),包内共享。 +var faqDAO dal.KnowledgeFAQDAO func init() { - faqRepo = repository.KnowledgeFAQRepo{} + faqDAO = dal.KnowledgeFAQDAO{} } // ListKnowledgeFAQs GET /api/knowledge/faqs?knowledge_space_key=&status=&keyword=&page=&size= @@ -29,7 +29,7 @@ func ListKnowledgeFAQs(c *gin.Context) { if size < 1 || size > 100 { size = 20 } - total, items := faqRepo.ListForAdmin( + total, items := faqDAO.ListForAdmin( sanitizeSpaceKey(c.Query("knowledge_space_key")), strings.TrimSpace(c.Query("status")), strings.TrimSpace(c.Query("keyword")), @@ -71,7 +71,7 @@ func CreateKnowledgeFAQ(c *gin.Context) { Status: orDefault(strings.TrimSpace(req.Status), "active"), SortOrder: req.SortOrder, } - if !faqRepo.Insert(&faq) { + if !faqDAO.Insert(&faq) { web.Fail(c, web.NewBadRequest("创建 FAQ 失败")) return } @@ -84,7 +84,7 @@ func UpdateKnowledgeFAQ(c *gin.Context) { if !ok { return } - faq, found := faqRepo.GetByID(id) + faq, found := faqDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("FAQ 不存在")) return @@ -116,7 +116,7 @@ func UpdateKnowledgeFAQ(c *gin.Context) { faq.Keywords = strings.Join(cleanStringList(req.Keywords), ",") faq.Status = orDefault(strings.TrimSpace(req.Status), "active") faq.SortOrder = req.SortOrder - if !faqRepo.Update(&faq) { + if !faqDAO.Update(&faq) { web.Fail(c, web.NewBadRequest("更新 FAQ 失败")) return } @@ -129,11 +129,11 @@ func DeleteKnowledgeFAQ(c *gin.Context) { if !ok { return } - if _, found := faqRepo.GetByID(id); !found { + if _, found := faqDAO.GetByID(id); !found { web.Fail(c, web.NewNotFoundError("FAQ 不存在")) return } - if !faqRepo.Delete(id) { + if !faqDAO.Delete(id) { web.Fail(c, web.NewBadRequest("删除 FAQ 失败")) return } diff --git a/eai_agentplatform/backend-go/internal/api/knowledge_index.go b/eai_agentplatform/backend-go/internal/api/knowledge_index.go index 20b104d..44b4afe 100644 --- a/eai_agentplatform/backend-go/internal/api/knowledge_index.go +++ b/eai_agentplatform/backend-go/internal/api/knowledge_index.go @@ -47,10 +47,10 @@ func rebuildKnowledgeIndexNow() (int, error) { func buildKnowledgeIndexItems() []ai.KnowledgeIndexItem { var chunks []model.KnowledgeChunk - chunkRepo.Type(&chunks).Order("id ASC").Find(&chunks) + chunkDAO.Type(&chunks).Order("id ASC").Find(&chunks) // 与 AI 检索候选共用同一份「已审批」映射,避免两处过滤条件漂移。 - mediaMap, sourceMap := chunkRepo.ApprovedMetaMaps() + mediaMap, sourceMap := chunkDAO.ApprovedMetaMaps() items := make([]ai.KnowledgeIndexItem, 0, len(chunks)) for _, chunk := range chunks { diff --git a/eai_agentplatform/backend-go/internal/api/knowledge_pipeline.go b/eai_agentplatform/backend-go/internal/api/knowledge_pipeline.go index 735c131..b798445 100644 --- a/eai_agentplatform/backend-go/internal/api/knowledge_pipeline.go +++ b/eai_agentplatform/backend-go/internal/api/knowledge_pipeline.go @@ -175,7 +175,7 @@ func extractKnowledgeSpaceKey(ctx map[string]any) string { } func matchKnowledgeFAQ(query, spaceKey string) (model.KnowledgeFAQ, bool) { - faqs := faqRepo.ActiveCandidates(sanitizeSpaceKey(spaceKey)) + faqs := faqDAO.ActiveCandidates(sanitizeSpaceKey(spaceKey)) queryNorm := normalizeQuestion(query) queryTerms := buildSearchTerms(query) bestScore := 0 @@ -190,7 +190,7 @@ func matchKnowledgeFAQ(query, spaceKey string) (model.KnowledgeFAQ, bool) { if bestScore < 70 { return model.KnowledgeFAQ{}, false } - faqRepo.IncrHit(best.ID) + faqDAO.IncrHit(best.ID) return best, true } @@ -295,10 +295,10 @@ type retrievalScore struct { func loadKnowledgeCandidates(spaceKey string) []knowledgeCandidate { var chunks []model.KnowledgeChunk - chunkRepo.Type(&chunks).Order("id ASC").Find(&chunks) + chunkDAO.Type(&chunks).Order("id ASC").Find(&chunks) // 必须传入真实的已审批映射:resolveChunkMeta 查不到就丢分片, // 传空 map 会让所有挂素材/知识源的分片消失,AI 检索候选集只剩无指针分片。 - mediaMap, sourceMap := chunkRepo.ApprovedMetaMaps() + mediaMap, sourceMap := chunkDAO.ApprovedMetaMaps() out := make([]knowledgeCandidate, 0, len(chunks)) for _, chunk := range chunks { title, resolvedSpace, ok := resolveChunkMeta(chunk, mediaMap, sourceMap) diff --git a/eai_agentplatform/backend-go/internal/api/knowledge_space.go b/eai_agentplatform/backend-go/internal/api/knowledge_space.go index d84da1d..d32f012 100644 --- a/eai_agentplatform/backend-go/internal/api/knowledge_space.go +++ b/eai_agentplatform/backend-go/internal/api/knowledge_space.go @@ -8,19 +8,19 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) var ( - spaceRepo repository.KnowledgeSpaceRepo - chunkRepo repository.KnowledgeChunkRepo + spaceDAO dal.KnowledgeSpaceDAO + chunkDAO dal.KnowledgeChunkDAO ) func init() { - spaceRepo = repository.KnowledgeSpaceRepo{} - chunkRepo = repository.KnowledgeChunkRepo{} + spaceDAO = dal.KnowledgeSpaceDAO{} + chunkDAO = dal.KnowledgeChunkDAO{} } type spaceMetrics struct { @@ -88,7 +88,7 @@ func CreateKnowledgeSpace(c *gin.Context) { Status: orDefault(strings.TrimSpace(req.Status), "active"), SortOrder: req.SortOrder, } - if spaceRepo.Insert(&space) { + if spaceDAO.Insert(&space) { web.OK(c, gin.H{"item": space}) return } @@ -101,7 +101,7 @@ func UpdateKnowledgeSpace(c *gin.Context) { if !ok { return } - space, found := spaceRepo.GetByID(id) + space, found := spaceDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("知识空间不存在")) return @@ -128,7 +128,7 @@ func UpdateKnowledgeSpace(c *gin.Context) { space.Status = strings.TrimSpace(req.Status) } space.SortOrder = req.SortOrder - if !spaceRepo.Update(&space) { + if !spaceDAO.Update(&space) { web.Fail(c, web.NewBadRequest("更新知识空间失败")) return } @@ -141,7 +141,7 @@ func DeleteKnowledgeSpace(c *gin.Context) { if !ok { return } - space, found := spaceRepo.GetByID(id) + space, found := spaceDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("知识空间不存在")) return @@ -150,7 +150,7 @@ func DeleteKnowledgeSpace(c *gin.Context) { web.Fail(c, web.NewConflictError("默认知识空间不可删除")) return } - if !spaceRepo.Type(&model.KnowledgeSpace{}).Where("id = ?", id).Delete(&model.KnowledgeSpace{}) { + if !spaceDAO.Type(&model.KnowledgeSpace{}).Where("id = ?", id).Delete(&model.KnowledgeSpace{}) { web.Fail(c, web.NewBadRequest("删除知识空间失败")) return } @@ -172,13 +172,13 @@ func SearchKnowledge(c *gin.Context) { } var chunks []model.KnowledgeChunk - chunkQuery := repository.DB.Model(&model.KnowledgeChunk{}).Order("created_at DESC") + chunkQuery := dal.DB.Model(&model.KnowledgeChunk{}).Order("created_at DESC") if spaceKey != "" { chunkQuery = chunkQuery.Where("knowledge_space_key = ? OR knowledge_space_key = '' OR knowledge_space_key IS NULL", spaceKey) } chunkQuery.Limit(400).Find(&chunks) - // 这里刻意不用 chunkRepo.ApprovedMetaMaps():本站已把分片限制在 400 条内, + // 这里刻意不用 chunkDAO.ApprovedMetaMaps():本站已把分片限制在 400 条内, // 按需只取被引用到的素材/知识源,比整表加载已审批记录更省。 // 未命中审批状态的记录由 resolveChunkMeta 兜底拦掉,语义与那份批量映射一致。 mediaMap := map[uint]model.MediaFile{} @@ -186,14 +186,14 @@ func SearchKnowledge(c *gin.Context) { for _, chunk := range chunks { if chunk.MediaFileID != nil { if _, ok := mediaMap[*chunk.MediaFileID]; !ok { - if m, ok := mediaRepo.GetByID(*chunk.MediaFileID); ok { + if m, ok := mediaDAO.GetByID(*chunk.MediaFileID); ok { mediaMap[*chunk.MediaFileID] = m } } } if chunk.KnowledgeSourceID != nil { if _, ok := sourceMap[*chunk.KnowledgeSourceID]; !ok { - if s, ok := sourceRepo.GetByID(*chunk.KnowledgeSourceID); ok { + if s, ok := sourceDAO.GetByID(*chunk.KnowledgeSourceID); ok { sourceMap[*chunk.KnowledgeSourceID] = s } } @@ -265,18 +265,18 @@ func listKnowledgeSpacesWithMetrics() ([]model.KnowledgeSpace, map[string]spaceM return nil, nil, err } var spaces []model.KnowledgeSpace - spaceRepo.Type(&model.KnowledgeSpace{}).Order("sort_order ASC, id ASC").Find(&spaces) + spaceDAO.Type(&model.KnowledgeSpace{}).Order("sort_order ASC, id ASC").Find(&spaces) metrics, err := buildKnowledgeSpaceMetrics() return spaces, metrics, err } func ensureDefaultKnowledgeSpaces() error { for _, item := range defaultKnowledgeSpaces { - _, found := spaceRepo.GetByName(item.Key) + _, found := spaceDAO.GetByName(item.Key) if found { continue } - spaceRepo.Insert(&item) + spaceDAO.Insert(&item) } return nil } @@ -288,9 +288,9 @@ func buildKnowledgeSpaceMetrics() (map[string]spaceMetrics, error) { } // 这里要的是「全量已审批素材」,与 ListForAudit 的分页/排序口径不同, - // 单个调用点不值得再加一个仓库方法,直接用包级 mediaRepo 取。 + // 单个调用点不值得再加一个仓库方法,直接用包级 mediaDAO 取。 var mediaFiles []model.MediaFile - mediaRepo.Type(&model.MediaFile{}).Where("status = ?", "approved").Find(&mediaFiles) + mediaDAO.Type(&model.MediaFile{}).Where("status = ?", "approved").Find(&mediaFiles) for _, f := range mediaFiles { key := resolveMediaKnowledgeSpaceKey(f) m := metrics[key] @@ -303,7 +303,7 @@ func buildKnowledgeSpaceMetrics() (map[string]spaceMetrics, error) { } } - sources := sourceRepo.ListApproved() + sources := sourceDAO.ListApproved() for _, s := range sources { key := resolveKnowledgeSourceSpaceKey(s) m := metrics[key] @@ -317,15 +317,15 @@ func buildKnowledgeSpaceMetrics() (map[string]spaceMetrics, error) { } var chunks []model.KnowledgeChunk - repository.DB.Find(&chunks) + dal.DB.Find(&chunks) for _, chunk := range chunks { key := ensureKnowledgeSpaceKeyOrDefault(chunk.KnowledgeSpaceKey) if chunk.KnowledgeSourceID != nil { - if src, ok := sourceRepo.GetByID(*chunk.KnowledgeSourceID); ok { + if src, ok := sourceDAO.GetByID(*chunk.KnowledgeSourceID); ok { key = resolveKnowledgeSourceSpaceKey(src) } } else if chunk.MediaFileID != nil { - if media, ok := mediaRepo.GetByID(*chunk.MediaFileID); ok { + if media, ok := mediaDAO.GetByID(*chunk.MediaFileID); ok { key = resolveMediaKnowledgeSpaceKey(media) } } else if key == "general" { @@ -349,7 +349,7 @@ func getKnowledgeSpaceDisplayName(key string) string { return item.Name } } - if space, ok := spaceRepo.GetByName(key); ok && strings.TrimSpace(space.Name) != "" { + if space, ok := spaceDAO.GetByName(key); ok && strings.TrimSpace(space.Name) != "" { return space.Name } return key @@ -394,7 +394,7 @@ func ensureKnowledgeSpaceKeyOrDefault(key string) string { } } } - _, ok := spaceRepo.GetByName(key) + _, ok := spaceDAO.GetByName(key) if ok { return key } diff --git a/eai_agentplatform/backend-go/internal/api/learning.go b/eai_agentplatform/backend-go/internal/api/learning.go index dbbd946..48920e7 100644 --- a/eai_agentplatform/backend-go/internal/api/learning.go +++ b/eai_agentplatform/backend-go/internal/api/learning.go @@ -5,17 +5,17 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// learningRepo 学习进度仓库(便于测试时覆写),包内共享。 -var learningRepo repository.LearningProgressRepo +// learningDAO 学习进度仓库(便于测试时覆写),包内共享。 +var learningDAO dal.LearningProgressDAO func init() { - learningRepo = repository.LearningProgressRepo{} + learningDAO = dal.LearningProgressDAO{} } var validItemTypes = map[string]bool{"company": true, "product": true, "course": true} @@ -40,15 +40,15 @@ func RecordLearningProgress(c *gin.Context) { } lp := model.LearningProgress{UserID: u.ID, ItemType: req.ItemType, ItemID: req.ItemID} // 幂等:已存在则仅刷新 updated_at;首次记录才加分(避免重复刷分) - if _, exists := learningRepo.Get(u.ID, req.ItemType, req.ItemID); !exists { - if !learningRepo.Insert(&lp) { + if _, exists := learningDAO.Get(u.ID, req.ItemType, req.ItemID); !exists { + if !learningDAO.Insert(&lp) { web.Fail(c, web.NewBadRequest("记录学习进度失败")) return } awardFirstView(u.ID, req.ItemType, req.ItemID) } else { // Upsert 命中已存在分支时只刷新 updated_at,不新增行 - learningRepo.Upsert(&lp) + learningDAO.Upsert(&lp) } web.OK(c, gin.H{"recorded": true, "item_type": req.ItemType, "item_id": req.ItemID}) } @@ -60,7 +60,7 @@ func MyLearningProgress(c *gin.Context) { web.Fail(c, web.NewAuthError("未登录")) return } - items := learningRepo.ListByUser(u.ID) + items := learningDAO.ListByUser(u.ID) if items == nil { items = []model.LearningProgress{} } @@ -70,8 +70,8 @@ func MyLearningProgress(c *gin.Context) { // AdminLearningProgress GET /api/system/learning-progress —— 全员学习进度(管理员) func AdminLearningProgress(c *gin.Context) { // 管理端全员视图:不限状态,已停用的员工也要能看到其历史进度 - employees := userRepo.ListEmployees("") - items := learningRepo.ListAll() + employees := userDAO.ListEmployees("") + items := learningDAO.ListAll() type agg struct { CompanyViewed bool `json:"company_viewed"` diff --git a/eai_agentplatform/backend-go/internal/api/media.go b/eai_agentplatform/backend-go/internal/api/media.go index 546707d..ed9b624 100644 --- a/eai_agentplatform/backend-go/internal/api/media.go +++ b/eai_agentplatform/backend-go/internal/api/media.go @@ -16,17 +16,17 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// mediaRepo 素材仓库(便于测试时覆写),包内共享。 -var mediaRepo repository.MediaFileRepo +// mediaDAO 素材仓库(便于测试时覆写),包内共享。 +var mediaDAO dal.MediaFileDAO func init() { - mediaRepo = repository.MediaFileRepo{} + mediaDAO = dal.MediaFileDAO{} } var blockedUploadExt = map[string]bool{ @@ -196,7 +196,7 @@ func Upload(c *gin.Context) { BindID: bindID, KnowledgeSpaceKey: knowledgeSpaceKey, } - if !mediaRepo.Insert(&m) { + if !mediaDAO.Insert(&m) { web.Fail(c, web.NewBadRequest("创建素材记录失败")) return } @@ -387,7 +387,7 @@ func UploadComplete(c *gin.Context) { Source: source, SubmitterID: u.ID, BindType: sess.BindType, BindID: sess.BindID, KnowledgeSpaceKey: sess.KnowledgeSpaceKey, } - if !mediaRepo.Insert(&m) { + if !mediaDAO.Insert(&m) { web.Fail(c, web.NewBadRequest("创建素材记录失败")) return } @@ -405,7 +405,7 @@ func Preview(c *gin.Context) { if !ok { return } - m, found := mediaRepo.GetByID(id) + m, found := mediaDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("素材不存在")) return @@ -427,7 +427,7 @@ func MediaStatus(c *gin.Context) { if !ok { return } - m, found := mediaRepo.GetByID(id) + m, found := mediaDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("素材不存在")) return @@ -435,7 +435,7 @@ func MediaStatus(c *gin.Context) { web.OK(c, gin.H{ "status": m.Status, "extracted": m.Extracted, - "chunk_count": chunkRepo.CountByMediaFile(m.ID), + "chunk_count": chunkDAO.CountByMediaFile(m.ID), "knowledge_space_key": m.KnowledgeSpaceKey, }) } @@ -452,7 +452,7 @@ func AuditList(c *gin.Context) { if size < 1 || size > 100 { size = 20 } - total, items := mediaRepo.ListForAudit( + total, items := mediaDAO.ListForAudit( c.Query("status"), sanitizeSpaceKey(c.Query("knowledge_space_key")), page, size) web.OK(c, gin.H{"total": total, "items": items}) } @@ -464,7 +464,7 @@ func AuditMedia(c *gin.Context) { if !ok { return } - m, found := mediaRepo.GetByID(id) + m, found := mediaDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("素材不存在")) return @@ -524,7 +524,7 @@ func AuditMedia(c *gin.Context) { web.Fail(c, web.NewBadRequest("action 必须为 approve 或 reject")) return } - if !mediaRepo.Update(&m) { + if !mediaDAO.Update(&m) { web.Fail(c, web.NewBadRequest("审批失败")) return } @@ -538,7 +538,7 @@ func AuditMedia(c *gin.Context) { // runExtractPipeline 审批通过后:文档转 PDF → pdftotext → 切片入库 func runExtractPipeline(mediaID uint) { - m, found := mediaRepo.GetByID(mediaID) + m, found := mediaDAO.GetByID(mediaID) if !found { return } @@ -554,7 +554,7 @@ func runExtractPipeline(mediaID uint) { text, err = pdftotextExtract(src) default: // 视频/图片:仅标记,不提取 - mediaRepo.MarkExtracted(m.ID) + mediaDAO.MarkExtracted(m.ID) return } if err != nil { @@ -579,8 +579,8 @@ func runExtractPipeline(mediaID uint) { Content: chunk, }) } - chunkRepo.BulkInsert(items) - mediaRepo.MarkExtracted(m.ID) + chunkDAO.BulkInsert(items) + mediaDAO.MarkExtracted(m.ID) triggerKnowledgeIndexRebuild() log.Printf("[提取完成] media_id=%d chunks=%d", mediaID, len(chunks)) } diff --git a/eai_agentplatform/backend-go/internal/api/my_task.go b/eai_agentplatform/backend-go/internal/api/my_task.go index 23d5703..7b90faf 100644 --- a/eai_agentplatform/backend-go/internal/api/my_task.go +++ b/eai_agentplatform/backend-go/internal/api/my_task.go @@ -38,7 +38,7 @@ func ListMyTasks(c *gin.Context) { } // 置顶的排在前面,其余按最近动过的排 —— 置顶只是一个排序偏好。 - web.OK(c, taskRecordRepo.ListByOwners(specialistruntime.MyTaskOwners(user), 50)) + web.OK(c, taskRecordDAO.ListByOwners(specialistruntime.MyTaskOwners(user), 50)) } // DeleteMyTask 彻底删掉一条任务。task_record 没有软删字段,删了就是删了 —— @@ -54,12 +54,12 @@ func DeleteMyTask(c *gin.Context) { return } - task, found := taskRecordRepo.GetByIDForOwners(id, specialistruntime.MyTaskOwners(user)) + task, found := taskRecordDAO.GetByIDForOwners(id, specialistruntime.MyTaskOwners(user)) if !found { web.Fail(c, web.NewNotFoundError("任务不存在")) return } - if !taskRecordRepo.Delete(&task) { + if !taskRecordDAO.Delete(&task) { web.Fail(c, web.NewBadRequest("删除任务失败")) return } @@ -85,7 +85,7 @@ func CreateMyTask(c *gin.Context) { if specialistKey == "" { specialistKey = generalAssistantKey } - specialist, found := specialistRepo.GetByKey(specialistKey) + specialist, found := specialistDAO.GetByKey(specialistKey) if !found { web.Fail(c, web.NewNotFoundError("专员不存在")) return @@ -113,7 +113,7 @@ func CreateMyTask(c *gin.Context) { task.Status = "待处理" } - if !taskRecordRepo.Insert(&task) { + if !taskRecordDAO.Insert(&task) { web.Fail(c, web.NewBadRequest("创建任务失败")) return } @@ -133,7 +133,7 @@ func UpdateMyTask(c *gin.Context) { } owners := specialistruntime.MyTaskOwners(user) - task, found := taskRecordRepo.GetByIDForOwners(id, owners) + task, found := taskRecordDAO.GetByIDForOwners(id, owners) if !found { web.Fail(c, web.NewNotFoundError("任务不存在")) return @@ -149,7 +149,7 @@ func UpdateMyTask(c *gin.Context) { task.Title = title } if key := strings.TrimSpace(req.SpecialistKey); key != "" && key != task.SpecialistKey { - specialist, ok := specialistRepo.GetByKey(key) + specialist, ok := specialistDAO.GetByKey(key) if !ok { web.Fail(c, web.NewNotFoundError("目标专员不存在")) return @@ -164,7 +164,7 @@ func UpdateMyTask(c *gin.Context) { if *req.ProjectID == 0 { task.ProjectID = nil } else { - project, ok := projectRepo.GetByIDForOwners(*req.ProjectID, owners) + project, ok := projectDAO.GetByIDForOwners(*req.ProjectID, owners) if !ok { web.Fail(c, web.NewNotFoundError("项目不存在")) return @@ -176,7 +176,7 @@ func UpdateMyTask(c *gin.Context) { task.Pinned = *req.Pinned } - if !taskRecordRepo.Update(&task) { + if !taskRecordDAO.Update(&task) { web.Fail(c, web.NewBadRequest("更新任务失败")) return } diff --git a/eai_agentplatform/backend-go/internal/api/note.go b/eai_agentplatform/backend-go/internal/api/note.go index ee0e0cd..1125b77 100644 --- a/eai_agentplatform/backend-go/internal/api/note.go +++ b/eai_agentplatform/backend-go/internal/api/note.go @@ -6,17 +6,17 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// noteRepo 学习笔记仓库(便于测试时覆写),包内共享。 -var noteRepo repository.StudyNoteRepo +// noteDAO 学习笔记仓库(便于测试时覆写),包内共享。 +var noteDAO dal.StudyNoteDAO func init() { - noteRepo = repository.StudyNoteRepo{} + noteDAO = dal.StudyNoteDAO{} } var validNoteItemTypes = map[string]bool{"company": true, "product": true, "course": true} @@ -37,7 +37,7 @@ func ListNotes(c *gin.Context) { itemID = &id } } - web.OK(c, noteRepo.ListByUser(u.ID, c.Query("item_type"), itemID)) + web.OK(c, noteDAO.ListByUser(u.ID, c.Query("item_type"), itemID)) } // CreateNote POST /api/notes —— 新增学习笔记 @@ -65,7 +65,7 @@ func CreateNote(c *gin.Context) { return } n := model.StudyNote{UserID: u.ID, ItemType: req.ItemType, ItemID: req.ItemID, Content: strings.TrimSpace(req.Content)} - if !noteRepo.Insert(&n) { + if !noteDAO.Insert(&n) { web.Fail(c, web.NewBadRequest("保存笔记失败")) return } @@ -83,7 +83,7 @@ func UpdateNote(c *gin.Context) { if !ok { return } - n, found := noteRepo.GetByID(id) + n, found := noteDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("笔记不存在")) return @@ -104,7 +104,7 @@ func UpdateNote(c *gin.Context) { return } n.Content = strings.TrimSpace(req.Content) - if !noteRepo.Update(&n) { + if !noteDAO.Update(&n) { web.Fail(c, web.NewBadRequest("更新笔记失败")) return } @@ -122,7 +122,7 @@ func DeleteNote(c *gin.Context) { if !ok { return } - n, found := noteRepo.GetByID(id) + n, found := noteDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("笔记不存在")) return @@ -131,7 +131,7 @@ func DeleteNote(c *gin.Context) { web.Fail(c, web.NewForbiddenError("无权操作他人笔记")) return } - if !noteRepo.Delete(&n) { + if !noteDAO.Delete(&n) { web.Fail(c, web.NewBadRequest("删除笔记失败")) return } diff --git a/eai_agentplatform/backend-go/internal/api/position.go b/eai_agentplatform/backend-go/internal/api/position.go index cd809e5..fc7113c 100644 --- a/eai_agentplatform/backend-go/internal/api/position.go +++ b/eai_agentplatform/backend-go/internal/api/position.go @@ -3,27 +3,27 @@ package api import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) var ( - positionRepo repository.PositionRepo - courseRepo repository.CourseRepo // productRepo 定义在 products.go + positionDAO dal.PositionDAO + courseDAO dal.CourseDAO // productDAO 定义在 products.go ) func init() { - positionRepo = repository.PositionRepo{} - courseRepo = repository.CourseRepo{} + positionDAO = dal.PositionDAO{} + courseDAO = dal.CourseDAO{} } // ============ 岗位 CRUD(管理员) ============ // ListPositions GET /api/positions?status= —— 岗位列表 func ListPositions(c *gin.Context) { - items := positionRepo.List(c.Query("status")) + items := positionDAO.List(c.Query("status")) web.OK(c, items) } @@ -41,11 +41,11 @@ func CreatePosition(c *gin.Context) { if p.Status == "" { p.Status = "active" } - if positionRepo.CountByName(p.Code, nil) > 0 { + if positionDAO.CountByName(p.Code, nil) > 0 { web.Fail(c, web.NewConflictError("岗位编号已存在")) return } - if !positionRepo.Insert(&p) { + if !positionDAO.Insert(&p) { web.Fail(c, web.NewBadRequest("创建岗位失败")) return } @@ -58,7 +58,7 @@ func UpdatePosition(c *gin.Context) { if !ok { return } - p, found := positionRepo.GetByID(id) + p, found := positionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("岗位不存在")) return @@ -76,7 +76,7 @@ func UpdatePosition(c *gin.Context) { req.Status = "active" } if req.Code != "" && req.Code != p.Code { - if positionRepo.CountByName(req.Code, &id) > 0 { + if positionDAO.CountByName(req.Code, &id) > 0 { web.Fail(c, web.NewConflictError("岗位编号已存在")) return } @@ -85,7 +85,7 @@ func UpdatePosition(c *gin.Context) { p.Name = req.Name p.Description = req.Description p.Status = req.Status - if !positionRepo.Update(&p) { + if !positionDAO.Update(&p) { web.Fail(c, web.NewBadRequest("更新岗位失败")) return } @@ -98,7 +98,7 @@ func DeletePosition(c *gin.Context) { if !ok { return } - if !positionRepo.Delete(id) { + if !positionDAO.Delete(id) { web.Fail(c, web.NewBadRequest("停用岗位失败")) return } @@ -138,7 +138,7 @@ func ListPositionKnowledge(c *gin.Context) { if !ok { return } - items := positionRepo.Knowledge(id) + items := positionDAO.Knowledge(id) if items == nil { items = []model.PositionKnowledge{} } @@ -151,7 +151,7 @@ func SavePositionKnowledge(c *gin.Context) { if !ok { return } - _, found := positionRepo.GetByID(id) + _, found := positionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("岗位不存在")) return @@ -191,11 +191,11 @@ func SavePositionKnowledge(c *gin.Context) { }) } // 整表覆盖:先删旧,再批量插入 - if !positionRepo.ReplaceKnowledge(id, rows) { + if !positionDAO.ReplaceKnowledge(id, rows) { web.Fail(c, web.NewBadRequest("保存岗位知识映射失败")) return } - out := positionRepo.Knowledge(id) + out := positionDAO.Knowledge(id) if out == nil { out = []model.PositionKnowledge{} } @@ -210,7 +210,7 @@ func SetUserPosition(c *gin.Context) { if !ok { return } - u, found := userRepo.GetByID(id) + u, found := userDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("用户不存在")) return @@ -223,14 +223,14 @@ func SetUserPosition(c *gin.Context) { return } if req.PositionID != nil { - _, found := positionRepo.GetByID(*req.PositionID) + _, found := positionDAO.GetByID(*req.PositionID) if !found { web.Fail(c, web.NewBadRequest("岗位不存在或已停用")) return } } u.PositionID = req.PositionID - if !userRepo.Update(&u) { + if !userDAO.Update(&u) { web.Fail(c, web.NewBadRequest("设置用户岗位失败")) return } @@ -246,13 +246,13 @@ func MyPosition(c *gin.Context) { web.OK(c, gin.H{"position": nil, "knowledge": []gin.H{}, "count": 0}) return } - pos, found := positionRepo.GetByID(*u.PositionID) + pos, found := positionDAO.GetByID(*u.PositionID) if !found || pos.Status != "active" { web.OK(c, gin.H{"position": nil, "knowledge": []gin.H{}, "count": 0}) return } - pks := positionRepo.Knowledge(pos.ID) + pks := positionDAO.Knowledge(pos.ID) // 批量解析课程/产品名称 courseIDs := make([]uint, 0, len(pks)) @@ -265,8 +265,8 @@ func MyPosition(c *gin.Context) { productIDs = append(productIDs, *pk.ProductID) } } - courseName := courseRepo.NamesByIDs(courseIDs) - productName := productRepo.NamesByIDs(productIDs) + courseName := courseDAO.NamesByIDs(courseIDs) + productName := productDAO.NamesByIDs(productIDs) list := make([]gin.H, 0, len(pks)) for _, pk := range pks { @@ -303,7 +303,7 @@ func ListPositionBlueprint(c *gin.Context) { if !ok { return } - items := positionRepo.Blueprints(id) + items := positionDAO.Blueprints(id) if items == nil { items = []model.PositionExamBlueprint{} } @@ -316,7 +316,7 @@ func SavePositionBlueprint(c *gin.Context) { if !ok { return } - _, found := positionRepo.GetByID(id) + _, found := positionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("岗位不存在")) return @@ -346,11 +346,11 @@ func SavePositionBlueprint(c *gin.Context) { PositionID: id, Domain: it.Domain, Type: it.Type, Count: it.Count, }) } - if !positionRepo.ReplaceBlueprints(id, rows) { + if !positionDAO.ReplaceBlueprints(id, rows) { web.Fail(c, web.NewBadRequest("保存岗位考试蓝图失败")) return } - out := positionRepo.Blueprints(id) + out := positionDAO.Blueprints(id) if out == nil { out = []model.PositionExamBlueprint{} } diff --git a/eai_agentplatform/backend-go/internal/api/products.go b/eai_agentplatform/backend-go/internal/api/products.go index b8f7544..3d4c19f 100644 --- a/eai_agentplatform/backend-go/internal/api/products.go +++ b/eai_agentplatform/backend-go/internal/api/products.go @@ -3,21 +3,21 @@ package api import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// productRepo 产品仓库(便于测试时覆写)。 -var productRepo repository.ProductRepo +// productDAO 产品仓库(便于测试时覆写)。 +var productDAO dal.ProductDAO func init() { - productRepo = repository.ProductRepo{} + productDAO = dal.ProductDAO{} } // ListProducts GET /api/products?category=&status= func ListProducts(c *gin.Context) { - items := productRepo.ProductsByStatus(c.Query("status"), map[string]string{ + items := productDAO.ProductsByStatus(c.Query("status"), map[string]string{ "category": c.Query("category"), }) web.OK(c, items) @@ -29,7 +29,7 @@ func GetProduct(c *gin.Context) { if !ok { return } - p, found := productRepo.GetByID(id) + p, found := productDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("产品不存在")) return @@ -51,11 +51,11 @@ func CreateProduct(c *gin.Context) { if p.Status == "" { p.Status = "active" } - if productRepo.CountByCode(p.Code, nil) > 0 { + if productDAO.CountByCode(p.Code, nil) > 0 { web.Fail(c, web.NewConflictError("产品编号已存在")) return } - if !productRepo.Insert(&p) { + if !productDAO.Insert(&p) { web.Fail(c, web.NewBadRequest("创建产品失败")) return } @@ -68,7 +68,7 @@ func UpdateProduct(c *gin.Context) { if !ok { return } - p, found := productRepo.GetByID(id) + p, found := productDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("产品不存在")) return @@ -87,7 +87,7 @@ func UpdateProduct(c *gin.Context) { } if req.Code != "" && req.Code != p.Code { - if productRepo.CountByCode(req.Code, &id) > 0 { + if productDAO.CountByCode(req.Code, &id) > 0 { web.Fail(c, web.NewConflictError("产品编号已存在")) return } @@ -105,7 +105,7 @@ func UpdateProduct(c *gin.Context) { p.ReportRules = req.ReportRules p.Status = req.Status - if !productRepo.Update(&p) { + if !productDAO.Update(&p) { web.Fail(c, web.NewBadRequest("更新产品失败")) return } @@ -118,7 +118,7 @@ func DeleteProduct(c *gin.Context) { if !ok { return } - if !productRepo.Delete(id) { + if !productDAO.Delete(id) { web.Fail(c, web.NewBadRequest("停用产品失败")) return } @@ -145,9 +145,9 @@ func ImportProducts(c *gin.Context) { it.Status = "active" } // 检查是否存在 - existing, found := productRepo.GetByCode(it.Code) + existing, found := productDAO.GetByCode(it.Code) if !found { - if productRepo.Insert(&it) { + if productDAO.Insert(&it) { created++ } continue @@ -184,7 +184,7 @@ func ImportProducts(c *gin.Context) { existing.ReportRules = it.ReportRules } existing.Status = it.Status - if productRepo.Update(&existing) { + if productDAO.Update(&existing) { updated++ } } diff --git a/eai_agentplatform/backend-go/internal/api/profile.go b/eai_agentplatform/backend-go/internal/api/profile.go index d38581c..1c37365 100644 --- a/eai_agentplatform/backend-go/internal/api/profile.go +++ b/eai_agentplatform/backend-go/internal/api/profile.go @@ -11,7 +11,7 @@ import ( "eai_agentplatform/backend/internal/web" ) -// 本文件用到的仓库:questionRepo/examRecordRepo 声明在 exam.go,learningRepo 声明在 learning.go。 +// 本文件用到的仓库:questionDAO/examRecordDAO 声明在 exam.go,learningDAO 声明在 learning.go。 // domainLabels 能力雷达维度(正式考试按域聚合的掌握度)。 var domainLabels = map[string]string{ @@ -40,7 +40,7 @@ func MyProfile(c *gin.Context) { } // 学习进度(公司/产品/课程浏览) - lps := learningRepo.ListByUser(u.ID) + lps := learningDAO.ListByUser(u.ID) companyViewed := false productViewed, courseViewed := 0, 0 for _, lp := range lps { @@ -55,18 +55,18 @@ func MyProfile(c *gin.Context) { } // 错题统计 - mistakeTotal := mistakeRepo.CountByUser(u.ID) - mistakeResolved := mistakeRepo.CountResolvedByUser(u.ID) + mistakeTotal := mistakeDAO.CountByUser(u.ID) + mistakeResolved := mistakeDAO.CountResolvedByUser(u.ID) // 自测次数(自测不落 exam_record,改由积分流水统计) var selfTestCount int64 store.DB.Model(&model.PointEvent{}).Where("user_id = ? AND event_type = ?", u.ID, "self_test").Count(&selfTestCount) // 正式考试记录 + 按域能力聚合(趋势图要按时间正序) - recs := examRecordRepo.ListByUserChronological(u.ID) + recs := examRecordDAO.ListByUserChronological(u.ID) // 题目 → 域映射(用于从答题明细反推各域掌握度) - qDomain := questionRepo.DomainMap() + qDomain := questionDAO.DomainMap() type domainAgg struct { Correct int `json:"correct"` diff --git a/eai_agentplatform/backend-go/internal/api/project.go b/eai_agentplatform/backend-go/internal/api/project.go index 87b711a..babd844 100644 --- a/eai_agentplatform/backend-go/internal/api/project.go +++ b/eai_agentplatform/backend-go/internal/api/project.go @@ -58,7 +58,7 @@ func ListProjects(c *gin.Context) { return } - web.OK(c, projectRepo.ListByOwners(specialistruntime.MyTaskOwners(user), 50)) + web.OK(c, projectDAO.ListByOwners(specialistruntime.MyTaskOwners(user), 50)) } // CreateProject 建一个项目。空 body 也收(跟「新建任务」一样,全走默认值), @@ -105,7 +105,7 @@ func CreateProject(c *gin.Context) { SkillKeys: encodeKeys(req.SkillKeys), ConnectorKeys: encodeKeys(req.ConnectorKeys), } - if !projectRepo.Insert(&project) { + if !projectDAO.Insert(&project) { web.Fail(c, web.NewBadRequest("创建项目失败")) return } @@ -125,7 +125,7 @@ func UpdateProject(c *gin.Context) { return } - project, found := projectRepo.GetByIDForOwners(id, specialistruntime.MyTaskOwners(user)) + project, found := projectDAO.GetByIDForOwners(id, specialistruntime.MyTaskOwners(user)) if !found { web.Fail(c, web.NewNotFoundError("项目不存在")) return @@ -169,7 +169,7 @@ func UpdateProject(c *gin.Context) { project.ConnectorKeys = encodeKeys(req.ConnectorKeys) } - if !projectRepo.Update(&project) { + if !projectDAO.Update(&project) { web.Fail(c, web.NewBadRequest("更新项目失败")) return } @@ -192,16 +192,16 @@ func DeleteProject(c *gin.Context) { return } - project, found := projectRepo.GetByIDForOwners(id, specialistruntime.MyTaskOwners(user)) + project, found := projectDAO.GetByIDForOwners(id, specialistruntime.MyTaskOwners(user)) if !found { web.Fail(c, web.NewNotFoundError("项目不存在")) return } - if !taskRecordRepo.ClearProject(project.ID) { + if !taskRecordDAO.ClearProject(project.ID) { web.Fail(c, web.NewBadRequest("解除任务归属失败")) return } - if !projectRepo.Delete(&project) { + if !projectDAO.Delete(&project) { web.Fail(c, web.NewBadRequest("删除项目失败")) return } @@ -221,13 +221,13 @@ func ListProjectTasks(c *gin.Context) { return } - project, found := projectRepo.GetByIDForOwners(id, specialistruntime.MyTaskOwners(user)) + project, found := projectDAO.GetByIDForOwners(id, specialistruntime.MyTaskOwners(user)) if !found { web.Fail(c, web.NewNotFoundError("项目不存在")) return } - web.OK(c, taskRecordRepo.ListByProject(project.ID, 100)) + web.OK(c, taskRecordDAO.ListByProject(project.ID, 100)) } // validateSpecialistKeys 专员 key 得真实存在才让存 —— 项目卡片上要显示专员名, @@ -240,7 +240,7 @@ func validateSpecialistKeys(keys []string) error { if trimmed == "" { continue } - if _, found := specialistRepo.GetByKey(trimmed); !found { + if _, found := specialistDAO.GetByKey(trimmed); !found { return errors.New("专员不存在:" + trimmed) } } diff --git a/eai_agentplatform/backend-go/internal/api/specialist_prompt.go b/eai_agentplatform/backend-go/internal/api/specialist_prompt.go index 7587a32..88fa595 100644 --- a/eai_agentplatform/backend-go/internal/api/specialist_prompt.go +++ b/eai_agentplatform/backend-go/internal/api/specialist_prompt.go @@ -25,7 +25,7 @@ func loadSpecialistByKey(key string) *specialistmodel.Specialist { } // state = inactive 的专员不再接新会话,但 system(通用助手)要能查到 —— // 「要不要拒绝 inactive」这个口径只在这里,不去污染仓库的取数口径。 - s, found := specialistRepo.GetByKey(key) + s, found := specialistDAO.GetByKey(key) if !found || s.State == "inactive" { return nil } @@ -44,7 +44,7 @@ func resolveSpecialist(req ChatMessageRequest) *specialistmodel.Specialist { if req.TaskID > 0 { // 与 task_runtime.go 其余读路径一致,不按 created_by 收窄: // 专员目录本身就是所有登录用户可读的,这里不构成新的信息暴露。 - if task, found := taskRecordRepo.GetByID(req.TaskID); found { + if task, found := taskRecordDAO.GetByID(req.TaskID); found { if s := loadSpecialistByKey(task.SpecialistKey); s != nil { return s } diff --git a/eai_agentplatform/backend-go/internal/api/specialist_prompt_test.go b/eai_agentplatform/backend-go/internal/api/specialist_prompt_test.go index 1294919..6e16254 100644 --- a/eai_agentplatform/backend-go/internal/api/specialist_prompt_test.go +++ b/eai_agentplatform/backend-go/internal/api/specialist_prompt_test.go @@ -9,8 +9,8 @@ import ( "gorm.io/gorm" "gorm.io/gorm/logger" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" specialistmodel "eai_agentplatform/backend/internal/specialists/model" "eai_agentplatform/backend/internal/store" ) @@ -125,11 +125,11 @@ func setupAPITestDB(t *testing.T) { store.DB = db t.Cleanup(func() { store.DB = prev }) - // 取数现在走仓库层,零值仓库(repository.XxxRepo{})的 base() 会回落到 - // 包级 repository.DB —— 这根线不接,第一个查询就是 nil 解引用。 - prevRepo := repository.DB - repository.SetDB(db) - t.Cleanup(func() { repository.SetDB(prevRepo) }) + // 取数现在走数据访问层,零值 DAO(dal.XxxDAO{})的 base() 会回落到 + // 包级 dal.DB —— 这根线不接,第一个查询就是 nil 解引用。 + prevDAO := dal.DB + dal.SetDB(db) + t.Cleanup(func() { dal.SetDB(prevDAO) }) for _, s := range []specialistmodel.Specialist{ {Key: "contract-review", Label: "合同审查专员", State: "active", Tier: "industry", ObjectEntryRoute: "/apps/contract-review"}, diff --git a/eai_agentplatform/backend-go/internal/api/system.go b/eai_agentplatform/backend-go/internal/api/system.go index f042be8..7e8ee86 100644 --- a/eai_agentplatform/backend-go/internal/api/system.go +++ b/eai_agentplatform/backend-go/internal/api/system.go @@ -10,21 +10,21 @@ import ( "github.com/gin-gonic/gin" "eai_agentplatform/backend/internal/auth" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" ) -// systemConfigRepo 声明在此;examRecordRepo 与考试域同属一个对象, +// systemConfigDAO 声明在此;examRecordDAO 与考试域同属一个对象, // 统一声明在 exam.go 的「考试域仓库」块内,避免同一个仓库有两份变量导致覆写时行为分叉。 var ( - userRepo repository.UserRepo - configRepo repository.SystemConfigRepo + userDAO dal.UserDAO + configDAO dal.SystemConfigDAO ) func init() { - userRepo = repository.UserRepo{} - configRepo = repository.SystemConfigRepo{} + userDAO = dal.UserDAO{} + configDAO = dal.SystemConfigDAO{} } // ============ 用户管理(管理员) ============ @@ -32,11 +32,11 @@ func init() { // ListUsers GET /api/system/users —— 含考试统计(考试次数/通过数/最近成绩) func ListUsers(c *gin.Context) { var items []model.User - userRepo.Query().Type(&model.User{}).Order("id ASC").Find(&items) + userDAO.Query().Type(&model.User{}).Order("id ASC").Find(&items) // 获取考试记录 var recs []model.ExamRecord - examRecordRepo.Inner().Model(&model.ExamRecord{}).Order("submitted_at DESC").Find(&recs) + examRecordDAO.Inner().Model(&model.ExamRecord{}).Order("submitted_at DESC").Find(&recs) type stat struct { ExamCount int @@ -108,7 +108,7 @@ func CreateUser(c *gin.Context) { if req.Role != "admin" && req.Role != "employee" { req.Role = "employee" } - _, found := userRepo.GetByUsername(req.Username) + _, found := userDAO.GetByUsername(req.Username) if found { web.Fail(c, web.NewConflictError("用户名已存在")) return @@ -126,7 +126,7 @@ func CreateUser(c *gin.Context) { if req.Role == "admin" { u.AiPoints = 999999 } - if !userRepo.Insert(&u) { + if !userDAO.Insert(&u) { web.Fail(c, web.NewBadRequest("创建用户失败")) return } @@ -139,7 +139,7 @@ func UpdateUser(c *gin.Context) { if !ok { return } - u, found := userRepo.GetByID(id) + u, found := userDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("用户不存在")) return @@ -191,7 +191,7 @@ func UpdateUser(c *gin.Context) { } u.AiPoints = *req.AiPoints } - if !userRepo.Update(&u) { + if !userDAO.Update(&u) { web.Fail(c, web.NewBadRequest("更新用户失败")) return } @@ -200,7 +200,7 @@ func UpdateUser(c *gin.Context) { // defaultAiPoints 读取新用户默认 AI 算力点(system_config.ai_points_default,缺省 100) func defaultAiPoints() int { - val := configRepo.GetByKey("ai_points_default") + val := configDAO.GetByKey("ai_points_default") if v, err := strconv.Atoi(strings.TrimSpace(val)); err == nil { return v } @@ -211,7 +211,7 @@ func defaultAiPoints() int { // ListExamRecords GET /api/system/exam-records?user_id=&paper_id= func ListExamRecords(c *gin.Context) { - items := examRecordRepo.List(c.Query("user_id"), c.Query("paper_id")) + items := examRecordDAO.List(c.Query("user_id"), c.Query("paper_id")) web.OK(c, items) } @@ -233,7 +233,7 @@ func GetExamRecord(c *gin.Context) { if !ok { return } - rec, found := examRecordRepo.GetByID(id) + rec, found := examRecordDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("考试记录不存在")) return @@ -254,7 +254,7 @@ func DeleteExamRecord(c *gin.Context) { if !ok { return } - if !examRecordRepo.Remove(id) { + if !examRecordDAO.Remove(id) { web.Fail(c, web.NewBadRequest("删除考试记录失败")) return } @@ -264,7 +264,7 @@ func DeleteExamRecord(c *gin.Context) { // ExportExamRecords GET /api/system/exam-records/export —— 导出 CSV(支持 user_id/paper_id 过滤) func ExportExamRecords(c *gin.Context) { var items []model.ExamRecord - q := repository.DB.Model(&model.ExamRecord{}) + q := dal.DB.Model(&model.ExamRecord{}) if uid := c.Query("user_id"); uid != "" { q = q.Where("user_id = ?", uid) } @@ -278,7 +278,7 @@ func ExportExamRecords(c *gin.Context) { // 用户名映射 var users []model.User - repository.DB.Find(&users) + dal.DB.Find(&users) nameMap := map[uint]model.User{} for _, u := range users { nameMap[u.ID] = u @@ -316,7 +316,7 @@ func ExportExamRecords(c *gin.Context) { // GetConfig GET /api/system/config —— 所有系统参数 func GetConfig(c *gin.Context) { - items := configRepo.List() + items := configDAO.List() type cfgItem struct { Key string `json:"config_key"` Value string `json:"config_value"` @@ -338,7 +338,7 @@ func UpdateConfig(c *gin.Context) { web.Fail(c, web.NewBadRequest("configs 必填")) return } - configRepo.BulkUpsert(toSystemConfigs(req.Configs)) + configDAO.BulkUpsert(toSystemConfigs(req.Configs)) web.OK(c, gin.H{"updated": len(req.Configs)}) } diff --git a/eai_agentplatform/backend-go/internal/api/task_runtime.go b/eai_agentplatform/backend-go/internal/api/task_runtime.go index 07d8040..3963691 100644 --- a/eai_agentplatform/backend-go/internal/api/task_runtime.go +++ b/eai_agentplatform/backend-go/internal/api/task_runtime.go @@ -8,9 +8,9 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" wechatofficialaccountapi "eai_agentplatform/backend/internal/specialists/packages/wechat_official_account/api" specialistruntime "eai_agentplatform/backend/internal/specialists/runtime" "eai_agentplatform/backend/internal/web" @@ -18,23 +18,23 @@ import ( // 任务域仓库,包内共享。 // -// specialistRepo 还被 my_task.go、project.go、specialist_prompt.go 共用, -// projectRepo 还被 my_task.go 共用 —— 同一个仓库只声明一处: +// specialistDAO 还被 my_task.go、project.go、specialist_prompt.go 共用, +// projectDAO 还被 my_task.go 共用 —— 同一个仓库只声明一处: // 两份变量持有同一个仓库时,测试里覆写一份、另一份照旧,行为会静默分叉。 var ( - specialistRepo repository.SpecialistRepo - taskRecordRepo repository.TaskRecordRepo - taskRunRepo repository.TaskRunRepo - taskArtifactRepo repository.TaskArtifactRepo - projectRepo repository.ProjectRepo + specialistDAO dal.SpecialistDAO + taskRecordDAO dal.TaskRecordDAO + taskRunDAO dal.TaskRunDAO + taskArtifactDAO dal.TaskArtifactDAO + projectDAO dal.ProjectDAO ) func init() { - specialistRepo = repository.SpecialistRepo{} - taskRecordRepo = repository.TaskRecordRepo{} - taskRunRepo = repository.TaskRunRepo{} - taskArtifactRepo = repository.TaskArtifactRepo{} - projectRepo = repository.ProjectRepo{} + specialistDAO = dal.SpecialistDAO{} + taskRecordDAO = dal.TaskRecordDAO{} + taskRunDAO = dal.TaskRunDAO{} + taskArtifactDAO = dal.TaskArtifactDAO{} + projectDAO = dal.ProjectDAO{} } func ListTasks(c *gin.Context) { @@ -43,7 +43,7 @@ func ListTasks(c *gin.Context) { web.Fail(c, web.NewBadRequest("specialist_key 不能为空")) return } - web.OK(c, taskRecordRepo.ListBySpecialistKey(specialistKey)) + web.OK(c, taskRecordDAO.ListBySpecialistKey(specialistKey)) } func GetTaskDetail(c *gin.Context) { @@ -52,14 +52,14 @@ func GetTaskDetail(c *gin.Context) { return } - task, found := taskRecordRepo.GetByID(id) + task, found := taskRecordDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("事项不存在")) return } - artifacts := taskArtifactRepo.ListByTask(id) - runs := taskRunRepo.ListByTask(id) + artifacts := taskArtifactDAO.ListByTask(id) + runs := taskRunDAO.ListByTask(id) if task.SpecialistKey == wechatofficialaccountapi.OfficialAccountSpecialistKey { artifacts = wechatofficialaccountapi.CompactOfficialAccountArtifactsForResponse(artifacts) runs = wechatofficialaccountapi.CompactOfficialAccountRunsForResponse(runs) @@ -79,13 +79,13 @@ func GetArtifactDetail(c *gin.Context) { return } - artifact, found := taskArtifactRepo.GetByID(id) + artifact, found := taskArtifactDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("交付物不存在")) return } - task, found := taskRecordRepo.GetByID(artifact.TaskID) + task, found := taskRecordDAO.GetByID(artifact.TaskID) if !found { web.Fail(c, web.NewNotFoundError("事项不存在")) return @@ -93,7 +93,7 @@ func GetArtifactDetail(c *gin.Context) { var runData any if artifact.CreatedByRunID != nil { - if run, ok := taskRunRepo.GetByID(*artifact.CreatedByRunID); ok { + if run, ok := taskRunDAO.GetByID(*artifact.CreatedByRunID); ok { runData = run } } @@ -116,7 +116,7 @@ func CreateTask(c *gin.Context) { return } - specialist, found := specialistRepo.GetByKey(strings.TrimSpace(req.SpecialistKey)) + specialist, found := specialistDAO.GetByKey(strings.TrimSpace(req.SpecialistKey)) if !found { web.Fail(c, web.NewNotFoundError("专员不存在")) return @@ -135,7 +135,7 @@ func CreateTask(c *gin.Context) { task.Status = "待处理" } - if !taskRecordRepo.Insert(&task) { + if !taskRecordDAO.Insert(&task) { web.Fail(c, web.NewBadRequest("创建事项失败")) return } @@ -148,7 +148,7 @@ func UpdateTask(c *gin.Context) { return } - task, found := taskRecordRepo.GetByID(id) + task, found := taskRecordDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("事项不存在")) return @@ -167,7 +167,7 @@ func UpdateTask(c *gin.Context) { } if key := strings.TrimSpace(req.SpecialistKey); key != "" && key != task.SpecialistKey { - specialist, ok := specialistRepo.GetByKey(key) + specialist, ok := specialistDAO.GetByKey(key) if !ok { web.Fail(c, web.NewNotFoundError("目标专员不存在")) return @@ -181,7 +181,7 @@ func UpdateTask(c *gin.Context) { task.Status = specialistruntime.NormalizeTaskStatus(updated.Status) task.ContextJSON = updated.ContextJSON task.DueAt = updated.DueAt - if !taskRecordRepo.Update(&task) { + if !taskRecordDAO.Update(&task) { web.Fail(c, web.NewBadRequest("更新事项失败")) return } @@ -194,7 +194,7 @@ func UpdateTaskStatus(c *gin.Context) { return } - task, found := taskRecordRepo.GetByID(id) + task, found := taskRecordDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("事项不存在")) return @@ -211,7 +211,7 @@ func UpdateTaskStatus(c *gin.Context) { return } task.Status = status - if !taskRecordRepo.Update(&task) { + if !taskRecordDAO.Update(&task) { web.Fail(c, web.NewBadRequest("更新事项状态失败")) return } @@ -224,14 +224,14 @@ func DeleteTask(c *gin.Context) { return } - task, found := taskRecordRepo.GetByID(id) + task, found := taskRecordDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("事项不存在")) return } // 交付物与运行记录跟着任务一起走,三张表在同一个事务里。 - if !taskRecordRepo.DeleteCascade(task.ID) { + if !taskRecordDAO.DeleteCascade(task.ID) { web.Fail(c, web.NewBadRequest("删除事项失败")) return } @@ -245,12 +245,12 @@ func UpdateArtifactStatus(c *gin.Context) { return } - artifact, found := taskArtifactRepo.GetByID(id) + artifact, found := taskArtifactDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("交付物不存在")) return } - task, found := taskRecordRepo.GetByID(artifact.TaskID) + task, found := taskRecordDAO.GetByID(artifact.TaskID) if !found { web.Fail(c, web.NewNotFoundError("事项不存在")) return @@ -267,14 +267,14 @@ func UpdateArtifactStatus(c *gin.Context) { return } artifact.Status = nextStatus - if !taskArtifactRepo.Update(&artifact) { + if !taskArtifactDAO.Update(&artifact) { web.Fail(c, web.NewBadRequest("更新交付物状态失败")) return } task.Status = specialistruntime.TaskStatusFromArtifactStatus(nextStatus) task.CurrentResult = specialistruntime.BuildArtifactStatusSummary(artifact, strings.TrimSpace(req.Remark)) - if !taskRecordRepo.Update(&task) { + if !taskRecordDAO.Update(&task) { web.Fail(c, web.NewBadRequest("更新事项状态失败")) return } @@ -291,12 +291,12 @@ func ExecuteTaskAction(c *gin.Context) { return } - task, found := taskRecordRepo.GetByID(id) + task, found := taskRecordDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("事项不存在")) return } - specialist, found := specialistRepo.GetByKey(task.SpecialistKey) + specialist, found := specialistDAO.GetByKey(task.SpecialistKey) if !found { web.Fail(c, web.NewNotFoundError("专员不存在")) return @@ -343,7 +343,7 @@ func ExecuteTaskAction(c *gin.Context) { StartedAt: now, FinishedAt: &now, } - if !taskRunRepo.Insert(&run) { + if !taskRunDAO.Insert(&run) { web.Fail(c, web.NewBadRequest("执行动作失败")) return } @@ -362,7 +362,7 @@ func ExecuteTaskAction(c *gin.Context) { SourceRefsJSON: string(sourceRefsJSON), CreatedByRunID: &run.ID, } - if !taskArtifactRepo.Insert(artifact) { + if !taskArtifactDAO.Insert(artifact) { web.Fail(c, web.NewBadRequest("保存交付物失败")) return } @@ -372,7 +372,7 @@ func ExecuteTaskAction(c *gin.Context) { task.CurrentRunID = &run.ID task.CurrentResult = runOutput.Summary task.LastTriggeredAt = &now - if !taskRecordRepo.Update(&task) { + if !taskRecordDAO.Update(&task) { web.Fail(c, web.NewBadRequest("更新事项状态失败")) return } @@ -386,13 +386,13 @@ func ExecuteTaskAction(c *gin.Context) { // ensureBootstrapTask 某专员名下一条任务都没有时,铺一条默认任务。 // -// 注意:目前全仓没有调用方(保留原样迁到仓库层,未删)。 +// 注意:目前全仓没有调用方(保留原样迁到数据访问层,未删)。 func ensureBootstrapTask(specialistKey string, user *model.User) error { - if taskRecordRepo.CountBySpecialistKey(specialistKey) > 0 { + if taskRecordDAO.CountBySpecialistKey(specialistKey) > 0 { return nil } - specialist, found := specialistRepo.GetByKey(specialistKey) + specialist, found := specialistDAO.GetByKey(specialistKey) if !found { return fmt.Errorf("专员不存在:%s", specialistKey) } @@ -419,7 +419,7 @@ func ensureBootstrapTask(specialistKey string, user *model.User) error { if user != nil { task.CreatedBy = &user.ID } - if !taskRecordRepo.Insert(&task) { + if !taskRecordDAO.Insert(&task) { return fmt.Errorf("创建铺底任务失败") } return nil diff --git a/eai_agentplatform/backend-go/internal/repository/action_definition.go b/eai_agentplatform/backend-go/internal/dal/action_definition.go similarity index 67% rename from eai_agentplatform/backend-go/internal/repository/action_definition.go rename to eai_agentplatform/backend-go/internal/dal/action_definition.go index 80d7a1f..b0fd0e1 100644 --- a/eai_agentplatform/backend-go/internal/repository/action_definition.go +++ b/eai_agentplatform/backend-go/internal/dal/action_definition.go @@ -1,17 +1,17 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // ActionDefinition 原子执行动作定义仓库。 -type ActionDefinitionRepo struct{ *QueryBuilder } +type ActionDefinitionDAO struct{ *QueryBuilder } // List 全部动作定义(sort_order ASC, id ASC)。 // // 这里不替调用方定 state 默认值:列表接口「不传 state 就只看 active」是接口契约, // 由 handler 解析 query 参数后把结果传进来。 -func (r ActionDefinitionRepo) List(state string) []model.ActionDefinition { +func (r ActionDefinitionDAO) List(state string) []model.ActionDefinition { q := r.Type(&model.ActionDefinition{}) if state != "" { q = q.Where("state = ?", state) @@ -24,7 +24,7 @@ func (r ActionDefinitionRepo) List(state string) []model.ActionDefinition { } // GetByID 按 ID 取。 -func (r ActionDefinitionRepo) GetByID(id uint) (model.ActionDefinition, bool) { +func (r ActionDefinitionDAO) GetByID(id uint) (model.ActionDefinition, bool) { var a model.ActionDefinition if r.Type(&a).Where("id = ?", id).First(&a) { return a, true @@ -33,7 +33,7 @@ func (r ActionDefinitionRepo) GetByID(id uint) (model.ActionDefinition, bool) { } // GetByKey 按 key 取(key 上有唯一索引)。 -func (r ActionDefinitionRepo) GetByKey(key string) (model.ActionDefinition, bool) { +func (r ActionDefinitionDAO) GetByKey(key string) (model.ActionDefinition, bool) { var a model.ActionDefinition if r.Type(&a).Where("key = ?", key).First(&a) { return a, true @@ -42,16 +42,16 @@ func (r ActionDefinitionRepo) GetByKey(key string) (model.ActionDefinition, bool } // Insert 新建。 -func (r ActionDefinitionRepo) Insert(a *model.ActionDefinition) bool { +func (r ActionDefinitionDAO) Insert(a *model.ActionDefinition) bool { return r.QueryBuilder.Insert(a) } // Update 更新。 -func (r ActionDefinitionRepo) Update(a *model.ActionDefinition) bool { +func (r ActionDefinitionDAO) Update(a *model.ActionDefinition) bool { return r.Save(a) } // Delete 硬删除。 -func (r ActionDefinitionRepo) Delete(a *model.ActionDefinition) bool { +func (r ActionDefinitionDAO) Delete(a *model.ActionDefinition) bool { return r.QueryBuilder.Delete(a) } diff --git a/eai_agentplatform/backend-go/internal/repository/certificate.go b/eai_agentplatform/backend-go/internal/dal/certificate.go similarity index 73% rename from eai_agentplatform/backend-go/internal/repository/certificate.go rename to eai_agentplatform/backend-go/internal/dal/certificate.go index 8b7d95b..66e9e9b 100644 --- a/eai_agentplatform/backend-go/internal/repository/certificate.go +++ b/eai_agentplatform/backend-go/internal/dal/certificate.go @@ -1,18 +1,18 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // Certificate 证书仓库。 -type CertificateRepo struct{ *QueryBuilder } +type CertificateDAO struct{ *QueryBuilder } // GetByExamRecord 按考试记录取证书。 // // 颁发幂等的依据:同一份 exam_record 只发一张证书。 // (此前这里叫 GetByUserAndExam、按不存在的 exam_id 列查,一调即 SQL 报错; // 表上只有 exam_record_id,且颁发幂等本来就该按考试记录而不是按用户+考试。) -func (r CertificateRepo) GetByExamRecord(examRecordID uint) (model.Certificate, bool) { +func (r CertificateDAO) GetByExamRecord(examRecordID uint) (model.Certificate, bool) { var c model.Certificate if r.Type(&c).Where("exam_record_id = ?", examRecordID).First(&c) { return c, true @@ -21,7 +21,7 @@ func (r CertificateRepo) GetByExamRecord(examRecordID uint) (model.Certificate, } // ListAll 取全部证书(issued_at 倒序,管理端全员视图)。 -func (r CertificateRepo) ListAll() []model.Certificate { +func (r CertificateDAO) ListAll() []model.Certificate { var items []model.Certificate if r.Type(&items).Order("issued_at DESC").Find(&items) { return items @@ -30,7 +30,7 @@ func (r CertificateRepo) ListAll() []model.Certificate { } // ListByUser 获取某用户的证书列表。 -func (r CertificateRepo) ListByUser(userID uint) []model.Certificate { +func (r CertificateDAO) ListByUser(userID uint) []model.Certificate { var items []model.Certificate if r.Type(&items).Where("user_id = ?", userID).Order("issued_at DESC").Find(&items) { return items @@ -39,7 +39,7 @@ func (r CertificateRepo) ListByUser(userID uint) []model.Certificate { } // GetByID 按 ID 获取。 -func (r CertificateRepo) GetByID(id uint) (model.Certificate, bool) { +func (r CertificateDAO) GetByID(id uint) (model.Certificate, bool) { var c model.Certificate if r.Type(&c).Where("id = ?", id).First(&c) { return c, true @@ -48,12 +48,12 @@ func (r CertificateRepo) GetByID(id uint) (model.Certificate, bool) { } // Insert 创建证书。 -func (r CertificateRepo) Insert(c *model.Certificate) bool { +func (r CertificateDAO) Insert(c *model.Certificate) bool { return r.QueryBuilder.Insert(c) } // CountByUser 统计某用户的证书数。 -func (r CertificateRepo) CountByUser(userID uint) int64 { +func (r CertificateDAO) CountByUser(userID uint) int64 { var c int64 r.Inner().Model(&model.Certificate{}).Where("user_id = ?", userID).Count(&c) return c diff --git a/eai_agentplatform/backend-go/internal/repository/core.go b/eai_agentplatform/backend-go/internal/dal/core.go similarity index 85% rename from eai_agentplatform/backend-go/internal/repository/core.go rename to eai_agentplatform/backend-go/internal/dal/core.go index 2ad8f0d..7e23f62 100644 --- a/eai_agentplatform/backend-go/internal/repository/core.go +++ b/eai_agentplatform/backend-go/internal/dal/core.go @@ -1,14 +1,14 @@ -// Package repository 提供统一的数据访问层。 +// Package dal 提供统一的数据访问层(Data Access Layer)。 // -// 所有 handler 必须通过 Repository 访问数据,禁止直接调用 store.DB。 +// 所有 handler 必须通过 DAO(Data Access Object)访问数据,禁止直接调用 store.DB。 // 核心 QueryBuilder 封装常用查询操作(FindAll / FindBy / FindByID / Create / Update / Delete), -// 各实体仓库基于 QueryBuilder 构建领域方法。 +// 各实体 DAO 基于 QueryBuilder 构建领域方法。 // // 设计原则: // - 只封装数据访问,不封装业务逻辑(业务逻辑留在 handler/service) // - 返回 *gorm.DB 的方法允许链式调用(Where / Order / Limit 等) // - 所有方法统一错误处理(错误已记录日志,调用方通过 bool 判断) -package repository +package dal import ( "log" @@ -18,7 +18,7 @@ import ( "eai_agentplatform/backend/internal/store" ) -// DB 全局数据库句柄(供仓库方法使用)。 +// DB 全局数据库句柄(供 DAO 方法使用)。 // 实际使用时指向 store.DB。 var DB *gorm.DB @@ -26,7 +26,7 @@ func init() { DB = store.DB } -// SetDB 设置仓库使用的数据库句柄(测试时覆写)。 +// SetDB 设置数据访问层使用的数据库句柄(测试时覆写)。 func SetDB(db *gorm.DB) { DB = db } @@ -97,7 +97,7 @@ func (q *QueryBuilder) First(model any) (found bool) { if err == gorm.ErrRecordNotFound { return false } - log.Printf("[repository] First error: %v", err) + log.Printf("[dal] First error: %v", err) return false } return true @@ -106,7 +106,7 @@ func (q *QueryBuilder) First(model any) (found bool) { // Find 查询所有匹配记录。 func (q *QueryBuilder) Find(dest any) (found bool) { if err := q.base().Find(dest).Error; err != nil { - log.Printf("[repository] Find error: %v", err) + log.Printf("[dal] Find error: %v", err) return false } return true @@ -122,7 +122,7 @@ func (q *QueryBuilder) Count() int64 { // Insert 插入记录。 func (q *QueryBuilder) Insert(value any) bool { if err := q.base().Create(value).Error; err != nil { - log.Printf("[repository] Insert error: %v", err) + log.Printf("[dal] Insert error: %v", err) return false } return true @@ -136,7 +136,7 @@ func (q *QueryBuilder) Create(value any) bool { // Save 保存记录(插入或更新)。 func (q *QueryBuilder) Save(value any) bool { if err := q.base().Save(value).Error; err != nil { - log.Printf("[repository] Save error: %v", err) + log.Printf("[dal] Save error: %v", err) return false } return true @@ -145,7 +145,7 @@ func (q *QueryBuilder) Save(value any) bool { // Updates 按条件更新(只更新提供的非零字段)。 func (q *QueryBuilder) Updates(value any) bool { if err := q.base().Updates(value).Error; err != nil { - log.Printf("[repository] Updates error: %v", err) + log.Printf("[dal] Updates error: %v", err) return false } return true @@ -154,7 +154,7 @@ func (q *QueryBuilder) Updates(value any) bool { // UpdateColumn 更新单列。 func (q *QueryBuilder) UpdateColumn(column string, value any) bool { if err := q.base().Update(column, value).Error; err != nil { - log.Printf("[repository] UpdateColumn error: %v", err) + log.Printf("[dal] UpdateColumn error: %v", err) return false } return true @@ -163,7 +163,7 @@ func (q *QueryBuilder) UpdateColumn(column string, value any) bool { // Delete 删除记录。 func (q *QueryBuilder) Delete(value any) bool { if err := q.base().Delete(value).Error; err != nil { - log.Printf("[repository] Delete error: %v", err) + log.Printf("[dal] Delete error: %v", err) return false } return true @@ -172,7 +172,7 @@ func (q *QueryBuilder) Delete(value any) bool { // DeleteByID 按主键 ID 删除。 func (q *QueryBuilder) DeleteByID(model any, id uint) bool { if err := q.base().Model(model).Where("id = ?", id).Delete(model).Error; err != nil { - log.Printf("[repository] DeleteByID error: %v", err) + log.Printf("[dal] DeleteByID error: %v", err) return false } return true @@ -186,7 +186,7 @@ func (q *QueryBuilder) Raw(sql string, args ...any) *QueryBuilder { // Scan 将结果扫描到目标结构体。 func (q *QueryBuilder) Scan(dest any) bool { if err := q.base().Scan(dest).Error; err != nil { - log.Printf("[repository] Scan error: %v", err) + log.Printf("[dal] Scan error: %v", err) return false } return true diff --git a/eai_agentplatform/backend-go/internal/repository/course.go b/eai_agentplatform/backend-go/internal/dal/course.go similarity index 78% rename from eai_agentplatform/backend-go/internal/repository/course.go rename to eai_agentplatform/backend-go/internal/dal/course.go index 01b6c14..c2b4f82 100644 --- a/eai_agentplatform/backend-go/internal/repository/course.go +++ b/eai_agentplatform/backend-go/internal/dal/course.go @@ -1,11 +1,11 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // Course 课程仓库。 -type CourseRepo struct{ *QueryBuilder } +type CourseDAO struct{ *QueryBuilder } // List 获取课程列表(按条件过滤)。 // @@ -13,7 +13,7 @@ type CourseRepo struct{ *QueryBuilder } // - ""(默认):仅 active —— 员工浏览视角 // - "all":管理员维护视角,不按状态过滤 // - 其他:按该状态精确过滤 -func (r CourseRepo) List(category, status string) []model.Course { +func (r CourseDAO) List(category, status string) []model.Course { q := r.Type(&model.Course{}) if category != "" { q = q.Where("category = ?", category) @@ -33,7 +33,7 @@ func (r CourseRepo) List(category, status string) []model.Course { } // GetByID 按 ID 获取。 -func (r CourseRepo) GetByID(id uint) (model.Course, bool) { +func (r CourseDAO) GetByID(id uint) (model.Course, bool) { var c model.Course if r.Type(&c).Where("id = ?", id).First(&c) { return c, true @@ -42,7 +42,7 @@ func (r CourseRepo) GetByID(id uint) (model.Course, bool) { } // GetByCode 按编号获取。 -func (r CourseRepo) GetByCode(code string) (model.Course, bool) { +func (r CourseDAO) GetByCode(code string) (model.Course, bool) { var c model.Course if r.Type(&c).Where("code = ?", code).First(&c) { return c, true @@ -51,22 +51,22 @@ func (r CourseRepo) GetByCode(code string) (model.Course, bool) { } // Insert 创建课程。 -func (r CourseRepo) Insert(c *model.Course) bool { +func (r CourseDAO) Insert(c *model.Course) bool { return r.QueryBuilder.Insert(c) } // Update 更新课程。 -func (r CourseRepo) Update(c *model.Course) bool { +func (r CourseDAO) Update(c *model.Course) bool { return r.Save(c) } // Delete 软删除。 -func (r CourseRepo) Delete(id uint) bool { +func (r CourseDAO) Delete(id uint) bool { return r.Type(&model.Course{}).Where("id = ?", id).Updates(map[string]any{"status": "inactive"}) } // CountByCode 按编号统计(唯一性检查)。 -func (r CourseRepo) CountByCode(code string, excludeID *uint) int64 { +func (r CourseDAO) CountByCode(code string, excludeID *uint) int64 { var c int64 q := r.Inner().Model(&model.Course{}).Where("code = ?", code) if excludeID != nil { @@ -78,7 +78,7 @@ func (r CourseRepo) CountByCode(code string, excludeID *uint) int64 { // NamesByIDs 批量解析课程名称(id → name),用于列表页回填关联名称。 // 未命中的 ID 不会出现在返回的 map 中,调用方需自行兜底。 -func (r CourseRepo) NamesByIDs(ids []uint) map[uint]string { +func (r CourseDAO) NamesByIDs(ids []uint) map[uint]string { names := map[uint]string{} if len(ids) == 0 { return names diff --git a/eai_agentplatform/backend-go/internal/repository/department.go b/eai_agentplatform/backend-go/internal/dal/department.go similarity index 69% rename from eai_agentplatform/backend-go/internal/repository/department.go rename to eai_agentplatform/backend-go/internal/dal/department.go index d663b52..6f399db 100644 --- a/eai_agentplatform/backend-go/internal/repository/department.go +++ b/eai_agentplatform/backend-go/internal/dal/department.go @@ -1,14 +1,14 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // Department 部门仓库。 -type DepartmentRepo struct{ *QueryBuilder } +type DepartmentDAO struct{ *QueryBuilder } // List 获取部门列表。 -func (r DepartmentRepo) List() []model.Department { +func (r DepartmentDAO) List() []model.Department { var items []model.Department if r.Type(&items).Order("id ASC").Find(&items) { return items @@ -18,12 +18,12 @@ func (r DepartmentRepo) List() []model.Department { // ListByStatus 按状态取部门列表(id 升序)。 // -// status 沿用本站列表的档位约定(与 CourseRepo.List 一致): +// status 沿用本站列表的档位约定(与 CourseDAO.List 一致): // // "" → 只看 active(前台字典默认) // "all" → 不过滤(管理员维护全量) // 其它 → 按该 status 过滤 -func (r DepartmentRepo) ListByStatus(status string) []model.Department { +func (r DepartmentDAO) ListByStatus(status string) []model.Department { q := r.Type(&model.Department{}) switch status { case "": @@ -41,7 +41,7 @@ func (r DepartmentRepo) ListByStatus(status string) []model.Department { } // CountByName 统计同名部门数;excludeID 非空时排除该条(改名查重用)。 -func (r DepartmentRepo) CountByName(name string, excludeID *uint) int64 { +func (r DepartmentDAO) CountByName(name string, excludeID *uint) int64 { q := r.Inner().Model(&model.Department{}).Where("name = ?", name) if excludeID != nil { q = q.Where("id <> ?", *excludeID) @@ -52,7 +52,7 @@ func (r DepartmentRepo) CountByName(name string, excludeID *uint) int64 { } // GetByID 按 ID 获取。 -func (r DepartmentRepo) GetByID(id uint) (model.Department, bool) { +func (r DepartmentDAO) GetByID(id uint) (model.Department, bool) { var d model.Department if r.Type(&d).Where("id = ?", id).First(&d) { return d, true @@ -61,7 +61,7 @@ func (r DepartmentRepo) GetByID(id uint) (model.Department, bool) { } // GetByName 按名称获取。 -func (r DepartmentRepo) GetByName(name string) (model.Department, bool) { +func (r DepartmentDAO) GetByName(name string) (model.Department, bool) { var d model.Department if r.Type(&d).Where("name = ?", name).First(&d) { return d, true @@ -70,16 +70,16 @@ func (r DepartmentRepo) GetByName(name string) (model.Department, bool) { } // Insert 创建部门。 -func (r DepartmentRepo) Insert(d *model.Department) bool { +func (r DepartmentDAO) Insert(d *model.Department) bool { return r.QueryBuilder.Insert(d) } // Update 更新部门。 -func (r DepartmentRepo) Update(d *model.Department) bool { +func (r DepartmentDAO) Update(d *model.Department) bool { return r.Save(d) } // Delete 删除部门。 -func (r DepartmentRepo) Delete(id uint) bool { +func (r DepartmentDAO) Delete(id uint) bool { return r.DeleteByID(&model.Department{}, id) } diff --git a/eai_agentplatform/backend-go/internal/repository/exam_paper.go b/eai_agentplatform/backend-go/internal/dal/exam_paper.go similarity index 68% rename from eai_agentplatform/backend-go/internal/repository/exam_paper.go rename to eai_agentplatform/backend-go/internal/dal/exam_paper.go index 0f6c8ac..69f4282 100644 --- a/eai_agentplatform/backend-go/internal/repository/exam_paper.go +++ b/eai_agentplatform/backend-go/internal/dal/exam_paper.go @@ -1,14 +1,14 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // ExamPaper 试卷仓库。 -type ExamPaperRepo struct{ *QueryBuilder } +type ExamPaperDAO struct{ *QueryBuilder } // List 获取全部试卷(id 升序,含已停用)—— 管理端考试配置列表。 -func (r ExamPaperRepo) List() []model.ExamPaper { +func (r ExamPaperDAO) List() []model.ExamPaper { var items []model.ExamPaper if r.Type(&items).Order("id ASC").Find(&items) { return items @@ -17,7 +17,7 @@ func (r ExamPaperRepo) List() []model.ExamPaper { } // GetByID 按 ID 获取。 -func (r ExamPaperRepo) GetByID(id uint) (model.ExamPaper, bool) { +func (r ExamPaperDAO) GetByID(id uint) (model.ExamPaper, bool) { var p model.ExamPaper if r.Type(&p).Where("id = ?", id).First(&p) { return p, true @@ -26,7 +26,7 @@ func (r ExamPaperRepo) GetByID(id uint) (model.ExamPaper, bool) { } // GetActive 获取所有激活的试卷。 -func (r ExamPaperRepo) GetActive() []model.ExamPaper { +func (r ExamPaperDAO) GetActive() []model.ExamPaper { var items []model.ExamPaper if r.Type(&items).Where("status = ?", "active").Find(&items) { return items @@ -35,22 +35,22 @@ func (r ExamPaperRepo) GetActive() []model.ExamPaper { } // Insert 创建试卷。 -func (r ExamPaperRepo) Insert(p *model.ExamPaper) bool { +func (r ExamPaperDAO) Insert(p *model.ExamPaper) bool { return r.QueryBuilder.Insert(p) } // Update 更新试卷。 -func (r ExamPaperRepo) Update(p *model.ExamPaper) bool { +func (r ExamPaperDAO) Update(p *model.ExamPaper) bool { return r.Save(p) } // Delete 软删除。 -func (r ExamPaperRepo) Delete(id uint) bool { +func (r ExamPaperDAO) Delete(id uint) bool { return r.Type(&model.ExamPaper{}).Where("id = ?", id).Updates(map[string]any{"status": "inactive"}) } // Count 统计试卷数。 -func (r ExamPaperRepo) Count() int64 { +func (r ExamPaperDAO) Count() int64 { var c int64 r.Inner().Model(&model.ExamPaper{}).Count(&c) return c diff --git a/eai_agentplatform/backend-go/internal/repository/exam_record.go b/eai_agentplatform/backend-go/internal/dal/exam_record.go similarity index 75% rename from eai_agentplatform/backend-go/internal/repository/exam_record.go rename to eai_agentplatform/backend-go/internal/dal/exam_record.go index a03f6bc..a1a4fd6 100644 --- a/eai_agentplatform/backend-go/internal/repository/exam_record.go +++ b/eai_agentplatform/backend-go/internal/dal/exam_record.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "strconv" @@ -7,10 +7,10 @@ import ( ) // ExamRecord 考试记录仓库。 -type ExamRecordRepo struct{ *QueryBuilder } +type ExamRecordDAO struct{ *QueryBuilder } // List 获取考试记录列表。 -func (r ExamRecordRepo) List(userIDStr, paperIDStr string) []model.ExamRecord { +func (r ExamRecordDAO) List(userIDStr, paperIDStr string) []model.ExamRecord { q := r.Type(&model.ExamRecord{}) if userIDStr != "" { if uid, err := strconv.ParseUint(userIDStr, 10, 32); err == nil { @@ -30,7 +30,7 @@ func (r ExamRecordRepo) List(userIDStr, paperIDStr string) []model.ExamRecord { } // GetByID 按 ID 获取。 -func (r ExamRecordRepo) GetByID(id uint) (model.ExamRecord, bool) { +func (r ExamRecordDAO) GetByID(id uint) (model.ExamRecord, bool) { var rec model.ExamRecord if r.Type(&rec).Where("id = ?", id).First(&rec) { return rec, true @@ -39,22 +39,22 @@ func (r ExamRecordRepo) GetByID(id uint) (model.ExamRecord, bool) { } // Insert 创建记录。 -func (r ExamRecordRepo) Insert(rec *model.ExamRecord) bool { +func (r ExamRecordDAO) Insert(rec *model.ExamRecord) bool { return r.QueryBuilder.Insert(rec) } // Update 更新记录。 -func (r ExamRecordRepo) Update(rec *model.ExamRecord) bool { +func (r ExamRecordDAO) Update(rec *model.ExamRecord) bool { return r.Save(rec) } // Remove 删除记录。 -func (r ExamRecordRepo) Remove(id uint) bool { +func (r ExamRecordDAO) Remove(id uint) bool { return r.DeleteByID(&model.ExamRecord{}, id) } // CountByUser 统计某用户的考试记录数。 -func (r ExamRecordRepo) CountByUser(userID uint) int64 { +func (r ExamRecordDAO) CountByUser(userID uint) int64 { var c int64 r.Inner().Model(&model.ExamRecord{}).Where("user_id = ?", userID).Count(&c) return c @@ -62,7 +62,7 @@ func (r ExamRecordRepo) CountByUser(userID uint) int64 { // HasTaken 判断用户是否已参加过某张试卷(正式考的唯一性依据)。 // 试卷列表标注「已完成」、开考拦截、交卷拦截三处共用同一语义。 -func (r ExamRecordRepo) HasTaken(userID, paperID uint) bool { +func (r ExamRecordDAO) HasTaken(userID, paperID uint) bool { var c int64 r.Inner().Model(&model.ExamRecord{}). Where("user_id = ? AND paper_id = ?", userID, paperID). @@ -71,7 +71,7 @@ func (r ExamRecordRepo) HasTaken(userID, paperID uint) bool { } // ListByUser 取某用户的考试记录(按提交时间倒序)。 -func (r ExamRecordRepo) ListByUser(userID uint) []model.ExamRecord { +func (r ExamRecordDAO) ListByUser(userID uint) []model.ExamRecord { var items []model.ExamRecord if r.Type(&items).Where("user_id = ?", userID).Order("submitted_at DESC").Find(&items) { return items @@ -82,7 +82,7 @@ func (r ExamRecordRepo) ListByUser(userID uint) []model.ExamRecord { // ListByUserChronological 取某用户的考试记录(按提交时间正序)。 // // 与 ListByUser 只差排序方向:列表页要最新在前,成绩趋势图要按时间从左到右。 -func (r ExamRecordRepo) ListByUserChronological(userID uint) []model.ExamRecord { +func (r ExamRecordDAO) ListByUserChronological(userID uint) []model.ExamRecord { var items []model.ExamRecord if r.Type(&items).Where("user_id = ?", userID).Order("submitted_at ASC").Find(&items) { return items @@ -91,7 +91,7 @@ func (r ExamRecordRepo) ListByUserChronological(userID uint) []model.ExamRecord } // ListAll 取全部考试记录(按提交时间倒序,供管理员导出与统计)。 -func (r ExamRecordRepo) ListAll() []model.ExamRecord { +func (r ExamRecordDAO) ListAll() []model.ExamRecord { var items []model.ExamRecord if r.Type(&items).Order("submitted_at DESC").Find(&items) { return items diff --git a/eai_agentplatform/backend-go/internal/repository/knowledge_chunk.go b/eai_agentplatform/backend-go/internal/dal/knowledge_chunk.go similarity index 76% rename from eai_agentplatform/backend-go/internal/repository/knowledge_chunk.go rename to eai_agentplatform/backend-go/internal/dal/knowledge_chunk.go index dca3972..0ceab70 100644 --- a/eai_agentplatform/backend-go/internal/repository/knowledge_chunk.go +++ b/eai_agentplatform/backend-go/internal/dal/knowledge_chunk.go @@ -1,11 +1,11 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // KnowledgeChunk 知识分片仓库。 -type KnowledgeChunkRepo struct{ *QueryBuilder } +type KnowledgeChunkDAO struct{ *QueryBuilder } // ApprovedMetaMaps 批量加载解析分片元信息所需的「已审批」素材与知识源(id → 记录)。 // @@ -14,7 +14,7 @@ type KnowledgeChunkRepo struct{ *QueryBuilder } // media_file_id / knowledge_source_id 的分片被整段丢弃**(历史上 loadKnowledgeCandidates // 就踩过这个坑,AI 检索候选集只剩「无指针」分片)。 // AI 检索候选与知识索引构建共用此方法,避免两处各自手写过滤条件而漂移。 -func (r KnowledgeChunkRepo) ApprovedMetaMaps() (map[uint]model.MediaFile, map[uint]model.KnowledgeSource) { +func (r KnowledgeChunkDAO) ApprovedMetaMaps() (map[uint]model.MediaFile, map[uint]model.KnowledgeSource) { var mediaFiles []model.MediaFile r.Type(&mediaFiles).Where("status = ?", "approved").Find(&mediaFiles) mediaMap := make(map[uint]model.MediaFile, len(mediaFiles)) @@ -32,14 +32,14 @@ func (r KnowledgeChunkRepo) ApprovedMetaMaps() (map[uint]model.MediaFile, map[ui } // CountByMediaFile 统计某素材切出的分片数(素材状态页用于展示提取结果)。 -func (r KnowledgeChunkRepo) CountByMediaFile(mediaID uint) int64 { +func (r KnowledgeChunkDAO) CountByMediaFile(mediaID uint) int64 { var c int64 r.Inner().Model(&model.KnowledgeChunk{}).Where("media_file_id = ?", mediaID).Count(&c) return c } // GetByID 按 ID 获取。 -func (r KnowledgeChunkRepo) GetByID(id uint) (model.KnowledgeChunk, bool) { +func (r KnowledgeChunkDAO) GetByID(id uint) (model.KnowledgeChunk, bool) { var c model.KnowledgeChunk if r.Type(&c).Where("id = ?", id).First(&c) { return c, true @@ -48,12 +48,12 @@ func (r KnowledgeChunkRepo) GetByID(id uint) (model.KnowledgeChunk, bool) { } // Insert 创建分片。 -func (r KnowledgeChunkRepo) Insert(c *model.KnowledgeChunk) bool { +func (r KnowledgeChunkDAO) Insert(c *model.KnowledgeChunk) bool { return r.QueryBuilder.Insert(c) } // BulkInsert 批量创建分片。 -func (r KnowledgeChunkRepo) BulkInsert(items []model.KnowledgeChunk) int { +func (r KnowledgeChunkDAO) BulkInsert(items []model.KnowledgeChunk) int { count := 0 for i := range items { if r.QueryBuilder.Insert(&items[i]) { @@ -64,11 +64,11 @@ func (r KnowledgeChunkRepo) BulkInsert(items []model.KnowledgeChunk) int { } // Update 更新分片。 -func (r KnowledgeChunkRepo) Update(c *model.KnowledgeChunk) bool { +func (r KnowledgeChunkDAO) Update(c *model.KnowledgeChunk) bool { return r.Save(c) } // DeleteByID 按 ID 删除。 -func (r KnowledgeChunkRepo) RemoveByID(id uint) bool { +func (r KnowledgeChunkDAO) RemoveByID(id uint) bool { return r.DeleteByID(&model.KnowledgeChunk{}, id) } diff --git a/eai_agentplatform/backend-go/internal/repository/knowledge_faq.go b/eai_agentplatform/backend-go/internal/dal/knowledge_faq.go similarity index 80% rename from eai_agentplatform/backend-go/internal/repository/knowledge_faq.go rename to eai_agentplatform/backend-go/internal/dal/knowledge_faq.go index 7068d2c..b55ea4d 100644 --- a/eai_agentplatform/backend-go/internal/repository/knowledge_faq.go +++ b/eai_agentplatform/backend-go/internal/dal/knowledge_faq.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "gorm.io/gorm" @@ -9,13 +9,13 @@ import ( // KnowledgeFAQ FAQ 仓库。 // // 知识空间一律用 knowledge_space_key 字符串关联,表上没有 space_id。 -type KnowledgeFAQRepo struct{ *QueryBuilder } +type KnowledgeFAQDAO struct{ *QueryBuilder } // ListForAdmin 后台 FAQ 列表(分页,sort_order 升序、id 倒序)。 // // spaceKey / status / keyword 为空表示不过滤该维度。page 从 1 起, // size 由调用方校验后传入。 -func (r KnowledgeFAQRepo) ListForAdmin(spaceKey, status, keyword string, page, size int) (int64, []model.KnowledgeFAQ) { +func (r KnowledgeFAQDAO) ListForAdmin(spaceKey, status, keyword string, page, size int) (int64, []model.KnowledgeFAQ) { q := r.Inner().Model(&model.KnowledgeFAQ{}) if spaceKey != "" { q = q.Where("knowledge_space_key = ?", spaceKey) @@ -40,7 +40,7 @@ func (r KnowledgeFAQRepo) ListForAdmin(spaceKey, status, keyword string, page, s // 口径:只取 status=active;spaceKey 为空 / general / all 时取全量, // 否则取该空间 + general 两级(通用 FAQ 对所有空间生效)。 // 打分与命中计数由调用方负责,仓库只负责把候选池的口径固定下来。 -func (r KnowledgeFAQRepo) ActiveCandidates(spaceKey string) []model.KnowledgeFAQ { +func (r KnowledgeFAQDAO) ActiveCandidates(spaceKey string) []model.KnowledgeFAQ { q := r.Type(&model.KnowledgeFAQ{}).Where("status = ?", "active") if spaceKey != "" && spaceKey != "general" && spaceKey != "all" { q = q.Where("knowledge_space_key IN ?", []string{spaceKey, "general"}) @@ -53,13 +53,13 @@ func (r KnowledgeFAQRepo) ActiveCandidates(spaceKey string) []model.KnowledgeFAQ } // IncrHit 命中计数 +1。 -func (r KnowledgeFAQRepo) IncrHit(id uint) bool { +func (r KnowledgeFAQDAO) IncrHit(id uint) bool { return r.Type(&model.KnowledgeFAQ{}).Where("id = ?", id). UpdateColumn("hit_count", gorm.Expr("hit_count + ?", 1)) } // GetByID 按 ID 获取。 -func (r KnowledgeFAQRepo) GetByID(id uint) (model.KnowledgeFAQ, bool) { +func (r KnowledgeFAQDAO) GetByID(id uint) (model.KnowledgeFAQ, bool) { var f model.KnowledgeFAQ if r.Type(&f).Where("id = ?", id).First(&f) { return f, true @@ -68,12 +68,12 @@ func (r KnowledgeFAQRepo) GetByID(id uint) (model.KnowledgeFAQ, bool) { } // Insert 创建 FAQ。 -func (r KnowledgeFAQRepo) Insert(f *model.KnowledgeFAQ) bool { +func (r KnowledgeFAQDAO) Insert(f *model.KnowledgeFAQ) bool { return r.QueryBuilder.Insert(f) } // Update 更新 FAQ(整字段覆盖,调用方需带回原主键与创建时间)。 -func (r KnowledgeFAQRepo) Update(f *model.KnowledgeFAQ) bool { +func (r KnowledgeFAQDAO) Update(f *model.KnowledgeFAQ) bool { return r.Save(f) } @@ -81,6 +81,6 @@ func (r KnowledgeFAQRepo) Update(f *model.KnowledgeFAQ) bool { // // 与本站其它对象的「软删除(置 status)」不同,FAQ 是直接删行: // 沿用原有行为,未改。若要改成软删需先确认后台 UI 与命中统计口径。 -func (r KnowledgeFAQRepo) Delete(id uint) bool { +func (r KnowledgeFAQDAO) Delete(id uint) bool { return r.DeleteByID(&model.KnowledgeFAQ{}, id) } diff --git a/eai_agentplatform/backend-go/internal/repository/knowledge_source.go b/eai_agentplatform/backend-go/internal/dal/knowledge_source.go similarity index 76% rename from eai_agentplatform/backend-go/internal/repository/knowledge_source.go rename to eai_agentplatform/backend-go/internal/dal/knowledge_source.go index 46bb689..95e0f05 100644 --- a/eai_agentplatform/backend-go/internal/repository/knowledge_source.go +++ b/eai_agentplatform/backend-go/internal/dal/knowledge_source.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" @@ -8,10 +8,10 @@ import ( // // 注意状态列是 audit_status(pending/approved/rejected),不是通用的 status; // 表上也没有 space_id —— 知识空间一律用 knowledge_space_key 字符串关联。 -type KnowledgeSourceRepo struct{ *QueryBuilder } +type KnowledgeSourceDAO struct{ *QueryBuilder } // GetByID 按 ID 获取。 -func (r KnowledgeSourceRepo) GetByID(id uint) (model.KnowledgeSource, bool) { +func (r KnowledgeSourceDAO) GetByID(id uint) (model.KnowledgeSource, bool) { var s model.KnowledgeSource if r.Type(&s).Where("id = ?", id).First(&s) { return s, true @@ -22,7 +22,7 @@ func (r KnowledgeSourceRepo) GetByID(id uint) (model.KnowledgeSource, bool) { // GetByFilePath 按文件名获取知识源。 // // 扫描入库时用它去重:file_path 存的是知识源目录下的文件名,不是绝对路径。 -func (r KnowledgeSourceRepo) GetByFilePath(name string) (model.KnowledgeSource, bool) { +func (r KnowledgeSourceDAO) GetByFilePath(name string) (model.KnowledgeSource, bool) { var s model.KnowledgeSource if r.Type(&s).Where("file_path = ?", name).First(&s) { return s, true @@ -33,7 +33,7 @@ func (r KnowledgeSourceRepo) GetByFilePath(name string) (model.KnowledgeSource, // ListForAudit 知识源审批列表(分页,id 升序)。 // // status / spaceKey 为空表示不过滤该维度。page 从 1 起,size 由调用方校验后传入。 -func (r KnowledgeSourceRepo) ListForAudit(status, spaceKey string, page, size int) (int64, []model.KnowledgeSource) { +func (r KnowledgeSourceDAO) ListForAudit(status, spaceKey string, page, size int) (int64, []model.KnowledgeSource) { q := r.Inner().Model(&model.KnowledgeSource{}) if status != "" { q = q.Where("audit_status = ?", status) @@ -52,7 +52,7 @@ func (r KnowledgeSourceRepo) ListForAudit(status, spaceKey string, page, size in // ListApproved 全部已审批知识源(id 升序)。 // // 供知识空间统计与检索元信息解析使用;调用方通常只需要 id → 记录 的映射。 -func (r KnowledgeSourceRepo) ListApproved() []model.KnowledgeSource { +func (r KnowledgeSourceDAO) ListApproved() []model.KnowledgeSource { var items []model.KnowledgeSource if r.Type(&items).Where("audit_status = ?", "approved").Find(&items) { return items @@ -61,11 +61,11 @@ func (r KnowledgeSourceRepo) ListApproved() []model.KnowledgeSource { } // Insert 创建知识源。 -func (r KnowledgeSourceRepo) Insert(s *model.KnowledgeSource) bool { +func (r KnowledgeSourceDAO) Insert(s *model.KnowledgeSource) bool { return r.QueryBuilder.Insert(s) } // Update 更新知识源(整字段覆盖,调用方需带回原主键与创建时间)。 -func (r KnowledgeSourceRepo) Update(s *model.KnowledgeSource) bool { +func (r KnowledgeSourceDAO) Update(s *model.KnowledgeSource) bool { return r.Save(s) } diff --git a/eai_agentplatform/backend-go/internal/repository/knowledge_space.go b/eai_agentplatform/backend-go/internal/dal/knowledge_space.go similarity index 67% rename from eai_agentplatform/backend-go/internal/repository/knowledge_space.go rename to eai_agentplatform/backend-go/internal/dal/knowledge_space.go index 7cba4ff..1e46954 100644 --- a/eai_agentplatform/backend-go/internal/repository/knowledge_space.go +++ b/eai_agentplatform/backend-go/internal/dal/knowledge_space.go @@ -1,14 +1,14 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // KnowledgeSpace 知识空间仓库。 -type KnowledgeSpaceRepo struct{ *QueryBuilder } +type KnowledgeSpaceDAO struct{ *QueryBuilder } // List 获取知识空间列表。 -func (r KnowledgeSpaceRepo) List(status string) []model.KnowledgeSpace { +func (r KnowledgeSpaceDAO) List(status string) []model.KnowledgeSpace { q := r.Type(&model.KnowledgeSpace{}) if status != "" { q = q.Where("status = ?", status) @@ -21,7 +21,7 @@ func (r KnowledgeSpaceRepo) List(status string) []model.KnowledgeSpace { } // GetByID 按 ID 获取。 -func (r KnowledgeSpaceRepo) GetByID(id uint) (model.KnowledgeSpace, bool) { +func (r KnowledgeSpaceDAO) GetByID(id uint) (model.KnowledgeSpace, bool) { var s model.KnowledgeSpace if r.Type(&s).Where("id = ?", id).First(&s) { return s, true @@ -30,7 +30,7 @@ func (r KnowledgeSpaceRepo) GetByID(id uint) (model.KnowledgeSpace, bool) { } // GetByName 按名称获取。 -func (r KnowledgeSpaceRepo) GetByName(name string) (model.KnowledgeSpace, bool) { +func (r KnowledgeSpaceDAO) GetByName(name string) (model.KnowledgeSpace, bool) { var s model.KnowledgeSpace if r.Type(&s).Where("name = ?", name).First(&s) { return s, true @@ -39,22 +39,22 @@ func (r KnowledgeSpaceRepo) GetByName(name string) (model.KnowledgeSpace, bool) } // Insert 创建知识空间。 -func (r KnowledgeSpaceRepo) Insert(s *model.KnowledgeSpace) bool { +func (r KnowledgeSpaceDAO) Insert(s *model.KnowledgeSpace) bool { return r.QueryBuilder.Insert(s) } // Update 更新知识空间。 -func (r KnowledgeSpaceRepo) Update(s *model.KnowledgeSpace) bool { +func (r KnowledgeSpaceDAO) Update(s *model.KnowledgeSpace) bool { return r.Save(s) } // Delete 软删除。 -func (r KnowledgeSpaceRepo) Delete(id uint) bool { +func (r KnowledgeSpaceDAO) Delete(id uint) bool { return r.Type(&model.KnowledgeSpace{}).Where("id = ?", id).Updates(map[string]any{"status": "inactive"}) } // CountByName 按名称统计(唯一性检查)。 -func (r KnowledgeSpaceRepo) CountByName(name string, excludeID *uint) int64 { +func (r KnowledgeSpaceDAO) CountByName(name string, excludeID *uint) int64 { q := r.Inner().Model(&model.KnowledgeSpace{}).Where("name = ?", name) if excludeID != nil { q = q.Where("id <> ?", *excludeID) @@ -65,7 +65,7 @@ func (r KnowledgeSpaceRepo) CountByName(name string, excludeID *uint) int64 { } // CountByID 按 ID 统计。 -func (r KnowledgeSpaceRepo) Count() int64 { +func (r KnowledgeSpaceDAO) Count() int64 { var c int64 r.Inner().Model(&model.KnowledgeSpace{}).Count(&c) return c diff --git a/eai_agentplatform/backend-go/internal/repository/learning_progress.go b/eai_agentplatform/backend-go/internal/dal/learning_progress.go similarity index 72% rename from eai_agentplatform/backend-go/internal/repository/learning_progress.go rename to eai_agentplatform/backend-go/internal/dal/learning_progress.go index 638a255..56fe735 100644 --- a/eai_agentplatform/backend-go/internal/repository/learning_progress.go +++ b/eai_agentplatform/backend-go/internal/dal/learning_progress.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "time" @@ -7,10 +7,10 @@ import ( ) // LearningProgress 学习进度仓库。 -type LearningProgressRepo struct{ *QueryBuilder } +type LearningProgressDAO struct{ *QueryBuilder } // Get 获取用户某条学习进度。 -func (r LearningProgressRepo) Get(userID uint, itemType string, itemID uint) (model.LearningProgress, bool) { +func (r LearningProgressDAO) Get(userID uint, itemType string, itemID uint) (model.LearningProgress, bool) { var p model.LearningProgress if r.Type(&p).Where("user_id = ? AND item_type = ? AND item_id = ?", userID, itemType, itemID).First(&p) { return p, true @@ -19,7 +19,7 @@ func (r LearningProgressRepo) Get(userID uint, itemType string, itemID uint) (mo } // ListByUser 获取某用户的所有学习进度。 -func (r LearningProgressRepo) ListByUser(userID uint) []model.LearningProgress { +func (r LearningProgressDAO) ListByUser(userID uint) []model.LearningProgress { var items []model.LearningProgress if r.Type(&items).Where("user_id = ?", userID).Order("updated_at DESC").Find(&items) { return items @@ -28,7 +28,7 @@ func (r LearningProgressRepo) ListByUser(userID uint) []model.LearningProgress { } // ListAll 取全部学习进度(updated_at 倒序,管理端全员视图)。 -func (r LearningProgressRepo) ListAll() []model.LearningProgress { +func (r LearningProgressDAO) ListAll() []model.LearningProgress { var items []model.LearningProgress if r.Type(&items).Order("updated_at DESC").Find(&items) { return items @@ -37,7 +37,7 @@ func (r LearningProgressRepo) ListAll() []model.LearningProgress { } // Upsert 插入或更新学习进度。 -func (r LearningProgressRepo) Upsert(p *model.LearningProgress) bool { +func (r LearningProgressDAO) Upsert(p *model.LearningProgress) bool { existing, found := r.Get(p.UserID, p.ItemType, p.ItemID) if !found { return r.Insert(p) @@ -47,7 +47,7 @@ func (r LearningProgressRepo) Upsert(p *model.LearningProgress) bool { } // Record 记录一条学习进度。 -func (r LearningProgressRepo) Record(userID uint, itemType string, itemID uint) bool { +func (r LearningProgressDAO) Record(userID uint, itemType string, itemID uint) bool { _, found := r.Get(userID, itemType, itemID) if found { return r.Upsert(&model.LearningProgress{UserID: userID, ItemType: itemType, ItemID: itemID}) diff --git a/eai_agentplatform/backend-go/internal/repository/media_file.go b/eai_agentplatform/backend-go/internal/dal/media_file.go similarity index 78% rename from eai_agentplatform/backend-go/internal/repository/media_file.go rename to eai_agentplatform/backend-go/internal/dal/media_file.go index b34ff0c..2a8202b 100644 --- a/eai_agentplatform/backend-go/internal/repository/media_file.go +++ b/eai_agentplatform/backend-go/internal/dal/media_file.go @@ -1,14 +1,14 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // MediaFile 媒体文件仓库。 -type MediaFileRepo struct{ *QueryBuilder } +type MediaFileDAO struct{ *QueryBuilder } // GetByID 按 ID 获取。 -func (r MediaFileRepo) GetByID(id uint) (model.MediaFile, bool) { +func (r MediaFileDAO) GetByID(id uint) (model.MediaFile, bool) { var m model.MediaFile if r.Type(&m).Where("id = ?", id).First(&m) { return m, true @@ -17,17 +17,17 @@ func (r MediaFileRepo) GetByID(id uint) (model.MediaFile, bool) { } // Insert 创建文件记录。 -func (r MediaFileRepo) Insert(m *model.MediaFile) bool { +func (r MediaFileDAO) Insert(m *model.MediaFile) bool { return r.QueryBuilder.Insert(m) } // Update 更新文件记录。 -func (r MediaFileRepo) Update(m *model.MediaFile) bool { +func (r MediaFileDAO) Update(m *model.MediaFile) bool { return r.Save(m) } // Delete 删除文件记录。 -func (r MediaFileRepo) Delete(id uint) bool { +func (r MediaFileDAO) Delete(id uint) bool { return r.DeleteByID(&model.MediaFile{}, id) } @@ -35,7 +35,7 @@ func (r MediaFileRepo) Delete(id uint) bool { // // 「审批前置」的落点:课程/产品详情只露出 approved 素材,pending 与 rejected 一律不出现在业务页面。 // 调用方无需再自己拼 bind_type/bind_id/status 三条件,避免各处漏掉 status 过滤而泄漏未审批素材。 -func (r MediaFileRepo) ListByBind(bindType string, bindID uint) []model.MediaFile { +func (r MediaFileDAO) ListByBind(bindType string, bindID uint) []model.MediaFile { var items []model.MediaFile if r.Type(&items). Where("bind_type = ? AND bind_id = ? AND status = ?", bindType, bindID, "approved"). @@ -49,7 +49,7 @@ func (r MediaFileRepo) ListByBind(bindType string, bindID uint) []model.MediaFil // // 与 ListByBind 的区别:只按绑定类型取,不限定 bind_id。 // 公司介绍课件这类「全局素材」不挂具体实体,bind_id 无意义。 -func (r MediaFileRepo) ListApprovedByBindType(bindType string) []model.MediaFile { +func (r MediaFileDAO) ListApprovedByBindType(bindType string) []model.MediaFile { var items []model.MediaFile if r.Type(&items). Where("bind_type = ? AND status = ?", bindType, "approved"). @@ -62,7 +62,7 @@ func (r MediaFileRepo) ListApprovedByBindType(bindType string) []model.MediaFile // ListForAudit 审批列表(分页):返回符合条件的总数与本页记录,created_at 倒序。 // // status / spaceKey 为空表示不过滤该维度。page 从 1 起,size 由调用方校验后再传入。 -func (r MediaFileRepo) ListForAudit(status, spaceKey string, page, size int) (int64, []model.MediaFile) { +func (r MediaFileDAO) ListForAudit(status, spaceKey string, page, size int) (int64, []model.MediaFile) { q := r.Inner().Model(&model.MediaFile{}) if status != "" { q = q.Where("status = ?", status) @@ -79,6 +79,6 @@ func (r MediaFileRepo) ListForAudit(status, spaceKey string, page, size int) (in } // MarkExtracted 标记素材已完成提取(视频/图片仅有此标记,文档由提取管线置位)。 -func (r MediaFileRepo) MarkExtracted(id uint) bool { +func (r MediaFileDAO) MarkExtracted(id uint) bool { return r.Type(&model.MediaFile{}).Where("id = ?", id).UpdateColumn("extracted", true) } diff --git a/eai_agentplatform/backend-go/internal/repository/mistake_record.go b/eai_agentplatform/backend-go/internal/dal/mistake_record.go similarity index 79% rename from eai_agentplatform/backend-go/internal/repository/mistake_record.go rename to eai_agentplatform/backend-go/internal/dal/mistake_record.go index 89ea110..4d3815d 100644 --- a/eai_agentplatform/backend-go/internal/repository/mistake_record.go +++ b/eai_agentplatform/backend-go/internal/dal/mistake_record.go @@ -1,18 +1,18 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) -// MistakeRecordRepo 错题记录仓库。 +// MistakeRecordDAO 错题记录仓库。 // // 错题本有两套口径,都收在本仓库里,避免调用方各写各的 Where: // - 入本/再次答错:唯一键 (user_id, question_id, source),见 RecordWrong // - 重练判分回写:按 (user_id, question_id) 扇出,把该题在所有来源下的记录一并更新,见 TouchOnPractice -type MistakeRecordRepo struct{ *QueryBuilder } +type MistakeRecordDAO struct{ *QueryBuilder } // ListByUser 我的错题本(按最近更新倒序)。 -func (r MistakeRecordRepo) ListByUser(userID uint) []model.MistakeRecord { +func (r MistakeRecordDAO) ListByUser(userID uint) []model.MistakeRecord { var items []model.MistakeRecord if r.Type(&items).Where("user_id = ?", userID).Order("updated_at DESC").Find(&items) { return items @@ -21,7 +21,7 @@ func (r MistakeRecordRepo) ListByUser(userID uint) []model.MistakeRecord { } // ListForPractice 错题重练选题:可按来源过滤、可只看未掌握(按最近更新倒序)。 -func (r MistakeRecordRepo) ListForPractice(userID uint, source string, onlyUnresolved bool) []model.MistakeRecord { +func (r MistakeRecordDAO) ListForPractice(userID uint, source string, onlyUnresolved bool) []model.MistakeRecord { q := r.Type(&model.MistakeRecord{}).Where("user_id = ?", userID) if source != "" { q = q.Where("source = ?", source) @@ -37,14 +37,14 @@ func (r MistakeRecordRepo) ListForPractice(userID uint, source string, onlyUnres } // CountByUser 统计某用户的错题总数。 -func (r MistakeRecordRepo) CountByUser(userID uint) int64 { +func (r MistakeRecordDAO) CountByUser(userID uint) int64 { var c int64 r.Inner().Model(&model.MistakeRecord{}).Where("user_id = ?", userID).Count(&c) return c } // CountResolvedByUser 统计某用户已掌握的错题数。 -func (r MistakeRecordRepo) CountResolvedByUser(userID uint) int64 { +func (r MistakeRecordDAO) CountResolvedByUser(userID uint) int64 { var c int64 r.Inner().Model(&model.MistakeRecord{}). Where("user_id = ? AND resolved = ?", userID, true).Count(&c) @@ -52,7 +52,7 @@ func (r MistakeRecordRepo) CountResolvedByUser(userID uint) int64 { } // GetByID 按 ID 获取。 -func (r MistakeRecordRepo) GetByID(id uint) (model.MistakeRecord, bool) { +func (r MistakeRecordDAO) GetByID(id uint) (model.MistakeRecord, bool) { var m model.MistakeRecord if r.Type(&m).Where("id = ?", id).First(&m) { return m, true @@ -62,7 +62,7 @@ func (r MistakeRecordRepo) GetByID(id uint) (model.MistakeRecord, bool) { // RecordWrong 答错入本:按唯一键 (user_id, question_id, source) upsert。 // 已有记录则整字段覆盖,并把 resolved 重置为未掌握——再次答错视为问题重新暴露。 -func (r MistakeRecordRepo) RecordWrong(m model.MistakeRecord) bool { +func (r MistakeRecordDAO) RecordWrong(m model.MistakeRecord) bool { m.Resolved = false var old model.MistakeRecord if !r.Type(&old). @@ -82,7 +82,7 @@ func (r MistakeRecordRepo) RecordWrong(m model.MistakeRecord) bool { // 返回 flipped 为本轮由「未掌握 → 已掌握」翻转的记录 ID,调用方据此加积分; // 只返回翻转的 ID(而非全部命中的记录)是为了避免反复重练刷分。 // touched=false 表示该题在错题本里一条都没有,调用方需自行兜底补建记录。 -func (r MistakeRecordRepo) TouchOnPractice(m model.MistakeRecord, resolved bool) (flipped []uint, touched bool) { +func (r MistakeRecordDAO) TouchOnPractice(m model.MistakeRecord, resolved bool) (flipped []uint, touched bool) { var recs []model.MistakeRecord if !r.Type(&recs).Where("user_id = ? AND question_id = ?", m.UserID, m.QuestionID).Find(&recs) { return nil, false @@ -107,21 +107,21 @@ func (r MistakeRecordRepo) TouchOnPractice(m model.MistakeRecord, resolved bool) } // Insert 创建错题记录。 -func (r MistakeRecordRepo) Insert(m *model.MistakeRecord) bool { +func (r MistakeRecordDAO) Insert(m *model.MistakeRecord) bool { return r.QueryBuilder.Insert(m) } // Update 保存已有记录(改掌握状态等)。 -func (r MistakeRecordRepo) Update(m *model.MistakeRecord) bool { +func (r MistakeRecordDAO) Update(m *model.MistakeRecord) bool { return r.Save(m) } // Delete 删除错题记录。 -func (r MistakeRecordRepo) Delete(id uint) bool { +func (r MistakeRecordDAO) Delete(id uint) bool { return r.DeleteByID(&model.MistakeRecord{}, id) } // DeleteByUser 删除某用户的全部错题。 -func (r MistakeRecordRepo) DeleteByUser(userID uint) bool { +func (r MistakeRecordDAO) DeleteByUser(userID uint) bool { return r.Type(&model.MistakeRecord{}).Where("user_id = ?", userID).Delete(&model.MistakeRecord{}) } diff --git a/eai_agentplatform/backend-go/internal/repository/official_account_article.go b/eai_agentplatform/backend-go/internal/dal/official_account_article.go similarity index 79% rename from eai_agentplatform/backend-go/internal/repository/official_account_article.go rename to eai_agentplatform/backend-go/internal/dal/official_account_article.go index 86e96e9..038cf93 100644 --- a/eai_agentplatform/backend-go/internal/repository/official_account_article.go +++ b/eai_agentplatform/backend-go/internal/dal/official_account_article.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "errors" @@ -12,7 +12,7 @@ import ( // // 模型定义在专员技能包内(specialists/packages/wechat_official_account/model), // 原先这个包自己拿 store.DB 读写,收口后统一走这里。 -type OfficialAccountArticleRepo struct{ *QueryBuilder } +type OfficialAccountArticleDAO struct{ *QueryBuilder } // FindByTaskID 按任务取文章状态。三种结果,**调用方必须分清**: // - row != nil 找到了 @@ -22,8 +22,8 @@ type OfficialAccountArticleRepo struct{ *QueryBuilder } // 第三种是本仓库要返回 error 而不是 bool 的原因。原实现是 // `if err == nil { return article }` 其余一律往下走新建 —— 也就是说读取 // 真出错时也会去建一篇新的。task_id 上有唯一索引,这种误建多半会撞唯一键 -// 而失败,但那是运气不是设计。(同 UserXAppCenterRepo.FindByUser) -func (r OfficialAccountArticleRepo) FindByTaskID(taskID uint) (*oaamodel.OfficialAccountArticle, error) { +// 而失败,但那是运气不是设计。(同 UserXAppCenterDAO.FindByUser) +func (r OfficialAccountArticleDAO) FindByTaskID(taskID uint) (*oaamodel.OfficialAccountArticle, error) { var row oaamodel.OfficialAccountArticle err := r.Inner().Where("task_id = ?", taskID).First(&row).Error if errors.Is(err, gorm.ErrRecordNotFound) { @@ -36,11 +36,11 @@ func (r OfficialAccountArticleRepo) FindByTaskID(taskID uint) (*oaamodel.Officia } // Insert 新建文章状态。 -func (r OfficialAccountArticleRepo) Insert(a *oaamodel.OfficialAccountArticle) bool { +func (r OfficialAccountArticleDAO) Insert(a *oaamodel.OfficialAccountArticle) bool { return r.QueryBuilder.Insert(a) } // Update 保存文章状态(改标题/提纲/正文/配图等一律走这里)。 -func (r OfficialAccountArticleRepo) Update(a *oaamodel.OfficialAccountArticle) bool { +func (r OfficialAccountArticleDAO) Update(a *oaamodel.OfficialAccountArticle) bool { return r.Save(a) } diff --git a/eai_agentplatform/backend-go/internal/repository/official_account_hotspot.go b/eai_agentplatform/backend-go/internal/dal/official_account_hotspot.go similarity index 87% rename from eai_agentplatform/backend-go/internal/repository/official_account_hotspot.go rename to eai_agentplatform/backend-go/internal/dal/official_account_hotspot.go index 90cb48a..c1a3ed9 100644 --- a/eai_agentplatform/backend-go/internal/repository/official_account_hotspot.go +++ b/eai_agentplatform/backend-go/internal/dal/official_account_hotspot.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "time" @@ -12,7 +12,7 @@ import ( // // 表里存的是抓取回来的 RSS/网页条目及其领域评分,按 (source_key, url) // 唯一,重复抓到同一条要就地更新而不是堆新行。 -type OfficialAccountHotspotRepo struct{ *QueryBuilder } +type OfficialAccountHotspotDAO struct{ *QueryBuilder } // hotspotListLimit 单次取回的热点条数上限。 // @@ -31,9 +31,9 @@ const hotspotListLimit = 40 // **注意:读取真出错时同样返回空**,调用方分不出「没有」和「读失败」。 // 收口前这里返回 error,读失败会让整个热点步骤失败;现在降级成「本轮没有热点」, // 调用方会走到不依赖热点的兜底选题路径。这个降级是有意接受的 —— -// 仓库层统一是 bool / 裸返回的风格(同 TaskRunRepo.ListByTask), +// 数据访问层统一是 bool / 裸返回的风格(同 TaskRunDAO.ListByTask), // 不为一次缓存读再造一个 error 出口;但这是**行为变化**,不是等价重构。 -func (r OfficialAccountHotspotRepo) ListFresh(domainKey string, cutoff time.Time) []oahmodel.OfficialAccountHotspot { +func (r OfficialAccountHotspotDAO) ListFresh(domainKey string, cutoff time.Time) []oahmodel.OfficialAccountHotspot { var items []oahmodel.OfficialAccountHotspot if r.Type(&items). Where("business_domain = ? AND fetched_at >= ? AND domain_score > 0", domainKey, cutoff). @@ -50,7 +50,7 @@ func (r OfficialAccountHotspotRepo) ListFresh(domainKey string, cutoff time.Time // 这里返回 error 而不是 bool,是因为调用方要把 err.Error() 拼进给用户看的 // 抓取日志(「热点入库失败:…」)——bool 装不下这句话,丢掉它用户就只看到 // 「本轮未写入新热点」,无从知道是库的问题还是源站的问题。 -func (r OfficialAccountHotspotRepo) UpsertAll(rows []oahmodel.OfficialAccountHotspot) error { +func (r OfficialAccountHotspotDAO) UpsertAll(rows []oahmodel.OfficialAccountHotspot) error { if len(rows) == 0 { return nil } diff --git a/eai_agentplatform/backend-go/internal/repository/position.go b/eai_agentplatform/backend-go/internal/dal/position.go similarity index 74% rename from eai_agentplatform/backend-go/internal/repository/position.go rename to eai_agentplatform/backend-go/internal/dal/position.go index 12ae55b..fb36cba 100644 --- a/eai_agentplatform/backend-go/internal/repository/position.go +++ b/eai_agentplatform/backend-go/internal/dal/position.go @@ -1,14 +1,14 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // Position 岗位仓库。 -type PositionRepo struct{ *QueryBuilder } +type PositionDAO struct{ *QueryBuilder } // List 获取岗位列表。 -func (r PositionRepo) List(status string) []model.Position { +func (r PositionDAO) List(status string) []model.Position { q := r.Type(&model.Position{}) if status != "" { q = q.Where("status = ?", status) @@ -23,7 +23,7 @@ func (r PositionRepo) List(status string) []model.Position { } // GetByID 按 ID 获取。 -func (r PositionRepo) GetByID(id uint) (model.Position, bool) { +func (r PositionDAO) GetByID(id uint) (model.Position, bool) { var p model.Position if r.Type(&p).Where("id = ?", id).First(&p) { return p, true @@ -32,7 +32,7 @@ func (r PositionRepo) GetByID(id uint) (model.Position, bool) { } // GetByName 按名称获取。 -func (r PositionRepo) GetByName(name string) (model.Position, bool) { +func (r PositionDAO) GetByName(name string) (model.Position, bool) { var p model.Position if r.Type(&p).Where("name = ?", name).First(&p) { return p, true @@ -41,29 +41,29 @@ func (r PositionRepo) GetByName(name string) (model.Position, bool) { } // Insert 创建岗位。 -func (r PositionRepo) Insert(p *model.Position) bool { +func (r PositionDAO) Insert(p *model.Position) bool { return r.QueryBuilder.Insert(p) } // Update 更新岗位。 -func (r PositionRepo) Update(p *model.Position) bool { +func (r PositionDAO) Update(p *model.Position) bool { return r.Save(p) } // Delete 软删除。 -func (r PositionRepo) Delete(id uint) bool { +func (r PositionDAO) Delete(id uint) bool { return r.Type(&model.Position{}).Where("id = ?", id).Updates(map[string]any{"status": "inactive"}) } // CountByDepartment 统计某部门的岗位数。 -func (r PositionRepo) CountByDepartment(departmentID uint) int64 { +func (r PositionDAO) CountByDepartment(departmentID uint) int64 { var c int64 r.Inner().Model(&model.Position{}).Where("department_id = ?", departmentID).Count(&c) return c } // CountByName 按名称统计(唯一性检查)。 -func (r PositionRepo) CountByName(name string, excludeID *uint) int64 { +func (r PositionDAO) CountByName(name string, excludeID *uint) int64 { q := r.Inner().Model(&model.Position{}).Where("name = ?", name) if excludeID != nil { q = q.Where("id <> ?", *excludeID) @@ -76,7 +76,7 @@ func (r PositionRepo) CountByName(name string, excludeID *uint) int64 { // ============ 岗位知识映射(PositionKnowledge) ============ // Knowledge 取岗位知识映射(按 id ASC)。学员应学清单与管理员编辑页共用。 -func (r PositionRepo) Knowledge(positionID uint) []model.PositionKnowledge { +func (r PositionDAO) Knowledge(positionID uint) []model.PositionKnowledge { var items []model.PositionKnowledge if r.Type(&items).Where("position_id = ?", positionID).Order("id ASC").Find(&items) { return items @@ -86,7 +86,7 @@ func (r PositionRepo) Knowledge(positionID uint) []model.PositionKnowledge { // ReplaceKnowledge 整表覆盖岗位知识映射(先删旧、再批量插入)。 // 两步非原子:调用方若需强一致,应在事务中执行。 -func (r PositionRepo) ReplaceKnowledge(positionID uint, rows []model.PositionKnowledge) bool { +func (r PositionDAO) ReplaceKnowledge(positionID uint, rows []model.PositionKnowledge) bool { if !r.Type(&model.PositionKnowledge{}).Where("position_id = ?", positionID). Delete(&model.PositionKnowledge{}) { return false @@ -98,7 +98,7 @@ func (r PositionRepo) ReplaceKnowledge(positionID uint, rows []model.PositionKno } // CountKnowledge 统计岗位知识映射条数。 -func (r PositionRepo) CountKnowledge(positionID uint) int64 { +func (r PositionDAO) CountKnowledge(positionID uint) int64 { var c int64 r.Inner().Model(&model.PositionKnowledge{}).Where("position_id = ?", positionID).Count(&c) return c @@ -107,7 +107,7 @@ func (r PositionRepo) CountKnowledge(positionID uint) int64 { // ============ 岗位考试蓝图(PositionExamBlueprint) ============ // Blueprints 取岗位考试蓝图(按 id ASC)。 -func (r PositionRepo) Blueprints(positionID uint) []model.PositionExamBlueprint { +func (r PositionDAO) Blueprints(positionID uint) []model.PositionExamBlueprint { var items []model.PositionExamBlueprint if r.Type(&items).Where("position_id = ?", positionID).Order("id ASC").Find(&items) { return items @@ -116,7 +116,7 @@ func (r PositionRepo) Blueprints(positionID uint) []model.PositionExamBlueprint } // ReplaceBlueprints 整表覆盖岗位考试蓝图(先删旧、再批量插入)。 -func (r PositionRepo) ReplaceBlueprints(positionID uint, rows []model.PositionExamBlueprint) bool { +func (r PositionDAO) ReplaceBlueprints(positionID uint, rows []model.PositionExamBlueprint) bool { if !r.Type(&model.PositionExamBlueprint{}).Where("position_id = ?", positionID). Delete(&model.PositionExamBlueprint{}) { return false diff --git a/eai_agentplatform/backend-go/internal/repository/product.go b/eai_agentplatform/backend-go/internal/dal/product.go similarity index 79% rename from eai_agentplatform/backend-go/internal/repository/product.go rename to eai_agentplatform/backend-go/internal/dal/product.go index 88029a6..22d3d54 100644 --- a/eai_agentplatform/backend-go/internal/repository/product.go +++ b/eai_agentplatform/backend-go/internal/dal/product.go @@ -1,19 +1,19 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // Product 产品仓库。 -type ProductRepo struct{ *QueryBuilder } +type ProductDAO struct{ *QueryBuilder } // Query 返回基础查询构建器(供复合查询使用)。 -func (r ProductRepo) Query() *QueryBuilder { +func (r ProductDAO) Query() *QueryBuilder { return r.Type(&model.Product{}) } // List 获取产品列表(按条件过滤)。 -func (r ProductRepo) List(conds ...map[string]any) []model.Product { +func (r ProductDAO) List(conds ...map[string]any) []model.Product { q := r.QueryBuilder.Type(&model.Product{}) for _, c := range conds { for k, v := range c { @@ -28,7 +28,7 @@ func (r ProductRepo) List(conds ...map[string]any) []model.Product { } // GetByID 按 ID 获取产品。 -func (r ProductRepo) GetByID(id uint) (model.Product, bool) { +func (r ProductDAO) GetByID(id uint) (model.Product, bool) { var p model.Product if r.Type(&p).Where("id = ?", id).First(&p) { return p, true @@ -40,7 +40,7 @@ func (r ProductRepo) GetByID(id uint) (model.Product, bool) { // // 与 GetByID 的区别是这里的业务口径:已停用(status=inactive)的产品不再出现在 // 课程详情这类业务页面上。此前该判断散落在 handler 里手写,容易被漏掉或写歪。 -func (r ProductRepo) GetVisibleByID(id uint) (model.Product, bool) { +func (r ProductDAO) GetVisibleByID(id uint) (model.Product, bool) { var p model.Product if r.Type(&p).Where("id = ? AND status != ?", id, "inactive").First(&p) { return p, true @@ -49,7 +49,7 @@ func (r ProductRepo) GetVisibleByID(id uint) (model.Product, bool) { } // GetByCode 按编号获取产品。 -func (r ProductRepo) GetByCode(code string) (model.Product, bool) { +func (r ProductDAO) GetByCode(code string) (model.Product, bool) { var p model.Product if r.Type(&p).Where("code = ?", code).First(&p) { return p, true @@ -58,12 +58,12 @@ func (r ProductRepo) GetByCode(code string) (model.Product, bool) { } // Insert 创建产品。 -func (r ProductRepo) Insert(p *model.Product) bool { +func (r ProductDAO) Insert(p *model.Product) bool { return r.QueryBuilder.Insert(p) } // Update 更新产品。 -func (r ProductRepo) Update(p *model.Product) bool { +func (r ProductDAO) Update(p *model.Product) bool { return r.Save(p) } @@ -73,12 +73,12 @@ func (r ProductRepo) Update(p *model.Product) bool { // active/inactive 两档词汇,POST /products/{id} 的 DELETE 处理器也据此向调用方 // 回包 {"status":"inactive"}。此前写成 "deleted" 会让接口回包与库内实际值不一致, // 管理员用 status=all 拉列表时会看到一个前端不认识的状态。 -func (r ProductRepo) Delete(id uint) bool { +func (r ProductDAO) Delete(id uint) bool { return r.Type(&model.Product{}).Where("id = ?", id).Updates(map[string]any{"status": "inactive"}) } // CountByCode 按编号统计(用于唯一性检查)。 -func (r ProductRepo) CountByCode(code string, excludeID *uint) int64 { +func (r ProductDAO) CountByCode(code string, excludeID *uint) int64 { q := r.Inner().Model(&model.Product{}).Where("code = ?", code) if excludeID != nil { q = q.Where("id <> ?", *excludeID) @@ -90,7 +90,7 @@ func (r ProductRepo) CountByCode(code string, excludeID *uint) int64 { // NamesByIDs 批量解析产品名称(id → name),用于列表页回填关联名称。 // 未命中的 ID 不会出现在返回的 map 中,调用方需自行兜底。 -func (r ProductRepo) NamesByIDs(ids []uint) map[uint]string { +func (r ProductDAO) NamesByIDs(ids []uint) map[uint]string { names := map[uint]string{} if len(ids) == 0 { return names @@ -105,7 +105,7 @@ func (r ProductRepo) NamesByIDs(ids []uint) map[uint]string { } // ProductsByStatus 按状态筛选产品列表。 -func (r ProductRepo) ProductsByStatus(status string, filter map[string]string) []model.Product { +func (r ProductDAO) ProductsByStatus(status string, filter map[string]string) []model.Product { q := r.Type(&model.Product{}) if cat, ok := filter["category"]; ok { q = q.Where("category = ?", cat) diff --git a/eai_agentplatform/backend-go/internal/repository/project.go b/eai_agentplatform/backend-go/internal/dal/project.go similarity index 71% rename from eai_agentplatform/backend-go/internal/repository/project.go rename to eai_agentplatform/backend-go/internal/dal/project.go index 56d002b..9d3fa88 100644 --- a/eai_agentplatform/backend-go/internal/repository/project.go +++ b/eai_agentplatform/backend-go/internal/dal/project.go @@ -1,17 +1,17 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // Project 项目仓库(任务的容器)。 -type ProjectRepo struct{ *QueryBuilder } +type ProjectDAO struct{ *QueryBuilder } // GetByIDForOwners 按 ID 取项目,且必须归属于 owners 里的一员。 // // owners 为空时查不到任何东西(而不是查到全部)——跟任务同一套归属口径, // 别人的项目和不存在的项目在这里不做区分,调用方一律回 404。 -func (r ProjectRepo) GetByIDForOwners(id uint, owners []string) (model.Project, bool) { +func (r ProjectDAO) GetByIDForOwners(id uint, owners []string) (model.Project, bool) { var p model.Project if ownerScope(r.Type(&p), owners).Where("id = ?", id).First(&p) { return p, true @@ -21,7 +21,7 @@ func (r ProjectRepo) GetByIDForOwners(id uint, owners []string) (model.Project, // ListByOwners 「我的项目」:置顶的排前面,其余按最近动过的排。 // limit <= 0 表示不设上限。 -func (r ProjectRepo) ListByOwners(owners []string, limit int) []model.Project { +func (r ProjectDAO) ListByOwners(owners []string, limit int) []model.Project { q := ownerScope(r.Type(&model.Project{}), owners) if limit > 0 { q = q.Limit(limit) @@ -34,19 +34,19 @@ func (r ProjectRepo) ListByOwners(owners []string, limit int) []model.Project { } // Insert 新建项目。 -func (r ProjectRepo) Insert(p *model.Project) bool { +func (r ProjectDAO) Insert(p *model.Project) bool { return r.QueryBuilder.Insert(p) } // Update 更新项目。 -func (r ProjectRepo) Update(p *model.Project) bool { +func (r ProjectDAO) Update(p *model.Project) bool { return r.Save(p) } // Delete 删除项目。 // // 项目里的任务**不删**——先由调用方把它们的 project_id 置空(见 -// TaskRecordRepo.ClearProject),再删项目本身。 -func (r ProjectRepo) Delete(p *model.Project) bool { +// TaskRecordDAO.ClearProject),再删项目本身。 +func (r ProjectDAO) Delete(p *model.Project) bool { return r.QueryBuilder.Delete(p) } diff --git a/eai_agentplatform/backend-go/internal/repository/question.go b/eai_agentplatform/backend-go/internal/dal/question.go similarity index 80% rename from eai_agentplatform/backend-go/internal/repository/question.go rename to eai_agentplatform/backend-go/internal/dal/question.go index 2b58be9..58b3a07 100644 --- a/eai_agentplatform/backend-go/internal/repository/question.go +++ b/eai_agentplatform/backend-go/internal/dal/question.go @@ -1,22 +1,22 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // Question 题目仓库。 -type QuestionRepo struct{ *QueryBuilder } +type QuestionDAO struct{ *QueryBuilder } // List 获取题目列表(id 升序)。 // -// status 沿用本站列表的档位约定(与 CourseRepo.List 一致): +// status 沿用本站列表的档位约定(与 CourseDAO.List 一致): // // "" → 只看 active(学员侧默认) // "all" → 不过滤(管理端题库默认,含已停用) // 其它 → 按该 status 过滤 // // domain 为空表示不过滤该维度。 -func (r QuestionRepo) List(domain, status string) []model.Question { +func (r QuestionDAO) List(domain, status string) []model.Question { q := r.Type(&model.Question{}) if domain != "" { q = q.Where("domain = ?", domain) @@ -40,7 +40,7 @@ func (r QuestionRepo) List(domain, status string) []model.Question { // // 判分专用:考试会话里下发的题目即使事后被停用,也必须能判分, // 否则学员交了卷却判不出来。要「只取可作答题目」用 ListActiveByIDs。 -func (r QuestionRepo) ListByIDs(ids []uint) []model.Question { +func (r QuestionDAO) ListByIDs(ids []uint) []model.Question { if len(ids) == 0 { return nil } @@ -54,7 +54,7 @@ func (r QuestionRepo) ListByIDs(ids []uint) []model.Question { // ListActiveByIDs 按 ID 批量取「已启用」的题(id 升序)。 // // 下发专用:错题重练等场景要剔除已停用/删除的题目。 -func (r QuestionRepo) ListActiveByIDs(ids []uint) []model.Question { +func (r QuestionDAO) ListActiveByIDs(ids []uint) []model.Question { if len(ids) == 0 { return nil } @@ -73,7 +73,7 @@ func (r QuestionRepo) ListActiveByIDs(ids []uint) []model.Question { // - courseIDs 非空时「题目属于这些课程,或未绑定课程但域匹配」(宽松口径,沿用原行为) // // 两个参数都为空表示全题库。 -func (r QuestionRepo) ActivePool(domains []string, courseIDs []uint) *QueryBuilder { +func (r QuestionDAO) ActivePool(domains []string, courseIDs []uint) *QueryBuilder { q := r.Type(&model.Question{}).Where("status = ?", "active") if len(domains) > 0 { q = q.Where("domain IN ?", domains) @@ -85,7 +85,7 @@ func (r QuestionRepo) ActivePool(domains []string, courseIDs []uint) *QueryBuild } // GetByID 按 ID 获取题目。 -func (r QuestionRepo) GetByID(id uint) (model.Question, bool) { +func (r QuestionDAO) GetByID(id uint) (model.Question, bool) { var q model.Question if r.Type(&q).Where("id = ?", id).First(&q) { return q, true @@ -94,7 +94,7 @@ func (r QuestionRepo) GetByID(id uint) (model.Question, bool) { } // GetActiveIDs 获取指定状态的题目 ID 列表。 -func (r QuestionRepo) GetActiveIDs(ids []uint) []uint { +func (r QuestionDAO) GetActiveIDs(ids []uint) []uint { var result []uint r.Inner().Model(&model.Question{}).Where("id IN ? AND status = ?", ids, "active").Pluck("id", &result) return result @@ -103,7 +103,7 @@ func (r QuestionRepo) GetActiveIDs(ids []uint) []uint { // DomainMap 返回「题目 ID → 知识域」映射。 // // 学员能力雷达要拿答题明细里的题目 ID 反查所属域;只取两列,避免整表加载题干。 -func (r QuestionRepo) DomainMap() map[uint]string { +func (r QuestionDAO) DomainMap() map[uint]string { var rows []model.Question r.Inner().Model(&model.Question{}).Select("id", "domain").Find(&rows) out := make(map[uint]string, len(rows)) @@ -114,7 +114,7 @@ func (r QuestionRepo) DomainMap() map[uint]string { } // CountByType 统计某类题目数量。 -func (r QuestionRepo) CountByType(domain, qType string) int64 { +func (r QuestionDAO) CountByType(domain, qType string) int64 { q := r.Inner().Model(&model.Question{}) if domain != "" { q = q.Where("domain = ?", domain) @@ -125,22 +125,22 @@ func (r QuestionRepo) CountByType(domain, qType string) int64 { } // Insert 创建题目。 -func (r QuestionRepo) Insert(item *model.Question) bool { +func (r QuestionDAO) Insert(item *model.Question) bool { return r.QueryBuilder.Insert(item) } // Update 更新题目。 -func (r QuestionRepo) Update(item *model.Question) bool { +func (r QuestionDAO) Update(item *model.Question) bool { return r.Save(item) } // Delete 软删除。 -func (r QuestionRepo) Delete(id uint) bool { +func (r QuestionDAO) Delete(id uint) bool { return r.Type(&model.Question{}).Where("id = ?", id).Updates(map[string]any{"status": "inactive"}) } // PickRandom 随机抽取 N 道题。 -func (r QuestionRepo) PickRandom(domain, qType string, count int, excludeIDs []uint) []model.Question { +func (r QuestionDAO) PickRandom(domain, qType string, count int, excludeIDs []uint) []model.Question { q := r.Type(&model.Question{}).Where("status = ? AND type = ?", "active", qType) if domain != "" { q = q.Where("domain = ?", domain) diff --git a/eai_agentplatform/backend-go/internal/repository/skill_definition.go b/eai_agentplatform/backend-go/internal/dal/skill_definition.go similarity index 74% rename from eai_agentplatform/backend-go/internal/repository/skill_definition.go rename to eai_agentplatform/backend-go/internal/dal/skill_definition.go index 8120c70..4e6285a 100644 --- a/eai_agentplatform/backend-go/internal/repository/skill_definition.go +++ b/eai_agentplatform/backend-go/internal/dal/skill_definition.go @@ -1,4 +1,4 @@ -package repository +package dal import ( skillmodel "eai_agentplatform/backend/internal/skills/model" @@ -8,16 +8,16 @@ import ( // // 技能是对象层三类一级对象之一(专员 / 技能 / 应用),与专员目录一样, // 「按 key 取技能」原先在多个文件里各写一遍,统一收这里。 -type SkillDefinitionRepo struct{ *QueryBuilder } +type SkillDefinitionDAO struct{ *QueryBuilder } // List 技能定义列表(sort_order ASC, id ASC)。 // // state 不在这里定默认值:「不传 state 就只看 active」是列表接口的契约, -// 由 handler 解析 query 参数后把结果传进来(与 ActionDefinitionRepo.List 同一约定)。 +// 由 handler 解析 query 参数后把结果传进来(与 ActionDefinitionDAO.List 同一约定)。 // // exposedToUser 是三态:nil 表示不按该列过滤,非 nil 按值精确匹配。 // 不用 bool 是因为「不传该参数」与「传 false」语义不同,前者要全量。 -func (r SkillDefinitionRepo) List(state string, exposedToUser *bool) []skillmodel.SkillDefinition { +func (r SkillDefinitionDAO) List(state string, exposedToUser *bool) []skillmodel.SkillDefinition { q := r.Type(&skillmodel.SkillDefinition{}) if state != "" { q = q.Where("state = ?", state) @@ -33,7 +33,7 @@ func (r SkillDefinitionRepo) List(state string, exposedToUser *bool) []skillmode } // GetByID 按 ID 取。 -func (r SkillDefinitionRepo) GetByID(id uint) (skillmodel.SkillDefinition, bool) { +func (r SkillDefinitionDAO) GetByID(id uint) (skillmodel.SkillDefinition, bool) { var s skillmodel.SkillDefinition if r.Type(&s).Where("id = ?", id).First(&s) { return s, true @@ -42,7 +42,7 @@ func (r SkillDefinitionRepo) GetByID(id uint) (skillmodel.SkillDefinition, bool) } // GetByKey 按 key 取(key 上有唯一索引)。 -func (r SkillDefinitionRepo) GetByKey(key string) (skillmodel.SkillDefinition, bool) { +func (r SkillDefinitionDAO) GetByKey(key string) (skillmodel.SkillDefinition, bool) { var s skillmodel.SkillDefinition if r.Type(&s).Where("key = ?", key).First(&s) { return s, true @@ -51,12 +51,12 @@ func (r SkillDefinitionRepo) GetByKey(key string) (skillmodel.SkillDefinition, b } // Insert 新建技能定义。 -func (r SkillDefinitionRepo) Insert(s *skillmodel.SkillDefinition) bool { +func (r SkillDefinitionDAO) Insert(s *skillmodel.SkillDefinition) bool { return r.QueryBuilder.Insert(s) } // Update 更新技能定义。 -func (r SkillDefinitionRepo) Update(s *skillmodel.SkillDefinition) bool { +func (r SkillDefinitionDAO) Update(s *skillmodel.SkillDefinition) bool { return r.Save(s) } @@ -64,6 +64,6 @@ func (r SkillDefinitionRepo) Update(s *skillmodel.SkillDefinition) bool { // // 表上没有软删字段,删了就是删了 —— 跟「停用」(state=inactive)是两回事: // 停用还留着记录,挂在它名下的技能引用仍能解释。 -func (r SkillDefinitionRepo) Delete(s *skillmodel.SkillDefinition) bool { +func (r SkillDefinitionDAO) Delete(s *skillmodel.SkillDefinition) bool { return r.QueryBuilder.Delete(s) } diff --git a/eai_agentplatform/backend-go/internal/repository/specialist.go b/eai_agentplatform/backend-go/internal/dal/specialist.go similarity index 83% rename from eai_agentplatform/backend-go/internal/repository/specialist.go rename to eai_agentplatform/backend-go/internal/dal/specialist.go index 40a6066..410cc44 100644 --- a/eai_agentplatform/backend-go/internal/repository/specialist.go +++ b/eai_agentplatform/backend-go/internal/dal/specialist.go @@ -1,4 +1,4 @@ -package repository +package dal import ( specialistmodel "eai_agentplatform/backend/internal/specialists/model" @@ -8,14 +8,14 @@ import ( // // 模型定义在 specialists 领域包内(internal/specialists/model),取数统一走这里—— // 「按 key 找专员」原先在 4 个文件里各写了一遍,散着改迟早分叉。 -type SpecialistRepo struct{ *QueryBuilder } +type SpecialistDAO struct{ *QueryBuilder } // GetByKey 按 key 取专员,**不限 state**。 // // 不过滤 state 是有意的:调用方对「停用的专员算不算数」口径不同—— // 建任务时要能查到(任务挂在已下线的专员上仍要能解释), // 而对话取 prompt 时要拒绝 inactive。把口径留在调用方,这里只负责取数。 -func (r SpecialistRepo) GetByKey(key string) (specialistmodel.Specialist, bool) { +func (r SpecialistDAO) GetByKey(key string) (specialistmodel.Specialist, bool) { var s specialistmodel.Specialist if r.Type(&s).Where("key = ?", key).First(&s) { return s, true @@ -24,7 +24,7 @@ func (r SpecialistRepo) GetByKey(key string) (specialistmodel.Specialist, bool) } // GetByID 按 ID 取专员。 -func (r SpecialistRepo) GetByID(id uint) (specialistmodel.Specialist, bool) { +func (r SpecialistDAO) GetByID(id uint) (specialistmodel.Specialist, bool) { var s specialistmodel.Specialist if r.Type(&s).Where("id = ?", id).First(&s) { return s, true @@ -36,7 +36,7 @@ func (r SpecialistRepo) GetByID(id uint) (specialistmodel.Specialist, bool) { // // 给「带自己那套 state 策略」的调用方用——比如按 key 取且非管理员只认 active、 // 或者按 state 分档计数。这类策略是各接口自己的口径,不在这里替它们定。 -func (r SpecialistRepo) Query() *QueryBuilder { +func (r SpecialistDAO) Query() *QueryBuilder { return r.QueryBuilder.Query().Type(&specialistmodel.Specialist{}) } @@ -50,7 +50,7 @@ func (r SpecialistRepo) Query() *QueryBuilder { // // 除显式要 system 外,一律排除 system 记录——它是内置的通用助手, // 不该混进专员目录里让人当成一个可选的专员。 -func (r SpecialistRepo) List(tier, marketTag, state string, isAdmin bool) []specialistmodel.Specialist { +func (r SpecialistDAO) List(tier, marketTag, state string, isAdmin bool) []specialistmodel.Specialist { q := r.Type(&specialistmodel.Specialist{}) if tier != "" { q = q.Where("tier = ?", tier) @@ -81,7 +81,7 @@ func (r SpecialistRepo) List(tier, marketTag, state string, isAdmin bool) []spec } // CountByKey 按 key 统计(唯一性检查)。excludeID 用于更新时排除自身,nil 表示不排除。 -func (r SpecialistRepo) CountByKey(key string, excludeID *uint) int64 { +func (r SpecialistDAO) CountByKey(key string, excludeID *uint) int64 { q := r.Inner().Model(&specialistmodel.Specialist{}).Where("key = ?", key) if excludeID != nil { q = q.Where("id <> ?", *excludeID) @@ -92,12 +92,12 @@ func (r SpecialistRepo) CountByKey(key string, excludeID *uint) int64 { } // Insert 新建专员。 -func (r SpecialistRepo) Insert(s *specialistmodel.Specialist) bool { +func (r SpecialistDAO) Insert(s *specialistmodel.Specialist) bool { return r.QueryBuilder.Insert(s) } // Update 更新专员。 -func (r SpecialistRepo) Update(s *specialistmodel.Specialist) bool { +func (r SpecialistDAO) Update(s *specialistmodel.Specialist) bool { return r.Save(s) } @@ -105,6 +105,6 @@ func (r SpecialistRepo) Update(s *specialistmodel.Specialist) bool { // // 表上没有软删字段,删了就是删了——跟「停用」(state=inactive)是两回事: // 停用还留着记录、还能查到,删除会让挂在它名下的历史任务失去解释依据。 -func (r SpecialistRepo) Delete(id uint) bool { +func (r SpecialistDAO) Delete(id uint) bool { return r.Type(&specialistmodel.Specialist{}).Where("id = ?", id).Delete(&specialistmodel.Specialist{}) } diff --git a/eai_agentplatform/backend-go/internal/repository/study_note.go b/eai_agentplatform/backend-go/internal/dal/study_note.go similarity index 74% rename from eai_agentplatform/backend-go/internal/repository/study_note.go rename to eai_agentplatform/backend-go/internal/dal/study_note.go index c3982c7..139eb79 100644 --- a/eai_agentplatform/backend-go/internal/repository/study_note.go +++ b/eai_agentplatform/backend-go/internal/dal/study_note.go @@ -1,17 +1,17 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // StudyNote 学习笔记仓库(员工私人笔记,按 user_id 隔离)。 -type StudyNoteRepo struct{ *QueryBuilder } +type StudyNoteDAO struct{ *QueryBuilder } // ListByUser 某用户的笔记,最近改过的在前。 // // itemType 为空表示不按内容类型过滤;itemID 为 nil 表示不按内容 ID 过滤 // (指针而非 0 值,是因为 company 类笔记的 item_id 本来就固定是 0)。 -func (r StudyNoteRepo) ListByUser(userID uint, itemType string, itemID *uint) []model.StudyNote { +func (r StudyNoteDAO) ListByUser(userID uint, itemType string, itemID *uint) []model.StudyNote { q := r.Type(&model.StudyNote{}).Where("user_id = ?", userID) if itemType != "" { q = q.Where("item_type = ?", itemType) @@ -28,7 +28,7 @@ func (r StudyNoteRepo) ListByUser(userID uint, itemType string, itemID *uint) [] // GetByID 按 ID 取笔记。**不在这里判归属**——越权检查留在 handler, // 那里能把「不存在」和「不是你的」分别回成 404 / 403。 -func (r StudyNoteRepo) GetByID(id uint) (model.StudyNote, bool) { +func (r StudyNoteDAO) GetByID(id uint) (model.StudyNote, bool) { var n model.StudyNote if r.Type(&n).Where("id = ?", id).First(&n) { return n, true @@ -37,16 +37,16 @@ func (r StudyNoteRepo) GetByID(id uint) (model.StudyNote, bool) { } // Insert 新建笔记。 -func (r StudyNoteRepo) Insert(n *model.StudyNote) bool { +func (r StudyNoteDAO) Insert(n *model.StudyNote) bool { return r.QueryBuilder.Insert(n) } // Update 更新笔记。 -func (r StudyNoteRepo) Update(n *model.StudyNote) bool { +func (r StudyNoteDAO) Update(n *model.StudyNote) bool { return r.Save(n) } // Delete 删除笔记(硬删,表上没有软删字段)。 -func (r StudyNoteRepo) Delete(n *model.StudyNote) bool { +func (r StudyNoteDAO) Delete(n *model.StudyNote) bool { return r.QueryBuilder.Delete(n) } diff --git a/eai_agentplatform/backend-go/internal/repository/system_config.go b/eai_agentplatform/backend-go/internal/dal/system_config.go similarity index 71% rename from eai_agentplatform/backend-go/internal/repository/system_config.go rename to eai_agentplatform/backend-go/internal/dal/system_config.go index f75e05c..2a312d0 100644 --- a/eai_agentplatform/backend-go/internal/repository/system_config.go +++ b/eai_agentplatform/backend-go/internal/dal/system_config.go @@ -1,14 +1,14 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // SystemConfig 系统参数仓库。 -type SystemConfigRepo struct{ *QueryBuilder } +type SystemConfigDAO struct{ *QueryBuilder } // GetByKey 按 key 获取参数值。 -func (r SystemConfigRepo) GetByKey(key string) string { +func (r SystemConfigDAO) GetByKey(key string) string { var c model.SystemConfig if r.Type(&c).Where("config_key = ?", key).First(&c) { return c.ConfigValue @@ -17,7 +17,7 @@ func (r SystemConfigRepo) GetByKey(key string) string { } // Get 按 key 获取完整记录。 -func (r SystemConfigRepo) Get(key string) (model.SystemConfig, bool) { +func (r SystemConfigDAO) Get(key string) (model.SystemConfig, bool) { var c model.SystemConfig if r.Type(&c).Where("config_key = ?", key).First(&c) { return c, true @@ -26,7 +26,7 @@ func (r SystemConfigRepo) Get(key string) (model.SystemConfig, bool) { } // SetOrUpdate 设置或更新参数。 -func (r SystemConfigRepo) SetOrUpdate(key, value string) bool { +func (r SystemConfigDAO) SetOrUpdate(key, value string) bool { existing, found := r.Get(key) if !found { return r.Insert(&model.SystemConfig{ConfigKey: key, ConfigValue: value}) @@ -36,7 +36,7 @@ func (r SystemConfigRepo) SetOrUpdate(key, value string) bool { } // List 获取所有参数。 -func (r SystemConfigRepo) List() []model.SystemConfig { +func (r SystemConfigDAO) List() []model.SystemConfig { var items []model.SystemConfig if r.Type(&items).Find(&items) { return items @@ -45,7 +45,7 @@ func (r SystemConfigRepo) List() []model.SystemConfig { } // BulkUpsert 批量插入或更新。 -func (r SystemConfigRepo) BulkUpsert(items []model.SystemConfig) int { +func (r SystemConfigDAO) BulkUpsert(items []model.SystemConfig) int { count := 0 for _, item := range items { if r.SetOrUpdate(item.ConfigKey, item.ConfigValue) { diff --git a/eai_agentplatform/backend-go/internal/repository/task_artifact.go b/eai_agentplatform/backend-go/internal/dal/task_artifact.go similarity index 63% rename from eai_agentplatform/backend-go/internal/repository/task_artifact.go rename to eai_agentplatform/backend-go/internal/dal/task_artifact.go index 11579e5..488e4e3 100644 --- a/eai_agentplatform/backend-go/internal/repository/task_artifact.go +++ b/eai_agentplatform/backend-go/internal/dal/task_artifact.go @@ -1,14 +1,14 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // TaskArtifact 专员交付物仓库。 -type TaskArtifactRepo struct{ *QueryBuilder } +type TaskArtifactDAO struct{ *QueryBuilder } // GetByID 按 ID 取交付物。 -func (r TaskArtifactRepo) GetByID(id uint) (model.TaskArtifact, bool) { +func (r TaskArtifactDAO) GetByID(id uint) (model.TaskArtifact, bool) { var a model.TaskArtifact if r.Type(&a).Where("id = ?", id).First(&a) { return a, true @@ -17,7 +17,7 @@ func (r TaskArtifactRepo) GetByID(id uint) (model.TaskArtifact, bool) { } // ListByTask 某任务的全部交付物(最近产出的在前)。 -func (r TaskArtifactRepo) ListByTask(taskID uint) []model.TaskArtifact { +func (r TaskArtifactDAO) ListByTask(taskID uint) []model.TaskArtifact { var items []model.TaskArtifact if r.Type(&items).Where("task_id = ?", taskID). Order("created_at DESC, id DESC").Find(&items) { @@ -27,18 +27,18 @@ func (r TaskArtifactRepo) ListByTask(taskID uint) []model.TaskArtifact { } // DeleteByTask 删掉某任务名下的全部交付物,条数一并返回。 -// 与 TaskRunRepo.DeleteByTask 配对使用(重置任务配置时两样一起清)。 -func (r TaskArtifactRepo) DeleteByTask(taskID uint) (int64, bool) { +// 与 TaskRunDAO.DeleteByTask 配对使用(重置任务配置时两样一起清)。 +func (r TaskArtifactDAO) DeleteByTask(taskID uint) (int64, bool) { res := r.Inner().Where("task_id = ?", taskID).Delete(&model.TaskArtifact{}) return res.RowsAffected, res.Error == nil } // Insert 新建交付物。 -func (r TaskArtifactRepo) Insert(a *model.TaskArtifact) bool { +func (r TaskArtifactDAO) Insert(a *model.TaskArtifact) bool { return r.QueryBuilder.Insert(a) } // Update 更新交付物(状态流转走这里)。 -func (r TaskArtifactRepo) Update(a *model.TaskArtifact) bool { +func (r TaskArtifactDAO) Update(a *model.TaskArtifact) bool { return r.Save(a) } diff --git a/eai_agentplatform/backend-go/internal/repository/task_record.go b/eai_agentplatform/backend-go/internal/dal/task_record.go similarity index 80% rename from eai_agentplatform/backend-go/internal/repository/task_record.go rename to eai_agentplatform/backend-go/internal/dal/task_record.go index 6b7cf9c..f0495e3 100644 --- a/eai_agentplatform/backend-go/internal/repository/task_record.go +++ b/eai_agentplatform/backend-go/internal/dal/task_record.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "gorm.io/gorm" @@ -10,10 +10,10 @@ import ( // // 任务是这个聚合的根:交付物(task_artifact)与运行记录(task_run)都挂在它下面, // 所以级联删除也放在这里,而不是让 handler 去协调三个仓库。 -type TaskRecordRepo struct{ *QueryBuilder } +type TaskRecordDAO struct{ *QueryBuilder } // GetByID 按 ID 取任务。 -func (r TaskRecordRepo) GetByID(id uint) (model.TaskRecord, bool) { +func (r TaskRecordDAO) GetByID(id uint) (model.TaskRecord, bool) { var t model.TaskRecord if r.Type(&t).Where("id = ?", id).First(&t) { return t, true @@ -25,7 +25,7 @@ func (r TaskRecordRepo) GetByID(id uint) (model.TaskRecord, bool) { // // owners 为空时查不到任何东西(而不是查到全部):归属标识缺失时必须退化成 // 「什么都看不到」,绝不能反过来退化成「看所有人的」。 -func (r TaskRecordRepo) GetByIDForOwners(id uint, owners []string) (model.TaskRecord, bool) { +func (r TaskRecordDAO) GetByIDForOwners(id uint, owners []string) (model.TaskRecord, bool) { var t model.TaskRecord if ownerScope(r.Type(&t), owners).Where("id = ?", id).First(&t) { return t, true @@ -34,7 +34,7 @@ func (r TaskRecordRepo) GetByIDForOwners(id uint, owners []string) (model.TaskRe } // ListBySpecialistKey 某专员名下的全部任务(最近更新的在前)。 -func (r TaskRecordRepo) ListBySpecialistKey(specialistKey string) []model.TaskRecord { +func (r TaskRecordDAO) ListBySpecialistKey(specialistKey string) []model.TaskRecord { var items []model.TaskRecord if r.Type(&items).Where("specialist_key = ?", specialistKey). Order("updated_at DESC, id DESC").Find(&items) { @@ -45,7 +45,7 @@ func (r TaskRecordRepo) ListBySpecialistKey(specialistKey string) []model.TaskRe // ListByOwners 「我的任务」:置顶的排前面,其余按最近动过的排。 // limit <= 0 表示不设上限。 -func (r TaskRecordRepo) ListByOwners(owners []string, limit int) []model.TaskRecord { +func (r TaskRecordDAO) ListByOwners(owners []string, limit int) []model.TaskRecord { q := ownerScope(r.Type(&model.TaskRecord{}), owners) if limit > 0 { q = q.Limit(limit) @@ -58,7 +58,7 @@ func (r TaskRecordRepo) ListByOwners(owners []string, limit int) []model.TaskRec } // ListByProject 项目下的任务(最近更新的在前)。limit <= 0 表示不设上限。 -func (r TaskRecordRepo) ListByProject(projectID uint, limit int) []model.TaskRecord { +func (r TaskRecordDAO) ListByProject(projectID uint, limit int) []model.TaskRecord { q := r.Type(&model.TaskRecord{}).Where("project_id = ?", projectID) if limit > 0 { q = q.Limit(limit) @@ -71,31 +71,31 @@ func (r TaskRecordRepo) ListByProject(projectID uint, limit int) []model.TaskRec } // CountBySpecialistKey 统计某专员名下的任务数(首次进入时判断要不要铺底任务)。 -func (r TaskRecordRepo) CountBySpecialistKey(specialistKey string) int64 { +func (r TaskRecordDAO) CountBySpecialistKey(specialistKey string) int64 { var c int64 r.Inner().Model(&model.TaskRecord{}).Where("specialist_key = ?", specialistKey).Count(&c) return c } // Insert 新建任务。 -func (r TaskRecordRepo) Insert(t *model.TaskRecord) bool { +func (r TaskRecordDAO) Insert(t *model.TaskRecord) bool { return r.QueryBuilder.Insert(t) } // Update 更新任务。 -func (r TaskRecordRepo) Update(t *model.TaskRecord) bool { +func (r TaskRecordDAO) Update(t *model.TaskRecord) bool { return r.Save(t) } // Delete 删除单条任务(不动它的交付物与运行记录,级联请用 DeleteCascade)。 -func (r TaskRecordRepo) Delete(t *model.TaskRecord) bool { +func (r TaskRecordDAO) Delete(t *model.TaskRecord) bool { return r.QueryBuilder.Delete(t) } // ClearProject 把项目下的任务全部解除归属(project_id 置空)。 // // 任务是「做过的事」,删一个分组不该把它一起抹掉,所以只解除归属、不删记录。 -func (r TaskRecordRepo) ClearProject(projectID uint) bool { +func (r TaskRecordDAO) ClearProject(projectID uint) bool { return r.Type(&model.TaskRecord{}).Where("project_id = ?", projectID). UpdateColumn("project_id", nil) } @@ -103,7 +103,7 @@ func (r TaskRecordRepo) ClearProject(projectID uint) bool { // DeleteCascade 删任务,连同它的交付物与运行记录。 // // 三张表必须一起成功或一起失败——留下没有任务的交付物,详情页就再也点不进去了。 -func (r TaskRecordRepo) DeleteCascade(id uint) bool { +func (r TaskRecordDAO) DeleteCascade(id uint) bool { err := r.Inner().Transaction(func(tx *gorm.DB) error { if err := tx.Where("task_id = ?", id).Delete(&model.TaskArtifact{}).Error; err != nil { return err diff --git a/eai_agentplatform/backend-go/internal/repository/task_run.go b/eai_agentplatform/backend-go/internal/dal/task_run.go similarity index 76% rename from eai_agentplatform/backend-go/internal/repository/task_run.go rename to eai_agentplatform/backend-go/internal/dal/task_run.go index ff1f887..cadf08e 100644 --- a/eai_agentplatform/backend-go/internal/repository/task_run.go +++ b/eai_agentplatform/backend-go/internal/dal/task_run.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" @@ -7,10 +7,10 @@ import ( // TaskRun 专员动作运行记录仓库。 // // 运行记录只增不改:一次动作一条,是任务详情的「时间线/回放」底稿。 -type TaskRunRepo struct{ *QueryBuilder } +type TaskRunDAO struct{ *QueryBuilder } // GetByID 按 ID 取运行记录。 -func (r TaskRunRepo) GetByID(id uint) (model.TaskRun, bool) { +func (r TaskRunDAO) GetByID(id uint) (model.TaskRun, bool) { var run model.TaskRun if r.Type(&run).Where("id = ?", id).First(&run) { return run, true @@ -19,7 +19,7 @@ func (r TaskRunRepo) GetByID(id uint) (model.TaskRun, bool) { } // ListByTask 某任务的全部运行记录(最近开始的在前)。 -func (r TaskRunRepo) ListByTask(taskID uint) []model.TaskRun { +func (r TaskRunDAO) ListByTask(taskID uint) []model.TaskRun { var items []model.TaskRun if r.Type(&items).Where("task_id = ?", taskID). Order("started_at DESC, id DESC").Find(&items) { @@ -31,14 +31,14 @@ func (r TaskRunRepo) ListByTask(taskID uint) []model.TaskRun { // DeleteByTask 删掉某任务名下的全部运行记录,条数一并返回。 // // 用于「重置任务配置」:旧配置下的运行记录留着会把时间线和产物对错, -// 所以整批清掉重来。这里不做级联,产物由 TaskArtifactRepo.DeleteByTask 单独清 —— +// 所以整批清掉重来。这里不做级联,产物由 TaskArtifactDAO.DeleteByTask 单独清 —— // 调用方要的是「两样都清干净」,出错了才分得清是哪一边没清成。 -func (r TaskRunRepo) DeleteByTask(taskID uint) (int64, bool) { +func (r TaskRunDAO) DeleteByTask(taskID uint) (int64, bool) { res := r.Inner().Where("task_id = ?", taskID).Delete(&model.TaskRun{}) return res.RowsAffected, res.Error == nil } // Insert 追加一条运行记录。 -func (r TaskRunRepo) Insert(run *model.TaskRun) bool { +func (r TaskRunDAO) Insert(run *model.TaskRun) bool { return r.QueryBuilder.Insert(run) } diff --git a/eai_agentplatform/backend-go/internal/repository/user.go b/eai_agentplatform/backend-go/internal/dal/user.go similarity index 78% rename from eai_agentplatform/backend-go/internal/repository/user.go rename to eai_agentplatform/backend-go/internal/dal/user.go index 5a951b8..93e9951 100644 --- a/eai_agentplatform/backend-go/internal/repository/user.go +++ b/eai_agentplatform/backend-go/internal/dal/user.go @@ -1,14 +1,14 @@ -package repository +package dal import ( "eai_agentplatform/backend/internal/model" ) // User 用户仓库。 -type UserRepo struct{ *QueryBuilder } +type UserDAO struct{ *QueryBuilder } // List 获取用户列表(分页)。 -func (r UserRepo) List(page, pageSize int, role, status string) []model.User { +func (r UserDAO) List(page, pageSize int, role, status string) []model.User { q := r.Type(&model.User{}) if role != "" { q = q.Where("role = ?", role) @@ -25,7 +25,7 @@ func (r UserRepo) List(page, pageSize int, role, status string) []model.User { } // Total 统计用户总数。 -func (r UserRepo) Total(role, status string) int64 { +func (r UserDAO) Total(role, status string) int64 { q := r.Inner().Model(&model.User{}) if role != "" { q = q.Where("role = ?", role) @@ -45,7 +45,7 @@ func (r UserRepo) Total(role, status string) int64 { // "active" → 仅在职(部门成员数、部门学情统计用这份口径) // "" → 不限状态(管理端全员视图,含已停用) // 其它 → 按该状态过滤 -func (r UserRepo) ListEmployees(status string) []model.User { +func (r UserDAO) ListEmployees(status string) []model.User { q := r.Type(&model.User{}).Where("role = ?", "employee") if status != "" { q = q.Where("status = ?", status) @@ -58,7 +58,7 @@ func (r UserRepo) ListEmployees(status string) []model.User { } // CountActiveByDepartment 统计归属某部门的在职员工数(按 user.department 字符串匹配)。 -func (r UserRepo) CountActiveByDepartment(name string) int64 { +func (r UserDAO) CountActiveByDepartment(name string) int64 { var c int64 r.Inner().Model(&model.User{}). Where("department = ? AND status = ?", name, "active").Count(&c) @@ -71,13 +71,13 @@ func (r UserRepo) CountActiveByDepartment(name string) int64 { // 否则按部门统计与展示会当场对不上。 // 用 Updates(而非 UpdateColumn)是为了让 GORM 照常带上 updated_at, // 与原实现 `Model(&User{}).Where(...).Update("department", ...)` 的行为一致。 -func (r UserRepo) RenameDepartment(oldName, newName string) bool { +func (r UserDAO) RenameDepartment(oldName, newName string) bool { return r.Type(&model.User{}).Where("department = ?", oldName). Updates(map[string]any{"department": newName}) } // GetByID 按 ID 获取。 -func (r UserRepo) GetByID(id uint) (model.User, bool) { +func (r UserDAO) GetByID(id uint) (model.User, bool) { var u model.User if r.Type(&u).Where("id = ?", id).First(&u) { return u, true @@ -86,7 +86,7 @@ func (r UserRepo) GetByID(id uint) (model.User, bool) { } // GetByUsername 按用户名获取。 -func (r UserRepo) GetByUsername(username string) (model.User, bool) { +func (r UserDAO) GetByUsername(username string) (model.User, bool) { var u model.User if r.Type(&u).Where("username = ?", username).First(&u) { return u, true @@ -95,7 +95,7 @@ func (r UserRepo) GetByUsername(username string) (model.User, bool) { } // GetByEmail 按邮箱获取。 -func (r UserRepo) GetByEmail(email string) (model.User, bool) { +func (r UserDAO) GetByEmail(email string) (model.User, bool) { var u model.User if r.Type(&u).Where("email = ?", email).First(&u) { return u, true @@ -104,16 +104,16 @@ func (r UserRepo) GetByEmail(email string) (model.User, bool) { } // Insert 创建用户。 -func (r UserRepo) Insert(u *model.User) bool { +func (r UserDAO) Insert(u *model.User) bool { return r.QueryBuilder.Insert(u) } // Update 更新用户。 -func (r UserRepo) Update(u *model.User) bool { +func (r UserDAO) Update(u *model.User) bool { return r.Save(u) } // UpdateStatus 更新状态。 -func (r UserRepo) UpdateStatus(id uint, status string) bool { +func (r UserDAO) UpdateStatus(id uint, status string) bool { return r.Type(&model.User{}).Where("id = ?", id).UpdateColumn("status", status) } diff --git a/eai_agentplatform/backend-go/internal/repository/xapp_center.go b/eai_agentplatform/backend-go/internal/dal/xapp_center.go similarity index 86% rename from eai_agentplatform/backend-go/internal/repository/xapp_center.go rename to eai_agentplatform/backend-go/internal/dal/xapp_center.go index 4d239a3..cf7d5df 100644 --- a/eai_agentplatform/backend-go/internal/repository/xapp_center.go +++ b/eai_agentplatform/backend-go/internal/dal/xapp_center.go @@ -1,4 +1,4 @@ -package repository +package dal import ( "errors" @@ -15,13 +15,13 @@ import ( // 调用方要新建一份」。若压成 bool,一旦读取真出错(SQLite 本地锁等待是常事) // 就会被当成「没配过」,转而写一份空白配置,把用户已有的收藏和最近使用抹掉。 // user_id 上有唯一索引,这种误写多半会撞唯一键而失败,但那是运气不是设计。 -type UserXAppCenterRepo struct{ *QueryBuilder } +type UserXAppCenterDAO struct{ *QueryBuilder } // FindByUser 取某用户的应用中心配置。三种结果: // - row != nil 找到 // - row == nil, err == nil 该用户还没有配置,调用方应新建(不是错误) // - err != nil 读取出错,调用方应报错,**不要**当成「没有配置」 -func (r UserXAppCenterRepo) FindByUser(userID uint) (*xappmodel.UserXAppCenter, error) { +func (r UserXAppCenterDAO) FindByUser(userID uint) (*xappmodel.UserXAppCenter, error) { var row xappmodel.UserXAppCenter err := r.Inner().Where("user_id = ?", userID).First(&row).Error if errors.Is(err, gorm.ErrRecordNotFound) { @@ -34,6 +34,6 @@ func (r UserXAppCenterRepo) FindByUser(userID uint) (*xappmodel.UserXAppCenter, } // Save 保存应用中心配置(新建或更新,由 row.ID 是否为零值决定)。 -func (r UserXAppCenterRepo) Save(row *xappmodel.UserXAppCenter) bool { +func (r UserXAppCenterDAO) Save(row *xappmodel.UserXAppCenter) bool { return r.QueryBuilder.Save(row) } diff --git a/eai_agentplatform/backend-go/internal/repository/xapp_definition.go b/eai_agentplatform/backend-go/internal/dal/xapp_definition.go similarity index 66% rename from eai_agentplatform/backend-go/internal/repository/xapp_definition.go rename to eai_agentplatform/backend-go/internal/dal/xapp_definition.go index 3f03690..755b2e3 100644 --- a/eai_agentplatform/backend-go/internal/repository/xapp_definition.go +++ b/eai_agentplatform/backend-go/internal/dal/xapp_definition.go @@ -1,4 +1,4 @@ -package repository +package dal import ( xappmodel "eai_agentplatform/backend/internal/xapps/model" @@ -7,14 +7,14 @@ import ( // XAppDefinition 应用定义仓库。 // // 应用(App)是对象层三类一级对象之一,定位是「长程任务运行壳」。 -// 本仓库只管应用目录本身的取数;用户自己的应用中心状态见 UserXAppCenterRepo。 -type XAppDefinitionRepo struct{ *QueryBuilder } +// 本仓库只管应用目录本身的取数;用户自己的应用中心状态见 UserXAppCenterDAO。 +type XAppDefinitionDAO struct{ *QueryBuilder } // List 应用定义列表(sort_order ASC, id ASC)。 // -// state 与 exposedToUser 的约定同 SkillDefinitionRepo.List: +// state 与 exposedToUser 的约定同 SkillDefinitionDAO.List: // state 的默认值由 handler 定,exposedToUser 用三态指针区分「不传」与「传 false」。 -func (r XAppDefinitionRepo) List(state string, exposedToUser *bool) []xappmodel.XAppDefinition { +func (r XAppDefinitionDAO) List(state string, exposedToUser *bool) []xappmodel.XAppDefinition { q := r.Type(&xappmodel.XAppDefinition{}) if state != "" { q = q.Where("state = ?", state) @@ -30,7 +30,7 @@ func (r XAppDefinitionRepo) List(state string, exposedToUser *bool) []xappmodel. } // GetByID 按 ID 取。 -func (r XAppDefinitionRepo) GetByID(id uint) (xappmodel.XAppDefinition, bool) { +func (r XAppDefinitionDAO) GetByID(id uint) (xappmodel.XAppDefinition, bool) { var a xappmodel.XAppDefinition if r.Type(&a).Where("id = ?", id).First(&a) { return a, true @@ -39,7 +39,7 @@ func (r XAppDefinitionRepo) GetByID(id uint) (xappmodel.XAppDefinition, bool) { } // GetByKey 按 key 取(key 上有唯一索引)。 -func (r XAppDefinitionRepo) GetByKey(key string) (xappmodel.XAppDefinition, bool) { +func (r XAppDefinitionDAO) GetByKey(key string) (xappmodel.XAppDefinition, bool) { var a xappmodel.XAppDefinition if r.Type(&a).Where("key = ?", key).First(&a) { return a, true @@ -48,16 +48,16 @@ func (r XAppDefinitionRepo) GetByKey(key string) (xappmodel.XAppDefinition, bool } // Insert 新建应用定义。 -func (r XAppDefinitionRepo) Insert(a *xappmodel.XAppDefinition) bool { +func (r XAppDefinitionDAO) Insert(a *xappmodel.XAppDefinition) bool { return r.QueryBuilder.Insert(a) } // Update 更新应用定义。 -func (r XAppDefinitionRepo) Update(a *xappmodel.XAppDefinition) bool { +func (r XAppDefinitionDAO) Update(a *xappmodel.XAppDefinition) bool { return r.Save(a) } // Delete 硬删除应用定义。 -func (r XAppDefinitionRepo) Delete(a *xappmodel.XAppDefinition) bool { +func (r XAppDefinitionDAO) Delete(a *xappmodel.XAppDefinition) bool { return r.QueryBuilder.Delete(a) } diff --git a/eai_agentplatform/backend-go/internal/skills/api/admin_handlers.go b/eai_agentplatform/backend-go/internal/skills/api/admin_handlers.go index 3e92fed..236f141 100644 --- a/eai_agentplatform/backend-go/internal/skills/api/admin_handlers.go +++ b/eai_agentplatform/backend-go/internal/skills/api/admin_handlers.go @@ -5,17 +5,17 @@ import ( "github.com/gin-gonic/gin" - "eai_agentplatform/backend/internal/repository" + "eai_agentplatform/backend/internal/dal" skillmodel "eai_agentplatform/backend/internal/skills/model" "eai_agentplatform/backend/internal/web" ) -// skillDefinitionRepo 技能定义仓库(便于测试时覆写)。query_handlers.go 里的读接口共用, +// skillDefinitionDAO 技能定义仓库(便于测试时覆写)。query_handlers.go 里的读接口共用, // 声明只此一处 —— 两份变量持有同一个仓库时,测试里覆写一份、另一份照旧,行为会静默分叉。 -var skillDefinitionRepo repository.SkillDefinitionRepo +var skillDefinitionDAO dal.SkillDefinitionDAO func init() { - skillDefinitionRepo = repository.SkillDefinitionRepo{} + skillDefinitionDAO = dal.SkillDefinitionDAO{} } func CreateSkillDefinition(c *gin.Context) { @@ -48,7 +48,7 @@ func CreateSkillDefinition(c *gin.Context) { State: req.State, SortOrder: req.SortOrder, } - if !skillDefinitionRepo.Insert(&item) { + if !skillDefinitionDAO.Insert(&item) { web.Fail(c, web.NewBadRequest("创建技能定义失败")) return } @@ -61,7 +61,7 @@ func UpdateSkillDefinition(c *gin.Context) { return } - item, found := skillDefinitionRepo.GetByID(id) + item, found := skillDefinitionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("技能定义不存在")) return @@ -99,7 +99,7 @@ func UpdateSkillDefinition(c *gin.Context) { item.State = req.State item.SortOrder = req.SortOrder - if !skillDefinitionRepo.Update(&item) { + if !skillDefinitionDAO.Update(&item) { web.Fail(c, web.NewBadRequest("更新技能定义失败")) return } @@ -112,12 +112,12 @@ func DeleteSkillDefinition(c *gin.Context) { return } - item, found := skillDefinitionRepo.GetByID(id) + item, found := skillDefinitionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("技能定义不存在")) return } - if !skillDefinitionRepo.Delete(&item) { + if !skillDefinitionDAO.Delete(&item) { web.Fail(c, web.NewBadRequest("删除技能定义失败")) return } diff --git a/eai_agentplatform/backend-go/internal/skills/api/office_handlers.go b/eai_agentplatform/backend-go/internal/skills/api/office_handlers.go index e94d697..402acd5 100644 --- a/eai_agentplatform/backend-go/internal/skills/api/office_handlers.go +++ b/eai_agentplatform/backend-go/internal/skills/api/office_handlers.go @@ -18,20 +18,20 @@ import ( officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts" specialistruntime "eai_agentplatform/backend/internal/specialists/runtime" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/middleware" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/store" "eai_agentplatform/backend/internal/web" ) -// taskRecordRepo 任务仓库(便于测试时覆写)。本文件里还有两处 +// taskRecordDAO 任务仓库(便于测试时覆写)。本文件里还有两处 // store.DB.Transaction —— 运行记录和交付物要在同一个事务里落库, // QueryBuilder 不带事务,那两处维持原样。 -var taskRecordRepo repository.TaskRecordRepo +var taskRecordDAO dal.TaskRecordDAO func init() { - taskRecordRepo = repository.TaskRecordRepo{} + taskRecordDAO = dal.TaskRecordDAO{} } type officeSkillExecuteReq struct { @@ -314,7 +314,7 @@ func persistOfficeExecution(task model.TaskRecord, definition officecontracts.Ru } func loadMyOwnedTask(c *gin.Context, user *model.User, taskID uint) (model.TaskRecord, bool) { - task, found := taskRecordRepo.GetByIDForOwners(taskID, specialistruntime.MyTaskOwners(user)) + task, found := taskRecordDAO.GetByIDForOwners(taskID, specialistruntime.MyTaskOwners(user)) if !found { web.Fail(c, web.NewNotFoundError("任务不存在")) return model.TaskRecord{}, false @@ -323,7 +323,7 @@ func loadMyOwnedTask(c *gin.Context, user *model.User, taskID uint) (model.TaskR } func reloadTask(taskID uint) (model.TaskRecord, error) { - task, found := taskRecordRepo.GetByID(taskID) + task, found := taskRecordDAO.GetByID(taskID) if !found { return model.TaskRecord{}, gorm.ErrRecordNotFound } diff --git a/eai_agentplatform/backend-go/internal/skills/api/query_handlers.go b/eai_agentplatform/backend-go/internal/skills/api/query_handlers.go index 4cc08d0..46887fd 100644 --- a/eai_agentplatform/backend-go/internal/skills/api/query_handlers.go +++ b/eai_agentplatform/backend-go/internal/skills/api/query_handlers.go @@ -21,7 +21,7 @@ func ListSkillDefinitions(c *gin.Context) { b := v == "true" exposed = &b } - web.OK(c, skillDefinitionRepo.List(state, exposed)) + web.OK(c, skillDefinitionDAO.List(state, exposed)) } func GetSkillDefinitionByKey(c *gin.Context) { @@ -31,7 +31,7 @@ func GetSkillDefinitionByKey(c *gin.Context) { return } - item, found := skillDefinitionRepo.GetByKey(key) + item, found := skillDefinitionDAO.GetByKey(key) if !found { web.Fail(c, web.NewNotFoundError("技能定义不存在")) return diff --git a/eai_agentplatform/backend-go/internal/specialists/api/admin_handlers.go b/eai_agentplatform/backend-go/internal/specialists/api/admin_handlers.go index e7b23d3..ad6527a 100644 --- a/eai_agentplatform/backend-go/internal/specialists/api/admin_handlers.go +++ b/eai_agentplatform/backend-go/internal/specialists/api/admin_handlers.go @@ -5,18 +5,18 @@ import ( "github.com/gin-gonic/gin" - "eai_agentplatform/backend/internal/repository" + "eai_agentplatform/backend/internal/dal" specialistmodel "eai_agentplatform/backend/internal/specialists/model" specialistruntime "eai_agentplatform/backend/internal/specialists/runtime" "eai_agentplatform/backend/internal/web" ) -// specialistRepo 专员目录仓库(便于测试时覆写)。query_handlers.go 里的读接口共用, +// specialistDAO 专员目录仓库(便于测试时覆写)。query_handlers.go 里的读接口共用, // 声明只此一处。 -var specialistRepo repository.SpecialistRepo +var specialistDAO dal.SpecialistDAO func init() { - specialistRepo = repository.SpecialistRepo{} + specialistDAO = dal.SpecialistDAO{} } // CreateSpecialist POST /api/specialists (admin) @@ -31,7 +31,7 @@ func CreateSpecialist(c *gin.Context) { return } - if specialistRepo.CountByKey(req.Key, nil) > 0 { + if specialistDAO.CountByKey(req.Key, nil) > 0 { web.Fail(c, web.NewConflictError("专员 key 已存在")) return } @@ -70,7 +70,7 @@ func CreateSpecialist(c *gin.Context) { SortOrder: req.SortOrder, } specialistruntime.EnsureStructuredRecords(&item) - if !specialistRepo.Insert(&item) { + if !specialistDAO.Insert(&item) { web.Fail(c, web.NewBadRequest("创建专员失败")) return } @@ -83,7 +83,7 @@ func UpdateSpecialist(c *gin.Context) { if !ok { return } - item, found := specialistRepo.GetByID(id) + item, found := specialistDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("专员不存在")) return @@ -99,7 +99,7 @@ func UpdateSpecialist(c *gin.Context) { return } - if specialistRepo.CountByKey(req.Key, &id) > 0 { + if specialistDAO.CountByKey(req.Key, &id) > 0 { web.Fail(c, web.NewConflictError("专员 key 已存在")) return } @@ -137,7 +137,7 @@ func UpdateSpecialist(c *gin.Context) { item.SortOrder = req.SortOrder specialistruntime.EnsureStructuredRecords(&item) - if !specialistRepo.Update(&item) { + if !specialistDAO.Update(&item) { web.Fail(c, web.NewBadRequest("更新专员失败")) return } @@ -150,11 +150,11 @@ func DeleteSpecialist(c *gin.Context) { if !ok { return } - if _, found := specialistRepo.GetByID(id); !found { + if _, found := specialistDAO.GetByID(id); !found { web.Fail(c, web.NewNotFoundError("专员不存在")) return } - if !specialistRepo.Delete(id) { + if !specialistDAO.Delete(id) { web.Fail(c, web.NewBadRequest("删除专员失败")) return } diff --git a/eai_agentplatform/backend-go/internal/specialists/api/query_handlers.go b/eai_agentplatform/backend-go/internal/specialists/api/query_handlers.go index e343d57..e60a892 100644 --- a/eai_agentplatform/backend-go/internal/specialists/api/query_handlers.go +++ b/eai_agentplatform/backend-go/internal/specialists/api/query_handlers.go @@ -16,7 +16,7 @@ func ListSpecialists(c *gin.Context) { user := middleware.CurrentUser(c) isAdmin := user != nil && user.Role == "admin" - items := specialistRepo.List(c.Query("tier"), c.Query("market_tag"), c.Query("state"), isAdmin) + items := specialistDAO.List(c.Query("tier"), c.Query("market_tag"), c.Query("state"), isAdmin) for i := range items { specialistruntime.EnsureStructuredRecords(&items[i]) } @@ -31,7 +31,7 @@ func GetSpecialistByKey(c *gin.Context) { return } - q := specialistRepo.Query().Where("key = ?", key) + q := specialistDAO.Query().Where("key = ?", key) user := middleware.CurrentUser(c) isAdmin := user != nil && user.Role == "admin" if !isAdmin { @@ -63,7 +63,7 @@ func SpecialistSummary(c *gin.Context) { // column 全是代码里写死的常量(tier / specialist_mode / market_tag), // 没有一处来自请求参数。 count := func(column string, value string) int64 { - q := specialistRepo.Query().Where("state = ?", "active") + q := specialistDAO.Query().Where("state = ?", "active") if column != "" { q = q.Where(column+" = ?", value) } diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/daos.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/daos.go new file mode 100644 index 0000000..b56faeb --- /dev/null +++ b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/daos.go @@ -0,0 +1,29 @@ +package wechatofficialaccountapi + +import "eai_agentplatform/backend/internal/dal" + +// 本包用到的仓库,集中声明(便于测试时覆写)。 +// +// 收口前这个包直接拿 store.DB 读写了 27 处,是本仓库仅剩的最大一块; +// 其中任务/运行记录/交付物/专员四类模型早就有仓库了(A4 收的), +// 这里多数不是新增能力,是改用既有能力。 +// +// 声明集中在同一个文件,是因为它们被本包 4 个文件共用 —— +// 两份变量持有同一个仓库时,测试里覆写一份、另一份照旧,行为会静默分叉。 +var ( + specialistDAO dal.SpecialistDAO + taskRecordDAO dal.TaskRecordDAO + taskRunDAO dal.TaskRunDAO + taskArtifactDAO dal.TaskArtifactDAO + oaArticleDAO dal.OfficialAccountArticleDAO + oaHotspotDAO dal.OfficialAccountHotspotDAO +) + +func init() { + specialistDAO = dal.SpecialistDAO{} + taskRecordDAO = dal.TaskRecordDAO{} + taskRunDAO = dal.TaskRunDAO{} + taskArtifactDAO = dal.TaskArtifactDAO{} + oaArticleDAO = dal.OfficialAccountArticleDAO{} + oaHotspotDAO = dal.OfficialAccountHotspotDAO{} +} diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_article_service.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_article_service.go index 069473d..5ea158a 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_article_service.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_article_service.go @@ -19,7 +19,7 @@ import ( // - 读取出错 → 原样返回错误,**不要**去建新的 —— task_id 上有唯一索引, // 误建多半会撞唯一键而失败,但那是运气不是设计 func ensureOfficialAccountArticle(task model.TaskRecord, workflow officialAccountWorkflowState) (*officialaccountmodel.OfficialAccountArticle, error) { - article, err := oaArticleRepo.FindByTaskID(task.ID) + article, err := oaArticleDAO.FindByTaskID(task.ID) if err != nil { return nil, err } @@ -41,7 +41,7 @@ func ensureOfficialAccountArticle(task model.TaskRecord, workflow officialAccoun MaxContentImages: normalizeOfficialAccountMaxContentImages(workflow.Form.MaxContentImages), Status: "draft", } - if !oaArticleRepo.Insert(row) { + if !oaArticleDAO.Insert(row) { return nil, errors.New("创建公众号文章状态失败") } return row, nil diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_generated_image.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_generated_image.go index d637d5d..e1dc26a 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_generated_image.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_generated_image.go @@ -44,10 +44,10 @@ func normalizeOfficialAccountMediaForResponse(task *model.TaskRecord, workflow * syncOfficialAccountArticleFromWorkflow(article, *workflow) task.ContextJSON = marshalOfficialAccountWorkflow(*workflow) - if !oaArticleRepo.Update(article) { + if !oaArticleDAO.Update(article) { return errors.New("保存公众号文章状态失败") } - if !taskRecordRepo.Update(task) { + if !taskRecordDAO.Update(task) { return errors.New("保存公众号任务失败") } return nil diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_hotspot_service.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_hotspot_service.go index 12b94c2..afcc496 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_hotspot_service.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_hotspot_service.go @@ -114,7 +114,7 @@ func ensureOfficialAccountHotspots(form officialAccountForm, force bool) ([]offi func loadFreshOfficialAccountHotspots(domainKey, keyword string, maxAge time.Duration) ([]officialaccountmodel.OfficialAccountHotspot, error) { // keyword 不在 SQL 里过滤,是取回来在内存里再滤一遍(见下)—— // 库里那 40 条是「该业务域里分数最高的」,关键词只用来在其中挑相关的。 - items := oaHotspotRepo.ListFresh(domainKey, time.Now().Add(-maxAge)) + items := oaHotspotDAO.ListFresh(domainKey, time.Now().Add(-maxAge)) filtered := filterOfficialAccountHotspotsByKeyword(items, keyword) if len(filtered) > 0 { return filtered, nil @@ -284,7 +284,7 @@ func upsertOfficialAccountHotspots(domainKey, keyword string, items []officialAc if len(upserts) == 0 { return 0, logs } - if err := oaHotspotRepo.UpsertAll(upserts); err != nil { + if err := oaHotspotDAO.UpsertAll(upserts); err != nil { logs = append(logs, "热点入库失败:"+err.Error()) return 0, logs } diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_workflow.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_workflow.go index 24db875..cc066e0 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_workflow.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_workflow.go @@ -182,9 +182,9 @@ func CreateOfficialAccountTask(c *gin.Context) { return } - // 按 key 取专员,不限 state —— 与 SpecialistRepo.GetByKey 的口径一致: + // 按 key 取专员,不限 state —— 与 SpecialistDAO.GetByKey 的口径一致: // 任务挂在已下线的专员上,历史记录仍要解释得通。 - specialist, found := specialistRepo.GetByKey(officialAccountSpecialistKey) + specialist, found := specialistDAO.GetByKey(officialAccountSpecialistKey) if !found { web.Fail(c, web.NewNotFoundError("公众号助手尚未配置")) return @@ -206,13 +206,13 @@ func CreateOfficialAccountTask(c *gin.Context) { if user != nil { task.CreatedBy = &user.ID } - if !taskRecordRepo.Insert(&task) { + if !taskRecordDAO.Insert(&task) { web.Fail(c, web.NewBadRequest("创建公众号任务失败")) return } if _, err := ensureOfficialAccountArticle(task, workflow); err != nil { // 文章状态没建起来,这个任务就是个空壳,回滚掉别留在库里 - taskRecordRepo.Delete(&task) + taskRecordDAO.Delete(&task) web.Fail(c, web.NewBadRequest("初始化公众号文章状态失败")) return } @@ -320,11 +320,11 @@ func UpdateOfficialAccountTask(c *gin.Context) { task.CurrentResult = "" task.CurrentRunID = nil task.LastTriggeredAt = nil - if _, ok := taskRunRepo.DeleteByTask(task.ID); !ok { + if _, ok := taskRunDAO.DeleteByTask(task.ID); !ok { web.Fail(c, web.NewBadRequest("清理旧运行记录失败")) return } - if _, ok := taskArtifactRepo.DeleteByTask(task.ID); !ok { + if _, ok := taskArtifactDAO.DeleteByTask(task.ID); !ok { web.Fail(c, web.NewBadRequest("清理旧产物失败")) return } @@ -336,11 +336,11 @@ func UpdateOfficialAccountTask(c *gin.Context) { } task.ContextJSON = marshalOfficialAccountWorkflow(workflow) - if !taskRecordRepo.Update(&task) { + if !taskRecordDAO.Update(&task) { web.Fail(c, web.NewBadRequest("更新任务配置失败")) return } - if !oaArticleRepo.Update(article) { + if !oaArticleDAO.Update(article) { web.Fail(c, web.NewBadRequest("保存公众号文章状态失败")) return } @@ -376,10 +376,10 @@ func UpdateOfficialAccountTask(c *gin.Context) { StartedAt: now, FinishedAt: &now, } - if taskRunRepo.Insert(&run) { + if taskRunDAO.Insert(&run) { task.CurrentRunID = &run.ID task.LastTriggeredAt = &now - taskRecordRepo.Update(&task) + taskRecordDAO.Update(&task) } } @@ -432,7 +432,7 @@ func ExecuteOfficialAccountWorkflowStep(c *gin.Context) { if appErr != nil { setOfficialAccountStepError(&workflow, stepKey, appErr.Message, now) task.ContextJSON = marshalOfficialAccountWorkflow(workflow) - taskRecordRepo.Update(&task) + taskRecordDAO.Update(&task) web.Fail(c, appErr) return } @@ -474,7 +474,7 @@ func ExecuteOfficialAccountWorkflowStep(c *gin.Context) { StartedAt: now, FinishedAt: &now, } - if !taskRunRepo.Insert(&run) { + if !taskRunDAO.Insert(&run) { web.Fail(c, web.NewBadRequest("保存步骤运行记录失败")) return } @@ -494,17 +494,17 @@ func ExecuteOfficialAccountWorkflowStep(c *gin.Context) { SourceRefsJSON: string(sourceRefsJSON), CreatedByRunID: &run.ID, } - if !taskArtifactRepo.Insert(artifact) { + if !taskArtifactDAO.Insert(artifact) { web.Fail(c, web.NewBadRequest("保存步骤产物失败")) return } } - if !oaArticleRepo.Update(article) { + if !oaArticleDAO.Update(article) { web.Fail(c, web.NewBadRequest("保存公众号文章状态失败")) return } - if !taskRecordRepo.Update(&task) { + if !taskRecordDAO.Update(&task) { web.Fail(c, web.NewBadRequest("更新公众号任务失败")) return } @@ -604,7 +604,7 @@ func RegenerateOfficialAccountImage(c *gin.Context) { StartedAt: now, FinishedAt: &now, } - if !taskRunRepo.Insert(&run) { + if !taskRunDAO.Insert(&run) { web.Fail(c, web.NewBadRequest("保存单张图片重生成记录失败")) return } @@ -621,16 +621,16 @@ func RegenerateOfficialAccountImage(c *gin.Context) { SourceRefsJSON: "[]", CreatedByRunID: &run.ID, } - if !taskArtifactRepo.Insert(artifact) { + if !taskArtifactDAO.Insert(artifact) { web.Fail(c, web.NewBadRequest("保存单张图片结果失败")) return } - if !oaArticleRepo.Update(article) { + if !oaArticleDAO.Update(article) { web.Fail(c, web.NewBadRequest("保存公众号文章状态失败")) return } - if !taskRecordRepo.Update(&task) { + if !taskRecordDAO.Update(&task) { web.Fail(c, web.NewBadRequest("更新公众号任务失败")) return } @@ -655,9 +655,9 @@ func respondOfficialAccountWorkflow(c *gin.Context, task model.TaskRecord) { // 收口前这两条查询出错会 web.Fail 成 400;ListByTask 是 bool 风格、失败返回 nil, // 所以现在读失败表现为「产物/运行记录为空」+200。这是行为变化,不是等价重构, - // 换的是与仓库层其余部分一致(TaskArtifactRepo.ListByTask 自 A4 起就是这个口径)。 - artifacts := taskArtifactRepo.ListByTask(task.ID) - runs := taskRunRepo.ListByTask(task.ID) + // 换的是与数据访问层其余部分一致(TaskArtifactDAO.ListByTask 自 A4 起就是这个口径)。 + artifacts := taskArtifactDAO.ListByTask(task.ID) + runs := taskRunDAO.ListByTask(task.ID) artifacts = compactOfficialAccountArtifactsForResponse(artifacts) runs = compactOfficialAccountRunsForResponse(runs) @@ -1564,9 +1564,9 @@ func loadAccessibleTask(c *gin.Context, user *model.User) (model.TaskRecord, boo found bool ) if user != nil && user.Role != "admin" { - task, found = taskRecordRepo.GetByIDForOwners(id, []string{user.FullName, user.Username}) + task, found = taskRecordDAO.GetByIDForOwners(id, []string{user.FullName, user.Username}) } else { - task, found = taskRecordRepo.GetByID(id) + task, found = taskRecordDAO.GetByID(id) } if !found { web.Fail(c, web.NewNotFoundError("事项不存在")) diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/repos.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/repos.go deleted file mode 100644 index 370a298..0000000 --- a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/repos.go +++ /dev/null @@ -1,29 +0,0 @@ -package wechatofficialaccountapi - -import "eai_agentplatform/backend/internal/repository" - -// 本包用到的仓库,集中声明(便于测试时覆写)。 -// -// 收口前这个包直接拿 store.DB 读写了 27 处,是本仓库仅剩的最大一块; -// 其中任务/运行记录/交付物/专员四类模型早就有仓库了(A4 收的), -// 这里多数不是新增能力,是改用既有能力。 -// -// 声明集中在同一个文件,是因为它们被本包 4 个文件共用 —— -// 两份变量持有同一个仓库时,测试里覆写一份、另一份照旧,行为会静默分叉。 -var ( - specialistRepo repository.SpecialistRepo - taskRecordRepo repository.TaskRecordRepo - taskRunRepo repository.TaskRunRepo - taskArtifactRepo repository.TaskArtifactRepo - oaArticleRepo repository.OfficialAccountArticleRepo - oaHotspotRepo repository.OfficialAccountHotspotRepo -) - -func init() { - specialistRepo = repository.SpecialistRepo{} - taskRecordRepo = repository.TaskRecordRepo{} - taskRunRepo = repository.TaskRunRepo{} - taskArtifactRepo = repository.TaskArtifactRepo{} - oaArticleRepo = repository.OfficialAccountArticleRepo{} - oaHotspotRepo = repository.OfficialAccountHotspotRepo{} -} diff --git a/eai_agentplatform/backend-go/internal/specialists/runtime/task_runtime.go b/eai_agentplatform/backend-go/internal/specialists/runtime/task_runtime.go index 74a250d..16a4ee9 100644 --- a/eai_agentplatform/backend-go/internal/specialists/runtime/task_runtime.go +++ b/eai_agentplatform/backend-go/internal/specialists/runtime/task_runtime.go @@ -11,8 +11,8 @@ import ( "eai_agentplatform/backend/internal/config" connectorcontracts "eai_agentplatform/backend/internal/connectors/core/contracts" connectorregistry "eai_agentplatform/backend/internal/connectors/registry" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/model" - "eai_agentplatform/backend/internal/repository" specialistmodel "eai_agentplatform/backend/internal/specialists/model" ) @@ -143,7 +143,7 @@ func BuildTaskFromReq(req TaskReq, user *model.User) (model.TaskRecord, error) { // 挂项目:得确认这个项目是自己的,否则等于给别人的项目里塞任务。 // 「自己的」判定复用 MyTaskOwners —— 任务和项目的归属是同一套口径。 if req.ProjectID != nil && *req.ProjectID != 0 { - project, found := repository.ProjectRepo{}.GetByIDForOwners(*req.ProjectID, MyTaskOwners(user)) + project, found := dal.ProjectDAO{}.GetByIDForOwners(*req.ProjectID, MyTaskOwners(user)) if !found { return task, fmt.Errorf("项目不存在") } diff --git a/eai_agentplatform/backend-go/internal/xapps/api/handlers.go b/eai_agentplatform/backend-go/internal/xapps/api/handlers.go index 09c4f7c..efd122c 100644 --- a/eai_agentplatform/backend-go/internal/xapps/api/handlers.go +++ b/eai_agentplatform/backend-go/internal/xapps/api/handlers.go @@ -9,22 +9,22 @@ import ( "github.com/gin-gonic/gin" + "eai_agentplatform/backend/internal/dal" "eai_agentplatform/backend/internal/jsonutil" "eai_agentplatform/backend/internal/middleware" - "eai_agentplatform/backend/internal/repository" "eai_agentplatform/backend/internal/web" xappdefs "eai_agentplatform/backend/internal/xapps/model" ) // 应用目录与用户应用中心两个仓库(便于测试时覆写),本包共用。 var ( - xAppDefinitionRepo repository.XAppDefinitionRepo - userXAppCenterRepo repository.UserXAppCenterRepo + xAppDefinitionDAO dal.XAppDefinitionDAO + userXAppCenterDAO dal.UserXAppCenterDAO ) func init() { - xAppDefinitionRepo = repository.XAppDefinitionRepo{} - userXAppCenterRepo = repository.UserXAppCenterRepo{} + xAppDefinitionDAO = dal.XAppDefinitionDAO{} + userXAppCenterDAO = dal.UserXAppCenterDAO{} } type definitionReq struct { @@ -148,7 +148,7 @@ func ListXAppDefinitions(c *gin.Context) { b := v == "true" exposed = &b } - web.OK(c, xAppDefinitionRepo.List(state, exposed)) + web.OK(c, xAppDefinitionDAO.List(state, exposed)) } func GetXAppDefinitionByKey(c *gin.Context) { @@ -157,7 +157,7 @@ func GetXAppDefinitionByKey(c *gin.Context) { web.Fail(c, web.NewBadRequest("应用 key 不能为空")) return } - item, found := xAppDefinitionRepo.GetByKey(key) + item, found := xAppDefinitionDAO.GetByKey(key) if !found { web.Fail(c, web.NewNotFoundError("应用定义不存在")) return @@ -200,7 +200,7 @@ func CreateXAppDefinition(c *gin.Context) { State: req.State, SortOrder: req.SortOrder, } - if !xAppDefinitionRepo.Insert(&item) { + if !xAppDefinitionDAO.Insert(&item) { web.Fail(c, web.NewBadRequest("创建应用定义失败")) return } @@ -212,7 +212,7 @@ func UpdateXAppDefinition(c *gin.Context) { if !ok { return } - item, found := xAppDefinitionRepo.GetByID(id) + item, found := xAppDefinitionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("应用定义不存在")) return @@ -253,7 +253,7 @@ func UpdateXAppDefinition(c *gin.Context) { } item.State = req.State item.SortOrder = req.SortOrder - if !xAppDefinitionRepo.Update(&item) { + if !xAppDefinitionDAO.Update(&item) { web.Fail(c, web.NewBadRequest("更新应用定义失败")) return } @@ -265,12 +265,12 @@ func DeleteXAppDefinition(c *gin.Context) { if !ok { return } - item, found := xAppDefinitionRepo.GetByID(id) + item, found := xAppDefinitionDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("应用定义不存在")) return } - if !xAppDefinitionRepo.Delete(&item) { + if !xAppDefinitionDAO.Delete(&item) { web.Fail(c, web.NewBadRequest("删除应用定义失败")) return } @@ -314,7 +314,7 @@ func GetMyXAppCenter(c *gin.Context) { web.Fail(c, web.NewAuthError("未登录")) return } - row, err := userXAppCenterRepo.FindByUser(user.ID) + row, err := userXAppCenterDAO.FindByUser(user.ID) if err != nil { web.Fail(c, web.NewBadRequest("读取应用中心失败")) return @@ -338,7 +338,7 @@ func UpdateMyXAppCenter(c *gin.Context) { RecentKeys: mustJSONXAppCenter(req.RecentKeys), CustomXApps: mustJSONXAppCenter(req.CustomXApps), }) - row, err := userXAppCenterRepo.FindByUser(user.ID) + row, err := userXAppCenterDAO.FindByUser(user.ID) if err != nil { web.Fail(c, web.NewBadRequest("读取应用中心失败")) return @@ -349,7 +349,7 @@ func UpdateMyXAppCenter(c *gin.Context) { row.FavoriteKeys = mustJSONXAppCenter(payload.FavoriteKeys) row.RecentKeys = mustJSONXAppCenter(payload.RecentKeys) row.CustomXApps = mustJSONXAppCenter(payload.CustomXApps) - if !userXAppCenterRepo.Save(row) { + if !userXAppCenterDAO.Save(row) { web.Fail(c, web.NewBadRequest("保存应用中心失败")) return }