first commit
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AdminHandler 管理员账号相关接口。
|
||||
type AdminHandler struct {
|
||||
svc *service.AdminService
|
||||
}
|
||||
|
||||
// NewAdminHandler 创建管理员 handler。
|
||||
func NewAdminHandler() *AdminHandler {
|
||||
return &AdminHandler{svc: service.NewAdminService()}
|
||||
}
|
||||
|
||||
// Login 管理员登录(公开)。
|
||||
func (h *AdminHandler) Login(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.AdminLoginRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Login(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// RefreshToken 刷新 token(公开)。
|
||||
func (h *AdminHandler) RefreshToken(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.AdminRefreshTokenRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.RefreshToken(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Logout 登出(需鉴权)。
|
||||
func (h *AdminHandler) Logout(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request struct {
|
||||
RefreshToken string `json:"refresh_token" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
accessToken := bearerToken(c)
|
||||
if e := h.svc.Logout(c.Request.Context(), accessToken, request.RefreshToken); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// ChangePassword 修改自己密码(需鉴权)。
|
||||
func (h *AdminHandler) ChangePassword(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.AdminChangePasswordRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, ok := middleware.GetAdminID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
if e := h.svc.ChangePassword(c.Request.Context(), adminID, &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// List 管理员列表(仅超级管理员)。
|
||||
func (h *AdminHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.AdminListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Create 创建管理员(仅超级管理员)。
|
||||
func (h *AdminHandler) Create(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.AdminCreateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Create(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Update 更新管理员(仅超级管理员)。
|
||||
func (h *AdminHandler) Update(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails("非法管理员 ID"))
|
||||
return
|
||||
}
|
||||
var request dto.AdminUpdateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, ok := middleware.GetAdminID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
if e := h.svc.Update(c.Request.Context(), adminID, id, &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// Delete 删除管理员(仅超级管理员)。
|
||||
func (h *AdminHandler) Delete(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails("非法管理员 ID"))
|
||||
return
|
||||
}
|
||||
adminID, ok := middleware.GetAdminID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
if e := h.svc.Delete(c.Request.Context(), adminID, id); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// bearerToken 从 Authorization 头提取裸 token。
|
||||
func bearerToken(c *gin.Context) string {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(parts) == 2 && parts[0] == "Bearer" {
|
||||
return parts[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ContentHandler 内容审核接口(穿搭/衣物/分享)。
|
||||
type ContentHandler struct {
|
||||
svc *service.ContentService
|
||||
}
|
||||
|
||||
// NewContentHandler 创建内容审核 handler。
|
||||
func NewContentHandler() *ContentHandler {
|
||||
return &ContentHandler{svc: service.NewContentService()}
|
||||
}
|
||||
|
||||
// OutfitList 穿搭列表。
|
||||
func (h *ContentHandler) OutfitList(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.OutfitListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.OutfitList(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// OutfitDetail 穿搭详情。
|
||||
func (h *ContentHandler) OutfitDetail(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
out, e := h.svc.OutfitDetail(c.Request.Context(), c.Param("uuid"))
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// OutfitAudit 穿搭审核(通过/驳回)。
|
||||
func (h *ContentHandler) OutfitAudit(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.OutfitAuditRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.OutfitAudit(c.Request.Context(), adminID, c.Param("uuid"), &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// OutfitBan 封禁穿搭。
|
||||
func (h *ContentHandler) OutfitBan(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.OutfitBanRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.OutfitBan(c.Request.Context(), adminID, c.Param("uuid"), &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// OutfitUnban 解封穿搭。
|
||||
func (h *ContentHandler) OutfitUnban(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.OutfitUnban(c.Request.Context(), adminID, c.Param("uuid")); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// ClothesList 衣物列表。
|
||||
func (h *ContentHandler) ClothesList(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.ClothesListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.ClothesList(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// ClothesDetail 衣物详情。
|
||||
func (h *ContentHandler) ClothesDetail(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
out, e := h.svc.ClothesDetail(c.Request.Context(), c.Param("uuid"))
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// ShareList 衣柜分享列表。
|
||||
func (h *ContentHandler) ShareList(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.ClosetShareListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.ShareList(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// ShareBan 封禁分享。
|
||||
func (h *ContentHandler) ShareBan(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.ShareBan(c.Request.Context(), adminID, c.Param("uuid")); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// ShareUnban 解封分享。
|
||||
func (h *ContentHandler) ShareUnban(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.ShareUnban(c.Request.Context(), adminID, c.Param("uuid")); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DashboardHandler 仪表盘统计接口。
|
||||
type DashboardHandler struct {
|
||||
svc *service.DashboardService
|
||||
}
|
||||
|
||||
// NewDashboardHandler 创建仪表盘 handler。
|
||||
func NewDashboardHandler() *DashboardHandler {
|
||||
return &DashboardHandler{svc: service.NewDashboardService()}
|
||||
}
|
||||
|
||||
// Summary 仪表盘核心指标。
|
||||
func (h *DashboardHandler) Summary(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
out, e := h.svc.Summary(c.Request.Context())
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Trend 近 N 天趋势。
|
||||
func (h *DashboardHandler) Trend(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.TrendRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Trends(c.Request.Context(), request.Days)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// GoodsHandler 商品管理接口。
|
||||
type GoodsHandler struct {
|
||||
svc *service.GoodsService
|
||||
}
|
||||
|
||||
// NewGoodsHandler 创建商品 handler。
|
||||
func NewGoodsHandler() *GoodsHandler {
|
||||
return &GoodsHandler{svc: service.NewGoodsService()}
|
||||
}
|
||||
|
||||
// List 商品列表(含下架)。
|
||||
func (h *GoodsHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.GoodsListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Create 创建商品。
|
||||
func (h *GoodsHandler) Create(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.GoodsCreateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
out, e := h.svc.Create(c.Request.Context(), adminID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Update 更新商品。
|
||||
func (h *GoodsHandler) Update(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails("非法商品 ID"))
|
||||
return
|
||||
}
|
||||
var request dto.GoodsUpdateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.Update(c.Request.Context(), adminID, id, &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// UpdateStatus 商品上下架。
|
||||
func (h *GoodsHandler) UpdateStatus(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails("非法商品 ID"))
|
||||
return
|
||||
}
|
||||
var request dto.GoodsStatusRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.UpdateStatus(c.Request.Context(), adminID, id, &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// Delete 软删除商品。
|
||||
func (h *GoodsHandler) Delete(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails("非法商品 ID"))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.Delete(c.Request.Context(), adminID, id); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// NotificationHandler 通知推送接口。
|
||||
type NotificationHandler struct {
|
||||
svc *service.NotificationService
|
||||
}
|
||||
|
||||
// NewNotificationHandler 创建通知 handler。
|
||||
func NewNotificationHandler() *NotificationHandler {
|
||||
return &NotificationHandler{svc: service.NewNotificationService()}
|
||||
}
|
||||
|
||||
// Send 向单个用户发送系统通知。
|
||||
func (h *NotificationHandler) Send(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.NotificationSendRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.Send(c.Request.Context(), adminID, &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// Broadcast 全量广播系统通知。
|
||||
func (h *NotificationHandler) Broadcast(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.NotificationBroadcastRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
out, e := h.svc.Broadcast(c.Request.Context(), adminID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// OrderHandler 订单与退款管理接口。
|
||||
type OrderHandler struct {
|
||||
svc *service.OrderService
|
||||
}
|
||||
|
||||
// NewOrderHandler 创建订单 handler。
|
||||
func NewOrderHandler() *OrderHandler {
|
||||
return &OrderHandler{svc: service.NewOrderService()}
|
||||
}
|
||||
|
||||
// List 订单列表。
|
||||
func (h *OrderHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.OrderListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Get 订单详情。
|
||||
func (h *OrderHandler) Get(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
out, e := h.svc.Get(c.Request.Context(), c.Param("orderNo"))
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// RefundList 退款单列表。
|
||||
func (h *OrderHandler) RefundList(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.RefundListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.RefundList(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// RefundApprove 退款审核通过。
|
||||
func (h *OrderHandler) RefundApprove(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.RefundAuditRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.RefundApprove(c.Request.Context(), adminID, c.Param("refundNo"), &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// RefundReject 退款审核驳回。
|
||||
func (h *OrderHandler) RefundReject(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.RefundAuditRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.RefundReject(c.Request.Context(), adminID, c.Param("refundNo"), &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// UserHandler 用户管理接口。
|
||||
type UserHandler struct {
|
||||
svc *service.UserService
|
||||
}
|
||||
|
||||
// NewUserHandler 创建用户管理 handler。
|
||||
func NewUserHandler() *UserHandler {
|
||||
return &UserHandler{svc: service.NewUserService()}
|
||||
}
|
||||
|
||||
// List 用户分页列表。
|
||||
func (h *UserHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.UserListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Detail 用户详情(含四类额度)。
|
||||
func (h *UserHandler) Detail(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
out, e := h.svc.Detail(c.Request.Context(), c.Param("uuid"))
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Ban 封禁用户。
|
||||
func (h *UserHandler) Ban(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.UserBanRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.Ban(c.Request.Context(), adminID, c.Param("uuid"), &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// Unban 解封用户。
|
||||
func (h *UserHandler) Unban(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.UserUnbanRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.Unban(c.Request.Context(), adminID, c.Param("uuid"), &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// QuotaAdjust 额度发放(有有效期额度凭证)。
|
||||
func (h *UserHandler) QuotaAdjust(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.UserQuotaAdjustRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.QuotaAdjust(c.Request.Context(), adminID, c.Param("uuid"), &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// VIPAdjust 会员人工调整。
|
||||
func (h *UserHandler) VIPAdjust(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.UserVIPAdjustRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.VIPAdjust(c.Request.Context(), adminID, c.Param("uuid"), &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
|
||||
// GrantRevoke 回收额度凭证。
|
||||
func (h *UserHandler) GrantRevoke(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
grantID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil || grantID <= 0 {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails("非法凭证 ID"))
|
||||
return
|
||||
}
|
||||
adminID, _ := middleware.GetAdminID(c.Request.Context())
|
||||
if e := h.svc.GrantRevoke(c.Request.Context(), adminID, c.Param("uuid"), grantID); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/middleware"
|
||||
v1 "git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/routers/api/v1"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// NewRouter 构建 gin 引擎:注册中间件链与 /api/v1 路由。
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.New()
|
||||
|
||||
// 中间件链:Recovery -> RequestID -> OTel -> Slog -> CORS
|
||||
r.Use(
|
||||
gin.Recovery(),
|
||||
middleware.RequestID(),
|
||||
middleware.GinOTelMiddleware(),
|
||||
middleware.GinSlogMiddleware(),
|
||||
middleware.CORS(),
|
||||
)
|
||||
|
||||
// 健康检查
|
||||
r.GET("/ping", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "pong"})
|
||||
})
|
||||
|
||||
// handler 实例
|
||||
adminHandler := v1.NewAdminHandler()
|
||||
dashboardHandler := v1.NewDashboardHandler()
|
||||
userHandler := v1.NewUserHandler()
|
||||
goodsHandler := v1.NewGoodsHandler()
|
||||
orderHandler := v1.NewOrderHandler()
|
||||
contentHandler := v1.NewContentHandler()
|
||||
notificationHandler := v1.NewNotificationHandler()
|
||||
|
||||
apiV1 := r.Group("/api/v1")
|
||||
|
||||
// ===== 公开路由(无需登录)=====
|
||||
{
|
||||
apiV1.POST("/admin/login", adminHandler.Login)
|
||||
apiV1.POST("/admin/refresh-token", adminHandler.RefreshToken)
|
||||
}
|
||||
|
||||
// ===== 鉴权路由(需登录)=====
|
||||
auth := apiV1.Group("")
|
||||
auth.Use(middleware.JWTAuth())
|
||||
{
|
||||
// 管理员(自己)
|
||||
auth.POST("/admin/logout", adminHandler.Logout)
|
||||
auth.PUT("/admin/password", adminHandler.ChangePassword)
|
||||
|
||||
// 仪表盘
|
||||
auth.GET("/dashboard/summary", dashboardHandler.Summary)
|
||||
auth.GET("/dashboard/trends", dashboardHandler.Trend)
|
||||
|
||||
// 用户管理
|
||||
auth.GET("/users", userHandler.List)
|
||||
auth.GET("/users/:uuid", userHandler.Detail)
|
||||
auth.PUT("/users/:uuid/ban", userHandler.Ban)
|
||||
auth.PUT("/users/:uuid/unban", userHandler.Unban)
|
||||
auth.PUT("/users/:uuid/quota", userHandler.QuotaAdjust)
|
||||
auth.PUT("/users/:uuid/vip", userHandler.VIPAdjust)
|
||||
auth.DELETE("/users/:uuid/grants/:id", userHandler.GrantRevoke)
|
||||
|
||||
// 商品管理
|
||||
auth.GET("/goods", goodsHandler.List)
|
||||
auth.POST("/goods", goodsHandler.Create)
|
||||
auth.PUT("/goods/:id", goodsHandler.Update)
|
||||
auth.PUT("/goods/:id/status", goodsHandler.UpdateStatus)
|
||||
auth.DELETE("/goods/:id", goodsHandler.Delete)
|
||||
|
||||
// 订单与退款
|
||||
auth.GET("/orders", orderHandler.List)
|
||||
auth.GET("/orders/:orderNo", orderHandler.Get)
|
||||
auth.GET("/refunds", orderHandler.RefundList)
|
||||
auth.POST("/refunds/:refundNo/approve", orderHandler.RefundApprove)
|
||||
auth.POST("/refunds/:refundNo/reject", orderHandler.RefundReject)
|
||||
|
||||
// 内容审核
|
||||
auth.GET("/outfits", contentHandler.OutfitList)
|
||||
auth.GET("/outfits/:uuid", contentHandler.OutfitDetail)
|
||||
auth.POST("/outfits/:uuid/audit", contentHandler.OutfitAudit)
|
||||
auth.POST("/outfits/:uuid/ban", contentHandler.OutfitBan)
|
||||
auth.POST("/outfits/:uuid/unban", contentHandler.OutfitUnban)
|
||||
auth.GET("/clothes", contentHandler.ClothesList)
|
||||
auth.GET("/clothes/:uuid", contentHandler.ClothesDetail)
|
||||
auth.GET("/closet-shares", contentHandler.ShareList)
|
||||
auth.POST("/closet-shares/:uuid/ban", contentHandler.ShareBan)
|
||||
auth.POST("/closet-shares/:uuid/unban", contentHandler.ShareUnban)
|
||||
|
||||
// 通知推送
|
||||
auth.POST("/notifications", notificationHandler.Send)
|
||||
auth.POST("/notifications/broadcast", notificationHandler.Broadcast)
|
||||
}
|
||||
|
||||
// ===== 超管专属路由 =====
|
||||
super := apiV1.Group("")
|
||||
super.Use(middleware.JWTAuth(), middleware.AdminSuperAuth())
|
||||
{
|
||||
super.GET("/admins", adminHandler.List)
|
||||
super.POST("/admins", adminHandler.Create)
|
||||
super.PUT("/admins/:id", adminHandler.Update)
|
||||
super.DELETE("/admins/:id", adminHandler.Delete)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
Reference in New Issue
Block a user