refactor: 主要功能实现

目前的工作已经实现的功能:
- 基本 FastAPI 路由;
- 基本 AI 聊天和创作功能;
- 用户信息管理、权限验证、JWT 令牌签发和验证、端点保护;
- HTML 验证码邮件发送和验证码验证。
This commit is contained in:
2026-05-24 13:58:51 +08:00
parent f06de85257
commit 21f0d7725e
98 changed files with 6483 additions and 116 deletions
+187
View File
@@ -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>