package handler import ( "net/http" "time" "github.com/gin-gonic/gin" "billai-server/model" "billai-server/repository" ) // ManualBillInput 手动输入的账单 type ManualBillInput struct { Time string `json:"time" binding:"required"` // 交易时间 Category string `json:"category" binding:"required"` // 交易分类 Merchant string `json:"merchant" binding:"required"` // 交易对方 Description string `json:"description"` // 商品说明 IncomeExpense string `json:"income_expense" binding:"required"` // 收/支 Amount float64 `json:"amount" binding:"required"` // 金额 PayMethod string `json:"pay_method"` // 支付方式 Status string `json:"status"` // 交易状态 Remark string `json:"remark"` // 备注 } // CreateManualBillsRequest 批量创建手动账单请求 type CreateManualBillsRequest struct { Bills []ManualBillInput `json:"bills" binding:"required,min=1"` } // CreateManualBillsResponse 批量创建手动账单响应 type CreateManualBillsResponse struct { Result bool `json:"result"` Message string `json:"message,omitempty"` Data *CreateManualBillsData `json:"data,omitempty"` } // CreateManualBillsData 批量创建手动账单数据 type CreateManualBillsData struct { Success int `json:"success"` // 成功创建数量 Failed int `json:"failed"` // 失败数量 Duplicates int `json:"duplicates"` // 重复数量 } // CreateManualBills 批量创建手动输入的账单 func CreateManualBills(c *gin.Context) { var req CreateManualBillsRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, CreateManualBillsResponse{ Result: false, Message: "参数解析失败: " + err.Error(), }) return } // 获取 repository repo := repository.GetRepository() if repo == nil { c.JSON(http.StatusInternalServerError, CreateManualBillsResponse{ Result: false, Message: "数据库未连接", }) return } // 转换为 CleanedBill bills := make([]model.CleanedBill, 0, len(req.Bills)) for _, input := range req.Bills { // 解析时间(使用本地时区,避免 UTC 时区问题) t, err := time.ParseInLocation("2006-01-02 15:04:05", input.Time, time.Local) if err != nil { // 尝试另一种格式 t, err = time.ParseInLocation("2006-01-02T15:04:05Z07:00", input.Time, time.Local) if err != nil { c.JSON(http.StatusBadRequest, CreateManualBillsResponse{ Result: false, Message: "时间格式错误: " + input.Time, }) return } } // 设置默认值 status := input.Status if status == "" { status = "交易成功" } bill := model.CleanedBill{ BillType: "manual", TransactionID: "", // 手动账单不设置交易ID MerchantOrderNo: "", Time: model.LocalTime(t), Category: input.Category, Merchant: input.Merchant, Description: input.Description, IncomeExpense: input.IncomeExpense, Amount: input.Amount, PayMethod: input.PayMethod, Status: status, Remark: input.Remark, ReviewLevel: "", // 手动账单不需要复核 CreatedAt: time.Now(), UpdatedAt: time.Now(), SourceFile: "manual_input", UploadBatch: time.Now().Format("20060102_150405"), } bills = append(bills, bill) } // 保存账单(带去重) saved, duplicates, err := repo.SaveCleanedBills(bills) if err != nil { c.JSON(http.StatusInternalServerError, CreateManualBillsResponse{ Result: false, Message: "保存失败: " + err.Error(), }) return } failed := len(bills) - saved - duplicates c.JSON(http.StatusOK, CreateManualBillsResponse{ Result: true, Message: "创建成功", Data: &CreateManualBillsData{ Success: saved, Failed: failed, Duplicates: duplicates, }, }) }