This commit is contained in:
oneao committed 2026-03-04 17:30:05 +08:00
1 parent 46106d0c76
commit 34240d2e16
36 files changed
+2853 -165

No files matched your search

+1
View File
@@ -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
View File
@@ -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, "更新成功")
}
@@ -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;
+53
View File
@@ -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
}
+13
View File
@@ -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
+17
View File
@@ -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)
}