From 6a8c31e20c4c8ea39da9739e3ef0ce4d53998965 Mon Sep 17 00:00:00 2001 From: ZhangAo Date: Fri, 30 Jan 2026 17:22:20 +0800 Subject: [PATCH] u --- .../handler/money/money_analysis_service.go | 105 +++++ code/allapp/allapp-go/biz/model/api/api.pb.go | 2 +- .../allapp-go/biz/model/money/money.pb.go | 193 +++++---- .../model/money/money_analysis_types.pb.go | 385 ++++++++++++++++++ .../model/money/money_category_types.pb.go | 2 +- .../biz/model/money/money_record_types.pb.go | 2 +- .../allapp-go/biz/router/middleware/auth.go | 1 + .../allapp-go/biz/router/money/middleware.go | 20 + .../allapp-go/biz/router/money/money.go | 5 + code/allapp/allapp-go/conf/conf.go | 1 + code/allapp/allapp-go/conf/dev/conf.yaml | 2 +- .../allapp-go/db/queries/money_record.sql | 57 ++- .../allapp-go/db/repo/money_record.sql.go | 132 ++++++ code/allapp/allapp-go/go.mod | 1 + code/allapp/allapp-go/go.sum | 2 + code/allapp/allapp-go/idl/money/money.proto | 10 + .../idl/money/money_analysis_types.proto | 27 ++ code/allapp/allapp-go/main.go | 37 ++ .../allapp-rn/src/app/(tabs)/_layout.tsx | 55 +-- .../money/components/TransactionsList.tsx | 236 ++++++----- .../allapp-rn/src/app/(tabs)/money/index.tsx | 1 - .../src/app/money/analysis/index.tsx | 238 +++++++++-- .../components/common/ao/DateRangePicker.tsx | 89 ++++ .../src/components/common/ao/index.ts | 5 +- .../src/request/api/money/analysis.ts | 13 + code/allapp/allapp-rn/src/request/index.ts | 4 +- .../allapp-rn/src/types/money/analysis.ts | 19 + code/allapp/allapp-rn/src/utils/time.ts | 14 + code/allapp/allapp-rn/test.html | 153 +++---- 29 files changed, 1454 insertions(+), 357 deletions(-) create mode 100644 code/allapp/allapp-go/biz/handler/money/money_analysis_service.go create mode 100644 code/allapp/allapp-go/biz/model/money/money_analysis_types.pb.go create mode 100644 code/allapp/allapp-go/idl/money/money_analysis_types.proto create mode 100644 code/allapp/allapp-rn/src/components/common/ao/DateRangePicker.tsx create mode 100644 code/allapp/allapp-rn/src/request/api/money/analysis.ts create mode 100644 code/allapp/allapp-rn/src/types/money/analysis.ts diff --git a/code/allapp/allapp-go/biz/handler/money/money_analysis_service.go b/code/allapp/allapp-go/biz/handler/money/money_analysis_service.go new file mode 100644 index 00000000..fad3afd0 --- /dev/null +++ b/code/allapp/allapp-go/biz/handler/money/money_analysis_service.go @@ -0,0 +1,105 @@ +// Code generated by hertz generator. + +package money + +import ( + money "allapp/biz/model/money" + "allapp/biz/router/middleware" + "allapp/db" + "allapp/db/repo" + "allapp/utils/errorx" + "allapp/utils/pgtypex" + "allapp/utils/response" + "context" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/protocol/consts" +) + +// AnalysisMoneyLine . +// @router /money/analysis/line [POST] +func AnalysisMoneyLine(ctx context.Context, c *app.RequestContext) { + var err error + var req money.AnalysisMoneyParams + err = c.BindAndValidate(&req) + if err != nil { + c.String(consts.StatusBadRequest, err.Error()) + return + } + + userID := middleware.GetUserID(ctx) + + analysis, err := db.Queries.ListMoneyRecordsByLineAnalysis(ctx, repo.ListMoneyRecordsByLineAnalysisParams{ + Column1: req.PeriodType, + UserID: userID, + RecordTime: pgtypex.StringToDate(req.StartDate), + RecordTime_2: pgtypex.StringToDate(req.EndDate), + Type: req.Type, + }) + + if err != nil { + errorx.AddError(c, err) + return + } + + // 循环赋值到响应数据中 + records := make([]*money.AnalysisMoneyAmount, 0, len(analysis)) + + for _, record := range analysis { + period, ok := record.Period.(string) + if !ok { + period = "" + } + + // 创建指向 AnalysisAmount 的指针 + records = append(records, &money.AnalysisMoneyAmount{ + X: period, + Y: pgtypex.NumericToString(record.TotalAmount), + }) + } + + response.Success(c).Data(&money.AnalysisMoneyLineResult{ + Records: records, + }).Send() +} + +// AnalysisMoneyPie . +// @router /money/analysis/pie [POST] +func AnalysisMoneyPie(ctx context.Context, c *app.RequestContext) { + var err error + var req money.AnalysisMoneyParams + err = c.BindAndValidate(&req) + if err != nil { + c.String(consts.StatusBadRequest, err.Error()) + return + } + + userID := middleware.GetUserID(ctx) + + analysis, err := db.Queries.ListMoneyRecordsByPieAnalysis(ctx, repo.ListMoneyRecordsByPieAnalysisParams{ + UserID: userID, + RecordTime: pgtypex.StringToDate(req.StartDate), + RecordTime_2: pgtypex.StringToDate(req.EndDate), + Type: req.Type, + }) + + if err != nil { + errorx.AddError(c, err) + return + } + + // 使用值类型而不是指针类型 + records := make([]*money.AnalysisMoneyAmount, 0, len(analysis)) + + for _, record := range analysis { + // 直接赋值而不是使用指针 + records = append(records, &money.AnalysisMoneyAmount{ + X: record.Name.String, + Y: pgtypex.NumericToString(record.TotalAmount), + }) + } + + response.Success(c).Data(&money.AnalysisMoneyPieResult{ + Records: records, + }).Send() +} diff --git a/code/allapp/allapp-go/biz/model/api/api.pb.go b/code/allapp/allapp-go/biz/model/api/api.pb.go index ff03c0ce..d82e6a07 100644 --- a/code/allapp/allapp-go/biz/model/api/api.pb.go +++ b/code/allapp/allapp-go/biz/model/api/api.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: api.proto package api diff --git a/code/allapp/allapp-go/biz/model/money/money.pb.go b/code/allapp/allapp-go/biz/model/money/money.pb.go index 156195a7..0d4655f8 100644 --- a/code/allapp/allapp-go/biz/model/money/money.pb.go +++ b/code/allapp/allapp-go/biz/model/money/money.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: money.proto package money @@ -29,74 +29,91 @@ var file_money_proto_rawDesc = []byte{ 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x32, 0xcb, 0x04, 0x0a, 0x14, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, - 0x6f, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x56, 0x0a, 0x04, 0x4c, 0x69, - 0x73, 0x74, 0x12, 0x1b, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, - 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x1a, - 0x1c, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x6e, 0x65, - 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x22, 0x13, 0xca, - 0xc1, 0x18, 0x0f, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, - 0x72, 0x79, 0x12, 0x74, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, - 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e, - 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, - 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, - 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, - 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1a, 0xd2, 0xc1, - 0x18, 0x16, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, - 0x79, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, + 0x6f, 0x1a, 0x20, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x5f, 0x61, + 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x32, 0xcb, 0x04, 0x0a, 0x14, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x56, 0x0a, 0x04, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1b, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, + 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, + 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x22, + 0x13, 0xca, 0xc1, 0x18, 0x0f, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x63, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x79, 0x12, 0x74, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, + 0x1d, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, + 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x1e, + 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, + 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1a, + 0xd2, 0xc1, 0x18, 0x16, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x63, 0x61, 0x74, 0x65, 0x67, + 0x6f, 0x72, 0x79, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x17, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, + 0x72, 0x79, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, + 0x72, 0x79, 0x53, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, + 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x53, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1e, 0xd2, + 0xc1, 0x18, 0x1a, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, + 0x72, 0x79, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x70, 0x0a, + 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x53, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x53, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, - 0x6f, 0x72, 0x79, 0x53, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1e, 0xd2, 0xc1, 0x18, - 0x1a, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x70, 0x0a, 0x13, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, - 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, - 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x22, 0x1a, 0xd2, 0xc1, 0x18, 0x16, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x63, 0x61, - 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x70, 0x0a, - 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, - 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1a, 0xd2, 0xc1, 0x18, 0x16, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, - 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x32, - 0xc7, 0x03, 0x0a, 0x12, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x64, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, - 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x6f, 0x6e, - 0x65, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1d, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, - 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x12, 0xd2, 0xc1, 0x18, 0x0e, 0x2f, 0x6d, - 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x6d, 0x0a, 0x11, - 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, + 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, + 0x70, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, + 0x72, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1a, 0xd2, 0xc1, 0x18, 0x16, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, + 0x79, 0x2f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x32, 0xc7, 0x03, 0x0a, 0x12, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x64, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, + 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1d, 0x2e, 0x6d, + 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1d, 0x2e, 0x6d, 0x6f, + 0x6e, 0x65, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x12, 0xd2, 0xc1, 0x18, 0x0e, + 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x6d, + 0x0a, 0x11, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x49, 0x6e, 0x73, 0x65, + 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x49, 0x6e, 0x73, 0x65, + 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x22, 0x18, 0xd2, 0xc1, 0x18, 0x14, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, + 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2f, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x12, 0x6d, 0x0a, + 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x22, 0x18, 0xd2, 0xc1, 0x18, 0x14, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x72, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x6d, 0x0a, 0x11, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, + 0x73, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x18, 0xd2, 0xc1, 0x18, 0x14, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x72, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x2f, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x12, 0x6d, 0x0a, 0x11, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x12, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, - 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, - 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x22, 0x18, 0xd2, 0xc1, 0x18, 0x14, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x72, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x6d, 0x0a, 0x11, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, - 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, - 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, - 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, - 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, - 0x18, 0xd2, 0xc1, 0x18, 0x14, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x18, 0x5a, 0x16, 0x61, 0x6c, 0x6c, - 0x61, 0x70, 0x70, 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x6d, 0x6f, - 0x6e, 0x65, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x6f, 0x72, 0x64, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x32, 0xe9, 0x01, 0x0a, 0x14, + 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x11, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, + 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x1a, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, + 0x79, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1e, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x41, 0x6e, + 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x4c, 0x69, 0x6e, 0x65, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x18, 0xd2, 0xc1, 0x18, 0x14, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, + 0x79, 0x2f, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x2f, 0x6c, 0x69, 0x6e, 0x65, 0x12, + 0x66, 0x0a, 0x10, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x4d, 0x6f, 0x6e, 0x65, 0x79, + 0x50, 0x69, 0x65, 0x12, 0x1a, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x41, 0x6e, 0x61, 0x6c, + 0x79, 0x73, 0x69, 0x73, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, + 0x1d, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, + 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x50, 0x69, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x17, + 0xd2, 0xc1, 0x18, 0x13, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x61, 0x6e, 0x61, 0x6c, 0x79, + 0x73, 0x69, 0x73, 0x2f, 0x70, 0x69, 0x65, 0x42, 0x18, 0x5a, 0x16, 0x61, 0x6c, 0x6c, 0x61, 0x70, + 0x70, 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, + 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_money_proto_goTypes = []interface{}{ @@ -109,15 +126,18 @@ var file_money_proto_goTypes = []interface{}{ (*InsertMoneyRecordParams)(nil), // 6: money.InsertMoneyRecordParams (*UpdateMoneyRecordParams)(nil), // 7: money.UpdateMoneyRecordParams (*DeleteMoneyRecordParams)(nil), // 8: money.DeleteMoneyRecordParams - (*ListMoneyCategoryResp)(nil), // 9: money.ListMoneyCategoryResp - (*DeleteMoneyCategoryResp)(nil), // 10: money.DeleteMoneyCategoryResp - (*UpdateMoneyCategorySortResp)(nil), // 11: money.UpdateMoneyCategorySortResp - (*CreateMoneyCategoryResp)(nil), // 12: money.CreateMoneyCategoryResp - (*UpdateMoneyCategoryResp)(nil), // 13: money.UpdateMoneyCategoryResp - (*ListMoneyRecordsResult)(nil), // 14: money.ListMoneyRecordsResult - (*InsertMoneyRecordResult)(nil), // 15: money.InsertMoneyRecordResult - (*UpdateMoneyRecordResult)(nil), // 16: money.UpdateMoneyRecordResult - (*DeleteMoneyRecordResult)(nil), // 17: money.DeleteMoneyRecordResult + (*AnalysisMoneyParams)(nil), // 9: money.AnalysisMoneyParams + (*ListMoneyCategoryResp)(nil), // 10: money.ListMoneyCategoryResp + (*DeleteMoneyCategoryResp)(nil), // 11: money.DeleteMoneyCategoryResp + (*UpdateMoneyCategorySortResp)(nil), // 12: money.UpdateMoneyCategorySortResp + (*CreateMoneyCategoryResp)(nil), // 13: money.CreateMoneyCategoryResp + (*UpdateMoneyCategoryResp)(nil), // 14: money.UpdateMoneyCategoryResp + (*ListMoneyRecordsResult)(nil), // 15: money.ListMoneyRecordsResult + (*InsertMoneyRecordResult)(nil), // 16: money.InsertMoneyRecordResult + (*UpdateMoneyRecordResult)(nil), // 17: money.UpdateMoneyRecordResult + (*DeleteMoneyRecordResult)(nil), // 18: money.DeleteMoneyRecordResult + (*AnalysisMoneyLineResult)(nil), // 19: money.AnalysisMoneyLineResult + (*AnalysisMoneyPieResult)(nil), // 20: money.AnalysisMoneyPieResult } var file_money_proto_depIdxs = []int32{ 0, // 0: money.MoneyCategoryService.List:input_type -> money.ListMoneyCategoryReq @@ -129,17 +149,21 @@ var file_money_proto_depIdxs = []int32{ 6, // 6: money.MoneyRecordService.InsertMoneyRecord:input_type -> money.InsertMoneyRecordParams 7, // 7: money.MoneyRecordService.UpdateMoneyRecord:input_type -> money.UpdateMoneyRecordParams 8, // 8: money.MoneyRecordService.DeleteMoneyRecord:input_type -> money.DeleteMoneyRecordParams - 9, // 9: money.MoneyCategoryService.List:output_type -> money.ListMoneyCategoryResp - 10, // 10: money.MoneyCategoryService.DeleteUserMoneyCategory:output_type -> money.DeleteMoneyCategoryResp - 11, // 11: money.MoneyCategoryService.UpdateMoneyCategorySort:output_type -> money.UpdateMoneyCategorySortResp - 12, // 12: money.MoneyCategoryService.CreateMoneyCategory:output_type -> money.CreateMoneyCategoryResp - 13, // 13: money.MoneyCategoryService.UpdateMoneyCategory:output_type -> money.UpdateMoneyCategoryResp - 14, // 14: money.MoneyRecordService.ListMoneyRecords:output_type -> money.ListMoneyRecordsResult - 15, // 15: money.MoneyRecordService.InsertMoneyRecord:output_type -> money.InsertMoneyRecordResult - 16, // 16: money.MoneyRecordService.UpdateMoneyRecord:output_type -> money.UpdateMoneyRecordResult - 17, // 17: money.MoneyRecordService.DeleteMoneyRecord:output_type -> money.DeleteMoneyRecordResult - 9, // [9:18] is the sub-list for method output_type - 0, // [0:9] is the sub-list for method input_type + 9, // 9: money.MoneyAnalysisService.AnalysisMoneyLine:input_type -> money.AnalysisMoneyParams + 9, // 10: money.MoneyAnalysisService.AnalysisMoneyPie:input_type -> money.AnalysisMoneyParams + 10, // 11: money.MoneyCategoryService.List:output_type -> money.ListMoneyCategoryResp + 11, // 12: money.MoneyCategoryService.DeleteUserMoneyCategory:output_type -> money.DeleteMoneyCategoryResp + 12, // 13: money.MoneyCategoryService.UpdateMoneyCategorySort:output_type -> money.UpdateMoneyCategorySortResp + 13, // 14: money.MoneyCategoryService.CreateMoneyCategory:output_type -> money.CreateMoneyCategoryResp + 14, // 15: money.MoneyCategoryService.UpdateMoneyCategory:output_type -> money.UpdateMoneyCategoryResp + 15, // 16: money.MoneyRecordService.ListMoneyRecords:output_type -> money.ListMoneyRecordsResult + 16, // 17: money.MoneyRecordService.InsertMoneyRecord:output_type -> money.InsertMoneyRecordResult + 17, // 18: money.MoneyRecordService.UpdateMoneyRecord:output_type -> money.UpdateMoneyRecordResult + 18, // 19: money.MoneyRecordService.DeleteMoneyRecord:output_type -> money.DeleteMoneyRecordResult + 19, // 20: money.MoneyAnalysisService.AnalysisMoneyLine:output_type -> money.AnalysisMoneyLineResult + 20, // 21: money.MoneyAnalysisService.AnalysisMoneyPie:output_type -> money.AnalysisMoneyPieResult + 11, // [11:22] is the sub-list for method output_type + 0, // [0:11] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name @@ -152,6 +176,7 @@ func file_money_proto_init() { } file_money_money_category_types_proto_init() file_money_money_record_types_proto_init() + file_money_money_analysis_types_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ @@ -160,7 +185,7 @@ func file_money_proto_init() { NumEnums: 0, NumMessages: 0, NumExtensions: 0, - NumServices: 2, + NumServices: 3, }, GoTypes: file_money_proto_goTypes, DependencyIndexes: file_money_proto_depIdxs, diff --git a/code/allapp/allapp-go/biz/model/money/money_analysis_types.pb.go b/code/allapp/allapp-go/biz/model/money/money_analysis_types.pb.go new file mode 100644 index 00000000..8f77324b --- /dev/null +++ b/code/allapp/allapp-go/biz/model/money/money_analysis_types.pb.go @@ -0,0 +1,385 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v4.25.3 +// source: money/money_analysis_types.proto + +package money + +import ( + _ "allapp/biz/model/api" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type AnalysisMoneyParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StartDate string `protobuf:"bytes,1,opt,name=StartDate,proto3" form:"start_date" json:"start_date"` // 开始时间 + EndDate string `protobuf:"bytes,2,opt,name=EndDate,proto3" form:"end_date" json:"end_date"` // 结束时间 + Type int32 `protobuf:"varint,3,opt,name=Type,proto3" form:"type" json:"type"` // 0 支出 1 收入 + PeriodType int32 `protobuf:"varint,4,opt,name=PeriodType,proto3" form:"period_type" json:"period_type"` // 0 = 日分析, 1 = 月分析, 2 = 年分析 +} + +func (x *AnalysisMoneyParams) Reset() { + *x = AnalysisMoneyParams{} + if protoimpl.UnsafeEnabled { + mi := &file_money_money_analysis_types_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AnalysisMoneyParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AnalysisMoneyParams) ProtoMessage() {} + +func (x *AnalysisMoneyParams) ProtoReflect() protoreflect.Message { + mi := &file_money_money_analysis_types_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AnalysisMoneyParams.ProtoReflect.Descriptor instead. +func (*AnalysisMoneyParams) Descriptor() ([]byte, []int) { + return file_money_money_analysis_types_proto_rawDescGZIP(), []int{0} +} + +func (x *AnalysisMoneyParams) GetStartDate() string { + if x != nil { + return x.StartDate + } + return "" +} + +func (x *AnalysisMoneyParams) GetEndDate() string { + if x != nil { + return x.EndDate + } + return "" +} + +func (x *AnalysisMoneyParams) GetType() int32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *AnalysisMoneyParams) GetPeriodType() int32 { + if x != nil { + return x.PeriodType + } + return 0 +} + +// PeriodAmount 用于存储按天、月、年汇总的金额 +type AnalysisMoneyAmount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + X string `protobuf:"bytes,1,opt,name=X,proto3" form:"x" json:"x"` // 时间段(按天、月、年) + Y string `protobuf:"bytes,2,opt,name=Y,proto3" form:"y" json:"y"` // 汇总金额 +} + +func (x *AnalysisMoneyAmount) Reset() { + *x = AnalysisMoneyAmount{} + if protoimpl.UnsafeEnabled { + mi := &file_money_money_analysis_types_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AnalysisMoneyAmount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AnalysisMoneyAmount) ProtoMessage() {} + +func (x *AnalysisMoneyAmount) ProtoReflect() protoreflect.Message { + mi := &file_money_money_analysis_types_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AnalysisMoneyAmount.ProtoReflect.Descriptor instead. +func (*AnalysisMoneyAmount) Descriptor() ([]byte, []int) { + return file_money_money_analysis_types_proto_rawDescGZIP(), []int{1} +} + +func (x *AnalysisMoneyAmount) GetX() string { + if x != nil { + return x.X + } + return "" +} + +func (x *AnalysisMoneyAmount) GetY() string { + if x != nil { + return x.Y + } + return "" +} + +type AnalysisMoneyLineResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Records []*AnalysisMoneyAmount `protobuf:"bytes,1,rep,name=Records,proto3" form:"records" json:"records"` +} + +func (x *AnalysisMoneyLineResult) Reset() { + *x = AnalysisMoneyLineResult{} + if protoimpl.UnsafeEnabled { + mi := &file_money_money_analysis_types_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AnalysisMoneyLineResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AnalysisMoneyLineResult) ProtoMessage() {} + +func (x *AnalysisMoneyLineResult) ProtoReflect() protoreflect.Message { + mi := &file_money_money_analysis_types_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AnalysisMoneyLineResult.ProtoReflect.Descriptor instead. +func (*AnalysisMoneyLineResult) Descriptor() ([]byte, []int) { + return file_money_money_analysis_types_proto_rawDescGZIP(), []int{2} +} + +func (x *AnalysisMoneyLineResult) GetRecords() []*AnalysisMoneyAmount { + if x != nil { + return x.Records + } + return nil +} + +type AnalysisMoneyPieResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Records []*AnalysisMoneyAmount `protobuf:"bytes,1,rep,name=Records,proto3" form:"records" json:"records"` +} + +func (x *AnalysisMoneyPieResult) Reset() { + *x = AnalysisMoneyPieResult{} + if protoimpl.UnsafeEnabled { + mi := &file_money_money_analysis_types_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AnalysisMoneyPieResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AnalysisMoneyPieResult) ProtoMessage() {} + +func (x *AnalysisMoneyPieResult) ProtoReflect() protoreflect.Message { + mi := &file_money_money_analysis_types_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AnalysisMoneyPieResult.ProtoReflect.Descriptor instead. +func (*AnalysisMoneyPieResult) Descriptor() ([]byte, []int) { + return file_money_money_analysis_types_proto_rawDescGZIP(), []int{3} +} + +func (x *AnalysisMoneyPieResult) GetRecords() []*AnalysisMoneyAmount { + if x != nil { + return x.Records + } + return nil +} + +var File_money_money_analysis_types_proto protoreflect.FileDescriptor + +var file_money_money_analysis_types_proto_rawDesc = []byte{ + 0x0a, 0x20, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x5f, 0x61, 0x6e, + 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x05, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x1a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xba, 0x01, 0x0a, 0x13, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, + 0x73, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2c, 0x0a, 0x09, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x0e, 0xca, 0xbb, 0x18, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x07, 0x45, 0x6e, + 0x64, 0x44, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0c, 0xca, 0xbb, 0x18, + 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x52, 0x07, 0x45, 0x6e, 0x64, 0x44, 0x61, + 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, + 0x42, 0x08, 0xca, 0xbb, 0x18, 0x04, 0x74, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x2f, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, + 0x65, 0x22, 0x3f, 0x0a, 0x13, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x4d, 0x6f, 0x6e, + 0x65, 0x79, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x01, 0x58, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x05, 0xca, 0xbb, 0x18, 0x01, 0x78, 0x52, 0x01, 0x58, 0x12, 0x13, 0x0a, + 0x01, 0x59, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x05, 0xca, 0xbb, 0x18, 0x01, 0x79, 0x52, + 0x01, 0x59, 0x22, 0x5c, 0x0a, 0x17, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x4d, 0x6f, + 0x6e, 0x65, 0x79, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41, 0x0a, + 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x4d, + 0x6f, 0x6e, 0x65, 0x79, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, + 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, + 0x22, 0x5b, 0x0a, 0x16, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x4d, 0x6f, 0x6e, 0x65, + 0x79, 0x50, 0x69, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41, 0x0a, 0x07, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x6f, + 0x6e, 0x65, 0x79, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x4d, 0x6f, 0x6e, 0x65, + 0x79, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x72, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x73, 0x52, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x42, 0x18, 0x5a, + 0x16, 0x61, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_money_money_analysis_types_proto_rawDescOnce sync.Once + file_money_money_analysis_types_proto_rawDescData = file_money_money_analysis_types_proto_rawDesc +) + +func file_money_money_analysis_types_proto_rawDescGZIP() []byte { + file_money_money_analysis_types_proto_rawDescOnce.Do(func() { + file_money_money_analysis_types_proto_rawDescData = protoimpl.X.CompressGZIP(file_money_money_analysis_types_proto_rawDescData) + }) + return file_money_money_analysis_types_proto_rawDescData +} + +var file_money_money_analysis_types_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_money_money_analysis_types_proto_goTypes = []interface{}{ + (*AnalysisMoneyParams)(nil), // 0: money.AnalysisMoneyParams + (*AnalysisMoneyAmount)(nil), // 1: money.AnalysisMoneyAmount + (*AnalysisMoneyLineResult)(nil), // 2: money.AnalysisMoneyLineResult + (*AnalysisMoneyPieResult)(nil), // 3: money.AnalysisMoneyPieResult +} +var file_money_money_analysis_types_proto_depIdxs = []int32{ + 1, // 0: money.AnalysisMoneyLineResult.Records:type_name -> money.AnalysisMoneyAmount + 1, // 1: money.AnalysisMoneyPieResult.Records:type_name -> money.AnalysisMoneyAmount + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_money_money_analysis_types_proto_init() } +func file_money_money_analysis_types_proto_init() { + if File_money_money_analysis_types_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_money_money_analysis_types_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AnalysisMoneyParams); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_money_money_analysis_types_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AnalysisMoneyAmount); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_money_money_analysis_types_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AnalysisMoneyLineResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_money_money_analysis_types_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AnalysisMoneyPieResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_money_money_analysis_types_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_money_money_analysis_types_proto_goTypes, + DependencyIndexes: file_money_money_analysis_types_proto_depIdxs, + MessageInfos: file_money_money_analysis_types_proto_msgTypes, + }.Build() + File_money_money_analysis_types_proto = out.File + file_money_money_analysis_types_proto_rawDesc = nil + file_money_money_analysis_types_proto_goTypes = nil + file_money_money_analysis_types_proto_depIdxs = nil +} diff --git a/code/allapp/allapp-go/biz/model/money/money_category_types.pb.go b/code/allapp/allapp-go/biz/model/money/money_category_types.pb.go index b101f19b..2332296b 100644 --- a/code/allapp/allapp-go/biz/model/money/money_category_types.pb.go +++ b/code/allapp/allapp-go/biz/model/money/money_category_types.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: money/money_category_types.proto package money diff --git a/code/allapp/allapp-go/biz/model/money/money_record_types.pb.go b/code/allapp/allapp-go/biz/model/money/money_record_types.pb.go index 54e9284a..2346f529 100644 --- a/code/allapp/allapp-go/biz/model/money/money_record_types.pb.go +++ b/code/allapp/allapp-go/biz/model/money/money_record_types.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v6.33.1 +// protoc v4.25.3 // source: money/money_record_types.proto package money diff --git a/code/allapp/allapp-go/biz/router/middleware/auth.go b/code/allapp/allapp-go/biz/router/middleware/auth.go index e771bd8a..2e7ba416 100644 --- a/code/allapp/allapp-go/biz/router/middleware/auth.go +++ b/code/allapp/allapp-go/biz/router/middleware/auth.go @@ -25,6 +25,7 @@ func Auth() app.HandlerFunc { "/auth/login", "/auth/register", "/auth/refresh/token", + "/ws", } return func(ctx context.Context, c *app.RequestContext) { diff --git a/code/allapp/allapp-go/biz/router/money/middleware.go b/code/allapp/allapp-go/biz/router/money/middleware.go index 20037ede..e2aa91c8 100644 --- a/code/allapp/allapp-go/biz/router/money/middleware.go +++ b/code/allapp/allapp-go/biz/router/money/middleware.go @@ -80,3 +80,23 @@ func _listmoneyrecordsMw() []app.HandlerFunc { // your code... return nil } + +func _analysismoneyMw() []app.HandlerFunc { + // your code... + return nil +} + +func _analysisMw() []app.HandlerFunc { + // your code... + return nil +} + +func _analysismoneylineMw() []app.HandlerFunc { + // your code... + return nil +} + +func _analysismoneypieMw() []app.HandlerFunc { + // your code... + return nil +} diff --git a/code/allapp/allapp-go/biz/router/money/money.go b/code/allapp/allapp-go/biz/router/money/money.go index e0e2f526..6958d041 100644 --- a/code/allapp/allapp-go/biz/router/money/money.go +++ b/code/allapp/allapp-go/biz/router/money/money.go @@ -26,6 +26,11 @@ func Register(r *server.Hertz) { _category.POST("/update", append(_updatemoneycategoryMw(), money.UpdateMoneyCategory)...) _category.POST("/updateSort", append(_updatemoneycategorysortMw(), money.UpdateMoneyCategorySort)...) _money.POST("/records", append(_listmoneyrecordsMw(), money.ListMoneyRecords)...) + { + _analysis := _money.Group("/analysis", _analysisMw()...) + _analysis.POST("/line", append(_analysismoneylineMw(), money.AnalysisMoneyLine)...) + _analysis.POST("/pie", append(_analysismoneypieMw(), money.AnalysisMoneyPie)...) + } { _record := _money.Group("/record", _recordMw()...) _record.POST("/delete", append(_deletemoneyrecordMw(), money.DeleteMoneyRecord)...) diff --git a/code/allapp/allapp-go/conf/conf.go b/code/allapp/allapp-go/conf/conf.go index 119792bb..d5a08a73 100644 --- a/code/allapp/allapp-go/conf/conf.go +++ b/code/allapp/allapp-go/conf/conf.go @@ -29,6 +29,7 @@ type Config struct { type ServerConfig struct { Port string `mapstructure:"port" yaml:"port"` BaseUrl string `mapstructure:"base_url" yaml:"base_url"` // 下划线 + WsUrl string `mapstructure:"ws_url" yaml:"ws_url"` } type JwtConfig struct { diff --git a/code/allapp/allapp-go/conf/dev/conf.yaml b/code/allapp/allapp-go/conf/dev/conf.yaml index c362dfd1..e484e13d 100644 --- a/code/allapp/allapp-go/conf/dev/conf.yaml +++ b/code/allapp/allapp-go/conf/dev/conf.yaml @@ -1,7 +1,7 @@ server: port: 8086 base_url: /app - + ws_url: /ws jwt: secret: 3Bde3BGEbYqtqyEUzW3ry8jKFcaPH17fRmTmqE7MDr05Lwj95uruRKrrkb44TJ4s access_expiry: -1 diff --git a/code/allapp/allapp-go/db/queries/money_record.sql b/code/allapp/allapp-go/db/queries/money_record.sql index d539cca2..73f940b2 100644 --- a/code/allapp/allapp-go/db/queries/money_record.sql +++ b/code/allapp/allapp-go/db/queries/money_record.sql @@ -52,4 +52,59 @@ RETURNING *; DELETE FROM money_record WHERE id = $1; -- name: DeleteMoneyRecordByCategoryId :exec -DELETE FROM money_record WHERE user_id = $1 AND category_id = $2; \ No newline at end of file +DELETE FROM money_record WHERE user_id = $1 AND category_id = $2; + +-- 折线图:按天、月、年汇总金额 +-- name: ListMoneyRecordsByLineAnalysis :many +SELECT + CASE + WHEN $1 = 0 THEN to_char(mr.record_time, 'DD') -- 日分析,转换为文本 + WHEN $1 = 1 THEN to_char(mr.record_time, 'MM') -- 月分析,转换为文本 + WHEN $1 = 2 THEN to_char(mr.record_time, 'YYYY') -- 年分析,转换为文本 + END AS period, + SUM(mr.amount)::DECIMAL AS total_amount +FROM + money_record mr + LEFT JOIN + money_user_category muc ON mr.category_id = muc.id -- 连接 money_user_category 获取 type + LEFT JOIN + space_user su ON su.user_id = $2 -- 连接 space_user 表,查找该用户在空间中的信息 + LEFT JOIN + space s ON s.id = su.space_id -- 连接 space 表,获取空间信息 +WHERE + ( + (su.user_id IS NOT NULL) -- 用户在空间,查询该空间内所有人的数据 + OR (mr.user_id = $1) -- 用户不在空间,查询该用户个人的账本数据 + ) + AND mr.record_time BETWEEN $3 AND $4 -- 时间范围 + AND muc.type = $5 -- 收入或支出类型 +GROUP BY + period +ORDER BY + period; + + +-- 饼图:按类别汇总金额 +-- name: ListMoneyRecordsByPieAnalysis :many +SELECT + muc.name, + SUM(mr.amount)::DECIMAL AS total_amount +FROM + money_record mr + LEFT JOIN + money_user_category muc ON mr.category_id = muc.id + LEFT JOIN + space_user su ON su.user_id = $1 -- 连接 space_user 表,查找该用户在空间中的信息 + LEFT JOIN + space s ON s.id = su.space_id -- 连接 space 表,获取空间信息 +WHERE + ( + (su.user_id IS NOT NULL) -- 用户在空间,查询该空间内所有人的数据 + OR (mr.user_id = $1) -- 用户不在空间,查询该用户个人的账本数据 + ) + AND mr.record_time BETWEEN $2 AND $3 -- 时间范围 + AND muc.type = $4 -- 收入或支出类型 +GROUP BY + muc.name +ORDER BY + total_amount DESC; diff --git a/code/allapp/allapp-go/db/repo/money_record.sql.go b/code/allapp/allapp-go/db/repo/money_record.sql.go index 65ec8e1e..838cdac7 100644 --- a/code/allapp/allapp-go/db/repo/money_record.sql.go +++ b/code/allapp/allapp-go/db/repo/money_record.sql.go @@ -160,6 +160,138 @@ func (q *Queries) ListMoneyRecords(ctx context.Context, arg ListMoneyRecordsPara return items, nil } +const listMoneyRecordsByLineAnalysis = `-- name: ListMoneyRecordsByLineAnalysis :many +SELECT + CASE + WHEN $1 = 0 THEN to_char(mr.record_time, 'DD') -- 日分析,转换为文本 + WHEN $1 = 1 THEN to_char(mr.record_time, 'MM') -- 月分析,转换为文本 + WHEN $1 = 2 THEN to_char(mr.record_time, 'YYYY') -- 年分析,转换为文本 + END AS period, + SUM(mr.amount)::DECIMAL AS total_amount +FROM + money_record mr + LEFT JOIN + money_user_category muc ON mr.category_id = muc.id -- 连接 money_user_category 获取 type + LEFT JOIN + space_user su ON su.user_id = $2 -- 连接 space_user 表,查找该用户在空间中的信息 + LEFT JOIN + space s ON s.id = su.space_id -- 连接 space 表,获取空间信息 +WHERE + ( + (su.user_id IS NOT NULL) -- 用户在空间,查询该空间内所有人的数据 + OR (mr.user_id = $1) -- 用户不在空间,查询该用户个人的账本数据 + ) + AND mr.record_time BETWEEN $3 AND $4 -- 时间范围 + AND muc.type = $5 -- 收入或支出类型 +GROUP BY + period +ORDER BY + period +` + +type ListMoneyRecordsByLineAnalysisParams struct { + Column1 interface{} + UserID int64 + RecordTime pgtype.Date + RecordTime_2 pgtype.Date + Type int32 +} + +type ListMoneyRecordsByLineAnalysisRow struct { + Period interface{} + TotalAmount pgtype.Numeric +} + +// 折线图:按天、月、年汇总金额 +func (q *Queries) ListMoneyRecordsByLineAnalysis(ctx context.Context, arg ListMoneyRecordsByLineAnalysisParams) ([]ListMoneyRecordsByLineAnalysisRow, error) { + rows, err := q.db.Query(ctx, listMoneyRecordsByLineAnalysis, + arg.Column1, + arg.UserID, + arg.RecordTime, + arg.RecordTime_2, + arg.Type, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListMoneyRecordsByLineAnalysisRow + for rows.Next() { + var i ListMoneyRecordsByLineAnalysisRow + if err := rows.Scan(&i.Period, &i.TotalAmount); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listMoneyRecordsByPieAnalysis = `-- name: ListMoneyRecordsByPieAnalysis :many +SELECT + muc.name, + SUM(mr.amount)::DECIMAL AS total_amount +FROM + money_record mr + LEFT JOIN + money_user_category muc ON mr.category_id = muc.id + LEFT JOIN + space_user su ON su.user_id = $1 -- 连接 space_user 表,查找该用户在空间中的信息 + LEFT JOIN + space s ON s.id = su.space_id -- 连接 space 表,获取空间信息 +WHERE + ( + (su.user_id IS NOT NULL) -- 用户在空间,查询该空间内所有人的数据 + OR (mr.user_id = $1) -- 用户不在空间,查询该用户个人的账本数据 + ) + AND mr.record_time BETWEEN $2 AND $3 -- 时间范围 + AND muc.type = $4 -- 收入或支出类型 +GROUP BY + muc.name +ORDER BY + total_amount DESC +` + +type ListMoneyRecordsByPieAnalysisParams struct { + UserID int64 + RecordTime pgtype.Date + RecordTime_2 pgtype.Date + Type int32 +} + +type ListMoneyRecordsByPieAnalysisRow struct { + Name pgtype.Text + TotalAmount pgtype.Numeric +} + +// 饼图:按类别汇总金额 +func (q *Queries) ListMoneyRecordsByPieAnalysis(ctx context.Context, arg ListMoneyRecordsByPieAnalysisParams) ([]ListMoneyRecordsByPieAnalysisRow, error) { + rows, err := q.db.Query(ctx, listMoneyRecordsByPieAnalysis, + arg.UserID, + arg.RecordTime, + arg.RecordTime_2, + arg.Type, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListMoneyRecordsByPieAnalysisRow + for rows.Next() { + var i ListMoneyRecordsByPieAnalysisRow + if err := rows.Scan(&i.Name, &i.TotalAmount); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const updateMoneyRecord = `-- name: UpdateMoneyRecord :exec UPDATE money_record SET diff --git a/code/allapp/allapp-go/go.mod b/code/allapp/allapp-go/go.mod index 966c4f6c..598151c9 100644 --- a/code/allapp/allapp-go/go.mod +++ b/code/allapp/allapp-go/go.mod @@ -28,6 +28,7 @@ require ( github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect diff --git a/code/allapp/allapp-go/go.sum b/code/allapp/allapp-go/go.sum index 492c1a7b..cb575c58 100644 --- a/code/allapp/allapp-go/go.sum +++ b/code/allapp/allapp-go/go.sum @@ -49,6 +49,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ= diff --git a/code/allapp/allapp-go/idl/money/money.proto b/code/allapp/allapp-go/idl/money/money.proto index 9decec24..d54fe0f5 100644 --- a/code/allapp/allapp-go/idl/money/money.proto +++ b/code/allapp/allapp-go/idl/money/money.proto @@ -7,6 +7,7 @@ option go_package = "money"; import "api.proto"; import "money/money_category_types.proto"; import "money/money_record_types.proto"; +import "money/money_analysis_types.proto"; service MoneyCategoryService { rpc List(ListMoneyCategoryReq) returns (ListMoneyCategoryResp){ @@ -40,3 +41,12 @@ service MoneyRecordService { option (api.post) = '/money/record/delete'; } } + +service MoneyAnalysisService { + rpc AnalysisMoneyLine(AnalysisMoneyParams) returns (AnalysisMoneyLineResult){ + option (api.post) = '/money/analysis/line'; + } + rpc AnalysisMoneyPie(AnalysisMoneyParams) returns (AnalysisMoneyPieResult){ + option (api.post) = '/money/analysis/pie'; + } +} diff --git a/code/allapp/allapp-go/idl/money/money_analysis_types.proto b/code/allapp/allapp-go/idl/money/money_analysis_types.proto new file mode 100644 index 00000000..92bc10a0 --- /dev/null +++ b/code/allapp/allapp-go/idl/money/money_analysis_types.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +import "api.proto"; +package money; + +option go_package = "money"; + +message AnalysisMoneyParams { + string StartDate = 1 [(api.body) = "start_date"]; // 开始时间 + string EndDate = 2 [(api.body) = "end_date"]; // 结束时间 + int32 Type = 3 [(api.body) = "type"];// 0 支出 1 收入 + int32 PeriodType = 4 [(api.body) = "period_type"]; // 0 = 日分析, 1 = 月分析, 2 = 年分析 +} + +// PeriodAmount 用于存储按天、月、年汇总的金额 +message AnalysisMoneyAmount { + string X = 1 [(api.body) = "x"]; // 时间段(按天、月、年) + string Y = 2 [(api.body) = "y"]; // 汇总金额 +} + +message AnalysisMoneyLineResult { + repeated AnalysisMoneyAmount Records = 1 [(api.body) = "records"]; +} + +message AnalysisMoneyPieResult { + repeated AnalysisMoneyAmount Records = 1 [(api.body) = "records"]; +} diff --git a/code/allapp/allapp-go/main.go b/code/allapp/allapp-go/main.go index b0c9ebc9..76431e31 100644 --- a/code/allapp/allapp-go/main.go +++ b/code/allapp/allapp-go/main.go @@ -8,11 +8,46 @@ import ( "allapp/utils/idgen" "allapp/utils/jwtx" "allapp/utils/redisx" + "log" + "net/http" "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/common/adaptor" + "github.com/gorilla/websocket" "github.com/hertz-contrib/requestid" ) +var upgrader = websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true // 允许所有来源的连接 + }, +} + +func echo(w http.ResponseWriter, r *http.Request) { + // 这里是通过升级协议来实现 WebSocket 连接 + c, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Print("upgrade:", err) + return + } + defer c.Close() + + // 不断监听 WebSocket 连接的数据 + for { + mt, message, err := c.ReadMessage() + if err != nil { + log.Println("read:", err) + break + } + log.Printf("recv: %s", message) + err = c.WriteMessage(mt, message) // 回显消息 + if err != nil { + log.Println("write:", err) + break + } + } +} + func main() { // 初始化雪花id options := idgen.NewIdGeneratorOptions(conf.GetConf().Snowflake.WorkerID) @@ -39,6 +74,8 @@ func main() { h.Use(middleware.Auth()) h.Use(middleware.RefreshActive()) + h.GET(conf.GetConf().Server.WsUrl, adaptor.HertzHandler(http.HandlerFunc(echo))) + register(h) h.Spin() } diff --git a/code/allapp/allapp-rn/src/app/(tabs)/_layout.tsx b/code/allapp/allapp-rn/src/app/(tabs)/_layout.tsx index 4981cfd7..2a1c2265 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/_layout.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/_layout.tsx @@ -5,7 +5,7 @@ import { useCallback, useEffect, useState } from 'react' import { Text, TouchableOpacity, View } from 'react-native' import Animated, { useAnimatedRef } from 'react-native-reanimated' import Sortable from 'react-native-sortables' -import { ADrawer, LucideIcon } from '@/components/common/ao' +import { ADivider, ADrawer, LucideIcon } from '@/components/common/ao' import { useNavStore } from '@/store/navigation' export default function TabsLayout() { @@ -75,37 +75,42 @@ export default function TabsLayout() { - - - - - + + + - - { - setShowNavDrawer(true) - }} - > - - {currentNav.label} - - - - - - - + + + { + setShowNavDrawer(true) + }} + > + + {currentNav.label} + + + + + + + setSelectedId(null)} - onBackdropPress={() => setSelectedId(null)} - onOpen={() => setSelectedId(item.id)} - onClose={() => setSelectedId(null)} - > - { - Vibration.vibrate(50) - }} - > - - - - - - - - {item.remark ? item.remark : category?.name} - - { - item.user_id !== userID && ( - - {item.username} - - ) - } - - - - { + setSelectedId(null) + }} + trigger={({ ...triggerProps }) => { + return ( + { + setSelectedId(item.id) + Vibration.vibrate(50) + // 手动触发菜单显示 + triggerProps.onPress?.(e) + }} + onPress={(_e) => { + // 阻止点击触发,可以执行其他点击操作 + // 如果需要点击执行其他操作,可以在这里添加 + }} + > + - {category?.type === MoneyCategoryEnum.Income ? '+' : '-'} - {' '} - {item.amount} - - - - - + + + + + + {item.remark ? item.remark : category?.name} + + { + item.user_id !== userID && ( + + {item.username} + + ) + } + + + + + {category?.type === MoneyCategoryEnum.Income ? '+' : '-'} + {' '} + {item.amount} + + + + + ) + }} + > + { + userID === item.user_id && ( + { + onUpdate?.(item) + }} + > + + 更新 + + ) + } + + { + onDelete?.(item.id) }} > - { - userID === item.user_id && ( - <> - { - onUpdate?.(item) - }} - > - - - 更新 - - - { - onDelete?.(item.id) - }} - > - - - 删除 - - - - ) - } - { - onDetail?.(item.id) - }} - > - - - 详细 - - - + + 删除 + + { + onDetail?.(item.id) + }} + > + + 详细 + ) }} diff --git a/code/allapp/allapp-rn/src/app/(tabs)/money/index.tsx b/code/allapp/allapp-rn/src/app/(tabs)/money/index.tsx index 04482297..22e6cf59 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/money/index.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/money/index.tsx @@ -161,7 +161,6 @@ export default function Money() { onPress={() => { router.navigate('/money/record/editor') }} - className="mb-20" > diff --git a/code/allapp/allapp-rn/src/app/money/analysis/index.tsx b/code/allapp/allapp-rn/src/app/money/analysis/index.tsx index 6ba14940..81434f0d 100644 --- a/code/allapp/allapp-rn/src/app/money/analysis/index.tsx +++ b/code/allapp/allapp-rn/src/app/money/analysis/index.tsx @@ -1,38 +1,131 @@ +import type { AnalysisMoneyAmount } from '@/types/money/analysis' import dayjs from 'dayjs' -import { useState } from 'react' -import { Text, TouchableOpacity, View } from 'react-native' -import { VictoryChart, VictoryLine, VictoryPie, VictoryTheme, VictoryTooltip, VictoryVoronoiContainer } from 'victory-native' -import { ADatePicker, ASegmentedTabs, LucideIcon } from '@/components/common/ao' +import { useEffect, useState } from 'react' +import { ScrollView, Text, TouchableOpacity, View } from 'react-native' +import Svg from 'react-native-svg' +import { VictoryChart, VictoryLabel, VictoryLine, VictoryPie, VictoryTheme, VictoryTooltip } from 'victory-native' +import { ADatePicker, ADateRangePicker, ASegmentedTabs, LucideIcon } from '@/components/common/ao' +import EmptyState from '@/components/common/EmptyStatus' import CustomHeader from '@/components/custom/Header' import PagerTabs from '@/components/custom/PagerTabs' - -type GroupBy = 'day' | 'month' | 'year' -type AnalysisType = 'expense' | 'income' +import { analysisMoneyLineApi, analysisMoneyPieApi } from '@/request/api/money/analysis' +import { MoneyCategoryEnum } from '@/types/money/category' +import { getCurrentYear, getCurrentYearMonth, getEndOfMonth, getStartOfMonth } from '@/utils/time' interface AnalysisContentProps { - analysisType: AnalysisType + analysisType: MoneyCategoryEnum } export default function Analysis() { function AnalysisContent({ analysisType }: AnalysisContentProps) { + // 按月0 按年1 自定义2 const [timeType, setTimeType] = useState(0) - const [groupBy, setGroupBy] = useState('day') - const [startDate, setStartDate] = useState( - dayjs().format('YYYY-MM'), - ) - const [endDate, setEndDate] = useState( - dayjs().format('YYYY-MM'), - ) + // 开始结束时间 + const [startDate, setStartDate] = useState(getCurrentYearMonth()) + const [endDate, setEndDate] = useState('') + // 显示 const [showDatePicker, setShowDatePicker] = useState(false) + // 数据 + const [lineRecords, setLineRecords] = useState([]) + const [pieRecords, setPieRecords] = useState([]) + + // 请求 + function fetchChartsData() { + let start = '' + let end = '' + + const selectedStartDate = dayjs(startDate) + const selectedEndDate = dayjs(endDate) + + let periodType = 0 + + if (timeType === 0) { + start = selectedStartDate.startOf('month').format('YYYY-MM-DD') + end = selectedStartDate.endOf('month').format('YYYY-MM-DD') + + periodType = 0 + } + else if (timeType === 1) { + start = selectedStartDate.startOf('year').format('YYYY-MM-DD') + end = selectedStartDate.endOf('year').format('YYYY-MM-DD') + + periodType = 1 + } + else { + console.log(selectedStartDate.isSame(selectedEndDate, 'day')) + console.log(selectedStartDate.isSame(selectedEndDate, 'month')) + console.log(selectedStartDate.isSame(selectedEndDate, 'year')) + + if (selectedStartDate.isSame(selectedEndDate, 'month')) { + periodType = 0 + start = selectedStartDate.startOf('month').format('YYYY-MM-DD') + end = selectedEndDate.endOf('month').format('YYYY-MM-DD') + } + else if (selectedStartDate.isSame(selectedEndDate, 'year')) { + periodType = 1 + start = selectedStartDate.startOf('year').format('YYYY-MM-DD') + end = selectedEndDate.endOf('year').format('YYYY-MM-DD') + } + else { + periodType = 2 + start = selectedStartDate.format('YYYY-MM-DD') + end = selectedEndDate.format('YYYY-MM-DD') + } + } + + analysisMoneyLineApi({ + start_date: start, + end_date: end, + type: analysisType, + period_type: periodType, + }).then((res) => { + if (res.isSuccess) { + setLineRecords(res.data.records) + } + }) + + analysisMoneyPieApi({ + start_date: start, + end_date: end, + type: analysisType, + period_type: periodType, + }).then((res) => { + if (res.isSuccess) { + setPieRecords(res.data.records) + } + }) + } + + useEffect(() => { + fetchChartsData() + }, [timeType, startDate, endDate]) + return ( - + { setTimeType(index) + if (index === 2) { + // 自定义类型,本月的 1号 - 终止号 + setStartDate(getStartOfMonth()) + setEndDate(getEndOfMonth()) + } + else if (index === 1) { + // 按年 + setStartDate(getCurrentYear()) + setEndDate('') + } + else { + // 按月 + setStartDate(getCurrentYearMonth()) + setEndDate('') + } }} tabs={[ { key: '1', label: '按月' }, @@ -42,9 +135,9 @@ export default function Analysis() { /> - + {startDate} {timeType === 2 && ( <> @@ -63,40 +156,99 @@ export default function Analysis() { - + 分类构成 - + { + pieRecords.length > 0 + ? ( + + ) + : ( + + ) + } + - { - setShowDatePicker(false) - }} - onClose={() => { - setShowDatePicker(false) - }} - /> - + + 分类详细 + + { + pieRecords.length > 0 + ? ( + + {pieRecords.map((item, index) => ( + + {item.x} + + {item.y} + {' '} + 元 + + + ))} + + ) + : ( + + ) + + } + + + + { + timeType === 2 + ? ( + { + setStartDate(startDate) + setEndDate(endDate) + setShowDatePicker(false) + }} + onClose={() => { + setShowDatePicker(false) + }} + /> + ) + : ( + { + setStartDate(val) + setShowDatePicker(false) + }} + onClose={() => { + setShowDatePicker(false) + }} + /> + ) + } + ) } @@ -112,12 +264,12 @@ export default function Analysis() { { key: 'expense', title: '支出', - element: , + element: , }, { key: 'income', title: '收入', - element: , + element: , }, ]} /> diff --git a/code/allapp/allapp-rn/src/components/common/ao/DateRangePicker.tsx b/code/allapp/allapp-rn/src/components/common/ao/DateRangePicker.tsx new file mode 100644 index 00000000..4b17f4d0 --- /dev/null +++ b/code/allapp/allapp-rn/src/components/common/ao/DateRangePicker.tsx @@ -0,0 +1,89 @@ +import type { IDateRangePickerProps } from '@yz1311/react-native-wheel-picker' +import { DateRangePicker } from '@yz1311/react-native-wheel-picker' +import dayjs from 'dayjs' +import { useEffect, useRef, useState } from 'react' +import { Animated, Modal, StyleSheet, TouchableOpacity } from 'react-native' + +interface ADateRangePickerProps extends IDateRangePickerProps { + show?: boolean + onClose?: () => void + onConfirm?: (startDate: string, endDate: string) => void +} + +export default function ADateRangePicker({ + show, + onClose, + onConfirm, + ...restProps +}: ADateRangePickerProps) { + const fadeAnim = useRef(new Animated.Value(0)).current + const slideAnim = useRef(new Animated.Value(300)).current + + const [visible, setVisible] = useState(show) + + useEffect(() => { + if (show) { + setVisible(true) + fadeAnim.setValue(0) + slideAnim.setValue(300) + Animated.parallel([ + Animated.timing(fadeAnim, { toValue: 1, duration: 250, useNativeDriver: true }), + Animated.timing(slideAnim, { toValue: 0, duration: 250, useNativeDriver: true }), + ]).start() + } + else { + Animated.parallel([ + Animated.timing(fadeAnim, { toValue: 0, duration: 250, useNativeDriver: true }), + Animated.timing(slideAnim, { toValue: 280, duration: 250, useNativeDriver: true }), + ]).start(() => setVisible(false)) + } + }, [show]) + + const handleCancel = () => onClose?.() + + const handleConfirm = (startDate: Date, endDate: Date) => { + const formattedStartDate = dayjs(startDate).format('YYYY-MM-DD') + const formattedEndDate = dayjs(endDate).format('YYYY-MM-DD') + + onConfirm?.(formattedStartDate, formattedEndDate) + } + + if (!visible) + return null + + return ( + + + + + + + + + + ) +} + +const styles = StyleSheet.create({ + overlay: { + ...StyleSheet.absoluteFillObject, + backgroundColor: 'rgba(0,0,0,0.5)', + }, + pickerContainer: { + backgroundColor: '#fff', + overflow: 'hidden', + position: 'absolute', + bottom: 0, + width: '100%', + }, +}) diff --git a/code/allapp/allapp-rn/src/components/common/ao/index.ts b/code/allapp/allapp-rn/src/components/common/ao/index.ts index 78485e67..414d2e6e 100644 --- a/code/allapp/allapp-rn/src/components/common/ao/index.ts +++ b/code/allapp/allapp-rn/src/components/common/ao/index.ts @@ -2,8 +2,9 @@ import { Avatar } from './Avatar' import Button from './Button' import { Cell, CellGroup } from './Cell' import Checkbox from './Checkbox' -import DatePicker from './DatePicker' +import DatePicker from './DatePicker' +import DateRangePicker from './DateRangePicker' import Divider from './Divider' import Drawer from './Drawer' import Form, { FormRef } from './Form' @@ -13,7 +14,6 @@ import ListItem from './ListItem' import LucideIcon from './LucideIcon' import Modal from './Modal' import SegmentedTabs from './SegmentedTabs' - import Tab from './Tab' export { @@ -23,6 +23,7 @@ export { CellGroup as ACellGroup, Checkbox as ACheckbox, DatePicker as ADatePicker, + DateRangePicker as ADateRangePicker, Divider as ADivider, Drawer as ADrawer, Form as AForm, diff --git a/code/allapp/allapp-rn/src/request/api/money/analysis.ts b/code/allapp/allapp-rn/src/request/api/money/analysis.ts new file mode 100644 index 00000000..7c7ce94b --- /dev/null +++ b/code/allapp/allapp-rn/src/request/api/money/analysis.ts @@ -0,0 +1,13 @@ +import type { AnalysisMoneyLineResult, AnalysisMoneyParams, AnalysisMoneyPieResult } from '@/types/money/analysis' + +import alovaInstance from '../../index' + +const API_PREFIX = '/money/analysis' + +export function analysisMoneyLineApi(params: AnalysisMoneyParams) { + return alovaInstance.Post>(`${API_PREFIX}/line`, params) +} + +export function analysisMoneyPieApi(params: AnalysisMoneyParams) { + return alovaInstance.Post>(`${API_PREFIX}/pie`, params) +} diff --git a/code/allapp/allapp-rn/src/request/index.ts b/code/allapp/allapp-rn/src/request/index.ts index 1288fff7..2f5e9787 100644 --- a/code/allapp/allapp-rn/src/request/index.ts +++ b/code/allapp/allapp-rn/src/request/index.ts @@ -28,8 +28,8 @@ function isWhiteListed(url: string) { } const alovaInstance = createAlova({ - baseURL: 'http://192.168.5.6:8086/app', - // baseURL: 'http://192.168.1.137:8086/app', + // baseURL: 'http://192.168.5.6:8086/app', + baseURL: 'http://192.168.1.137:8086/app', requestAdapter: axiosRequestAdapter(), timeout: 5000, cacheFor: null, diff --git a/code/allapp/allapp-rn/src/types/money/analysis.ts b/code/allapp/allapp-rn/src/types/money/analysis.ts new file mode 100644 index 00000000..e8106196 --- /dev/null +++ b/code/allapp/allapp-rn/src/types/money/analysis.ts @@ -0,0 +1,19 @@ +export interface AnalysisMoneyParams { + start_date: string + end_date: string + type: number + period_type: number // 0 = 日分析, 1 = 月分析, 2 = 年分析 +} + +export interface AnalysisMoneyAmount { + x: string + y: string +} + +export interface AnalysisMoneyLineResult { + records: AnalysisMoneyAmount[] +} + +export interface AnalysisMoneyPieResult { + records: AnalysisMoneyAmount[] +} diff --git a/code/allapp/allapp-rn/src/utils/time.ts b/code/allapp/allapp-rn/src/utils/time.ts index 93c02d29..5134b81b 100644 --- a/code/allapp/allapp-rn/src/utils/time.ts +++ b/code/allapp/allapp-rn/src/utils/time.ts @@ -28,6 +28,10 @@ export function getCurrentYearMonth(format = 'YYYY-MM'): string { return dayjs().format(format) } +export function getCurrentYear(): string { + return dayjs().format('YYYY') +} + /** 字符串 / 数字 / Date → Date(无效返回 null) */ export function toDate(input: string | number | Date | undefined | null): Date { if (!input) @@ -105,3 +109,13 @@ export function formatRelativeTime(date: string | Date | number): string { return `${years}年前` } } + +// 获取本月的第一天 +export function getStartOfMonth() { + return dayjs().startOf('month').format('YYYY-MM-DD') +} + +// 获取本月的最后一天 +export function getEndOfMonth() { + return dayjs().endOf('month').format('YYYY-MM-DD') +} diff --git a/code/allapp/allapp-rn/test.html b/code/allapp/allapp-rn/test.html index b0b91c4a..25bd9b0c 100644 --- a/code/allapp/allapp-rn/test.html +++ b/code/allapp/allapp-rn/test.html @@ -1,87 +1,94 @@ - + - - - 财务分析 Demo - + + + WebSocket Test + - + - -
- - -
- - -
- - - -
- - -
- - - - - -
-

这里显示图表或分析结果

-
+
+

Messages:

+
+
- + // WebSocket onclose event: Fired when the connection is closed + socket.onclose = function(event) { + console.log("WebSocket connection closed"); + displayMessage("WebSocket connection closed"); + }; + + // Function to display messages on the page + function displayMessage(message) { + const messageElement = document.createElement('div'); + messageElement.textContent = message; + messagesDiv.appendChild(messageElement); + } + + // Button to send the message + sendButton.onclick = function() { + const message = messageInput.value; + if (message) { + console.log("Sending message: " + message); + socket.send(message); + displayMessage("You: " + message); + messageInput.value = ''; // Clear the input field + } else { + alert("Please enter a message!"); + } + }; +