diff --git a/frontend/src/Route.tsx b/frontend/src/Route.tsx
index ac3246a..7ef429d 100644
--- a/frontend/src/Route.tsx
+++ b/frontend/src/Route.tsx
@@ -4,6 +4,7 @@ import Login from '@/views/Login'
import Register from '@/views/Register'
import Profile from '@/views/profile/Profile'
import Textures from '@/views/profile/Textures'
+import Security from '@/views/profile/Security'
import Layout from '@/views/Layout'
const router = createBrowserRouter([
@@ -19,7 +20,7 @@ function Root() {
} />
} />
} />
-
+ } />
diff --git a/frontend/src/apis/apis.ts b/frontend/src/apis/apis.ts
index 4c50a00..334391e 100644
--- a/frontend/src/apis/apis.ts
+++ b/frontend/src/apis/apis.ts
@@ -53,4 +53,21 @@ export async function yggProfile(uuid: string) {
throw new Error(data?.errorMessage)
}
return data as YggProfile
+}
+
+export async function upTextures(uuid: string, token: string, textureType: 'skin' | 'cape', model: 'slim' | '', file: File) {
+ const f = new FormData()
+ f.set("file", file)
+ f.set("model", model)
+
+ const r = await fetch(import.meta.env.VITE_APIADDR + "/api/yggdrasil/api/user/profile/" + uuid + "/" + textureType, {
+ method: "PUT",
+ body: f,
+ headers: {
+ "Authorization": "Bearer " + token
+ }
+ })
+ if (r.status != 204) {
+ throw new Error("上传失败 " + String(r.status))
+ }
}
\ No newline at end of file
diff --git a/frontend/src/apis/model.ts b/frontend/src/apis/model.ts
index 03b0342..b6e3e38 100644
--- a/frontend/src/apis/model.ts
+++ b/frontend/src/apis/model.ts
@@ -2,7 +2,7 @@ export interface tokenData {
accessToken: string
selectedProfile: {
name: string
- uuid: string
+ id: string
}
}
diff --git a/frontend/src/views/Layout.tsx b/frontend/src/views/Layout.tsx
index 31a0353..3b02627 100644
--- a/frontend/src/views/Layout.tsx
+++ b/frontend/src/views/Layout.tsx
@@ -110,7 +110,7 @@ const MyToolbar = memo(function MyToolbar() {
setAnchorEl(null);
setNowUser({ name: "", uuid: "" })
setToken("")
- navigate("/")
+ navigate("/login")
})
useTilg()
@@ -240,7 +240,7 @@ const MyDrawer = function MyDrawer() {
{
icon: ,
title: '安全设置',
- link: '/setting'
+ link: '/security'
}
] as ListItem[], [])
diff --git a/frontend/src/views/Login.tsx b/frontend/src/views/Login.tsx
index 03acf69..8fd90bb 100644
--- a/frontend/src/views/Login.tsx
+++ b/frontend/src/views/Login.tsx
@@ -49,7 +49,7 @@ export default function SignIn() {
if (!v) return
setToken(v.accessToken)
setUserInfo({
- uuid: v.selectedProfile.uuid,
+ uuid: v.selectedProfile.id,
name: v.selectedProfile.name,
})
navigate("/profile")
diff --git a/frontend/src/views/profile/Profile.tsx b/frontend/src/views/profile/Profile.tsx
index 73c3c3a..1be2283 100644
--- a/frontend/src/views/profile/Profile.tsx
+++ b/frontend/src/views/profile/Profile.tsx
@@ -5,10 +5,9 @@ import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import CardHeader from '@mui/material/CardHeader';
import { useHover, useRequest, useUnmount } from 'ahooks';
-import { ApiErr } from '@/apis/error';
-import { LayoutAlertErr, token } from '@/store/store';
+import { LayoutAlertErr, user } from '@/store/store';
import { useAtomValue, useSetAtom } from 'jotai';
-import { userInfo, yggProfile } from '@/apis/apis';
+import { yggProfile } from '@/apis/apis';
import { useNavigate } from 'react-router-dom';
import Box from '@mui/material/Box';
import { useEffect, useRef, useState } from 'react';
@@ -22,32 +21,21 @@ import useTilg from 'tilg';
import useTitle from '@/hooks/useTitle';
const Profile = function Profile() {
- const nowToken = useAtomValue(token)
const navigate = useNavigate();
const setErr = useSetAtom(LayoutAlertErr)
+ const userinfo = useAtomValue(user)
+
const [textures, setTextures] = useState({ skin: "", cape: "", model: "default" })
useTitle("个人信息")
- const userinfo = useRequest(() => userInfo(nowToken), {
- refreshDeps: [nowToken],
- cacheKey: "/api/v1/user" + nowToken,
- staleTime: 60000,
- onError: e => {
- if (e instanceof ApiErr && e.code == 5) {
- navigate("/login")
- }
- console.warn(e)
- setErr(String(e))
- }
- })
- const SkinInfo = useRequest(() => yggProfile(userinfo.data?.uuid ?? ""), {
- cacheKey: "/api/yggdrasil/sessionserver/session/minecraft/profile/" + userinfo.data?.uuid,
+ const SkinInfo = useRequest(() => yggProfile(userinfo.uuid ?? ""), {
+ cacheKey: "/api/yggdrasil/sessionserver/session/minecraft/profile/" + userinfo?.uuid,
onError: e => {
console.warn(e)
setErr(String(e))
},
- refreshDeps: [userinfo.data?.uuid],
+ refreshDeps: [userinfo?.uuid],
})
useEffect(() => {
@@ -70,12 +58,10 @@ const Profile = function Profile() {
- uid
- {(userinfo.loading && !userinfo.data) ? : userinfo.data?.uid}
name
- {(SkinInfo.loading || userinfo.loading) && !SkinInfo.data ? : SkinInfo.data?.name}
+ {userinfo.name}
uuid
- {(userinfo.loading && !userinfo.data) ? : userinfo.data?.uuid}
+ {userinfo.uuid}
{/*
diff --git a/frontend/src/views/profile/Security.tsx b/frontend/src/views/profile/Security.tsx
new file mode 100644
index 0000000..f508280
--- /dev/null
+++ b/frontend/src/views/profile/Security.tsx
@@ -0,0 +1,6 @@
+
+export default function Security() {
+ return (<>
+ 密码设置
+ >)
+}
\ No newline at end of file
diff --git a/frontend/src/views/profile/Textures.tsx b/frontend/src/views/profile/Textures.tsx
index 714d291..b49a4a4 100644
--- a/frontend/src/views/profile/Textures.tsx
+++ b/frontend/src/views/profile/Textures.tsx
@@ -16,45 +16,48 @@ import Box from "@mui/material/Box";
import ReactSkinview3d from "react-skinview3d";
import { useUnmount } from "ahooks";
import { SkinViewer } from "skinview3d";
+import { useAtomValue, useSetAtom } from "jotai";
+import { LayoutAlertErr, token, user } from "@/store/store";
+import { upTextures } from "@/apis/apis";
+import Loading from "@/components/Loading";
const Textures = function Textures() {
const [redioValue, setRedioValue] = useState("skin")
useTitle("上传皮肤")
const [file, setFile] = useState(null)
- const skin = useRef({
- skinUrl: "",
- capeUrl: "",
- })
+ const skin = useRef("")
const skinview3dView = useRef(null);
+ const setErr = useSetAtom(LayoutAlertErr)
+ const [loading, setLoading] = useState(false)
+ const userinfo = useAtomValue(user)
+ const nowToken = useAtomValue(token)
useUnmount(() => {
- skin.current.skinUrl && URL.revokeObjectURL(skin.current.skinUrl)
- skin.current.capeUrl && URL.revokeObjectURL(skin.current.capeUrl)
+ skin.current && URL.revokeObjectURL(skin.current)
skinview3dView.current?.dispose()
})
useEffect(() => {
if (file) {
const nu = URL.createObjectURL(file)
- skin.current.skinUrl && URL.revokeObjectURL(skin.current.skinUrl)
- skin.current.capeUrl && URL.revokeObjectURL(skin.current.capeUrl)
+ skin.current && URL.revokeObjectURL(skin.current)
skinview3dView.current?.loadSkin(null)
skinview3dView.current?.loadCape(null)
switch (redioValue) {
case "skin":
- skin.current.skinUrl = nu
+ skin.current = nu
skinview3dView.current?.loadSkin(nu, { model: "default" }).then(() =>
skinview3dView.current?.loadSkin(nu, { model: "default" })
)
break
case "slim":
- skin.current.skinUrl = nu
+ skin.current = nu
skinview3dView.current?.loadSkin(nu, { model: "slim" }).then(() =>
skinview3dView.current?.loadSkin(nu, { model: "slim" })
)
break
case "cape":
- skin.current.capeUrl = nu
+ skin.current = nu
skinview3dView.current?.loadCape(nu).then(() => {
skinview3dView.current?.loadCape(nu)
})
@@ -70,6 +73,15 @@ const Textures = function Textures() {
setFile(newFile)
}
+ const handleToUpload = () => {
+ if (!file || loading) return
+ setLoading(true)
+ const textureType = redioValue == "cape" ? "cape" : "skin"
+ const model = redioValue == "slim" ? "slim" : ""
+ upTextures(userinfo.uuid, nowToken, textureType, model, file).catch(e => [setErr(String(e)), console.warn(e)]).
+ finally(() => setLoading(false))
+ }
+
useTilg()
return (<>
@@ -98,7 +110,7 @@ const Textures = function Textures() {
-
+
@@ -114,6 +126,7 @@ const Textures = function Textures() {
+ {loading && }
>)
}