feat: admin api

This commit is contained in:
wangfuduo 2026-07-07 18:22:24 +08:00
parent 503a4adba9
commit ca93be0371
6 changed files with 258 additions and 5 deletions

View File

@ -0,0 +1,61 @@
package controller
import (
"net/http"
"strings"
"twin-api/app/admin/request"
"twin-api/app/admin/service"
"twin-api/base/config"
"git.u8t.cn/open/go-server/session"
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
)
type Pkg struct{}
func (pkg *Pkg) Query(ctx *gin.Context) {
var req request.PkgGet
if err := ctx.ShouldBind(&req); err != nil {
panic(config.ErrParam.New().Append(err))
}
count, res, err := service.NewPkg().Query(&req)
if err != nil {
panic(err)
}
ctx.JSON(http.StatusOK, session.NewListRsp(count, res))
}
func (pkg *Pkg) Create(ctx *gin.Context) {
var req request.PkgCreate
if err := ctx.ShouldBindJSON(&req); err != nil {
panic(config.ErrParam.New().Append(err))
}
if err := service.NewPkg().Create(&req); err != nil {
panic(err)
}
ctx.JSON(http.StatusOK, session.NewRspOk())
}
func (pkg *Pkg) Update(ctx *gin.Context) {
var req request.PkgPut
if err := ctx.ShouldBindJSON(&req); err != nil {
panic(config.ErrParam.New().Append(err))
}
if err := service.NewPkg().Update(&req); err != nil {
panic(err)
}
ctx.JSON(http.StatusOK, session.NewRspOk())
}
func (pkg *Pkg) Delete(ctx *gin.Context) {
var req request.PkgDelete
if err := ctx.ShouldBind(&req); err != nil {
panic(config.ErrParam.New().Append(err))
}
if err := service.NewPkg().Delete(cast.ToInt64(strings.TrimSpace(req.Id))); err != nil {
panic(err)
}
ctx.JSON(http.StatusOK, session.NewRspOk())
}

52
app/admin/request/pkg.go Normal file
View File

@ -0,0 +1,52 @@
package request
import "github.com/spf13/cast"
const MaxPageSize = 100
type PkgGet struct {
Page string `form:"page" json:"page"`
Size string `form:"size" json:"size"`
Sort string `form:"sort" json:"sort"`
Name string `form:"name" json:"name"`
Version string `form:"version" json:"version"`
Status string `form:"status" json:"status"`
}
type PkgPut struct {
Id string `json:"id"`
Expire string `json:"expire"`
Status string `json:"status"`
}
type PkgDelete struct {
Id string `form:"id" json:"id"`
}
type PkgCreate struct {
Name string `json:"package_name"`
Version string `json:"version"`
Expire string `json:"expire"`
Link string `json:"link"`
}
func (r *PkgGet) Default() {
if cast.ToInt(r.Size) == 0 {
r.Size = "10"
}
if cast.ToInt(r.Page) <= 0 {
r.Page = "1"
}
}
func (r *PkgGet) PageInt() int {
return cast.ToInt(r.Page)
}
func (r *PkgGet) SizeInt() int {
size := cast.ToInt(r.Size)
if size > MaxPageSize {
return MaxPageSize
}
return size
}

View File

