init: 毛孩子计划 小程序 + Go 后端 + 内嵌后台
- pets-fe: 微信原生小程序(首页/计划/记录/报告/社区/引导), 服务端驱动、无假数据;弹层改用 scroll-view,打开时隐藏自定义 tabBar - pets-be: Gin + GORM(MySQL, sundynix_ 前缀) + MinIO,统一响应/分页, 微信 code2session 登录,provider-neutral AI(DeepSeek),go:embed React 后台 - 修复:分段选择类型不匹配(字符串 vs 数字)导致选不中 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/sundynix/pets-be/internal/middleware"
|
||||
"github.com/sundynix/pets-be/internal/model"
|
||||
appjwt "github.com/sundynix/pets-be/pkg/jwt"
|
||||
"github.com/sundynix/pets-be/pkg/response"
|
||||
)
|
||||
|
||||
type adminLoginReq struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// AdminLogin POST /api/admin/login
|
||||
func (h *Handler) AdminLogin(c *gin.Context) {
|
||||
var req adminLoginReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailParams(c, err.Error())
|
||||
return
|
||||
}
|
||||
admin, err := h.svc.AdminLogin(req.Username, req.Password)
|
||||
if err != nil {
|
||||
response.Fail(c, 40100, "账号或密码错误")
|
||||
return
|
||||
}
|
||||
token, err := h.jwt.Generate(admin.ID, appjwt.KindAdmin, admin.Username, admin.Role)
|
||||
if err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"token": token, "admin": admin})
|
||||
}
|
||||
|
||||
// AdminMe GET /api/admin/me
|
||||
func (h *Handler) AdminMe(c *gin.Context) {
|
||||
admin, err := h.svc.GetAdmin(middleware.AdminID(c))
|
||||
if err != nil {
|
||||
respondErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, admin)
|
||||
}
|
||||
|
||||
// AdminStats GET /api/admin/stats
|
||||
func (h *Handler) AdminStats(c *gin.Context) {
|
||||
stats, err := h.svc.Stats()
|
||||
if err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, stats)
|
||||
}
|
||||
|
||||
type adminListReq struct {
|
||||
response.PageQuery
|
||||
Keyword string `form:"keyword"`
|
||||
Status string `form:"status"`
|
||||
}
|
||||
|
||||
// AdminListUsers GET /api/admin/users
|
||||
func (h *Handler) AdminListUsers(c *gin.Context) {
|
||||
var req adminListReq
|
||||
_ = c.ShouldBindQuery(&req)
|
||||
req.Normalize()
|
||||
users, total, err := h.svc.ListUsers(req.Keyword, req.Offset(), req.Limit())
|
||||
if err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, response.NewPage(users, total, req.PageQuery))
|
||||
}
|
||||
|
||||
type disableReq struct {
|
||||
Disabled bool `json:"disabled"`
|
||||
}
|
||||
|
||||
// AdminSetUserDisabled PUT /api/admin/users/:id/disabled
|
||||
func (h *Handler) AdminSetUserDisabled(c *gin.Context) {
|
||||
var req disableReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailParams(c, err.Error())
|
||||
return
|
||||
}
|
||||
if err := h.svc.SetUserDisabled(uintParam(c, "id"), req.Disabled); err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// AdminListPets GET /api/admin/pets
|
||||
func (h *Handler) AdminListPets(c *gin.Context) {
|
||||
var req adminListReq
|
||||
_ = c.ShouldBindQuery(&req)
|
||||
req.Normalize()
|
||||
pets, total, err := h.svc.ListPetsAdmin(req.Offset(), req.Limit())
|
||||
if err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, response.NewPage(pets, total, req.PageQuery))
|
||||
}
|
||||
|
||||
// AdminListPosts GET /api/admin/posts
|
||||
func (h *Handler) AdminListPosts(c *gin.Context) {
|
||||
var req adminListReq
|
||||
_ = c.ShouldBindQuery(&req)
|
||||
req.Normalize()
|
||||
posts, total, err := h.svc.ListPostsAdmin(req.Status, req.Offset(), req.Limit())
|
||||
if err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, response.NewPage(posts, total, req.PageQuery))
|
||||
}
|
||||
|
||||
type postStatusReq struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// AdminSetPostStatus PUT /api/admin/posts/:id/status
|
||||
func (h *Handler) AdminSetPostStatus(c *gin.Context) {
|
||||
var req postStatusReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailParams(c, err.Error())
|
||||
return
|
||||
}
|
||||
if err := h.svc.SetPostStatus(uintParam(c, "id"), req.Status); err != nil {
|
||||
respondErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// AdminListComments GET /api/admin/comments
|
||||
func (h *Handler) AdminListComments(c *gin.Context) {
|
||||
var req adminListReq
|
||||
_ = c.ShouldBindQuery(&req)
|
||||
req.Normalize()
|
||||
comments, total, err := h.svc.ListCommentsAdmin(req.Offset(), req.Limit())
|
||||
if err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, response.NewPage(comments, total, req.PageQuery))
|
||||
}
|
||||
|
||||
// AdminDeleteComment DELETE /api/admin/comments/:id
|
||||
func (h *Handler) AdminDeleteComment(c *gin.Context) {
|
||||
if err := h.svc.DeleteCommentAdmin(uintParam(c, "id")); err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// AdminListArticles GET /api/admin/articles
|
||||
func (h *Handler) AdminListArticles(c *gin.Context) {
|
||||
var req adminListReq
|
||||
_ = c.ShouldBindQuery(&req)
|
||||
req.Normalize()
|
||||
articles, total, err := h.svc.ListArticlesAdmin(req.Offset(), req.Limit())
|
||||
if err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, response.NewPage(articles, total, req.PageQuery))
|
||||
}
|
||||
|
||||
type articleReq struct {
|
||||
ID uint `json:"id"`
|
||||
Icon string `json:"icon"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Content string `json:"content"`
|
||||
Category string `json:"category"`
|
||||
RelatedSheetType string `json:"related_sheet_type"`
|
||||
Published bool `json:"published"`
|
||||
}
|
||||
|
||||
// AdminSaveArticle POST /api/admin/articles(id>0 为更新)
|
||||
func (h *Handler) AdminSaveArticle(c *gin.Context) {
|
||||
var req articleReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailParams(c, err.Error())
|
||||
return
|
||||
}
|
||||
article := &model.Article{
|
||||
Icon: req.Icon, Title: req.Title, Description: req.Description, Content: req.Content,
|
||||
Category: req.Category, RelatedSheetType: req.RelatedSheetType, Published: req.Published,
|
||||
}
|
||||
article.ID = req.ID
|
||||
if err := h.svc.SaveArticle(article); err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, article)
|
||||
}
|
||||
|
||||
// AdminDeleteArticle DELETE /api/admin/articles/:id
|
||||
func (h *Handler) AdminDeleteArticle(c *gin.Context) {
|
||||
if err := h.svc.DeleteArticle(uintParam(c, "id")); err != nil {
|
||||
respondErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// AdminListPro GET /api/admin/memberships
|
||||
func (h *Handler) AdminListPro(c *gin.Context) {
|
||||
var req adminListReq
|
||||
_ = c.ShouldBindQuery(&req)
|
||||
req.Normalize()
|
||||
list, total, err := h.svc.ListProAdmin(req.Offset(), req.Limit())
|
||||
if err != nil {
|
||||
response.FailErr(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, response.NewPage(list, total, req.PageQuery))
|
||||
}
|
||||
Reference in New Issue
Block a user