添加粉丝关注页面

This commit is contained in:
张成
2025-10-01 01:48:36 +08:00
parent 78d8ec659e
commit a5539bd219
7 changed files with 187 additions and 62 deletions

View File

@@ -24,8 +24,8 @@ const envConfigs: Record<EnvType, EnvConfig> = {
// 开发环境
development: {
name: '开发环境',
apiBaseURL: 'https://sit.light120.com',
// apiBaseURL: 'http://localhost:9098',
// apiBaseURL: 'https://sit.light120.com',
apiBaseURL: 'http://localhost:9098',
timeout: 15000,
enableLog: true,
enableMock: true,

View File

@@ -182,29 +182,6 @@
.reply-icon {
width: 12px;
height: 12px;
position: relative;
// 绘制回复图标使用SVG路径
&::before,
&::after {
content: '';
position: absolute;
background: #333333;
}
&::before {
top: 1px;
left: 1px;
width: 10px;
height: 8.75px;
clip-path: polygon(0% 0%, 100% 0%, 100% 20%, 20% 20%, 20% 100%, 0% 100%);
}
&::after {
width: 0;
height: 0.75px;
background: #333333;
}
}
.reply-text {
@@ -225,6 +202,11 @@
border-radius: 9px;
background: #F5F5F5;
flex-shrink: 0;
cursor: pointer;
&:active {
opacity: 0.8;
}
}
}

View File

@@ -2,13 +2,13 @@ import { useState, useEffect } from "react";
import { View, Text, ScrollView, Image } from "@tarojs/components";
import { Avatar } from "@nutui/nutui-react-taro";
import { withAuth, EmptyState } from "@/components";
import noticeService from "@/services/noticeService";
import commentService, { CommentActivity } from "@/services/commentService";
import Taro from "@tarojs/taro";
import "./index.scss";
// 评论/回复类型定义
interface CommentReplyItem {
id: string;
id: number;
user_avatar: string;
user_nickname: string;
action_type: "comment" | "reply"; // 评论了你的球局 / 回复了你的评论
@@ -16,8 +16,8 @@ interface CommentReplyItem {
content: string;
original_comment?: string; // 被回复的评论内容
activity_image: string;
activity_id?: string;
is_read: number;
activity_id: number;
activity_title: string;
}
const CommentReply = () => {
@@ -34,23 +34,24 @@ const CommentReply = () => {
setLoading(true);
try {
const res = await noticeService.getNotificationList({
notification_type: "comment", // 筛选评论类型
const res = await commentService.getMyActivities({
page: 1,
pageSize: 20,
});
if (res.code === 0) {
if (res.code === 0 && res.data) {
// 映射数据
const mappedList = res.data.list.map((item: any) => ({
const mappedList = res.data.rows.map((item: CommentActivity) => ({
id: item.id,
user_avatar: item.related_user_avatar || "",
user_nickname: item.related_user_nickname || "匿名用户",
action_type: (item.notification_type === "reply" ? "reply" : "comment") as "comment" | "reply",
time: item.created_at,
user_avatar: item.user?.avatar_url || "",
user_nickname: item.user?.nickname || "匿名用户",
action_type: item.type === "reply" ? "reply" as const : "comment" as const,
time: item.create_time,
content: item.content || "",
original_comment: item.original_content || "",
activity_image: item.activity_image || "",
activity_id: item.related_activity_id || "",
is_read: item.is_read,
original_comment: item.parent_comment?.content || "",
activity_image: item.game?.image_list?.[0] || "",
activity_id: item.game_id,
activity_title: item.game?.title || "",
}));
setCommentList(mappedList);
@@ -98,6 +99,13 @@ const CommentReply = () => {
// TODO: 跳转到回复页面或弹出回复框
};
// 处理点击球局
const handleGameClick = (gameId: number) => {
Taro.navigateTo({
url: `/game_pages/detail/index?id=${gameId}`,
});
};
// 处理返回
const handleBack = () => {
Taro.navigateBack();
@@ -136,14 +144,22 @@ const CommentReply = () => {
{/* 回复按钮 */}
<View className="reply-button" onClick={() => handleReply(item)}>
<View className="reply-icon"></View>
<Image
className="reply-icon"
src={require('@/static/message/reply-icon.svg')}
/>
<Text className="reply-text"></Text>
</View>
</View>
</View>
{/* 右侧球局图片 */}
<Image className="activity-image" src={item.activity_image} mode="aspectFill" />
<Image
className="activity-image"
src={item.activity_image}
mode="aspectFill"
onClick={() => handleGameClick(item.activity_id)}
/>
</View>
);
};

View File

@@ -2,20 +2,21 @@ import { useState, useEffect } from "react";
import { View, Text, ScrollView } from "@tarojs/components";
import { Avatar } from "@nutui/nutui-react-taro";
import { withAuth, EmptyState } from "@/components";
import noticeService from "@/services/noticeService";
import FollowService from "@/services/followService";
import Taro from "@tarojs/taro";
import "./index.scss";
// 关注项类型定义
interface FollowItem {
id: string;
user_id: string;
id: number;
user_id: number;
user_avatar: string;
user_nickname: string;
user_signature?: string;
city?: string;
ntrp_level?: string;
time: string;
is_mutual: boolean; // 是否互相关注
is_read: number;
}
const NewFollow = () => {
@@ -32,21 +33,20 @@ const NewFollow = () => {
setLoading(true);
try {
const res = await noticeService.getNotificationList({
notification_type: "follow", // 筛选关注类型
});
const res = await FollowService.get_new_fans_list(1, 20);
if (res.code === 0) {
if (res.list) {
// 映射数据
const mappedList = res.data.list.map((item: any) => ({
const mappedList = res.list.map((item: any) => ({
id: item.id,
user_id: item.related_user_id || "",
user_avatar: item.related_user_avatar || "",
user_nickname: item.related_user_nickname || "匿名用户",
user_signature: item.related_user_signature || "",
time: item.created_at,
is_mutual: item.is_mutual_follow || false,
is_read: item.is_read,
user_id: item.id,
user_avatar: item.avatar_url || "",
user_nickname: item.nickname || "匿名用户",
user_signature: item.personal_profile || "",
city: item.city || "",
ntrp_level: item.ntrp_level || "",
time: item.follow_time,
is_mutual: item.is_mutual || false,
}));
setFollowList(mappedList);
@@ -93,8 +93,7 @@ const NewFollow = () => {
}
try {
// TODO: 调用关注接口
// await userService.followUser({ user_id: item.user_id });
await FollowService.follow_back(item.user_id);
Taro.showToast({
title: "关注成功",
@@ -125,7 +124,7 @@ const NewFollow = () => {
};
// 处理点击用户
const handleUserClick = (userId: string) => {
const handleUserClick = (userId: number) => {
Taro.navigateTo({
url: `/user_pages/other/index?user_id=${userId}`,
});

View File

@@ -0,0 +1,94 @@
import httpService from "./httpService";
import type { ApiResponse } from "./httpService";
// 评论项接口定义
export interface CommentActivity {
id: number;
type: "comment" | "reply";
activity_type: string;
game_id: number;
parent_id: number | null;
content: string;
like_count: number;
reply_count: number;
create_time: string;
user: {
id: number;
nickname: string;
province: string;
avatar_url: string;
};
game: {
id: number;
title: string;
start_time: string;
location_name: string;
image_list?: string[];
};
reply_to_user: {
id: number;
nickname: string;
avatar_url: string;
} | null;
parent_comment: {
id: number;
content: string;
user_id: number;
user_nickname: string;
} | null;
}
// 获取评论动态请求参数
export interface GetMyActivitiesParams {
page?: number;
pageSize?: number;
}
// 评论动态列表响应
export interface CommentActivitiesResponse {
rows: CommentActivity[];
count: number;
page: number;
pageSize: number;
totalPages: number;
}
class CommentService {
// 获取当前用户的评论和回复动态
async getMyActivities(params: GetMyActivitiesParams = {}): Promise<ApiResponse<CommentActivitiesResponse>> {
const { page = 1, pageSize = 10 } = params;
return httpService.post("/comments/my_activities", { page, pageSize }, { showLoading: false });
}
// 发表评论
async createComment(game_id: number, content: string): Promise<ApiResponse<any>> {
return httpService.post("/comments/create", { game_id, content });
}
// 回复评论
async replyComment(parent_id: number, reply_to_user_id: number, content: string): Promise<ApiResponse<any>> {
return httpService.post("/comments/reply", { parent_id, reply_to_user_id, content });
}
// 获取评论列表
async getCommentList(game_id: number, page: number = 1, pageSize: number = 10): Promise<ApiResponse<any>> {
return httpService.post("/comments/list", { game_id, page, pageSize });
}
// 点赞/取消点赞评论
async likeComment(comment_id: number): Promise<ApiResponse<any>> {
return httpService.post("/comments/like", { comment_id });
}
// 删除评论
async deleteComment(comment_id: number): Promise<ApiResponse<any>> {
return httpService.post("/comments/delete", { comment_id });
}
// 获取评论的所有回复
async getCommentReplies(comment_id: number, page: number = 1, pageSize: number = 10): Promise<ApiResponse<any>> {
return httpService.post("/comments/replies", { comment_id, page, pageSize });
}
}
export default new CommentService();

View File

@@ -84,6 +84,34 @@ export class FollowService {
}
}
// 获取新增粉丝列表(新关注的人)
static async get_new_fans_list(
page: number = 1,
page_size: number = 20
): Promise<FollowListResponse> {
try {
const response = await httpService.post<FollowListResponse>(
'/user_follow/new_fans_list',
{ page, page_size },
{ showLoading: false }
);
if (response.code === 0) {
// 为数据添加 follow_status 标识
const list = response.data.list.map(user => ({
...user,
follow_status: user.is_mutual ? 'mutual_follow' as const : 'follower' as const
}));
return { ...response.data, list };
} else {
throw new Error(response.message || '获取新增粉丝列表失败');
}
} catch (error) {
console.error('获取新增粉丝列表失败:', error);
return { list: [], total: 0 };
}
}
// 获取我的关注列表
static async get_following_list(
page: number = 1,

View File

@@ -0,0 +1,6 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 1.5H1V9H3.25V10.25L5.75 9H11V1.5Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.5 4.875V5.625" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 4.875V5.625" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8.5 4.875V5.625" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 494 B