diff --git a/beans/beans.go b/beans/beans.go index 07d8340..a86f531 100644 --- a/beans/beans.go +++ b/beans/beans.go @@ -10,11 +10,22 @@ type ResponseEmpty struct { } type Page struct { - PageNum int `p:"pageNum"` //当前页码 - PageSize int `p:"pageSize"` //每页数 - Total int //总页数 + PageNum int64 `p:"pageNum"` //当前页码 + PageSize int64 `p:"pageSize"` //每页数 + Total int64 //总页数 } +type OrderEnum string + +const ( + Asc OrderEnum = "asc" // 正序 + Desc OrderEnum = "desc" // 倒序 +) + +type OrderBy struct { + Field string `p:"field"` //排序字段 + Order OrderEnum `p:"order"` //排序方式 +} type MongoBaseDO struct { Id bson.ObjectID `bson:"_id,omitempty" json:"id"` // MongoDB 默认 ID Creator interface{} `bson:"creator,omitempty" json:"creator"` diff --git a/http/http.go b/http/http.go index f03e3c3..45be505 100644 --- a/http/http.go +++ b/http/http.go @@ -20,8 +20,6 @@ import ( "github.com/gogf/gf/v2/util/gconv" ) -const PageSize = 20 - var Httpserver = g.Server() var Httpclient = g.Client() diff --git a/log/controller/log_controller.go b/log/controller/log_controller.go index 996293d..9b0ec56 100644 --- a/log/controller/log_controller.go +++ b/log/controller/log_controller.go @@ -2,7 +2,6 @@ package controller import ( "context" - "strings" "gitee.com/red-future---jilin-g/common/log/model/dto" "gitee.com/red-future---jilin-g/common/log/service" @@ -32,13 +31,7 @@ func (c *operationLog) GetByID(ctx context.Context, req *dto.GetLogReq) (res *dt // @Summary 查询操作日志列表 // @Description 根据多个条件查询操作日志列表 func (c *operationLog) List(ctx context.Context, req *dto.ListLogsReq) (res *dto.ListLogsResp, err error) { - // 处理排序字段 - var sortFields []string - if req.SortFields != "" { - sortFields = strings.Split(req.SortFields, ",") - } - - logs, total, err := service.OperationLog.List(ctx, req, sortFields...) + logs, total, err := service.OperationLog.List(ctx, req) if err != nil { return } diff --git a/log/dao/log_dao.go b/log/dao/log_dao.go index c459117..7e21a18 100644 --- a/log/dao/log_dao.go +++ b/log/dao/log_dao.go @@ -86,7 +86,7 @@ func (d *log) List(ctx context.Context, filter *dto.ListLogsReq, sortFields ...s } var logs []*entity.OperationLog - err = mongo.DB().Find(ctx, bsonFilter, &logs, consts.OperationLogCollection, findOptions...) + err = mongo.DB().Find(ctx, bsonFilter, &logs, consts.OperationLogCollection, nil, nil) if err != nil { return nil, 0, err } diff --git a/log/model/dto/log_dto.go b/log/model/dto/log_dto.go index 81e8b29..862e91c 100644 --- a/log/model/dto/log_dto.go +++ b/log/model/dto/log_dto.go @@ -34,13 +34,13 @@ type OperationLogInfo struct { type ListLogsReq struct { g.Meta `path:"/listLogs" method:"get" tags:"操作日志" summary:"查询操作日志列表" dc:"根据多个条件查询操作日志列表"` beans.Page - ServiceName string `json:"service_name" dc:"服务名(可选)"` - Collection string `json:"collection" dc:"数据所在集合名称(可选)"` - CollectionID string `json:"collection_id" dc:"数据ID(可选)"` - Operation string `json:"operation" dc:"操作类型(可选)"` - StartTime string `json:"start_time" dc:"开始时间(可选)"` - EndTime string `json:"end_time" dc:"结束时间(可选)"` - SortFields string `json:"sort_fields" dc:"排序字段,多个用逗号分隔,如:-createdAt"` + ServiceName string `json:"service_name" dc:"服务名(可选)"` + Collection string `json:"collection" dc:"数据所在集合名称(可选)"` + CollectionID string `json:"collection_id" dc:"数据ID(可选)"` + Operation string `json:"operation" dc:"操作类型(可选)"` + StartTime string `json:"start_time" dc:"开始时间(可选)"` + EndTime string `json:"end_time" dc:"结束时间(可选)"` + OrderBy []beans.OrderBy `json:"orderBy" dc:"排序字段"` } // ListLogsResp 查询操作日志列表响应 diff --git a/log/service/log_service.go b/log/service/log_service.go index cc9ea4e..70fcac4 100644 --- a/log/service/log_service.go +++ b/log/service/log_service.go @@ -53,8 +53,8 @@ func (s *operationLog) GetByID(ctx context.Context, id string) (*dto.OperationLo } // List 查询操作日志列表 -func (s *operationLog) List(ctx context.Context, filter *dto.ListLogsReq, sortFields ...string) ([]dto.OperationLogInfo, int64, error) { - logs, total, err := dao.Log.List(ctx, filter, sortFields...) +func (s *operationLog) List(ctx context.Context, req *dto.ListLogsReq) ([]dto.OperationLogInfo, int64, error) { + logs, total, err := dao.Log.List(ctx, req) if err != nil { return nil, 0, err } diff --git a/mongo/mongo.go b/mongo/mongo.go index 3df3396..2f75dc4 100644 --- a/mongo/mongo.go +++ b/mongo/mongo.go @@ -4,10 +4,12 @@ import ( "context" "errors" "fmt" + "reflect" "strings" "sync" "time" + "gitee.com/red-future---jilin-g/common/beans" "gitee.com/red-future---jilin-g/common/log/model/dto" "github.com/gogf/gf/v2/container/gvar" @@ -219,56 +221,11 @@ func close() { isConnected = false glog.Info(context.Background(), "MongoDB连接已关闭") } -func listOptionsToMap(ctx context.Context, opts ...options.Lister[options.FindOptions]) (m map[string]interface{}) { - // 输出opts参数中的值 - m = make(map[string]interface{}) - for _, opt := range opts { - var findOpts options.FindOptions - optFuncs := opt.List() - for _, fn := range optFuncs { - fn(&findOpts) - } - if findOpts.Limit != nil { - m["limit"] = *findOpts.Limit - } - if findOpts.Skip != nil { - m["skip"] = *findOpts.Skip - } - if findOpts.Sort != nil { - m["sort"] = findOpts.Sort - } - if findOpts.Projection != nil { - m["projection"] = findOpts.Projection - } - } - m = utils.OrderMap(m) - return -} -func oneOptionsToMap(ctx context.Context, opts ...options.Lister[options.FindOneOptions]) (m map[string]interface{}) { - // 输出opts参数中的值 - m = make(map[string]interface{}) - for _, opt := range opts { - var findOpts options.FindOneOptions - optFuncs := opt.List() - for _, fn := range optFuncs { - fn(&findOpts) - } - if findOpts.Skip != nil { - m["skip"] = *findOpts.Skip - } - if findOpts.Sort != nil { - m["sort"] = findOpts.Sort - } - if findOpts.Projection != nil { - m["projection"] = findOpts.Projection - } - } - m = utils.OrderMap(m) - return -} + +const PageSize = 20 // Find 查询多条记录 -func (m *MongoDB) Find(ctx context.Context, filter bson.M, result interface{}, collection string, opts ...options.Lister[options.FindOptions]) (err error) { +func (m *MongoDB) Find(ctx context.Context, filter bson.M, result interface{}, collection string, page *beans.Page, orderBy []beans.OrderBy) (err error) { if err = utils.ValidStructPtr(result); err != nil { return } @@ -277,34 +234,79 @@ func (m *MongoDB) Find(ctx context.Context, filter bson.M, result interface{}, c return } filter["isDeleted"] = false - filterMap := utils.OrderMap(filter) - optsMap := listOptionsToMap(ctx, opts...) - redisKey := fmt.Sprintf(redis.List, user.TenantId, collection, gconv.String(filterMap), gconv.String(optsMap)) + filterKey := fmt.Sprintf("%+v", filter) + optionsKey := fmt.Sprintf("%+v%+v", page, orderBy) + redisKey := fmt.Sprintf(redis.List, user.TenantId, collection, filterKey, optionsKey) + resultValue := reflect.ValueOf(result) + resultValue = resultValue.Elem() + listField := resultValue.FieldByName("List") if m.Cache { var resultStr *gvar.Var resultStr, err = redis.RedisClient.Get(ctx, redisKey) if err != nil { return } - if !g.IsEmpty(resultStr) { - err = gconv.Scan(resultStr, result) - if err != nil { - return err - } + if !resultStr.IsEmpty() { + resultStr.Structs(listField.Addr().Interface()) return } } filter["tenantId"] = user.TenantId - cur, err := db.Collection(collection).Find(ctx, filter, opts...) + + // 分页参数处理 + limit := int64(PageSize) + skip := int64(0) + if page != nil { + limit = page.PageSize + skip = (page.PageNum - 1) * limit + if skip <= 0 { + skip = 0 + } + } + total, err := m.Count(ctx, filter, collection) + if err != nil || total == 0 { + return + } + utils.SetValue(ctx, result, "Total", total) + opt := options.Find().SetSkip(skip) + if limit != -1 { + opt.SetLimit(limit) + } + if orderBy == nil { + opt.SetSort(bson.M{"createdAt": -1}) + } else { + orderBson := bson.M{} + for _, v := range orderBy { + if v.Order == beans.Asc { + orderBson[v.Field] = 1 + } else { + orderBson[v.Field] = -1 + } + } + opt.SetSort(orderBson) + } + + cur, err := db.Collection(collection).Find(ctx, filter, opt) if err != nil { return } defer cur.Close(ctx) - if err = cur.All(ctx, result); err != nil { + + // 先解码到[]bson.M,再转换到目标类型,处理datetime到string的转换 + var docs []bson.M + if err = cur.All(ctx, &docs); err != nil { + return + } + for _, v := range docs { + v["id"] = v["_id"].(bson.ObjectID).Hex() + delete(v, "_id") + } + // 使用gconv转换,处理类型转换 + if err = gconv.Structs(docs, listField.Addr().Interface()); err != nil { return } if m.Cache { - err = redis.RedisClient.SetEX(ctx, redisKey, result, int64(time.Hour)) + err = redis.RedisClient.SetEX(ctx, redisKey, docs, int64(time.Hour)) if err != nil { return err } @@ -326,8 +328,8 @@ func (m *MongoDB) FindOne(ctx context.Context, filter bson.M, result interface{} return } filter["isDeleted"] = false - filterMap := utils.OrderMap(filter) - redisKey := fmt.Sprintf(redis.One, user.TenantId, collection, gconv.String(filterMap)) + filterKey := fmt.Sprintf("%+v", filter) + redisKey := fmt.Sprintf(redis.One, user.TenantId, collection, filterKey) if m.Cache { var resultStr *gvar.Var resultStr, err = redis.RedisClient.Get(ctx, redisKey) @@ -383,8 +385,8 @@ func (m *MongoDB) CleanRedis(ctx context.Context, filter bson.M, tenantId interf } filter["isDeleted"] = false delete(filter, "tenantId") - filterMap := utils.OrderMap(filter) - oneKey := fmt.Sprintf(redis.One, tenantId, collection, gconv.String(filterMap)) + filterKey := fmt.Sprintf("%+v", filter) + oneKey := fmt.Sprintf(redis.One, tenantId, collection, filterKey) _, err = redis.RedisClient.Del(ctx, oneKey) if err != nil { return @@ -404,7 +406,7 @@ func (m *MongoDB) Delete(ctx context.Context, filter bson.M, collection string, } filter["tenantId"] = user.TenantId var rows []interface{} - if err = m.Find(ctx, filter, &rows, collection); err != nil { + if err = m.Find(ctx, filter, &rows, collection, nil, nil); err != nil { return } r, err := db.Collection(collection).DeleteMany(ctx, filter, opts...) @@ -446,7 +448,7 @@ func (m *MongoDB) Update(ctx context.Context, filter bson.M, update bson.M, coll setDoc["updatedAt"] = gtime.Now().Time update = bson.M{"$set": setDoc} var rows []interface{} - if err = m.Find(ctx, filter, &rows, collection); err != nil { + if err = m.Find(ctx, filter, &rows, collection, nil, nil); err != nil { return } result, err = db.Collection(collection).UpdateMany(ctx, filter, update, opts...) @@ -631,7 +633,7 @@ func (m *MongoDB) Insert(ctx context.Context, documents []interface{}, collectio rows = append(rows, doc) } else { filter := bson.M{"_id": bson.M{"$in": ids}} - if err = m.Find(ctx, filter, &rows, collection); err != nil { + if err = m.Find(ctx, filter, &rows, collection, nil, nil); err != nil { return } } @@ -652,8 +654,9 @@ func (m *MongoDB) Count(ctx context.Context, filter bson.M, collection string) ( return } filter["isDeleted"] = false - filterMap := utils.OrderMap(filter) - redisKey := fmt.Sprintf(redis.Count, user.TenantId, collection, gconv.String(filterMap)) + delete(filter, "tenantId") + filterKey := fmt.Sprintf("%+v", filter) + redisKey := fmt.Sprintf(redis.Count, user.TenantId, collection, filterKey) if m.Cache { var resultStr *gvar.Var resultStr, err = redis.RedisClient.Get(ctx, redisKey) diff --git a/utils/utils.go b/utils/utils.go index 8d9efa4..0915ca9 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -107,7 +107,34 @@ func GetUserInfo(ctx context.Context) (user beans.User, err error) { } return } +func SetValue(ctx context.Context, result any, key string, value any) { + // 检查context是否已取消 + select { + case <-ctx.Done(): + return + default: + // 使用反射设置result的Total属性 + resultValue := reflect.ValueOf(result) + if resultValue.Kind() == reflect.Ptr { + resultValue = resultValue.Elem() + totalField := resultValue.FieldByName(key) + if totalField.IsValid() && totalField.CanSet() { + totalField.Set(reflect.ValueOf(value)) + } + } + return + } +} +func Struts(ctx context.Context, pointer any, mapping ...map[string]string) { + // 检查context是否已取消 + select { + case <-ctx.Done(): + return + default: + return + } +} func OrderMap(m map[string]interface{}) map[string]interface{} { // 提取所有key keys := make([]string, 0, len(m))