完善 admin 接口筛选机制

This commit is contained in:
2026-03-23 14:26:10 +08:00
parent 71f1c6f141
commit 9f7160edfc
11 changed files with 380 additions and 18 deletions

View File

@@ -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())
}

View File

@@ -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"`
}

View File

@@ -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 {
// 检查权限

View File

@@ -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 {
// 检查权限

View File

@@ -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()

View File

@@ -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 {
// 检查权限

View File

@@ -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 {
// 检查权限

View File

@@ -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"`
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
}