代码优化
This commit is contained in:
@@ -94,6 +94,20 @@ export async function exportWechatMoments(params: {
|
||||
}
|
||||
);
|
||||
|
||||
// 检查响应类型,如果是JSON错误响应,需要解析错误信息
|
||||
const contentType = response.headers["content-type"] || "";
|
||||
if (contentType.includes("application/json")) {
|
||||
// 如果是JSON响应,说明可能是错误信息
|
||||
const text = await response.data.text();
|
||||
const errorData = JSON.parse(text);
|
||||
throw new Error(errorData.message || errorData.msg || "导出失败");
|
||||
}
|
||||
|
||||
// 检查响应状态
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`导出失败,状态码: ${response.status}`);
|
||||
}
|
||||
|
||||
// 创建下载链接
|
||||
const blob = new Blob([response.data]);
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
@@ -116,6 +130,32 @@ export async function exportWechatMoments(params: {
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error: any) {
|
||||
throw new Error(error.response?.data?.message || error.message || "导出失败");
|
||||
// 如果是我们抛出的错误,直接抛出
|
||||
if (error.message && error.message !== "导出失败") {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// 处理axios错误响应
|
||||
if (error.response) {
|
||||
// 如果响应是blob类型,尝试读取为文本
|
||||
if (error.response.data instanceof Blob) {
|
||||
try {
|
||||
const text = await error.response.data.text();
|
||||
const errorData = JSON.parse(text);
|
||||
throw new Error(errorData.message || errorData.msg || "导出失败");
|
||||
} catch (parseError) {
|
||||
throw new Error("导出失败,请重试");
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
error.response.data?.message ||
|
||||
error.response.data?.msg ||
|
||||
error.message ||
|
||||
"导出失败"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error(error.message || "导出失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,6 +373,12 @@
|
||||
font-weight: 600;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.stat-value-negative {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,9 +874,10 @@
|
||||
.type-selector {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
|
||||
.type-option {
|
||||
flex: 1;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
@@ -879,6 +886,7 @@
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
background: white;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
border-color: #1677ff;
|
||||
@@ -1331,82 +1339,54 @@
|
||||
}
|
||||
}
|
||||
|
||||
.moments-action-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background: white;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.action-button, .action-button-dark {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
background: #1677ff;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
color: white;
|
||||
|
||||
&:active {
|
||||
background: #0958d9;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.action-button-dark {
|
||||
background: #1677ff;
|
||||
color: white;
|
||||
|
||||
&:active {
|
||||
background: #0958d9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moments-content {
|
||||
padding: 16px 0;
|
||||
height: 500px;
|
||||
overflow-y: auto;
|
||||
background: #f5f5f5;
|
||||
|
||||
.moments-action-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 16px 16px;
|
||||
|
||||
.action-button, .action-button-dark {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 70px;
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
background: #1677ff;
|
||||
|
||||
.action-icon-text, .action-icon-image, .action-icon-video, .action-icon-export {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 2px;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 12px;
|
||||
height: 2px;
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
|
||||
.action-icon-image::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 2px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.action-icon-video::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 5px 0 5px 8px;
|
||||
border-color: transparent transparent transparent white;
|
||||
}
|
||||
|
||||
.action-text, .action-text-light {
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.action-button-dark {
|
||||
background: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.moments-list {
|
||||
padding: 0 16px;
|
||||
|
||||
@@ -1459,7 +1439,7 @@
|
||||
|
||||
.image-grid {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
gap: 4px;
|
||||
width: 100%;
|
||||
|
||||
// 1张图片:宽度拉伸,高度自适应
|
||||
@@ -1469,56 +1449,57 @@
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 400px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 2张图片:左右并列
|
||||
// 2张图片:左右并列,1:1比例
|
||||
&.double {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
aspect-ratio: 1 / 1;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 3张图片:三张并列
|
||||
// 3张图片:三张并列,1:1比例
|
||||
&.triple {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
aspect-ratio: 1 / 1;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 4张图片:2x2网格布局
|
||||
// 4张图片:2x2网格布局,1:1比例
|
||||
&.quad {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 140px;
|
||||
aspect-ratio: 1 / 1;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 5张及以上:网格布局(9宫格)
|
||||
// 5张及以上:网格布局(9宫格),1:1比例
|
||||
&.grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
aspect-ratio: 1 / 1;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.image-more {
|
||||
@@ -1526,11 +1507,11 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
height: 100px;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1547,6 +1528,34 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moments-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.moments-no-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.friends-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.friends-no-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,18 @@ import {
|
||||
Tag,
|
||||
Switch,
|
||||
DatePicker,
|
||||
InfiniteScroll,
|
||||
} from "antd-mobile";
|
||||
import { Input, Pagination } from "antd";
|
||||
import { Input } from "antd";
|
||||
import NavCommon from "@/components/NavCommon";
|
||||
import {
|
||||
SearchOutlined,
|
||||
ReloadOutlined,
|
||||
UserOutlined,
|
||||
FileTextOutlined,
|
||||
PictureOutlined,
|
||||
VideoCameraOutlined,
|
||||
DownloadOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import Layout from "@/components/Layout/Layout";
|
||||
import style from "./detail.module.scss";
|
||||
@@ -32,6 +37,7 @@ import {
|
||||
} from "./api";
|
||||
import DeviceSelection from "@/components/DeviceSelection";
|
||||
import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { WechatAccountSummary, Friend, MomentItem } from "./data";
|
||||
|
||||
@@ -107,6 +113,84 @@ const WechatAccountDetail: React.FC = () => {
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
// 计算账号价值
|
||||
// 规则:
|
||||
// 1. 1个好友3块
|
||||
// 2. 1个群1块
|
||||
// 3. 修改过微信号10块
|
||||
const calculateAccountValue = useCallback(() => {
|
||||
// 获取好友数量(优先使用概览数据,其次使用好友列表总数,最后使用账号信息)
|
||||
const friendsCount = overviewData?.totalFriends || friendsTotal || accountInfo?.friendShip?.totalFriend || 0;
|
||||
|
||||
// 获取群数量(优先使用概览数据,其次使用账号信息)
|
||||
const groupsCount = overviewData?.highValueChatrooms || accountInfo?.friendShip?.groupNumber || 0;
|
||||
|
||||
// 判断是否修改过微信号
|
||||
// 注意:需要根据实际API返回的字段来判断,可能的字段名:
|
||||
// - isWechatIdModified (布尔值)
|
||||
// - wechatIdModified (布尔值)
|
||||
// - hasModifiedWechatId (布尔值)
|
||||
// - wechatIdChangeCount (数字,大于0表示修改过)
|
||||
// 如果API没有返回该字段,需要后端添加或根据其他逻辑判断
|
||||
const isWechatIdModified =
|
||||
accountInfo?.isWechatIdModified ||
|
||||
accountInfo?.wechatIdModified ||
|
||||
accountInfo?.hasModifiedWechatId ||
|
||||
(accountInfo?.wechatIdChangeCount && accountInfo.wechatIdChangeCount > 0) ||
|
||||
false;
|
||||
|
||||
// 计算各部分价值
|
||||
const friendsValue = friendsCount * 3; // 好友数 * 3
|
||||
const groupsValue = groupsCount * 1; // 群数 * 1
|
||||
const wechatIdModifiedValue = isWechatIdModified ? 10 : 0; // 修改过微信号 ? 10 : 0
|
||||
|
||||
// 计算总价值
|
||||
const totalValue = friendsValue + groupsValue + wechatIdModifiedValue;
|
||||
|
||||
return {
|
||||
value: totalValue,
|
||||
formatted: `¥${totalValue.toLocaleString()}`,
|
||||
breakdown: {
|
||||
friends: friendsValue,
|
||||
groups: groupsValue,
|
||||
wechatIdModified: wechatIdModifiedValue,
|
||||
friendsCount,
|
||||
groupsCount,
|
||||
isWechatIdModified,
|
||||
},
|
||||
};
|
||||
}, [overviewData, friendsTotal, accountInfo]);
|
||||
|
||||
// 计算今日价值变化
|
||||
// 规则:
|
||||
// 1. 今日新增好友 * 3块
|
||||
// 2. 今日新增群 * 1块
|
||||
const calculateTodayValueChange = useCallback(() => {
|
||||
// 获取今日新增好友数
|
||||
const todayNewFriends = overviewData?.todayNewFriends || accountSummary?.statistics?.todayAdded || 0;
|
||||
|
||||
// 获取今日新增群数
|
||||
const todayNewChatrooms = overviewData?.todayNewChatrooms || 0;
|
||||
|
||||
// 计算今日价值变化
|
||||
const friendsValueChange = todayNewFriends * 3; // 今日新增好友数 * 3
|
||||
const groupsValueChange = todayNewChatrooms * 1; // 今日新增群数 * 1
|
||||
|
||||
const totalChange = friendsValueChange + groupsValueChange;
|
||||
|
||||
return {
|
||||
change: totalChange,
|
||||
formatted: totalChange >= 0 ? `+${totalChange.toLocaleString()}` : `${totalChange.toLocaleString()}`,
|
||||
isPositive: totalChange >= 0,
|
||||
breakdown: {
|
||||
friends: friendsValueChange,
|
||||
groups: groupsValueChange,
|
||||
todayNewFriends,
|
||||
todayNewChatrooms,
|
||||
},
|
||||
};
|
||||
}, [overviewData, accountSummary]);
|
||||
|
||||
// 获取概览数据
|
||||
const fetchOverviewData = useCallback(async () => {
|
||||
if (!id) return;
|
||||
@@ -122,7 +206,7 @@ const WechatAccountDetail: React.FC = () => {
|
||||
|
||||
// 获取好友列表 - 封装为独立函数
|
||||
const fetchFriendsList = useCallback(
|
||||
async (page: number = 1, keyword: string = "") => {
|
||||
async (page: number = 1, keyword: string = "", append: boolean = false) => {
|
||||
if (!id) return;
|
||||
|
||||
setIsFetchingFriends(true);
|
||||
@@ -132,7 +216,7 @@ const WechatAccountDetail: React.FC = () => {
|
||||
const response = await getWechatFriends({
|
||||
wechatAccount: id,
|
||||
page: page,
|
||||
limit: 5,
|
||||
limit: 20,
|
||||
keyword: keyword,
|
||||
});
|
||||
|
||||
@@ -175,15 +259,17 @@ const WechatAccountDetail: React.FC = () => {
|
||||
};
|
||||
});
|
||||
|
||||
setFriends(newFriends);
|
||||
setFriends(prev => (append ? [...prev, ...newFriends] : newFriends));
|
||||
setFriendsTotal(response.total);
|
||||
setFriendsPage(page);
|
||||
setIsFriendsEmpty(newFriends.length === 0);
|
||||
setIsFriendsEmpty(newFriends.length === 0 && !append);
|
||||
} catch (error) {
|
||||
console.error("获取好友列表失败:", error);
|
||||
setHasFriendLoadError(true);
|
||||
setFriends([]);
|
||||
setIsFriendsEmpty(true);
|
||||
if (!append) {
|
||||
setFriends([]);
|
||||
setIsFriendsEmpty(true);
|
||||
}
|
||||
Toast.show({
|
||||
content: "获取好友列表失败,请检查网络连接",
|
||||
position: "top",
|
||||
@@ -238,22 +324,20 @@ const WechatAccountDetail: React.FC = () => {
|
||||
// 搜索好友
|
||||
const handleSearch = useCallback(() => {
|
||||
setFriendsPage(1);
|
||||
fetchFriendsList(1, searchQuery);
|
||||
fetchFriendsList(1, searchQuery, false);
|
||||
}, [searchQuery, fetchFriendsList]);
|
||||
|
||||
// 刷新好友列表
|
||||
const handleRefreshFriends = useCallback(() => {
|
||||
fetchFriendsList(friendsPage, searchQuery);
|
||||
fetchFriendsList(friendsPage, searchQuery, false);
|
||||
}, [friendsPage, searchQuery, fetchFriendsList]);
|
||||
|
||||
// 分页切换
|
||||
const handlePageChange = useCallback(
|
||||
(page: number) => {
|
||||
setFriendsPage(page);
|
||||
fetchFriendsList(page, searchQuery);
|
||||
},
|
||||
[searchQuery, fetchFriendsList],
|
||||
);
|
||||
// 加载更多好友
|
||||
const handleLoadMoreFriends = async () => {
|
||||
if (isFetchingFriends) return;
|
||||
if (friends.length >= friendsTotal) return;
|
||||
await fetchFriendsList(friendsPage + 1, searchQuery, true);
|
||||
};
|
||||
|
||||
// 初始化数据
|
||||
useEffect(() => {
|
||||
@@ -268,7 +352,7 @@ const WechatAccountDetail: React.FC = () => {
|
||||
if (activeTab === "friends" && id) {
|
||||
setIsFriendsEmpty(false);
|
||||
setHasFriendLoadError(false);
|
||||
fetchFriendsList(1, searchQuery);
|
||||
fetchFriendsList(1, searchQuery, false);
|
||||
}
|
||||
}, [activeTab, id, fetchFriendsList, searchQuery]);
|
||||
|
||||
@@ -298,8 +382,8 @@ const WechatAccountDetail: React.FC = () => {
|
||||
setInheritInfo(true);
|
||||
// 设置默认打招呼内容,使用当前微信账号昵称
|
||||
const nickname = accountInfo?.nickname || "未知";
|
||||
setGreeting(`这个是${nickname}的新号,之前那个号没用了,重新加一下您`);
|
||||
setFirstMessage("");
|
||||
setGreeting(`我是${nickname}的新号,请通过`);
|
||||
setFirstMessage("这个是我的新号,重新加你一下,以后业务就用这个号!");
|
||||
setShowTransferConfirm(true);
|
||||
};
|
||||
|
||||
@@ -385,10 +469,10 @@ const WechatAccountDetail: React.FC = () => {
|
||||
navigate(`/mine/traffic-pool/detail/${friend.wechatId}/${friend.id}`);
|
||||
};
|
||||
|
||||
const handleLoadMoreMoments = () => {
|
||||
const handleLoadMoreMoments = async () => {
|
||||
if (isFetchingMoments) return;
|
||||
if (moments.length >= momentsTotal) return;
|
||||
fetchMomentsList(momentsPage + 1, true);
|
||||
await fetchMomentsList(momentsPage + 1, true);
|
||||
};
|
||||
|
||||
// 处理朋友圈导出
|
||||
@@ -398,6 +482,18 @@ const WechatAccountDetail: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证时间范围不超过1个月
|
||||
if (exportStartTime && exportEndTime) {
|
||||
const maxDate = dayjs(exportStartTime).add(1, "month").toDate();
|
||||
if (exportEndTime > maxDate) {
|
||||
Toast.show({
|
||||
content: "日期范围不能超过1个月",
|
||||
position: "top",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setExportLoading(true);
|
||||
try {
|
||||
// 格式化时间
|
||||
@@ -418,18 +514,27 @@ const WechatAccountDetail: React.FC = () => {
|
||||
});
|
||||
|
||||
Toast.show({ content: "导出成功", position: "top" });
|
||||
setShowExportPopup(false);
|
||||
// 重置筛选条件
|
||||
// 重置筛选条件(先重置,再关闭弹窗)
|
||||
setExportKeyword("");
|
||||
setExportType(undefined);
|
||||
setExportStartTime(null);
|
||||
setExportEndTime(null);
|
||||
setShowStartTimePicker(false);
|
||||
setShowEndTimePicker(false);
|
||||
// 延迟关闭弹窗,确保Toast显示
|
||||
setTimeout(() => {
|
||||
setShowExportPopup(false);
|
||||
}, 500);
|
||||
} catch (error: any) {
|
||||
console.error("导出失败:", error);
|
||||
const errorMessage = error?.message || "导出失败,请重试";
|
||||
Toast.show({
|
||||
content: error.message || "导出失败,请重试",
|
||||
content: errorMessage,
|
||||
position: "top",
|
||||
duration: 2000,
|
||||
});
|
||||
// 确保loading状态被重置
|
||||
setExportLoading(false);
|
||||
} finally {
|
||||
setExportLoading(false);
|
||||
}
|
||||
@@ -548,7 +653,7 @@ const WechatAccountDetail: React.FC = () => {
|
||||
<div className={style["stat-icon-up"]}></div>
|
||||
</div>
|
||||
<div className={style["stat-value"]}>
|
||||
{overviewData?.accountValue?.formatted || `¥${overviewData?.accountValue?.value || "29,800"}`}
|
||||
{calculateAccountValue().formatted}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -558,8 +663,8 @@ const WechatAccountDetail: React.FC = () => {
|
||||
<div className={style["stat-title"]}>今日价值变化</div>
|
||||
<div className={style["stat-icon-plus"]}></div>
|
||||
</div>
|
||||
<div className={style["stat-value-positive"]}>
|
||||
{overviewData?.todayValueChange?.formatted || `+${overviewData?.todayValueChange?.change || "500"}`}
|
||||
<div className={calculateTodayValueChange().isPositive ? style["stat-value-positive"] : style["stat-value-negative"]}>
|
||||
{calculateTodayValueChange().formatted}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -761,7 +866,7 @@ const WechatAccountDetail: React.FC = () => {
|
||||
<div className={style["summary-item"]}>
|
||||
<div className={style["summary-label"]}>好友总估值</div>
|
||||
<div className={style["summary-value-highlight"]}>
|
||||
{overviewData?.accountValue?.formatted || "¥1,500,000"}
|
||||
{calculateAccountValue().formatted}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -780,7 +885,7 @@ const WechatAccountDetail: React.FC = () => {
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() =>
|
||||
fetchFriendsList(friendsPage, searchQuery)
|
||||
fetchFriendsList(friendsPage, searchQuery, false)
|
||||
}
|
||||
>
|
||||
重试
|
||||
@@ -837,47 +942,58 @@ const WechatAccountDetail: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 分页组件 */}
|
||||
{friendsTotal > 20 &&
|
||||
!isFriendsEmpty &&
|
||||
!hasFriendLoadError && (
|
||||
<div className={style["pagination-wrapper"]}>
|
||||
<Pagination
|
||||
total={Math.ceil(friendsTotal / 20)}
|
||||
current={friendsPage}
|
||||
onChange={handlePageChange}
|
||||
/>
|
||||
{/* 无限滚动加载 */}
|
||||
<InfiniteScroll
|
||||
loadMore={handleLoadMoreFriends}
|
||||
hasMore={friends.length < friendsTotal}
|
||||
threshold={100}
|
||||
>
|
||||
{isFetchingFriends && friends.length > 0 && (
|
||||
<div className={style["friends-loading"]}>
|
||||
<SpinLoading color="primary" style={{ fontSize: 16 }} />
|
||||
<span style={{ marginLeft: 8, color: "#999", fontSize: 12 }}>
|
||||
加载中...
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{friends.length >= friendsTotal && friends.length > 0 && (
|
||||
<div className={style["friends-no-more"]}>
|
||||
<span style={{ color: "#999", fontSize: 12 }}>没有更多了</span>
|
||||
</div>
|
||||
)}
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
</Tabs.Tab>
|
||||
|
||||
|
||||
<Tabs.Tab title="朋友圈" key="moments">
|
||||
<div className={style["moments-content"]}>
|
||||
{/* 功能按钮栏 */}
|
||||
<div className={style["moments-action-bar"]}>
|
||||
<div className={style["action-button"]}>
|
||||
<span className={style["action-icon-text"]}></span>
|
||||
<span className={style["action-text"]}>文本</span>
|
||||
</div>
|
||||
<div className={style["action-button"]}>
|
||||
<span className={style["action-icon-image"]}></span>
|
||||
<span className={style["action-text"]}>图片</span>
|
||||
</div>
|
||||
<div className={style["action-button"]}>
|
||||
<span className={style["action-icon-video"]}></span>
|
||||
<span className={style["action-text"]}>视频</span>
|
||||
</div>
|
||||
<div
|
||||
className={style["action-button-dark"]}
|
||||
onClick={() => setShowExportPopup(true)}
|
||||
>
|
||||
<span className={style["action-icon-export"]}></span>
|
||||
<span className={style["action-text-light"]}>导出</span>
|
||||
</div>
|
||||
{/* 功能按钮栏 - 移到白色背景上 */}
|
||||
<div className={style["moments-action-bar"]}>
|
||||
<div className={style["action-button"]}>
|
||||
<FileTextOutlined />
|
||||
</div>
|
||||
<div className={style["action-button"]}>
|
||||
<PictureOutlined />
|
||||
</div>
|
||||
<div className={style["action-button"]}>
|
||||
<VideoCameraOutlined />
|
||||
</div>
|
||||
<div
|
||||
className={style["action-button-dark"]}
|
||||
onClick={() => {
|
||||
// 默认设置近7天
|
||||
const today = new Date();
|
||||
const sevenDaysAgo = dayjs(today).subtract(7, "day").toDate();
|
||||
setExportStartTime(sevenDaysAgo);
|
||||
setExportEndTime(today);
|
||||
setShowExportPopup(true);
|
||||
}}
|
||||
>
|
||||
<DownloadOutlined />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={style["moments-content"]}>
|
||||
{/* 朋友圈列表 */}
|
||||
<div className={style["moments-list"]}>
|
||||
{isFetchingMoments && moments.length === 0 ? (
|
||||
@@ -949,18 +1065,25 @@ const WechatAccountDetail: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{moments.length < momentsTotal && (
|
||||
<div className={style["moments-load-more"]}>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={handleLoadMoreMoments}
|
||||
loading={isFetchingMoments}
|
||||
disabled={isFetchingMoments}
|
||||
>
|
||||
加载更多
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<InfiniteScroll
|
||||
loadMore={handleLoadMoreMoments}
|
||||
hasMore={moments.length < momentsTotal}
|
||||
threshold={100}
|
||||
>
|
||||
{isFetchingMoments && moments.length > 0 && (
|
||||
<div className={style["moments-loading"]}>
|
||||
<SpinLoading color="primary" style={{ fontSize: 16 }} />
|
||||
<span style={{ marginLeft: 8, color: "#999", fontSize: 12 }}>
|
||||
加载中...
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{moments.length >= momentsTotal && moments.length > 0 && (
|
||||
<div className={style["moments-no-more"]}>
|
||||
<span style={{ color: "#999", fontSize: 12 }}>没有更多了</span>
|
||||
</div>
|
||||
)}
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
</Tabs.Tab>
|
||||
|
||||
@@ -1124,7 +1247,11 @@ const WechatAccountDetail: React.FC = () => {
|
||||
{/* 朋友圈导出弹窗 */}
|
||||
<Popup
|
||||
visible={showExportPopup}
|
||||
onMaskClick={() => setShowExportPopup(false)}
|
||||
onMaskClick={() => {
|
||||
setShowExportPopup(false);
|
||||
setShowStartTimePicker(false);
|
||||
setShowEndTimePicker(false);
|
||||
}}
|
||||
bodyStyle={{ borderRadius: "16px 16px 0 0" }}
|
||||
>
|
||||
<div className={style["popup-content"]}>
|
||||
@@ -1133,7 +1260,11 @@ const WechatAccountDetail: React.FC = () => {
|
||||
<Button
|
||||
size="small"
|
||||
fill="outline"
|
||||
onClick={() => setShowExportPopup(false)}
|
||||
onClick={() => {
|
||||
setShowExportPopup(false);
|
||||
setShowStartTimePicker(false);
|
||||
setShowEndTimePicker(false);
|
||||
}}
|
||||
>
|
||||
关闭
|
||||
</Button>
|
||||
@@ -1207,11 +1338,13 @@ const WechatAccountDetail: React.FC = () => {
|
||||
visible={showStartTimePicker}
|
||||
title="开始时间"
|
||||
value={exportStartTime}
|
||||
max={exportEndTime || new Date()}
|
||||
onClose={() => setShowStartTimePicker(false)}
|
||||
onConfirm={val => {
|
||||
setExportStartTime(val);
|
||||
setShowStartTimePicker(false);
|
||||
}}
|
||||
onCancel={() => setShowStartTimePicker(false)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1230,6 +1363,8 @@ const WechatAccountDetail: React.FC = () => {
|
||||
visible={showEndTimePicker}
|
||||
title="结束时间"
|
||||
value={exportEndTime}
|
||||
min={exportStartTime || undefined}
|
||||
max={new Date()}
|
||||
onClose={() => setShowEndTimePicker(false)}
|
||||
onConfirm={val => {
|
||||
setExportEndTime(val);
|
||||
@@ -1259,6 +1394,8 @@ const WechatAccountDetail: React.FC = () => {
|
||||
setExportType(undefined);
|
||||
setExportStartTime(null);
|
||||
setExportEndTime(null);
|
||||
setShowStartTimePicker(false);
|
||||
setShowEndTimePicker(false);
|
||||
}}
|
||||
style={{ marginTop: 12 }}
|
||||
>
|
||||
|
||||
@@ -67,7 +67,7 @@ class PostTransferFriends extends BaseController
|
||||
'endTime' => '18:00',
|
||||
'remarkType' => 'phone',
|
||||
'addFriendInterval' => 60,
|
||||
'greeting' => !empty($greeting) ? $greeting :'这个是'. $wechat['nickname'] .'的新号,之前那个号没用了,重新加一下您'
|
||||
'greeting' => !empty($greeting) ? $greeting :'我是'. $wechat['nickname'] .'的新号,请通过'
|
||||
];
|
||||
|
||||
if (!empty($firstMessage)){
|
||||
|
||||
Reference in New Issue
Block a user