@ -3,9 +3,11 @@ package dao
import (
"errors"
"fmt"
"time"
"twin-api/app/common/model"
"twin-api/base/global"
"git.u8t.cn/open/go-server/utils"
"gorm.io/gorm"
)
@ -31,8 +33,15 @@ func (p *Pkg) Update(m *model.Pkg) error {
return p.db.Table(p.TableName()).Save(m).Error
}
func (p *Pkg) UpdateCols(m *model.Pkg, cols ...string) error {
return p.db.Table(p.TableName()).Select(cols).Updates(m).Error
}
func (p *Pkg) Delete(m *model.Pkg) error {
return p.db.Table(p.TableName()).Where("id = ?", m.Id).Update("status", model.PkgDelete).Error
return p.db.Table(p.TableName()).Where("id = ?", m.Id).Updates(map[string]any{
"status": model.PkgDelete,
"update_time": time.Now().Unix(),
}).Error
}
func (p *Pkg) Get(id int64) (*model.Pkg, error) {
@ -47,13 +56,24 @@ func (p *Pkg) Get(id int64) (*model.Pkg, error) {
return &res, nil
}
func (p *Pkg) GetById(id int64) (*model.Pkg, error) {
var res model.Pkg
if err := p.db.Table(p.TableName()).Where("id = ?", id).First(&res).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &res, nil
}
func (p *Pkg) GetByPkgName(name string) (*model.Pkg, error) {
var res model.Pkg
tx := p.db.Table(p.TableName()).Where("status = ?", model.PkgNormal)
if name != "" {
tx = tx.Where("name = ?", name)
}
tx.Order("id desc")
tx = tx.Order("id desc")
if err := tx.First(&res).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
@ -63,6 +83,36 @@ func (p *Pkg) GetByPkgName(name string) (*model.Pkg, error) {
return &res, nil
}
func (p *Pkg) GetLatestByName(name string) (*model.Pkg, error) {
var list []*model.Pkg
if err := p.db.Table(p.TableName()).Where("name = ? AND status = ?", name, model.PkgNormal).Find(&list).Error; err != nil {
return nil, err
}
if len(list) == 0 {
return nil, nil
}
latest := list[0]
latestVal := utils.VersionToInt(latest.Version)
for _, item := range list[1:] {
if v := utils.VersionToInt(item.Version); v > latestVal {
latest = item
latestVal = v
}
}
return latest, nil
}
func (p *Pkg) GetByNameVersion(name, version string) (*model.Pkg, error) {
var res model.Pkg
if err := p.db.Table(p.TableName()).Where("name = ? AND version = ?", name, version).First(&res).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &res, nil
}
func (p *Pkg) GetOne(name, version string) (*model.Pkg, error) {
var res model.Pkg
tx := p.db.Table(p.TableName()).Where("status = ?", model.PkgNormal)
@ -70,7 +120,7 @@ func (p *Pkg) GetOne(name, version string) (*model.Pkg, error) {
tx = tx.Where("name = ? AND version = ?", name, version)
}
tx.Order("id desc")
tx = tx.Order("id desc")
if err := tx.First(&res).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil

View File

@ -60,6 +60,29 @@ func (p *UserPkg) GetLatest(userId int64) (*model.UserPkgInfo, error) {
return &res, nil
}
func (p *UserPkg) CountByPackageIds(packageIds []int64) (map[int64]int64, error) {
res := make(map[int64]int64)
if len(packageIds) == 0 {
return res, nil
}
type countResult struct {
PackageId int64 `gorm:"column:package_id"`
Count int64 `gorm:"column:count"`
}
var rows []countResult
if err := p.db.Table(p.TableName()).
Select("package_id, count(*) as count").
Where("package_id IN ?", packageIds).
Group("package_id").
Find(&rows).Error; err != nil {
return nil, err
}
for _, row := range rows {
res[row.PackageId] = row.Count
}
return res, nil
}
func (p *UserPkg) Query(...any) (any, error) {
panic("implement me")
}

View File

@ -1,5 +1,13 @@
package model
import (
"fmt"
"strings"
gsUtils "git.u8t.cn/open/go-server/utils"
"github.com/spf13/cast"
)
type Pkg struct {
Id int64 `json:"id"`
ExpireTime int64 `json:"expire_time"`
@ -15,3 +23,51 @@ const (
PkgNormal = 1
PkgDelete = 2
)
func (p *Pkg) Format() map[string]any {
res := make(map[string]any)
res["id"] = p.Id
res["name"] = p.Name
res["version"] = p.Version
res["link"] = p.Link
res["status"] = p.Status
res["expire"] = gsUtils.TimeToDateTime(p.ExpireTime)
res["create_date"] = gsUtils.TimeToDateTime(p.CreateTime)
res["update_date"] = gsUtils.TimeToDateTime(p.UpdateTime)
return res
}
func (p *Pkg) FormatAdmin(userCount int64) map[string]any {
res := p.Format()
res["user_count"] = userCount
return res
}
func ParseExpire(expire string) (int64, error) {
expire = strings.TrimSpace(expire)
if expire == "" {
return 0, fmt.Errorf("expire is required")
}
if isUnixTimestamp(expire) {
return cast.ToInt64(expire), nil
}
if ts := gsUtils.DateTimeToTime(expire); ts > 0 {
return ts, nil
}
if ts := gsUtils.DateToTime(expire); ts > 0 {
return ts, nil
}
return 0, fmt.Errorf("invalid expire format, supports timestamp or date")
}
func isUnixTimestamp(s string) bool {
if len(s) < 10 {
return false
}
for _, c := range s {
if c < '0' || c > '9' {
return false
}
}
return cast.ToInt64(s) > 1e9
}

View File

@ -2,10 +2,12 @@ package routers
import (
"net/http"
adminController "twin-api/app/admin/controller"
"twin-api/app/api/controller"
"twin-api/app/common/middle"
gsController "git.u8t.cn/open/go-server/api/controller"
gsAdminController "git.u8t.cn/open/go-server/admin/controller"
gsApiController "git.u8t.cn/open/go-server/api/controller"
"github.com/gin-gonic/gin"
)
@ -20,7 +22,7 @@ func InitRouter(engine *gin.Engine) {
// 客户端接口路由
func initApiRouter(engine *gin.Engine) {
base := new(gsController.BaseController)
base := new(gsApiController.BaseController)
userGroup := engine.Group("/api/user").Use(base.Recovery).Use(base.Before).Use(base.Token).Use(base.IpLimit).Use(base.Response).Use(middle.UserPkg)
userApi := new(controller.User)
@ -29,4 +31,13 @@ func initApiRouter(engine *gin.Engine) {
// 管理接口路由
func initAdminRouter(engine *gin.Engine) {
base := new(gsAdminController.BaseController)
adminGroup := engine.Group("/admin")
adminGroup.Use(base.Recovery).Use(base.Before).Use(base.Token)
pkgApi := new(adminController.Pkg)
adminGroup.GET("/package", pkgApi.Query)
adminGroup.POST("/package", pkgApi.Create)
adminGroup.PUT("/package", pkgApi.Update)
adminGroup.DELETE("/package", pkgApi.Delete)
}