From 8663cb2e3d032dbec2d45cf4cf33355192ffa872 Mon Sep 17 00:00:00 2001 From: oneao Date: Mon, 26 Jan 2026 22:31:12 +0800 Subject: [PATCH] u --- .../biz/handler/space/space_service.go | 18 + .../allapp-go/biz/model/space/space.pb.go | 135 ++++---- .../biz/model/space/space_types.pb.go | 122 ++++++- .../allapp-go/biz/router/space/middleware.go | 5 + .../allapp-go/biz/router/space/space.go | 1 + code/allapp/allapp-go/conf/conf.go | 8 + code/allapp/allapp-go/conf/dev/conf.yaml | 7 + code/allapp/allapp-go/go.mod | 37 +- code/allapp/allapp-go/go.sum | 36 ++ code/allapp/allapp-go/idl/space/space.proto | 4 + .../allapp-go/idl/space/space_types.proto | 5 + code/allapp/allapp-go/main.go | 3 + code/allapp/allapp-go/utils/redisx/helper.go | 27 ++ code/allapp/allapp-go/utils/redisx/redis.go | 49 +++ .../allapp-rn/src/app/(tabs)/_layout.tsx | 51 +-- .../allapp-rn/src/app/(tabs)/_layout2.tsx | 0 .../allapp/allapp-rn/src/app/(tabs)/index.tsx | 32 +- .../allapp-rn/src/app/(tabs)/money/index.tsx | 315 +++++++++--------- code/allapp/allapp-rn/src/app/auth/login.tsx | 152 --------- .../allapp-rn/src/app/auth/register.tsx | 129 ------- .../src/components/common/ao/Drawer.tsx | 289 ++++++---------- code/allapp/allapp-rn/src/request/index.ts | 4 +- .../allapp-rn/src/static/images/welcome.png | Bin 0 -> 92793 bytes code/allapp/allapp-rn/src/store/app.ts | 4 +- code/allapp/allapp-rn/src/store/navigation.ts | 50 ++- code/base-project/go.mod | 9 + code/base-project/go.sum | 6 + code/docusaurus | 2 +- 28 files changed, 744 insertions(+), 756 deletions(-) create mode 100644 code/allapp/allapp-go/utils/redisx/helper.go create mode 100644 code/allapp/allapp-go/utils/redisx/redis.go delete mode 100644 code/allapp/allapp-rn/src/app/(tabs)/_layout2.tsx delete mode 100644 code/allapp/allapp-rn/src/app/auth/login.tsx delete mode 100644 code/allapp/allapp-rn/src/app/auth/register.tsx create mode 100644 code/allapp/allapp-rn/src/static/images/welcome.png create mode 100644 code/base-project/go.mod create mode 100644 code/base-project/go.sum diff --git a/code/allapp/allapp-go/biz/handler/space/space_service.go b/code/allapp/allapp-go/biz/handler/space/space_service.go index 6643469c..c3bc74f3 100644 --- a/code/allapp/allapp-go/biz/handler/space/space_service.go +++ b/code/allapp/allapp-go/biz/handler/space/space_service.go @@ -63,3 +63,21 @@ func DissolveSpace(ctx context.Context, c *app.RequestContext) { response.Success(c).Send() } + +// EnterSpace . +// @router /space/enter [POST] +func EnterSpace(ctx context.Context, c *app.RequestContext) { + var err error + var req space.EnterSpaceParams + err = c.BindAndValidate(&req) + if err != nil { + c.String(consts.StatusBadRequest, err.Error()) + return + } + + resp := new(space.EnterSpaceResult) + + userID := middleware.GetUserID(ctx) + + c.JSON(consts.StatusOK, resp) +} diff --git a/code/allapp/allapp-go/biz/model/space/space.pb.go b/code/allapp/allapp-go/biz/model/space/space.pb.go index 6c875e34..8c067df8 100644 --- a/code/allapp/allapp-go/biz/model/space/space.pb.go +++ b/code/allapp/allapp-go/biz/model/space/space.pb.go @@ -28,77 +28,86 @@ var file_space_proto_rawDesc = []byte{ 0x17, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x6c, 0x0a, 0x0c, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5c, 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x73, 0x6f, 0x6c, - 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, - 0x44, 0x69, 0x73, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x1a, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x44, 0x69, 0x73, 0x73, - 0x6f, 0x6c, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, - 0x13, 0xd2, 0xc1, 0x18, 0x0f, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x64, 0x69, 0x73, 0x73, - 0x6f, 0x6c, 0x76, 0x65, 0x32, 0xdc, 0x03, 0x0a, 0x10, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x0c, 0x67, 0x65, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, - 0x13, 0xca, 0xc1, 0x18, 0x0f, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x75, 0x73, 0x65, 0x72, - 0x2f, 0x67, 0x65, 0x74, 0x12, 0x51, 0x0a, 0x09, 0x45, 0x78, 0x69, 0x74, 0x53, 0x70, 0x61, 0x63, - 0x65, 0x12, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x45, 0x78, 0x69, 0x74, 0x53, 0x70, - 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x2e, 0x45, 0x78, 0x69, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x22, 0x14, 0xd2, 0xc1, 0x18, 0x10, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x75, 0x73, - 0x65, 0x72, 0x2f, 0x65, 0x78, 0x69, 0x74, 0x12, 0x60, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xbe, 0x01, 0x0a, 0x0c, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5c, 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x2e, 0x44, 0x69, 0x73, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x44, 0x69, 0x73, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x22, 0x13, 0xd2, 0xc1, 0x18, 0x0f, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x64, 0x69, 0x73, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, 0x50, 0x0a, 0x0a, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x12, 0x17, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x45, 0x6e, 0x74, 0x65, + 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x17, 0x2e, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x2e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x10, 0xd2, 0xc1, 0x18, 0x0c, 0x2f, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x2f, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x32, 0xdc, 0x03, 0x0a, 0x10, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x0c, + 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x19, 0x2e, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x22, 0x13, 0xca, 0xc1, 0x18, 0x0f, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x75, + 0x73, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x51, 0x0a, 0x09, 0x45, 0x78, 0x69, 0x74, 0x53, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x45, 0x78, 0x69, + 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x16, 0x2e, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x2e, 0x45, 0x78, 0x69, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x22, 0x14, 0xd2, 0xc1, 0x18, 0x10, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x65, 0x78, 0x69, 0x74, 0x12, 0x60, 0x0a, 0x0e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x22, 0x14, 0xd2, 0xc1, 0x18, 0x10, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, - 0x75, 0x73, 0x65, 0x72, 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x0f, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, - 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x16, 0xd2, 0xc1, 0x18, 0x12, 0x2f, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x12, 0x51, 0x0a, 0x09, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x16, 0x2e, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4a, 0x6f, - 0x69, 0x6e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x14, 0xd2, - 0xc1, 0x18, 0x10, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x6a, - 0x6f, 0x69, 0x6e, 0x42, 0x18, 0x5a, 0x16, 0x61, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x2f, 0x62, 0x69, - 0x7a, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x14, 0xd2, 0xc1, 0x18, 0x10, 0x2f, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x0f, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1c, 0x2e, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x16, 0xd2, 0xc1, 0x18, + 0x12, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x12, 0x51, 0x0a, 0x09, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x12, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x70, 0x61, + 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x22, 0x14, 0xd2, 0xc1, 0x18, 0x10, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x2f, 0x6a, 0x6f, 0x69, 0x6e, 0x42, 0x18, 0x5a, 0x16, 0x61, 0x6c, 0x6c, 0x61, 0x70, 0x70, + 0x2f, 0x62, 0x69, 0x7a, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_space_proto_goTypes = []interface{}{ (*DissolveSpaceParams)(nil), // 0: space.DissolveSpaceParams - (*GetUserSpaceParams)(nil), // 1: space.GetUserSpaceParams - (*ExitSpaceParams)(nil), // 2: space.ExitSpaceParams - (*ListSpaceUsersParams)(nil), // 3: space.ListSpaceUsersParams - (*RemoveSpaceUserParams)(nil), // 4: space.RemoveSpaceUserParams - (*JoinSpaceParams)(nil), // 5: space.JoinSpaceParams - (*DissolveSpaceResult)(nil), // 6: space.DissolveSpaceResult - (*GetUserSpaceResult)(nil), // 7: space.GetUserSpaceResult - (*ExitSpaceResult)(nil), // 8: space.ExitSpaceResult - (*ListSpaceUsersResult)(nil), // 9: space.ListSpaceUsersResult - (*RemoveSpaceUserResult)(nil), // 10: space.RemoveSpaceUserResult - (*JoinSpaceResult)(nil), // 11: space.JoinSpaceResult + (*EnterSpaceParams)(nil), // 1: space.EnterSpaceParams + (*GetUserSpaceParams)(nil), // 2: space.GetUserSpaceParams + (*ExitSpaceParams)(nil), // 3: space.ExitSpaceParams + (*ListSpaceUsersParams)(nil), // 4: space.ListSpaceUsersParams + (*RemoveSpaceUserParams)(nil), // 5: space.RemoveSpaceUserParams + (*JoinSpaceParams)(nil), // 6: space.JoinSpaceParams + (*DissolveSpaceResult)(nil), // 7: space.DissolveSpaceResult + (*EnterSpaceResult)(nil), // 8: space.EnterSpaceResult + (*GetUserSpaceResult)(nil), // 9: space.GetUserSpaceResult + (*ExitSpaceResult)(nil), // 10: space.ExitSpaceResult + (*ListSpaceUsersResult)(nil), // 11: space.ListSpaceUsersResult + (*RemoveSpaceUserResult)(nil), // 12: space.RemoveSpaceUserResult + (*JoinSpaceResult)(nil), // 13: space.JoinSpaceResult } var file_space_proto_depIdxs = []int32{ 0, // 0: space.SpaceService.DissolveSpace:input_type -> space.DissolveSpaceParams - 1, // 1: space.SpaceUserService.getUserSpace:input_type -> space.GetUserSpaceParams - 2, // 2: space.SpaceUserService.ExitSpace:input_type -> space.ExitSpaceParams - 3, // 3: space.SpaceUserService.ListSpaceUsers:input_type -> space.ListSpaceUsersParams - 4, // 4: space.SpaceUserService.RemoveSpaceUser:input_type -> space.RemoveSpaceUserParams - 5, // 5: space.SpaceUserService.JoinSpace:input_type -> space.JoinSpaceParams - 6, // 6: space.SpaceService.DissolveSpace:output_type -> space.DissolveSpaceResult - 7, // 7: space.SpaceUserService.getUserSpace:output_type -> space.GetUserSpaceResult - 8, // 8: space.SpaceUserService.ExitSpace:output_type -> space.ExitSpaceResult - 9, // 9: space.SpaceUserService.ListSpaceUsers:output_type -> space.ListSpaceUsersResult - 10, // 10: space.SpaceUserService.RemoveSpaceUser:output_type -> space.RemoveSpaceUserResult - 11, // 11: space.SpaceUserService.JoinSpace:output_type -> space.JoinSpaceResult - 6, // [6:12] is the sub-list for method output_type - 0, // [0:6] is the sub-list for method input_type + 1, // 1: space.SpaceService.EnterSpace:input_type -> space.EnterSpaceParams + 2, // 2: space.SpaceUserService.getUserSpace:input_type -> space.GetUserSpaceParams + 3, // 3: space.SpaceUserService.ExitSpace:input_type -> space.ExitSpaceParams + 4, // 4: space.SpaceUserService.ListSpaceUsers:input_type -> space.ListSpaceUsersParams + 5, // 5: space.SpaceUserService.RemoveSpaceUser:input_type -> space.RemoveSpaceUserParams + 6, // 6: space.SpaceUserService.JoinSpace:input_type -> space.JoinSpaceParams + 7, // 7: space.SpaceService.DissolveSpace:output_type -> space.DissolveSpaceResult + 8, // 8: space.SpaceService.EnterSpace:output_type -> space.EnterSpaceResult + 9, // 9: space.SpaceUserService.getUserSpace:output_type -> space.GetUserSpaceResult + 10, // 10: space.SpaceUserService.ExitSpace:output_type -> space.ExitSpaceResult + 11, // 11: space.SpaceUserService.ListSpaceUsers:output_type -> space.ListSpaceUsersResult + 12, // 12: space.SpaceUserService.RemoveSpaceUser:output_type -> space.RemoveSpaceUserResult + 13, // 13: space.SpaceUserService.JoinSpace:output_type -> space.JoinSpaceResult + 7, // [7:14] is the sub-list for method output_type + 0, // [0:7] 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 diff --git a/code/allapp/allapp-go/biz/model/space/space_types.pb.go b/code/allapp/allapp-go/biz/model/space/space_types.pb.go index 2d53ce81..68d4c9ba 100644 --- a/code/allapp/allapp-go/biz/model/space/space_types.pb.go +++ b/code/allapp/allapp-go/biz/model/space/space_types.pb.go @@ -192,6 +192,91 @@ func (*DissolveSpaceResult) Descriptor() ([]byte, []int) { return file_space_space_types_proto_rawDescGZIP(), []int{3} } +type EnterSpaceParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SpaceId int64 `protobuf:"varint,1,opt,name=SpaceId,proto3" form:"space_id" json:"space_id"` +} + +func (x *EnterSpaceParams) Reset() { + *x = EnterSpaceParams{} + if protoimpl.UnsafeEnabled { + mi := &file_space_space_types_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EnterSpaceParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EnterSpaceParams) ProtoMessage() {} + +func (x *EnterSpaceParams) ProtoReflect() protoreflect.Message { + mi := &file_space_space_types_proto_msgTypes[4] + 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 EnterSpaceParams.ProtoReflect.Descriptor instead. +func (*EnterSpaceParams) Descriptor() ([]byte, []int) { + return file_space_space_types_proto_rawDescGZIP(), []int{4} +} + +func (x *EnterSpaceParams) GetSpaceId() int64 { + if x != nil { + return x.SpaceId + } + return 0 +} + +type EnterSpaceResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *EnterSpaceResult) Reset() { + *x = EnterSpaceResult{} + if protoimpl.UnsafeEnabled { + mi := &file_space_space_types_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EnterSpaceResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EnterSpaceResult) ProtoMessage() {} + +func (x *EnterSpaceResult) ProtoReflect() protoreflect.Message { + mi := &file_space_space_types_proto_msgTypes[5] + 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 EnterSpaceResult.ProtoReflect.Descriptor instead. +func (*EnterSpaceResult) Descriptor() ([]byte, []int) { + return file_space_space_types_proto_rawDescGZIP(), []int{5} +} + var File_space_space_types_proto protoreflect.FileDescriptor var file_space_space_types_proto_rawDesc = []byte{ @@ -207,7 +292,12 @@ var file_space_space_types_proto_rawDesc = []byte{ 0x64, 0x65, 0x52, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x69, 0x73, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x69, 0x73, 0x73, 0x6f, 0x6c, 0x76, - 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x42, 0x18, 0x5a, 0x16, + 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x0a, 0x10, + 0x45, 0x6e, 0x74, 0x65, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x12, 0x26, 0x0a, 0x07, 0x53, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x42, 0x0c, 0xca, 0xbb, 0x18, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, + 0x07, 0x53, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x12, 0x0a, 0x10, 0x45, 0x6e, 0x74, 0x65, + 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 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, 0x73, 0x70, 0x61, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } @@ -224,12 +314,14 @@ func file_space_space_types_proto_rawDescGZIP() []byte { return file_space_space_types_proto_rawDescData } -var file_space_space_types_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_space_space_types_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_space_space_types_proto_goTypes = []interface{}{ (*CreateSpaceParams)(nil), // 0: space.CreateSpaceParams (*CreateSpaceResult)(nil), // 1: space.CreateSpaceResult (*DissolveSpaceParams)(nil), // 2: space.DissolveSpaceParams (*DissolveSpaceResult)(nil), // 3: space.DissolveSpaceResult + (*EnterSpaceParams)(nil), // 4: space.EnterSpaceParams + (*EnterSpaceResult)(nil), // 5: space.EnterSpaceResult } var file_space_space_types_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type @@ -293,6 +385,30 @@ func file_space_space_types_proto_init() { return nil } } + file_space_space_types_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EnterSpaceParams); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_space_space_types_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EnterSpaceResult); 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{ @@ -300,7 +416,7 @@ func file_space_space_types_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_space_space_types_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/code/allapp/allapp-go/biz/router/space/middleware.go b/code/allapp/allapp-go/biz/router/space/middleware.go index 48a340f5..cffaab6f 100644 --- a/code/allapp/allapp-go/biz/router/space/middleware.go +++ b/code/allapp/allapp-go/biz/router/space/middleware.go @@ -80,3 +80,8 @@ func _getuserspaceMw() []app.HandlerFunc { // your code... return nil } + +func _enterspaceMw() []app.HandlerFunc { + // your code... + return nil +} diff --git a/code/allapp/allapp-go/biz/router/space/space.go b/code/allapp/allapp-go/biz/router/space/space.go index 8794bf5d..6fc94d8f 100644 --- a/code/allapp/allapp-go/biz/router/space/space.go +++ b/code/allapp/allapp-go/biz/router/space/space.go @@ -20,6 +20,7 @@ func Register(r *server.Hertz) { { _space := root.Group("/space", _spaceMw()...) _space.POST("/dissolve", append(_dissolvespaceMw(), space.DissolveSpace)...) + _space.POST("/enter", append(_enterspaceMw(), space.EnterSpace)...) { _user := _space.Group("/user", _userMw()...) _user.POST("/exit", append(_exitspaceMw(), space.ExitSpace)...) diff --git a/code/allapp/allapp-go/conf/conf.go b/code/allapp/allapp-go/conf/conf.go index 04f8ec44..119792bb 100644 --- a/code/allapp/allapp-go/conf/conf.go +++ b/code/allapp/allapp-go/conf/conf.go @@ -23,6 +23,7 @@ type Config struct { Pgsql PgsqlConfig `mapstructure:"pgsql" yaml:"pgsql"` Log LogConfig `mapstructure:"log" yaml:"log"` Wx WxConfig `mapstructure:"wx" yaml:"wx"` + Redis RedisConfig `mapstructure:"redis" yaml:"redis"` } type ServerConfig struct { @@ -67,6 +68,13 @@ type WxConfig struct { AppSecret string `mapstructure:"app_secret" yaml:"app_secret"` } +type RedisConfig struct { + Host string `mapstructure:"host" yaml:"host"` + Port int `mapstructure:"port" yaml:"port"` + Db int `mapstructure:"db" yaml:"db"` + Password string `mapstructure:"password" yaml:"password"` +} + func GetConf() *Config { once.Do(initConf) return conf diff --git a/code/allapp/allapp-go/conf/dev/conf.yaml b/code/allapp/allapp-go/conf/dev/conf.yaml index 5c066a2c..c362dfd1 100644 --- a/code/allapp/allapp-go/conf/dev/conf.yaml +++ b/code/allapp/allapp-go/conf/dev/conf.yaml @@ -22,6 +22,12 @@ pgsql: conn_max_lifetime: 30m sll_mode: false +redis: + host: 117.72.182.135 + port: 6379 + password: zhang520.. + db: 0 + log: level: "debug" dir: "./logs" @@ -33,3 +39,4 @@ log: wx: app_id: wxdab3e21a1f7e392f app_secret: 0895443c6fedfc21cb92c9cd60de2a26 + diff --git a/code/allapp/allapp-go/go.mod b/code/allapp/allapp-go/go.mod index b1b46006..c8367155 100644 --- a/code/allapp/allapp-go/go.mod +++ b/code/allapp/allapp-go/go.mod @@ -3,15 +3,15 @@ module allapp go 1.25.3 require ( - github.com/cloudwego/hertz v0.10.3 + github.com/cloudwego/hertz v0.10.4 github.com/golang-jwt/jwt/v4 v4.5.2 - github.com/hertz-contrib/jwt v1.0.4 github.com/hertz-contrib/requestid v1.1.0 - github.com/jackc/pgx/v5 v5.7.6 + github.com/jackc/pgx/v5 v5.8.0 github.com/pkg/errors v0.9.1 + github.com/shopspring/decimal v1.4.0 github.com/spf13/viper v1.21.0 go.uber.org/zap v1.27.1 - google.golang.org/protobuf v1.36.10 + google.golang.org/protobuf v1.36.11 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) @@ -23,22 +23,25 @@ require ( github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/bmatcuk/doublestar v1.3.4 // indirect github.com/bytedance/gopkg v0.1.3 // indirect - github.com/bytedance/sonic v1.14.2 // indirect - github.com/bytedance/sonic/loader v0.4.0 // indirect + github.com/bytedance/sonic v1.15.0 // indirect + github.com/bytedance/sonic/loader v0.5.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect - github.com/cloudwego/gopkg v0.1.7 // indirect + github.com/cloudwego/gopkg v0.1.8 // indirect github.com/cloudwego/netpoll v0.7.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/elastic/pkcs8 v1.0.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-openapi/inflect v0.21.3 // indirect github.com/go-sql-driver/mysql v1.9.3 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/hcl/v2 v2.24.0 // indirect + github.com/hertz-contrib/jwt v1.0.4 // indirect github.com/hertz-contrib/logger/zap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect @@ -47,10 +50,10 @@ require ( github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/nyaruka/phonenumbers v1.6.7 // indirect + github.com/nyaruka/phonenumbers v1.6.8 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/redis/go-redis/v9 v9.17.3 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect - github.com/shopspring/decimal v1.4.0 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -66,13 +69,13 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.23.0 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/crypto v0.47.0 // indirect + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // indirect + golang.org/x/tools v0.41.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect xorm.io/builder v0.3.13 // indirect xorm.io/xorm v1.3.11 // indirect diff --git a/code/allapp/allapp-go/go.sum b/code/allapp/allapp-go/go.sum index de6b8615..b2ad0abb 100644 --- a/code/allapp/allapp-go/go.sum +++ b/code/allapp/allapp-go/go.sum @@ -21,17 +21,27 @@ github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE= github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980= +github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE= +github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k= github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o= github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE= +github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/cloudwego/gopkg v0.1.4/go.mod h1:FQuXsRWRsSqJLsMVd5SYzp8/Z1y5gXKnVvRrWUOsCMI= github.com/cloudwego/gopkg v0.1.7 h1:P9+HwBwKIayJOg0V6hsxS3WVPzlad5BKxmDlZ8c8EkI= github.com/cloudwego/gopkg v0.1.7/go.mod h1:FQuXsRWRsSqJLsMVd5SYzp8/Z1y5gXKnVvRrWUOsCMI= +github.com/cloudwego/gopkg v0.1.8 h1:ma9oACsY3v6xJwQ8NUc/h19GLV2ZCIjx0P6hqaSIlt4= +github.com/cloudwego/gopkg v0.1.8/go.mod h1:FQuXsRWRsSqJLsMVd5SYzp8/Z1y5gXKnVvRrWUOsCMI= github.com/cloudwego/hertz v0.4.2/go.mod h1:K1U0RlU07CDeBINfHNbafH/3j9uSgIW8otbjUys3OPY= github.com/cloudwego/hertz v0.10.3 h1:NFcQAjouVJsod79XPLC/PaFfHgjMTYbiErmW+vGBi8A= github.com/cloudwego/hertz v0.10.3/go.mod h1:W5dUFXZPZkyfjMMo3EQrMQbofuvTsctM9IxmhbkuT18= +github.com/cloudwego/hertz v0.10.4 h1:xJxomApZYR67cROevam6SrtUBDvhcI4ZZhx/WgvpHwU= +github.com/cloudwego/hertz v0.10.4/go.mod h1:tZXEi/4o7R0Ho9yw5V2C+k/wVx3S8+wuuiJGDMopnpg= github.com/cloudwego/netpoll v0.3.1/go.mod h1:1T2WVuQ+MQw6h6DpE45MohSvDTKdy2DlzCx2KsnPI4E= github.com/cloudwego/netpoll v0.7.2 h1:4qDBGQ6CG2SvEXhZSDxMdtqt/NLDxjAVk0PC/biKiJo= github.com/cloudwego/netpoll v0.7.2/go.mod h1:PI+YrmyS7cIr0+SD4seJz3Eo3ckkXdu2ZVKBLhURLNU= @@ -39,6 +49,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/elastic/pkcs8 v1.0.0 h1:HhitlUKxhN288kcNcYkjW6/ouvuwJWd9ioxpjnD9jVA= github.com/elastic/pkcs8 v1.0.0/go.mod h1:ipsZToJfq1MxclVTwpG7U/bgeDtf+0HkUiOxebk95+0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -56,6 +68,8 @@ github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= @@ -92,6 +106,8 @@ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7Ulw github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk= github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= +github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= @@ -119,6 +135,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= github.com/nyaruka/phonenumbers v1.6.7 h1:WmebT8TNEzNaui5QlrGqbccRC6dZkEkYc+MGQoILSSo= github.com/nyaruka/phonenumbers v1.6.7/go.mod h1:7gjs+Lchqm49adhAKB5cdcng5ZXgt6x7Jgvi0ZorUtU= +github.com/nyaruka/phonenumbers v1.6.8 h1:k7HAJ/LeBkXE0vfbajITzTCZD0z0j+epdBNx43yTygk= +github.com/nyaruka/phonenumbers v1.6.8/go.mod h1:IUu45lj2bSeYXQuxDyyuzOrdV10tyRa1YSsfH8EKN5c= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -130,6 +148,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.17.3 h1:fN29NdNrE17KttK5Ndf20buqfDZwGNgoUr9qjl1DQx4= +github.com/redis/go-redis/v9 v9.17.3/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= @@ -206,14 +226,20 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0= golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -230,6 +256,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -244,6 +272,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -258,18 +288,24 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= diff --git a/code/allapp/allapp-go/idl/space/space.proto b/code/allapp/allapp-go/idl/space/space.proto index b638fa10..814ee573 100644 --- a/code/allapp/allapp-go/idl/space/space.proto +++ b/code/allapp/allapp-go/idl/space/space.proto @@ -13,6 +13,10 @@ service SpaceService { rpc DissolveSpace(DissolveSpaceParams) returns (DissolveSpaceResult){ option (api.post) = '/space/dissolve'; }; + // 进入空间 + rpc EnterSpace(EnterSpaceParams) returns (EnterSpaceResult){ + option (api.post) = '/space/enter'; + } } service SpaceUserService{ diff --git a/code/allapp/allapp-go/idl/space/space_types.proto b/code/allapp/allapp-go/idl/space/space_types.proto index 51d623f7..dff57608 100644 --- a/code/allapp/allapp-go/idl/space/space_types.proto +++ b/code/allapp/allapp-go/idl/space/space_types.proto @@ -25,3 +25,8 @@ message DissolveSpaceResult { } +message EnterSpaceParams { + int64 SpaceId = 1 [(api.body)="space_id"]; +} +message EnterSpaceResult { +} \ No newline at end of file diff --git a/code/allapp/allapp-go/main.go b/code/allapp/allapp-go/main.go index 41c2d99b..b0c9ebc9 100644 --- a/code/allapp/allapp-go/main.go +++ b/code/allapp/allapp-go/main.go @@ -7,6 +7,7 @@ import ( "allapp/logx" "allapp/utils/idgen" "allapp/utils/jwtx" + "allapp/utils/redisx" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" @@ -19,6 +20,8 @@ func main() { // 数据库 db.InitDB() + // Redis + redisx.Init() // 日志 logx.InitLog() // jwt diff --git a/code/allapp/allapp-go/utils/redisx/helper.go b/code/allapp/allapp-go/utils/redisx/helper.go new file mode 100644 index 00000000..91a031ca --- /dev/null +++ b/code/allapp/allapp-go/utils/redisx/helper.go @@ -0,0 +1,27 @@ +package redisx + +import ( + "context" + "time" +) + +// Set 设置 key +func Set(ctx context.Context, key string, value any, ttl time.Duration) error { + return Client().Set(ctx, key, value, ttl).Err() +} + +// Get 获取 string +func Get(ctx context.Context, key string) (string, error) { + return Client().Get(ctx, key).Result() +} + +// Del 删除 +func Del(ctx context.Context, keys ...string) error { + return Client().Del(ctx, keys...).Err() +} + +// Exists 是否存在 +func Exists(ctx context.Context, key string) (bool, error) { + n, err := Client().Exists(ctx, key).Result() + return n > 0, err +} diff --git a/code/allapp/allapp-go/utils/redisx/redis.go b/code/allapp/allapp-go/utils/redisx/redis.go new file mode 100644 index 00000000..fc1c08e5 --- /dev/null +++ b/code/allapp/allapp-go/utils/redisx/redis.go @@ -0,0 +1,49 @@ +package redisx + +import ( + "allapp/conf" + "context" + "fmt" + "sync" + "time" + + "github.com/redis/go-redis/v9" +) + +var ( + client *redis.Client + once sync.Once +) + +// Init 初始化 Redis(只会执行一次) +func Init() *redis.Client { + once.Do(func() { + redisConfig := conf.GetConf().Redis + + addr := fmt.Sprintf("%s:%d", redisConfig.Host, redisConfig.Port) + + client = redis.NewClient(&redis.Options{ + Addr: addr, + Password: redisConfig.Password, + DB: redisConfig.Db, + }) + + // 启动时检测连接 + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + if err := client.Ping(ctx).Err(); err != nil { + panic("redis 连接失败: " + err.Error()) + } + }) + + return client +} + +// Client 获取 Redis 客户端 +func Client() *redis.Client { + if client == nil { + panic("redis 尚未初始化") + } + return client +} diff --git a/code/allapp/allapp-rn/src/app/(tabs)/_layout.tsx b/code/allapp/allapp-rn/src/app/(tabs)/_layout.tsx index 13c5c50e..4981cfd7 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/_layout.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/_layout.tsx @@ -1,43 +1,40 @@ -import type { icons } from 'lucide-react-native' import type { SortableGridRenderItem } from 'react-native-sortables' +import type { NavItem } from '@/store/navigation' import { Slot, usePathname, useRouter } from 'expo-router' import { useCallback, useEffect, useState } from 'react' -import { Pressable, Text, TouchableOpacity, Vibration, View } from 'react-native' +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' - -interface NavItem { - label: string - path: string - icon: keyof typeof icons -} - -const NAV_MENUS: NavItem[] = [ - { label: '记账', path: '/money', icon: 'CircleDollarSign' }, - { label: '恋爱记', path: '/love', icon: 'Heart' }, - { label: '聊天', path: '/chat', icon: 'MessageCircle' }, - { label: '个人中心', path: '/user', icon: 'CircleUserRound' }, -] +import { useNavStore } from '@/store/navigation' export default function TabsLayout() { const scrollableRef = useAnimatedRef() const router = useRouter() const pathname = usePathname() + const navStore = useNavStore() + const [showNavDrawer, setShowNavDrawer] = useState(false) - const [draggingId, setDraggingId] = useState('') + const [currentNav, setCurrentNav] = useState({ - label: '', - path: '', - icon: 'AArrowDown', + label: 'Welcome', + path: '/', + icon: 'Sparkles', }) useEffect(() => { - const current = NAV_MENUS.find(item => item.path === pathname) + const current = navStore.navMenus.find(item => item.path === pathname) if (current) { setCurrentNav(current) } + else { + setCurrentNav({ + label: 'Welcome', + path: '/', + icon: 'Sparkles', + }) + } }, [pathname]) const refreshPage = () => { @@ -46,15 +43,14 @@ export default function TabsLayout() { const renderNavItem = useCallback>( ({ item }) => ( - { @@ -66,7 +62,7 @@ export default function TabsLayout() { {item.label} - + ), [], ) @@ -86,6 +82,7 @@ export default function TabsLayout() { px-2 gap-4 " + style={{ zIndex: 0 }} > @@ -128,11 +125,15 @@ export default function TabsLayout() { columnGap={16} rowGap={16} columns={3} - data={NAV_MENUS} + data={navStore.navMenus} keyExtractor={item => item.path} renderItem={renderNavItem} scrollableRef={scrollableRef} autoScrollActivationOffset={200} + showDropIndicator + onDragEnd={(dragData) => { + navStore.setNavMenus(dragData.data) + }} /> diff --git a/code/allapp/allapp-rn/src/app/(tabs)/_layout2.tsx b/code/allapp/allapp-rn/src/app/(tabs)/_layout2.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/code/allapp/allapp-rn/src/app/(tabs)/index.tsx b/code/allapp/allapp-rn/src/app/(tabs)/index.tsx index ad9e78c2..dc0f8167 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/index.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/index.tsx @@ -1,20 +1,34 @@ import { useRouter } from 'expo-router' -import { Text, View } from 'react-native' +import { Image, Text, View } from 'react-native' import { SafeAreaView } from 'react-native-safe-area-context' import { AButton } from '@/components/common/ao' -// 这个页面的作用是作为占位页,避免进入 (tabs) layout 时出现 404 页面。 -// 如果想指定默认页面,可以通过 router.replace 或 TabTrigger 指向具体子页面。 + export default function Index() { const router = useRouter() return ( - - - { - router.push('/money') - }} + + + + + + + 🎉 欢迎使用 OneAO + + + + 记录生活,记录情绪,也记录每一笔重要的支出 + + + router.replace('/money')} > - 测试 + 开始使用 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 8c6cb1ec..4d8d1e53 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/money/index.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/money/index.tsx @@ -1,20 +1,17 @@ import { useFocusEffect, useRouter } from 'expo-router' import React, { useCallback, useEffect, useState } from 'react' import { Image, Text, TouchableOpacity, View } from 'react-native' -import { Drawer } from 'react-native-drawer-layout' import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' -import { ADatePicker, AListItem, LucideIcon } from '@/components/common/ao' +import { ADatePicker, ADrawer, AListItem, LucideIcon } from '@/components/common/ao' import { Fab, FabIcon } from '@/components/ui/fab' import { AddIcon } from '@/components/ui/icon' import { queryMoneyRecordsApi } from '@/request/api/money/record' -import { useAppStore } from '@/store/app' import { useMoneyRecordStore } from '@/store/moneyRecord' import { getCurrentYearMonth } from '@/utils/time' import { toast } from '@/utils/toast' import TransactionsList from './components/TransactionsList' export default function Money() { - const appStore = useAppStore() const moneyRecordStore = useMoneyRecordStore() const router = useRouter() // 安全高度 @@ -47,12 +44,6 @@ export default function Money() { }) } - useEffect(() => { - if (!appStore.ready) - return - getMoneyRecords() - }, [appStore.ready, searchParams]) - useFocusEffect( useCallback(() => { // 页面显示 / 返回时 @@ -68,120 +59,78 @@ export default function Money() { - setShowActionsMenu(true)} - onClose={() => setShowActionsMenu(false)} - drawerPosition="right" - drawerStyle={{ - width: '70%', - }} - renderDrawerContent={() => { - return ( - - - - - 管理功能 - - - { - router.navigate('/money/category/setting') - }} - /> - - - - - 统计分析 - - - - - - - ) + - - - setShowDatePicker(true)} - className="flex flex-row items-center gap-1" - > - {searchParams.record_time} - - - - { - setShowActionsMenu(true) - }} - > - - - - - - + setShowDatePicker(true)} + className="flex flex-row items-center gap-1" > - - - 收入 - - {moneyRecordStore.getTotalIncome()} - - + {searchParams.record_time} + + - - 支出 - - {moneyRecordStore.getTotalExpense()} - - + { + setShowActionsMenu(true) + }} + > + + - - 结余 - - {moneyRecordStore.getTotalBalance()} - - + + + + + + 收入 + + {moneyRecordStore.getTotalIncome()} + - {/* + 支出 + + {moneyRecordStore.getTotalExpense()} + + + + + 结余 + + {moneyRecordStore.getTotalBalance()} + + + + + {/* 点击设置 */} - + - - { - router.navigate({ - pathname: '/money/record/editor', - params: { id: data.id }, - }) - }} - onDetail={(id) => { - router.navigate({ - pathname: '/money/record/detail', - params: { id }, - }) - }} - onDelete={(id) => { - moneyRecordStore.deleteMoneyRecord(id) - }} - onRefreshData={() => { - getMoneyRecords() - }} - /> - - - { - router.navigate('/money/record/editor') - }} - > - - - - { - setSearchParams({ - ...searchParams, - record_time: val, + + { + router.navigate({ + pathname: '/money/record/editor', + params: { id: data.id }, }) - setShowDatePicker(false) }} - onClose={() => { - setShowDatePicker(false) + onDetail={(id) => { + router.navigate({ + pathname: '/money/record/detail', + params: { id }, + }) + }} + onDelete={(id) => { + moneyRecordStore.deleteMoneyRecord(id) + }} + onRefreshData={() => { + getMoneyRecords() }} /> - + + + { + router.navigate('/money/record/editor') + }} + className="mb-20" + > + + + + { + setSearchParams({ + ...searchParams, + record_time: val, + }) + setShowDatePicker(false) + }} + onClose={() => { + setShowDatePicker(false) + }} + /> + + { + setShowActionsMenu(false) + }} + menuPosition="right" + height="60%" + showHeader={false} + > + + + + + 管理功能 + + + { + router.navigate('/money/category/setting') + }} + /> + + + + + 统计分析 + + + + + + + ) } diff --git a/code/allapp/allapp-rn/src/app/auth/login.tsx b/code/allapp/allapp-rn/src/app/auth/login.tsx deleted file mode 100644 index 8578e399..00000000 --- a/code/allapp/allapp-rn/src/app/auth/login.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { useRouter } from 'expo-router' -import { useState } from 'react' -import { Image, Text, View } from 'react-native' -import { AButton, ACheckbox, AForm, AFormItem, AInput } from '@/components/common/ao' -import CustomHeader from '@/components/custom/Header' -import { IconQq, IconWeixin, IconZhiwen } from '@/components/iconfont' -import { Divider } from '@/components/ui/divider' -import useFormValidation from '@/hooks/useFormValidation' -import { loginDefaultApi } from '@/request/api/auth' -import { useAppStore } from '@/store/app' -import { useUserStore } from '@/store/user' -import { toast } from '@/utils/toast' - -interface LoginForm { - account: string - password: string - rememberMe: boolean - socialType?: 'qq' | 'weixin' | 'fingerprint' -} - -export default function AuthLogin() { - const router = useRouter() - const userStore = useUserStore() - const appStore = useAppStore() - - const [loading, setLoading] = useState(false) - const [form, setForm] = useState({ - account: userStore.userInfo?.account || '', - password: '', - rememberMe: true, - }) - - const handleInputChange = (field: keyof LoginForm, value: string) => { - setForm(prev => ({ ...prev, [field]: value })) - } - - const rules = { - account: { required: true, message: '账号是必填项' }, - password: { required: true, message: '密码是必填项' }, - } - - const { isValid } = useFormValidation(form, rules) - - const loginDefault = () => { - setLoading(true) - loginDefaultApi({ - account: form.account, - password: form.password, - }).then((res) => { - if (res.isSuccess) { - toast.show({ - title: '登录成功', - }) - - userStore.setUserInfo({ - account: form.account, - id: res.data.userId, - seqNo: res.data.seqNo, - username: res.data.username, - gender: res.data.gender, - token: res.data.token, - refreshToken: res.data.refreshToken, - rememberMe: form.rememberMe, - }) - - appStore.init() - - router.replace('/money') - } - else { - toast.show({ - title: res.message || '登录失败', - }) - } - }).catch((_err) => { - - }).finally(() => { - setLoading(false) - }) - } - - const loginQq = () => { - toast.show({ title: '功能待开发,请稍等. . .' }) - } - const loginWx = () => { - toast.show({ title: '功能待开发,请稍等. . .' }) - } - const loginZhiwen = () => { - toast.show({ title: '功能待开发,请稍等. . .' }) - } - - return ( - - - - - - - - handleInputChange('account', text)} - /> - - - - handleInputChange('password', text)} - /> - - - - - setForm(prev => ({ ...prev, rememberMe: checked }))} - label="记住我" - /> - - 忘记密码? - - - - 登录 - - - - - - - 社交账号 - - - - - - - - - - - - - - ) -} diff --git a/code/allapp/allapp-rn/src/app/auth/register.tsx b/code/allapp/allapp-rn/src/app/auth/register.tsx deleted file mode 100644 index b1ccc8d8..00000000 --- a/code/allapp/allapp-rn/src/app/auth/register.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import type { AFormRef } from '@/components/common/ao' -import { useRouter } from 'expo-router' -import { Lock, UserRound } from 'lucide-react-native' -import { useRef, useState } from 'react' - -import { Image, ScrollView, View } from 'react-native' -import { AButton, AForm, AFormItem, AInput } from '@/components/common/ao' -import CustomHeader from '@/components/custom/Header' -import { registerDefaultApi } from '@/request/api/auth' -import { toast } from '@/utils/toast' - -interface RegisterForm { - username: string - password: string - confirmPassword: string -} - -export default function AuthRegister() { - const router = useRouter() - const scrollRef = useRef(null) - - const [form, setForm] = useState({ - username: '', - password: '', - confirmPassword: '', - }) - const [loading, setLoading] = useState(false) - const formRef = useRef(null) - - const handleInputChange = (field: keyof RegisterForm, value: string) => { - setForm(prev => ({ ...prev, [field]: value })) - } - - const handleRegister = async () => { - if (formRef.current?.validate()) { - setLoading(true) - - await registerDefaultApi({ - account: form.username, - password: form.password, - }).then((res) => { - if (res.isSuccess) { - toast.show({ - title: '注册成功', - }) - router.replace('/auth/login') - } - else { - toast.show({ - title: res.message || '注册失败', - }) - } - }).catch((_err) => { - }).finally(() => { - setLoading(false) - }) - } - } - - return ( - - - - - - - - - handleInputChange('username', text)} - /> - - - - handleInputChange('password', text)} - /> - - - val === form.password, - message: '两次密码不一致', - }, - ]} - > - handleInputChange('confirmPassword', text)} - /> - - - - - - 注册 - - - - - - ) -} diff --git a/code/allapp/allapp-rn/src/components/common/ao/Drawer.tsx b/code/allapp/allapp-rn/src/components/common/ao/Drawer.tsx index 0c5a1bdb..ddbea8c2 100644 --- a/code/allapp/allapp-rn/src/components/common/ao/Drawer.tsx +++ b/code/allapp/allapp-rn/src/components/common/ao/Drawer.tsx @@ -1,19 +1,18 @@ import type { ReactNode } from 'react' import type { DimensionValue, ViewStyle } from 'react-native' -import React, { useCallback, useEffect, useRef, useState } from 'react' -import { - Animated, - Dimensions, - Modal, - Platform, - StyleSheet, - Text, - TouchableWithoutFeedback, - View, -} from 'react-native' +import React, { useEffect, useMemo, useState } from 'react' +import { Dimensions, StyleSheet, Text, View } from 'react-native' +import { Gesture, GestureDetector } from 'react-native-gesture-handler' +import Animated, { + interpolate, + runOnJS, + useAnimatedStyle, + useSharedValue, + withTiming, +} from 'react-native-reanimated' import LucideIcon from './LucideIcon' -const WINDOW = Dimensions.get('window') +const SCREEN = Dimensions.get('screen') interface DrawerMenuProps { visible: boolean @@ -27,218 +26,145 @@ interface DrawerMenuProps { CircleNum?: number isShadowHideModal?: boolean title?: string + showHeader?: boolean } export default function Drawer({ visible, - height, + height = 300, hideModal, duration = 300, isCircle, menuPosition = 'bottom', children, - CircleNum = 8, + CircleNum = 12, isShadowHideModal = true, header, title, + showHeader = true, }: DrawerMenuProps) { - const [menuPositionStyle, setMenuPositionStyle] = useState() - const [drawerMenuBox, setDrawerMenuBox] = useState() + const progress = useSharedValue(0) + const drag = useSharedValue(0) const [innerVisible, setInnerVisible] = useState(false) - const anim = useRef(new Animated.Value(0)).current - + /* ================= 显隐 ================= */ useEffect(() => { if (visible) { setInnerVisible(true) - open() + progress.value = withTiming(1, { duration }) } else { - close() + progress.value = withTiming(0, { duration }, () => { + runOnJS(setInnerVisible)(false) + }) } }, [visible]) - useEffect(() => { + /* ================= Drawer 尺寸 ================= */ + const drawerBox = useMemo(() => { switch (menuPosition) { case 'left': - setMenuPositionStyle({ - flex: 1, - backgroundColor: '#fff', - borderTopRightRadius: isCircle ? CircleNum : 0, - borderBottomRightRadius: isCircle ? CircleNum : 0, - }) - setDrawerMenuBox({ - width: height, - height: WINDOW.height, - position: 'absolute', - left: 0, - top: 0, - }) - break - + return { width: height, left: 0, top: 0, bottom: 0 } case 'right': - setMenuPositionStyle({ - flex: 1, - backgroundColor: '#fff', - borderTopLeftRadius: isCircle ? CircleNum : 0, - borderBottomLeftRadius: isCircle ? CircleNum : 0, - }) - setDrawerMenuBox({ - width: height, - height: WINDOW.height, - position: 'absolute', - right: 0, - top: 0, - }) - break - + return { width: height, right: 0, top: 0, bottom: 0 } case 'top': - setMenuPositionStyle({ - flex: 1, - backgroundColor: '#fff', - borderBottomLeftRadius: isCircle ? CircleNum : 0, - borderBottomRightRadius: isCircle ? CircleNum : 0, - }) - setDrawerMenuBox({ - width: WINDOW.width, - height, - position: 'absolute', - top: 0, - right: 0, - }) - break - + return { height, left: 0, right: 0, top: 0 } case 'bottom': default: - setMenuPositionStyle({ - flex: 1, - backgroundColor: '#fff', - borderTopLeftRadius: isCircle ? CircleNum : 0, - borderTopRightRadius: isCircle ? CircleNum : 0, - }) - setDrawerMenuBox({ - width: WINDOW.width, - height, - position: 'absolute', - bottom: 0, - right: 0, - }) - break + return { height, left: 0, right: 0, bottom: 0 } } - }, [menuPosition, height, isCircle, CircleNum]) + }, [menuPosition, height]) - /* ================== 动画 ================== */ - const open = () => { - Animated.timing(anim, { - toValue: 1, - duration, - useNativeDriver: true, - }).start() - } + /* ================= 动画样式(关键) ================= */ + const drawerStyle = useAnimatedStyle(() => { + switch (menuPosition) { + case 'bottom': { + const y = interpolate(progress.value, [0, 1], [SCREEN.height, 0], 'clamp') + return { transform: [{ translateY: y + drag.value }] } + } + case 'top': { + const y = interpolate(progress.value, [0, 1], [-SCREEN.height, 0], 'clamp') + return { transform: [{ translateY: y }] } + } + case 'left': { + const x = interpolate(progress.value, [0, 1], [-SCREEN.width, 0], 'clamp') + return { transform: [{ translateX: x }] } + } + case 'right': { + const x = interpolate(progress.value, [0, 1], [SCREEN.width, 0], 'clamp') + return { transform: [{ translateX: x }] } + } + default: + return {} + } + }) - const close = () => { - Animated.timing(anim, { - toValue: 0, - duration, - useNativeDriver: true, - }).start(({ finished }) => { - if (finished) { - setInnerVisible(false) - hideModal() + const maskStyle = useAnimatedStyle(() => ({ + opacity: interpolate(progress.value, [0, 1], [0, 0.45], 'clamp'), + })) + + /* ================= 手势(只给 bottom) ================= */ + const pan = Gesture.Pan() + .onUpdate((e) => { + if (menuPosition === 'bottom' && e.translationY > 0) { + drag.value = e.translationY + } + }) + .onEnd(() => { + if (menuPosition === 'bottom' && drag.value > 120) { + progress.value = withTiming(0, { duration }, () => { + drag.value = 0 + runOnJS(hideModal)() + }) + } + else { + drag.value = withTiming(0) } }) - } - - /* ================== 位移 ================== */ - const getTransform = useCallback(() => { - switch (menuPosition) { - case 'left': - return { - translateX: anim.interpolate({ - inputRange: [0, 1], - outputRange: [-WINDOW.width, 0], - }), - } - case 'right': - return { - translateX: anim.interpolate({ - inputRange: [0, 1], - outputRange: [WINDOW.width, 0], - }), - } - case 'top': - return { - translateY: anim.interpolate({ - inputRange: [0, 1], - outputRange: [-WINDOW.height, 0], - }), - } - case 'bottom': - default: - return { - translateY: anim.interpolate({ - inputRange: [0, 1], - outputRange: [WINDOW.height, 0], - }), - } - } - }, [menuPosition]) if (!innerVisible) return null return ( - + {/* 遮罩 */} - isShadowHideModal && close()}> - - + isShadowHideModal && hideModal()} + /> {/* Drawer */} - - - - {menuPosition !== 'bottom' && ( - - )} - - { - header || ( + + + + {showHeader && ( + header ?? ( {title} ) - } + )} + {children} - - + + - + ) } @@ -247,18 +173,25 @@ const styles = StyleSheet.create({ ...StyleSheet.absoluteFillObject, backgroundColor: '#000', }, - container: { - height: '100%', - width: '100%', + drawerBox: { position: 'absolute', }, + drawer: { + flex: 1, + backgroundColor: '#fff', + }, headTitle: { - width: '100%', - padding: 10, - justifyContent: 'center', + padding: 12, alignItems: 'center', + justifyContent: 'center', }, title: { fontSize: 18, + fontWeight: '600', + }, + close: { + position: 'absolute', + right: 16, + top: 12, }, }) diff --git a/code/allapp/allapp-rn/src/request/index.ts b/code/allapp/allapp-rn/src/request/index.ts index e1c32c43..9c71bff7 100644 --- a/code/allapp/allapp-rn/src/request/index.ts +++ b/code/allapp/allapp-rn/src/request/index.ts @@ -30,8 +30,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/static/images/welcome.png b/code/allapp/allapp-rn/src/static/images/welcome.png new file mode 100644 index 0000000000000000000000000000000000000000..51e36f88b963641294ae453a7d0c145a77d0b1f5 GIT binary patch literal 92793 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 j_%;PI)?_At(uppp!0RF}Py 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�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 literal 0 HcmV?d00001 diff --git a/code/allapp/allapp-rn/src/store/app.ts b/code/allapp/allapp-rn/src/store/app.ts index 9f229324..be92310d 100644 --- a/code/allapp/allapp-rn/src/store/app.ts +++ b/code/allapp/allapp-rn/src/store/app.ts @@ -26,21 +26,19 @@ export const useAppStore = create((set, get) => ({ const moneyCategoryStore = useMoneyCategoryStore.getState() const spaceStore = useSpaceStore.getState() - // 未登录:跳转到登录页,但认为初始化已完成(允许 UI 继续渲染) if (!userStore.isLoggedIn()) { navStore.navigateToAuth() set({ ready: true }) return } - // 登录状态:执行完整初始化流程 try { // 分类初始化 await moneyCategoryStore.init() // 获取空间信息 const res = await getUserSpaceApi() - spaceStore.setUserSpace(res.data) + spaceStore.setUserSpace(res.data) } catch (err) { console.error('app init error:', err) diff --git a/code/allapp/allapp-rn/src/store/navigation.ts b/code/allapp/allapp-rn/src/store/navigation.ts index b8f9473a..20739a16 100644 --- a/code/allapp/allapp-rn/src/store/navigation.ts +++ b/code/allapp/allapp-rn/src/store/navigation.ts @@ -1,21 +1,49 @@ +import type { icons } from 'lucide-react-native' +import AsyncStorage from '@react-native-async-storage/async-storage' import { router } from 'expo-router' -// store/navigation.ts import { create } from 'zustand' +import { createJSONStorage, persist } from 'zustand/middleware' + +export interface NavItem { + label: string + path: string + icon: keyof typeof icons +} interface NavState { + navMenus: NavItem[] pathname: string setPathname: (p: string) => void navigateToAuth: () => void + setNavMenus: (menus: NavItem[]) => void } -export const useNavStore = create(set => ({ - pathname: '/', - setPathname: (p: string) => set({ pathname: p }), - navigateToAuth: () => { - const pathname = useNavStore.getState().pathname +const DEFAULT_NAV_MENUS: NavItem[] = [ + { label: '记账', path: '/money', icon: 'CircleDollarSign' }, + { label: '恋爱记', path: '/love', icon: 'Heart' }, + { label: '聊天', path: '/chat', icon: 'MessageCircle' }, + { label: '个人中心', path: '/user', icon: 'CircleUserRound' }, +] - if (!pathname.startsWith('/auth')) { - router.replace('/auth') - } - }, -})) +export const useNavStore = create()( + persist( + (set, get) => ({ + pathname: '/', + navMenus: DEFAULT_NAV_MENUS, + + setPathname: (p: string) => set({ pathname: p }), + navigateToAuth: () => { + const pathname = useNavStore.getState().pathname + + if (!pathname.startsWith('/auth')) { + router.replace('/auth') + } + }, + setNavMenus: navMenus => set({ navMenus }), + }), + { + name: 'nav-storage', + storage: createJSONStorage(() => AsyncStorage), + }, + ), +) diff --git a/code/base-project/go.mod b/code/base-project/go.mod new file mode 100644 index 00000000..68dec248 --- /dev/null +++ b/code/base-project/go.mod @@ -0,0 +1,9 @@ +module allapp-go + +go 1.25.3 + +require ( + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/redis/go-redis/v9 v9.17.3 // indirect +) diff --git a/code/base-project/go.sum b/code/base-project/go.sum new file mode 100644 index 00000000..cfd379aa --- /dev/null +++ b/code/base-project/go.sum @@ -0,0 +1,6 @@ +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/redis/go-redis/v9 v9.17.3 h1:fN29NdNrE17KttK5Ndf20buqfDZwGNgoUr9qjl1DQx4= +github.com/redis/go-redis/v9 v9.17.3/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= diff --git a/code/docusaurus b/code/docusaurus index 55d88676..4f58d5b9 160000 --- a/code/docusaurus +++ b/code/docusaurus @@ -1 +1 @@ -Subproject commit 55d88676f302e5e16d6da7a17ff21816d3c87613 +Subproject commit 4f58d5b99b0def543df87b1c72211456b00292dc