2025-09-28 17:45:40 +08:00
|
|
|
|
// message.ts (适配最新数据库结构)
|
2025-09-28 00:14:39 +08:00
|
|
|
|
|
2025-09-28 20:22:23 +08:00
|
|
|
|
import envConfig from "../../env";
|
|
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
// 接口:定义从API获取的原始消息数据结构 (与数据库完全一致)
|
|
|
|
|
|
interface IApiMessage {
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
sender_id: string;
|
|
|
|
|
|
receiver_id: string;
|
|
|
|
|
|
status: number; // 假设 status 字段仍有其他用途
|
|
|
|
|
|
sequence: string;
|
|
|
|
|
|
created_at: string; // e.g., "2025-09-28 18:10:00"
|
|
|
|
|
|
content: string;
|
|
|
|
|
|
is_read: 0 | 1; // 0: 未读, 1: 已读
|
|
|
|
|
|
msg_type: 'comment' | 'like' | 'follow' | 'system';
|
|
|
|
|
|
target: string | null; // e.g., "post:123", "user:456", "/pages/...", or null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 接口:定义页面渲染所需的数据结构
|
|
|
|
|
|
interface IViewMessage {
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
type: 'system' | 'user'; // 用于区分图标
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
content: string;
|
|
|
|
|
|
timestamp: string;
|
|
|
|
|
|
is_read: 0 | 1; // 用于显示未读红点
|
|
|
|
|
|
target: string | null; // 用于点击跳转
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Page({
|
|
|
|
|
|
data: {
|
|
|
|
|
|
systemIcon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzQ3OTZGMyI+PHBhdGggZD0iTTIgMTVoMnYyaC0yem0wLTRoMnYyaC0yem0wLThoMnY2aC0yem00IDEyaDJ2MmgtMnptMC00aDJ2MmgtMnptMC00aDJ2MmgtMnptMTYtNGgtOHYtMmgtNHYyaC0yYTEgMSAwIDAgMC0xIDF2MTBhMSAxIDAgMCAwIDEgMWgxNGExIDEgMCAwIDAgMS0xdi0xMGExIDEgMCAwIDAtMS0xem0tMyAxMGgtMTB2LThoMTB6bS0xMS00aDJ2MmgtMnptMC00aDJ2MmgtMnptNCA0aDJ2MmgtMnptMC00aDJ2MmgtMnptNCA0aDJ2MmgtMnptMC00aDJ2MmgtMnoiLz48L3N2Zz4=',
|
|
|
|
|
|
userIcon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZDQjMwMCI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMSu3OS00IDQgMS.3OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAyLjY5LTggNnYxaDE2di0xYzAtMi4zMS01LjMzLTUtOC01eiIvPjwvc3ZnPg==',
|
|
|
|
|
|
|
|
|
|
|
|
messageList: [] as IViewMessage[],
|
|
|
|
|
|
},
|
2025-09-28 00:14:39 +08:00
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
onLoad() {
|
|
|
|
|
|
this.fetchAndProcessMessages();
|
|
|
|
|
|
},
|
2025-09-28 00:14:39 +08:00
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
fetchAndProcessMessages() {
|
2025-09-28 20:22:23 +08:00
|
|
|
|
|
|
|
|
|
|
const app = getApp();
|
|
|
|
|
|
console.log("全局userinfo",app.globalData.userInfo)
|
|
|
|
|
|
const userInfo = app.globalData.userInfo || {};
|
|
|
|
|
|
console.log("userInfo 的数据类型:", typeof userInfo);
|
|
|
|
|
|
console.log("user中的userInfo:",userInfo)
|
|
|
|
|
|
let userInfoObj = userInfo;
|
|
|
|
|
|
if (typeof userInfo === "string") {
|
|
|
|
|
|
try {
|
|
|
|
|
|
userInfoObj = JSON.parse(userInfo); // 字符串转对象
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error("解析 userInfo 字符串失败:", e);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
wx.request({
|
|
|
|
|
|
url: `${envConfig.apiBaseUrl}/notification/get`, // 替换为你的后端接口地址
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
data: {
|
|
|
|
|
|
"uid": userInfoObj.uid
|
|
|
|
|
|
},
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
console.log("该用户消息通知:",res)
|
|
|
|
|
|
const apiResponse = res.data.data as IApiMessage[];
|
|
|
|
|
|
|
|
|
|
|
|
// ⭐️ 关键步骤:调用 transformMessage 对每条消息进行处理
|
|
|
|
|
|
const viewList = apiResponse.map(msg => this.transformMessage(msg));
|
|
|
|
|
|
|
|
|
|
|
|
// 将处理过后的、符合 WXML 要求的 viewList 设置给页面
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
messageList: viewList
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-09-28 17:45:40 +08:00
|
|
|
|
|
2025-09-28 20:22:23 +08:00
|
|
|
|
// const viewList = apiResponse.map(msg => this.transformMessage(msg));
|
2025-09-28 17:45:40 +08:00
|
|
|
|
|
2025-09-28 20:22:23 +08:00
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
transformMessage(msg: IApiMessage): IViewMessage {
|
|
|
|
|
|
let title = '';
|
2025-09-28 20:22:23 +08:00
|
|
|
|
let finalContent = '';
|
|
|
|
|
|
|
|
|
|
|
|
// 在真实应用中,您应该根据 sender_id 从用户数据中查找真实的昵称
|
|
|
|
|
|
// 此处为了演示,我们先用 sender_id 的一部分作为临时名称
|
|
|
|
|
|
const senderName = msg.sender_id.substring(0, 8); // 取 sender_id 前8位做为临时昵称
|
2025-09-28 17:45:40 +08:00
|
|
|
|
|
|
|
|
|
|
switch (msg.msg_type) {
|
2025-09-28 20:22:23 +08:00
|
|
|
|
case 'comment':
|
|
|
|
|
|
title = '新的评论';
|
|
|
|
|
|
// ⭐️ 修正:使用 senderName (它等于 msg.sender_id)
|
|
|
|
|
|
finalContent = `「${senderName}」评论了你:「${msg.content}」`;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'like':
|
|
|
|
|
|
title = '新的点赞';
|
|
|
|
|
|
// ⭐️ 修正:使用 senderName
|
|
|
|
|
|
finalContent = `「${senderName}」赞了您的动态:${msg.content}`;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'follow':
|
|
|
|
|
|
title = '新的关注';
|
|
|
|
|
|
// ⭐️ 修正:使用 senderName
|
|
|
|
|
|
finalContent = `「${senderName}」关注了你`;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'system':
|
|
|
|
|
|
title = '系统通知';
|
|
|
|
|
|
finalContent = msg.content;
|
|
|
|
|
|
break;
|
2025-09-28 00:14:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
return {
|
|
|
|
|
|
id: msg.id,
|
|
|
|
|
|
type: msg.msg_type === 'system' ? 'system' : 'user',
|
|
|
|
|
|
title: title,
|
2025-09-28 20:22:23 +08:00
|
|
|
|
content: finalContent,
|
2025-09-28 17:45:40 +08:00
|
|
|
|
timestamp: this.formatDisplayTime(msg.created_at),
|
|
|
|
|
|
is_read: msg.is_read,
|
|
|
|
|
|
target: msg.target,
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// ⭐️ 新增/恢复:卡片点击跳转的处理函数
|
|
|
|
|
|
handleNavigate(event: WechatMiniprogram.TouchEvent) {
|
|
|
|
|
|
const { target } = event.currentTarget.dataset;
|
2025-09-28 00:14:39 +08:00
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
if (!target) {
|
|
|
|
|
|
console.log("此消息没有可跳转的目标");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-28 00:14:39 +08:00
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
let url = '';
|
|
|
|
|
|
// 解析 target, e.g., "post:abc-123"
|
|
|
|
|
|
const parts = target.split(':');
|
|
|
|
|
|
const type = parts[0];
|
|
|
|
|
|
const id = parts[1];
|
2025-09-28 00:14:39 +08:00
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
switch (type) {
|
|
|
|
|
|
case 'post':
|
|
|
|
|
|
url = `/pages/post-detail/index?id=${id}`;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'user':
|
|
|
|
|
|
url = `/pages/user-profile/index?userId=${id}`;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
// 如果 target 不包含 ':', 说明它可能是一个完整的内部页面路径
|
|
|
|
|
|
if (target.startsWith('/')) {
|
|
|
|
|
|
url = target;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.warn("未知的 target 类型:", target);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-28 00:14:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
wx.navigateTo({
|
|
|
|
|
|
url: url,
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
console.error("页面跳转失败", err);
|
|
|
|
|
|
wx.showToast({ title: '页面不存在', icon: 'none' });
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
formatDisplayTime(dateString: string): string {
|
2025-09-28 20:22:23 +08:00
|
|
|
|
// ⭐️ 修正:直接解析标准日期字符串,不再需要 replace
|
|
|
|
|
|
const date = new Date(dateString);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查日期是否有效
|
|
|
|
|
|
if (isNaN(date.getTime())) {
|
|
|
|
|
|
return "日期无效"; // 返回一个友好的错误提示
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
const now = new Date();
|
|
|
|
|
|
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
|
|
|
|
const yesterdayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
|
2025-09-28 20:22:23 +08:00
|
|
|
|
|
2025-09-28 17:45:40 +08:00
|
|
|
|
const time = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
|
2025-09-28 20:22:23 +08:00
|
|
|
|
|
|
|
|
|
|
if (date.getTime() >= todayStart.getTime()) {
|
|
|
|
|
|
return `今天 ${time}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (date.getTime() >= yesterdayStart.getTime()) {
|
|
|
|
|
|
return `昨天 ${time}`;
|
|
|
|
|
|
}
|
2025-09-28 17:45:40 +08:00
|
|
|
|
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
|
2025-09-28 20:22:23 +08:00
|
|
|
|
},
|
2025-09-28 17:45:40 +08:00
|
|
|
|
});
|