小程序一些功能更新

This commit is contained in:
李琦
2026-09-29 10:57:01 +08:00
parent 0cb70a7618
commit 3bb7fa8db3
96 changed files with 13890 additions and 213 deletions

View File

@@ -0,0 +1,111 @@
package logic
import (
"context"
"strings"
"github.com/gogf/gf/v2/frame/g"
v1 "tool-api/api/admin/v1"
"tool-api/internal/consts"
"tool-api/internal/model/entity"
)
// ============================================================================
// 年会域:查座审计列表(A19,架构 §5.2 遗漏项补录)
//
// 数据源 event_seat_queries(架构 §3.2.9),与公开查座(event_query.go)共用同一张表:
// - phone_masked 落库时已脱敏(writeSeatAudit → maskPhone),此处原样返回,不再二次脱敏;
// - openid 不做落库脱敏(限流需要原始值),输出时二次脱敏(前 6 位 + ***);
// - event_title 通过一次 IN 查询批量补齐,避免逐条查(N+1)。
// ============================================================================
// AdminEventQueryLog 查座审计列表。
//
// EventId = 0 表示全部活动;
// Result = -1 表示全部结果,0 失败 / 1 成功(其余取值同样视为全部,避免前端漏传时误过滤)。
func AdminEventQueryLog(ctx context.Context, req *v1.EventQueryLogReq) (*v1.EventQueryLogRes, error) {
model := g.Model(consts.TableEventSeatQueries)
if req.EventId > 0 {
model = model.Where("event_id", req.EventId)
}
if req.Result == consts.SeatResultFail || req.Result == consts.SeatResultSuccess {
model = model.Where("result", req.Result)
}
total, err := model.Count()
if err != nil {
return nil, err
}
page, size := normalizeAdminPage(req.Page, req.PageSize)
records, err := model.OrderDesc("id").Page(page, size).All()
if err != nil {
return nil, err
}
// 解析实体 + 收集去重后的活动 id
rows := make([]*entity.EventSeatQueries, 0, len(records))
eventIds := make([]int64, 0)
seen := make(map[int64]bool)
for _, r := range records {
item := &entity.EventSeatQueries{}
if err = r.Struct(item); err != nil {
continue
}
rows = append(rows, item)
if item.EventId > 0 && !seen[item.EventId] {
seen[item.EventId] = true
eventIds = append(eventIds, item.EventId)
}
}
// 批量补齐活动标题(一次 IN 查询,避免 N+1)
titleMap, err := loadEventTitles(ctx, eventIds)
if err != nil {
return nil, err
}
list := make([]v1.QueryLogItem, 0, len(rows))
for _, item := range rows {
list = append(list, v1.QueryLogItem{
Id: item.Id,
EventId: item.EventId,
EventTitle: titleMap[item.EventId],
Ip: item.Ip,
PhoneMasked: item.PhoneMasked,
OpenidMasked: maskOpenid(item.Openid),
Result: item.Result,
CreatedAt: formatGTime(item.CreatedAt),
})
}
return &v1.EventQueryLogRes{List: list, Total: total}, nil
}
// loadEventTitles 批量读取活动标题:id -> title(一次 IN 查询,避免 N+1)。
func loadEventTitles(ctx context.Context, eventIds []int64) (map[int64]string, error) {
out := make(map[int64]string, len(eventIds))
if len(eventIds) == 0 {
return out, nil
}
records, err := g.Model(consts.TableAnnualEvents).Fields("id", "title").WhereIn("id", eventIds).All()
if err != nil {
return nil, err
}
for _, r := range records {
out[r["id"].Int64()] = r["title"].String()
}
return out, nil
}
// maskOpenid openid 脱敏:保留前 6 位 + "***";空串返回空串。
// 说明:openid 落库未脱敏(限流需原始值比对),仅在审计列表输出时脱敏。
func maskOpenid(openid string) string {
openid = strings.TrimSpace(openid)
if openid == "" {
return ""
}
if len(openid) <= 6 {
return openid + "***"
}
return openid[:6] + "***"
}