fix: 修复账单删除功能并支持分析页面删除操作
Some checks are pending
Deploy BillAI / Deploy to Production (push) Waiting to run

- 将删除接口从 DELETE /api/bills/:id 改为 POST /api/bills/:id/delete 以兼容 SvelteKit 代理
- 分析页面组件 (TopExpenses/BillRecordsTable/DailyTrendChart) 支持删除并同步更新统计数据
- Review 接口改为直接查询 MongoDB 而非读取文件
- 软删除时记录 updated_at 时间戳
- 添加 .dockerignore 文件优化构建
- 完善 AGENTS.md 文档
This commit is contained in:
clz
2026-02-16 22:28:49 +08:00
parent a5f1a370c7
commit 642ea2d3ef
13 changed files with 277 additions and 151 deletions

25
server/.dockerignore Normal file
View File

@@ -0,0 +1,25 @@
# Ignore these files for docker build context
# Binaries
server
billai-server
*.exe
*.dll
# Dependencies (if any are local and not in go.mod/go.sum, unlikely for Go)
vendor/
# Logs and outputs
*.log
outputs/
uploads/
# IDE config
.idea/
.vscode/
# Git
.git/
.gitignore
# OS
.DS_Store

View File

@@ -14,7 +14,7 @@ type DeleteBillResponse struct {
Message string `json:"message,omitempty"`
}
// DeleteBill DELETE /api/bills/:id 删除清洗后的账单记录
// DeleteBill POST /api/bills/:id/delete 删除清洗后的账单记录
func DeleteBill(c *gin.Context) {
id := strings.TrimSpace(c.Param("id"))
if id == "" {

View File

@@ -1,61 +1,59 @@
package handler
import (
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/gin-gonic/gin"
"billai-server/config"
"billai-server/model"
"billai-server/service"
"billai-server/repository"
)
// Review 获取需要复核的记录
func Review(c *gin.Context) {
// 获取文件名参
fileName := c.Query("file")
if fileName == "" {
c.JSON(http.StatusBadRequest, model.ReviewResponse{
// 获取数
repo := repository.GetRepository()
if repo == nil {
c.JSON(http.StatusInternalServerError, model.ReviewResponse{
Result: false,
Message: "请提供文件名参数 (file)",
Message: "数据库未连接",
})
return
}
// 构建文件路径
outputDirAbs := config.ResolvePath(config.Global.OutputDir)
filePath := filepath.Join(outputDirAbs, fileName)
// 检查文件是否存在
if _, err := os.Stat(filePath); os.IsNotExist(err) {
c.JSON(http.StatusNotFound, model.ReviewResponse{
// 从MongoDB查询所有需要复核的账单
bills, err := repo.GetBillsNeedReview()
if err != nil {
c.JSON(http.StatusInternalServerError, model.ReviewResponse{
Result: false,
Message: "文件不存在: " + fileName,
Message: "查询失败: " + err.Error(),
})
return
}
// 判断文件格式
format := "csv"
if strings.HasSuffix(fileName, ".json") {
format = "json"
}
// 提取需要复核的记录
records := service.ExtractNeedsReview(filePath, format)
// 统计高低优先级数量
// 统计高低优先级数量并转换为 ReviewRecord
highCount := 0
lowCount := 0
for _, r := range records {
if r.ReviewLevel == "HIGH" {
records := make([]model.ReviewRecord, 0, len(bills))
for _, bill := range bills {
if bill.ReviewLevel == "HIGH" {
highCount++
} else if r.ReviewLevel == "LOW" {
} else if bill.ReviewLevel == "LOW" {
lowCount++
}
records = append(records, model.ReviewRecord{
Time: bill.Time.Time().Format("2006-01-02 15:04:05"),
Category: bill.Category,
Merchant: bill.Merchant,
Description: bill.Description,
IncomeExpense: bill.IncomeExpense,
Amount: fmt.Sprintf("%.2f", bill.Amount),
Remark: bill.Remark,
ReviewLevel: bill.ReviewLevel,
})
}
c.JSON(http.StatusOK, model.ReviewResponse{

View File

@@ -445,7 +445,12 @@ func (r *Repository) DeleteCleanedBillByID(id string) error {
defer cancel()
filter := bson.M{"_id": oid}
update := bson.M{"$set": bson.M{"is_deleted": true}}
update := bson.M{
"$set": bson.M{
"is_deleted": true,
"updated_at": time.Now(), // 记录更新时间
},
}
result, err := r.cleanedCollection.UpdateOne(ctx, filter, update)
if err != nil {
return fmt.Errorf("soft delete bill failed: %w", err)

View File

@@ -63,7 +63,7 @@ func setupAPIRoutes(r *gin.Engine) {
authed.POST("/bills/:id", handler.UpdateBill)
// 删除账单(软删除)
authed.DELETE("/bills/:id", handler.DeleteBill)
authed.POST("/bills/:id/delete", handler.DeleteBill)
// 手动创建账单
authed.POST("/bills/manual", handler.CreateManualBills)