Files
opencloud/src/views/profile/ProfileSettingsView.vue
T

203 lines
6.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { RouterLink } from 'vue-router'
import { NAlert, NButton, NCard, NForm, NInput, useMessage } from 'naive-ui'
import { useAuthStore } from '@/stores/auth'
const authStore = useAuthStore()
const message = useMessage()
const usernameDraft = ref('')
const newPassword = ref('')
const confirmNewPassword = ref('')
const error = ref('')
const success = ref('')
const usernameSaving = ref(false)
const passwordSaving = ref(false)
onMounted(() => {
usernameDraft.value = authStore.profile?.username || ''
})
async function saveUsername() {
const nextUsername = usernameDraft.value.trim()
error.value = ''
success.value = ''
if (!nextUsername) {
error.value = '昵称不能为空。'
return
}
if (nextUsername.length < 2) {
error.value = '昵称至少需要 2 个字符。'
return
}
if (nextUsername === authStore.profile?.username) {
success.value = '昵称没有变化。'
return
}
usernameSaving.value = true
try {
await authStore.updateUsername(nextUsername)
success.value = '昵称已更新。'
message.success('昵称已更新')
} catch (e) {
error.value = e instanceof Error ? e.message : '昵称更新失败'
} finally {
usernameSaving.value = false
}
}
async function savePassword() {
error.value = ''
success.value = ''
if (newPassword.value.length < 8) {
error.value = '新密码至少需要 8 位。'
return
}
if (newPassword.value !== confirmNewPassword.value) {
error.value = '两次输入的新密码不一致。'
return
}
passwordSaving.value = true
try {
await authStore.updatePassword(newPassword.value)
newPassword.value = ''
confirmNewPassword.value = ''
success.value = '密码已更新。'
message.success('密码已更新')
} catch (e) {
error.value = e instanceof Error ? e.message : '密码更新失败'
} finally {
passwordSaving.value = false
}
}
</script>
<template>
<div class="min-h-[calc(100vh-4rem)] bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)] py-10">
<div class="oc-container oc-container--content">
<RouterLink to="/profile">
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral">← 返回个人主页</NButton>
</RouterLink>
<div class="mt-6">
<p class="oc-page-eyebrow">Account Settings</p>
<h1 class="oc-page-title">个人资料设置</h1>
<p class="oc-page-description">
修改公开昵称和登录密码。昵称会显示在画廊、图鉴和地图中,且不能与其他用户重复。
</p>
</div>
<div class="mt-8 grid gap-6">
<NAlert
v-if="error"
type="error"
:show-icon="false"
:bordered="false"
>
{{ error }}
</NAlert>
<NAlert
v-if="success"
type="success"
:show-icon="false"
:bordered="false"
>
{{ success }}
</NAlert>
<NCard class="oc-panel-card border border-slate-200 bg-white shadow-sm" :bordered="false">
<div class="grid gap-5 lg:grid-cols-[0.8fr_1.2fr] lg:items-start">
<div>
<h2 class="text-2xl font-bold text-slate-900">公开昵称</h2>
<p class="mt-2 text-sm leading-6 text-slate-500">
用于公开展示你的上传记录。保存前会检查是否与其他用户重复。
</p>
</div>
<div class="grid gap-3 sm:grid-cols-[minmax(0,1fr)_auto]">
<NInput
v-model:value="usernameDraft"
placeholder="输入新的昵称"
maxlength="32"
show-count
/>
<NButton
secondary
strong
type="default"
class="oc-panel-button oc-panel-button--teal"
:loading="usernameSaving"
@click="saveUsername"
>
保存昵称
</NButton>
</div>
</div>
</NCard>
<NCard class="oc-panel-card border border-slate-200 bg-white shadow-sm" :bordered="false">
<div class="grid gap-5 lg:grid-cols-[0.8fr_1.2fr] lg:items-start">
<div>
<h2 class="text-2xl font-bold text-slate-900">登录密码</h2>
<p class="mt-2 text-sm leading-6 text-slate-500">
修改后下次登录需要使用新密码。建议使用至少 8 位且不易猜测的密码。
</p>
</div>
<NForm class="grid gap-3" @submit.prevent="savePassword">
<input
:value="authStore.user?.email || ''"
type="text"
name="username"
autocomplete="username"
class="sr-only"
tabindex="-1"
aria-label="账户邮箱"
readonly
/>
<NInput
v-model:value="newPassword"
type="password"
show-password-on="click"
:input-props="{
autocomplete: 'new-password',
name: 'new-password',
required: true,
}"
placeholder="新密码"
/>
<NInput
v-model:value="confirmNewPassword"
type="password"
show-password-on="click"
:input-props="{
autocomplete: 'new-password',
name: 'confirm-new-password',
required: true,
}"
placeholder="确认新密码"
/>
<div class="flex justify-end">
<NButton
secondary
strong
type="default"
attr-type="submit"
class="oc-panel-button oc-panel-button--teal"
:loading="passwordSaving"
>
保存密码
</NButton>
</div>
</NForm>
</div>
</NCard>
</div>
</div>
</div>
</template>