diff --git a/pkg/u/u.go b/pkg/u/u.go index f99e2a8..2112c69 100644 --- a/pkg/u/u.go +++ b/pkg/u/u.go @@ -82,7 +82,7 @@ func DateHead(date time.Time) time.Time { return time.Date(y, m, d, 0, 0, 0, 0, date.Location()) } -func DateFoot(date time.Time) time.Time { +func DateTail(date time.Time) time.Time { var y, m, d = date.Date() return time.Date(y, m, d, 23, 59, 59, 999999999, date.Location()) } diff --git a/web/handlers/batch.go b/web/handlers/batch.go index ebeb8c3..7841bfa 100644 --- a/web/handlers/batch.go +++ b/web/handlers/batch.go @@ -1,6 +1,7 @@ package handlers import ( + "platform/pkg/u" "platform/web/auth" "platform/web/core" c "platform/web/core" @@ -63,18 +64,48 @@ func PageBatchByAdmin(c *fiber.Ctx) error { return err } - req := new(struct{ core.PageReq }) - if err = g.Validator.ParseBody(c, req); err != nil { + var req PageBatchByAdminReq + if err = g.Validator.ParseBody(c, &req); err != nil { return err } + do := q.LogsUserUsage.Where() + if req.UserPhone != nil { + do = do.Where(q.User.Phone.Eq(*req.UserPhone)) + } + if req.ResourceNo != nil { + do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo)) + } + if req.BatchNo != nil { + do = do.Where(q.LogsUserUsage.BatchNo.Eq(*req.BatchNo)) + } + if req.Prov != nil { + do = do.Where(q.LogsUserUsage.Prov.Eq(*req.Prov)) + } + if req.City != nil { + do = do.Where(q.LogsUserUsage.City.Eq(*req.City)) + } + if req.Isp != nil { + do = do.Where(q.LogsUserUsage.ISP.Eq(*req.Isp)) + } + if req.CreatedAtStart != nil { + time := u.DateHead(*req.CreatedAtStart) + do = do.Where(q.LogsUserUsage.Time.Gte(time)) + } + if req.CreatedAtEnd != nil { + time := u.DateTail(*req.CreatedAtEnd) + do = do.Where(q.LogsUserUsage.Time.Lte(time)) + } + list, total, err := q.LogsUserUsage. - Joins(q.LogsUserUsage.User). + Joins(q.LogsUserUsage.User, q.LogsUserUsage.Resource). Select( q.LogsUserUsage.ALL, q.User.As("User").Phone.As("User__phone"), q.User.As("User").Name.As("User__name"), + q.Resource.As("Resource").ResourceNo.As("Resource__resource_no"), ). + Where(do). FindByPage(req.GetOffset(), req.GetLimit()) return c.JSON(core.PageResp{ @@ -84,3 +115,15 @@ func PageBatchByAdmin(c *fiber.Ctx) error { Size: req.GetSize(), }) } + +type PageBatchByAdminReq struct { + c.PageReq + UserPhone *string `json:"user_phone"` + ResourceNo *string `json:"resource_no"` + BatchNo *string `json:"batch_no"` + Prov *string `json:"prov"` + City *string `json:"city"` + Isp *string `json:"isp"` + CreatedAtStart *time.Time `json:"created_at_start"` + CreatedAtEnd *time.Time `json:"created_at_end"` +} diff --git a/web/handlers/bill.go b/web/handlers/bill.go index e0a4f68..3a0a7fc 100644 --- a/web/handlers/bill.go +++ b/web/handlers/bill.go @@ -1,6 +1,7 @@ package handlers import ( + "platform/pkg/u" "platform/web/auth" "platform/web/core" g "platform/web/globals" @@ -19,19 +20,45 @@ func PageBillByAdmin(c *fiber.Ctx) error { } // 解析请求参数 - req := new(core.PageReq) + req := new(PageBillByAdminReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } + // 构造查询条件 + do := q.Bill.Where() + if req.UserPhone != nil { + do = do.Where(q.User.Phone.Eq(*req.UserPhone)) + } + if req.TradeInnerNo != nil { + do = do.Where(q.Trade.InnerNo.Eq(*req.TradeInnerNo)) + } + if req.ResourceNo != nil { + do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo)) + } + if req.BillNo != nil { + do = do.Where(q.Bill.BillNo.Eq(*req.BillNo)) + } + if req.CreatedAtStart != nil { + time := u.DateHead(*req.CreatedAtStart) + do = do.Where(q.Bill.CreatedAt.Gte(time)) + } + if req.CreatedAtEnd != nil { + time := u.DateHead(*req.CreatedAtEnd) + do = do.Where(q.Bill.CreatedAt.Lte(time)) + } + // 查询用户列表 - list, total, err := q.Bill. - Joins(q.Bill.User). + list, total, err := q.Bill.Debug(). + Joins(q.Bill.User, q.Bill.Resource, q.Bill.Trade). Select( q.Bill.ALL, q.User.As("User").Phone.As("User__phone"), q.User.As("User").Name.As("User__name"), + q.Trade.As("Trade").InnerNo.As("Trade__inner_no"), + q.Resource.As("Resource").ResourceNo.As("Resource__resource_no"), ). + Where(do). FindByPage(req.GetOffset(), req.GetLimit()) if err != nil { return err @@ -46,6 +73,16 @@ func PageBillByAdmin(c *fiber.Ctx) error { }) } +type PageBillByAdminReq struct { + core.PageReq + UserPhone *string `json:"user_phone,omitempty"` + TradeInnerNo *string `json:"trade_inner_no,omitempty"` + ResourceNo *string `json:"resource_no,omitempty"` + BillNo *string `json:"bill_no,omitempty"` + CreatedAtStart *time.Time `json:"created_at_start,omitempty"` + CreatedAtEnd *time.Time `json:"created_at_end,omitempty"` +} + // ListBill 获取账单列表 func ListBill(c *fiber.Ctx) error { // 检查权限 diff --git a/web/handlers/channel.go b/web/handlers/channel.go index ba3ca23..034b9f4 100644 --- a/web/handlers/channel.go +++ b/web/handlers/channel.go @@ -6,6 +6,7 @@ import ( "platform/web/auth" "platform/web/core" g "platform/web/globals" + "platform/web/globals/orm" m "platform/web/models" q "platform/web/queries" s "platform/web/services" @@ -23,11 +24,44 @@ func PageChannelsByAdmin(c *fiber.Ctx) error { } // 解析请求参数 - req := new(core.PageReq) - if err := g.Validator.ParseBody(c, req); err != nil { + var req PageChannelsByAdminReq + if err := g.Validator.ParseBody(c, &req); err != nil { return err } + // 构建查询条件 + do := q.Channel.Where() + if req.UserPhone != nil { + do = do.Where(q.User.Phone.Eq(*req.UserPhone)) + } + if req.ResourceNo != nil { + do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo)) + } + if req.BatchNo != nil { + do = do.Where(q.Channel.BatchNo.Eq(*req.BatchNo)) + } + if req.ProxyHost != nil { + do = do.Where(q.Channel.Host.Eq(*req.ProxyHost)) + } + if req.ProxyPort != nil { + do = do.Where(q.Channel.Port.Eq(*req.ProxyPort)) + } + if req.NodeIP != nil { + ip, err := orm.ParseInet(*req.NodeIP) + if err != nil { + return core.NewBizErr("查询参数 ip 格式不正确") + } + do = do.Where(q.Channel.IP.Eq(ip)) + } + if req.ExpiredAtStart != nil { + time := u.DateHead(*req.ExpiredAtStart) + do = do.Where(q.Channel.ExpiredAt.Gte(time)) + } + if req.ExpiredAtEnd != nil { + time := u.DateHead(*req.ExpiredAtEnd) + do = do.Where(q.Channel.ExpiredAt.Lte(time)) + } + // 查询通道列表 list, total, err := q.Channel. Joins(q.Channel.User). @@ -36,6 +70,7 @@ func PageChannelsByAdmin(c *fiber.Ctx) error { q.User.As("User").Phone.As("User__phone"), q.User.As("User").Name.As("User__name"), ). + Where(do). FindByPage(req.GetOffset(), req.GetLimit()) if err != nil { return err @@ -50,6 +85,18 @@ func PageChannelsByAdmin(c *fiber.Ctx) error { }) } +type PageChannelsByAdminReq struct { + core.PageReq + UserPhone *string `json:"user_phone"` + ResourceNo *string `json:"resource_no"` + BatchNo *string `json:"batch_no"` + ProxyHost *string `json:"proxy_host"` + ProxyPort *uint16 `json:"proxy_port"` + NodeIP *string `json:"node_ip" validator:"omitempty,ip"` + ExpiredAtStart *time.Time `json:"expired_at_start"` + ExpiredAtEnd *time.Time `json:"expired_at_end"` +} + // 分页查询当前用户通道 func ListChannels(c *fiber.Ctx) error { // 检查权限 diff --git a/web/handlers/resource.go b/web/handlers/resource.go index 535901d..b92e0a7 100644 --- a/web/handlers/resource.go +++ b/web/handlers/resource.go @@ -214,11 +214,33 @@ func PageResourceShortByAdmin(c *fiber.Ctx) error { return err } - req := new(struct{ core.PageReq }) - if err = g.Validator.ParseBody(c, req); err != nil { + var req PageResourceShortByAdminReq + if err = g.Validator.ParseBody(c, &req); err != nil { return err } + do := q.Resource.Where() + if req.UserPhone != nil { + do = do.Where(q.User.Phone.Eq(*req.UserPhone)) + } + if req.ResourceNo != nil { + do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo)) + } + if req.Active != nil { + do = do.Where(q.Resource.Active.Is(*req.Active)) + } + if req.Mode != nil { + do = do.Where(q.Resource.Type.Eq(int(m.ResourceTypeShort))) + } + if req.CreatedAtStart != nil { + time := u.DateHead(*req.CreatedAtStart) + do = do.Where(q.Resource.CreatedAt.Gte(time)) + } + if req.CreatedAtEnd != nil { + time := u.DateTail(*req.CreatedAtEnd) + do = do.Where(q.Resource.CreatedAt.Lte(time)) + } + list, total, err := q.Resource. Joins(q.Resource.User, q.Resource.Short). Select( @@ -227,7 +249,7 @@ func PageResourceShortByAdmin(c *fiber.Ctx) error { q.User.As("User").Phone.As("User__phone"), q.User.As("User").Name.As("User__name"), ). - Where(q.Resource.Type.Eq(int(m.ResourceTypeShort))). + Where(q.Resource.Type.Eq(int(m.ResourceTypeShort)), do). FindByPage(req.GetOffset(), req.GetLimit()) return c.JSON(core.PageResp{ @@ -238,6 +260,16 @@ func PageResourceShortByAdmin(c *fiber.Ctx) error { }) } +type PageResourceShortByAdminReq struct { + core.PageReq + UserPhone *string `json:"user_phone" form:"user_phone"` + ResourceNo *string `json:"resource_no" form:"resource_no"` + Active *bool `json:"active" form:"active"` + Mode *int `json:"mode" form:"mode"` + CreatedAtStart *time.Time `json:"created_at_start" form:"created_at_start"` + CreatedAtEnd *time.Time `json:"created_at_end" form:"created_at_end"` +} + // PageResourceLongByAdmin 分页查询全部短效套餐 func PageResourceLongByAdmin(c *fiber.Ctx) error { _, err := auth.GetAuthCtx(c).PermitAdmin() diff --git a/web/handlers/trade.go b/web/handlers/trade.go index e011722..baedb2e 100644 --- a/web/handlers/trade.go +++ b/web/handlers/trade.go @@ -5,6 +5,7 @@ import ( "fmt" "log/slog" "platform/pkg/env" + "platform/pkg/u" "platform/web/auth" "platform/web/core" g "platform/web/globals" @@ -26,11 +27,40 @@ func PageTradeByAdmin(c *fiber.Ctx) error { } // 解析请求参数 - req := new(core.PageReq) + req := new(PageTradeByAdminReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } + // 构建查询语句 + do := q.Trade.Where() + if req.UserPhone != nil { + do = do.Where(q.User.As("User").Phone.Eq(*req.UserPhone)) + } + if req.InnerNo != nil { + do = do.Where(q.Trade.InnerNo.Eq(*req.InnerNo)) + } + if req.OuterNo != nil { + do = do.Where(q.Trade.OuterNo.Eq(*req.OuterNo)) + } + if req.Method != nil { + do = do.Where(q.Trade.Method.Eq(*req.Method)) + } + if req.Platform != nil { + do = do.Where(q.Trade.Platform.Eq(*req.Platform)) + } + if req.Status != nil { + do = do.Where(q.Trade.Status.Eq(*req.Status)) + } + if req.CreatedAtStart != nil { + time := u.DateHead(*req.CreatedAtStart) + do = do.Where(q.Trade.CreatedAt.Gte(time)) + } + if req.CreatedAtEnd != nil { + time := u.DateTail(*req.CreatedAtEnd) + do = do.Where(q.Trade.CreatedAt.Lte(time)) + } + // 查询用户列表 list, total, err := q.Trade. Joins(q.Trade.User). @@ -39,6 +69,7 @@ func PageTradeByAdmin(c *fiber.Ctx) error { q.User.As("User").Phone.As("User__phone"), q.User.As("User").Name.As("User__name"), ). + Where(do). FindByPage(req.GetOffset(), req.GetLimit()) if err != nil { return err @@ -53,6 +84,18 @@ func PageTradeByAdmin(c *fiber.Ctx) error { }) } +type PageTradeByAdminReq struct { + core.PageReq + UserPhone *string `json:"user_phone,omitempty"` + InnerNo *string `json:"inner_no,omitempty"` + OuterNo *string `json:"outer_no,omitempty"` + Method *int `json:"method,omitempty"` + Platform *int `json:"platform,omitempty"` + Status *int `json:"status,omitempty"` + CreatedAtStart *time.Time `json:"created_at_start,omitempty"` + CreatedAtEnd *time.Time `json:"created_at_end,omitempty"` +} + // 创建订单 func TradeCreate(c *fiber.Ctx) error { // 检查权限 diff --git a/web/handlers/user.go b/web/handlers/user.go index bb9ba91..8b2d6d1 100644 --- a/web/handlers/user.go +++ b/web/handlers/user.go @@ -21,15 +21,46 @@ func PageUserByAdmin(c *fiber.Ctx) error { } // 解析请求参数 - req := new(core.PageReq) + req := new(PageUserByAdminReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } + // 构建查询条件 + do := q.User.Where() + if req.Phone != nil { + do = do.Where(q.User.Phone.Eq(*req.Phone)) + } + if req.Name != nil { + do = do.Where(q.User.Name.Eq(*req.Name)) + } + if req.Identified != nil { + if *req.Identified { + do = do.Where(q.User.IDType.Gt(0)) + } else { + do = do.Where(q.User.IDType.Eq(0)) + } + } + if req.Enabled != nil { + if *req.Enabled { + do = do.Where(q.User.Status.Eq(1)) + } else { + do = do.Where(q.User.Status.Eq(0)) + } + } + if req.Assigned != nil { + if *req.Assigned { + do = do.Where(q.User.AdminID.IsNotNull()) + } else { + do = do.Where(q.User.AdminID.IsNull()) + } + } + // 查询用户列表 users, total, err := q.User. Preload(q.User.Admin). Omit(q.User.Password). + Where(do). FindByPage(req.GetOffset(), req.GetLimit()) if err != nil { return err @@ -52,6 +83,15 @@ func PageUserByAdmin(c *fiber.Ctx) error { }) } +type PageUserByAdminReq struct { + core.PageReq + Phone *string `json:"phone,omitempty" validate:"omitempty,number"` + Name *string `json:"name,omitempty"` + Identified *bool `json:"identified,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Assigned *bool `json:"assigned,omitempty"` +} + // 绑定管理员 func BindAdmin(c *fiber.Ctx) error { // 检查权限 diff --git a/web/models/logs_user_usage.go b/web/models/logs_user_usage.go index 572a0ba..b606769 100644 --- a/web/models/logs_user_usage.go +++ b/web/models/logs_user_usage.go @@ -18,5 +18,6 @@ type LogsUserUsage struct { IP orm.Inet `json:"ip" gorm:"column:ip"` // IP地址 Time time.Time `json:"time" gorm:"column:time"` // 提取时间 - User *User `json:"user,omitempty" gorm:"foreignKey:UserID"` + User *User `json:"user,omitempty" gorm:"foreignKey:UserID"` + Resource *Resource `json:"resource,omitempty" gorm:"foreignKey:ResourceID"` } diff --git a/web/queries/logs_user_usage.gen.go b/web/queries/logs_user_usage.gen.go index 66e9c19..8fe7256 100644 --- a/web/queries/logs_user_usage.gen.go +++ b/web/queries/logs_user_usage.gen.go @@ -108,6 +108,27 @@ func newLogsUserUsage(db *gorm.DB, opts ...gen.DOOption) logsUserUsage { }, } + _logsUserUsage.Resource = logsUserUsageBelongsToResource{ + db: db.Session(&gorm.Session{}), + + RelationField: field.NewRelation("Resource", "models.Resource"), + User: struct { + field.RelationField + }{ + RelationField: field.NewRelation("Resource.User", "models.User"), + }, + Short: struct { + field.RelationField + }{ + RelationField: field.NewRelation("Resource.Short", "models.ResourceShort"), + }, + Long: struct { + field.RelationField + }{ + RelationField: field.NewRelation("Resource.Long", "models.ResourceLong"), + }, + } + _logsUserUsage.fillFieldMap() return _logsUserUsage @@ -129,6 +150,8 @@ type logsUserUsage struct { Time field.Time User logsUserUsageBelongsToUser + Resource logsUserUsageBelongsToResource + fieldMap map[string]field.Expr } @@ -170,7 +193,7 @@ func (l *logsUserUsage) GetFieldByName(fieldName string) (field.OrderExpr, bool) } func (l *logsUserUsage) fillFieldMap() { - l.fieldMap = make(map[string]field.Expr, 11) + l.fieldMap = make(map[string]field.Expr, 12) l.fieldMap["id"] = l.ID l.fieldMap["user_id"] = l.UserID l.fieldMap["resource_id"] = l.ResourceID @@ -188,12 +211,15 @@ func (l logsUserUsage) clone(db *gorm.DB) logsUserUsage { l.logsUserUsageDo.ReplaceConnPool(db.Statement.ConnPool) l.User.db = db.Session(&gorm.Session{Initialized: true}) l.User.db.Statement.ConnPool = db.Statement.ConnPool + l.Resource.db = db.Session(&gorm.Session{Initialized: true}) + l.Resource.db.Statement.ConnPool = db.Statement.ConnPool return l } func (l logsUserUsage) replaceDB(db *gorm.DB) logsUserUsage { l.logsUserUsageDo.ReplaceDB(db) l.User.db = db.Session(&gorm.Session{}) + l.Resource.db = db.Session(&gorm.Session{}) return l } @@ -300,6 +326,97 @@ func (a logsUserUsageBelongsToUserTx) Unscoped() *logsUserUsageBelongsToUserTx { return &a } +type logsUserUsageBelongsToResource struct { + db *gorm.DB + + field.RelationField + + User struct { + field.RelationField + } + Short struct { + field.RelationField + } + Long struct { + field.RelationField + } +} + +func (a logsUserUsageBelongsToResource) Where(conds ...field.Expr) *logsUserUsageBelongsToResource { + if len(conds) == 0 { + return &a + } + + exprs := make([]clause.Expression, 0, len(conds)) + for _, cond := range conds { + exprs = append(exprs, cond.BeCond().(clause.Expression)) + } + a.db = a.db.Clauses(clause.Where{Exprs: exprs}) + return &a +} + +func (a logsUserUsageBelongsToResource) WithContext(ctx context.Context) *logsUserUsageBelongsToResource { + a.db = a.db.WithContext(ctx) + return &a +} + +func (a logsUserUsageBelongsToResource) Session(session *gorm.Session) *logsUserUsageBelongsToResource { + a.db = a.db.Session(session) + return &a +} + +func (a logsUserUsageBelongsToResource) Model(m *models.LogsUserUsage) *logsUserUsageBelongsToResourceTx { + return &logsUserUsageBelongsToResourceTx{a.db.Model(m).Association(a.Name())} +} + +func (a logsUserUsageBelongsToResource) Unscoped() *logsUserUsageBelongsToResource { + a.db = a.db.Unscoped() + return &a +} + +type logsUserUsageBelongsToResourceTx struct{ tx *gorm.Association } + +func (a logsUserUsageBelongsToResourceTx) Find() (result *models.Resource, err error) { + return result, a.tx.Find(&result) +} + +func (a logsUserUsageBelongsToResourceTx) Append(values ...*models.Resource) (err error) { + targetValues := make([]interface{}, len(values)) + for i, v := range values { + targetValues[i] = v + } + return a.tx.Append(targetValues...) +} + +func (a logsUserUsageBelongsToResourceTx) Replace(values ...*models.Resource) (err error) { + targetValues := make([]interface{}, len(values)) + for i, v := range values { + targetValues[i] = v + } + return a.tx.Replace(targetValues...) +} + +func (a logsUserUsageBelongsToResourceTx) Delete(values ...*models.Resource) (err error) { + targetValues := make([]interface{}, len(values)) + for i, v := range values { + targetValues[i] = v + } + return a.tx.Delete(targetValues...) +} + +func (a logsUserUsageBelongsToResourceTx) Clear() error { + return a.tx.Clear() +} + +func (a logsUserUsageBelongsToResourceTx) Count() int64 { + return a.tx.Count() +} + +func (a logsUserUsageBelongsToResourceTx) Unscoped() *logsUserUsageBelongsToResourceTx { + a.tx = a.tx.Unscoped() + return &a +} + type logsUserUsageDo struct{ gen.DO } func (l logsUserUsageDo) Debug() *logsUserUsageDo { diff --git a/web/services/admin.go b/web/services/admin.go index 07e93ad..bf8775e 100644 --- a/web/services/admin.go +++ b/web/services/admin.go @@ -5,6 +5,7 @@ import ( "platform/web/core" m "platform/web/models" q "platform/web/queries" + "time" "golang.org/x/crypto/bcrypt" "gorm.io/gen/field" @@ -146,6 +147,6 @@ func (s *adminService) UpdateAdmin(update *UpdateAdmin) error { } func (s *adminService) RemoveAdmin(id int32) error { - _, err := q.Admin.Where(q.Admin.ID.Eq(id)).Delete() + _, err := q.Admin.Where(q.Admin.ID.Eq(id)).UpdateColumn(q.Admin.DeletedAt, time.Now()) return err } diff --git a/web/services/admin_role.go b/web/services/admin_role.go index 77e4bfd..5ba4d0a 100644 --- a/web/services/admin_role.go +++ b/web/services/admin_role.go @@ -7,6 +7,7 @@ import ( "platform/web/models" m "platform/web/models" q "platform/web/queries" + "time" "gorm.io/gen/field" ) @@ -136,7 +137,7 @@ type UpdateAdminRole struct { } func (r *adminRoleService) RemoveAdminRole(id int32) error { - _, err := q.AdminRole.Where(q.AdminRole.ID.Eq(id)).Delete() + _, err := q.AdminRole.Where(q.AdminRole.ID.Eq(id)).UpdateColumn(q.AdminRole.DeletedAt, time.Now()) return err }