u
This commit is contained in:
1 parent
46106d0c76
commit
34240d2e16
36 files changed
+2853
-165
No files matched your search
@@ -4,6 +4,7 @@
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d/console_1.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/finance_category_default.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/finance_category_space.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/finance_record.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/space.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||
</component>
|
||||
</project>
|
||||
+1
@@ -3,6 +3,7 @@
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/db/queries/finance_category_default.sql" dialect="PostgreSQL" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/finance_category_space.sql" dialect="PostgreSQL" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/finance_record.sql" dialect="PostgreSQL" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/space.sql" dialect="PostgreSQL" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/space_member.sql" dialect="GenericSQL" />
|
||||
<file url="file://$PROJECT_DIR$/db/queries/user.sql" dialect="GenericSQL" />
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
package finance
|
||||
|
||||
import (
|
||||
"allapp/api/router/middleware"
|
||||
"allapp/api/types"
|
||||
"allapp/db"
|
||||
"allapp/db/repo"
|
||||
"allapp/utils/errorx"
|
||||
"allapp/utils/requestx"
|
||||
"allapp/utils/responsex"
|
||||
"allapp/utils/uniqueid"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// ListFinanceCategories 查看记账分类
|
||||
func ListFinanceCategories(c fiber.Ctx) error {
|
||||
spaceId, err := middleware.GetSpaceID(c)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
categories, err := db.Queries.ListFinanceCategories(c.Context(), spaceId)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
financeCategories := make([]types.FinanceCategory, 0, len(categories))
|
||||
|
||||
for _, category := range categories {
|
||||
financeCategories = append(financeCategories, types.FinanceCategory{
|
||||
Id: category.ID,
|
||||
Name: category.Name,
|
||||
Icon: category.Icon,
|
||||
Type: category.Type,
|
||||
SortNumber: category.SortNumber,
|
||||
})
|
||||
}
|
||||
|
||||
vo := new(types.ListFinanceCategoriesVO)
|
||||
vo.Categories = financeCategories
|
||||
|
||||
return responsex.OK(c, vo)
|
||||
}
|
||||
|
||||
// CreateFinanceCategory 新建分类
|
||||
func CreateFinanceCategory(c fiber.Ctx) error {
|
||||
dto := new(types.CreateFinanceCategoryDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spaceID, err2 := middleware.GetSpaceID(c)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
|
||||
_, err = db.Queries.GetFinanceCategoryByName(c.Context(), repo.GetFinanceCategoryByNameParams{
|
||||
SpaceID: spaceID,
|
||||
Name: dto.Name,
|
||||
Type: dto.Type,
|
||||
})
|
||||
|
||||
isFound := true
|
||||
|
||||
if err != nil {
|
||||
if errorx.IsNotFound(err) {
|
||||
isFound = false
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if isFound {
|
||||
return responsex.Error(c, "分类名称不能重复")
|
||||
}
|
||||
|
||||
nextId := uniqueid.NextId()
|
||||
|
||||
err = db.Queries.InsertFinanceCategory(c.Context(), repo.InsertFinanceCategoryParams{
|
||||
ID: nextId,
|
||||
SpaceID: spaceID,
|
||||
Name: dto.Name,
|
||||
Icon: dto.Icon,
|
||||
Type: dto.Type,
|
||||
SortNumber: dto.SortNumber,
|
||||
CreateBy: userId,
|
||||
UpdateBy: userId,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vo := new(types.CreateFinanceCategoryVO)
|
||||
vo.Id = nextId
|
||||
|
||||
return responsex.OK(c, vo)
|
||||
}
|
||||
|
||||
// UpdateFinanceCategorySortNumber 更新记账分类顺序
|
||||
func UpdateFinanceCategorySortNumber(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateFinanceCategorySortDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 组装批量更新参数
|
||||
params := make([]repo.BatchUpdateFinanceCategorySortNumberParams, 0, len(dto.Categories))
|
||||
for _, datum := range dto.Categories {
|
||||
params = append(params, repo.BatchUpdateFinanceCategorySortNumberParams{
|
||||
ID: datum.Id,
|
||||
SortNumber: datum.SortNumber,
|
||||
UpdateBy: userId,
|
||||
})
|
||||
}
|
||||
|
||||
// 使用统一事务封装
|
||||
err = db.WithTx(c.Context(), func(q *repo.Queries) error {
|
||||
batch := q.BatchUpdateFinanceCategorySortNumber(c.Context(), params)
|
||||
|
||||
if err := db.RunBatch(c.Context(), batch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, nil)
|
||||
}
|
||||
|
||||
// DeleteFinanceCategory 删除记账分类
|
||||
func DeleteFinanceCategory(c fiber.Ctx) error {
|
||||
dto := new(types.DeleteFinanceCategoryDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := db.WithTx(c.Context(), func(q *repo.Queries) error {
|
||||
err := q.DeleteFinanceCategory(c.Context(), dto.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = q.DeleteFinanceRecordByCategoryId(c.Context(), dto.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, nil)
|
||||
}
|
||||
|
||||
// UpdateFinanceCategory 更新记账分类
|
||||
func UpdateFinanceCategory(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateFinanceCategoryDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.Queries.UpdateFinanceCategory(c.Context(), repo.UpdateFinanceCategoryParams{
|
||||
ID: dto.Id,
|
||||
Name: dto.Name,
|
||||
Icon: dto.Icon,
|
||||
UpdateBy: userId,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, nil)
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package finance
|
||||
|
||||
import (
|
||||
"allapp/api/router/middleware"
|
||||
"allapp/api/types"
|
||||
"allapp/db"
|
||||
"allapp/db/repo"
|
||||
"allapp/utils/pgtypex"
|
||||
"allapp/utils/requestx"
|
||||
"allapp/utils/responsex"
|
||||
"allapp/utils/timex"
|
||||
"allapp/utils/uniqueid"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// ListFinanceRecords 记账记录
|
||||
func ListFinanceRecords(c fiber.Ctx) error {
|
||||
dto := new(types.ListFinanceRecordsDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spaceID, err := middleware.GetSpaceID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析年月(yyyy-MM)
|
||||
startTime, err := timex.ParseTimeFlexible(dto.StartTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endTime, err := timex.ParseTimeFlexible(dto.EndTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 开始时间兜底
|
||||
if startTime == nil {
|
||||
t := time.Unix(0, 0)
|
||||
startTime = &t
|
||||
}
|
||||
|
||||
// 结束时间兜底
|
||||
if endTime == nil {
|
||||
t := time.Now().AddDate(10, 0, 0)
|
||||
endTime = &t
|
||||
}
|
||||
|
||||
categoryId := dto.CategoryId
|
||||
|
||||
records, err := db.Queries.ListFinanceRecords(c.Context(), repo.ListFinanceRecordsParams{
|
||||
SpaceID: spaceID,
|
||||
RecordTime: pgtypex.TimePtrToPgDate(startTime),
|
||||
RecordTime_2: pgtypex.TimePtrToPgDate(endTime),
|
||||
Column4: categoryId,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
financeRecords := make([]types.FinanceRecord, 0, len(records))
|
||||
|
||||
for _, record := range records {
|
||||
financeRecords = append(financeRecords, types.FinanceRecord{
|
||||
Id: record.ID,
|
||||
CategoryId: record.CategoryID,
|
||||
Amount: pgtypex.NumericToString(record.Amount),
|
||||
Remark: pgtypex.TextToString(record.Remark),
|
||||
RecordTime: pgtypex.DateToString(record.RecordTime),
|
||||
MemberId: record.UpdateBy,
|
||||
MemberName: pgtypex.TextToString(record.MemberName),
|
||||
})
|
||||
}
|
||||
|
||||
vo := new(types.ListFinanceRecordsVO)
|
||||
vo.Records = financeRecords
|
||||
|
||||
return responsex.OK(c, vo)
|
||||
}
|
||||
|
||||
// CreateFinanceRecord 新增记账记录
|
||||
func CreateFinanceRecord(c fiber.Ctx) error {
|
||||
dto := new(types.CreateFinanceRecordDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spaceID, err := middleware.GetSpaceID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userID, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.Queries.InsertFinanceRecord(c.Context(), repo.InsertFinanceRecordParams{
|
||||
ID: uniqueid.NextId(),
|
||||
SpaceID: spaceID,
|
||||
CategoryID: dto.CategoryId,
|
||||
Amount: pgtypex.StringToNumeric(dto.Amount),
|
||||
RecordTime: pgtypex.StringToDate(dto.RecordTime),
|
||||
Remark: pgtypex.StringToText(dto.Remark),
|
||||
CreateBy: userID,
|
||||
UpdateBy: userID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, nil)
|
||||
}
|
||||
|
||||
// UpdateFinanceRecord 更新记账记录
|
||||
func UpdateFinanceRecord(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateFinanceRecordDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userID, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.Queries.UpdateFinanceRecord(c.Context(), repo.UpdateFinanceRecordParams{
|
||||
ID: uniqueid.NextId(),
|
||||
CategoryID: dto.CategoryId,
|
||||
Amount: pgtypex.StringToNumeric(dto.Amount),
|
||||
Remark: pgtypex.StringToText(dto.Remark),
|
||||
RecordTime: pgtypex.StringToDate(dto.RecordTime),
|
||||
UpdateBy: userID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, nil)
|
||||
}
|
||||
|
||||
// DeleteFinanceRecord 删除记账记录
|
||||
func DeleteFinanceRecord(c fiber.Ctx) error {
|
||||
dto := new(types.DeleteFinanceRecordDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := db.Queries.DeleteFinanceRecord(c.Context(), dto.Id)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, nil)
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package space
|
||||
|
||||
import (
|
||||
"allapp/api/router/middleware"
|
||||
"allapp/api/types"
|
||||
"allapp/db"
|
||||
"allapp/db/repo"
|
||||
"allapp/utils/requestx"
|
||||
"allapp/utils/responsex"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// UpdateSpaceDefault 更新空间默认情况
|
||||
func UpdateSpaceDefault(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateSpaceIsDefaultDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.WithTx(c.Context(), func(q *repo.Queries) error {
|
||||
err = q.UpdateSpaceIsDefault(c.Context(), repo.UpdateSpaceIsDefaultParams{
|
||||
SpaceID: dto.SpaceId,
|
||||
UserID: userId,
|
||||
IsDefault: dto.IsDefault,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var otherDefault int16
|
||||
|
||||
if dto.IsDefault == 1 {
|
||||
otherDefault = 0
|
||||
}
|
||||
|
||||
err = q.UpdateOtherSpacesIsDefault(c.Context(), repo.UpdateOtherSpacesIsDefaultParams{
|
||||
IsDefault: otherDefault,
|
||||
UserID: userId,
|
||||
SpaceID: dto.SpaceId,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, "更新成功")
|
||||
}
|
||||
|
||||
// UpdateMemberName 更新群成员名称
|
||||
func UpdateMemberName(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateMemberNameDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.Queries.UpdateSpaceMemberName(c.Context(), repo.UpdateSpaceMemberNameParams{
|
||||
SpaceID: dto.SpaceId,
|
||||
UserID: userId,
|
||||
MemberName: dto.MemberName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, "更新成功")
|
||||
}
|
||||
|
||||
// UpdateSpaceSortNumber 更新空间排序
|
||||
func UpdateSpaceSortNumber(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateSpaceSortNumberDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 组装批量更新参数
|
||||
params := make([]repo.BatchUpdateSpaceSortNumberParams, 0, len(dto.Spaces))
|
||||
|
||||
for _, datum := range dto.Spaces {
|
||||
params = append(params, repo.BatchUpdateSpaceSortNumberParams{
|
||||
SortNumber: datum.SortNumber,
|
||||
SpaceID: datum.SpaceId,
|
||||
UserID: userId,
|
||||
})
|
||||
}
|
||||
|
||||
// 使用统一事务封装
|
||||
err = db.WithTx(c.Context(), func(q *repo.Queries) error {
|
||||
batch := q.BatchUpdateSpaceSortNumber(c.Context(), params)
|
||||
|
||||
if err := db.RunBatch(c.Context(), batch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, "更新成功")
|
||||
}
|
||||
-115
@@ -228,80 +228,6 @@ func ExitSpace(c fiber.Ctx) error {
|
||||
return responsex.OK(c, "空间已成功退出")
|
||||
}
|
||||
|
||||
// UpdateMemberName 更新群成员名称
|
||||
func UpdateMemberName(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateMemberNameDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.Queries.UpdateSpaceMemberName(c.Context(), repo.UpdateSpaceMemberNameParams{
|
||||
SpaceID: dto.SpaceId,
|
||||
UserID: userId,
|
||||
MemberName: dto.MemberName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, "更新成功")
|
||||
}
|
||||
|
||||
// UpdateSpaceDefault 更新空间默认情况
|
||||
func UpdateSpaceDefault(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateSpaceIsDefaultDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.WithTx(c.Context(), func(q *repo.Queries) error {
|
||||
err = q.UpdateSpaceIsDefault(c.Context(), repo.UpdateSpaceIsDefaultParams{
|
||||
SpaceID: dto.SpaceId,
|
||||
UserID: userId,
|
||||
IsDefault: dto.IsDefault,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var otherDefault int16
|
||||
|
||||
if dto.IsDefault == 1 {
|
||||
otherDefault = 0
|
||||
}
|
||||
|
||||
err = q.UpdateOtherSpacesIsDefault(c.Context(), repo.UpdateOtherSpacesIsDefaultParams{
|
||||
IsDefault: otherDefault,
|
||||
UserID: userId,
|
||||
SpaceID: dto.SpaceId,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, "更新成功")
|
||||
}
|
||||
|
||||
// UpdateSpaceName 更新空间名称
|
||||
func UpdateSpaceName(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateSpaceNameDTO)
|
||||
@@ -381,47 +307,6 @@ func GetSpaceSettings(c fiber.Ctx) error {
|
||||
return responsex.OK(c, vo)
|
||||
}
|
||||
|
||||
// UpdateSpaceSortNumber 更新空间排序
|
||||
func UpdateSpaceSortNumber(c fiber.Ctx) error {
|
||||
dto := new(types.UpdateSpaceSortNumberDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 组装批量更新参数
|
||||
params := make([]repo.BatchUpdateSpaceSortNumberParams, 0, len(dto.Spaces))
|
||||
|
||||
for _, datum := range dto.Spaces {
|
||||
params = append(params, repo.BatchUpdateSpaceSortNumberParams{
|
||||
SortNumber: datum.SortNumber,
|
||||
SpaceID: datum.SpaceId,
|
||||
UserID: userId,
|
||||
})
|
||||
}
|
||||
|
||||
// 使用统一事务封装
|
||||
err = db.WithTx(c.Context(), func(q *repo.Queries) error {
|
||||
batch := q.BatchUpdateSpaceSortNumber(c.Context(), params)
|
||||
|
||||
if err := db.RunBatch(c.Context(), batch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return responsex.OK(c, "更新成功")
|
||||
}
|
||||
|
||||
func ListSpaceMembers(c fiber.Ctx) error {
|
||||
dto := new(types.ListSpaceMembersDTO)
|
||||
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||
@@ -2,6 +2,7 @@ package router
|
||||
|
||||
import (
|
||||
"allapp/api/handler/auth"
|
||||
"allapp/api/handler/finance"
|
||||
"allapp/api/handler/space"
|
||||
"allapp/api/router/middleware"
|
||||
"allapp/config"
|
||||
@@ -39,6 +40,19 @@ func SetupRouters(app *fiber.App) {
|
||||
spaceRouter.Post("/member/name", space.UpdateMemberName)
|
||||
spaceRouter.Post("/member/sortNumber", space.UpdateSpaceSortNumber)
|
||||
|
||||
// 记账操作
|
||||
financeRouter := api.Group("/finance").Use(middleware.Auth()).Use(middleware.SpaceGuard())
|
||||
financeRouter.Post("/category/list", finance.ListFinanceCategories)
|
||||
financeRouter.Post("/category/create", finance.CreateFinanceCategory)
|
||||
financeRouter.Post("/category/sortNumber", finance.UpdateFinanceCategorySortNumber)
|
||||
financeRouter.Post("/category/delete", finance.DeleteFinanceCategory)
|
||||
financeRouter.Post("/category/update", finance.UpdateFinanceCategory)
|
||||
|
||||
financeRouter.Post("/record/list", finance.ListFinanceRecords)
|
||||
financeRouter.Post("/record/create", finance.CreateFinanceRecord)
|
||||
financeRouter.Post("/record/update", finance.UpdateFinanceRecord)
|
||||
financeRouter.Post("/record/delete", finance.DeleteFinanceRecord)
|
||||
|
||||
// authGroup.Get("/user/profile", user.GetProfile)
|
||||
// spaceGroup.Get("/space/info", space.GetInfo)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package types
|
||||
|
||||
// =================================== 记账分类 ===================================
|
||||
|
||||
// FinanceCategory 记账分类
|
||||
type FinanceCategory struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
Type int16 `json:"type"`
|
||||
SortNumber int32 `json:"sort_number"`
|
||||
}
|
||||
|
||||
type ListFinanceCategoriesVO struct {
|
||||
Categories []FinanceCategory `json:"categories"`
|
||||
}
|
||||
|
||||
// CreateFinanceCategoryDTO 创建记账分类
|
||||
type CreateFinanceCategoryDTO struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Icon string `json:"icon" validate:"required"`
|
||||
Type int16 `json:"type" validate:"required"`
|
||||
SortNumber int32 `json:"sort_number" validate:"required"`
|
||||
}
|
||||
|
||||
type CreateFinanceCategoryVO struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
// UpdateFinanceCategorySortItem 更新记账分类排序
|
||||
type UpdateFinanceCategorySortItem struct {
|
||||
Id int64 `json:"id" validate:"required"`
|
||||
SortNumber int32 `json:"sort_number" validate:"required"`
|
||||
}
|
||||
|
||||
type UpdateFinanceCategorySortDTO struct {
|
||||
Categories []UpdateFinanceCategorySortItem `json:"categories" validate:"required,dive"`
|
||||
}
|
||||
|
||||
// DeleteFinanceCategoryDTO 删除记账分类
|
||||
type DeleteFinanceCategoryDTO struct {
|
||||
Id int64 `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type UpdateFinanceCategoryDTO struct {
|
||||
Id int64 `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Icon string `json:"icon" validate:"required"`
|
||||
}
|
||||
|
||||
// =================================== 记账分类 ===================================
|
||||
|
||||
// =================================== 记账 ===================================
|
||||
|
||||
type FinanceRecord struct {
|
||||
Id int64 `json:"id"`
|
||||
CategoryId int64 `json:"category_id"`
|
||||
Amount string `json:"amount"`
|
||||
Remark string `json:"remark"`
|
||||
RecordTime string `json:"record_time"`
|
||||
MemberId int64 `json:"member_id"`
|
||||
MemberName string `json:"member_name"`
|
||||
}
|
||||
|
||||
type ListFinanceRecordsDTO struct {
|
||||
StartTime string `json:"start_time"`
|
||||
EndTime string `json:"end_time"`
|
||||
CategoryId int64 `json:"category_id"`
|
||||
}
|
||||
|
||||
type ListFinanceRecordsVO struct {
|
||||
Records []FinanceRecord `json:"records"`
|
||||
}
|
||||
|
||||
// CreateFinanceRecordDTO 新建记账
|
||||
type CreateFinanceRecordDTO struct {
|
||||
CategoryId int64 `json:"category_id" validate:"required"`
|
||||
Amount string `json:"amount" validate:"required"`
|
||||
RecordTime string `json:"record_time" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// UpdateFinanceRecordDTO 更新记账
|
||||
type UpdateFinanceRecordDTO struct {
|
||||
Id int64 `json:"id" validate:"required"`
|
||||
CategoryId int64 `json:"category_id" validate:"required"`
|
||||
Amount string `json:"amount" validate:"required"`
|
||||
RecordTime string `json:"record_time" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// DeleteFinanceRecordDTO 删除记账
|
||||
type DeleteFinanceRecordDTO struct {
|
||||
Id int64 `json:"id" validate:"required"`
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
-- name: BatchInsertFinanceCategorySpace :copyfrom
|
||||
INSERT INTO finance_category_space (id, space_id, name, icon, type, sort_number,create_by,update_by)
|
||||
VALUES ($1, $2, $3, $4, $5, $6,$7,$8);
|
||||
VALUES ($1, $2, $3, $4, $5, $6,$7,$8);
|
||||
|
||||
-- name: ListFinanceCategories :many
|
||||
SELECT * FROM finance_category_space WHERE space_id = $1;
|
||||
|
||||
-- name: GetFinanceCategoryByName :one
|
||||
SELECT * FROM finance_category_space WHERE space_id = $1 AND name = $2 AND type = $3;
|
||||
|
||||
-- name: InsertFinanceCategory :exec
|
||||
INSERT INTO finance_category_space(id,space_id,name,icon,type,sort_number,create_by,update_by,create_time,update_time)
|
||||
values ($1,$2,$3,$4,$5,$6,$7,$8,NOW(),NOW());
|
||||
|
||||
-- name: BatchUpdateFinanceCategorySortNumber :batchexec
|
||||
UPDATE finance_category_space
|
||||
SET sort_number = $1,update_by = $2,update_time = NOW()
|
||||
WHERE id = $3;
|
||||
|
||||
-- name: DeleteFinanceCategory :exec
|
||||
DELETE FROM finance_category_space WHERE id = $1;
|
||||
|
||||
-- name: UpdateFinanceCategory :exec
|
||||
UPDATE finance_category_space
|
||||
SET name = $1,icon = $2,update_by = $3,update_time = NOW()
|
||||
WHERE id = $4;
|
||||
@@ -0,0 +1,40 @@
|
||||
-- name: ListFinanceRecords :many
|
||||
SELECT
|
||||
fr.*,
|
||||
su.member_name
|
||||
FROM finance_record fr
|
||||
LEFT JOIN space_member su
|
||||
ON fr.space_id = su.space_id
|
||||
AND fr.update_by = su.user_id
|
||||
WHERE
|
||||
fr.space_id = $1
|
||||
AND fr.record_time >= $2
|
||||
AND fr.record_time < $3
|
||||
AND (
|
||||
$4 = 0
|
||||
OR fr.category_id = $4
|
||||
)
|
||||
ORDER BY
|
||||
fr.record_time DESC,
|
||||
fr.create_time DESC;
|
||||
|
||||
-- name: InsertFinanceRecord :exec
|
||||
INSERT INTO finance_record(id,category_id,space_id,amount,record_time,remark,create_by,update_by,create_time,update_time)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NOW(),NOW());
|
||||
|
||||
-- name: UpdateFinanceRecord :exec
|
||||
UPDATE finance_record
|
||||
SET
|
||||
category_id = $2,
|
||||
amount = $3,
|
||||
remark = $4,
|
||||
record_time = $5,
|
||||
update_by = $6,
|
||||
update_time = NOW()
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: DeleteFinanceRecord :exec
|
||||
DELETE FROM finance_record WHERE id = $1;
|
||||
|
||||
-- name: DeleteFinanceRecordByCategoryId :exec
|
||||
DELETE FROM finance_record WHERE category_id = $1;
|
||||
@@ -16,6 +16,59 @@ var (
|
||||
ErrBatchAlreadyClosed = errors.New("batch already closed")
|
||||
)
|
||||
|
||||
const batchUpdateFinanceCategorySortNumber = `-- name: BatchUpdateFinanceCategorySortNumber :batchexec
|
||||
UPDATE finance_category_space
|
||||
SET sort_number = $1,update_by = $2,update_time = NOW()
|
||||
WHERE id = $3
|
||||
`
|
||||
|
||||
type BatchUpdateFinanceCategorySortNumberBatchResults struct {
|
||||
br pgx.BatchResults
|
||||
tot int
|
||||
closed bool
|
||||
}
|
||||
|
||||
type BatchUpdateFinanceCategorySortNumberParams struct {
|
||||
SortNumber int32
|
||||
UpdateBy int64
|
||||
ID int64
|
||||
}
|
||||
|
||||
func (q *Queries) BatchUpdateFinanceCategorySortNumber(ctx context.Context, arg []BatchUpdateFinanceCategorySortNumberParams) *BatchUpdateFinanceCategorySortNumberBatchResults {
|
||||
batch := &pgx.Batch{}
|
||||
for _, a := range arg {
|
||||
vals := []interface{}{
|
||||
a.SortNumber,
|
||||
a.UpdateBy,
|
||||
a.ID,
|
||||
}
|
||||
batch.Queue(batchUpdateFinanceCategorySortNumber, vals...)
|
||||
}
|
||||
br := q.db.SendBatch(ctx, batch)
|
||||
return &BatchUpdateFinanceCategorySortNumberBatchResults{br, len(arg), false}
|
||||
}
|
||||
|
||||
func (b *BatchUpdateFinanceCategorySortNumberBatchResults) Exec(f func(int, error)) {
|
||||
defer b.br.Close()
|
||||
for t := 0; t < b.tot; t++ {
|
||||
if b.closed {
|
||||
if f != nil {
|
||||
f(t, ErrBatchAlreadyClosed)
|
||||
}
|
||||
continue
|
||||
}
|
||||
_, err := b.br.Exec()
|
||||
if f != nil {
|
||||
f(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BatchUpdateFinanceCategorySortNumberBatchResults) Close() error {
|
||||
b.closed = true
|
||||
return b.br.Close()
|
||||
}
|
||||
|
||||
const batchUpdateSpaceSortNumber = `-- name: BatchUpdateSpaceSortNumber :batchexec
|
||||
UPDATE space_member
|
||||
SET sort_number = $1
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type BatchInsertFinanceCategorySpaceParams struct {
|
||||
ID int64
|
||||
SpaceID int64
|
||||
@@ -15,3 +19,128 @@ type BatchInsertFinanceCategorySpaceParams struct {
|
||||
CreateBy int64
|
||||
UpdateBy int64
|
||||
}
|
||||
|
||||
const deleteFinanceCategory = `-- name: DeleteFinanceCategory :exec
|
||||
DELETE FROM finance_category_space WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteFinanceCategory(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, deleteFinanceCategory, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const getFinanceCategoryByName = `-- name: GetFinanceCategoryByName :one
|
||||
SELECT id, space_id, name, icon, type, sort_number, create_by, create_time, update_by, update_time FROM finance_category_space WHERE space_id = $1 AND name = $2 AND type = $3
|
||||
`
|
||||
|
||||
type GetFinanceCategoryByNameParams struct {
|
||||
SpaceID int64
|
||||
Name string
|
||||
Type int16
|
||||
}
|
||||
|
||||
func (q *Queries) GetFinanceCategoryByName(ctx context.Context, arg GetFinanceCategoryByNameParams) (FinanceCategorySpace, error) {
|
||||
row := q.db.QueryRow(ctx, getFinanceCategoryByName, arg.SpaceID, arg.Name, arg.Type)
|
||||
var i FinanceCategorySpace
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.SpaceID,
|
||||
&i.Name,
|
||||
&i.Icon,
|
||||
&i.Type,
|
||||
&i.SortNumber,
|
||||
&i.CreateBy,
|
||||
&i.CreateTime,
|
||||
&i.UpdateBy,
|
||||
&i.UpdateTime,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const insertFinanceCategory = `-- name: InsertFinanceCategory :exec
|
||||
INSERT INTO finance_category_space(id,space_id,name,icon,type,sort_number,create_by,update_by,create_time,update_time)
|
||||
values ($1,$2,$3,$4,$5,$6,$7,$8,NOW(),NOW())
|
||||
`
|
||||
|
||||
type InsertFinanceCategoryParams struct {
|
||||
ID int64
|
||||
SpaceID int64
|
||||
Name string
|
||||
Icon string
|
||||
Type int16
|
||||
SortNumber int32
|
||||
CreateBy int64
|
||||
UpdateBy int64
|
||||
}
|
||||
|
||||
func (q *Queries) InsertFinanceCategory(ctx context.Context, arg InsertFinanceCategoryParams) error {
|
||||
_, err := q.db.Exec(ctx, insertFinanceCategory,
|
||||
arg.ID,
|
||||
arg.SpaceID,
|
||||
arg.Name,
|
||||
arg.Icon,
|
||||
arg.Type,
|
||||
arg.SortNumber,
|
||||
arg.CreateBy,
|
||||
arg.UpdateBy,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const listFinanceCategories = `-- name: ListFinanceCategories :many
|
||||
SELECT id, space_id, name, icon, type, sort_number, create_by, create_time, update_by, update_time FROM finance_category_space WHERE space_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) ListFinanceCategories(ctx context.Context, spaceID int64) ([]FinanceCategorySpace, error) {
|
||||
rows, err := q.db.Query(ctx, listFinanceCategories, spaceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []FinanceCategorySpace
|
||||
for rows.Next() {
|
||||
var i FinanceCategorySpace
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.SpaceID,
|
||||
&i.Name,
|
||||
&i.Icon,
|
||||
&i.Type,
|
||||
&i.SortNumber,
|
||||
&i.CreateBy,
|
||||
&i.CreateTime,
|
||||
&i.UpdateBy,
|
||||
&i.UpdateTime,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateFinanceCategory = `-- name: UpdateFinanceCategory :exec
|
||||
UPDATE finance_category_space
|
||||
SET name = $1,icon = $2,update_by = $3,update_time = NOW()
|
||||
WHERE id = $4
|
||||
`
|
||||
|
||||
type UpdateFinanceCategoryParams struct {
|
||||
Name string
|
||||
Icon string
|
||||
UpdateBy int64
|
||||
ID int64
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateFinanceCategory(ctx context.Context, arg UpdateFinanceCategoryParams) error {
|
||||
_, err := q.db.Exec(ctx, updateFinanceCategory,
|
||||
arg.Name,
|
||||
arg.Icon,
|
||||
arg.UpdateBy,
|
||||
arg.ID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
// source: finance_record.sql
|
||||
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const deleteFinanceRecord = `-- name: DeleteFinanceRecord :exec
|
||||
DELETE FROM finance_record WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteFinanceRecord(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, deleteFinanceRecord, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteFinanceRecordByCategoryId = `-- name: DeleteFinanceRecordByCategoryId :exec
|
||||
DELETE FROM finance_record WHERE category_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteFinanceRecordByCategoryId(ctx context.Context, categoryID int64) error {
|
||||
_, err := q.db.Exec(ctx, deleteFinanceRecordByCategoryId, categoryID)
|
||||
return err
|
||||
}
|
||||
|
||||
const insertFinanceRecord = `-- name: InsertFinanceRecord :exec
|
||||
INSERT INTO finance_record(id,category_id,space_id,amount,record_time,remark,create_by,update_by,create_time,update_time)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NOW(),NOW())
|
||||
`
|
||||
|
||||
type InsertFinanceRecordParams struct {
|
||||
ID int64
|
||||
CategoryID int64
|
||||
SpaceID int64
|
||||
Amount pgtype.Numeric
|
||||
RecordTime pgtype.Date
|
||||
Remark pgtype.Text
|
||||
CreateBy int64
|
||||
UpdateBy int64
|
||||
}
|
||||
|
||||
func (q *Queries) InsertFinanceRecord(ctx context.Context, arg InsertFinanceRecordParams) error {
|
||||
_, err := q.db.Exec(ctx, insertFinanceRecord,
|
||||
arg.ID,
|
||||
arg.CategoryID,
|
||||
arg.SpaceID,
|
||||
arg.Amount,
|
||||
arg.RecordTime,
|
||||
arg.Remark,
|
||||
arg.CreateBy,
|
||||
arg.UpdateBy,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const listFinanceRecords = `-- name: ListFinanceRecords :many
|
||||
SELECT
|
||||
fr.id, fr.category_id, fr.space_id, fr.amount, fr.remark, fr.record_time, fr.create_by, fr.create_time, fr.update_by, fr.update_time,
|
||||
su.member_name
|
||||
FROM finance_record fr
|
||||
LEFT JOIN space_member su
|
||||
ON fr.space_id = su.space_id
|
||||
AND fr.update_by = su.user_id
|
||||
WHERE
|
||||
fr.space_id = $1
|
||||
AND fr.record_time >= $2
|
||||
AND fr.record_time < $3
|
||||
AND (
|
||||
$4 = 0
|
||||
OR fr.category_id = $4
|
||||
)
|
||||
ORDER BY
|
||||
fr.record_time DESC,
|
||||
fr.create_time DESC
|
||||
`
|
||||
|
||||
type ListFinanceRecordsParams struct {
|
||||
SpaceID int64
|
||||
RecordTime pgtype.Date
|
||||
RecordTime_2 pgtype.Date
|
||||
Column4 interface{}
|
||||
}
|
||||
|
||||
type ListFinanceRecordsRow struct {
|
||||
ID int64
|
||||
CategoryID int64
|
||||
SpaceID int64
|
||||
Amount pgtype.Numeric
|
||||
Remark pgtype.Text
|
||||
RecordTime pgtype.Date
|
||||
CreateBy int64
|
||||
CreateTime pgtype.Timestamptz
|
||||
UpdateBy int64
|
||||
UpdateTime pgtype.Timestamptz
|
||||
MemberName pgtype.Text
|
||||
}
|
||||
|
||||
func (q *Queries) ListFinanceRecords(ctx context.Context, arg ListFinanceRecordsParams) ([]ListFinanceRecordsRow, error) {
|
||||
rows, err := q.db.Query(ctx, listFinanceRecords,
|
||||
arg.SpaceID,
|
||||
arg.RecordTime,
|
||||
arg.RecordTime_2,
|
||||
arg.Column4,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListFinanceRecordsRow
|
||||
for rows.Next() {
|
||||
var i ListFinanceRecordsRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.CategoryID,
|
||||
&i.SpaceID,
|
||||
&i.Amount,
|
||||
&i.Remark,
|
||||
&i.RecordTime,
|
||||
&i.CreateBy,
|
||||
&i.CreateTime,
|
||||
&i.UpdateBy,
|
||||
&i.UpdateTime,
|
||||
&i.MemberName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateFinanceRecord = `-- name: UpdateFinanceRecord :exec
|
||||
UPDATE finance_record
|
||||
SET
|
||||
category_id = $2,
|
||||
amount = $3,
|
||||
remark = $4,
|
||||
record_time = $5,
|
||||
update_by = $6,
|
||||
update_time = NOW()
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
type UpdateFinanceRecordParams struct {
|
||||
ID int64
|
||||
CategoryID int64
|
||||
Amount pgtype.Numeric
|
||||
Remark pgtype.Text
|
||||
RecordTime pgtype.Date
|
||||
UpdateBy int64
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateFinanceRecord(ctx context.Context, arg UpdateFinanceRecordParams) error {
|
||||
_, err := q.db.Exec(ctx, updateFinanceRecord,
|
||||
arg.ID,
|
||||
arg.CategoryID,
|
||||
arg.Amount,
|
||||
arg.Remark,
|
||||
arg.RecordTime,
|
||||
arg.UpdateBy,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -31,6 +31,19 @@ type FinanceCategorySpace struct {
|
||||
UpdateTime pgtype.Timestamptz
|
||||
}
|
||||
|
||||
type FinanceRecord struct {
|
||||
ID int64
|
||||
CategoryID int64
|
||||
SpaceID int64
|
||||
Amount pgtype.Numeric
|
||||
Remark pgtype.Text
|
||||
RecordTime pgtype.Date
|
||||
CreateBy int64
|
||||
CreateTime pgtype.Timestamptz
|
||||
UpdateBy int64
|
||||
UpdateTime pgtype.Timestamptz
|
||||
}
|
||||
|
||||
type Space struct {
|
||||
ID int64
|
||||
Name string
|
||||
|
||||
@@ -66,6 +66,7 @@ create table space_member
|
||||
unique (space_id, user_id)
|
||||
);
|
||||
|
||||
--记账分类默认表
|
||||
create table finance_category_default
|
||||
(
|
||||
id bigint not null
|
||||
@@ -78,6 +79,7 @@ create table finance_category_default
|
||||
update_time timestamp with time zone default now()
|
||||
);
|
||||
|
||||
--记账分类空间表
|
||||
create table finance_category_space
|
||||
(
|
||||
id bigint not null
|
||||
@@ -93,4 +95,19 @@ create table finance_category_space
|
||||
update_time timestamp with time zone default now()
|
||||
);
|
||||
|
||||
-- 记账记录表
|
||||
create table finance_record
|
||||
(
|
||||
id bigint not null
|
||||
primary key,
|
||||
category_id bigint not null,
|
||||
space_id bigint not null,
|
||||
amount numeric(12, 2) not null,
|
||||
remark varchar(255),
|
||||
record_time date,
|
||||
create_by bigint not null,
|
||||
create_time timestamp with time zone default now(),
|
||||
update_by bigint not null,
|
||||
update_time timestamp with time zone default now()
|
||||
);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package timex
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ParseTimeFlexible(value string) (*time.Time, error) {
|
||||
if value == "" {
|
||||
return nil, nil // ⭐ 空字符串 → 不限时间
|
||||
}
|
||||
|
||||
layouts := []string{
|
||||
"2006-01-02 15:04:05",
|
||||
"2006-01-02 15:04",
|
||||
"2006-01-02",
|
||||
"2006-01",
|
||||
time.RFC3339,
|
||||
}
|
||||
|
||||
for _, layout := range layouts {
|
||||
t, err := time.Parse(layout, value)
|
||||
if err == nil {
|
||||
return &t, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unsupported time format: %s", value)
|
||||
}
|
||||
Reference in new issue
Block a user