feat(csmanualentry): 手动录单支持收号出号分组
- 录单记录新增组别(收号/出号),唯一约束放宽为编号+组别,同一编号两组各可登记一次 - 操作人选项支持组别标记,录单选中后自动带出组别 - 列表新增组别列与筛选,今日统计按收号/出号分列
This commit is contained in:
@@ -34,9 +34,10 @@ func (r *Repository) FindAdminSnapshot(ctx context.Context, adminID uint64) (nam
|
||||
}
|
||||
|
||||
// Create 写入一条录单记录。
|
||||
func (r *Repository) Create(ctx context.Context, adminID uint64, adminName, adminUsername, entryNo, platform, operator, remark string) (*EntryDTO, error) {
|
||||
func (r *Repository) Create(ctx context.Context, adminID uint64, adminName, adminUsername, entryNo, entryGroup, platform, operator, remark string) (*EntryDTO, error) {
|
||||
row := model.CSManualEntry{
|
||||
EntryNo: entryNo,
|
||||
EntryGroup: entryGroup,
|
||||
Platform: platform,
|
||||
Operator: operator,
|
||||
AdminID: adminID,
|
||||
@@ -67,15 +68,16 @@ func (r *Repository) FindByID(ctx context.Context, id uint64) (*EntryDTO, error)
|
||||
return &dto, nil
|
||||
}
|
||||
|
||||
// Update 修正录单的编号、平台、操作人与备注。编号唯一冲突返回 ErrEntryNoExists。
|
||||
func (r *Repository) Update(ctx context.Context, id uint64, entryNo, platform, operator, remark string) (*EntryDTO, error) {
|
||||
// Update 修正录单的编号、组别、平台、操作人与备注。同组内编号唯一冲突返回 ErrEntryNoExists。
|
||||
func (r *Repository) Update(ctx context.Context, id uint64, entryNo, entryGroup, platform, operator, remark string) (*EntryDTO, error) {
|
||||
result := r.db.WithContext(ctx).Model(&model.CSManualEntry{}).
|
||||
Where("id = ?", id).
|
||||
Updates(map[string]any{
|
||||
"entry_no": entryNo,
|
||||
"platform": platform,
|
||||
"operator": operator,
|
||||
"remark": remark,
|
||||
"entry_no": entryNo,
|
||||
"entry_group": entryGroup,
|
||||
"platform": platform,
|
||||
"operator": operator,
|
||||
"remark": remark,
|
||||
})
|
||||
if result.Error != nil {
|
||||
if isDuplicateEntry(result.Error) {
|
||||
@@ -116,6 +118,10 @@ func (r *Repository) List(ctx context.Context, query ListQuery) (*PaginatedResul
|
||||
db = db.Where("entry_no = ?", query.EntryNo)
|
||||
countDB = countDB.Where("entry_no = ?", query.EntryNo)
|
||||
}
|
||||
if query.EntryGroup != "" {
|
||||
db = db.Where("entry_group = ?", query.EntryGroup)
|
||||
countDB = countDB.Where("entry_group = ?", query.EntryGroup)
|
||||
}
|
||||
if query.AdminID > 0 {
|
||||
db = db.Where("admin_id = ?", query.AdminID)
|
||||
countDB = countDB.Where("admin_id = ?", query.AdminID)
|
||||
@@ -168,13 +174,17 @@ func (r *Repository) TodayAgentStats(ctx context.Context, day time.Time) ([]Agen
|
||||
end := start.AddDate(0, 0, 1)
|
||||
|
||||
type row struct {
|
||||
AdminID uint64
|
||||
AdminName string
|
||||
Count int64
|
||||
AdminID uint64
|
||||
AdminName string
|
||||
Count int64
|
||||
CollectCount int64
|
||||
SellCount int64
|
||||
}
|
||||
rows := make([]row, 0)
|
||||
if err := r.db.WithContext(ctx).Table("cs_manual_entries").
|
||||
Select("admin_id, MAX(admin_name) AS admin_name, COUNT(*) AS count").
|
||||
Select(`admin_id, MAX(admin_name) AS admin_name, COUNT(*) AS count,
|
||||
SUM(CASE WHEN entry_group = 'collect' THEN 1 ELSE 0 END) AS collect_count,
|
||||
SUM(CASE WHEN entry_group = 'sell' THEN 1 ELSE 0 END) AS sell_count`).
|
||||
Where("created_at >= ? AND created_at < ?", start, end).
|
||||
Group("admin_id").
|
||||
Scan(&rows).Error; err != nil {
|
||||
@@ -190,10 +200,12 @@ func (r *Repository) TodayAgentStats(ctx context.Context, day time.Time) ([]Agen
|
||||
items := make([]AgentDayStatsDTO, 0, len(rows))
|
||||
for _, item := range rows {
|
||||
items = append(items, AgentDayStatsDTO{
|
||||
Date: date,
|
||||
AdminID: item.AdminID,
|
||||
AdminName: item.AdminName,
|
||||
Count: item.Count,
|
||||
Date: date,
|
||||
AdminID: item.AdminID,
|
||||
AdminName: item.AdminName,
|
||||
Count: item.Count,
|
||||
CollectCount: item.CollectCount,
|
||||
SellCount: item.SellCount,
|
||||
})
|
||||
}
|
||||
return items, nil
|
||||
@@ -232,11 +244,12 @@ func (r *Repository) ListAllOptions(ctx context.Context) (*OptionListDTO, error)
|
||||
}
|
||||
|
||||
// CreateOption 新增一个平台 / 操作人选项,重名返回 ErrOptionExists。
|
||||
func (r *Repository) CreateOption(ctx context.Context, optionType, name string) (*OptionDTO, error) {
|
||||
// 操作人选项可通过 groupTag 标记所属组别(collect/sell,空表示未分组)。
|
||||
func (r *Repository) CreateOption(ctx context.Context, optionType, name, groupTag string) (*OptionDTO, error) {
|
||||
if !IsValidOptionType(optionType) {
|
||||
return nil, ErrOptionTypeInvalid
|
||||
}
|
||||
row := model.CSManualEntryOption{Type: optionType, Name: name}
|
||||
row := model.CSManualEntryOption{Type: optionType, Name: name, GroupTag: groupTag}
|
||||
if err := r.db.WithContext(ctx).Create(&row).Error; err != nil {
|
||||
if isDuplicateEntry(err) {
|
||||
return nil, ErrOptionExists
|
||||
@@ -247,8 +260,8 @@ func (r *Repository) CreateOption(ctx context.Context, optionType, name string)
|
||||
return &dto, nil
|
||||
}
|
||||
|
||||
// UpdateOption 重命名一个选项,重名返回 ErrOptionExists。
|
||||
func (r *Repository) UpdateOption(ctx context.Context, id uint64, name string) (*OptionDTO, error) {
|
||||
// UpdateOption 重命名一个选项并可更新组别标记,重名返回 ErrOptionExists。
|
||||
func (r *Repository) UpdateOption(ctx context.Context, id uint64, name, groupTag string) (*OptionDTO, error) {
|
||||
var row model.CSManualEntryOption
|
||||
if err := r.db.WithContext(ctx).First(&row, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -258,7 +271,10 @@ func (r *Repository) UpdateOption(ctx context.Context, id uint64, name string) (
|
||||
}
|
||||
result := r.db.WithContext(ctx).Model(&model.CSManualEntryOption{}).
|
||||
Where("id = ?", id).
|
||||
Update("name", name)
|
||||
Updates(map[string]any{
|
||||
"name": name,
|
||||
"group_tag": groupTag,
|
||||
})
|
||||
if result.Error != nil {
|
||||
if isDuplicateEntry(result.Error) {
|
||||
return nil, ErrOptionExists
|
||||
@@ -266,6 +282,7 @@ func (r *Repository) UpdateOption(ctx context.Context, id uint64, name string) (
|
||||
return nil, result.Error
|
||||
}
|
||||
row.Name = name
|
||||
row.GroupTag = groupTag
|
||||
dto := toOptionDTO(row)
|
||||
return &dto, nil
|
||||
}
|
||||
@@ -306,6 +323,7 @@ func toDTO(row model.CSManualEntry) EntryDTO {
|
||||
return EntryDTO{
|
||||
ID: row.ID,
|
||||
EntryNo: row.EntryNo,
|
||||
EntryGroup: row.EntryGroup,
|
||||
Platform: row.Platform,
|
||||
Operator: row.Operator,
|
||||
AdminID: row.AdminID,
|
||||
@@ -321,6 +339,7 @@ func toOptionDTO(row model.CSManualEntryOption) OptionDTO {
|
||||
ID: row.ID,
|
||||
Type: row.Type,
|
||||
Name: row.Name,
|
||||
GroupTag: row.GroupTag,
|
||||
SortOrder: row.SortOrder,
|
||||
CreatedAt: row.CreatedAt,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user