This commit is contained in:
oneao committed 2026-03-02 22:09:47 +08:00
1 parent cf23acdabc
commit 2efeb7cee2
13 files changed
+271 -49

No files matched your search

@@ -0,0 +1,96 @@
import * as Clipboard from 'expo-clipboard'
import { useLocalSearchParams } from 'expo-router'
import { useEffect, useState } from 'react'
import {
Modal,
Pressable,
Text,
TouchableOpacity,
View,
} from 'react-native'
import QRCode from 'react-native-qrcode-svg'
import { toast } from 'sonner-native'
import { AButton, ADivider, LucideIcon } from '@/components/common/ao'
import CustomHeader from '@/components/custom/Header'
export default function Invite() {
const params = useLocalSearchParams<{ invite_code: string }>()
const { invite_code } = params
const [qrcode, setQrcode] = useState('space:')
const [previewVisible, setPreviewVisible] = useState(false)
async function copyInviteCode() {
await Clipboard.setStringAsync(invite_code)
toast.success('邀请码已复制')
}
useEffect(() => {
setQrcode(`space:${invite_code}`)
console.log(`space:${invite_code}`)
}, [invite_code])
return (
<View className="flex-1 bg-[#f5f6f8]">
<CustomHeader title="分享空间" />
<View className="px-5 pt-6">
{/* 邀请码卡片 */}
<View className="bg-white rounded-2xl p-6 items-center">
<Text className="text-gray-500 text-sm mb-3">
复制邀请码邀请家庭成员加入
</Text>
<Text className="text-4xl font-bold tracking-[8px] text-gray-900 mb-4">
{invite_code}
</Text>
<AButton
onPress={copyInviteCode}
className="rounded-full"
leftIcon={
<LucideIcon icon="Copy" size={16} color="#fff" clickable={false} />
}
>
复制邀请码
</AButton>
</View>
<View className="my-8">
<ADivider direction="horizontal" text="或扫描二维码" />
</View>
{/* 二维码卡片 */}
<TouchableOpacity
activeOpacity={0.9}
onPress={() => setPreviewVisible(true)}
className="bg-white rounded-2xl py-8 items-center"
>
<QRCode
size={160}
value={qrcode || ''}
/>
</TouchableOpacity>
</View>
{/* 全屏预览(无动画) */}
<Modal
visible={previewVisible}
transparent={false}
>
<Pressable
onPress={() => setPreviewVisible(false)}
className="flex-1 bg-white items-center justify-center"
>
<QRCode
size={280}
value={qrcode || ''}
/>
</Pressable>
</Modal>
</View>
)
}
@@ -0,0 +1,10 @@
import { View } from 'react-native'
import CustomHeader from '@/components/custom/Header'
export default function () {
return (
<View className="flex-1">
<CustomHeader title="成员管理" />
</View>
)
}
@@ -14,7 +14,7 @@ import {
ActionsheetDragIndicator,
ActionsheetDragIndicatorWrapper,
} from '@/components/ui/actionsheet'
import { dissolveSpaceApi, getSpaceSettingsApi, updateSpaceDefaultApi, updateSpaceMemberNameApi, updateSpaceNameApi } from '@/request/api/space'
import { dissolveSpaceApi, exitSpaceApi, getSpaceSettingsApi, updateSpaceDefaultApi, updateSpaceMemberNameApi, updateSpaceNameApi } from '@/request/api/space'
import { useUserStore } from '@/store/user'
interface ItemProps {
@@ -65,6 +65,8 @@ export default function Settings() {
const { spaceId } = params
const [space, setSpace] = useState<UserSpace | null>(null)
// 是否自己的空间
const [isOwner, setIsOwner] = useState(false)
// 空间名称
const [showName, setShowName] = useState(false)
@@ -114,6 +116,15 @@ export default function Settings() {
}
}, [spaceId])
useEffect(() => {
if (space) {
setIsOwner(space.owner_id === userStore.userInfo.id)
}
else {
setIsOwner(false)
}
}, [space])
return (
<View className="flex-1 bg-[#f5f6f8]">
<CustomHeader title="空间设置" />
@@ -124,13 +135,14 @@ export default function Settings() {
)
: (
<View className="flex-1 px-4 pt-4">
<Text className="text-sm font-semibold text-gray-400 mb-2 tracking-wider">
常用设置
</Text>
<View className="bg-white rounded-xl overflow-hidden mb-6">
{
space?.owner_id === userStore.userInfo.id && (
isOwner && (
<Item
icon="Earth"
title="空间名称"
@@ -205,19 +217,42 @@ export default function Settings() {
/>
</View>
<Text className="text-sm font-semibold text-gray-400 mb-2 tracking-wider">
分享
</Text>
<View className="bg-white rounded-xl overflow-hidden mb-6">
<Item
icon="Share2"
title="邀请"
onPress={() => {
router.navigate({
pathname: '/space/manage/sub-page/invite',
params: {
invite_code: space.invite_code,
},
})
}}
/>
</View>
<Text className="text-sm font-semibold text-gray-400 mb-2 tracking-wider">
其它操作
</Text>
<View className="bg-white rounded-xl overflow-hidden">
<Item
icon="Users"
title="成员管理"
/>
{
isOwner && (
<Item
icon="Users"
title="成员管理"
/>
)
}
<Item
icon="LogOut"
title={userStore.userInfo.id === space.owner_id ? '解散空间' : '退出空间'}
title={isOwner ? '解散空间' : '退出空间'}
isLast
onPress={() => {
setShowDissolve(true)
@@ -397,7 +432,7 @@ export default function Settings() {
{/* 解散 */}
<AModal
title="提示"
body="确认解散该空间么?"
body={isOwner ? '确认解散该空间么?' : '确定解散空间么?'}
isOpen={showDissolve}
onClose={() => {
setShowDissolve(false)
@@ -411,18 +446,34 @@ export default function Settings() {
return
}
await dissolveSpaceApi({
space_id: space.space_id,
}).then((res) => {
if (res.isSuccess) {
setShowDissolve(false)
toast.success('解散成功')
if (isOwner) {
await dissolveSpaceApi({
space_id: space.space_id,
}).then((res) => {
if (res.isSuccess) {
setShowDissolve(false)
toast.success('已解散该空间')
setTimeout(() => {
router.back()
}, 300)
}
})
setTimeout(() => {
router.back()
}, 300)
}
})
}
else {
await exitSpaceApi({
space_id: space.space_id,
}).then((res) => {
if (res.isSuccess) {
setShowDissolve(false)
toast.success('已退出该空间')
setTimeout(() => {
router.back()
}, 300)
}
})
}
}}
/>
</View>
@@ -2,9 +2,7 @@ import type {
CreateSpaceParams,
CreateSpaceResult,
DissolveSpaceParams,
DissolveSpaceResult,
ExitSpaceParams,
ExitSpaceResult,
GetSpaceSettingsParams,
JoinSpaceParams,
JoinSpaceResult,
@@ -60,21 +58,21 @@ export function getSpaceSettingsApi(params: GetSpaceSettingsParams) {
return alovaInstance.Post<ResponseData<UserSpace>>(`${API_PREFIX}/settings`, params)
}
// 解散空间
export function dissolveSpaceApi(params: DissolveSpaceParams) {
return alovaInstance.Post<ResponseData<void>>(`${API_PREFIX}/dissolve`, params)
}
// 退出空间
export function exitSpaceApi(params: ExitSpaceParams) {
return alovaInstance.Post<ResponseData<void>>(`${API_PREFIX}/member/exit`, params)
}
// 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)
}
// Exit Space API
export function exitSpaceApi(params: ExitSpaceParams) {
return alovaInstance.Post<ResponseData<ExitSpaceResult>>(`${API_PREFIX}/exit`, params)
}
// Remove Space User API
export function removeSpaceMemberApi(params: RemoveSpaceMemberParams) {
return alovaInstance.Post<ResponseData<RemoveSpaceMemberResult>>(`${API_PREFIX}/remove`, params)
+2 -2
View File
@@ -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,
@@ -8,6 +8,8 @@ export interface UserSpace {
member_name: string
sort_number: number
invite_code: string
}
// 创建空间
@@ -31,9 +33,11 @@ export interface ListUserSpacesResult {
export interface DissolveSpaceParams {
space_id: number
}
export interface DissolveSpaceResult {
}
// 退出空间
export interface ExitSpaceParams {
space_id: number
}
// 更新空间名称
export interface UpdateSpaceNameParams {
space_id: number
@@ -74,13 +78,6 @@ export interface JoinSpaceResult {
space_name: string
}
// 退出空间
export interface ExitSpaceParams {
space_id: number
}
export interface ExitSpaceResult {
}
// 踢出用户
export interface RemoveSpaceMemberParams {
space_id: number