This commit is contained in:
oneao committed 2026-02-27 22:09:50 +08:00
1 parent 1b1a54f7dd
commit fc005e0fb4
22 files changed
+300 -193

No files matched your search

-10
View File
@@ -1,10 +0,0 @@
package handler
import (
"github.com/gofiber/fiber/v3"
)
// Hello handle api status
func Hello(c fiber.Ctx) error {
panic("测试 panic")
}
@@ -53,11 +53,24 @@ func CreateSpace(c fiber.Ctx) error {
spaceId := uniqueid.NextId()
err := db.WithTx(c.Context(), func(q *repo.Queries) error {
// 查询是否存在空间
countSpaces, err3 := q.CountUserSpaces(c.Context(), userID)
if err3 != nil {
return err3
}
isDefault := 0
if countSpaces == 0 {
isDefault = 1
}
// 创建空间
params := repo.InsertSpaceParams{
ID: spaceId,
Name: dto.Name,
InviteCode: inviteCode,
OwnerID: userID,
}
err := q.InsertSpace(c.Context(), params)
@@ -68,10 +81,13 @@ func CreateSpace(c fiber.Ctx) error {
// 将创建用户默认添加到该空间内
spaceMemberParams := repo.InsertSpaceMemberParams{
ID: uniqueid.NextId(),
SpaceID: spaceId,
UserID: userID,
Role: 0,
ID: uniqueid.NextId(),
SpaceID: spaceId,
UserID: userID,
Role: 0,
IsDefault: int16(isDefault),
UserName: dto.UserName,
SortNumber: dto.SortNumber,
}
err = q.InsertSpaceMember(c.Context(), spaceMemberParams)
@@ -98,6 +114,41 @@ func CreateSpace(c fiber.Ctx) error {
return responsex.OK(c, vo)
}
func ListUserSpaces(c fiber.Ctx) error {
vo := new(types.ListSpacesVO)
userID, err := middleware.GetUserID(c)
if err != nil {
return err
}
rows, err := db.Queries.ListSpacesByUserId(c.Context(), userID)
if err != nil {
return err
}
userSpaces := make([]types.UserSpace, 0, len(rows))
for _, row := range rows {
userSpaces = append(userSpaces, types.UserSpace{
Id: row.ID,
OwnerId: row.OwnerID,
Name: row.Name,
Role: row.Role,
MemberCount: row.MemberCount,
IsDefault: row.IsDefault,
UserName: row.UserName,
SortNumber: row.SortNumber,
})
}
vo.Spaces = userSpaces
return responsex.OK(c, vo)
}
func initFinanceCategory(ctx context.Context, q *repo.Queries, spaceId int64, userId int64) error {
categoryDefaults, err := q.ListFinanceCategoryDefault(ctx)
if err != nil {
+6 -11
View File
@@ -12,23 +12,18 @@ import (
func SetupRouters(app *fiber.App) {
api := app.Group(config.GetConf().Server.BaseUrl)
// 1️⃣ 公开接口(无需登录)
publicGroup := api.Group("")
// 2️⃣ 需要登录
authGroup := api.Group("", middleware.Auth())
//
//// 3️⃣ 需要登录 + 需要空间
//spaceGroup := api.Group("", middleware.Auth(), middleware.SpaceGuard())
// --------------------
// auth
authRouter := publicGroup.Group("/auth")
authRouter := api.Group("/auth")
authRouter.Post("/login/qq", auth.LoginQq)
authRouter.Post("/login/wechat", auth.LoginWechat)
// 空间操作
authGroup.Post("/space/create", space.CreateSpace)
spaceRouter := api.Group("/space").Use(middleware.Auth())
spaceRouter.Post("/create", space.CreateSpace)
spaceRouter.Post("/list", space.ListUserSpaces)
// authGroup.Get("/user/profile", user.GetProfile)
// spaceGroup.Get("/space/info", space.GetInfo)
}
+19 -1
View File
@@ -1,10 +1,28 @@
package types
type CreateSpaceDTO struct {
Name string `json:"name" validate:"required"`
Name string `json:"name" validate:"required"`
UserName string `json:"user_name" validate:"required"`
SortNumber int32 `json:"sort_number" validate:"required"`
}
type CreateSpaceVO struct {
SpaceId int64 `json:"space_id"`
InviteCode string `json:"invite_code"`
SortNumber int32 `json:"sort_number"`
}
type UserSpace struct {
Id int64 `json:"id"`
OwnerId int64 `json:"owner_id"`
Name string `json:"name"`
Role int16 `json:"role"`
MemberCount int64 `json:"member_count"`
IsDefault int16 `json:"is_default"`
UserName string `json:"user_name"`
SortNumber int32 `json:"sort_number"`
}
type ListSpacesVO struct {
Spaces []UserSpace `json:"spaces"`
}
+24 -2
View File
@@ -6,8 +6,8 @@ SELECT * FROM space WHERE id = $1;
-- 创建空间
-- name: InsertSpace :exec
INSERT INTO space (
id,name,invite_code,create_time,update_time
) VALUES ($1,$2,$3,NOW(),NOW());
id,name,invite_code,owner_id,create_time,update_time
) VALUES ($1,$2,$3,$4,NOW(),NOW());
-- 删除空间
-- name: DeleteSpace :exec
@@ -16,3 +16,25 @@ DELETE FROM space WHERE id = $1;
-- 根据邀请码获取
-- name: GetSpaceByInviteCode :one
SELECT * FROM space WHERE invite_code = $1;
-- name: ListSpacesByUserId :many
SELECT
s.id,
s.owner_id,
s.name,
sm.role,
COALESCE(mc.member_count, 0) AS member_count,
sm.is_default,
sm.user_name,
sm.sort_number
FROM space s
JOIN space_member sm
ON s.id = sm.space_id
LEFT JOIN (
SELECT space_id, COUNT(*) AS member_count
FROM space_member
GROUP BY space_id
) mc
ON s.id = mc.space_id
WHERE sm.user_id = $1
ORDER BY sm.is_default DESC, sm.sort_number ASC;
@@ -6,8 +6,8 @@ WHERE user_id = $1
AND space_id = $2;
-- name: InsertSpaceMember :exec
INSERT INTO space_member(id,space_id,user_id,role,is_default,join_time,update_time)
VALUES ($1,$2,$3,$4,$5,NOW(),NOW());
INSERT INTO space_member(id,space_id,user_id,role,is_default,user_name,sort_number,join_time,update_time)
VALUES ($1,$2,$3,$4,$5,$6,$7,NOW(),NOW());
-- name: CountUserSpaces :one
SELECT COUNT(1)
+3
View File
@@ -35,6 +35,7 @@ type Space struct {
ID int64
Name string
InviteCode string
OwnerID int64
CreateTime pgtype.Timestamptz
UpdateTime pgtype.Timestamptz
}
@@ -45,6 +46,8 @@ type SpaceMember struct {
UserID int64
Role int16
IsDefault int16
UserName string
SortNumber int32
JoinTime pgtype.Timestamptz
UpdateTime pgtype.Timestamptz
}
+76 -5
View File
@@ -20,7 +20,7 @@ func (q *Queries) DeleteSpace(ctx context.Context, id int64) error {
}
const getSpaceById = `-- name: GetSpaceById :one
SELECT id, name, invite_code, create_time, update_time FROM space WHERE id = $1
SELECT id, name, invite_code, owner_id, create_time, update_time FROM space WHERE id = $1
`
// 根据id获取分享空间信息
@@ -31,6 +31,7 @@ func (q *Queries) GetSpaceById(ctx context.Context, id int64) (Space, error) {
&i.ID,
&i.Name,
&i.InviteCode,
&i.OwnerID,
&i.CreateTime,
&i.UpdateTime,
)
@@ -38,7 +39,7 @@ func (q *Queries) GetSpaceById(ctx context.Context, id int64) (Space, error) {
}
const getSpaceByInviteCode = `-- name: GetSpaceByInviteCode :one
SELECT id, name, invite_code, create_time, update_time FROM space WHERE invite_code = $1
SELECT id, name, invite_code, owner_id, create_time, update_time FROM space WHERE invite_code = $1
`
// 根据邀请码获取
@@ -49,6 +50,7 @@ func (q *Queries) GetSpaceByInviteCode(ctx context.Context, inviteCode string) (
&i.ID,
&i.Name,
&i.InviteCode,
&i.OwnerID,
&i.CreateTime,
&i.UpdateTime,
)
@@ -57,18 +59,87 @@ func (q *Queries) GetSpaceByInviteCode(ctx context.Context, inviteCode string) (
const insertSpace = `-- name: InsertSpace :exec
INSERT INTO space (
id,name,invite_code,create_time,update_time
) VALUES ($1,$2,$3,NOW(),NOW())
id,name,invite_code,owner_id,create_time,update_time
) VALUES ($1,$2,$3,$4,NOW(),NOW())
`
type InsertSpaceParams struct {
ID int64
Name string
InviteCode string
OwnerID int64
}
// 创建空间
func (q *Queries) InsertSpace(ctx context.Context, arg InsertSpaceParams) error {
_, err := q.db.Exec(ctx, insertSpace, arg.ID, arg.Name, arg.InviteCode)
_, err := q.db.Exec(ctx, insertSpace,
arg.ID,
arg.Name,
arg.InviteCode,
arg.OwnerID,
)
return err
}
const listSpacesByUserId = `-- name: ListSpacesByUserId :many
SELECT
s.id,
s.owner_id,
s.name,
sm.role,
COALESCE(mc.member_count, 0) AS member_count,
sm.is_default,
sm.user_name,
sm.sort_number
FROM space s
JOIN space_member sm
ON s.id = sm.space_id
LEFT JOIN (
SELECT space_id, COUNT(*) AS member_count
FROM space_member
GROUP BY space_id
) mc
ON s.id = mc.space_id
WHERE sm.user_id = $1
ORDER BY sm.is_default DESC, sm.sort_number ASC
`
type ListSpacesByUserIdRow struct {
ID int64
OwnerID int64
Name string
Role int16
MemberCount int64
IsDefault int16
UserName string
SortNumber int32
}
func (q *Queries) ListSpacesByUserId(ctx context.Context, userID int64) ([]ListSpacesByUserIdRow, error) {
rows, err := q.db.Query(ctx, listSpacesByUserId, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListSpacesByUserIdRow
for rows.Next() {
var i ListSpacesByUserIdRow
if err := rows.Scan(
&i.ID,
&i.OwnerID,
&i.Name,
&i.Role,
&i.MemberCount,
&i.IsDefault,
&i.UserName,
&i.SortNumber,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
@@ -43,16 +43,18 @@ func (q *Queries) GetUserSpaceRole(ctx context.Context, arg GetUserSpaceRolePara
}
const insertSpaceMember = `-- name: InsertSpaceMember :exec
INSERT INTO space_member(id,space_id,user_id,role,is_default,join_time,update_time)
VALUES ($1,$2,$3,$4,$5,NOW(),NOW())
INSERT INTO space_member(id,space_id,user_id,role,is_default,user_name,sort_number,join_time,update_time)
VALUES ($1,$2,$3,$4,$5,$6,$7,NOW(),NOW())
`
type InsertSpaceMemberParams struct {
ID int64
SpaceID int64
UserID int64
Role int16
IsDefault int16
ID int64
SpaceID int64
UserID int64
Role int16
IsDefault int16
UserName string
SortNumber int32
}
func (q *Queries) InsertSpaceMember(ctx context.Context, arg InsertSpaceMemberParams) error {
@@ -62,6 +64,8 @@ func (q *Queries) InsertSpaceMember(ctx context.Context, arg InsertSpaceMemberPa
arg.UserID,
arg.Role,
arg.IsDefault,
arg.UserName,
arg.SortNumber,
)
return err
}
+3
View File
@@ -27,6 +27,7 @@ create table space
primary key,
name varchar(255) not null,
invite_code varchar(30) not null,
owner_id bigint not null,
create_time timestamp with time zone default now(),
update_time timestamp with time zone default now()
);
@@ -39,6 +40,8 @@ create table space_member
user_id bigint not null,
role smallint default 2 not null,
is_default smallint default 0 not null,
user_name varchar(255) not null,
sort_number integer default 0 not null,
join_time timestamp with time zone default now(),
update_time timestamp with time zone default now()
);
+4 -2
View File
@@ -46,12 +46,14 @@ func CreateToken(ctx context.Context, userID int64) (string, error) {
// VerifyToken 校验 token 并返回 claims
func VerifyToken(ctx context.Context, tokenString string) (*CustomClaims, bool) {
if tokenString == "" || manager == nil {
if tokenString == "" {
return nil, false
}
m := getManager()
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(manager.secret), nil
return []byte(m.secret), nil
})
if err != nil || !token.Valid {
+5 -5
View File
@@ -55,12 +55,12 @@ export default function RootLayout() {
}, [pathname])
useEffect(() => {
if (!fontsLoaded)
if (!fontsLoaded) {
return
appStore.init().finally(() => {
SplashScreen.hideAsync()
})
}
SplashScreen.hideAsync()
// appStore.init().finally(() => {
// })
}, [fontsLoaded])
return (
+5 -3
View File
@@ -117,6 +117,8 @@ export default function Auth() {
// avatar: onGetUserInfo.figureurlQq_2 || onGetUserInfo.figureurl_2,
// })
// console.log(loginRes)
// if (loginRes.isSuccess) {
// userStore.setUserInfo({
// token: loginRes.data.token,
@@ -182,15 +184,15 @@ export default function Auth() {
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo3NjY3ODU5ODIxNjUwNjEsImlhdCI6MTc2OTM0ODI0Nn0.17ZNaHD3HSLM8dVn_JQK-gvsG9MKj47IRYV9D4xZkzs
userStore.setUserInfo({
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo3NzgxMTUwMzIxMDA5MzMsImlhdCI6MTc3MjExMDQ5N30.Ab7_YNwftJigktnPt8f-FwwcLeS45CkrH0jT2jLjRtA',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo3NzgxMTUwMzIxMDA5MzMsImlhdCI6MTc3MjE5MDQ0Mn0.GF611RBvU47QuW2s4kOcdvh88ieIbHu7M_SmWeBOqLY',
id: 778115032100933,
nickname: 'Zhang',
avatar: 'http://thirdqq.qlogo.cn/ek_qqapp/AQHVialeUibE42oV8RvTTVZ4tyRlPYeJrUibWTwtCPfV68E4rSzn9cw00GkXQ3QDTiawwhjoqQb7/100',
})
appStore.init()
// appStore.init()
router.push('/')
router.replace('/')
}
return (
+44 -85
View File
@@ -1,5 +1,5 @@
import type { Space } from '@/types/space/space'
import { useCallback, useState } from 'react'
import type { UserSpace } from '@/types/space'
import { useCallback, useEffect, useState } from 'react'
import { Pressable, Text, View } from 'react-native'
import Animated, { useAnimatedRef } from 'react-native-reanimated'
import Sortable from 'react-native-sortables'
@@ -9,9 +9,12 @@ import { AModal } from '@/components/common/ao/index'
import EmptyState from '@/components/common/EmptyStatus'
import CustomHeader from '@/components/custom/Header'
import { Badge, BadgeText } from '@/components/ui/badge'
import { createSpaceApi } from '@/request/api/space/space'
import { createSpaceApi, listUserSpacesApi } from '@/request/api/space/index'
import { useUserStore } from '@/store/user'
export default function AuthSpace() {
const userStore = useUserStore()
const scrollableRef = useAnimatedRef<Animated.ScrollView>()
const [selectedId, setSelectedId] = useState<number | null>(null)
@@ -22,74 +25,18 @@ export default function AuthSpace() {
name: '',
})
const spaces: Space[] = [
{
id: 1,
name: 'A 的空间',
role: 1,
member_count: 8,
is_default: 1,
sort_number: 1,
user_name: '张三',
},
{
id: 2,
name: 'B 的空间',
role: 2,
member_count: 5,
is_default: 0,
sort_number: 2,
user_name: '李四',
},
{
id: 3,
name: 'C 的空间',
role: 3,
member_count: 12,
is_default: 0,
sort_number: 3,
user_name: '王五',
},
{
id: 4,
name: 'D 的空间',
role: 2,
member_count: 6,
is_default: 0,
sort_number: 4,
user_name: '赵六',
},
{
id: 5,
name: 'E 的空间',
role: 1,
member_count: 3,
is_default: 0,
sort_number: 5,
user_name: '钱七',
},
{
id: 6,
name: 'F 的空间',
role: 2,
member_count: 9,
is_default: 0,
sort_number: 6,
user_name: '孙八',
},
{
id: 7,
name: 'G 的空间',
role: 3,
member_count: 4,
is_default: 0,
sort_number: 7,
user_name: '周九',
},
]
const [spaces, setSpaces] = useState<UserSpace[]>([])
const renderItem = useCallback(
({ item }: { item: Space }) => (
function listUserSpaces() {
listUserSpacesApi().then((res) => {
if (res.isSuccess) {
setSpaces(res.data.spaces)
}
})
}
const renderItem
= ({ item }: { item: UserSpace }) => (
<Pressable
key={item.id}
onPress={() => setSelectedId(item.id)}
@@ -112,22 +59,31 @@ export default function AuthSpace() {
{item.name}
</Text>
<Badge size="sm" variant="solid" action="muted">
<BadgeText>创建者</BadgeText>
</Badge>
{
item.owner_id === userStore.userInfo.id && (
<Badge size="sm" variant="solid" action="muted">
<BadgeText>创建者</BadgeText>
</Badge>
)
}
{
item.is_default === 1 && (
<Badge size="sm" variant="solid" action="info">
<BadgeText>默认</BadgeText>
</Badge>
)
}
<Badge size="sm" variant="solid" action="info">
<BadgeText>默认</BadgeText>
</Badge>
</View>
<View className="flex-row items-center gap-3 mt-2">
<View className="flex-row gap-1">
<LucideIcon icon="UserRound" size={12} />
<Text
className={`text-xs `}
className="text-xs"
>
用户A
{item.user_name}
</Text>
</View>
<View className="flex-row gap-1">
@@ -135,7 +91,7 @@ export default function AuthSpace() {
<Text
className={`text-xs `}
>
0
{item.member_count}
</Text>
</View>
</View>
@@ -148,9 +104,11 @@ export default function AuthSpace() {
className="p-1"
/>
</Pressable>
),
[],
)
)
useEffect(() => {
listUserSpaces()
}, [])
return (
<View className="flex-1 bg-white">
@@ -186,6 +144,7 @@ export default function AuthSpace() {
<Animated.ScrollView
className="flex-1"
showsVerticalScrollIndicator={false}
ref={scrollableRef}
>
{spaces.length === 0
@@ -256,18 +215,18 @@ export default function AuthSpace() {
toast.warning('请输入空间名称')
return
}
await createSpaceApi({
name: createForm.name,
user_name: userStore.userInfo.nickname,
sort_number: 0,
}).then((res) => {
console.log(res)
if (res.isSuccess) {
toast.success('创建成功')
setCreateOpen(false)
setCreateForm({
name: '',
})
}
})
}}
@@ -1,4 +1,4 @@
import type { SpaceMember } from '@/types/space/space'
import type { SpaceMember } from '@/types/space'
import * as Clipboard from 'expo-clipboard'
import { useState } from 'react'
import { FlatList, TouchableHighlight, TouchableOpacity, View } from 'react-native'
@@ -28,7 +28,7 @@ import { HStack } from '@/components/ui/hstack'
import { ChevronDownIcon, ChevronUpIcon } from '@/components/ui/icon'
import { Text } from '@/components/ui/text'
import { VStack } from '@/components/ui/vstack'
import { dissolveSpaceApi, exitSpaceApi, removeSpaceMemberApi } from '@/request/api/space/space'
import { dissolveSpaceApi, exitSpaceApi, removeSpaceMemberApi } from '@/request/api/space/index'
import { useUserStore } from '@/store/user'
import { formatRelativeTime } from '@/utils/time'
import { toast } from '@/utils/toast'
@@ -1,8 +1,8 @@
import type { SpaceMember } from '@/types/space/space'
import type { SpaceMember } from '@/types/space'
import { useEffect, useState } from 'react'
import { View } from 'react-native'
import CustomHeader from '@/components/custom/Header'
import { createSpaceApi, joinSpaceApi, listSpaceMembersApi } from '@/request/api/space/space'
import { createSpaceApi, joinSpaceApi, listSpaceMembersApi } from '@/request/api/space/index'
import { useSpaceStore } from '@/store/space'
import { useUserStore } from '@/store/user'
import JoinSpace from './components/JoinSpace'
@@ -9,25 +9,30 @@ import type {
JoinSpaceResult,
ListSpaceMembersParams,
ListSpaceMembersResult,
ListUserSpacesResult,
RemoveSpaceMemberParams,
RemoveSpaceMemberResult,
UpdateSpaceMemberRoleParams,
UpdateSpaceMemberRoleResult,
} from '@/types/space/space'
} from '@/types/space'
import alovaInstance from '../../index'
const API_PREFIX = '/space'
// Join Space API
export function joinSpaceApi(params: JoinSpaceParams) {
return alovaInstance.Post<ResponseData<JoinSpaceResult>>(`${API_PREFIX}/join`, params)
}
// Create Space API
export function createSpaceApi(params: CreateSpaceParams) {
return alovaInstance.Post<ResponseData<CreateSpaceResult>>(`${API_PREFIX}/create`, params)
}
export function listUserSpacesApi() {
return alovaInstance.Post<ResponseData<ListUserSpacesResult>>(`${API_PREFIX}/list`)
}
// Join Space API
export function joinSpaceApi(params: JoinSpaceParams) {
return alovaInstance.Post<ResponseData<JoinSpaceResult>>(`${API_PREFIX}/join`, params)
}
// Dissolve Space API
export function dissolveSpaceApi(params: DissolveSpaceParams) {
return alovaInstance.Post<ResponseData<DissolveSpaceResult>>(`${API_PREFIX}/dissolve`, params)
+4 -37
View File
@@ -8,7 +8,7 @@ import { toast } from '@/utils/toast'
enum HttpCode {
Success = 1000,
Unauthorized = 401,
Unauthorized = 1001,
Fail = 500,
}
@@ -28,8 +28,8 @@ function isWhiteListed(url: string) {
}
const alovaInstance = createAlova({
// baseURL: 'http://192.168.5.6:8086/app',
baseURL: 'http://192.168.1.137:8086/app',
baseURL: 'http://192.168.5.6:8086/app',
// baseURL: 'http://192.168.1.137:8086/app',
requestAdapter: axiosRequestAdapter(),
timeout: 5000,
cacheFor: null,
@@ -46,46 +46,13 @@ const alovaInstance = createAlova({
if (resData.code === HttpCode.Unauthorized) {
useUserStore.getState().clear()
useNavStore.getState().navigateToAuth()
return Promise.reject(new Error('登录已失效'))
return result
}
return result
},
onError: (error: AxiosError) => {
const status = error.status
console.log(error)
switch (status) {
case 400:
toast.show({ title: '请求错误,请检查输入参数' })
break
case 401:
toast.show({ title: '未授权,请重新登录' })
break
case 403:
toast.show({ title: '没有权限访问该资源' })
break
case 404:
toast.show({ title: '请求丢失啦,请稍后再试!' })
break
case 500:
toast.show({ title: '服务器出错啦,请稍后重试' })
break
case 502:
toast.show({ title: '网关错误,请稍后重试' })
break
case 503:
toast.show({ title: '服务暂不可用,请稍后再试' })
break
case 504:
toast.show({ title: '网关超时,请稍后再试' })
break
default:
toast.show({ title: '服务器出错啦,请稍后重试' })
break
}
return Promise.reject(error)
},
},
@@ -36,7 +36,7 @@ export const useNavStore = create<NavState>()(
navigateToAuth: () => {
const pathname = useNavStore.getState().pathname
if (!pathname.startsWith('/auth')) {
if (pathname !== '/auth') {
router.replace('/auth')
}
},
@@ -44,7 +44,7 @@ export const useNavStore = create<NavState>()(
}),
{
name: 'nav-storage',
// storage: createJSONStorage(() => AsyncStorage),
storage: createJSONStorage(() => AsyncStorage),
},
),
)
+11 -4
View File
@@ -4,8 +4,8 @@ import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'
interface UserState {
userInfo: UserInfo | null
setUserInfo: (userInfo: UserInfo | null) => void
userInfo: UserInfo
setUserInfo: (userInfo: UserInfo) => void
clear: () => void
isLoggedIn: () => boolean
@@ -13,17 +13,24 @@ interface UserState {
setUserSpace: (userSpace: UserSpace | null) => void
}
const defaultUserInfo: UserInfo = {
id: 0,
token: '',
nickname: '',
avatar: '',
}
const useUserStore = create<UserState>()(
persist(
(set, get) => ({
userInfo: null,
userInfo: defaultUserInfo,
userSpace: null,
setUserInfo: userInfo => set({ userInfo }),
setUserSpace: userSpace => set({ userSpace }),
clear: () => {
set({ userInfo: null, userSpace: null })
set({ userInfo: defaultUserInfo, userSpace: null })
},
isLoggedIn: () => Boolean(get().userInfo?.token),
+2 -2
View File
@@ -12,8 +12,8 @@ declare global {
interface UserInfo {
id: number
token: string
nickname?: string
avatar?: string
nickname: string
avatar: string
}
interface UserSpace {
@@ -1,5 +1,6 @@
export interface Space {
export interface UserSpace {
id: number
owner_id: number
name: string
role: number
member_count: number
@@ -12,12 +13,19 @@ export interface Space {
// 创建空间
export interface CreateSpaceParams {
name: string
user_name: string
sort_number: number
}
export interface CreateSpaceResult {
space_id: number
invite_code: string
}
// 获取用户空间
export interface ListUserSpacesResult {
spaces: UserSpace[]
}
// 解散空间
export interface DissolveSpaceParams {
space_id: number