feat: 添加用户关注功能

- 新增 Follow 表和 User.bio 字段 (Prisma schema)
- 创建 follow 模块 (action-service-repository)
- 新增 FollowButton/FollowStats/UserList 组件
- 用户页面显示 bio、粉丝/关注数、关注按钮
- 新增 /users/[username]/followers 和 following 页面
- 添加 en-US/zh-CN i18n 翻译

⚠️ 需要运行: prisma migrate dev --name add_follow_and_bio
This commit is contained in:
2026-03-10 14:56:06 +08:00
parent abcae1b8d1
commit 683a4104ec
20 changed files with 940 additions and 145 deletions

View File

@@ -56,6 +56,7 @@ export type ActionOutputUserProfile = {
username: string | null;
displayUsername: string | null;
image: string | null;
bio: string | null;
createdAt: Date;
updatedAt: Date;
};

View File

@@ -8,6 +8,7 @@ export type RepoOutputUserProfile = {
username: string | null;
displayUsername: string | null;
image: string | null;
bio: string | null;
createdAt: Date;
updatedAt: Date;
} | null;

View File

@@ -6,9 +6,6 @@ import {
RepoOutputUserProfile
} from "./auth-repository-dto";
/**
* Find user by username
*/
export async function repoFindUserByUsername(dto: RepoInputFindUserByUsername): Promise<RepoOutputUserProfile> {
const user = await prisma.user.findUnique({
where: { username: dto.username },
@@ -19,6 +16,7 @@ export async function repoFindUserByUsername(dto: RepoInputFindUserByUsername):
username: true,
displayUsername: true,
image: true,
bio: true,
createdAt: true,
updatedAt: true,
}
@@ -27,9 +25,6 @@ export async function repoFindUserByUsername(dto: RepoInputFindUserByUsername):
return user;
}
/**
* Find user by ID
*/
export async function repoFindUserById(dto: RepoInputFindUserById): Promise<RepoOutputUserProfile> {
const user = await prisma.user.findUnique({
where: { id: dto.id },
@@ -40,6 +35,7 @@ export async function repoFindUserById(dto: RepoInputFindUserById): Promise<Repo
username: true,
displayUsername: true,
image: true,
bio: true,
createdAt: true,
updatedAt: true,
}
@@ -48,9 +44,6 @@ export async function repoFindUserById(dto: RepoInputFindUserById): Promise<Repo
return user;
}
/**
* Find user by email
*/
export async function repoFindUserByEmail(dto: RepoInputFindUserByEmail): Promise<RepoOutputUserProfile> {
const user = await prisma.user.findUnique({
where: { email: dto.email },
@@ -61,6 +54,7 @@ export async function repoFindUserByEmail(dto: RepoInputFindUserByEmail): Promis
username: true,
displayUsername: true,
image: true,
bio: true,
createdAt: true,
updatedAt: true,
}

View File

@@ -34,6 +34,7 @@ export type ServiceOutputUserProfile = {
username: string | null;
displayUsername: string | null;
image: string | null;
bio: string | null;
createdAt: Date;
updatedAt: Date;
} | null;