-feat 修复部分bug
This commit is contained in:
43
internal/handler/health_score_handler.go
Normal file
43
internal/handler/health_score_handler.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"accounting-app/internal/service"
|
||||
"accounting-app/pkg/api"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// HealthScoreHandler handles HTTP requests for health score
|
||||
type HealthScoreHandler struct {
|
||||
healthScoreService *service.HealthScoreService
|
||||
}
|
||||
|
||||
// NewHealthScoreHandler creates a new HealthScoreHandler instance
|
||||
func NewHealthScoreHandler(healthScoreService *service.HealthScoreService) *HealthScoreHandler {
|
||||
return &HealthScoreHandler{
|
||||
healthScoreService: healthScoreService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetHealthScore handles GET /api/v1/reports/health-score
|
||||
// Returns the user's financial health score
|
||||
func (h *HealthScoreHandler) GetHealthScore(c *gin.Context) {
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
api.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.healthScoreService.CalculateHealthScore(userID.(uint))
|
||||
if err != nil {
|
||||
api.InternalError(c, "Failed to calculate health score: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
api.Success(c, result)
|
||||
}
|
||||
|
||||
// RegisterRoutes registers health score route
|
||||
func (h *HealthScoreHandler) RegisterRoutes(rg *gin.RouterGroup) {
|
||||
rg.GET("/reports/health-score", h.GetHealthScore)
|
||||
}
|
||||
198
internal/handler/notification_handler.go
Normal file
198
internal/handler/notification_handler.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"accounting-app/internal/models"
|
||||
"accounting-app/internal/service"
|
||||
"accounting-app/pkg/api"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// NotificationHandler handles HTTP requests for notification operations
|
||||
type NotificationHandler struct {
|
||||
notificationService *service.NotificationService
|
||||
}
|
||||
|
||||
// NewNotificationHandler creates a new NotificationHandler instance
|
||||
func NewNotificationHandler(notificationService *service.NotificationService) *NotificationHandler {
|
||||
return &NotificationHandler{
|
||||
notificationService: notificationService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetNotifications handles GET /api/v1/notifications
|
||||
// Returns a list of notifications with pagination and filtering
|
||||
func (h *NotificationHandler) GetNotifications(c *gin.Context) {
|
||||
// Get user ID from context
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
api.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
input := service.NotificationListInput{}
|
||||
|
||||
// Parse type filter
|
||||
if typeStr := c.Query("type"); typeStr != "" {
|
||||
notifType := models.NotificationType(typeStr)
|
||||
input.Type = ¬ifType
|
||||
}
|
||||
|
||||
// Parse is_read filter
|
||||
if isReadStr := c.Query("is_read"); isReadStr != "" {
|
||||
isRead := isReadStr == "true"
|
||||
input.IsRead = &isRead
|
||||
}
|
||||
|
||||
// Parse pagination
|
||||
if offsetStr := c.Query("offset"); offsetStr != "" {
|
||||
offset, err := strconv.Atoi(offsetStr)
|
||||
if err != nil || offset < 0 {
|
||||
api.BadRequest(c, "Invalid offset")
|
||||
return
|
||||
}
|
||||
input.Offset = offset
|
||||
}
|
||||
|
||||
if limitStr := c.Query("limit"); limitStr != "" {
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil || limit < 0 {
|
||||
api.BadRequest(c, "Invalid limit")
|
||||
return
|
||||
}
|
||||
input.Limit = limit
|
||||
}
|
||||
|
||||
result, err := h.notificationService.ListNotifications(userID.(uint), input)
|
||||
if err != nil {
|
||||
api.InternalError(c, "Failed to get notifications: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate total pages
|
||||
totalPages := 0
|
||||
if result.Limit > 0 {
|
||||
totalPages = int((result.Total + int64(result.Limit) - 1) / int64(result.Limit))
|
||||
}
|
||||
|
||||
// Calculate current page (1-indexed)
|
||||
currentPage := 1
|
||||
if result.Limit > 0 {
|
||||
currentPage = (result.Offset / result.Limit) + 1
|
||||
}
|
||||
|
||||
api.SuccessWithMeta(c, result.Notifications, &api.Meta{
|
||||
Page: currentPage,
|
||||
PageSize: result.Limit,
|
||||
TotalCount: result.Total,
|
||||
TotalPages: totalPages,
|
||||
})
|
||||
}
|
||||
|
||||
// GetUnreadCount handles GET /api/v1/notifications/unread-count
|
||||
// Returns the count of unread notifications
|
||||
func (h *NotificationHandler) GetUnreadCount(c *gin.Context) {
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
api.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
count, err := h.notificationService.GetUnreadCount(userID.(uint))
|
||||
if err != nil {
|
||||
api.InternalError(c, "Failed to get unread count: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
api.Success(c, gin.H{"count": count})
|
||||
}
|
||||
|
||||
// MarkAsRead handles PUT /api/v1/notifications/:id/read
|
||||
// Marks a notification as read
|
||||
func (h *NotificationHandler) MarkAsRead(c *gin.Context) {
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
api.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
api.BadRequest(c, "Invalid notification ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.notificationService.MarkAsRead(userID.(uint), uint(id))
|
||||
if err != nil {
|
||||
if errors.Is(err, service.ErrNotificationNotFound) {
|
||||
api.NotFound(c, "Notification not found")
|
||||
return
|
||||
}
|
||||
api.InternalError(c, "Failed to mark notification as read: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
api.Success(c, gin.H{"message": "Notification marked as read"})
|
||||
}
|
||||
|
||||
// MarkAllAsRead handles POST /api/v1/notifications/read-all
|
||||
// Marks all notifications as read
|
||||
func (h *NotificationHandler) MarkAllAsRead(c *gin.Context) {
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
api.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
err := h.notificationService.MarkAllAsRead(userID.(uint))
|
||||
if err != nil {
|
||||
api.InternalError(c, "Failed to mark all notifications as read: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
api.Success(c, gin.H{"message": "All notifications marked as read"})
|
||||
}
|
||||
|
||||
// DeleteNotification handles DELETE /api/v1/notifications/:id
|
||||
// Deletes a notification
|
||||
func (h *NotificationHandler) DeleteNotification(c *gin.Context) {
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
api.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
api.BadRequest(c, "Invalid notification ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.notificationService.DeleteNotification(userID.(uint), uint(id))
|
||||
if err != nil {
|
||||
if errors.Is(err, service.ErrNotificationNotFound) {
|
||||
api.NotFound(c, "Notification not found")
|
||||
return
|
||||
}
|
||||
api.InternalError(c, "Failed to delete notification: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
api.NoContent(c)
|
||||
}
|
||||
|
||||
// RegisterRoutes registers all notification routes to the given router group
|
||||
func (h *NotificationHandler) RegisterRoutes(rg *gin.RouterGroup) {
|
||||
notifications := rg.Group("/notifications")
|
||||
{
|
||||
notifications.GET("", h.GetNotifications)
|
||||
notifications.GET("/unread-count", h.GetUnreadCount)
|
||||
notifications.PUT("/:id/read", h.MarkAsRead)
|
||||
notifications.POST("/read-all", h.MarkAllAsRead)
|
||||
notifications.DELETE("/:id", h.DeleteNotification)
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"accounting-app/pkg/api"
|
||||
"accounting-app/internal/models"
|
||||
"accounting-app/internal/service"
|
||||
"accounting-app/pkg/api"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -155,6 +155,17 @@ func (h *TransactionHandler) GetTransactions(c *gin.Context) {
|
||||
input.AccountID = &accID
|
||||
}
|
||||
|
||||
// Parse ledger filter
|
||||
if ledgerIDStr := c.Query("ledger_id"); ledgerIDStr != "" {
|
||||
ledgerID, err := strconv.ParseUint(ledgerIDStr, 10, 32)
|
||||
if err != nil {
|
||||
api.BadRequest(c, "Invalid ledger_id")
|
||||
return
|
||||
}
|
||||
lid := uint(ledgerID)
|
||||
input.LedgerID = &lid
|
||||
}
|
||||
|
||||
if typeStr := c.Query("type"); typeStr != "" {
|
||||
txnType := models.TransactionType(typeStr)
|
||||
input.Type = &txnType
|
||||
|
||||
Reference in New Issue
Block a user