This commit is contained in:
oneao committed 2026-01-26 22:31:12 +08:00
1 parent 5a79414319
commit 8663cb2e3d
28 files changed
+743 -755

No files matched your search

@@ -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)
}
@@ -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
@@ -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,
},
@@ -80,3 +80,8 @@ func _getuserspaceMw() []app.HandlerFunc {
// your code...
return nil
}
func _enterspaceMw() []app.HandlerFunc {
// your code...
return nil
}
@@ -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)...)
+8
View File
@@ -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
+7
View File
@@ -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
+20 -17
View File
@@ -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
+36
View File
@@ -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=
@@ -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{
@@ -25,3 +25,8 @@ message DissolveSpaceResult {
}
message EnterSpaceParams {
int64 SpaceId = 1 [(api.body)="space_id"];
}
message EnterSpaceResult {
}
+3
View File
@@ -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
@@ -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
}
@@ -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
}
@@ -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<Animated.ScrollView>()
const router = useRouter()
const pathname = usePathname()
const navStore = useNavStore()
const [showNavDrawer, setShowNavDrawer] = useState(false)
const [draggingId, setDraggingId] = useState<string>('')
const [currentNav, setCurrentNav] = useState<NavItem>({
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<SortableGridRenderItem<NavItem>>(
({ item }) => (
<Pressable
<TouchableOpacity
className="
flex
flex-col
items-center
justify-center
bg-[white]
bg-[#f9f9f9]
rounded-md
shadow-md
p-3
"
onPress={() => {
@@ -66,7 +62,7 @@ export default function TabsLayout() {
<Text className="text-sm mt-2">
{item.label}
</Text>
</Pressable>
</TouchableOpacity>
),
[],
)
@@ -86,6 +82,7 @@ export default function TabsLayout() {
px-2
gap-4
"
style={{ zIndex: 0 }}
>
<View className="bg-white rounded-md shadow-lg h-12 w-12">
<TouchableOpacity className="w-full h-full items-center justify-center">
@@ -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)
}}
/>
</Animated.ScrollView>
</ADrawer>
Whitespace-only changes.
+23 -9
View File
@@ -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 (
<SafeAreaView>
<View>
<AButton onPress={() => {
router.push('/money')
}}
<SafeAreaView className="flex-1 bg-white">
<View className="flex-1 items-center justify-center px-6">
<Image
source={require('@/static/images/welcome.png')}
className="w-86 h-48 mb-6"
resizeMode="contain"
/>
<Text className="text-2xl font-semibold text-gray-900 mb-3">
🎉 欢迎使用 OneAO
</Text>
<Text className="text-base text-gray-500 text-center mb-10">
记录生活,记录情绪,也记录每一笔重要的支出
</Text>
<AButton
className="w-full"
onPress={() => router.replace('/money')}
>
测试
开始使用
</AButton>
</View>
</SafeAreaView>
@@ -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() {
<View
className="flex-1"
>
<Drawer
open={showActionsMenu}
onOpen={() => setShowActionsMenu(true)}
onClose={() => setShowActionsMenu(false)}
drawerPosition="right"
drawerStyle={{
width: '70%',
}}
renderDrawerContent={() => {
return (
<SafeAreaView className="flex-col px-3">
<Image
source={require('@/static/images/logo.png')}
style={{ width: 40, height: 40 }}
className="self-center"
/>
<View className="mt-2">
<Text className="text-gray-600 font-semibold text-sm">管理功能</Text>
<View className="p-1">
<AListItem
icon="LayoutGrid"
text="类别设置"
onPress={() => {
router.navigate('/money/category/setting')
}}
/>
</View>
</View>
<View className="mt-2">
<Text className="text-gray-600 font-semibold text-sm">统计分析</Text>
<View className="p-1">
<AListItem icon="ChartSpline" text="图表分析" />
</View>
</View>
</SafeAreaView>
)
<View
style={{
paddingTop: insets.top,
backgroundColor: '#fff',
elevation: 3,
}}
>
<View
style={{
paddingTop: insets.top,
backgroundColor: '#fff',
elevation: 3,
}}
>
<View className="flex flex-row justify-between items-center px-3">
<TouchableOpacity
onPress={() => setShowDatePicker(true)}
className="flex flex-row items-center gap-1"
>
<Text className="font-semibold text-lg">{searchParams.record_time}</Text>
<LucideIcon icon="ChevronDown" size={16} color="#666" clickable={false} />
</TouchableOpacity>
<TouchableOpacity
className="flex flex-row items-center gap-2"
onPress={() => {
setShowActionsMenu(true)
}}
>
<LucideIcon icon="Menu" size={24} clickable={false} />
</TouchableOpacity>
</View>
<View
className="px-3 py-3"
<View className="flex flex-row justify-between items-center px-3">
<TouchableOpacity
onPress={() => setShowDatePicker(true)}
className="flex flex-row items-center gap-1"
>
<View
className="flex flex-row gap-4"
style={{
borderBottomLeftRadius: 16,
borderBottomRightRadius: 18,
}}
>
<View className="flex-1">
<Text className="text-gray-500 text-sm">收入</Text>
<Text
className="text-lg font-semibold mt-0.5"
numberOfLines={1}
ellipsizeMode="tail"
>
{moneyRecordStore.getTotalIncome()}
</Text>
</View>
<Text className="font-semibold text-lg">{searchParams.record_time}</Text>
<LucideIcon icon="ChevronDown" size={16} color="#666" clickable={false} />
</TouchableOpacity>
<View className="flex-1">
<Text className="text-gray-500 text-sm">支出</Text>
<Text
className="text-lg font-semibold mt-0.5"
numberOfLines={1}
ellipsizeMode="tail"
>
{moneyRecordStore.getTotalExpense()}
</Text>
</View>
<TouchableOpacity
className="flex flex-row items-center gap-2"
onPress={() => {
setShowActionsMenu(true)
}}
>
<LucideIcon icon="Menu" size={24} clickable={false} />
</TouchableOpacity>
<View className="flex-1">
<Text className="text-gray-500 text-sm">结余</Text>
<Text
className="text-lg font-semibold mt-0.5"
numberOfLines={1}
ellipsizeMode="tail"
>
{moneyRecordStore.getTotalBalance()}
</Text>
</View>
</View>
<View
className="px-3 py-3"
>
<View
className="flex flex-row gap-4"
style={{
borderBottomLeftRadius: 16,
borderBottomRightRadius: 18,
}}
>
<View className="flex-1">
<Text className="text-gray-500 text-sm">收入</Text>
<Text
className="text-lg font-semibold mt-0.5"
numberOfLines={1}
ellipsizeMode="tail"
>
{moneyRecordStore.getTotalIncome()}
</Text>
</View>
{/* <View
<View className="flex-1">
<Text className="text-gray-500 text-sm">支出</Text>
<Text
className="text-lg font-semibold mt-0.5"
numberOfLines={1}
ellipsizeMode="tail"
>
{moneyRecordStore.getTotalExpense()}
</Text>
</View>
<View className="flex-1">
<Text className="text-gray-500 text-sm">结余</Text>
<Text
className="text-lg font-semibold mt-0.5"
numberOfLines={1}
ellipsizeMode="tail"
>
{moneyRecordStore.getTotalBalance()}
</Text>
</View>
</View>
{/* <View
className="flex-row items-center gap-3 mt-2"
style={{
borderBottomLeftRadius: 8,
@@ -196,58 +145,98 @@ export default function Money() {
</View>
<Text className="text-xs text-blue-500">点击设置</Text>
</View> */}
</View>
</View>
</View>
<View className="flex-1 mt-2">
<TransactionsList
records={moneyRecordStore.records}
onUpdate={(data) => {
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()
}}
/>
</View>
<Fab
size="lg"
onPress={() => {
router.navigate('/money/record/editor')
}}
>
<FabIcon as={AddIcon} size="xl" />
</Fab>
<ADatePicker
show={showDatePicker}
mode="month"
date={searchParams.record_time}
onConfirm={(val) => {
setSearchParams({
...searchParams,
record_time: val,
<View className="flex-1 mt-2">
<TransactionsList
records={moneyRecordStore.records}
onUpdate={(data) => {
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()
}}
/>
</Drawer>
</View>
<Fab
size="lg"
onPress={() => {
router.navigate('/money/record/editor')
}}
className="mb-20"
>
<FabIcon as={AddIcon} size="xl" />
</Fab>
<ADatePicker
show={showDatePicker}
mode="month"
date={searchParams.record_time}
onConfirm={(val) => {
setSearchParams({
...searchParams,
record_time: val,
})
setShowDatePicker(false)
}}
onClose={() => {
setShowDatePicker(false)
}}
/>
<ADrawer
visible={showActionsMenu}
hideModal={() => {
setShowActionsMenu(false)
}}
menuPosition="right"
height="60%"
showHeader={false}
>
<SafeAreaView className="flex-col px-3">
<Image
source={require('@/static/images/logo.png')}
style={{ width: 40, height: 40 }}
className="self-center"
/>
<View className="mt-2">
<Text className="text-gray-600 font-semibold text-sm">管理功能</Text>
<View className="p-1">
<AListItem
icon="LayoutGrid"
text="类别设置"
onPress={() => {
router.navigate('/money/category/setting')
}}
/>
</View>
</View>
<View className="mt-2">
<Text className="text-gray-600 font-semibold text-sm">统计分析</Text>
<View className="p-1">
<AListItem icon="ChartSpline" text="图表分析" />
</View>
</View>
</SafeAreaView>
</ADrawer>
</View>
)
}
@@ -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<boolean>(false)
const [form, setForm] = useState<LoginForm>({
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 (
<View className="flex-1">
<CustomHeader title="登录" />
<View className="flex flex-col items-center px-6 h-full">
<Image
source={require('@/static/images/logo.png')}
style={{ width: 120, height: 120 }}
className="my-12"
/>
<AForm form={form}>
<AFormItem label="账号">
<AInput
value={form.account}
onChangeText={text => handleInputChange('account', text)}
/>
</AFormItem>
<AFormItem label="密码">
<AInput
isPassword
value={form.password}
onChangeText={text => handleInputChange('password', text)}
/>
</AFormItem>
</AForm>
<View className="w-full flex-row justify-between items-center mb-6">
<ACheckbox
isChecked={form.rememberMe}
onChange={checked => setForm(prev => ({ ...prev, rememberMe: checked }))}
label="记住我"
/>
<Text className="text-blue-500">忘记密码?</Text>
</View>
<AButton className="w-full" onPress={loginDefault} disabled={!isValid} loading={loading}>
登录
</AButton>
<View className="flex-row items-center my-8 w-full">
<View className="flex-1">
<Divider />
</View>
<Text className="mx-3 text-gray-500 text-sm">社交账号</Text>
<View className="flex-1">
<Divider />
</View>
</View>
<View className="w-full flex-row justify-between items-center">
<IconQq size={32} onPress={loginQq} />
<IconWeixin size={32} onPress={loginWx} />
<IconZhiwen size={32} onPress={loginZhiwen} />
</View>
</View>
</View>
)
}
@@ -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<ScrollView>(null)
const [form, setForm] = useState<RegisterForm>({
username: '',
password: '',
confirmPassword: '',
})
const [loading, setLoading] = useState(false)
const formRef = useRef<AFormRef>(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 (
<View className="flex-1">
<CustomHeader title="注册" />
<ScrollView ref={scrollRef} style={{ flex: 1 }}>
<View className="flex flex-col items-center px-6 bg-white ">
<Image
source={require('@/static/images/logo.png')}
style={{ width: 120, height: 120 }}
className="my-12"
/>
<AForm ref={formRef} form={form} scrollRef={scrollRef}>
<AFormItem
name="username"
label="账号"
isRequired
>
<AInput
placeholder="请输入账号"
leftIcon={UserRound}
value={form.username}
onChangeText={text => handleInputChange('username', text)}
/>
</AFormItem>
<AFormItem
name="password"
label="密码"
isRequired
>
<AInput
placeholder="请输入密码"
leftIcon={Lock}
isPassword
value={form.password}
onChangeText={text => handleInputChange('password', text)}
/>
</AFormItem>
<AFormItem
name="confirmPassword"
label="确认密码"
isRequired
rules={[
{
validator: val => val === form.password,
message: '两次密码不一致',
},
]}
>
<AInput
placeholder="请再次输入密码"
leftIcon={Lock}
isPassword
value={form.confirmPassword}
onChangeText={text => handleInputChange('confirmPassword', text)}
/>
</AFormItem>
</AForm>
<AButton className="w-full mb-4" onPress={handleRegister} loading={loading}>
注册
</AButton>
</View>
</ScrollView>
</View>
)
}
@@ -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<ViewStyle>()
const [drawerMenuBox, setDrawerMenuBox] = useState<ViewStyle>()
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<ViewStyle>(() => {
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 (
<Modal transparent visible animationType="none">
<View style={StyleSheet.absoluteFill} pointerEvents="box-none" className="z-[99]">
{/* 遮罩 */}
<TouchableWithoutFeedback onPress={() => isShadowHideModal && close()}>
<Animated.View
style={[
styles.mask,
{
opacity: anim.interpolate({
inputRange: [0, 1],
outputRange: [0, 0.5],
}),
},
]}
/>
</TouchableWithoutFeedback>
<Animated.View
style={[styles.mask, maskStyle]}
onTouchEnd={() => isShadowHideModal && hideModal()}
/>
{/* Drawer */}
<View style={drawerMenuBox} pointerEvents="box-none">
<Animated.View
pointerEvents="box-none"
style={[
styles.container,
{
transform: [getTransform()],
},
]}
>
<View style={menuPositionStyle}>
{menuPosition !== 'bottom' && (
<View style={{ paddingTop: Platform.OS === 'ios' ? 50 : 0 }} />
)}
{
header || (
<View style={[styles.drawerBox, drawerBox]}>
<GestureDetector gesture={pan}>
<Animated.View
style={[
styles.drawer,
drawerStyle,
{
borderTopLeftRadius: isCircle ? CircleNum : 0,
borderTopRightRadius: isCircle ? CircleNum : 0,
},
]}
>
{showHeader && (
header ?? (
<View style={styles.headTitle}>
<Text style={styles.title}>{title}</Text>
<LucideIcon
icon="X"
size={22}
color="black"
style={{ position: 'absolute', right: 15, top: 11 }}
onPress={close}
style={styles.close}
onPress={hideModal}
/>
</View>
)
}
)}
{children}
</View>
</Animated.View>
</Animated.View>
</GestureDetector>
</View>
</Modal>
</View>
)
}
@@ -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,
},
})
+2 -2
View File
@@ -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,
Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

-2
View File
@@ -26,14 +26,12 @@ export const useAppStore = create<AppState>((set, get) => ({
const moneyCategoryStore = useMoneyCategoryStore.getState()
const spaceStore = useSpaceStore.getState()
// 未登录:跳转到登录页,但认为初始化已完成(允许 UI 继续渲染)
if (!userStore.isLoggedIn()) {
navStore.navigateToAuth()
set({ ready: true })
return
}
// 登录状态:执行完整初始化流程
try {
// 分类初始化
await moneyCategoryStore.init()
+39 -11
View File
@@ -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<NavState>(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<NavState>()(
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),
},
),
)
+9
View File
@@ -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
)
+6
View File
@@ -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=