Skip to content

Commit

Permalink
✨ 用户信息更新功能 + 欢迎页用户信息填写功能
Browse files Browse the repository at this point in the history
✨
1. 设置页用户信息更新功能
2. 欢迎页用户信息填写 / 重置功能
3. 更新全新头像上传流程,点击提交后头像不会直接更新而是最终确认更新才会更新。
  • Loading branch information
cfdxkk committed May 17, 2024
1 parent 7e1e254 commit e32edfe
Show file tree
Hide file tree
Showing 7 changed files with 298 additions and 100 deletions.
29 changes: 24 additions & 5 deletions components/Settings/SettingsUserProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
const validChar = makeUsername();
const profile = defineModel<{
name: string;
nickname: string;
nameValid?: boolean;
bio: string;
gender: string;
Expand Down Expand Up @@ -48,16 +49,33 @@

<template>
<div class="name">
<!-- TODO: 使用多语言 -->
<!-- FIXME: t.user.name 应为“用户名”而非“昵称” -->
<TextBox
ref="nameTextBox"
v-model="profile.name"
:placeholder="t.user.name"
placeholder="用户名"
size="large"
icon="person"
required
:pattern="validChar"
:maxLength="20"
/>
<!-- TODO: 使用多语言 -->
<span>1~20个字符,不允许重名,仅可包含数字、大小写拉丁字母、越南语字母、汉字、常用平/片假名、现代谚文音节、特殊符号 「-」 「_」</span>
</div>

<div class="nickname">
<!-- TODO: 使用多语言 -->
<TextBox
ref="nameTextBox"
v-model="profile.nickname"
placeholder="昵称"
size="large"
icon="person"
:pattern="validChar"
:maxLength="20"
/>
<span>{{ t.user.name_requirements }}</span>
</div>

Expand Down Expand Up @@ -96,12 +114,13 @@
</div>
</div>
</div>

<div class="gender">
<div class="gender-subtitle">
<Icon name="tag" class="icon" />
<span class="text">{{ t(profile.tags.length).tag }}</span>
</div>
<!-- TODO: 需要改成和投稿页面一致的 TAG 创建逻辑 -->
<TagsEditor v-model="profile.tags" />
</div>
</template>
Expand All @@ -110,8 +129,8 @@
.text-box:not(.normal) {
--size: large;
}
.name {
.name, .nickname {
display: flex;
flex-direction: column;
gap: 8px;
Expand All @@ -125,11 +144,11 @@
.gender {
display: flex;
row-gap: 1rem;
align-items: center;
min-height: 36px;
padding: 0 12px;
color: c(icon-color);
row-gap: 1rem;
&,
* {
Expand Down
34 changes: 23 additions & 11 deletions composables/api/User/UserController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GET, POST, uploadFile2CloudflareImages } from "api/Common";
import getCorrectUri from "api/Common/getCorrectUri";
import type { CheckUserTokenResponseDto, GetSelfUserInfoRequestDto, GetSelfUserInfoResponseDto, GetUserAvatarUploadSignedUrlResponseDto, GetUserInfoByUidRequestDto, GetUserInfoByUidResponseDto, GetUserSettingsRequestDto, GetUserSettingsResponseDto, UpdateOrCreateUserSettingsRequestDto, UpdateOrCreateUserSettingsResponseDto, UpdateUserEmailRequestDto, UserExistsCheckRequestDto, UserExistsCheckResponseDto, UserLoginRequestDto, UserLoginResponseDto, UserRegistrationRequestDto, UserRegistrationResponseDto } from "./UserControllerDto";
import type { CheckUserTokenResponseDto, GetSelfUserInfoRequestDto, GetSelfUserInfoResponseDto, GetUserAvatarUploadSignedUrlResponseDto, GetUserInfoByUidRequestDto, GetUserInfoByUidResponseDto, GetUserSettingsRequestDto, GetUserSettingsResponseDto, UpdateOrCreateUserInfoResponseDto, UpdateOrCreateUserSettingsRequestDto, UpdateOrCreateUserSettingsResponseDto, UpdateUserEmailRequestDto, UpdateUserEmailResponseDto, UserExistsCheckRequestDto, UserExistsCheckResponseDto, UserLoginRequestDto, UserLoginResponseDto, UserRegistrationRequestDto, UserRegistrationResponseDto } from "./UserControllerDto";

const BACK_END_URL = getCorrectUri();
const USER_API_URI = `${BACK_END_URL}/user`;
Expand Down Expand Up @@ -36,11 +36,20 @@ export const userExistsCheck = async (userExistsCheckRequest: UserExistsCheckReq

/**
* 用户更改邮箱
* @param updateUserEmailRequest 用户更改邮箱的请求的参数
* @param updateUserEmailRequest 用户更改邮箱的请求的请求载荷
* @returns 用户更改邮箱返回的参数
*/
export const updateUserEmail = async (updateUserEmailRequest: UpdateUserEmailRequestDto): Promise<UserLoginResponseDto> => {
return await POST(`${USER_API_URI}/update/email`, updateUserEmailRequest) as UserLoginResponseDto;
export const updateUserEmail = async (updateUserEmailRequest: UpdateUserEmailRequestDto): Promise<UpdateUserEmailResponseDto> => {
return await POST(`${USER_API_URI}/update/email`, updateUserEmailRequest, { credentials: "include" }) as UpdateUserEmailResponseDto;
};

/**
* 创建或更新用户信息
* @param updateOrCreateUserInfoRequest 创建或更新用户信息的请求载荷
* @returns 创建或更新用户信息的响应结果
*/
export const updateOrCreateUserInfo = async (updateOrCreateUserInfoRequest: UpdateOrCreateUserInfoRequestDto): Promise<UpdateOrCreateUserInfoResponseDto> => {
return await POST(`${USER_API_URI}/update/info`, updateOrCreateUserInfoRequest, { credentials: "include" }) as UpdateOrCreateUserInfoResponseDto;
};

/**
Expand All @@ -52,15 +61,17 @@ export const updateUserEmail = async (updateUserEmailRequest: UpdateUserEmailReq
export const getSelfUserInfo = async (getSelfUserInfoRequest?: GetSelfUserInfoRequestDto): Promise<GetSelfUserInfoResponseDto> => {
// TODO: use { credentials: "include" } to allow save/read cookies from cross-origin domains. Maybe we should remove it before deployment to production env.
const selfUserInfo = await POST(`${USER_API_URI}/self`, getSelfUserInfoRequest, { credentials: "include" }) as GetSelfUserInfoResponseDto;
if (selfUserInfo.success) {
const selfUserInfoResult = selfUserInfo.result;
if (selfUserInfo.success && selfUserInfoResult) {
const selfUserInfoStore = useSelfUserInfoStore();
selfUserInfoStore.isLogined = true;
selfUserInfoStore.uid = selfUserInfo.result?.uid;
selfUserInfoStore.userAvatar = selfUserInfo.result?.avatar || "";
selfUserInfoStore.username = selfUserInfo.result?.username || "User"; // TODO: 使用多语言,为未设置用户名的用户提供国际化的缺省用户名
selfUserInfoStore.gender = selfUserInfo.result?.gender || "";
selfUserInfoStore.signature = selfUserInfo.result?.signature || "";
selfUserInfoStore.tags = selfUserInfo.result?.label || [];
selfUserInfoStore.uid = selfUserInfoResult.uid;
selfUserInfoStore.userAvatar = selfUserInfoResult.avatar || "";
selfUserInfoStore.username = selfUserInfoResult.username || "Anonymous"; // TODO: 使用多语言,为未设置用户名的用户提供国际化的缺省用户名
selfUserInfoStore.userNickname = selfUserInfoResult.userNickname || "Anonymous"; // TODO: 使用多语言,为未设置用户昵称的用户提供国际化的缺省用户昵称
selfUserInfoStore.gender = selfUserInfoResult.gender || "";
selfUserInfoStore.signature = selfUserInfoResult.signature || "";
selfUserInfoStore.tags = selfUserInfoResult.label?.map(label => label.labelName) || [];
}
return selfUserInfo;
};
Expand Down Expand Up @@ -95,6 +106,7 @@ export const userLogout = async (): Promise<undefined> => {
selfUserInfoStore.uid = undefined;
selfUserInfoStore.userAvatar = "";
selfUserInfoStore.username = "";
selfUserInfoStore.userNickname = "";
selfUserInfoStore.gender = "";
selfUserInfoStore.signature = "";
selfUserInfoStore.tags = [];
Expand Down
24 changes: 9 additions & 15 deletions composables/api/User/UserControllerDto.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ export type BeforeHashPasswordDataType = {
passwordHash: string;
};



/**
* 用户的个人标签
*/
Expand Down Expand Up @@ -170,7 +168,6 @@ export type UpdateOrCreateUserInfoRequestDto = {
userWebsite?: UserWebsite;
};


/**
* 更新或创建用户信息的请求结果
*/
Expand All @@ -183,8 +180,6 @@ export type UpdateOrCreateUserInfoResponseDto = {
result?: {} & UpdateOrCreateUserInfoRequestDto;
};



/**
* 获取当前登录的用户信息的请求参数
*/
Expand Down Expand Up @@ -282,8 +277,8 @@ export type GetUserAvatarUploadSignedUrlResponseDto = {
type UserLinkAccountsPrivacySettingDto = {
/** 关联账户类型 - 非空 - 例:"X" */
accountType: string;
/** 显示方式 - 非空 - 允许的值有:{public: 公开, following: 仅关注, private: 隐藏}; */
privacyType: 'public' | 'following' | 'private';
/** 显示方式 - 非空 - 允许的值有:{public: 公开, following: 仅关注, private: 隐藏} */
privacyType: "public" | "following" | "private";
};

/**
Expand All @@ -292,8 +287,8 @@ type UserLinkAccountsPrivacySettingDto = {
export type BasicUserSettingsDto = {
/** 是否启用 Cookie - 布尔 */
enableCookie?: boolean;
/** 主题外观设置(主题类型) - 可选的值:{light: 浅色, dark: 深色, system: 跟随系统}; */
themeType?: 'light' | 'dark' | 'system';
/** 主题外观设置(主题类型) - 可选的值:{light: 浅色, dark: 深色, system: 跟随系统} */
themeType?: "light" | "dark" | "system";
/** 主题颜色 - 字符串,颜色字符串 */
themeColor?: string;
/** 用户自定义主题颜色 - 字符串,HAX 颜色字符串,不包含井号 */
Expand All @@ -303,7 +298,7 @@ export type BasicUserSettingsDto = {
/** 是否启用彩色导航栏 - 布尔 */
coloredSideBar?: boolean;
/** 流量使用偏好 - 字符串,{standard: 标准, limit: 节省网络流量模式, preview: 超前加载} */
dataSaverMode?: 'standard' | 'limit' | 'preview';
dataSaverMode?: "standard" | "limit" | "preview";
/** 禁用搜索推荐 - 布尔 */
noSearchRecommendations?: boolean;
/** 禁用相关视频推荐 - 布尔 */
Expand All @@ -328,16 +323,16 @@ export type BasicUserSettingsDto = {
sharpAppearanceMode?: boolean;
/** 实验性:启用扁平模式 - 布尔 */
flatAppearanceMode?: boolean;
/** 用户关联网站的隐私设置 - 允许的值有:{public: 公开, following: 仅关注, private: 隐藏}; */
userWebsitePrivacySetting?: 'public' | 'following' | 'private';
/** 用户关联网站的隐私设置 - 允许的值有:{public: 公开, following: 仅关注, private: 隐藏} */
userWebsitePrivacySetting?: "public" | "following" | "private";
/** 用户关联账户的隐私设置 */
userLinkAccountsPrivacySetting?: UserLinkAccountsPrivacySettingDto[];
};

/**
* 获取用于渲染页面的用户设定的请求参数
*/
export type GetUserSettingsRequestDto = {} & GetSelfUserInfoRequestDto
export type GetUserSettingsRequestDto = {} & GetSelfUserInfoRequestDto;

/**
* 获取用于渲染页面的用户设定的请求响应
Expand All @@ -351,11 +346,10 @@ export type GetUserSettingsResponseDto = {
message?: string;
};


/**
* 更新或创建用户设定的请求参数
*/
export type UpdateOrCreateUserSettingsRequestDto = {} & BasicUserSettingsDto
export type UpdateOrCreateUserSettingsRequestDto = {} & BasicUserSettingsDto;

/**
* 更新或创建用户设定的请求响应
Expand Down
Loading

0 comments on commit e32edfe

Please sign in to comment.