u
This commit is contained in:
1 parent
b6415c0d65
commit
89aaef1d6b
29 files changed
+1118
-277
No files matched your search
@@ -0,0 +1,25 @@
|
||||
import { memo } from "react";
|
||||
import {
|
||||
KeyboardAwareScrollView,
|
||||
KeyboardAwareScrollViewProps,
|
||||
} from "react-native-keyboard-controller";
|
||||
import {
|
||||
SCROLLABLE_TYPE,
|
||||
createBottomSheetScrollableComponent,
|
||||
type BottomSheetScrollViewMethods,
|
||||
} from "@gorhom/bottom-sheet";
|
||||
import type { BottomSheetScrollViewProps } from "@gorhom/bottom-sheet/src/components/bottomSheetScrollable/types";
|
||||
import Reanimated from "react-native-reanimated";
|
||||
|
||||
const AnimatedScrollView = Reanimated.createAnimatedComponent(KeyboardAwareScrollView);
|
||||
const BottomSheetScrollViewComponent = createBottomSheetScrollableComponent<
|
||||
BottomSheetScrollViewMethods,
|
||||
BottomSheetScrollViewProps
|
||||
>(SCROLLABLE_TYPE.SCROLLVIEW, AnimatedScrollView);
|
||||
const BottomSheetKeyboardAwareScrollView = memo(BottomSheetScrollViewComponent);
|
||||
|
||||
BottomSheetKeyboardAwareScrollView.displayName = "BottomSheetKeyboardAwareScrollView";
|
||||
|
||||
export default BottomSheetKeyboardAwareScrollView as (
|
||||
props: BottomSheetScrollViewProps & KeyboardAwareScrollViewProps,
|
||||
) => ReturnType<typeof BottomSheetKeyboardAwareScrollView>;
|
||||
@@ -1,43 +1,54 @@
|
||||
import { Button, Toast, useToast, useThemeColor } from "heroui-native";
|
||||
import { View } from "react-native";
|
||||
import { BottomSheet, Button, TextField, Input, useBottomSheetAwareHandlers } from "heroui-native";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { Keyboard } from "react-native";
|
||||
|
||||
export default function ToastExample() {
|
||||
const { toast } = useToast();
|
||||
const themeColorForeground = useThemeColor("foreground");
|
||||
const BottomSheetTextInput = ({ isOpen }: { isOpen: boolean }) => {
|
||||
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
|
||||
const inputRef = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
inputRef.current?.focus();
|
||||
} else {
|
||||
inputRef.current?.blur();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<View className="gap-4 p-4">
|
||||
<Button
|
||||
onPress={() =>
|
||||
toast.show({
|
||||
variant: "success",
|
||||
label: "You have upgraded your plan",
|
||||
description: "You can continue using HeroUI Chat",
|
||||
actionLabel: "Close",
|
||||
onActionPress: ({ hide }) => hide(),
|
||||
})
|
||||
}
|
||||
>
|
||||
Show Success Toast
|
||||
</Button>
|
||||
<TextField>
|
||||
<Input ref={inputRef} placeholder="Type here..." onFocus={onFocus} onBlur={onBlur} />
|
||||
</TextField>
|
||||
);
|
||||
};
|
||||
|
||||
<Button
|
||||
onPress={() =>
|
||||
toast.show({
|
||||
duration: 0,
|
||||
component: (props) => (
|
||||
<Toast variant="accent" {...props}>
|
||||
<Toast.Title>Custom Toast</Toast.Title>
|
||||
<Toast.Description>This uses a custom component</Toast.Description>
|
||||
<Toast.Action onPress={() => props.hide()}>Undo</Toast.Action>
|
||||
<Toast.Close className="absolute top-0 right-0" />
|
||||
</Toast>
|
||||
),
|
||||
})
|
||||
export default function BottomSheetExample() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<BottomSheet
|
||||
isOpen={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
setIsOpen(open);
|
||||
|
||||
if (!open) {
|
||||
Keyboard.dismiss(); // ✅ 关闭时收键盘
|
||||
}
|
||||
>
|
||||
Show Custom Toast
|
||||
</Button>
|
||||
</View>
|
||||
}}
|
||||
animation="disable-all"
|
||||
>
|
||||
<BottomSheet.Trigger asChild>
|
||||
<Button variant="secondary" className="mt-30">
|
||||
Open Bottom Sheet
|
||||
</Button>
|
||||
</BottomSheet.Trigger>
|
||||
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content enableBlurKeyboardOnGesture keyboardBlurBehavior="restore">
|
||||
<BottomSheetTextInput isOpen={isOpen} />
|
||||
</BottomSheet.Content>
|
||||
</BottomSheet.Portal>
|
||||
</BottomSheet>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { BottomSheet, Button, TextField, Input, useBottomSheetAwareHandlers } from "heroui-native";
|
||||
import { useState } from "react";
|
||||
|
||||
const BottomSheetTextInput = () => {
|
||||
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
|
||||
|
||||
return (
|
||||
<TextField>
|
||||
<Input placeholder="Type here..." onFocus={onFocus} onBlur={onBlur} />
|
||||
</TextField>
|
||||
);
|
||||
};
|
||||
|
||||
export default function BottomSheetExample() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<BottomSheet
|
||||
isOpen={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
setIsOpen(open);
|
||||
}}
|
||||
>
|
||||
<BottomSheet.Trigger asChild>
|
||||
<Button variant="secondary" className="mt-30">
|
||||
Open Bottom Sheet
|
||||
</Button>
|
||||
</BottomSheet.Trigger>
|
||||
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content keyboardBlurBehavior="restore">
|
||||
<BottomSheetTextInput />
|
||||
</BottomSheet.Content>
|
||||
</BottomSheet.Portal>
|
||||
</BottomSheet>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import LayoutView from "@/components/layout/view";
|
||||
import EmptyState from "@/components/EmptyStatus";
|
||||
import { s3ListBucketsApi } from "@/request/api";
|
||||
|
||||
export default function Home() {
|
||||
// const [dailyData, setDailyData] = useState<any>(null);
|
||||
|
||||
@@ -15,6 +17,12 @@ export default function Home() {
|
||||
// .catch(() => {});
|
||||
// }, []);
|
||||
|
||||
useEffect(() => {
|
||||
s3ListBucketsApi().then((res) => {
|
||||
console.log(res);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<LayoutView>
|
||||
<LayoutView.ScrollView>
|
||||
|
||||
@@ -30,12 +30,14 @@ export default function My() {
|
||||
<LayoutView.ScrollView>
|
||||
<View className="flex-row items-center">
|
||||
<Avatar alt="">
|
||||
<Avatar.Image source={{ uri: "https://example.com/avatar.jpg" }} />
|
||||
<Avatar.Fallback className="text-sm">JD</Avatar.Fallback>
|
||||
<Avatar.Image source={{ uri: userStore.userInfo.avatar }} />
|
||||
<Avatar.Fallback className="text-sm">{userStore.userInfo.nickname}</Avatar.Fallback>
|
||||
</Avatar>
|
||||
|
||||
<View className="ml-3 mr-1">
|
||||
<Text className="text-xl font-semibold text-foreground">JD</Text>
|
||||
<Text className="text-xl font-semibold text-foreground">
|
||||
{userStore.userInfo.nickname}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<ChevronRightIcon size={18} color="#c7c7cc" />
|
||||
|
||||
@@ -26,6 +26,48 @@ import { UserRoundIcon, UsersRoundIcon } from "lucide-react-native";
|
||||
import { toast } from "sonner-native";
|
||||
import { FadeIn } from "react-native-reanimated";
|
||||
import { generateCode } from "@/utils/common";
|
||||
import { Keyboard } from "react-native";
|
||||
import { forwardRef } from "react";
|
||||
|
||||
const BottomSheetTextInput = forwardRef<any, React.ComponentProps<typeof Input>>((props, ref) => {
|
||||
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
|
||||
|
||||
return (
|
||||
<Input
|
||||
ref={ref}
|
||||
{...props}
|
||||
onFocus={(e) => {
|
||||
onFocus(e);
|
||||
props.onFocus?.(e);
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
onBlur(e);
|
||||
props.onBlur?.(e);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const BottomSheetTextInputOTP = forwardRef<any, React.ComponentProps<typeof InputOTP>>(
|
||||
(props, ref) => {
|
||||
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
|
||||
|
||||
return (
|
||||
<InputOTP
|
||||
ref={ref}
|
||||
{...props}
|
||||
onFocus={(e) => {
|
||||
onFocus(e);
|
||||
props.onFocus?.(e);
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
onBlur(e);
|
||||
props.onBlur?.(e);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default function Space() {
|
||||
const router = useRouter();
|
||||
@@ -54,28 +96,38 @@ export default function Space() {
|
||||
const [createLoading, setCreateLoading] = useState(false);
|
||||
const createInputRef = useRef<any>(null);
|
||||
|
||||
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
|
||||
useEffect(() => {
|
||||
listUserSpaces();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (showCreate) {
|
||||
setTimeout(() => {
|
||||
requestAnimationFrame(() => {
|
||||
createInputRef.current?.focus();
|
||||
}, 0);
|
||||
});
|
||||
} else {
|
||||
setCreateForm({
|
||||
name: "",
|
||||
});
|
||||
setCreateLoading(false);
|
||||
Keyboard.dismiss();
|
||||
}
|
||||
}, [showCreate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (showJoin) {
|
||||
setTimeout(() => {
|
||||
requestAnimationFrame(() => {
|
||||
joinInputRef.current?.focus();
|
||||
}, 0);
|
||||
});
|
||||
} else {
|
||||
setJoinForm({
|
||||
invite_code: "",
|
||||
});
|
||||
setJoinLoading(false);
|
||||
Keyboard.dismiss();
|
||||
}
|
||||
}, [showJoin]);
|
||||
|
||||
useEffect(() => {
|
||||
listUserSpaces();
|
||||
}, []);
|
||||
|
||||
function listUserSpaces(loading = true) {
|
||||
if (loading) {
|
||||
setLoading(true);
|
||||
@@ -396,7 +448,7 @@ export default function Space() {
|
||||
className="flex-1"
|
||||
onPress={() => {
|
||||
setShowCreate(true);
|
||||
createInputRef.current?.focus();
|
||||
// createInputRef.current?.focus();
|
||||
}}
|
||||
>
|
||||
<PlusIcon color="#fff" size={20} />
|
||||
@@ -463,32 +515,25 @@ export default function Space() {
|
||||
/>
|
||||
)}
|
||||
</LayoutView.ScrollView>
|
||||
|
||||
<BottomSheet
|
||||
isOpen={showCreate}
|
||||
onOpenChange={(val) => {
|
||||
if (!val) {
|
||||
setCreateForm({
|
||||
name: "",
|
||||
});
|
||||
setCreateLoading(false);
|
||||
}
|
||||
|
||||
setShowCreate(val);
|
||||
}}
|
||||
>
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content>
|
||||
<BottomSheet.Content
|
||||
animation="disabled"
|
||||
enableBlurKeyboardOnGesture
|
||||
keyboardBlurBehavior="restore"
|
||||
>
|
||||
<View>
|
||||
<TextField>
|
||||
<Label>空间名称</Label>
|
||||
<Input
|
||||
<BottomSheetTextInput
|
||||
ref={createInputRef}
|
||||
placeholder="请输入空间名称"
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
value={createForm.name}
|
||||
onChangeText={(val) =>
|
||||
setCreateForm({
|
||||
@@ -510,28 +555,23 @@ export default function Space() {
|
||||
<BottomSheet
|
||||
isOpen={showJoin}
|
||||
onOpenChange={(val) => {
|
||||
if (!val) {
|
||||
setJoinForm({
|
||||
invite_code: "",
|
||||
});
|
||||
setJoinLoading(false);
|
||||
}
|
||||
|
||||
setShowJoin(val);
|
||||
}}
|
||||
>
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content>
|
||||
<BottomSheet.Content
|
||||
animation={"disabled"}
|
||||
enableBlurKeyboardOnGesture
|
||||
keyboardBlurBehavior="restore"
|
||||
>
|
||||
<View>
|
||||
<TextField>
|
||||
<Label>邀请码</Label>
|
||||
<InputOTP
|
||||
<BottomSheetTextInputOTP
|
||||
ref={joinInputRef}
|
||||
maxLength={6}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
value={joinForm.invite_code}
|
||||
onChange={(val) => {
|
||||
setJoinForm({
|
||||
@@ -550,7 +590,7 @@ export default function Space() {
|
||||
<InputOTP.Slot index={4} />
|
||||
<InputOTP.Slot index={5} />
|
||||
</InputOTP.Group>
|
||||
</InputOTP>
|
||||
</BottomSheetTextInputOTP>
|
||||
</TextField>
|
||||
|
||||
<Button className="mt-3" onPress={handleJoin}>
|
||||
|
||||
@@ -11,9 +11,16 @@ import { Toaster } from "sonner-native";
|
||||
import { KeyboardProvider } from "react-native-keyboard-controller";
|
||||
import { useUserStore } from "@/store";
|
||||
import { useRouter } from "expo-router";
|
||||
import { HeroUINativeConfig } from "heroui-native";
|
||||
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
|
||||
const config: HeroUINativeConfig = {
|
||||
devInfo: {
|
||||
stylingPrinciples: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout() {
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
@@ -46,15 +53,9 @@ export default function RootLayout() {
|
||||
|
||||
return (
|
||||
<GestureHandlerRootView className="flex-1">
|
||||
<KeyboardProvider>
|
||||
<ThemeProvider value={isDark ? DarkTheme : DefaultTheme}>
|
||||
<HeroUINativeProvider
|
||||
config={{
|
||||
devInfo: {
|
||||
stylingPrinciples: false,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ThemeProvider value={isDark ? DarkTheme : DefaultTheme}>
|
||||
<KeyboardProvider>
|
||||
<HeroUINativeProvider config={config}>
|
||||
<Stack
|
||||
screenOptions={{
|
||||
animation: "slide_from_right",
|
||||
@@ -66,8 +67,8 @@ export default function RootLayout() {
|
||||
/>
|
||||
{!isDev && <StatusBar style={isDark ? "light" : "dark"} />}
|
||||
</HeroUINativeProvider>
|
||||
</ThemeProvider>
|
||||
</KeyboardProvider>
|
||||
</KeyboardProvider>
|
||||
</ThemeProvider>
|
||||
<Toaster duration={1000} />
|
||||
</GestureHandlerRootView>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import { useEffect } from "react";
|
||||
import { Stack } from "expo-router";
|
||||
import { Image, Text, View } from "react-native";
|
||||
import { Button, LinkButton, ControlField, Checkbox, Spinner } from "heroui-native";
|
||||
@@ -7,19 +7,55 @@ import { useState } from "react";
|
||||
import { FadeIn } from "react-native-reanimated";
|
||||
import { useUserStore } from "@/store";
|
||||
import { useRouter } from "expo-router";
|
||||
import ExpoQQ from "expo-qq";
|
||||
import ExpoWeChat from "expo-wechat";
|
||||
import { useEvent } from "expo";
|
||||
import { toast } from "sonner-native";
|
||||
import { loginQqApi, loginWxApi } from "@/request/api";
|
||||
|
||||
export default function Login() {
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 登录
|
||||
const onLoginFinished = useEvent(ExpoQQ, "onLoginFinished");
|
||||
const onGetUserInfo = useEvent(ExpoQQ, "onGetUserInfo");
|
||||
const authResult = useEvent(ExpoWeChat, "onAuthResult");
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isAgreed, setIsAgreed] = useState(true);
|
||||
const [form, setForm] = useState({
|
||||
type: 0,
|
||||
openid: "",
|
||||
code: "",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
ExpoQQ.init("102826474", "");
|
||||
ExpoWeChat.registerApp("wxdab3e21a1f7e392f", "");
|
||||
}, []);
|
||||
|
||||
// 微信登录
|
||||
async function handleLoginWechat() {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
|
||||
// 检查微信是否安装
|
||||
const isInstalled = await ExpoWeChat.isWXAppInstalled();
|
||||
if (!isInstalled) {
|
||||
toast.warning(onLoginFinished?.errorMessage || "请先安装微信");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setForm((val) => ({
|
||||
...val,
|
||||
type: 0,
|
||||
}));
|
||||
|
||||
ExpoWeChat.sendAuthRequest("snsapi_userinfo", "state123");
|
||||
}
|
||||
|
||||
// QQ 登录
|
||||
@@ -30,23 +66,152 @@ export default function Login() {
|
||||
|
||||
setLoading(true);
|
||||
|
||||
setTimeout(() => {
|
||||
requestAnimationFrame(() => {
|
||||
userStore.setUserInfo({
|
||||
id: 779895419121733,
|
||||
token: "123",
|
||||
nickname: "Zhang",
|
||||
avatar: "",
|
||||
setForm((val) => ({
|
||||
...val,
|
||||
type: 1,
|
||||
}));
|
||||
await ExpoQQ.login(["get_user_info"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {"code": 1000, "data": {"avatar": "http://thirdqq.qlogo.cn/ek_qqapp/AQHVialeUibE42oV8RvTTVZ4tyRlPYeJrUibWTwtCPfV68E4rSzn9cw00GkXQ3QDTiawwhjoqQb7/100", "nickname": "Zhang", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImlkIjo3OTY0NTY3MTI3ODU5ODl9LCJpYXQiOjE3NzY1ODU2MDR9.ZwmN5_0MGrP9dYpn3quK94HXMG3QYKmAq7wnP5X68dY", "userId": 796456712785989}, "isSuccess": true, "message": "success", "track_id": "djIRo23SZlA160zBTH2DX-kxeuLApKTNyZdxqqauSMk"}
|
||||
*/
|
||||
|
||||
// function handleTest() {
|
||||
// if (loading) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// setLoading(true);
|
||||
|
||||
// setTimeout(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
// userStore.setUserInfo({
|
||||
// id: 779895419121733,
|
||||
// token: "ZwmN5_0MGrP9dYpn3quK94HXMG3QYKmAq7wnP5X68dY",
|
||||
// nickname: "Zhang",
|
||||
// avatar: "http://thirdqq.qlogo.cn/ek_qqapp/AQHVialeUibE42oV8RvTTVZ4tyRlPYeJrUibWTwtCPfV68E4rSzn9cw00GkXQ3QDTiawwhjoqQb7/100",
|
||||
// });
|
||||
// userStore.setAuthExpired(false);
|
||||
// router.replace("/(tabs)/home");
|
||||
// });
|
||||
// setLoading(false);
|
||||
// }, 2000);
|
||||
// }
|
||||
|
||||
useEffect(() => {
|
||||
if (!onLoginFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!onLoginFinished.success) {
|
||||
toast.warning(onLoginFinished?.errorMessage || "授权失败,请检查手机是否安装 QQ 或确认授权");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchUserInfo = async () => {
|
||||
try {
|
||||
const tokenInfo = await ExpoQQ.getLoginTokenInfo();
|
||||
if (!tokenInfo.openId) {
|
||||
toast.warning(tokenInfo?.errorMessage || "授权失败,请检查手机是否安装 QQ 或确认授权");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setForm((val) => ({
|
||||
...val,
|
||||
openid: String(tokenInfo.openId),
|
||||
}));
|
||||
|
||||
await ExpoQQ.sendGetUserInfoReq();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchUserInfo();
|
||||
}, [onLoginFinished]);
|
||||
|
||||
// QQ登录
|
||||
useEffect(() => {
|
||||
const handleLogin = async () => {
|
||||
if (!onGetUserInfo) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const loginRes = await loginQqApi({
|
||||
openid: form.openid,
|
||||
nickname: onGetUserInfo.nickname || "",
|
||||
avatar: onGetUserInfo.figureurlQq_2 || onGetUserInfo.figureurl_2,
|
||||
});
|
||||
|
||||
userStore.setAuthExpired(false);
|
||||
console.log(loginRes);
|
||||
|
||||
router.replace("/(tabs)/home");
|
||||
});
|
||||
if (loginRes.isSuccess) {
|
||||
requestAnimationFrame(() => {
|
||||
userStore.setUserInfo({
|
||||
token: loginRes.data.token,
|
||||
id: loginRes.data.userId,
|
||||
nickname: loginRes.data.nickname,
|
||||
avatar: loginRes.data.avatar,
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
}, 2000);
|
||||
}
|
||||
userStore.setAuthExpired(false);
|
||||
router.replace("/(tabs)/home");
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("登录接口出错", err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
handleLogin();
|
||||
}, [onGetUserInfo]);
|
||||
|
||||
// 微信登录
|
||||
useEffect(() => {
|
||||
if (!authResult) return;
|
||||
|
||||
const handleLogin = async () => {
|
||||
if (authResult.errorCode === 0) {
|
||||
try {
|
||||
const loginRes = await loginWxApi({
|
||||
code: authResult.code,
|
||||
});
|
||||
|
||||
if (loginRes.isSuccess) {
|
||||
requestAnimationFrame(() => {
|
||||
userStore.setUserInfo({
|
||||
token: loginRes.data.token,
|
||||
id: loginRes.data.userId,
|
||||
nickname: loginRes.data.nickname,
|
||||
avatar: loginRes.data.avatar,
|
||||
});
|
||||
|
||||
userStore.setAuthExpired(false);
|
||||
router.replace("/(tabs)/home");
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("登录接口出错", err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
} else {
|
||||
console.log("授权失败:", authResult.errorMessage);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
handleLogin();
|
||||
}, [authResult]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -47,3 +47,21 @@ interface SaveDataParams {
|
||||
export function saveDataApi(params: SaveDataParams[]) {
|
||||
return alovaInstance.Post<ResponseData<null>>(`/data/saveData`, params);
|
||||
}
|
||||
|
||||
export function s3ListBucketsApi() {
|
||||
return alovaInstance.Post<ResponseData<string[]>>(`/s3/listBuckets`);
|
||||
}
|
||||
|
||||
export function s3UploadFileApi(files: { uri: string; name: string; type: string }[]) {
|
||||
const form = new FormData();
|
||||
|
||||
files.forEach((file) => {
|
||||
form.append("files", file as any);
|
||||
});
|
||||
|
||||
return alovaInstance.Post<ResponseData<string[]>>("/s3/upload", form, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user