package store import ( "errors" "time" "gorm.io/gorm" "gorm.io/gorm/clause" ) // --- 账号台账 --- // AllAccounts 返回全部受管账号。 func (s *Store) AllAccounts() ([]*Account, error) { var out []*Account if err := s.db.Order("uid").Find(&out).Error; err != nil { return nil, err } return out, nil } // AccountsByUID 返回 uid → 账号 的映射,供 diff 引擎使用。 func (s *Store) AccountsByUID() (map[string]*Account, error) { list, err := s.AllAccounts() if err != nil { return nil, err } out := make(map[string]*Account, len(list)) for _, a := range list { out[a.UID] = a } return out, nil } // UpsertAccount 写入或更新一条账号台账。 func (s *Store) UpsertAccount(a *Account) error { a.LastSyncedAt = time.Now() return s.db.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "uid"}}, DoUpdates: clause.AssignmentColumns([]string{ "dn", "union_id", "user_id", "email", "name", "state", "attrs_hash", "dept_ids", "last_synced_at", }), }).Create(a).Error } // SetAccountState 更新账号状态与 DN(用于在职 ↔ 离职迁移)。 func (s *Store) SetAccountState(uid, state, dn string) error { return s.db.Model(&Account{}).Where("uid = ?", uid). Updates(map[string]any{"state": state, "dn": dn}).Error } // DeleteAccount 从台账删除一条账号。 func (s *Store) DeleteAccount(uid string) error { return s.db.Where("uid = ?", uid).Delete(&Account{}).Error } // --- 分组台账 --- // AllGroups 返回全部受管分组。 func (s *Store) AllGroups() ([]*Group, error) { var out []*Group if err := s.db.Order("dept_id").Find(&out).Error; err != nil { return nil, err } return out, nil } // GroupsByDeptID 返回 dept_id → 分组 的映射。 func (s *Store) GroupsByDeptID() (map[string]*Group, error) { list, err := s.AllGroups() if err != nil { return nil, err } out := make(map[string]*Group, len(list)) for _, g := range list { out[g.DeptID] = g } return out, nil } // UpsertGroup 写入或更新一条分组台账。 func (s *Store) UpsertGroup(g *Group) error { g.LastSyncedAt = time.Now() return s.db.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "dept_id"}}, DoUpdates: clause.AssignmentColumns([]string{ "dn", "name", "parent_id", "state", "last_synced_at", }), }).Create(g).Error } // SetGroupState 更新分组状态。 func (s *Store) SetGroupState(deptID, state string) error { return s.db.Model(&Group{}).Where("dept_id = ?", deptID). Update("state", state).Error } // DeleteGroup 从台账删除一条分组。 func (s *Store) DeleteGroup(deptID string) error { return s.db.Where("dept_id = ?", deptID).Delete(&Group{}).Error } // --- 同步记录 --- // StartRun 创建一条同步记录并返回该记录。 // // 返回完整记录而非仅 ID:调用方若自行构造一个只含 ID 的结构体再保存, // GORM 的 Save 会把未赋值的 StartedAt/Mode/Trigger 一并写成零值, // 导致历史页面显示 0001-01-01 与空白模式。 func (s *Store) StartRun(mode, trigger string) (*SyncRun, error) { run := &SyncRun{ StartedAt: time.Now(), Mode: mode, Trigger: trigger, Status: "running", } if err := s.db.Create(run).Error; err != nil { return nil, err } return run, nil } // FinishRun 完成一条同步记录。 func (s *Store) FinishRun(run *SyncRun) error { run.FinishedAt = time.Now() return s.db.Save(run).Error } // RecentRuns 返回最近的同步记录,最新在前。 func (s *Store) RecentRuns(limit int) ([]*SyncRun, error) { if limit <= 0 { limit = 50 } var out []*SyncRun if err := s.db.Order("id desc").Limit(limit).Find(&out).Error; err != nil { return nil, err } return out, nil } // LastRun 返回最近一次成功执行的记录,没有则返回 nil。 func (s *Store) LastRun() (*SyncRun, error) { var out SyncRun err := s.db.Where("status = ?", "success").Order("id desc").First(&out).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } if err != nil { return nil, err } return &out, nil }