Files
workspace/code/base-project/base-go-v2/internal/api/money/index.go
T
2025-11-15 17:31:36 +08:00

300 lines
7.4 KiB
Go

package money
import (
"base-go-v2/internal/db"
response "base-go-v2/internal/reponse"
"base-go-v2/internal/router"
"base-go-v2/internal/utils/idgen"
"base-go-v2/internal/utils/mapx"
"fmt"
"github.com/shopspring/decimal"
"time"
)
func InitMoneyRouter(r *router.Router) {
group := r.Group("money")
group.POST("/query", queryMoneyRecords)
group.GET("/category", getUserCategory)
group.POST("/insert", insertMoneyRecord)
group.POST("/update", updateMoneyRecord)
group.POST("/delete", deleteMoneyRecord)
}
// InitDefaultCategories 初始化系统默认分类到用户分类表
func InitDefaultCategories(userID int64) error {
// 1. 查询系统分类表
sysCategories, err := db.SelectList("money_sys_category", "", "sort_number")
if err != nil {
return err
}
fmt.Printf("系统分类数量: %d\n", len(sysCategories))
// 2. 构建批量插入数据
userCategories := mapx.NewArr(len(sysCategories))
for i, row := range sysCategories {
m := mapx.New().SetKV(
"id", idgen.NextId(),
"user_id", userID,
"name", row.GetString("name"),
"icon", row.GetString("icon"),
"type", row.GetInt("type"),
"sort_number", row.GetInt("sort_number"),
)
fmt.Printf("用户分类 %d: %+v\n", i+1, m)
userCategories = append(userCategories, m)
}
// 3. 批量插入到用户分类表
if _, err := db.InsertBatch("money_user_category", userCategories); err != nil {
return err
}
return nil
}
// 根据
func queryMoneyRecords(c *router.Context) error {
bodyData, err := c.GetBodyWithRequired("record_time") // "YYYY-MM"
if err != nil {
return c.AddError(err)
}
recordMonth := bodyData.GetString("record_time")
// 解析年月
startTime, err := time.Parse("2006-01", recordMonth)
if err != nil {
return c.AddError(fmt.Errorf("invalid record_time format: %v", err))
}
// 获取当月最后一天
endTime := startTime.AddDate(0, 1, 0).Add(-time.Nanosecond)
// SQL: money_record LEFT JOIN money_user_category
sqlStr := fmt.Sprintf(`
SELECT
mr.*,
muc.name AS category_name,
muc.icon AS category_icon,
muc.type AS category_type
FROM money_record mr
LEFT JOIN money_user_category muc ON mr.category_id = muc.id
WHERE mr.create_time BETWEEN '%s' AND '%s'
ORDER BY mr.create_time DESC
`, startTime.Format("2006-01-02 15:04:05"), endTime.Format("2006-01-02 15:04:05"))
// 查询
list, err := db.SelectBySql(sqlStr)
if err != nil {
return c.AddError(err)
}
// 分组数据
grouped := mapx.New() // mapx.M
totalIncome := decimal.NewFromInt(0)
totalExpense := decimal.NewFromInt(0)
for _, r := range list {
row := mapx.M(r)
createTime, ok := row["create_time"].(time.Time)
if !ok {
continue
}
day := createTime.Format("2006-01-02")
// 获取当天数据
dayDataI := grouped.Get(day)
var dayData mapx.M
if dayDataI == nil {
dayData = mapx.New().
Set("records", mapx.NewArr()).
Set("income", decimal.NewFromInt(0).String()).
Set("expense", decimal.NewFromInt(0).String())
} else {
dayData = dayDataI.(mapx.M)
}
// 追加记录
records := dayData.GetArray("records")
records = append(records, row)
dayData.Set("records", records)
// 计算当天收入支出
categoryType := row.GetInt("category_type")
amount, err := decimal.NewFromString(row.GetString("amount"))
if err != nil {
continue
}
dayIncome, err := decimal.NewFromString(dayData.GetString("income"))
if err != nil {
dayIncome = decimal.NewFromInt(0)
}
dayExpense, err := decimal.NewFromString(dayData.GetString("expense"))
if err != nil {
dayExpense = decimal.NewFromInt(0)
}
if categoryType == 0 {
dayIncome = dayIncome.Add(amount)
totalIncome = totalIncome.Add(amount)
} else if categoryType == 1 {
dayExpense = dayExpense.Add(amount)
totalExpense = totalExpense.Add(amount)
}
dayData.Set("income", dayIncome.String())
dayData.Set("expense", dayExpense.String())
grouped.Set(day, dayData)
}
result := mapx.New().
Set("records", grouped).
Set("total_income", totalIncome.String()).
Set("total_expense", totalExpense.String())
return response.Success(c).Data(result).Send()
}
func getUserCategory(c *router.Context) error {
userId := c.GetUserID()
// 查询当前用户的分类
userCategories, err := db.SelectList("money_user_category",
db.BuildWhereString(mapx.New().Set("user_id", userId)),
"sort_number ASC")
if err != nil {
return c.AddError(err)
}
// 按 type 分组
result := map[string][]mapx.M{
"income": {},
"expense": {},
}
for _, cat := range userCategories {
switch cat.GetInt("type") {
case 0:
result["income"] = append(result["income"], cat)
case 1:
result["expense"] = append(result["expense"], cat)
}
}
return response.Success(c).Data(result).Send()
}
func insertMoneyRecord(c *router.Context) error {
bodyData, err := c.GetBodyWithRequired("category_id", "amount", "record_time")
if err != nil {
return c.AddError(err)
}
categoryId := bodyData.GetInt64("category_id")
recordTime := bodyData.GetString("record_time")
amountStr := bodyData.GetString("amount")
remark := bodyData.GetString("remark")
amountDecimal, err := decimal.NewFromString(amountStr)
if err != nil {
return c.AddError(err)
}
newRecord := mapx.New().SetKV("id", idgen.NextId(),
"category_id", categoryId,
"user_id", c.GetUserID(),
"amount", amountDecimal,
"remark", remark,
"record_time", recordTime,
)
insertOne, err := db.InsertOne("money_record", newRecord)
if err != nil {
return response.Fail(c).Message("新增失败").Send()
}
if insertOne != 1 {
return response.Fail(c).Message("新增失败").Send()
}
return response.Success(c).Data(newRecord).Message("新增成功").Send()
}
func updateMoneyRecord(c *router.Context) error {
bodyData, err := c.GetBodyWithRequired("id")
if err != nil {
return c.AddError(err)
}
recordId := bodyData.GetInt64("id")
record, err := db.SelectById("money_record", "id", recordId)
if err != nil {
return c.AddError(err)
}
if record == nil {
return response.Fail(c).Message("该条账单不存在").Send()
}
categoryId := bodyData.GetInt64("category_id")
recordTime := bodyData.GetString("record_time")
amountStr := bodyData.GetString("amount")
remark := bodyData.GetString("remark")
updateRecord := mapx.New().SetKV("id", recordId)
if record.GetInt64("category_id") != categoryId {
updateRecord.SetKV("category_id", categoryId)
}
if record.GetString("record_time") != recordTime {
updateRecord.SetKV("record_time", recordTime)
}
if record.GetString("amount") != amountStr {
amountDecimal, err := decimal.NewFromString(amountStr)
if err != nil {
return c.AddError(err)
}
updateRecord.SetKV("amount", amountDecimal)
}
if record.GetString("remark") != remark {
updateRecord.SetKV("remark", remark)
}
updateOne, err := db.UpdateOne("money_record", "id", recordId, updateRecord)
if err != nil {
return c.AddError(err)
}
if updateOne != 1 {
return response.Fail(c).Message("更新失败").Send()
}
return response.Success(c).Message("更新成功").Send()
}
func deleteMoneyRecord(c *router.Context) error {
bodyData, err := c.GetBodyWithRequired("id")
if err != nil {
return c.AddError(err)
}
recordId := bodyData.GetInt64("id")
deleteOne, err := db.DeleteOne("money_record", "id", recordId)
if err != nil {
return c.AddError(err)
}
if deleteOne != 1 {
return response.Fail(c).Message("删除失败").Send()
}
return response.Success(c).Message("删除成功").Send()
}