From 041d288b252e4a9ba4c44ec1de7e8e10bd08826c Mon Sep 17 00:00:00 2001 From: Ap_Tx <3045929398@qq.com> Date: Sat, 17 Oct 2026 19:33:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=9A=AE=E8=82=A4?= =?UTF-8?q?=E7=AB=99=E8=B4=A6=E5=8F=B7=E8=AE=BE=E7=BD=AE=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - API 层补充改名、改网站密码、改 Minecraft 密码、上传头像。 - SkinSiteProfileModal:用户名修改、头像上传(居中裁剪为 256×256)、 网站密码修改、Minecraft 密码修改与恢复默认。 - 主页账号卡增加「Account」入口打开该弹窗。 --- .../ui/skin-site/SkinSiteAccountCard.vue | 10 +- .../components/ui/skin-site/SkinSiteHome.vue | 5 +- .../ui/skin-site/SkinSiteProfileModal.vue | 402 ++++++++++++++++++ .../app-frontend/src/helpers/skin-site-api.ts | 49 +++ 4 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 apps/app-frontend/src/components/ui/skin-site/SkinSiteProfileModal.vue diff --git a/apps/app-frontend/src/components/ui/skin-site/SkinSiteAccountCard.vue b/apps/app-frontend/src/components/ui/skin-site/SkinSiteAccountCard.vue index a935c24..69d0b28 100644 --- a/apps/app-frontend/src/components/ui/skin-site/SkinSiteAccountCard.vue +++ b/apps/app-frontend/src/components/ui/skin-site/SkinSiteAccountCard.vue @@ -29,9 +29,10 @@ const messages = defineMessages({ loading: { id: 'app.skin-site.home.loading', defaultMessage: 'Loading…' }, error: { id: 'app.skin-site.home.error', defaultMessage: 'Could not load players.' }, signIn: { id: 'app.skin-site.home.sign-in', defaultMessage: 'Sign in' }, + settings: { id: 'app.skin-site.home.settings', defaultMessage: 'Account' }, }) -const emit = defineEmits<{ (e: 'sign-in'): void }>() +const emit = defineEmits<{ (e: 'sign-in' | 'open-settings'): void }>() const luck = ref(null) const luckLoading = ref(false) @@ -89,6 +90,13 @@ watch(signedIn, loadLuck) {{ skinSiteUser!.username }} {{ skinSiteUser!.uuid }} +
>() +const profileModal = ref>() async function copyAddress() { try { @@ -43,7 +45,7 @@ async function copyAddress() {

{{ formatMessage(messages.subtitle) }}

- +
@@ -71,5 +73,6 @@ async function copyAddress() {
+
diff --git a/apps/app-frontend/src/components/ui/skin-site/SkinSiteProfileModal.vue b/apps/app-frontend/src/components/ui/skin-site/SkinSiteProfileModal.vue new file mode 100644 index 0000000..b263a7b --- /dev/null +++ b/apps/app-frontend/src/components/ui/skin-site/SkinSiteProfileModal.vue @@ -0,0 +1,402 @@ + + diff --git a/apps/app-frontend/src/helpers/skin-site-api.ts b/apps/app-frontend/src/helpers/skin-site-api.ts index 90e3017..0879bc7 100644 --- a/apps/app-frontend/src/helpers/skin-site-api.ts +++ b/apps/app-frontend/src/helpers/skin-site-api.ts @@ -431,3 +431,52 @@ export interface SkinSiteAnnouncement { export function skinSiteAnnouncements(): Promise> { return skinSiteRequest('broadcast/all', { type: 'skin' }) } +// --------------------------------------------------------------------------- +// Account updates (requires the JWT) +// --------------------------------------------------------------------------- + +export function skinSiteChangeUsername(newUsername: string): Promise> { + return skinSiteRequest('update/username', { + method: 'POST', + body: { newUsername }, + }) +} + +export function skinSiteChangePassword( + oldPassword: string, + newPassword: string, +): Promise> { + return skinSiteRequest('update/password', { + method: 'POST', + body: { oldPassword, newPassword }, + }) +} + +/** Pass null to reset the Minecraft password back to the website password. */ +export function skinSiteChangeYggdrasilPassword( + newPassword: string | null, +): Promise> { + return skinSiteRequest('update/yggdrasilPassword', { + method: 'POST', + body: { newPassword }, + }) +} + +/** Upload a new avatar image (multipart). */ +export async function skinSiteUploadAvatar(blob: Blob): Promise> { + const form = new FormData() + form.append('avatar', blob) + + const url = `${SKIN_SITE_ORIGIN}/starlight/update/avatar` + const headers: Record = {} + const token = getSkinSiteToken() + if (token) headers['Authorization'] = `Bearer ${token}` + + let response: Response + try { + response = await tauriFetch(url, { method: 'POST', headers, body: form }) + } catch { + return handleException(0) + } + return processResponse(response) +}