u
This commit is contained in:
1 parent
fc005e0fb4
commit
10d0cadfe3
18 files changed
+554
-96
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="DataSourcePerFileMappings">
|
<component name="DataSourcePerFileMappings">
|
||||||
|
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d/console_1.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||||
<file url="file://$PROJECT_DIR$/db/queries/finance_category_default.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
<file url="file://$PROJECT_DIR$/db/queries/finance_category_default.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||||
<file url="file://$PROJECT_DIR$/db/queries/finance_category_space.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
<file url="file://$PROJECT_DIR$/db/queries/finance_category_space.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||||
<file url="file://$PROJECT_DIR$/db/queries/space.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
<file url="file://$PROJECT_DIR$/db/queries/space.sql" value="4db2dbd4-857e-4234-ba5e-f8cbf0ba6e5d" />
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func CreateSpace(c fiber.Ctx) error {
|
|||||||
UserID: userID,
|
UserID: userID,
|
||||||
Role: 0,
|
Role: 0,
|
||||||
IsDefault: int16(isDefault),
|
IsDefault: int16(isDefault),
|
||||||
UserName: dto.UserName,
|
MemberName: dto.MemberName,
|
||||||
SortNumber: dto.SortNumber,
|
SortNumber: dto.SortNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +114,7 @@ func CreateSpace(c fiber.Ctx) error {
|
|||||||
return responsex.OK(c, vo)
|
return responsex.OK(c, vo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListUserSpaces 查询该用户的空间
|
||||||
func ListUserSpaces(c fiber.Ctx) error {
|
func ListUserSpaces(c fiber.Ctx) error {
|
||||||
vo := new(types.ListSpacesVO)
|
vo := new(types.ListSpacesVO)
|
||||||
|
|
||||||
@@ -133,13 +134,13 @@ func ListUserSpaces(c fiber.Ctx) error {
|
|||||||
|
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
userSpaces = append(userSpaces, types.UserSpace{
|
userSpaces = append(userSpaces, types.UserSpace{
|
||||||
Id: row.ID,
|
SpaceId: row.SpaceID,
|
||||||
OwnerId: row.OwnerID,
|
OwnerId: row.OwnerID,
|
||||||
Name: row.Name,
|
Name: row.Name,
|
||||||
Role: row.Role,
|
Role: row.Role,
|
||||||
MemberCount: row.MemberCount,
|
MemberCount: row.MemberCount,
|
||||||
IsDefault: row.IsDefault,
|
IsDefault: row.IsDefault,
|
||||||
UserName: row.UserName,
|
MemberName: row.MemberName,
|
||||||
SortNumber: row.SortNumber,
|
SortNumber: row.SortNumber,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -149,6 +150,127 @@ func ListUserSpaces(c fiber.Ctx) error {
|
|||||||
return responsex.OK(c, vo)
|
return responsex.OK(c, vo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DissolveSpace 解散空间
|
||||||
|
func DissolveSpace(c fiber.Ctx) error {
|
||||||
|
dto := new(types.DissolveSpaceDTO)
|
||||||
|
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userId, err := middleware.GetUserID(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
spaceId := dto.SpaceId
|
||||||
|
|
||||||
|
space, err := db.Queries.GetSpaceById(c.Context(), spaceId)
|
||||||
|
if err != nil {
|
||||||
|
if errorx.IsNotFound(err) {
|
||||||
|
return responsex.Error(c, "空间不存在或已解散")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if userId != space.OwnerID {
|
||||||
|
return responsex.Error(c, "您不是该空间的拥有者,无法解散")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Queries.DissolveSpace(c.Context(), spaceId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return responsex.OK(c, "空间已成功解散")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMemberName 更新群成员名称
|
||||||
|
func UpdateMemberName(c fiber.Ctx) error {
|
||||||
|
dto := new(types.UpdateMemberNameDTO)
|
||||||
|
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userId, err := middleware.GetUserID(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Queries.UpdateSpaceMemberName(c.Context(), repo.UpdateSpaceMemberNameParams{
|
||||||
|
SpaceID: dto.SpaceId,
|
||||||
|
UserID: userId,
|
||||||
|
MemberName: dto.MemberName,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return responsex.OK(c, "更新成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSpaceDefault 更新空间默认情况
|
||||||
|
func UpdateSpaceDefault(c fiber.Ctx) error {
|
||||||
|
dto := new(types.UpdateSpaceIsDefaultDTO)
|
||||||
|
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userId, err := middleware.GetUserID(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Queries.UpdateSpaceIsDefault(c.Context(), repo.UpdateSpaceIsDefaultParams{
|
||||||
|
SpaceID: dto.SpaceId,
|
||||||
|
UserID: userId,
|
||||||
|
IsDefault: dto.IsDefault,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return responsex.OK(c, "更新成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateSpaceName(c fiber.Ctx) error {
|
||||||
|
dto := new(types.UpdateSpaceNameDTO)
|
||||||
|
if err := requestx.BindAndValidate(c, dto); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userId, err := middleware.GetUserID(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
spaceId := dto.SpaceId
|
||||||
|
|
||||||
|
space, err := db.Queries.GetSpaceById(c.Context(), spaceId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errorx.IsNotFound(err) {
|
||||||
|
return responsex.Error(c, "空间不存在或已解散")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if userId != space.OwnerID {
|
||||||
|
return responsex.Error(c, "您不是该空间的拥有者,无法修改群名称")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Queries.UpdateSpaceName(c.Context(), repo.UpdateSpaceNameParams{
|
||||||
|
Name: dto.SpaceName,
|
||||||
|
ID: spaceId,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return responsex.OK(c, "更新成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化记账分类
|
||||||
func initFinanceCategory(ctx context.Context, q *repo.Queries, spaceId int64, userId int64) error {
|
func initFinanceCategory(ctx context.Context, q *repo.Queries, spaceId int64, userId int64) error {
|
||||||
categoryDefaults, err := q.ListFinanceCategoryDefault(ctx)
|
categoryDefaults, err := q.ListFinanceCategoryDefault(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ func SetupRouters(app *fiber.App) {
|
|||||||
|
|
||||||
spaceRouter.Post("/create", space.CreateSpace)
|
spaceRouter.Post("/create", space.CreateSpace)
|
||||||
spaceRouter.Post("/list", space.ListUserSpaces)
|
spaceRouter.Post("/list", space.ListUserSpaces)
|
||||||
|
spaceRouter.Post("/dissolve", space.DissolveSpace)
|
||||||
|
spaceRouter.Post("/name", space.UpdateSpaceName)
|
||||||
|
|
||||||
|
spaceRouter.Post("/member/default", space.UpdateSpaceDefault)
|
||||||
|
spaceRouter.Post("/member/name", space.UpdateMemberName)
|
||||||
|
|
||||||
// authGroup.Get("/user/profile", user.GetProfile)
|
// authGroup.Get("/user/profile", user.GetProfile)
|
||||||
// spaceGroup.Get("/space/info", space.GetInfo)
|
// spaceGroup.Get("/space/info", space.GetInfo)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package types
|
|||||||
|
|
||||||
type CreateSpaceDTO struct {
|
type CreateSpaceDTO struct {
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
UserName string `json:"user_name" validate:"required"`
|
MemberName string `json:"member_name" validate:"required"`
|
||||||
SortNumber int32 `json:"sort_number" validate:"required"`
|
SortNumber int32 `json:"sort_number" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,16 +13,35 @@ type CreateSpaceVO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UserSpace struct {
|
type UserSpace struct {
|
||||||
Id int64 `json:"id"`
|
SpaceId int64 `json:"space_id"`
|
||||||
OwnerId int64 `json:"owner_id"`
|
OwnerId int64 `json:"owner_id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Role int16 `json:"role"`
|
Role int16 `json:"role"`
|
||||||
MemberCount int64 `json:"member_count"`
|
MemberCount int64 `json:"member_count"`
|
||||||
IsDefault int16 `json:"is_default"`
|
IsDefault int16 `json:"is_default"`
|
||||||
UserName string `json:"user_name"`
|
MemberName string `json:"member_name"`
|
||||||
SortNumber int32 `json:"sort_number"`
|
SortNumber int32 `json:"sort_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListSpacesVO struct {
|
type ListSpacesVO struct {
|
||||||
Spaces []UserSpace `json:"spaces"`
|
Spaces []UserSpace `json:"spaces"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DissolveSpaceDTO struct {
|
||||||
|
SpaceId int64 `json:"space_id" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateMemberNameDTO struct {
|
||||||
|
SpaceId int64 `json:"space_id" validate:"required"`
|
||||||
|
MemberName string `json:"member_name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateSpaceIsDefaultDTO struct {
|
||||||
|
IsDefault int16 `json:"is_default" validate:"required"`
|
||||||
|
SpaceId int64 `json:"space_id" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateSpaceNameDTO struct {
|
||||||
|
SpaceId int64 `json:"space_id" validate:"required"`
|
||||||
|
SpaceName string `json:"space_name" validate:"required"`
|
||||||
|
}
|
||||||
@@ -9,9 +9,12 @@ INSERT INTO space (
|
|||||||
id,name,invite_code,owner_id,create_time,update_time
|
id,name,invite_code,owner_id,create_time,update_time
|
||||||
) VALUES ($1,$2,$3,$4,NOW(),NOW());
|
) VALUES ($1,$2,$3,$4,NOW(),NOW());
|
||||||
|
|
||||||
-- 删除空间
|
-- name: DissolveSpace :exec
|
||||||
-- name: DeleteSpace :exec
|
UPDATE space SET
|
||||||
DELETE FROM space WHERE id = $1;
|
status = 2,
|
||||||
|
dissolve_time = NOW(),
|
||||||
|
update_time = NOW()
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
-- 根据邀请码获取
|
-- 根据邀请码获取
|
||||||
-- name: GetSpaceByInviteCode :one
|
-- name: GetSpaceByInviteCode :one
|
||||||
@@ -19,13 +22,13 @@ SELECT * FROM space WHERE invite_code = $1;
|
|||||||
|
|
||||||
-- name: ListSpacesByUserId :many
|
-- name: ListSpacesByUserId :many
|
||||||
SELECT
|
SELECT
|
||||||
s.id,
|
s.id AS space_id,
|
||||||
s.owner_id,
|
s.owner_id,
|
||||||
s.name,
|
s.name,
|
||||||
sm.role,
|
sm.role,
|
||||||
COALESCE(mc.member_count, 0) AS member_count,
|
COALESCE(mc.member_count, 0) AS member_count,
|
||||||
sm.is_default,
|
sm.is_default,
|
||||||
sm.user_name,
|
sm.member_name,
|
||||||
sm.sort_number
|
sm.sort_number
|
||||||
FROM space s
|
FROM space s
|
||||||
JOIN space_member sm
|
JOIN space_member sm
|
||||||
@@ -38,3 +41,7 @@ FROM space s
|
|||||||
ON s.id = mc.space_id
|
ON s.id = mc.space_id
|
||||||
WHERE sm.user_id = $1
|
WHERE sm.user_id = $1
|
||||||
ORDER BY sm.is_default DESC, sm.sort_number ASC;
|
ORDER BY sm.is_default DESC, sm.sort_number ASC;
|
||||||
|
|
||||||
|
-- name: UpdateSpaceName :exec
|
||||||
|
UPDATE space SET name = $1
|
||||||
|
WHERE id = $2;
|
||||||
@@ -5,11 +5,23 @@ FROM space_member
|
|||||||
WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
AND space_id = $2;
|
AND space_id = $2;
|
||||||
|
|
||||||
|
-- 插入空间用户
|
||||||
-- name: InsertSpaceMember :exec
|
-- name: InsertSpaceMember :exec
|
||||||
INSERT INTO space_member(id,space_id,user_id,role,is_default,user_name,sort_number,join_time,update_time)
|
INSERT INTO space_member(id,space_id,user_id,role,is_default,member_name,sort_number,join_time,update_time)
|
||||||
VALUES ($1,$2,$3,$4,$5,$6,$7,NOW(),NOW());
|
VALUES ($1,$2,$3,$4,$5,$6,$7,NOW(),NOW());
|
||||||
|
|
||||||
|
-- 合计某个用户的空间数量
|
||||||
-- name: CountUserSpaces :one
|
-- name: CountUserSpaces :one
|
||||||
SELECT COUNT(1)
|
SELECT COUNT(1)
|
||||||
FROM space_member
|
FROM space_member
|
||||||
WHERE user_id = $1;
|
WHERE user_id = $1;
|
||||||
|
|
||||||
|
-- 更新用户在空间内的名称
|
||||||
|
-- name: UpdateSpaceMemberName :exec
|
||||||
|
UPDATE space_member SET member_name = $1
|
||||||
|
WHERE space_id = $2 AND user_id = $3;
|
||||||
|
|
||||||
|
-- 更新空间是否为默认
|
||||||
|
-- name: UpdateSpaceIsDefault :exec
|
||||||
|
UPDATE space_member SET is_default = $1
|
||||||
|
WHERE space_id = $2 AND user_id = $3;
|
||||||
@@ -36,6 +36,9 @@ type Space struct {
|
|||||||
Name string
|
Name string
|
||||||
InviteCode string
|
InviteCode string
|
||||||
OwnerID int64
|
OwnerID int64
|
||||||
|
Status int16
|
||||||
|
DisabledTime pgtype.Timestamptz
|
||||||
|
DissolveTime pgtype.Timestamptz
|
||||||
CreateTime pgtype.Timestamptz
|
CreateTime pgtype.Timestamptz
|
||||||
UpdateTime pgtype.Timestamptz
|
UpdateTime pgtype.Timestamptz
|
||||||
}
|
}
|
||||||
@@ -46,8 +49,11 @@ type SpaceMember struct {
|
|||||||
UserID int64
|
UserID int64
|
||||||
Role int16
|
Role int16
|
||||||
IsDefault int16
|
IsDefault int16
|
||||||
UserName string
|
|
||||||
SortNumber int32
|
SortNumber int32
|
||||||
|
MemberName string
|
||||||
|
Status int16
|
||||||
|
DisabledTime pgtype.Timestamptz
|
||||||
|
ExitTime pgtype.Timestamptz
|
||||||
JoinTime pgtype.Timestamptz
|
JoinTime pgtype.Timestamptz
|
||||||
UpdateTime pgtype.Timestamptz
|
UpdateTime pgtype.Timestamptz
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,18 +9,21 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
const deleteSpace = `-- name: DeleteSpace :exec
|
const dissolveSpace = `-- name: DissolveSpace :exec
|
||||||
DELETE FROM space WHERE id = $1
|
UPDATE space SET
|
||||||
|
status = 2,
|
||||||
|
dissolve_time = NOW(),
|
||||||
|
update_time = NOW()
|
||||||
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
// 删除空间
|
func (q *Queries) DissolveSpace(ctx context.Context, id int64) error {
|
||||||
func (q *Queries) DeleteSpace(ctx context.Context, id int64) error {
|
_, err := q.db.Exec(ctx, dissolveSpace, id)
|
||||||
_, err := q.db.Exec(ctx, deleteSpace, id)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSpaceById = `-- name: GetSpaceById :one
|
const getSpaceById = `-- name: GetSpaceById :one
|
||||||
SELECT id, name, invite_code, owner_id, create_time, update_time FROM space WHERE id = $1
|
SELECT id, name, invite_code, owner_id, status, disabled_time, dissolve_time, create_time, update_time FROM space WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
// 根据id获取分享空间信息
|
// 根据id获取分享空间信息
|
||||||
@@ -32,6 +35,9 @@ func (q *Queries) GetSpaceById(ctx context.Context, id int64) (Space, error) {
|
|||||||
&i.Name,
|
&i.Name,
|
||||||
&i.InviteCode,
|
&i.InviteCode,
|
||||||
&i.OwnerID,
|
&i.OwnerID,
|
||||||
|
&i.Status,
|
||||||
|
&i.DisabledTime,
|
||||||
|
&i.DissolveTime,
|
||||||
&i.CreateTime,
|
&i.CreateTime,
|
||||||
&i.UpdateTime,
|
&i.UpdateTime,
|
||||||
)
|
)
|
||||||
@@ -39,7 +45,7 @@ func (q *Queries) GetSpaceById(ctx context.Context, id int64) (Space, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getSpaceByInviteCode = `-- name: GetSpaceByInviteCode :one
|
const getSpaceByInviteCode = `-- name: GetSpaceByInviteCode :one
|
||||||
SELECT id, name, invite_code, owner_id, create_time, update_time FROM space WHERE invite_code = $1
|
SELECT id, name, invite_code, owner_id, status, disabled_time, dissolve_time, create_time, update_time FROM space WHERE invite_code = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
// 根据邀请码获取
|
// 根据邀请码获取
|
||||||
@@ -51,6 +57,9 @@ func (q *Queries) GetSpaceByInviteCode(ctx context.Context, inviteCode string) (
|
|||||||
&i.Name,
|
&i.Name,
|
||||||
&i.InviteCode,
|
&i.InviteCode,
|
||||||
&i.OwnerID,
|
&i.OwnerID,
|
||||||
|
&i.Status,
|
||||||
|
&i.DisabledTime,
|
||||||
|
&i.DissolveTime,
|
||||||
&i.CreateTime,
|
&i.CreateTime,
|
||||||
&i.UpdateTime,
|
&i.UpdateTime,
|
||||||
)
|
)
|
||||||
@@ -83,13 +92,13 @@ func (q *Queries) InsertSpace(ctx context.Context, arg InsertSpaceParams) error
|
|||||||
|
|
||||||
const listSpacesByUserId = `-- name: ListSpacesByUserId :many
|
const listSpacesByUserId = `-- name: ListSpacesByUserId :many
|
||||||
SELECT
|
SELECT
|
||||||
s.id,
|
s.id AS space_id,
|
||||||
s.owner_id,
|
s.owner_id,
|
||||||
s.name,
|
s.name,
|
||||||
sm.role,
|
sm.role,
|
||||||
COALESCE(mc.member_count, 0) AS member_count,
|
COALESCE(mc.member_count, 0) AS member_count,
|
||||||
sm.is_default,
|
sm.is_default,
|
||||||
sm.user_name,
|
sm.member_name,
|
||||||
sm.sort_number
|
sm.sort_number
|
||||||
FROM space s
|
FROM space s
|
||||||
JOIN space_member sm
|
JOIN space_member sm
|
||||||
@@ -105,13 +114,13 @@ ORDER BY sm.is_default DESC, sm.sort_number ASC
|
|||||||
`
|
`
|
||||||
|
|
||||||
type ListSpacesByUserIdRow struct {
|
type ListSpacesByUserIdRow struct {
|
||||||
ID int64
|
SpaceID int64
|
||||||
OwnerID int64
|
OwnerID int64
|
||||||
Name string
|
Name string
|
||||||
Role int16
|
Role int16
|
||||||
MemberCount int64
|
MemberCount int64
|
||||||
IsDefault int16
|
IsDefault int16
|
||||||
UserName string
|
MemberName string
|
||||||
SortNumber int32
|
SortNumber int32
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,13 +134,13 @@ func (q *Queries) ListSpacesByUserId(ctx context.Context, userID int64) ([]ListS
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i ListSpacesByUserIdRow
|
var i ListSpacesByUserIdRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.SpaceID,
|
||||||
&i.OwnerID,
|
&i.OwnerID,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.Role,
|
&i.Role,
|
||||||
&i.MemberCount,
|
&i.MemberCount,
|
||||||
&i.IsDefault,
|
&i.IsDefault,
|
||||||
&i.UserName,
|
&i.MemberName,
|
||||||
&i.SortNumber,
|
&i.SortNumber,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -143,3 +152,18 @@ func (q *Queries) ListSpacesByUserId(ctx context.Context, userID int64) ([]ListS
|
|||||||
}
|
}
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateSpaceName = `-- name: UpdateSpaceName :exec
|
||||||
|
UPDATE space SET name = $1
|
||||||
|
WHERE id = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateSpaceNameParams struct {
|
||||||
|
Name string
|
||||||
|
ID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateSpaceName(ctx context.Context, arg UpdateSpaceNameParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateSpaceName, arg.Name, arg.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ func (q *Queries) GetUserSpaceRole(ctx context.Context, arg GetUserSpaceRolePara
|
|||||||
}
|
}
|
||||||
|
|
||||||
const insertSpaceMember = `-- name: InsertSpaceMember :exec
|
const insertSpaceMember = `-- name: InsertSpaceMember :exec
|
||||||
INSERT INTO space_member(id,space_id,user_id,role,is_default,user_name,sort_number,join_time,update_time)
|
INSERT INTO space_member(id,space_id,user_id,role,is_default,member_name,sort_number,join_time,update_time)
|
||||||
VALUES ($1,$2,$3,$4,$5,$6,$7,NOW(),NOW())
|
VALUES ($1,$2,$3,$4,$5,$6,$7,NOW(),NOW())
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ type InsertSpaceMemberParams struct {
|
|||||||
UserID int64
|
UserID int64
|
||||||
Role int16
|
Role int16
|
||||||
IsDefault int16
|
IsDefault int16
|
||||||
UserName string
|
MemberName string
|
||||||
SortNumber int32
|
SortNumber int32
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +64,40 @@ func (q *Queries) InsertSpaceMember(ctx context.Context, arg InsertSpaceMemberPa
|
|||||||
arg.UserID,
|
arg.UserID,
|
||||||
arg.Role,
|
arg.Role,
|
||||||
arg.IsDefault,
|
arg.IsDefault,
|
||||||
arg.UserName,
|
arg.MemberName,
|
||||||
arg.SortNumber,
|
arg.SortNumber,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateSpaceIsDefault = `-- name: UpdateSpaceIsDefault :exec
|
||||||
|
UPDATE space_member SET is_default = $1
|
||||||
|
WHERE space_id = $2 AND user_id = $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateSpaceIsDefaultParams struct {
|
||||||
|
IsDefault int16
|
||||||
|
SpaceID int64
|
||||||
|
UserID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateSpaceIsDefault(ctx context.Context, arg UpdateSpaceIsDefaultParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateSpaceIsDefault, arg.IsDefault, arg.SpaceID, arg.UserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateSpaceMemberName = `-- name: UpdateSpaceMemberName :exec
|
||||||
|
UPDATE space_member SET member_name = $1
|
||||||
|
WHERE space_id = $2 AND user_id = $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateSpaceMemberNameParams struct {
|
||||||
|
MemberName string
|
||||||
|
SpaceID int64
|
||||||
|
UserID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateSpaceMemberName(ctx context.Context, arg UpdateSpaceMemberNameParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, updateSpaceMemberName, arg.MemberName, arg.SpaceID, arg.UserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -23,27 +23,47 @@ primary key,
|
|||||||
|
|
||||||
create table space
|
create table space
|
||||||
(
|
(
|
||||||
id bigint not null
|
id bigint primary key,
|
||||||
primary key,
|
|
||||||
|
-- 核心业务字段
|
||||||
name varchar(255) not null,
|
name varchar(255) not null,
|
||||||
invite_code varchar(30) not null,
|
invite_code varchar(30) not null unique,
|
||||||
owner_id bigint not null,
|
owner_id bigint not null,
|
||||||
create_time timestamp with time zone default now(),
|
|
||||||
update_time timestamp with time zone default now()
|
-- 状态字段
|
||||||
|
status smallint default 0 not null, -- 0 active 1 disabled 2 dissolved
|
||||||
|
disabled_time timestamp with time zone,
|
||||||
|
dissolve_time timestamp with time zone,
|
||||||
|
|
||||||
|
-- 时间字段
|
||||||
|
create_time timestamp with time zone default now() not null,
|
||||||
|
update_time timestamp with time zone default now() not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table space_member
|
create table space_member
|
||||||
(
|
(
|
||||||
id bigint not null
|
id bigint primary key,
|
||||||
primary key,
|
|
||||||
|
-- 关系核心字段
|
||||||
space_id bigint not null,
|
space_id bigint not null,
|
||||||
user_id bigint not null,
|
user_id bigint not null,
|
||||||
|
|
||||||
|
-- 角色 & 默认
|
||||||
role smallint default 2 not null,
|
role smallint default 2 not null,
|
||||||
is_default smallint default 0 not null,
|
is_default smallint default 0 not null,
|
||||||
user_name varchar(255) not null,
|
|
||||||
sort_number integer default 0 not null,
|
sort_number integer default 0 not null,
|
||||||
join_time timestamp with time zone default now(),
|
member_name varchar(255) not null,
|
||||||
update_time timestamp with time zone default now()
|
|
||||||
|
-- 成员状态
|
||||||
|
status smallint default 0 not null, -- 0 active 1 disabled 2 exited
|
||||||
|
disabled_time timestamp with time zone,
|
||||||
|
exit_time timestamp with time zone,
|
||||||
|
|
||||||
|
-- 时间字段
|
||||||
|
join_time timestamp with time zone default now() not null,
|
||||||
|
update_time timestamp with time zone default now() not null,
|
||||||
|
|
||||||
|
unique (space_id, user_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
create table finance_category_default
|
create table finance_category_default
|
||||||
|
|||||||
@@ -56,10 +56,8 @@
|
|||||||
"react-native-screens": "~4.16.0",
|
"react-native-screens": "~4.16.0",
|
||||||
"react-native-sortables": "^1.9.3",
|
"react-native-sortables": "^1.9.3",
|
||||||
"react-native-svg": "15.12.1",
|
"react-native-svg": "15.12.1",
|
||||||
"react-native-toast-message": "^2.3.3",
|
|
||||||
"react-native-web": "^0.21.0",
|
"react-native-web": "^0.21.0",
|
||||||
"react-native-worklets": "0.5.1",
|
"react-native-worklets": "0.5.1",
|
||||||
"react-native-z-view": "^0.2.4",
|
|
||||||
"sonner-native": "^0.23.1",
|
"sonner-native": "^0.23.1",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.4.0",
|
||||||
"victory-native": "^37.3.6",
|
"victory-native": "^37.3.6",
|
||||||
|
|||||||
Generated
-30
@@ -146,18 +146,12 @@ importers:
|
|||||||
react-native-svg:
|
react-native-svg:
|
||||||
specifier: 15.12.1
|
specifier: 15.12.1
|
||||||
version: 15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
version: 15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
react-native-toast-message:
|
|
||||||
specifier: ^2.3.3
|
|
||||||
version: 2.3.3(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
|
||||||
react-native-web:
|
react-native-web:
|
||||||
specifier: ^0.21.0
|
specifier: ^0.21.0
|
||||||
version: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
react-native-worklets:
|
react-native-worklets:
|
||||||
specifier: 0.5.1
|
specifier: 0.5.1
|
||||||
version: 0.5.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
version: 0.5.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
react-native-z-view:
|
|
||||||
specifier: ^0.2.4
|
|
||||||
version: 0.2.4(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
|
||||||
sonner-native:
|
sonner-native:
|
||||||
specifier: ^0.23.1
|
specifier: ^0.23.1
|
||||||
version: 0.23.1(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@0.5.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
version: 0.23.1(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@0.5.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
@@ -5123,12 +5117,6 @@ packages:
|
|||||||
react: '*'
|
react: '*'
|
||||||
react-native: '*'
|
react-native: '*'
|
||||||
|
|
||||||
react-native-toast-message@2.3.3:
|
|
||||||
resolution: {integrity: sha512-4IIUHwUPvKHu4gjD0Vj2aGQzqPATiblL1ey8tOqsxOWRPGGu52iIbL8M/mCz4uyqecvPdIcMY38AfwRuUADfQQ==}
|
|
||||||
peerDependencies:
|
|
||||||
react: '*'
|
|
||||||
react-native: '*'
|
|
||||||
|
|
||||||
react-native-web@0.21.2:
|
react-native-web@0.21.2:
|
||||||
resolution: {integrity: sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==}
|
resolution: {integrity: sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -5142,13 +5130,6 @@ packages:
|
|||||||
react: '*'
|
react: '*'
|
||||||
react-native: '*'
|
react-native: '*'
|
||||||
|
|
||||||
react-native-z-view@0.2.4:
|
|
||||||
resolution: {integrity: sha512-K/z6GhHmDsyEZAy6ib8DEmITSyPb0rCJ95IZjilZbAarx8xB6prdvHvtgmCg67nFKO/l/ldBuYhvxQmClda+pQ==}
|
|
||||||
peerDependencies:
|
|
||||||
react: '*'
|
|
||||||
react-native: '*'
|
|
||||||
react-native-screens: '*'
|
|
||||||
|
|
||||||
react-native@0.81.5:
|
react-native@0.81.5:
|
||||||
resolution: {integrity: sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==}
|
resolution: {integrity: sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==}
|
||||||
engines: {node: '>= 20.19.4'}
|
engines: {node: '>= 20.19.4'}
|
||||||
@@ -12365,11 +12346,6 @@ snapshots:
|
|||||||
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
||||||
warn-once: 0.1.1
|
warn-once: 0.1.1
|
||||||
|
|
||||||
react-native-toast-message@2.3.3(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
|
||||||
dependencies:
|
|
||||||
react: 19.1.0
|
|
||||||
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
|
||||||
|
|
||||||
react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.4
|
'@babel/runtime': 7.28.4
|
||||||
@@ -12404,12 +12380,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
react-native-z-view@0.2.4(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
|
||||||
dependencies:
|
|
||||||
react: 19.1.0
|
|
||||||
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
|
||||||
react-native-screens: 4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
|
||||||
|
|
||||||
react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0):
|
react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/create-cache-key-function': 29.7.0
|
'@jest/create-cache-key-function': 29.7.0
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ export default function Auth() {
|
|||||||
// avatar: loginRes.data.avatar,
|
// avatar: loginRes.data.avatar,
|
||||||
// })
|
// })
|
||||||
|
|
||||||
// router.push('/auth/space')
|
// router.push('/space/manage')
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// catch (err) {
|
// catch (err) {
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
import type { UserSpace } from '@/types/space'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { Text, View } from 'react-native'
|
||||||
|
import { toast } from 'sonner-native'
|
||||||
|
import { LucideIcon } from '@/components/common/ao'
|
||||||
|
import { AInput, AModal } from '@/components/common/ao/index'
|
||||||
|
import {
|
||||||
|
Actionsheet,
|
||||||
|
ActionsheetBackdrop,
|
||||||
|
ActionsheetContent,
|
||||||
|
ActionsheetDragIndicator,
|
||||||
|
ActionsheetDragIndicatorWrapper,
|
||||||
|
ActionsheetIcon,
|
||||||
|
ActionsheetItem,
|
||||||
|
ActionsheetItemText,
|
||||||
|
} from '@/components/ui/actionsheet'
|
||||||
|
import { dissolveSpaceApi } from '@/request/api/space'
|
||||||
|
import { useUserStore } from '@/store/user'
|
||||||
|
|
||||||
|
interface SettingActionsProps {
|
||||||
|
isOpen: boolean
|
||||||
|
onClose: () => void
|
||||||
|
|
||||||
|
space: UserSpace | null
|
||||||
|
|
||||||
|
onActionSuccess?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SettingActions(
|
||||||
|
{
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
space,
|
||||||
|
onActionSuccess
|
||||||
|
}: SettingActionsProps,
|
||||||
|
) {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
const [localSpace, setLocalSpace] = useState(space)
|
||||||
|
|
||||||
|
const [showNameModal, setShowNameModal] = useState(false)
|
||||||
|
|
||||||
|
const [showMemberNameModal, setShowMemberNameModal] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLocalSpace(space)
|
||||||
|
}, [space])
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Actionsheet
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={() => {
|
||||||
|
onClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ActionsheetBackdrop />
|
||||||
|
<ActionsheetContent
|
||||||
|
style={{
|
||||||
|
paddingBottom: 6,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ActionsheetDragIndicatorWrapper>
|
||||||
|
<ActionsheetDragIndicator />
|
||||||
|
</ActionsheetDragIndicatorWrapper>
|
||||||
|
{
|
||||||
|
space?.role === 0 && (
|
||||||
|
<ActionsheetItem>
|
||||||
|
<ActionsheetIcon
|
||||||
|
as={() => <LucideIcon icon="UserCog" />}
|
||||||
|
/>
|
||||||
|
<ActionsheetItemText>成员管理</ActionsheetItemText>
|
||||||
|
</ActionsheetItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
space?.owner_id === userStore.userInfo.id && (
|
||||||
|
<ActionsheetItem onPress={() => {
|
||||||
|
setShowNameModal(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ActionsheetIcon
|
||||||
|
as={() => <LucideIcon icon="Pencil" />}
|
||||||
|
/>
|
||||||
|
<ActionsheetItemText>修改空间名称</ActionsheetItemText>
|
||||||
|
</ActionsheetItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<ActionsheetItem>
|
||||||
|
<ActionsheetIcon
|
||||||
|
as={() => <LucideIcon icon="Pencil" />}
|
||||||
|
/>
|
||||||
|
<ActionsheetItemText>修改我的空间昵称</ActionsheetItemText>
|
||||||
|
</ActionsheetItem>
|
||||||
|
|
||||||
|
<ActionsheetItem>
|
||||||
|
<ActionsheetIcon
|
||||||
|
as={() => <LucideIcon icon="Star" />}
|
||||||
|
/>
|
||||||
|
<ActionsheetItemText>
|
||||||
|
{space?.is_default === 1 ? '取消' : '设置'}
|
||||||
|
默认
|
||||||
|
</ActionsheetItemText>
|
||||||
|
</ActionsheetItem>
|
||||||
|
|
||||||
|
<ActionsheetItem onPress={() => {
|
||||||
|
if (space?.owner_id === userStore.userInfo.id) {
|
||||||
|
// 解散空间
|
||||||
|
dissolveSpaceApi({
|
||||||
|
space_id: space.space_id,
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.isSuccess) {
|
||||||
|
toast.success('空间已解散')
|
||||||
|
onActionSuccess?.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 退出空间
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ActionsheetIcon
|
||||||
|
as={() => <LucideIcon icon="LogOut" />}
|
||||||
|
/>
|
||||||
|
<ActionsheetItemText>
|
||||||
|
{space?.owner_id === userStore.userInfo.id ? '解散' : '退出'}
|
||||||
|
空间
|
||||||
|
</ActionsheetItemText>
|
||||||
|
</ActionsheetItem>
|
||||||
|
|
||||||
|
</ActionsheetContent>
|
||||||
|
</Actionsheet>
|
||||||
|
|
||||||
|
<AModal
|
||||||
|
title="修改空间名称"
|
||||||
|
showCloseIcon
|
||||||
|
body={
|
||||||
|
(
|
||||||
|
<View className="gap-2">
|
||||||
|
<Text>空间名称</Text>
|
||||||
|
<AInput
|
||||||
|
value={localSpace?.name || ''}
|
||||||
|
onChangeText={(val) => {
|
||||||
|
setLocalSpace(prev => prev
|
||||||
|
? ({
|
||||||
|
...prev,
|
||||||
|
name: val,
|
||||||
|
})
|
||||||
|
: null)
|
||||||
|
}}
|
||||||
|
className="flex-1"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
isOpen={showNameModal}
|
||||||
|
onCancel={() => {
|
||||||
|
setShowNameModal(false)
|
||||||
|
setLocalSpace(space)
|
||||||
|
}}
|
||||||
|
onClose={() => {
|
||||||
|
setShowNameModal(false)
|
||||||
|
setLocalSpace(space)
|
||||||
|
}}
|
||||||
|
onConfirm={async () => {
|
||||||
|
// 更新名称
|
||||||
|
if (!localSpace?.name) {
|
||||||
|
toast.warning('请输入空间名称')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</AModal>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
+77
-11
@@ -1,5 +1,5 @@
|
|||||||
import type { UserSpace } from '@/types/space'
|
import type { UserSpace } from '@/types/space'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Pressable, Text, View } from 'react-native'
|
import { Pressable, Text, View } from 'react-native'
|
||||||
import Animated, { useAnimatedRef } from 'react-native-reanimated'
|
import Animated, { useAnimatedRef } from 'react-native-reanimated'
|
||||||
import Sortable from 'react-native-sortables'
|
import Sortable from 'react-native-sortables'
|
||||||
@@ -11,12 +11,18 @@ import CustomHeader from '@/components/custom/Header'
|
|||||||
import { Badge, BadgeText } from '@/components/ui/badge'
|
import { Badge, BadgeText } from '@/components/ui/badge'
|
||||||
import { createSpaceApi, listUserSpacesApi } from '@/request/api/space/index'
|
import { createSpaceApi, listUserSpacesApi } from '@/request/api/space/index'
|
||||||
import { useUserStore } from '@/store/user'
|
import { useUserStore } from '@/store/user'
|
||||||
|
import SettingActions from './components/SettingActions'
|
||||||
|
|
||||||
export default function AuthSpace() {
|
export default function AuthSpace() {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
// scrollView 相关
|
||||||
const scrollableRef = useAnimatedRef<Animated.ScrollView>()
|
const scrollableRef = useAnimatedRef<Animated.ScrollView>()
|
||||||
|
const [scrollHeight, setScrollHeight] = useState(0)
|
||||||
|
const ITEM_HEIGHT = 64
|
||||||
|
|
||||||
|
// 空间列表
|
||||||
|
const [spaces, setSpaces] = useState<UserSpace[]>([])
|
||||||
const [selectedId, setSelectedId] = useState<number | null>(null)
|
const [selectedId, setSelectedId] = useState<number | null>(null)
|
||||||
|
|
||||||
// 新建
|
// 新建
|
||||||
@@ -25,8 +31,11 @@ export default function AuthSpace() {
|
|||||||
name: '',
|
name: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const [spaces, setSpaces] = useState<UserSpace[]>([])
|
// 设置
|
||||||
|
const [showSettings, setShowSettings] = useState(false)
|
||||||
|
const [settingCurrentSpace, setSettingCurrentSpace] = useState<UserSpace | null>(null)
|
||||||
|
|
||||||
|
// 获取空间列表
|
||||||
function listUserSpaces() {
|
function listUserSpaces() {
|
||||||
listUserSpacesApi().then((res) => {
|
listUserSpacesApi().then((res) => {
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
@@ -36,12 +45,18 @@ export default function AuthSpace() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const renderItem
|
const renderItem
|
||||||
= ({ item }: { item: UserSpace }) => (
|
= ({ item, index }: { item: UserSpace, index: number }) => (
|
||||||
<Pressable
|
<Pressable
|
||||||
key={item.id}
|
key={item.space_id}
|
||||||
onPress={() => setSelectedId(item.id)}
|
onPress={() => {
|
||||||
|
setSelectedId(item.space_id)
|
||||||
|
scrollToCenter(index)
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
height: ITEM_HEIGHT,
|
||||||
|
}}
|
||||||
className={`rounded-md flex-row items-center justify-between px-4 py-3 border
|
className={`rounded-md flex-row items-center justify-between px-4 py-3 border
|
||||||
${item.id === selectedId ? 'border-gray-700' : 'border-gray-300'}`}
|
${item.space_id === selectedId ? 'border-gray-700' : 'border-gray-300'}`}
|
||||||
>
|
>
|
||||||
<View className="flex-row items-center">
|
<View className="flex-row items-center">
|
||||||
<Sortable.Handle>
|
<Sortable.Handle>
|
||||||
@@ -83,7 +98,7 @@ export default function AuthSpace() {
|
|||||||
<Text
|
<Text
|
||||||
className="text-xs"
|
className="text-xs"
|
||||||
>
|
>
|
||||||
{item.user_name}
|
{item.member_name}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className="flex-row gap-1">
|
<View className="flex-row gap-1">
|
||||||
@@ -98,21 +113,55 @@ export default function AuthSpace() {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
<View className="flex flex-row items-center gap-3">
|
||||||
|
<View className="w-8 h-8 rounded-full items-center justify-center bg-[#333333]">
|
||||||
|
<LucideIcon
|
||||||
|
icon="UserPlus"
|
||||||
|
size={18}
|
||||||
|
color="#fff"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Pressable
|
||||||
|
className="w-8 h-8 rounded-full items-center justify-center bg-[#333333]"
|
||||||
|
onPress={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
setSettingCurrentSpace(item)
|
||||||
|
setShowSettings(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<LucideIcon
|
<LucideIcon
|
||||||
icon="Bolt"
|
icon="Bolt"
|
||||||
size={20}
|
size={18}
|
||||||
className="p-1"
|
color="#fff"
|
||||||
|
clickable={false}
|
||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const scrollToCenter = (index: number) => {
|
||||||
|
if (!scrollHeight)
|
||||||
|
return
|
||||||
|
|
||||||
|
const itemTop = index * ITEM_HEIGHT
|
||||||
|
|
||||||
|
const scrollY
|
||||||
|
= itemTop - scrollHeight / 2 + ITEM_HEIGHT / 2
|
||||||
|
|
||||||
|
scrollableRef.current?.scrollTo({
|
||||||
|
y: Math.max(0, scrollY),
|
||||||
|
animated: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
listUserSpaces()
|
listUserSpaces()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className="flex-1 bg-white">
|
<View className="flex-1 bg-white">
|
||||||
{/* Header */}
|
|
||||||
<CustomHeader title="空间列表" />
|
<CustomHeader title="空间列表" />
|
||||||
|
|
||||||
<View className="flex-1 px-4">
|
<View className="flex-1 px-4">
|
||||||
@@ -146,6 +195,9 @@ export default function AuthSpace() {
|
|||||||
className="flex-1"
|
className="flex-1"
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
ref={scrollableRef}
|
ref={scrollableRef}
|
||||||
|
onLayout={(e) => {
|
||||||
|
setScrollHeight(e.nativeEvent.layout.height)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{spaces.length === 0
|
{spaces.length === 0
|
||||||
? (
|
? (
|
||||||
@@ -218,7 +270,7 @@ export default function AuthSpace() {
|
|||||||
|
|
||||||
await createSpaceApi({
|
await createSpaceApi({
|
||||||
name: createForm.name,
|
name: createForm.name,
|
||||||
user_name: userStore.userInfo.nickname,
|
member_name: userStore.userInfo.nickname,
|
||||||
sort_number: 0,
|
sort_number: 0,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
@@ -227,11 +279,25 @@ export default function AuthSpace() {
|
|||||||
setCreateForm({
|
setCreateForm({
|
||||||
name: '',
|
name: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
listUserSpaces()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
</AModal>
|
</AModal>
|
||||||
|
|
||||||
|
<SettingActions
|
||||||
|
isOpen={showSettings}
|
||||||
|
onClose={() => {
|
||||||
|
setShowSettings(false)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setSettingCurrentSpace(null)
|
||||||
|
}, 300)
|
||||||
|
}}
|
||||||
|
space={settingCurrentSpace}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,9 @@ import type { Method } from 'alova'
|
|||||||
import type { AxiosError } from 'axios'
|
import type { AxiosError } from 'axios'
|
||||||
import { axiosRequestAdapter } from '@alova/adapter-axios'
|
import { axiosRequestAdapter } from '@alova/adapter-axios'
|
||||||
import { createAlova } from 'alova'
|
import { createAlova } from 'alova'
|
||||||
|
import { toast } from 'sonner-native'
|
||||||
import { useNavStore } from '@/store/navigation'
|
import { useNavStore } from '@/store/navigation'
|
||||||
import { useUserStore } from '@/store/user'
|
import { useUserStore } from '@/store/user'
|
||||||
import { toast } from '@/utils/toast'
|
|
||||||
|
|
||||||
enum HttpCode {
|
enum HttpCode {
|
||||||
Success = 1000,
|
Success = 1000,
|
||||||
@@ -28,8 +28,8 @@ function isWhiteListed(url: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const alovaInstance = createAlova({
|
const alovaInstance = createAlova({
|
||||||
baseURL: 'http://192.168.5.6:8086/app',
|
// baseURL: 'http://192.168.5.6:8086/app',
|
||||||
// baseURL: 'http://192.168.1.137:8086/app',
|
baseURL: 'http://192.168.1.137:8086/app',
|
||||||
requestAdapter: axiosRequestAdapter(),
|
requestAdapter: axiosRequestAdapter(),
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
cacheFor: null,
|
cacheFor: null,
|
||||||
@@ -44,6 +44,7 @@ const alovaInstance = createAlova({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (resData.code === HttpCode.Unauthorized) {
|
if (resData.code === HttpCode.Unauthorized) {
|
||||||
|
toast.error('登录状态已过期,请重新登录')
|
||||||
useUserStore.getState().clear()
|
useUserStore.getState().clear()
|
||||||
useNavStore.getState().navigateToAuth()
|
useNavStore.getState().navigateToAuth()
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -23,11 +23,10 @@ const DEFAULT_NAV_MENUS: NavItem[] = [
|
|||||||
{ label: '恋爱记', path: '/love', icon: 'Heart' },
|
{ label: '恋爱记', path: '/love', icon: 'Heart' },
|
||||||
{ label: '聊天', path: '/chat', icon: 'MessageCircle' },
|
{ label: '聊天', path: '/chat', icon: 'MessageCircle' },
|
||||||
{ label: '个人中心', path: '/user', icon: 'CircleUserRound' },
|
{ label: '个人中心', path: '/user', icon: 'CircleUserRound' },
|
||||||
{ label: '我的空间', path: '/auth/space', icon: 'Earth' },
|
{ label: '我的空间', path: '/space/manage', icon: 'Earth' },
|
||||||
]
|
]
|
||||||
|
|
||||||
export const useNavStore = create<NavState>()(
|
export const useNavStore = create<NavState>()(
|
||||||
persist(
|
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
pathname: '/',
|
pathname: '/',
|
||||||
navMenus: DEFAULT_NAV_MENUS,
|
navMenus: DEFAULT_NAV_MENUS,
|
||||||
@@ -42,9 +41,4 @@ export const useNavStore = create<NavState>()(
|
|||||||
},
|
},
|
||||||
setNavMenus: navMenus => set({ navMenus }),
|
setNavMenus: navMenus => set({ navMenus }),
|
||||||
}),
|
}),
|
||||||
{
|
|
||||||
name: 'nav-storage',
|
|
||||||
storage: createJSONStorage(() => AsyncStorage),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
@@ -1,21 +1,22 @@
|
|||||||
export interface UserSpace {
|
export interface UserSpace {
|
||||||
id: number
|
space_id: number
|
||||||
owner_id: number
|
owner_id: number
|
||||||
name: string
|
name: string
|
||||||
role: number
|
role: number
|
||||||
member_count: number
|
member_count: number
|
||||||
is_default: number
|
is_default: number
|
||||||
|
|
||||||
user_name: string
|
member_name: string
|
||||||
sort_number: number
|
sort_number: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建空间
|
// 创建空间
|
||||||
export interface CreateSpaceParams {
|
export interface CreateSpaceParams {
|
||||||
name: string
|
name: string
|
||||||
user_name: string
|
member_name: string
|
||||||
sort_number: number
|
sort_number: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateSpaceResult {
|
export interface CreateSpaceResult {
|
||||||
space_id: number
|
space_id: number
|
||||||
invite_code: string
|
invite_code: string
|
||||||
@@ -37,6 +38,7 @@ export interface DissolveSpaceResult {
|
|||||||
export interface JoinSpaceParams {
|
export interface JoinSpaceParams {
|
||||||
invite_code: string
|
invite_code: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface JoinSpaceResult {
|
export interface JoinSpaceResult {
|
||||||
space_id: number
|
space_id: number
|
||||||
space_name: string
|
space_name: string
|
||||||
|
|||||||
Reference in new issue
Block a user