349 lines
8.7 KiB
Go
349 lines
8.7 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"
|
|
"base-go-v2/internal/utils/timex"
|
|
"fmt"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
func InitMoneyRouter(r *router.Router) {
|
|
groupRecord := r.Group("money")
|
|
groupRecord.POST("/query", queryMoneyRecords)
|
|
groupRecord.POST("/insert", insertMoneyRecord)
|
|
groupRecord.POST("/update", updateMoneyRecord)
|
|
groupRecord.POST("/delete", deleteMoneyRecord)
|
|
|
|
groupCategory := r.Group("money/category")
|
|
groupCategory.GET("", getUserCategory)
|
|
groupCategory.POST("/updateSort", updateMoneyCategorySort)
|
|
groupCategory.POST("/delete", deleteMoneyCategoryById)
|
|
}
|
|
|
|
// 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")
|
|
|
|
fmt.Println(recordMonth)
|
|
|
|
// 解析年月
|
|
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
|
|
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.record_time BETWEEN '%s' AND '%s'
|
|
ORDER BY mr.record_time DESC, 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()
|
|
totalIncome := decimal.NewFromInt(0)
|
|
totalExpense := decimal.NewFromInt(0)
|
|
|
|
for _, r := range list {
|
|
row := mapx.M(r)
|
|
|
|
recordTime, ok := row["record_time"].(time.Time)
|
|
if !ok {
|
|
continue
|
|
}
|
|
day := recordTime.Format("2006-01-02")
|
|
|
|
// 获取当天数据
|
|
dayDataI := grouped.Get(day)
|
|
var dayData mapx.M
|
|
if dayDataI == nil {
|
|
dayData = mapx.New().
|
|
Set("records", mapx.NewArr()).
|
|
Set("income", "0.00").
|
|
Set("expense", "0.00")
|
|
} 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, _ := decimal.NewFromString(dayData.GetString("income"))
|
|
dayExpense, _ := decimal.NewFromString(dayData.GetString("expense"))
|
|
|
|
if categoryType == 1 {
|
|
dayIncome = dayIncome.Add(amount)
|
|
totalIncome = totalIncome.Add(amount)
|
|
} else if categoryType == 0 {
|
|
dayExpense = dayExpense.Add(amount)
|
|
totalExpense = totalExpense.Add(amount)
|
|
}
|
|
|
|
// ⭐ 保留两位小数
|
|
dayData.Set("income", dayIncome.Round(2).StringFixed(2))
|
|
dayData.Set("expense", dayExpense.Round(2).StringFixed(2))
|
|
|
|
grouped.Set(day, dayData)
|
|
}
|
|
|
|
// 对日期排序,最新在前
|
|
dates := make([]string, 0, len(grouped))
|
|
for k := range grouped {
|
|
dates = append(dates, k)
|
|
}
|
|
sort.Slice(dates, func(i, j int) bool {
|
|
return dates[i] > dates[j]
|
|
})
|
|
|
|
// 构建最终 records 数组
|
|
recordsArr := make([]mapx.M, 0, len(dates))
|
|
for _, date := range dates {
|
|
dayData := grouped.Get(date).(mapx.M)
|
|
recordsArr = append(recordsArr, mapx.New().
|
|
Set("record_time", date).
|
|
Set("income", dayData.GetString("income")).
|
|
Set("expense", dayData.GetString("expense")).
|
|
Set("records", dayData.GetArray("records")))
|
|
}
|
|
|
|
// ⭐ 最终总收入/支出保留两位小数
|
|
result := mapx.New().
|
|
Set("records", recordsArr).
|
|
Set("total_income", totalIncome.Round(2).StringFixed(2)).
|
|
Set("total_expense", totalExpense.Round(2).StringFixed(2))
|
|
|
|
return response.Success(c).Data(result).Send()
|
|
}
|
|
|
|
func getUserCategory(c *router.Context) error {
|
|
userId := c.GetUserID()
|
|
|
|
// 查询当前用户的分类,已经按 sort_number 升序
|
|
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)
|
|
}
|
|
|
|
return response.Success(c).Data(userCategories).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)
|
|
}
|
|
|
|
updateRecord.SetKV("update_time", timex.DateTimeString())
|
|
|
|
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")
|
|
|
|
_, err = db.DeleteOne("money_record", "id", recordId)
|
|
if err != nil {
|
|
return c.AddError(err)
|
|
}
|
|
|
|
return response.Success(c).Message("删除成功").Send()
|
|
}
|
|
|
|
func updateMoneyCategorySort(c *router.Context) error {
|
|
bodyData, err := c.BodyMap()
|
|
fmt.Println("进入了===")
|
|
|
|
if err == nil {
|
|
fmt.Println(err.Error())
|
|
fmt.Println("发生异常===")
|
|
return c.AddError(err)
|
|
}
|
|
|
|
if bodyData == nil {
|
|
return response.Success(c).Send()
|
|
}
|
|
|
|
updateArray := bodyData.GetArray("data")
|
|
|
|
fmt.Println(updateArray)
|
|
|
|
_, err = db.UpdateBatch("money_user_category", "id", updateArray)
|
|
|
|
if err != nil {
|
|
return c.AddError(err)
|
|
}
|
|
|
|
return response.Success(c).Send()
|
|
}
|
|
|
|
func deleteMoneyCategoryById(c *router.Context) error {
|
|
bodyData, err := c.GetBodyWithRequired("id")
|
|
if err != nil {
|
|
return c.AddError(err)
|
|
}
|
|
recordId := bodyData.GetInt64("id")
|
|
|
|
_, err = db.DeleteOne("money_user_category", "id", recordId)
|
|
if err != nil {
|
|
return c.AddError(err)
|
|
}
|
|
|
|
return response.Success(c).Message("删除成功").Send()
|
|
}
|