refactor: 主要功能实现
目前的工作已经实现的功能: - 基本 FastAPI 路由; - 基本 AI 聊天和创作功能; - 用户信息管理、权限验证、JWT 令牌签发和验证、端点保护; - HTML 验证码邮件发送和验证码验证。
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
<script setup lang="ts">
|
||||
import { useNowUser } from '@/stores/now-user.js'
|
||||
import { ref, watch } from 'vue'
|
||||
import SelectFileModal from '@/components/file/SelectFileModal.vue'
|
||||
import { api } from '@/tools/web.js'
|
||||
import type { UploadFileDto, UserDto } from '@/types/user.js'
|
||||
import { useHead } from '@unhead/vue'
|
||||
import ChangeEmailModal from '@/components/admin/ChangeEmailModal.vue'
|
||||
|
||||
useHead({
|
||||
title: '用户资料',
|
||||
})
|
||||
|
||||
const NOWUSER = useNowUser()
|
||||
|
||||
const showAvatarModal = ref(false)
|
||||
const showBackgroundModal = ref(false)
|
||||
const files = ref<UploadFileDto[]>([])
|
||||
const avatar_selectFiles = ref<UploadFileDto[]>([])
|
||||
const background_selectFiles = ref<UploadFileDto[]>([])
|
||||
|
||||
const showChangeEmailModal = ref(false)
|
||||
const showChangePhoneModal = ref(false)
|
||||
|
||||
async function loadFiles() {
|
||||
return await api.get('/file/').then((res) => (files.value = res.data as UploadFileDto[]))
|
||||
}
|
||||
|
||||
const infoForm = ref({
|
||||
name: '',
|
||||
display_name: '',
|
||||
avatar_url: '',
|
||||
background_url: '',
|
||||
description: '',
|
||||
})
|
||||
|
||||
function reInitForm() {
|
||||
infoForm.value.name = NOWUSER.name
|
||||
infoForm.value.display_name = NOWUSER.display_name
|
||||
infoForm.value.avatar_url = NOWUSER.avatar_url
|
||||
infoForm.value.background_url = NOWUSER.background_url
|
||||
infoForm.value.description = NOWUSER.description
|
||||
}
|
||||
|
||||
watch(
|
||||
() => avatar_selectFiles.value.at(0)?.download_url,
|
||||
(value) => {
|
||||
if (value) {
|
||||
infoForm.value.avatar_url = value
|
||||
} else {
|
||||
infoForm.value.avatar_url = NOWUSER.avatar_url
|
||||
}
|
||||
},
|
||||
)
|
||||
watch(
|
||||
() => background_selectFiles.value.at(0)?.download_url,
|
||||
(value) => {
|
||||
if (value) {
|
||||
infoForm.value.background_url = value
|
||||
} else {
|
||||
infoForm.value.background_url = NOWUSER.background_url
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => NOWUSER.isLogin,
|
||||
() => {
|
||||
reInitForm()
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
async function save() {
|
||||
const user = await api
|
||||
.post('/admin/me/', JSON.stringify(infoForm.value))
|
||||
.then((res) => res.data as UserDto)
|
||||
await NOWUSER.loadWithUserInfo(user)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-card>
|
||||
<template #header>
|
||||
<n-h3 prefix="bar" style="margin: 0">用户资料</n-h3>
|
||||
</template>
|
||||
<n-alert type="warning">
|
||||
您需要通过用户名、邮箱和手机号三者之一进行登录,修改之后请牢记新的用户名。
|
||||
</n-alert>
|
||||
<div class="ui-content">
|
||||
<n-form style="width: 450px" label-width="auto" label-placement="left" label-align="right">
|
||||
<n-form-item label="用户名">
|
||||
<n-input v-model:value="infoForm.name" />
|
||||
</n-form-item>
|
||||
<n-form-item label="展示名称">
|
||||
<n-input v-model:value="infoForm.display_name" />
|
||||
</n-form-item>
|
||||
<n-form-item label="头像">
|
||||
<n-flex>
|
||||
<n-avatar v-model:src="infoForm.avatar_url" :size="96" circle />
|
||||
<n-flex vertical>
|
||||
<n-tag type="info">需在「内容-上传」中提前上传图像。</n-tag>
|
||||
<n-tag type="warning">使用方形图像以获得最佳效果。</n-tag>
|
||||
<n-flex>
|
||||
<n-button secondary type="info" @click="showAvatarModal = true">选择</n-button>
|
||||
<n-button
|
||||
secondary
|
||||
type="tertiary"
|
||||
@click="infoForm.avatar_url = NOWUSER.avatar_url"
|
||||
>重置
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-form-item>
|
||||
<n-form-item label="个人背景">
|
||||
<n-flex>
|
||||
<n-avatar v-model:src="infoForm.background_url" :size="96" object-fit="cover" />
|
||||
<n-flex vertical>
|
||||
<n-tag type="info">需在「内容-上传」中提前上传图像。</n-tag>
|
||||
<n-flex>
|
||||
<n-button secondary type="info" @click="showBackgroundModal = true">选择</n-button>
|
||||
<n-button
|
||||
secondary
|
||||
type="tertiary"
|
||||
@click="infoForm.background_url = NOWUSER.background_url"
|
||||
>重置
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-form-item>
|
||||
<n-form-item label="个人介绍">
|
||||
<n-input
|
||||
v-model:value="infoForm.description"
|
||||
:autosize="{ minRows: 2, maxRows: 5 }"
|
||||
type="textarea"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="邮箱">
|
||||
<n-input v-model:value="NOWUSER.email" disabled />
|
||||
</n-form-item>
|
||||
<n-form-item label="手机号">
|
||||
<n-input v-model:value="NOWUSER.phone" disabled />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-flex>
|
||||
<n-button class="ui-button" type="primary" @click="save">保存</n-button>
|
||||
<n-button class="ui-button" type="warning" @click="showChangeEmailModal = true"
|
||||
>更改邮箱</n-button
|
||||
>
|
||||
<n-button class="ui-button" type="warning">更改手机号</n-button>
|
||||
<n-button class="ui-button" type="tertiary">重置全部</n-button>
|
||||
</n-flex>
|
||||
</div>
|
||||
|
||||
<select-file-modal
|
||||
:load-files="loadFiles"
|
||||
:max="1"
|
||||
:extensions="['png', 'jpg', 'jpeg']"
|
||||
v-model:show-modal="showAvatarModal"
|
||||
v-model:select-files="avatar_selectFiles"
|
||||
/>
|
||||
<select-file-modal
|
||||
:load-files="loadFiles"
|
||||
:max="1"
|
||||
:extensions="['png', 'jpg', 'jpeg']"
|
||||
v-model:show-modal="showBackgroundModal"
|
||||
v-model:select-files="background_selectFiles"
|
||||
/>
|
||||
<change-email-modal v-model:show-modal="showChangeEmailModal" />
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
div.ui-content {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ui-button {
|
||||
flex-basis: 100px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user