first commit
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AdRewardHandler 广告激励额度接口。
|
||||
type AdRewardHandler struct {
|
||||
svc *service.AdRewardService
|
||||
}
|
||||
|
||||
// NewAdRewardHandler 创建广告激励 handler。
|
||||
func NewAdRewardHandler() *AdRewardHandler {
|
||||
return &AdRewardHandler{svc: service.NewAdRewardService()}
|
||||
}
|
||||
|
||||
// Grant 发放广告激励额度(当天有效,幂等防重复领取)。
|
||||
func (h *AdRewardHandler) Grant(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.AdRewardGrantRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Grant(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AIRecommendHandler AI 穿搭推荐相关接口。
|
||||
type AIRecommendHandler struct {
|
||||
svc *service.AIRecommendService
|
||||
}
|
||||
|
||||
// NewAIRecommendHandler 创建 AI 推荐 handler。
|
||||
func NewAIRecommendHandler() *AIRecommendHandler {
|
||||
return &AIRecommendHandler{svc: service.NewAIRecommendService()}
|
||||
}
|
||||
|
||||
// Create 发起 AI 穿搭推荐。
|
||||
func (h *AIRecommendHandler) Create(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.AIRecommendCreateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Create(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Save 保存 AI 推荐穿搭到我的搭配。
|
||||
func (h *AIRecommendHandler) Save(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.AIRecommendSaveRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
if e := h.svc.Save(c.Request.Context(), userID, &request); e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(nil)
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ClosetShareHandler 衣柜分享相关接口。
|
||||
type ClosetShareHandler struct {
|
||||
svc *service.ClosetShareService
|
||||
}
|
||||
|
||||
// NewClosetShareHandler 创建衣柜分享 handler。
|
||||
func NewClosetShareHandler() *ClosetShareHandler {
|
||||
return &ClosetShareHandler{svc: service.NewClosetShareService()}
|
||||
}
|
||||
|
||||
// Create 创建衣柜分享。
|
||||
func (h *ClosetShareHandler) Create(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.ClosetShareCreateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Create(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// List 分页查询我的分享。
|
||||
func (h *ClosetShareHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.ClosetShareListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// ReceivedList 分页查询分享给我的分享。
|
||||
func (h *ClosetShareHandler) ReceivedList(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.ClosetShareListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.ListReceived(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Detail 查看分享详情(uuid 来自路径参数)。
|
||||
func (h *ClosetShareHandler) Detail(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
shareUUID := c.Param("uuid")
|
||||
if shareUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Detail(c.Request.Context(), userID, shareUUID)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Cancel 取消分享(uuid 来自路径参数)。
|
||||
func (h *ClosetShareHandler) Cancel(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.ClosetShareCancelRequest{ShareUUID: c.Param("uuid")}
|
||||
if request.ShareUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Cancel(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/global"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ClothesHandler 衣物相关接口。
|
||||
type ClothesHandler struct {
|
||||
svc *service.ClothesService
|
||||
}
|
||||
|
||||
// NewClothesHandler 创建衣物 handler。
|
||||
func NewClothesHandler() *ClothesHandler {
|
||||
return &ClothesHandler{svc: service.NewClothesService()}
|
||||
}
|
||||
|
||||
// Upload 上传衣物图片(multipart,字段名 file)。
|
||||
func (h *ClothesHandler) Upload(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
// 解析 multipart 前限制请求体大小(MaxSizeMB + 1MB 的 multipart 边界开销),
|
||||
// 防止超大 body 在 FormFile 解析时耗尽内存/磁盘。
|
||||
maxBytes := int64(global.UploadSetting.MaxSizeMB)*1024*1024 + 1024*1024
|
||||
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxBytes)
|
||||
fileHeader, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
response.ToErrorResponse(errcode.UploadFileEmpty.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Upload(c.Request.Context(), userID, fileHeader)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// List 分页查询当前用户衣物。
|
||||
func (h *ClothesHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.ClothesListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Get 获取衣物详情(uuid 来自路径参数)。
|
||||
func (h *ClothesHandler) Get(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.ClothesGetByUUIDRequest{ClothesUUID: c.Param("uuid")}
|
||||
if request.ClothesUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.GetByUUID(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Status 查询衣物图片处理状态(uuid 来自路径参数)。
|
||||
func (h *ClothesHandler) Status(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.ClothesProcessStatusGetByUUIDRequest{ClothesUUID: c.Param("uuid")}
|
||||
if request.ClothesUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.ProcessStatusGetByUUID(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Update 修改衣物属性(uuid 来自路径参数)。
|
||||
func (h *ClothesHandler) Update(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.ClothesUpdateByUUIDRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
request.ClothesUUID = c.Param("uuid")
|
||||
if request.ClothesUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.UpdateByUUID(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Delete 删除衣物(uuid 来自路径参数)。
|
||||
func (h *ClothesHandler) Delete(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.ClothesDeleteByUUIDRequest{ClothesUUID: c.Param("uuid")}
|
||||
if request.ClothesUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.DeleteByUUID(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CollectHandler 收藏相关接口。
|
||||
type CollectHandler struct {
|
||||
svc *service.CollectService
|
||||
}
|
||||
|
||||
// NewCollectHandler 创建收藏 handler。
|
||||
func NewCollectHandler() *CollectHandler {
|
||||
return &CollectHandler{svc: service.NewCollectService()}
|
||||
}
|
||||
|
||||
// Collect 收藏/取消收藏社区穿搭。
|
||||
func (h *CollectHandler) Collect(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.CollectRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Collect(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// List 分页查询我收藏的穿搭。
|
||||
func (h *CollectHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.CollectListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// GetByTarget 查询穿搭收藏状态与数量(targetUUID 来自路径参数)。
|
||||
func (h *CollectHandler) GetByTarget(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.CollectGetByTargetRequest{TargetUUID: c.Param("targetUUID")}
|
||||
if request.TargetUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.GetByTarget(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-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()}
|
||||
}
|
||||
|
||||
// GetByCode 按商品编码查询商品(编码来自路径参数)。
|
||||
func (h *GoodsHandler) GetByCode(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
request := dto.GoodsGetByCodeRequest{GoodsCode: c.Param("code")}
|
||||
if request.GoodsCode == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.GetByCode(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// HoroscopeHandler 今日运势接口。
|
||||
type HoroscopeHandler struct {
|
||||
svc *service.HoroscopeService
|
||||
}
|
||||
|
||||
// NewHoroscopeHandler 创建运势 handler。
|
||||
func NewHoroscopeHandler() *HoroscopeHandler {
|
||||
return &HoroscopeHandler{svc: service.NewHoroscopeService()}
|
||||
}
|
||||
|
||||
// Today 获取当前用户今日运势。
|
||||
func (h *HoroscopeHandler) Today(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.GetToday(c.Request.Context(), userID)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// LikeHandler 点赞相关接口。
|
||||
type LikeHandler struct {
|
||||
svc *service.LikeService
|
||||
}
|
||||
|
||||
// NewLikeHandler 创建点赞 handler。
|
||||
func NewLikeHandler() *LikeHandler {
|
||||
return &LikeHandler{svc: service.NewLikeService()}
|
||||
}
|
||||
|
||||
// Like 点赞/取消点赞社区穿搭。
|
||||
func (h *LikeHandler) Like(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.LikeCreateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.LikeCreate(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// GetByTarget 查询穿搭点赞状态与数量(targetUUID 来自路径参数)。
|
||||
func (h *LikeHandler) GetByTarget(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.LikeGetByTargetIDRequest{TargetUUID: c.Param("targetUUID")}
|
||||
if request.TargetUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.GetByTargetID(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-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()}
|
||||
}
|
||||
|
||||
// List 分页查询当前用户通知。
|
||||
func (h *NotificationHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.NotificationListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Unread 获取当前用户未读数。
|
||||
func (h *NotificationHandler) Unread(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Unread(c.Request.Context(), userID)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Get 获取通知详情(uuid 来自路径参数)。
|
||||
func (h *NotificationHandler) Get(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.NotificationGetByUUIDRequest{NotificationUUID: c.Param("uuid")}
|
||||
if request.NotificationUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.GetByUUID(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Read 标记通知已读(uuid 来自路径参数)。
|
||||
func (h *NotificationHandler) Read(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.NotificationReadRequest{NotificationUUID: c.Param("uuid")}
|
||||
if request.NotificationUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Read(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/wechat"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// OrderHandler 订单与退款相关接口。
|
||||
type OrderHandler struct {
|
||||
svc *service.OrderService
|
||||
}
|
||||
|
||||
// NewOrderHandler 创建订单 handler。
|
||||
func NewOrderHandler() *OrderHandler {
|
||||
return &OrderHandler{svc: service.NewOrderService()}
|
||||
}
|
||||
|
||||
// Create 创建订单并发起微信下单。
|
||||
func (h *OrderHandler) Create(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.OrderCreateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Create(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// VirtualCreate 创建虚拟支付订单(小程序虚拟支付,覆盖 iOS/Android 全终端)。
|
||||
func (h *OrderHandler) VirtualCreate(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.VirtualOrderCreateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.VirtualOrderCreate(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// List 分页查询我的订单。
|
||||
func (h *OrderHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
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(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Cancel 取消订单(orderNo 来自路径参数)。
|
||||
func (h *OrderHandler) Cancel(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.OrderCancelRequest{OrderNo: c.Param("orderNo")}
|
||||
if request.OrderNo == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Cancel(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// RefundApply 申请退款。
|
||||
func (h *OrderHandler) RefundApply(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.RefundApplyRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.RefundApply(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// PayNotify 微信支付结果回调(公开,按微信规范返回受理结果)。
|
||||
func (h *OrderHandler) PayNotify(c *gin.Context) {
|
||||
if e := h.svc.PayNotify(c.Request.Context(), c.Request); e != nil {
|
||||
wechatCallbackFail(c, e.Msg())
|
||||
return
|
||||
}
|
||||
wechatCallbackSuccess(c)
|
||||
}
|
||||
|
||||
// RefundNotify 微信退款结果回调(公开,按微信规范返回受理结果)。
|
||||
func (h *OrderHandler) RefundNotify(c *gin.Context) {
|
||||
if e := h.svc.RefundNotify(c.Request.Context(), c.Request); e != nil {
|
||||
wechatCallbackFail(c, e.Msg())
|
||||
return
|
||||
}
|
||||
wechatCallbackSuccess(c)
|
||||
}
|
||||
|
||||
// XPayVerify 虚拟支付消息推送 URL 配置验证(GET):校验签名并原样回显 echostr。
|
||||
func (h *OrderHandler) XPayVerify(c *gin.Context) {
|
||||
timestamp := c.Query("timestamp")
|
||||
nonce := c.Query("nonce")
|
||||
signature := c.Query("signature")
|
||||
echostr := c.Query("echostr")
|
||||
if wechat.VerifyNotifyURL(timestamp, nonce, signature) {
|
||||
c.String(http.StatusOK, echostr)
|
||||
return
|
||||
}
|
||||
c.String(http.StatusUnauthorized, "invalid signature")
|
||||
}
|
||||
|
||||
// XPayNotify 虚拟支付消息推送回调(POST,公开,按虚拟支付规范返回 ErrCode 应答)。
|
||||
func (h *OrderHandler) XPayNotify(c *gin.Context) {
|
||||
raw, err := io.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
c.Data(http.StatusOK, "application/json; charset=utf-8", wechat.BuildNotifyResponse(false))
|
||||
return
|
||||
}
|
||||
resp := h.svc.XPayNotify(c.Request.Context(), raw)
|
||||
c.Data(http.StatusOK, "application/json; charset=utf-8", resp)
|
||||
}
|
||||
|
||||
// wechatCallbackSuccess 按微信规范返回受理成功,避免微信重复回调。
|
||||
func wechatCallbackSuccess(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"code": "SUCCESS", "message": "成功"})
|
||||
}
|
||||
|
||||
// wechatCallbackFail 按微信规范返回受理失败,微信将按策略重试。
|
||||
func wechatCallbackFail(c *gin.Context, message string) {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"code": "FAIL", "message": message})
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// OutfitHandler 穿搭相关接口。
|
||||
type OutfitHandler struct {
|
||||
svc *service.OutfitService
|
||||
}
|
||||
|
||||
// NewOutfitHandler 创建穿搭 handler。
|
||||
func NewOutfitHandler() *OutfitHandler {
|
||||
return &OutfitHandler{svc: service.NewOutfitService()}
|
||||
}
|
||||
|
||||
// Create 创建穿搭。
|
||||
func (h *OutfitHandler) Create(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.OutfitCreateRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Create(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// List 分页查询我的穿搭。
|
||||
func (h *OutfitHandler) List(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.OutfitListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.List(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Get 获取穿搭详情(uuid 来自路径参数)。
|
||||
func (h *OutfitHandler) Get(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.OutfitGetByUUIDRequest{OutfitUUID: c.Param("uuid")}
|
||||
if request.OutfitUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.GetByUUID(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Update 修改穿搭(uuid 来自路径参数)。
|
||||
func (h *OutfitHandler) Update(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.OutfitUpdateByUUIDRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
request.OutfitUUID = c.Param("uuid")
|
||||
if request.OutfitUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.UpdateByUUID(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Delete 删除穿搭(uuid 来自路径参数)。
|
||||
func (h *OutfitHandler) Delete(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
request := dto.OutfitDeleteRequest{OutfitUUID: c.Param("uuid")}
|
||||
if request.OutfitUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Delete(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// Public 设置穿搭公开状态(uuid 来自路径参数)。
|
||||
func (h *OutfitHandler) Public(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.OutfitPublicRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
request.OutfitUUID = c.Param("uuid")
|
||||
if request.OutfitUUID == "" {
|
||||
response.ToErrorResponse(errcode.InvalidParams)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.Public(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// QuotaHandler 额度相关接口。
|
||||
type QuotaHandler struct {
|
||||
svc *service.QuotaService
|
||||
}
|
||||
|
||||
// NewQuotaHandler 创建额度 handler。
|
||||
func NewQuotaHandler() *QuotaHandler {
|
||||
return &QuotaHandler{svc: service.NewQuotaService()}
|
||||
}
|
||||
|
||||
// Info 获取当前用户额度概览。
|
||||
func (h *QuotaHandler) Info(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.InfoGetBySelf(c.Request.Context(), userID)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// FlowList 分页查询当前用户额度流水。
|
||||
func (h *QuotaHandler) FlowList(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.QuotaFlowListRequest
|
||||
if err := c.ShouldBindQuery(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.FlowList(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// Package v1 提供 /api/v1 版本的 HTTP handler,负责请求绑定、鉴权透传与统一响应,
|
||||
// 业务逻辑与归属校验均在 internal/service 层完成。
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/global"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/service"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/app"
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-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()}
|
||||
}
|
||||
|
||||
// WxLogin 微信登录(公开)。
|
||||
func (h *UserHandler) WxLogin(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.UserWxLoginRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.WxLogin(c.Request.Context(), &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// RefreshToken 刷新访问令牌(公开)。
|
||||
func (h *UserHandler) RefreshToken(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
var request dto.UserRefreshTokenRequest
|
||||
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)
|
||||
}
|
||||
|
||||
// InfoGetBySelf 获取当前用户信息。
|
||||
func (h *UserHandler) InfoGetBySelf(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
out, e := h.svc.InfoGetBySelf(c.Request.Context(), userID)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// ProfileUpdate 修改当前用户资料。
|
||||
func (h *UserHandler) ProfileUpdate(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
var request dto.UserProfileUpdateBySelfRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
response.ToErrorResponse(errcode.InvalidParams.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.ProfileUpdate(c.Request.Context(), userID, &request)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
|
||||
// AvatarUpload 上传用户头像(multipart,字段名 file)。
|
||||
func (h *UserHandler) AvatarUpload(c *gin.Context) {
|
||||
response := app.NewResponse(c)
|
||||
userID, ok := middleware.GetUserID(c.Request.Context())
|
||||
if !ok {
|
||||
response.ToErrorResponse(errcode.Unauthorized)
|
||||
return
|
||||
}
|
||||
// 解析 multipart 前限制请求体大小(MaxSizeMB + 1MB 的 multipart 边界开销),
|
||||
// 防止超大 body 在 FormFile 解析时耗尽内存/磁盘。
|
||||
maxBytes := int64(global.UploadSetting.MaxSizeMB)*1024*1024 + 1024*1024
|
||||
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxBytes)
|
||||
fileHeader, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
response.ToErrorResponse(errcode.UploadFileEmpty.WithDetails(err.Error()))
|
||||
return
|
||||
}
|
||||
out, e := h.svc.AvatarUpload(c.Request.Context(), userID, fileHeader)
|
||||
if e != nil {
|
||||
response.ToErrorResponse(e)
|
||||
return
|
||||
}
|
||||
response.ToResponse(out)
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/middleware"
|
||||
v1 "git.lzcwy.cn/zhengchiliu/zt-closet-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 实例
|
||||
userHandler := v1.NewUserHandler()
|
||||
quotaHandler := v1.NewQuotaHandler()
|
||||
horoscopeHandler := v1.NewHoroscopeHandler()
|
||||
clothesHandler := v1.NewClothesHandler()
|
||||
outfitHandler := v1.NewOutfitHandler()
|
||||
closetHandler := v1.NewClosetShareHandler()
|
||||
collectHandler := v1.NewCollectHandler()
|
||||
likeHandler := v1.NewLikeHandler()
|
||||
notificationHandler := v1.NewNotificationHandler()
|
||||
goodsHandler := v1.NewGoodsHandler()
|
||||
orderHandler := v1.NewOrderHandler()
|
||||
aiHandler := v1.NewAIRecommendHandler()
|
||||
adRewardHandler := v1.NewAdRewardHandler()
|
||||
|
||||
apiV1 := r.Group("/api/v1")
|
||||
|
||||
// ===== 公开路由(无需登录)=====
|
||||
{
|
||||
apiV1.POST("/user/wxlogin", userHandler.WxLogin)
|
||||
apiV1.POST("/user/refresh-token", userHandler.RefreshToken)
|
||||
|
||||
apiV1.GET("/goods", goodsHandler.List)
|
||||
apiV1.GET("/goods/:code", goodsHandler.GetByCode)
|
||||
|
||||
// 微信支付/退款回调
|
||||
apiV1.POST("/order/pay/notify", orderHandler.PayNotify)
|
||||
apiV1.POST("/order/refund/notify", orderHandler.RefundNotify)
|
||||
|
||||
// 虚拟支付消息推送(GET 为 URL 配置验证,POST 为业务回调)
|
||||
apiV1.GET("/xpay/notify", orderHandler.XPayVerify)
|
||||
apiV1.POST("/xpay/notify", orderHandler.XPayNotify)
|
||||
}
|
||||
|
||||
// ===== 鉴权路由(需登录)=====
|
||||
auth := apiV1.Group("")
|
||||
auth.Use(middleware.JWTAuth())
|
||||
{
|
||||
// 用户
|
||||
auth.GET("/user/info", userHandler.InfoGetBySelf)
|
||||
auth.PUT("/user/profile", userHandler.ProfileUpdate)
|
||||
auth.POST("/user/avatar/upload", userHandler.AvatarUpload)
|
||||
|
||||
// 额度
|
||||
auth.GET("/quota/info", quotaHandler.Info)
|
||||
auth.GET("/quota/flow", quotaHandler.FlowList)
|
||||
|
||||
// 运势
|
||||
auth.GET("/horoscope/today", horoscopeHandler.Today)
|
||||
|
||||
// 衣物
|
||||
auth.POST("/clothes/upload", clothesHandler.Upload)
|
||||
auth.GET("/clothes", clothesHandler.List)
|
||||
auth.GET("/clothes/:uuid", clothesHandler.Get)
|
||||
auth.GET("/clothes/:uuid/status", clothesHandler.Status)
|
||||
auth.PUT("/clothes/:uuid", clothesHandler.Update)
|
||||
auth.DELETE("/clothes/:uuid", clothesHandler.Delete)
|
||||
|
||||
// 穿搭
|
||||
auth.POST("/outfit", outfitHandler.Create)
|
||||
auth.GET("/outfit", outfitHandler.List)
|
||||
auth.GET("/outfit/:uuid", outfitHandler.Get)
|
||||
auth.PUT("/outfit/:uuid", outfitHandler.Update)
|
||||
auth.DELETE("/outfit/:uuid", outfitHandler.Delete)
|
||||
auth.PUT("/outfit/:uuid/public", outfitHandler.Public)
|
||||
|
||||
// 衣柜分享
|
||||
auth.POST("/closet-share", closetHandler.Create)
|
||||
auth.GET("/closet-share", closetHandler.List)
|
||||
auth.GET("/closet-share/received", closetHandler.ReceivedList)
|
||||
auth.GET("/closet-share/:uuid", closetHandler.Detail)
|
||||
auth.POST("/closet-share/:uuid/cancel", closetHandler.Cancel)
|
||||
|
||||
// 收藏
|
||||
auth.POST("/collect", collectHandler.Collect)
|
||||
auth.GET("/collect", collectHandler.List)
|
||||
auth.GET("/collect/:targetUUID", collectHandler.GetByTarget)
|
||||
|
||||
// 点赞
|
||||
auth.POST("/like", likeHandler.Like)
|
||||
auth.GET("/like/:targetUUID", likeHandler.GetByTarget)
|
||||
|
||||
// 通知
|
||||
auth.GET("/notification", notificationHandler.List)
|
||||
auth.GET("/notification/unread", notificationHandler.Unread)
|
||||
auth.GET("/notification/:uuid", notificationHandler.Get)
|
||||
auth.POST("/notification/:uuid/read", notificationHandler.Read)
|
||||
|
||||
// 订单
|
||||
auth.POST("/order", orderHandler.Create)
|
||||
auth.POST("/order/virtual", orderHandler.VirtualCreate)
|
||||
auth.GET("/order", orderHandler.List)
|
||||
auth.POST("/order/:orderNo/cancel", orderHandler.Cancel)
|
||||
auth.POST("/order/refund", orderHandler.RefundApply)
|
||||
|
||||
// 广告激励额度
|
||||
auth.POST("/ad-reward/grant", adRewardHandler.Grant)
|
||||
|
||||
// AI 推荐
|
||||
auth.POST("/ai-recommend", aiHandler.Create)
|
||||
auth.POST("/ai-recommend/save", aiHandler.Save)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
Reference in New Issue
Block a user