diff --git a/babel.config.js b/babel.config.js index 5df4526..ee2edf5 100644 --- a/babel.config.js +++ b/babel.config.js @@ -9,6 +9,7 @@ module.exports = { compiler: 'webpack5', }] ], + plugins: [ [ "import", @@ -46,7 +47,12 @@ module.exports = { // 自动加载 css 样式文件 // customStyleName: (name) => `@nutui/nutui-react-taro/dist/es/packages/${name.toLowerCase()}/style-jrkf/css` }, + + 'nutui-react', ], + + ['transform-remove-console', { exclude: ['error', 'warn'] }], + ['@babel/plugin-transform-runtime', { corejs: false }] ], } diff --git a/package.json b/package.json index 71d29f8..2207efa 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ ], "author": "", "dependencies": { + "@babel/plugin-transform-runtime": "^7.28.3", "@babel/runtime": "^7.21.5", "@nutui/nutui-react-taro": "^2.6.14", "@tarojs/components": "4.1.5", @@ -53,6 +54,7 @@ "@tarojs/runtime": "4.1.5", "@tarojs/shared": "4.1.5", "@tarojs/taro": "4.1.5", + "babel-plugin-transform-remove-console": "^6.9.4", "dayjs": "^1.11.13", "qweather-icons": "^1.8.0", "react": "^18.0.0", diff --git a/project.config.json b/project.config.json index eaad1b7..00f5065 100644 --- a/project.config.json +++ b/project.config.json @@ -1,46 +1,46 @@ { - "miniprogramRoot": "dist/", - "projectname": "playBallTogether", - "description": "playBallTogether", - "appid": "wx815b533167eb7b53", - "setting": { - "urlCheck": true, - "es6": true, - "enhance": true, - "postcss": false, - "preloadBackgroundData": false, - "minified": false, - "newFeature": true, - "coverView": true, - "nodeModules": false, - "autoAudits": false, - "showShadowRootInWxmlPanel": false, - "scopeDataCheck": false, - "uglifyFileName": false, - "checkInvalidKey": true, - "checkSiteMap": true, - "uploadWithSourceMap": true, - "compileHotReLoad": false, - "useMultiFrameRuntime": true, - "useApiHook": true, - "useApiHostProcess": false, - "babelSetting": { - "ignore": [], - "disablePlugins": [], - "outputPath": "" - }, - "enableEngineNative": false, - "useIsolateContext": true, - "useCompilerModule": false, - "userConfirmedUseCompilerModuleSwitch": false, - "userConfirmedBundleSwitch": false, - "packNpmManually": false, - "packNpmRelationList": [], - "minifyWXSS": true, - "minifyWXML": true - }, - "compileType": "miniprogram", - "simulatorType": "wechat", - "simulatorPluginLibVersion": {}, - "condition": {} - } + "miniprogramRoot": "dist/", + "projectname": "playBallTogether", + "description": "playBallTogether", + "appid": "wx815b533167eb7b53", + "setting": { + "urlCheck": true, + "es6": true, + "enhance": true, + "postcss": true, + "preloadBackgroundData": false, + "minified": true, + "newFeature": true, + "coverView": true, + "nodeModules": false, + "autoAudits": false, + "showShadowRootInWxmlPanel": false, + "scopeDataCheck": false, + "uglifyFileName": false, + "checkInvalidKey": true, + "checkSiteMap": true, + "uploadWithSourceMap": true, + "compileHotReLoad": false, + "useMultiFrameRuntime": true, + "useApiHook": true, + "useApiHostProcess": false, + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + }, + "enableEngineNative": false, + "useIsolateContext": true, + "useCompilerModule": false, + "userConfirmedUseCompilerModuleSwitch": false, + "userConfirmedBundleSwitch": false, + "packNpmManually": false, + "packNpmRelationList": [], + "minifyWXSS": true, + "minifyWXML": true + }, + "compileType": "miniprogram", + "simulatorType": "wechat", + "simulatorPluginLibVersion": {}, + "condition": {} +} \ No newline at end of file diff --git a/project.private.config.json b/project.private.config.json index 2c19aa8..aaeb056 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -3,12 +3,12 @@ "projectname": "playBallTogether", "condition": {}, "setting": { - "urlCheck": true, + "urlCheck": false, "coverView": true, "lazyloadPlaceholderEnable": false, "skylineRenderEnable": false, "preloadBackgroundData": false, - "autoAudits": false, + "autoAudits": true, "useApiHook": true, "useApiHostProcess": true, "showShadowRootInWxmlPanel": false, diff --git a/src/app.config.ts b/src/app.config.ts index 5ae88f1..09a4ec6 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -54,6 +54,8 @@ export default defineAppConfig({ root: 'other_pages', pages: [ "message/index", + "comment_reply/index", // 收到的评论和回复 + "new_follow/index", // 新增关注 "favorites/index", // 收藏页 "ntrp-evaluate/index", // NTRP评估页 ], @@ -84,4 +86,5 @@ export default defineAppConfig({ provider: "wx76a9a06e5b4e693e", }, }, + "lazyCodeLoading": "requiredComponents" }); diff --git a/src/app.ts b/src/app.ts index 565dd5f..bf0017c 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,7 +1,7 @@ import { Component, ReactNode } from "react"; import "./nutui-theme.scss"; import "./app.scss"; -import "qweather-icons/font/qweather-icons.css"; +import "./scss/qweather-icons/qweather-icons.css"; import { useGlobalStore } from "./store/global"; interface AppProps { diff --git a/src/components/EmptyState/index.scss b/src/components/EmptyState/index.scss new file mode 100644 index 0000000..dd79951 --- /dev/null +++ b/src/components/EmptyState/index.scss @@ -0,0 +1,33 @@ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 124px 16px; + min-height: 400px; + + .empty-icon { + width: 221px; + height: 200px; + position: relative; + border-radius: 20px; + margin-bottom: 12px; + + .img { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 100%; + height: 100%; + } + } + + .empty-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 14px; + line-height: 1.71; + color: rgba(0, 0, 0, 0.35); + } +} diff --git a/src/components/EmptyState/index.tsx b/src/components/EmptyState/index.tsx new file mode 100644 index 0000000..f0d2f14 --- /dev/null +++ b/src/components/EmptyState/index.tsx @@ -0,0 +1,23 @@ +import { View, Text, Image } from "@tarojs/components"; +import "./index.scss"; + +interface EmptyStateProps { + text?: string; + icon?: any; // 图片资源 +} + +const EmptyState = ({ + text = "暂无数据", + icon = require("@/static/message/emi.svg") +}: EmptyStateProps) => { + return ( + + + + + {text} + + ); +}; + +export default EmptyState; diff --git a/src/components/index.ts b/src/components/index.ts index be082a9..49d9462 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -23,6 +23,7 @@ import FollowUserCard from './FollowUserCard/index'; import Comments from "./Comments"; import GeneralNavbar from "./GeneralNavbar"; import RadarChart from './Radar' +import EmptyState from './EmptyState'; export { ActivityTypeSwitch, @@ -51,4 +52,5 @@ export { Comments, GeneralNavbar, RadarChart, + EmptyState, }; diff --git a/src/config/env.ts b/src/config/env.ts index 00d5ebd..4587a0e 100644 --- a/src/config/env.ts +++ b/src/config/env.ts @@ -24,8 +24,8 @@ const envConfigs: Record = { // 开发环境 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, diff --git a/src/other_pages/comment_reply/index.config.ts b/src/other_pages/comment_reply/index.config.ts new file mode 100644 index 0000000..82a32e0 --- /dev/null +++ b/src/other_pages/comment_reply/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationStyle: "custom", + navigationBarTitleText: "收到的评论和回复", +}); diff --git a/src/other_pages/comment_reply/index.scss b/src/other_pages/comment_reply/index.scss new file mode 100644 index 0000000..92755ea --- /dev/null +++ b/src/other_pages/comment_reply/index.scss @@ -0,0 +1,228 @@ +@use '~@/scss/images.scss' as img; + +.comment-reply-container { + width: 100%; + height: 100vh; + box-sizing: border-box; + display: flex; + flex-direction: column; + background: #FFFFFF; + + // 顶部导航栏 + .navbar { + height: 100px; + background: #FFFFFF; + position: sticky; + top: 0; + z-index: 100; + + .navbar-content { + height: 56px; + display: flex; + align-items: center; + justify-content: center; + padding: 0 15px; + margin-top: 44px; + position: relative; + + .back-button { + position: absolute; + left: 10px; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + + .back-icon { + width: 8px; + height: 16px; + position: relative; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 8px; + height: 8px; + border-left: 2.67px solid #000000; + border-bottom: 2.67px solid #000000; + transform: rotate(45deg); + } + } + } + + .navbar-title { + font-family: 'PingFang SC'; + font-weight: 600; + font-size: 20px; + line-height: 1.4; + letter-spacing: 0.019em; + color: #000000; + } + } + } + + // 评论列表滚动区域 + .comment-scroll { + flex: 1; + height: 100%; + padding: 0 15px; + } + + // 评论列表 + .comment-list { + padding-bottom: 20px; + } + + // 评论项 + .comment-item { + display: flex; + justify-content: space-between; + gap: 12px; + padding: 16px 0; + border-bottom: 0.5px solid rgba(0, 0, 0, 0.08); + + .comment-left { + display: flex; + gap: 12px; + flex: 1; + min-width: 0; + + .user-avatar { + width: 48px; + height: 48px; + border-radius: 999px; + flex-shrink: 0; + } + + .comment-content { + display: flex; + flex-direction: column; + gap: 4px; + flex: 1; + min-width: 0; + + .user-nickname { + font-family: 'PingFang SC'; + font-weight: 600; + font-size: 14px; + line-height: 1.43; + color: #000000; + } + + .action-row { + display: flex; + align-items: center; + gap: 8px; + + .action-text, + .time-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 10px; + line-height: 1.6; + color: rgba(60, 60, 67, 0.6); + } + } + + .comment-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 12px; + line-height: 1.5; + color: #000000; + word-break: break-word; + } + + // 被回复的评论 + .original-comment { + display: flex; + align-items: flex-start; + gap: 4px; + margin-top: 4px; + + .quote-line { + width: 2px; + height: 14px; + background: rgba(120, 120, 128, 0.12); + border-radius: 7px; + flex-shrink: 0; + } + + .original-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 12px; + line-height: 1.5; + color: rgba(60, 60, 67, 0.6); + word-break: break-word; + flex: 1; + } + } + + // 回复按钮 + .reply-button { + display: flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + background: rgba(120, 120, 128, 0.12); + border-radius: 20px; + width: fit-content; + margin-top: 4px; + cursor: pointer; + + &:active { + opacity: 0.8; + } + + .reply-icon { + width: 12px; + height: 12px; + } + + .reply-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 10px; + line-height: 1.6; + color: #000000; + } + } + } + } + + // 右侧球局图片 + .activity-image { + width: 48px; + height: 48px; + border-radius: 9px; + background: #F5F5F5; + flex-shrink: 0; + cursor: pointer; + + &:active { + opacity: 0.8; + } + } + } + + // 到底了提示 + .bottom-tip { + display: flex; + justify-content: center; + align-items: center; + padding: 24px 0 12px; + + .tip-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 14px; + line-height: 1.71; + color: rgba(0, 0, 0, 0.35); + } + } +} diff --git a/src/other_pages/comment_reply/index.tsx b/src/other_pages/comment_reply/index.tsx new file mode 100644 index 0000000..8e94dd3 --- /dev/null +++ b/src/other_pages/comment_reply/index.tsx @@ -0,0 +1,244 @@ +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 commentService, { CommentActivity } from "@/services/commentService"; +import Taro from "@tarojs/taro"; +import "./index.scss"; + +// 评论/回复类型定义 +interface CommentReplyItem { + id: number; + user_avatar: string; + user_nickname: string; + action_type: "comment" | "reply"; // 评论了你的球局 / 回复了你的评论 + time: string; + content: string; + original_comment?: string; // 被回复的评论内容 + activity_image: string; + activity_id: number; + activity_title: string; +} + +const CommentReply = () => { + const [commentList, setCommentList] = useState([]); + const [loading, setLoading] = useState(false); + const [refreshing, setRefreshing] = useState(false); + + useEffect(() => { + getCommentReplyList(); + }, []); + + // 获取评论和回复列表 + const getCommentReplyList = async () => { + if (loading) return; + + setLoading(true); + try { + const res = await commentService.getMyActivities({ + page: 1, + pageSize: 20, + }); + + if (res.code === 0 && res.data) { + // 映射数据 + const mappedList = res.data.rows.map((item: CommentActivity) => ({ + id: item.id, + 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.parent_comment?.content || "", + activity_image: item.game?.image_list?.[0] || "", + activity_id: item.game_id, + activity_title: item.game?.title || "", + })); + + setCommentList(mappedList); + } + } catch (e) { + Taro.showToast({ + title: "获取列表失败", + icon: "none", + duration: 2000, + }); + } finally { + setLoading(false); + } + }; + + // 格式化时间显示 + const formatTime = (timeStr: string) => { + if (!timeStr) return ""; + + const date = new Date(timeStr); + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const minutes = Math.floor(diff / (1000 * 60)); + const hours = Math.floor(diff / (1000 * 60 * 60)); + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + + if (minutes < 60) { + return `${minutes}分钟前`; + } else if (hours < 24) { + return `${hours}小时前`; + } else if (days === 1) { + return "1天前"; + } else if (days < 7) { + return `${days}天前`; + } else { + const month = date.getMonth() + 1; + const day = date.getDate(); + return `${month}月${day}日`; + } + }; + + // 处理回复 + const handleReply = (item: CommentReplyItem) => { + console.log("回复:", item); + // TODO: 跳转到回复页面或弹出回复框 + }; + + // 处理点击球局 + const handleGameClick = (gameId: number) => { + Taro.navigateTo({ + url: `/game_pages/detail/index?id=${gameId}`, + }); + }; + + // 处理返回 + const handleBack = () => { + Taro.navigateBack(); + }; + + // 处理下拉刷新 + const handleRefresh = async () => { + setRefreshing(true); + try { + const res = await commentService.getMyActivities({ + page: 1, + pageSize: 20, + }); + + if (res.code === 0 && res.data) { + const mappedList = res.data.rows.map((item: CommentActivity) => ({ + id: item.id, + 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.parent_comment?.content || "", + activity_image: item.game?.image_list?.[0] || "", + activity_id: item.game_id, + activity_title: item.game?.title || "", + })); + + setCommentList(mappedList); + } + } catch (e) { + Taro.showToast({ + title: "刷新失败", + icon: "none", + duration: 2000, + }); + } finally { + setRefreshing(false); + } + }; + + // 渲染评论/回复项 + const renderCommentItem = (item: CommentReplyItem) => { + const actionText = item.action_type === "comment" ? "评论了你的球局" : "回复了你的评论"; + + return ( + + + + + + {item.user_nickname} + + + {actionText} + {formatTime(item.time)} + + + {item.content} + + {/* 如果是回复,显示被回复的评论 */} + {item.action_type === "reply" && item.original_comment && ( + + + {item.original_comment} + + )} + + {/* 回复按钮 */} + handleReply(item)}> + + 回复 + + + + + {/* 右侧球局图片 */} + handleGameClick(item.activity_id)} + /> + + ); + }; + + return ( + + {/* 顶部导航栏 */} + + + + + + 收到的评论和回复 + + + + {/* 评论列表 */} + + {commentList.length > 0 ? ( + + {commentList.map(renderCommentItem)} + + {/* 到底了提示 */} + + 到底了 + + + ) : ( + + )} + + + ); +}; + +export default withAuth(CommentReply); diff --git a/src/other_pages/message/index.scss b/src/other_pages/message/index.scss index d2730dc..b644b3d 100644 --- a/src/other_pages/message/index.scss +++ b/src/other_pages/message/index.scss @@ -6,23 +6,22 @@ box-sizing: border-box; display: flex; flex-direction: column; + background: #FFFFFF; - // 导航栏 + // 顶部导航栏 .navbar { - height: 56px; + height: 100px; background: #FFFFFF; - padding-top: 44px; position: sticky; top: 0; z-index: 100; - box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.06); .navbar-content { height: 56px; display: flex; align-items: center; - justify-content: space-between; padding: 0 15px; + margin-top: 44px; .navbar-left { display: flex; @@ -39,52 +38,109 @@ font-weight: 600; font-size: 20px; line-height: 1.4; + letter-spacing: 0.019em; color: #000000; } } } } + // 分类标签区 + .category-tabs { + display: flex; + align-items: stretch; + gap: 20px; + padding: 6px 24px; + background: #FFFFFF; - // 消息列表 - .message-list { - flex: 1; - overflow: hidden; - box-sizing: border-box; - // margin-bottom:100px; - background-color: none !important; - - .message-list-content { + .tab-item { display: flex; flex-direction: column; - padding: 12px 12px 112px; + justify-content: center; + align-items: center; gap: 8px; + padding: 12px 15px; + flex: 1; + cursor: pointer; + transition: all 0.2s; + + .tab-icon { + width: 56px; + height: 56px; + border-radius: 56px; + transition: all 0.3s; + } + + .tab-text { + font-family: 'PingFang SC'; + font-weight: 600; + font-size: 16px; + line-height: 1.5; + color: #000000; + } + + &.active { + .tab-icon { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); + transform: scale(1.05); + } + } + + &:active { + .tab-icon { + transform: scale(0.95); + } + } + } + } + + // 消息滚动区域 + .message-scroll { + flex: 1; + overflow: hidden; + background: #FFFFFF; + + .message-cards { + padding: 12px; + display: flex; + flex-direction: column; + gap: 8px; + padding-bottom: 120px; } - // 系统消息样式 - .system-message { + // 系统消息卡片 + .message-card { background: #FFFFFF; border: 0.5px solid rgba(0, 0, 0, 0.08); border-radius: 20px; - padding: 0 0 12px; box-shadow: 0px 4px 36px 0px rgba(0, 0, 0, 0.06); - box-sizing: border-box; + padding: 0 0 12px; + transition: all 0.2s; - .message-header { - display: flex; - align-items: center; + &:active { + transform: scale(0.98); + opacity: 0.95; + } + + .card-title-row { padding: 12px 15px 0; - .message-title { + .card-title { font-family: 'PingFang SC'; font-weight: 600; font-size: 16px; line-height: 1.5; color: #000000; - flex: 1; } + } - .message-time { + .card-time-row { + padding: 4px 15px 0; + display: flex; + align-items: center; + gap: 2px; + + .card-time { font-family: 'PingFang SC'; font-weight: 400; font-size: 12px; @@ -93,31 +149,37 @@ } } - .message-content { + .card-content-row { padding: 8px 15px 0; + display: flex; + align-items: stretch; + gap: 2px; - .message-text { + .card-content { font-family: 'PingFang SC'; font-weight: 400; font-size: 14px; line-height: 1.43; color: rgba(0, 0, 0, 0.7); + flex: 1; } } - .message-action { + .card-footer { padding: 12px 15px 0; - .action-divider { + .footer-divider { height: 0.5px; background: rgba(0, 0, 0, 0.08); margin-bottom: 12px; + width: 100%; } - .action-button { + .footer-action { display: flex; justify-content: space-between; align-items: center; + cursor: pointer; .action-text { font-family: 'PingFang SC'; @@ -128,151 +190,94 @@ } .action-arrow { - width: 16px; - height: 16px; + position: relative; + .img { + position: absolute; + left: -16px; + top: -9px; + width: 14px;; + height: 14px; + } + } + + &:active { + opacity: 0.7; } } } } - // 用户消息样式 - .user-message { + // 到底了提示 + .bottom-tip { display: flex; + justify-content: center; align-items: center; - gap: 12px; - padding: 12px 15px; - background: #FFFFFF; - border: 0.5px solid rgba(0, 0, 0, 0.08); - border-radius: 20px; - box-shadow: 0px 4px 36px 0px rgba(0, 0, 0, 0.06); - box-sizing: border-box; + padding: 24px 0 12px; - .message-avatar { - position: relative; - flex-shrink: 0; - - .unread-dot { - position: absolute; - top: -2px; - right: -2px; - width: 10px; - height: 10px; - background: #FF4848; - border-radius: 50%; - } - } - - .message-info { - flex: 1; - min-width: 0; - - .message-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 4px; - - .message-title { - font-family: 'PingFang SC'; - font-weight: 600; - font-size: 16px; - line-height: 1.5; - color: #000000; - } - - .message-time { - font-family: 'PingFang SC'; - font-weight: 400; - font-size: 14px; - line-height: 1.71; - color: rgba(0, 0, 0, 0.35); - } - } - - .message-content { - display: flex; - align-items: center; - gap: 4px; - min-width: 0; - - .message-text { - font-family: 'PingFang SC'; - font-weight: 400; - font-size: 14px; - line-height: 1.29; - color: rgba(0, 0, 0, 0.35); - flex: 1; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .unread-indicator { - width: 10px; - height: 10px; - background: #FF4848; - border-radius: 50%; - flex-shrink: 0; - } - } + .tip-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 14px; + line-height: 1.71; + color: rgba(0, 0, 0, 0.35); } } } - // 空状态 - .empty-state { + // 悬浮新建消息按钮 + .floating-button { + position: fixed; + right: 12px; + bottom: 132px; + width: 60px; + height: 60px; + border-radius: 50%; + background: radial-gradient(circle at 27% 8%, rgba(189, 255, 74, 1) 17%, rgba(149, 242, 62, 1) 54%, rgba(50, 216, 56, 1) 100%); + border: 2px solid rgba(0, 0, 0, 0.06); + box-shadow: 0px 4px 48px 0px rgba(0, 0, 0, 0.08); display: flex; - flex-direction: column; align-items: center; - padding: 124px 16px; - height: 746px; + justify-content: center; + cursor: pointer; + z-index: 99; + transition: all 0.2s; - .empty-icon { - width: 300px; - height: 225px; - margin-bottom: 12px; - position: relative; - - .empty-message-icon { - width: 100%; - height: 100%; - background: linear-gradient(135deg, #f0f0f0 0%, #e0e0e0 100%); - border-radius: 12px; - position: relative; - - &::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 60px; - height: 60px; - background: #d0d0d0; - border-radius: 50%; - } - - &::after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 30px; - height: 30px; - background: #a0a0a0; - border-radius: 50%; - } - } + &:active { + transform: scale(0.92); } - .empty-text { - font-family: 'PingFang SC'; - font-weight: 500; - font-size: 14px; - line-height: 1.71; - color: rgba(0, 0, 0, 0.85); + .button-icon { + width: 36px; + height: 36px; + position: relative; + + // 加号图标 - 竖线 + &::before { + content: ''; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 4px; + height: 25px; + background: #FFFFFF; + border-radius: 2px; + box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.2); + } + + // 加号图标 - 横线 + &::after { + content: ''; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 25px; + height: 4px; + background: #FFFFFF; + border-radius: 2px; + box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.2); + } } } } \ No newline at end of file diff --git a/src/other_pages/message/index.tsx b/src/other_pages/message/index.tsx index e4a6653..342b4c3 100644 --- a/src/other_pages/message/index.tsx +++ b/src/other_pages/message/index.tsx @@ -1,136 +1,249 @@ import { useState, useEffect } from "react"; -import { View, Text, ScrollView, Image } from "@tarojs/components"; +import { View, Text, Image, ScrollView } from "@tarojs/components"; import { Avatar } from "@nutui/nutui-react-taro"; import GuideBar from "@/components/GuideBar"; -import { withAuth } from "@/components"; +import { withAuth, EmptyState } from "@/components"; import noticeService from "@/services/noticeService"; -import Taro, { useRouter } from "@tarojs/taro"; +import { useUserInfo } from "@/store/userStore"; +import Taro from "@tarojs/taro"; import "./index.scss"; // 消息类型定义 interface MessageItem { id: string; - type: "system" | "user" | "like" | "comment" | "follow"; + notification_type: string; title: string; content: string; - time: string; - avatar?: string; - isRead: boolean; - hasAction?: boolean; - actionText?: string; + create_time: string; + is_read: number; + related_user_avatar?: string; + related_user_nickname?: string; + activity_image?: string; } +// 消息分类类型 +type MessageCategory = "comment" | "follow"; + const Message = () => { - const [activeTab] = useState<"all" | "like" | "comment" | "follow">("all"); + const userInfo = useUserInfo() as any; + const [activeTab, setActiveTab] = useState(null); const [messageList, setMessageList] = useState([]); + const [loading, setLoading] = useState(false); + const [reachedBottom, setReachedBottom] = useState(false); + const [refreshing, setRefreshing] = useState(false); + + // 获取消息列表 + const getNoticeList = async () => { + if (loading) return; + setLoading(true); + try { + const res = await noticeService.getNotificationList({}); + if (res.code === 0) { + setMessageList(res.data.list || []); + } + } catch (e) { + Taro.showToast({ + title: "获取列表失败,请重试", + icon: "none", + duration: 2000, + }); + } finally { + setLoading(false); + } + }; useEffect(() => { - const getNoticeList = async () => { - try { - const res = await noticeService.getNotificationList({}); - if (res.code === 0) { - setMessageList(res.data.list); - } - } catch (e) { - Taro.showToast({ - title: "获取列表失败,请重试", - icon: "none", - duration: 2000, - }); - } finally { - } - }; getNoticeList(); }, []); - // 过滤消息 - const filteredMessages = messageList.filter((message) => { - if (activeTab === "all") return true; - return message.type === activeTab; - }); + // 过滤系统消息 + const filteredMessages = messageList; - // 渲染消息项 - const renderMessageItem = (message: MessageItem) => { - if (message.type === "system") { - return ( - - - {message.title} - {message.time} - - - {message.content} - - {message.hasAction && ( - - - - {message.actionText} - - - - )} - - ); + // 处理分类标签点击 + const handleTabClick = (tab: MessageCategory) => { + // 点击评论标签跳转到评论和回复页面 + if (tab === "comment") { + Taro.navigateTo({ + url: "/other_pages/comment_reply/index", + }); + return; } + + // 点击关注标签跳转到新增关注页面 + if (tab === "follow") { + Taro.navigateTo({ + url: "/other_pages/new_follow/index", + }); + return; + } + + setActiveTab(activeTab === tab ? null : tab); + }; - return ( - - - - - - - {message.title} - {message.time} - - - {message.content} - {!message.isRead && } - - - - ); + // 处理查看详情 + const handleViewDetail = (messageId: string) => { + console.log("查看详情:", messageId); + // TODO: 根据消息类型跳转到对应详情页 + }; + + // 处理滚动到底部 + const handleScrollToLower = () => { + if (!reachedBottom && filteredMessages.length > 0) { + setReachedBottom(true); + // 2秒后隐藏提示 + setTimeout(() => { + setReachedBottom(false); + }, 2000); + } + }; + + // 处理下拉刷新 + const handleRefresh = async () => { + setRefreshing(true); + try { + const res = await noticeService.getNotificationList({}); + if (res.code === 0) { + setMessageList(res.data.list || []); + } + } catch (e) { + Taro.showToast({ + title: "刷新失败", + icon: "none", + duration: 2000, + }); + } finally { + setRefreshing(false); + } + }; + + // 格式化时间显示 + const formatTime = (timeStr: string) => { + if (!timeStr) return ""; + const date = new Date(timeStr); + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + + if (days === 0) { + const hours = date.getHours(); + const minutes = date.getMinutes(); + return `今天 ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; + } else if (days === 1) { + const hours = date.getHours(); + const minutes = date.getMinutes(); + return `昨天 ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; + } else if (days < 3) { + return `${days}天前`; + } else { + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const day = date.getDate(); + const hours = date.getHours(); + const minutes = date.getMinutes(); + return `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')} ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; + } }; return ( - {/* 导航栏 */} + {/* 顶部导航栏 */} 消息 - {/* 消息列表 */} - + {/* 分类标签 */} + + handleTabClick("comment")} + > + + 评论和回复 + + handleTabClick("follow")} + > + + 新增关注 + + + + {/* 系统消息卡片列表 */} + {filteredMessages.length > 0 ? ( - - {filteredMessages.map(renderMessageItem)} + + {filteredMessages.map((message) => ( + + + {message.title} + + + {formatTime(message.create_time)} + + + {message.content} + + + + handleViewDetail(message.id)}> + 查看详情 + + + + + + + + + ))} + {/* 到底了提示 */} + {filteredMessages.length > 0 && ( + + 到底了 + + )} ) : ( - - - - - 暂无消息 - + )} + {/* 悬浮新建按钮 */} + console.log("新建消息")}> + + + {/* 底部导航 */} ); }; -export default withAuth(Message); +export default withAuth(Message); \ No newline at end of file diff --git a/src/other_pages/new_follow/index.config.ts b/src/other_pages/new_follow/index.config.ts new file mode 100644 index 0000000..4626cb8 --- /dev/null +++ b/src/other_pages/new_follow/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationStyle: "custom", + navigationBarTitleText: "新增关注", +}); diff --git a/src/other_pages/new_follow/index.scss b/src/other_pages/new_follow/index.scss new file mode 100644 index 0000000..5e8dc98 --- /dev/null +++ b/src/other_pages/new_follow/index.scss @@ -0,0 +1,199 @@ +@use '~@/scss/images.scss' as img; + +.new-follow-container { + width: 100%; + height: 100vh; + box-sizing: border-box; + display: flex; + flex-direction: column; + background: #FFFFFF; + + // 顶部导航栏 + .navbar { + height: 100px; + background: #FFFFFF; + position: sticky; + top: 0; + z-index: 100; + + .navbar-content { + height: 56px; + display: flex; + align-items: center; + justify-content: center; + padding: 0 15px; + margin-top: 44px; + position: relative; + + .back-button { + position: absolute; + left: 10px; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + + .back-icon { + width: 8px; + height: 16px; + position: relative; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 8px; + height: 8px; + border-left: 2.67px solid #000000; + border-bottom: 2.67px solid #000000; + transform: rotate(45deg); + } + } + } + + .navbar-title { + font-family: 'PingFang SC'; + font-weight: 600; + font-size: 20px; + line-height: 1.4; + letter-spacing: 0.019em; + color: #000000; + } + } + } + + // 关注列表滚动区域 + .follow-scroll { + flex: 1; + height: 100%; + } + + // 关注列表 + .follow-list { + display: flex; + flex-direction: column; + gap: 12px; + padding: 0 0 20px; + } + + // 关注项 + .follow-item { + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; + padding: 8px 20px; + + .follow-left { + display: flex; + align-items: center; + gap: 12px; + flex: 1; + min-width: 0; + cursor: pointer; + + .user-avatar { + width: 40px; + height: 40px; + border-radius: 999px; + flex-shrink: 0; + } + + .user-info { + display: flex; + flex-direction: column; + gap: 8px; + flex: 1; + min-width: 0; + height: 40px; + justify-content: center; + + .user-nickname { + font-family: 'PingFang SC'; + font-weight: 600; + font-size: 14px; + line-height: 1.14; + color: rgba(0, 0, 0, 0.8); + } + + .user-signature { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 12px; + line-height: 1.33; + color: rgba(60, 60, 67, 0.6); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .action-row { + display: flex; + align-items: center; + gap: 8px; + + .action-text, + .time-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 12px; + line-height: 1.33; + color: rgba(60, 60, 67, 0.6); + } + } + } + } + + // 回关按钮 + .follow-button { + display: flex; + justify-content: center; + align-items: center; + padding: 4px 16px; + border: 0.5px solid #000000; + border-radius: 20px; + cursor: pointer; + flex-shrink: 0; + + &:active { + opacity: 0.8; + } + + &.mutual { + border-color: rgba(120, 120, 128, 0.12); + background: transparent; + } + + .button-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 12px; + line-height: 1.33; + color: #000000; + } + + &.mutual .button-text { + color: rgba(0, 0, 0, 0.8); + } + } + } + + // 到底了提示 + .bottom-tip { + display: flex; + justify-content: center; + align-items: center; + padding: 24px 0 12px; + + .tip-text { + font-family: 'PingFang SC'; + font-weight: 400; + font-size: 14px; + line-height: 1.71; + color: rgba(0, 0, 0, 0.35); + } + } +} diff --git a/src/other_pages/new_follow/index.tsx b/src/other_pages/new_follow/index.tsx new file mode 100644 index 0000000..c7d722c --- /dev/null +++ b/src/other_pages/new_follow/index.tsx @@ -0,0 +1,261 @@ +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 FollowService from "@/services/followService"; +import Taro from "@tarojs/taro"; +import "./index.scss"; + +// 关注项类型定义 +interface FollowItem { + id: number; + user_id: number; + user_avatar: string; + user_nickname: string; + user_signature?: string; + city?: string; + ntrp_level?: string; + time: string; + is_mutual: boolean; // 是否互相关注 +} + +const NewFollow = () => { + const [followList, setFollowList] = useState([]); + const [loading, setLoading] = useState(false); + const [refreshing, setRefreshing] = useState(false); + + useEffect(() => { + getFollowList(); + }, []); + + // 获取新增关注列表 + const getFollowList = async () => { + if (loading) return; + + setLoading(true); + try { + const res = await FollowService.get_new_fans_list(1, 20); + + if (res.list) { + // 映射数据 + const mappedList = res.list.map((item: any) => ({ + id: item.id, + 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); + } + } catch (e) { + Taro.showToast({ + title: "获取列表失败", + icon: "none", + duration: 2000, + }); + } finally { + setLoading(false); + } + }; + + // 格式化时间显示 + const formatTime = (timeStr: string) => { + if (!timeStr) return ""; + + const date = new Date(timeStr); + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const minutes = Math.floor(diff / (1000 * 60)); + const hours = Math.floor(diff / (1000 * 60 * 60)); + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + + if (minutes < 1) { + return "刚刚"; + } else if (minutes < 60) { + return `${minutes}分钟前`; + } else if (hours < 24) { + return `${hours}小时前`; + } else if (days === 1) { + return "1天前"; + } else if (days < 7) { + return `${days}天前`; + } else { + const month = date.getMonth() + 1; + const day = date.getDate(); + return `${month}月${day}日`; + } + }; + + // 处理回关/取消关注 + const handleFollowBack = async (item: FollowItem) => { + try { + if (item.is_mutual) { + // 已经互相关注,点击取消关注 + await FollowService.unfollow_user(item.user_id); + + Taro.showToast({ + title: "取消关注成功", + icon: "success", + duration: 2000, + }); + + // 更新列表 + setFollowList(prevList => + prevList.map(followItem => + followItem.id === item.id + ? { ...followItem, is_mutual: false } + : followItem + ) + ); + } else { + // 未互关,点击回关 + await FollowService.follow_back(item.user_id); + + Taro.showToast({ + title: "关注成功", + icon: "success", + duration: 2000, + }); + + // 更新列表 + setFollowList(prevList => + prevList.map(followItem => + followItem.id === item.id + ? { ...followItem, is_mutual: true } + : followItem + ) + ); + } + } catch (e) { + Taro.showToast({ + title: item.is_mutual ? "取消关注失败" : "关注失败", + icon: "none", + duration: 2000, + }); + } + }; + + // 处理返回 + const handleBack = () => { + Taro.navigateBack(); + }; + + // 处理点击用户 + const handleUserClick = (userId: number) => { + Taro.navigateTo({ + url: `/user_pages/other/index?user_id=${userId}`, + }); + }; + + // 处理下拉刷新 + const handleRefresh = async () => { + setRefreshing(true); + try { + const res = await FollowService.get_new_fans_list(1, 20); + + if (res.list) { + const mappedList = res.list.map((item: any) => ({ + id: item.id, + 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); + } + } catch (e) { + Taro.showToast({ + title: "刷新失败", + icon: "none", + duration: 2000, + }); + } finally { + setRefreshing(false); + } + }; + + // 渲染关注项 + const renderFollowItem = (item: FollowItem) => { + return ( + + handleUserClick(item.user_id)}> + + + + {item.user_nickname} + + {item.user_signature ? ( + {item.user_signature} + ) : ( + + {formatTime(item.time)}关注了你 + + )} + + + + handleFollowBack(item)} + > + {item.is_mutual ? "互相关注" : "回关"} + + + ); + }; + + return ( + + {/* 顶部导航栏 */} + + + + + + 新增关注 + + + + {/* 关注列表 */} + + {followList.length > 0 ? ( + + {followList.map(renderFollowItem)} + + {/* 到底了提示 */} + + 到底了 + + + ) : ( + + )} + + + ); +}; + +export default withAuth(NewFollow); diff --git a/src/scss/qweather-icons/fonts/qweather-icons.ttf b/src/scss/qweather-icons/fonts/qweather-icons.ttf new file mode 100644 index 0000000..2a47642 Binary files /dev/null and b/src/scss/qweather-icons/fonts/qweather-icons.ttf differ diff --git a/src/scss/qweather-icons/fonts/qweather-icons.woff2 b/src/scss/qweather-icons/fonts/qweather-icons.woff2 new file mode 100644 index 0000000..e1f8f48 Binary files /dev/null and b/src/scss/qweather-icons/fonts/qweather-icons.woff2 differ diff --git a/src/scss/qweather-icons/qweather-icons.css b/src/scss/qweather-icons/qweather-icons.css new file mode 100644 index 0000000..6dc64d9 --- /dev/null +++ b/src/scss/qweather-icons/qweather-icons.css @@ -0,0 +1,92 @@ + + +@font-face { + font-family: "qweather-icons"; + src: url("./fonts/qweather-icons.woff2?3696017a726a77099c2617f87a3367ac") format("woff2") + +} + +[class^="qi-"]::before, +[class*=" qi-"]::before { + display: inline-block; + font-family: "qweather-icons" !important; + font-style: normal; + font-weight: normal !important; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: -.125em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.qi-100::before { content: "\f101"; } +.qi-101::before { content: "\f102"; } +.qi-102::before { content: "\f103"; } +.qi-103::before { content: "\f104"; } +.qi-104::before { content: "\f105"; } +.qi-150::before { content: "\f106"; } +.qi-151::before { content: "\f107"; } +.qi-152::before { content: "\f108"; } +.qi-153::before { content: "\f109"; } +.qi-300::before { content: "\f10a"; } +.qi-301::before { content: "\f10b"; } +.qi-302::before { content: "\f10c"; } +.qi-303::before { content: "\f10d"; } +.qi-304::before { content: "\f10e"; } +.qi-305::before { content: "\f10f"; } +.qi-306::before { content: "\f110"; } +.qi-307::before { content: "\f111"; } +.qi-308::before { content: "\f112"; } +.qi-309::before { content: "\f113"; } +.qi-310::before { content: "\f114"; } +.qi-311::before { content: "\f115"; } +.qi-312::before { content: "\f116"; } +.qi-313::before { content: "\f117"; } +.qi-314::before { content: "\f118"; } +.qi-315::before { content: "\f119"; } +.qi-316::before { content: "\f11a"; } +.qi-317::before { content: "\f11b"; } +.qi-318::before { content: "\f11c"; } +.qi-350::before { content: "\f11d"; } +.qi-351::before { content: "\f11e"; } +.qi-399::before { content: "\f11f"; } +.qi-400::before { content: "\f120"; } +.qi-401::before { content: "\f121"; } +.qi-402::before { content: "\f122"; } +.qi-403::before { content: "\f123"; } +.qi-404::before { content: "\f124"; } +.qi-405::before { content: "\f125"; } +.qi-406::before { content: "\f126"; } +.qi-407::before { content: "\f127"; } +.qi-408::before { content: "\f128"; } +.qi-409::before { content: "\f129"; } +.qi-410::before { content: "\f12a"; } +.qi-456::before { content: "\f12b"; } +.qi-457::before { content: "\f12c"; } +.qi-499::before { content: "\f12d"; } +.qi-500::before { content: "\f12e"; } +.qi-501::before { content: "\f12f"; } +.qi-502::before { content: "\f130"; } +.qi-503::before { content: "\f131"; } +.qi-504::before { content: "\f132"; } +.qi-507::before { content: "\f133"; } +.qi-508::before { content: "\f134"; } +.qi-509::before { content: "\f135"; } +.qi-510::before { content: "\f136"; } +.qi-511::before { content: "\f137"; } +.qi-512::before { content: "\f138"; } +.qi-513::before { content: "\f139"; } +.qi-514::before { content: "\f13a"; } +.qi-515::before { content: "\f13b"; } +.qi-800::before { content: "\f13c"; } +.qi-801::before { content: "\f13d"; } +.qi-802::before { content: "\f13e"; } +.qi-803::before { content: "\f13f"; } +.qi-804::before { content: "\f140"; } +.qi-805::before { content: "\f141"; } +.qi-806::before { content: "\f142"; } +.qi-807::before { content: "\f143"; } +.qi-900::before { content: "\f144"; } +.qi-901::before { content: "\f145"; } +.qi-999::before { content: "\f146"; } diff --git a/src/services/commentService.ts b/src/services/commentService.ts new file mode 100644 index 0000000..88913c6 --- /dev/null +++ b/src/services/commentService.ts @@ -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> { + const { page = 1, pageSize = 10 } = params; + return httpService.post("/comments/my_activities", { page, pageSize }, { showLoading: false }); + } + + // 发表评论 + async createComment(game_id: number, content: string): Promise> { + return httpService.post("/comments/create", { game_id, content }); + } + + // 回复评论 + async replyComment(parent_id: number, reply_to_user_id: number, content: string): Promise> { + return httpService.post("/comments/reply", { parent_id, reply_to_user_id, content }); + } + + // 获取评论列表 + async getCommentList(game_id: number, page: number = 1, pageSize: number = 10): Promise> { + return httpService.post("/comments/list", { game_id, page, pageSize }); + } + + // 点赞/取消点赞评论 + async likeComment(comment_id: number): Promise> { + return httpService.post("/comments/like", { comment_id }); + } + + // 删除评论 + async deleteComment(comment_id: number): Promise> { + return httpService.post("/comments/delete", { comment_id }); + } + + // 获取评论的所有回复 + async getCommentReplies(comment_id: number, page: number = 1, pageSize: number = 10): Promise> { + return httpService.post("/comments/replies", { comment_id, page, pageSize }); + } +} + +export default new CommentService(); diff --git a/src/services/followService.ts b/src/services/followService.ts index acf6e3f..0589ee1 100644 --- a/src/services/followService.ts +++ b/src/services/followService.ts @@ -84,6 +84,34 @@ export class FollowService { } } + // 获取新增粉丝列表(新关注的人) + static async get_new_fans_list( + page: number = 1, + page_size: number = 20 + ): Promise { + try { + const response = await httpService.post( + '/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, diff --git a/src/static/message/ar-right.svg b/src/static/message/ar-right.svg new file mode 100644 index 0000000..412901b --- /dev/null +++ b/src/static/message/ar-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/static/message/comment-icon.svg b/src/static/message/comment-icon.svg new file mode 100644 index 0000000..69a4659 --- /dev/null +++ b/src/static/message/comment-icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/static/message/emi.svg b/src/static/message/emi.svg new file mode 100644 index 0000000..6a526d1 --- /dev/null +++ b/src/static/message/emi.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/static/message/follow-icon.svg b/src/static/message/follow-icon.svg new file mode 100644 index 0000000..b6fffff --- /dev/null +++ b/src/static/message/follow-icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/static/message/reply-icon.svg b/src/static/message/reply-icon.svg new file mode 100644 index 0000000..0d560d2 --- /dev/null +++ b/src/static/message/reply-icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/yarn.lock b/yarn.lock index ee50824..7718bc9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -720,6 +720,18 @@ babel-plugin-polyfill-regenerator "^0.6.5" semver "^6.3.1" +"@babel/plugin-transform-runtime@^7.28.3": + version "7.28.3" + resolved "https://registry.npmmirror.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.3.tgz#f5990a1b2d2bde950ed493915e0719841c8d0eaa" + integrity sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + babel-plugin-polyfill-corejs2 "^0.4.14" + babel-plugin-polyfill-corejs3 "^0.13.0" + babel-plugin-polyfill-regenerator "^0.6.5" + semver "^6.3.1" + "@babel/plugin-transform-shorthand-properties@^7.27.1": version "7.27.1" resolved "https://registry.npmmirror.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz#532abdacdec87bfee1e0ef8e2fcdee543fe32b90" @@ -3203,6 +3215,11 @@ babel-plugin-transform-imports-api@1.0.0: dependencies: is-invalid-path "^1.0.2" +babel-plugin-transform-remove-console@^6.9.4: + version "6.9.4" + resolved "https://registry.npmmirror.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780" + integrity sha512-88blrUrMX3SPiGkT1GnvVY8E/7A+k6oj3MNvUtTIxJflFzXTw1bHkuJ/y039ouhFMp2prRn5cQGzokViYi1dsg== + babel-plugin-transform-solid-jsx@4.1.5: version "4.1.5" resolved "https://registry.npmmirror.com/babel-plugin-transform-solid-jsx/-/babel-plugin-transform-solid-jsx-4.1.5.tgz#203d07a15f32e65e09f266b6ad2080f346eb453a"