diff --git a/code/allapp/allapp-go/biz/handler/money/money_record_service.go b/code/allapp/allapp-go/biz/handler/money/money_record_service.go index aa13efc4..1499ff0a 100644 --- a/code/allapp/allapp-go/biz/handler/money/money_record_service.go +++ b/code/allapp/allapp-go/biz/handler/money/money_record_service.go @@ -56,6 +56,8 @@ func ListMoneyRecords(ctx context.Context, c *app.RequestContext) { userID := middleware.GetUserID(ctx) + categoryId := req.CategoryId + // 查询账目列表(统一 SQL) dbRecords, err := db.Queries.ListMoneyRecords( ctx, @@ -65,6 +67,7 @@ func ListMoneyRecords(ctx context.Context, c *app.RequestContext) { RecordTime_2: pgtypex.TimePtrToPgDate(endTime), }, ) + if err != nil { errorx.AddError(c, err) return 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 0dfed8c2..98d74574 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 @@ -139,8 +139,9 @@ type ListMoneyRecordsParams struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - StartTime string `protobuf:"bytes,1,opt,name=StartTime,proto3" form:"start_time" json:"start_time"` - EndTime string `protobuf:"bytes,2,opt,name=EndTime,proto3" form:"end_time" json:"end_time"` + StartTime string `protobuf:"bytes,1,opt,name=StartTime,proto3" form:"start_time" json:"start_time"` + EndTime string `protobuf:"bytes,2,opt,name=EndTime,proto3" form:"end_time" json:"end_time"` + CategoryId int64 `protobuf:"varint,3,opt,name=CategoryId,proto3" form:"category_id" json:"category_id"` } func (x *ListMoneyRecordsParams) Reset() { @@ -189,6 +190,13 @@ func (x *ListMoneyRecordsParams) GetEndTime() string { return "" } +func (x *ListMoneyRecordsParams) GetCategoryId() int64 { + if x != nil { + return x.CategoryId + } + return 0 +} + // 查询记账记录结果 type ListMoneyRecordsResult struct { state protoimpl.MessageState @@ -582,63 +590,66 @@ var file_money_money_record_types_proto_rawDesc = []byte{ 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0c, 0xca, 0xbb, 0x18, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x08, 0x55, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x6e, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x6e, - 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, - 0x2c, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x52, 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, 0x0a, - 0x07, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0c, - 0xca, 0xbb, 0x18, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x07, 0x45, 0x6e, - 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x6e, - 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, - 0x39, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x12, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x73, 0x52, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0xa4, 0x02, 0x0a, 0x17, 0x49, - 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, - 0x72, 0x79, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x18, 0xca, 0xbb, 0x18, 0x0b, - 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0xda, 0xbb, 0x18, 0x05, 0x24, - 0x21, 0x3d, 0x27, 0x27, 0x52, 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, - 0x12, 0x4d, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x35, 0xca, 0xbb, 0x18, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xda, 0xbb, 0x18, 0x27, - 0x24, 0x21, 0x3d, 0x27, 0x27, 0x20, 0x26, 0x26, 0x20, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x28, - 0x27, 0x5e, 0x5c, 0x64, 0x2b, 0x28, 0x5c, 0x2e, 0x5c, 0x64, 0x7b, 0x31, 0x2c, 0x32, 0x7d, 0x29, - 0x3f, 0x24, 0x27, 0x2c, 0x20, 0x24, 0x29, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x22, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, + 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x12, 0x2c, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x52, 0x09, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, + 0x0a, 0x07, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x0c, 0xca, 0xbb, 0x18, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x07, 0x45, + 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, + 0x72, 0x79, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, + 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x43, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x22, 0x53, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4d, + 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x39, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x65, 0x79, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x42, 0x0b, 0xca, 0xbb, 0x18, 0x07, 0x72, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x52, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0xa4, 0x02, 0x0a, + 0x17, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x43, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x18, 0xca, 0xbb, + 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0xda, 0xbb, 0x18, + 0x05, 0x24, 0x21, 0x3d, 0x27, 0x27, 0x52, 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, + 0x49, 0x64, 0x12, 0x4d, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x35, 0xca, 0xbb, 0x18, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xda, 0xbb, + 0x18, 0x27, 0x24, 0x21, 0x3d, 0x27, 0x27, 0x20, 0x26, 0x26, 0x20, 0x72, 0x65, 0x67, 0x65, 0x78, + 0x70, 0x28, 0x27, 0x5e, 0x5c, 0x64, 0x2b, 0x28, 0x5c, 0x2e, 0x5c, 0x64, 0x7b, 0x31, 0x2c, 0x32, + 0x7d, 0x29, 0x3f, 0x24, 0x27, 0x2c, 0x20, 0x24, 0x29, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x22, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x06, 0x52, + 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x5c, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, + 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3c, 0xca, 0xbb, 0x18, 0x0b, 0x72, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0xda, 0xbb, 0x18, 0x29, 0x24, 0x21, + 0x3d, 0x27, 0x27, 0x20, 0x26, 0x26, 0x20, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x28, 0x27, 0x5e, + 0x5c, 0x64, 0x7b, 0x34, 0x7d, 0x2d, 0x5c, 0x64, 0x7b, 0x32, 0x7d, 0x2d, 0x5c, 0x64, 0x7b, 0x32, + 0x7d, 0x24, 0x27, 0x2c, 0x20, 0x24, 0x29, 0x52, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, + 0x69, 0x6d, 0x65, 0x22, 0x19, 0x0a, 0x17, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, + 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xe3, + 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x02, 0x49, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0xda, 0xbb, + 0x18, 0x04, 0x24, 0x21, 0x3d, 0x30, 0x52, 0x02, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x0a, 0x43, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0f, + 0xca, 0xbb, 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x52, + 0x0a, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x06, 0x41, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x22, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x06, 0x52, 0x65, 0x6d, - 0x61, 0x72, 0x6b, 0x12, 0x5c, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3c, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0xda, 0xbb, 0x18, 0x29, 0x24, 0x21, 0x3d, 0x27, - 0x27, 0x20, 0x26, 0x26, 0x20, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x28, 0x27, 0x5e, 0x5c, 0x64, - 0x7b, 0x34, 0x7d, 0x2d, 0x5c, 0x64, 0x7b, 0x32, 0x7d, 0x2d, 0x5c, 0x64, 0x7b, 0x32, 0x7d, 0x24, - 0x27, 0x2c, 0x20, 0x24, 0x29, 0x52, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, - 0x65, 0x22, 0x19, 0x0a, 0x17, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x6f, 0x6e, 0x65, 0x79, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xe3, 0x01, 0x0a, - 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0xda, 0xbb, 0x18, 0x04, - 0x24, 0x21, 0x3d, 0x30, 0x52, 0x02, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x0a, 0x43, 0x61, 0x74, 0x65, - 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0f, 0xca, 0xbb, - 0x18, 0x0b, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x43, - 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x06, 0x41, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, 0xbb, 0x18, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, - 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xca, - 0xbb, 0x18, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, - 0x6b, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x22, 0x19, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, - 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x39, 0x0a, - 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0xda, 0xbb, 0x18, 0x04, - 0x24, 0x21, 0x3d, 0x30, 0x52, 0x02, 0x49, 0x64, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 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, + 0x61, 0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x69, 0x6d, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0f, 0xca, 0xbb, 0x18, 0x0b, 0x72, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x54, 0x69, 0x6d, 0x65, 0x22, 0x19, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x6f, + 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, + 0x39, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x02, 0x49, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0e, 0xca, 0xbb, 0x18, 0x02, 0x69, 0x64, 0xda, 0xbb, + 0x18, 0x04, 0x24, 0x21, 0x3d, 0x30, 0x52, 0x02, 0x49, 0x64, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 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 ( diff --git a/code/allapp/allapp-go/idl/money/money_record_types.proto b/code/allapp/allapp-go/idl/money/money_record_types.proto index aa4bfa73..1f6641a0 100644 --- a/code/allapp/allapp-go/idl/money/money_record_types.proto +++ b/code/allapp/allapp-go/idl/money/money_record_types.proto @@ -23,6 +23,7 @@ message MoneyRecord { message ListMoneyRecordsParams { string StartTime = 1 [(api.body)="start_time"]; string EndTime = 2 [(api.body)="end_time"]; + int64 CategoryId = 3 [(api.body)="category_id"]; } // 查询记账记录结果 diff --git a/code/allapp/allapp-go/utils/redisx/helper.go b/code/allapp/allapp-go/utils/redisx/helper.go index 4f4c84ca..f77dfeb4 100644 --- a/code/allapp/allapp-go/utils/redisx/helper.go +++ b/code/allapp/allapp-go/utils/redisx/helper.go @@ -40,101 +40,65 @@ func Exists(key string) (bool, error) { return cnt > 0, nil } -// SetUserSpaces 初始化用户空间列表(spaceID -> role) -func SetUserSpaces(ctx context.Context, userID int64, spaces map[int64]int32) error { - key := fmt.Sprintf("user:%d:spaces", userID) +// ================== Space User / Role ================== - pipe := Client().TxPipeline() +const ( + RoleMember int32 = 1 + RoleAdmin int32 = 5 + RoleOwner int32 = 9 - // 1. 先清空旧数据 - pipe.Del(ctx, key) + SpaceUserTTL = 10 * time.Minute +) - // 2. 再写入新数据(如果有) - if len(spaces) > 0 { - data := make(map[string]interface{}, len(spaces)) - for spaceID, role := range spaces { - data[strconv.FormatInt(spaceID, 10)] = role - } - pipe.HSet(ctx, key, data) - } - - // 3. 执行 - _, err := pipe.Exec(ctx) - return err +// space:user:{spaceId}:{userId} +func SpaceUserKey(spaceId int64, userId int64) string { + return fmt.Sprintf("space:user:%d:%d", spaceId, userId) } -// AddOrUpdateUserSpace 添加或更新单个空间的角色(增量更新) -func AddOrUpdateUserSpace(ctx context.Context, userID, spaceID int64, role int32) error { - key := fmt.Sprintf("user:%d:spaces", userID) - return Client().HSet(ctx, key, strconv.FormatInt(spaceID, 10), role).Err() +// Set / Create space user role +func SetSpaceUserRole(spaceId int64, userId int64, role int32) error { + key := SpaceUserKey(spaceId, userId) + return Set(key, role, SpaceUserTTL) } -// GetUserSpaces 获取用户所有空间列表和角色 -func GetUserSpaces(ctx context.Context, userID int64) (map[int64]int, error) { - key := fmt.Sprintf("user:%d:spaces", userID) - result, err := Client().HGetAll(ctx, key).Result() +// Update space user role (same as set, semantic clarity) +func UpdateSpaceUserRole(spaceId int64, userId int64, role int32) error { + return SetSpaceUserRole(spaceId, userId, role) +} + +// Get space user role +// return 0 means not exists +func GetSpaceUserRole(spaceId int64, userId int64) (int32, error) { + key := SpaceUserKey(spaceId, userId) + val, err := Get(key) if err != nil { - return nil, err + return 0, err + } + if val == "" { + return 0, nil } - spaces := make(map[int64]int, len(result)) - for k, v := range result { - spaceID, err1 := strconv.ParseInt(k, 10, 64) - role, err2 := strconv.Atoi(v) - if err1 != nil || err2 != nil { - continue - } - spaces[spaceID] = role - } - - return spaces, nil -} - -// GetUserSpaceRole 获取用户在指定空间的角色 -func GetUserSpaceRole(ctx context.Context, userID int64, spaceID int64) (role int, exists bool, err error) { - key := fmt.Sprintf("user:%d:spaces", userID) - val, err := Client().HGet(ctx, key, strconv.FormatInt(spaceID, 10)).Result() + r, err := strconv.ParseInt(val, 10, 32) if err != nil { - if errors.Is(err, redis.Nil) { - return 0, false, nil // 用户不在空间 - } - return 0, false, err + return 0, err } - - role, err = strconv.Atoi(val) - if err != nil { - return 0, false, err - } - - return role, true, nil + return int32(r), nil } -// RemoveUserSpace 从用户缓存中删除一个空间(用户退出或被踢) -func RemoveUserSpace(ctx context.Context, userID int64, spaceID int64) error { - key := fmt.Sprintf("user:%d:spaces", userID) - return Client().HDel(ctx, key, strconv.FormatInt(spaceID, 10)).Err() +// Delete space user (kick / dissolve) +func DeleteSpaceUser(spaceId int64, userId int64) error { + key := SpaceUserKey(spaceId, userId) + return Delete(key) } -// ClearUserSpaces 删除用户的所有空间列表 -func ClearUserSpaces(ctx context.Context, userID int64) error { - key := fmt.Sprintf("user:%d:spaces", userID) - return Client().Del(ctx, key).Err() +// Exists space user +func ExistsSpaceUser(spaceId int64, userId int64) (bool, error) { + key := SpaceUserKey(spaceId, userId) + return Exists(key) } -func InSpace(ctx context.Context, userID, spaceID int64) (bool, error) { - key := fmt.Sprintf("user:%d:spaces", userID) - return Client().HExists(ctx, key, strconv.FormatInt(spaceID, 10)).Result() -} - -// HasUserSpaces 判断用户是否在 Redis 中有空间缓存 -func HasUserSpaces(ctx context.Context, userID int64) (bool, error) { - key := fmt.Sprintf("user:%d:spaces", userID) - - // HLen 返回 hash 的字段数量 - cnt, err := Client().HLen(ctx, key).Result() - if err != nil { - return false, err - } - - return cnt > 0, nil +// Permission check +// owner > admin > member +func HasPermission(userRole int32, needRole int32) bool { + return userRole >= needRole } 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 ea0554ee..066bfd4e 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/money/index.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/money/index.tsx @@ -1,14 +1,16 @@ +import type { DateMorePickerMode } from '@/components/common/ao/DateMorePicker' import { useFocusEffect, useRouter } from 'expo-router' import React, { useCallback, useState } from 'react' import { Image, Text, TouchableOpacity, View } from 'react-native' import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' -import { ADatePicker, ADrawer, AListItem, LucideIcon } from '@/components/common/ao' +import { ADateMorePicker, ADatePicker, ADrawer, AListItem, LucideIcon } from '@/components/common/ao' +import { resolveDateRange } from '@/components/common/ao/DateMorePicker' import { Fab, FabIcon } from '@/components/ui/fab' import { AddIcon } from '@/components/ui/icon' import { deleteMoneyRecordApi, listMoneyRecordsApi } from '@/request/api/money/record' import { useMoneyCategoryStore } from '@/store/moneyCategory' import { useMoneyRecordStore } from '@/store/moneyRecord' -import { getCurrentYearMonth } from '@/utils/time' +import { getCurrentYearMonth, normalizeDateTime } from '@/utils/time' import { toast } from '@/utils/toast' import CategorySheet from './components/CategorySheet' import TransactionsList from './components/TransactionsList' @@ -22,23 +24,30 @@ export default function Money() { // 日期筛选 const [showDatePicker, setShowDatePicker] = useState(false) + const [dateMode, setDateMode] = useState('month') + const [searchParams, setSearchParams] = useState({ - record_time: getCurrentYearMonth(), + startTime: getCurrentYearMonth(), + endTime: '', category: -1, }) + const [showCategorySheet, setShowCategorySheet] = useState(false) // 操作菜单 const [showActionsMenu, setShowActionsMenu] = useState(false) function fetchMoneyRecords() { + console.log(searchParams) + + const resolveDate = resolveDateRange(dateMode, searchParams.startTime) + listMoneyRecordsApi({ - // record_time: searchParams.record_time, - start_time: '', - end_time: '', + start_time: resolveDate.startTime, + end_time: resolveDate.endTime, }).then((res) => { if (res.isSuccess) { - moneyRecordStore.setRecords(res.data.records || [], searchParams.record_time) + moneyRecordStore.setRecords(res.data.records || []) } else { toast.show({ @@ -52,7 +61,7 @@ export default function Money() { useFocusEffect( useCallback(() => { fetchMoneyRecords() - }, [searchParams.record_time]), + }, [searchParams.startTime, searchParams.endTime]), ) async function handleDeleteRecord(id: number) { @@ -63,6 +72,18 @@ export default function Money() { fetchMoneyRecords() } + function timeModeTip() { + if (dateMode === 'unlimited') { + return '全部' + } + else if (dateMode === 'range') { + return `${searchParams.startTime} - ${searchParams.endTime}` + } + else { + return searchParams.startTime + } + } + return ( setShowDatePicker(true)} className="flex flex-row items-center gap-1" > - {searchParams.record_time} + + {timeModeTip()} + @@ -182,7 +209,26 @@ export default function Money() { - { + setShowDatePicker(false) + }} + startDate={searchParams.startTime} + endDate={searchParams.endTime} + hiddenModes={['datetime', 'time']} + onConfirm={(value) => { + setDateMode(value.mode) + + setSearchParams(val => ({ + ...val, + startTime: value.startTime, + endTime: value.endTime, + })) + }} + /> + {/* { setShowDatePicker(false) }} - /> + /> */} void onConfirm?: (value: { - mode: PickerMode + mode: DateMorePickerMode startTime: string endTime: string }) => void - onChange?: (mode: PickerMode) => void + hiddenModes?: DateMorePickerMode[] + onChange?: (mode: DateMorePickerMode) => void +} + +interface DateRangeResult { + startTime: string + endTime: string +} + +export function resolveDateRange( + dateMode: DateMorePickerMode, + baseDate?: string | Date | Dayjs, +): DateRangeResult { + const now = dayjs() + const base = baseDate ? dayjs(baseDate) : now + + // 兜底非法时间 + if (!base.isValid()) { + return { startTime: '', endTime: '' } + } + + let start: Dayjs + let end: Dayjs + + switch (dateMode) { + case 'unlimited': + start = dayjs('1970-01-01 00:00:00') + end = now.add(10, 'year').endOf('day') + break + + case 'date': + start = base.startOf('day') + end = base.endOf('day') + break + + case 'month': + start = base.startOf('month') + end = base.endOf('month') + break + + case 'year': + start = base.startOf('year') + end = base.endOf('year') + break + + case 'time': + case 'datetime': + start = base + end = base + break + + case 'range': + default: + start = base.startOf('day') + end = base.endOf('day') + break + } + + return { + startTime: start.format('YYYY-MM-DD HH:mm:ss'), + endTime: end.format('YYYY-MM-DD HH:mm:ss'), + } } export default function DateMorePicker({ @@ -46,100 +108,85 @@ export default function DateMorePicker({ onClose, onConfirm, onChange, + hiddenModes = [], }: DateMorePickerProps) { const [localVisible, setLocalVisible] = useState(false) - const coreModes: DatePickerMode[] = ['date', 'month', 'year', 'time', 'datetime'] - const coreLabels = ['日', '月', '年', '时间', '日期'] - /** ================= 内部编辑态 ================= */ - const [internalMode, setInternalMode] = useState('date') - const [internalStart, setInternalStart] = useState(getCurrentDate()) - const [internalEnd, setInternalEnd] = useState(getCurrentDate()) + const [internalMode, setInternalMode] = useState(mode || 'date') + const [internalStart, setInternalStart] = useState(startDate || getCurrentDate()) + const [internalEnd, setInternalEnd] = useState(endDate || getCurrentDate()) const [activeTab, setActiveTab] = useState('custom') /** ================= 重置编辑态(关键) ================= */ - const resetInternalState = () => { - setInternalMode(mode || 'date') - setInternalStart(startDate ?? getCurrentDate()) - setInternalEnd(endDate ?? getCurrentDate()) - setActiveTab('custom') - } - useEffect(() => { if (visible) { - resetInternalState() + if (mode === 'unlimited') { + setActiveTab('unlimited') + } + else if (mode === 'range') { + setActiveTab('range') + } + else { + setActiveTab('custom') + } + setLocalVisible(true) } }, [visible]) /** ================= 快速选择逻辑(修复时间归零) ================= */ + function getDefaultDateByMode(mode: DatePickerMode, now = dayjs()) { + switch (mode) { + case 'date': + return now.startOf('day') + case 'month': + return now.startOf('month') + case 'year': + return now.startOf('year') + case 'time': + return now.second(0) + case 'datetime': + return now + default: + return now + } + } const handleModeChange = (next: PickerModeInternal) => { const now = dayjs() - switch (next) { - case 'custom': - setInternalMode('date') - break - - case 'unlimited': - setInternalStart('') - setInternalEnd('') - setInternalMode('unlimited') - break - - case 'range': { - const base = now.startOf('day') - setInternalStart(base.toDate()) - setInternalEnd(base.toDate()) - setInternalMode('range') - break - } - - case 'date': { - const base = now.startOf('day') - setInternalStart(base.toDate()) - setInternalEnd(base.toDate()) - setInternalMode('date') - break - } - - case 'month': { - const base = now.startOf('month') - setInternalStart(base.toDate()) - setInternalEnd(base.toDate()) - setInternalMode('month') - break - } - - case 'year': { - const base = now.startOf('year') - setInternalStart(base.toDate()) - setInternalEnd(base.toDate()) - setInternalMode('year') - break - } - - case 'time': { - const base = now.second(0) - setInternalStart(base.toDate()) - setInternalEnd(base.toDate()) - setInternalMode('time') - break - } - - case 'datetime': { - setInternalStart(now.toDate()) - setInternalEnd(now.toDate()) - setInternalMode('datetime') - break - } + if (next === 'unlimited') { + setInternalStart('') + setInternalEnd('') + setInternalMode('unlimited') + onChange?.('unlimited') + return } - onChange?.(next === 'custom' ? 'date' : next) + if (next === 'range') { + const base = now.startOf('day') + setInternalStart(base.toDate()) + setInternalEnd(base.toDate()) + setInternalMode('range') + onChange?.('range') + return + } + + const targetMode: DatePickerMode + = next === 'custom' + ? visibleCoreModeOptions[0].mode + : next + + const base = getDefaultDateByMode(targetMode, now) + + setInternalStart(base.toDate()) + setInternalEnd(base.toDate()) + setInternalMode(targetMode) + + onChange?.(targetMode) } const handleClose = () => { @@ -149,7 +196,7 @@ export default function DateMorePicker({ /** ================= 确认(提交) ================= */ - const formatMap: Record = { + const formatMap: Record = { unlimited: '', range: 'YYYY-MM-DD', date: 'YYYY-MM-DD', @@ -189,6 +236,73 @@ export default function DateMorePicker({ handleClose() } + const isHidden = (mode: DateMorePickerMode) => + hiddenModes.includes(mode) + + const tabItems: { label: string, key: TabKey }[] = [ + { label: '自定义', key: 'custom' }, + { label: '不限', key: 'unlimited' }, + { label: '范围', key: 'range' }, + { label: '今天', key: 'date' }, + { label: '本月', key: 'month' }, + { label: '本年', key: 'year' }, + ] + + const visibleTabItems = tabItems.filter((item) => { + if (item.key === 'unlimited' && isHidden('unlimited')) + return false + if (item.key === 'range' && isHidden('range')) + return false + if (item.key === 'date' && isHidden('date')) + return false + if (item.key === 'month' && isHidden('month')) + return false + if (item.key === 'year' && isHidden('year')) + return false + return true + }) + + const coreModeOptions: { mode: DatePickerMode, label: string }[] = [ + { mode: 'date', label: '日' }, + { mode: 'month', label: '月' }, + { mode: 'year', label: '年' }, + { mode: 'time', label: '时间' }, + { mode: 'datetime', label: '日期' }, + ] + + const visibleCoreModeOptions = coreModeOptions.filter((item) => { + if (item.mode === 'date' && isHidden('date')) + return false + if (item.mode === 'month' && isHidden('month')) + return false + if (item.mode === 'year' && isHidden('year')) + return false + if (item.mode === 'time' && isHidden('time')) + return false + if (item.mode === 'datetime' && isHidden('datetime')) + return false + return true + }) + + function isDatePickerMode( + mode: DateMorePickerMode, + ): mode is DatePickerMode { + return ['date', 'month', 'year', 'time', 'datetime'].includes(mode) + } + + const canConfirm = (() => { + if (internalMode !== 'range') + return true + console.log(internalMode) + console.log(internalStart) + console.log(internalEnd) + + const startValid = dayjs(internalStart).isValid() + const endValid = dayjs(internalEnd).isValid() + + return startValid && endValid + })() + /** ================= UI ================= */ return ( @@ -200,14 +314,7 @@ export default function DateMorePicker({ 快速选择 { setActiveTab(key as TabKey) handleModeChange(key as PickerModeInternal) @@ -219,18 +326,22 @@ export default function DateMorePicker({ {!['unlimited', 'range'].includes(internalMode) && ( 选择模式 - { - const next = coreModes[e.nativeEvent.selectedSegmentIndex] - setInternalMode(next) - setInternalStart(dayjs().toDate()) - setActiveTab('custom') - }} - /> + {visibleCoreModeOptions.length > 0 && ( + i.label)} + selectedIndex={visibleCoreModeOptions.findIndex( + i => i.mode === internalMode, + )} + onChange={(e: any) => { + const next = visibleCoreModeOptions[e.nativeEvent.selectedSegmentIndex].mode + setInternalMode(next) + setInternalStart(dayjs().toDate()) + setActiveTab('custom') + }} + /> + )} )} @@ -238,14 +349,14 @@ export default function DateMorePicker({ {internalMode === 'unlimited' && ( - + 不限时间 @@ -253,6 +364,8 @@ export default function DateMorePicker({ {internalMode === 'range' && ( )} - {coreModes.includes(internalMode as DatePickerMode) && ( + {isDatePickerMode(internalMode) + && visibleCoreModeOptions.some(i => i.mode === internalMode) && ( { @@ -286,7 +400,11 @@ export default function DateMorePicker({ - diff --git a/code/allapp/allapp-rn/src/store/moneyRecord.ts b/code/allapp/allapp-rn/src/store/moneyRecord.ts index eff437d8..1dc4560a 100644 --- a/code/allapp/allapp-rn/src/store/moneyRecord.ts +++ b/code/allapp/allapp-rn/src/store/moneyRecord.ts @@ -14,7 +14,7 @@ interface MoneyRecordStore { getTotalExpense: () => string getTotalBalance: () => string - setRecords: (records: MoneyRecord[], month: string) => void + setRecords: (records: MoneyRecord[]) => void setCurrentMonth: (month: string) => void getMoneyRecordById: (id: number) => MoneyRecord | null @@ -71,12 +71,9 @@ export const useMoneyRecordStore = create((set, get) => ({ }, /* ---------------- base ---------------- */ - setRecords: (records, month) => { - const filtered = records.filter(r => - isInMonth(r.record_time, month), - ) - const newGroups = recomputeGroups(filtered) - set({ records: newGroups, currentMonth: month }) + setRecords: (records) => { + const newGroups = recomputeGroups(records) + set({ records: newGroups }) }, setCurrentMonth: month => set({ currentMonth: month }), diff --git a/code/allapp/allapp-rn/src/utils/time.ts b/code/allapp/allapp-rn/src/utils/time.ts index 5134b81b..cc25d99c 100644 --- a/code/allapp/allapp-rn/src/utils/time.ts +++ b/code/allapp/allapp-rn/src/utils/time.ts @@ -119,3 +119,34 @@ export function getStartOfMonth() { export function getEndOfMonth() { return dayjs().endOf('month').format('YYYY-MM-DD') } + +export function normalizeDateTime( + input?: string | Date | dayjs.Dayjs, +): string { + if (!input) + return '' + + const raw = typeof input === 'string' ? input.trim() : input + let d = dayjs(raw) + + if (!d.isValid()) + return '' + + // string 才需要“猜精度”,Date / dayjs 默认是完整的 + if (typeof raw === 'string') { + if (/^\d{4}$/.test(raw)) { + d = d.startOf('year') + } + else if (/^\d{4}-\d{2}$/.test(raw)) { + d = d.startOf('month') + } + else if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) { + d = d.startOf('day') + } + else if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(raw)) { + d = d.second(0) + } + } + + return d.format('YYYY-MM-DD HH:mm:ss') +}