fix(community): persist post liked status in MySQL and local storage to prevent state loss on page switch
这个提交包含在:
@@ -313,7 +313,20 @@ export async function initDatabase(): Promise<void> {
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// 16. 首页轮播图运营配置表
|
||||
// 16. 友圈动态用户点赞明细表 (用于持久化用户点赞状态并防重)
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS post_likes (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
post_id VARCHAR(64) NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uq_post_user (post_id, user_id),
|
||||
INDEX idx_post_likes_user (user_id),
|
||||
INDEX idx_post_likes_post (post_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
// 17. 首页轮播图运营配置表
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS banners (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
|
||||
@@ -2215,7 +2215,19 @@ export class MysqlRepository {
|
||||
|
||||
|
||||
// 友圈动态相关
|
||||
async getPosts(category?: string, keyword?: string, status?: string): Promise<any[]> {
|
||||
async getPosts(category?: string, keyword?: string, status?: string, userId?: number): Promise<any[]> {
|
||||
const currentUserId = userId !== undefined ? Number(userId) : 1001;
|
||||
const likedPostIdSet = new Set<string>();
|
||||
try {
|
||||
const [likedRows]: any = await pool.query(
|
||||
'SELECT post_id FROM post_likes WHERE user_id = ?',
|
||||
[currentUserId]
|
||||
);
|
||||
if (Array.isArray(likedRows)) {
|
||||
likedRows.forEach((row: any) => likedPostIdSet.add(String(row.post_id)));
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
let sql = `
|
||||
SELECT
|
||||
id, user_id as userId, author, avatar, tag, tag_type as tagType,
|
||||
@@ -2257,6 +2269,7 @@ export class MysqlRepository {
|
||||
|
||||
return {
|
||||
...r,
|
||||
liked: likedPostIdSet.has(String(r.id)),
|
||||
isTop: Boolean(r.isTop),
|
||||
status: r.status || '正常',
|
||||
topics: topicsArr,
|
||||
@@ -2354,10 +2367,41 @@ export class MysqlRepository {
|
||||
};
|
||||
}
|
||||
|
||||
async likePost(id: string): Promise<any> {
|
||||
await pool.query('UPDATE posts SET likes = likes + 1 WHERE id = ?', [id]);
|
||||
async likePost(id: string, userId: number = 1001, action?: 'like' | 'unlike'): Promise<any> {
|
||||
const currentUserId = Number(userId) || 1001;
|
||||
let liked = false;
|
||||
try {
|
||||
const [existing]: any = await pool.query(
|
||||
'SELECT id FROM post_likes WHERE post_id = ? AND user_id = ?',
|
||||
[id, currentUserId]
|
||||
);
|
||||
const isCurrentlyLiked = existing && existing.length > 0;
|
||||
const shouldLike = action ? action === 'like' : !isCurrentlyLiked;
|
||||
|
||||
if (!shouldLike) {
|
||||
if (isCurrentlyLiked) {
|
||||
await pool.query('DELETE FROM post_likes WHERE post_id = ? AND user_id = ?', [id, currentUserId]);
|
||||
await pool.query('UPDATE posts SET likes = GREATEST(0, likes - 1) WHERE id = ?', [id]);
|
||||
}
|
||||
liked = false;
|
||||
} else {
|
||||
if (!isCurrentlyLiked) {
|
||||
const likeId = `like_${Date.now()}_${Math.floor(100 + Math.random() * 900)}`;
|
||||
await pool.query(
|
||||
'INSERT IGNORE INTO post_likes (id, post_id, user_id, created_at) VALUES (?, ?, ?, NOW())',
|
||||
[likeId, id, currentUserId]
|
||||
);
|
||||
await pool.query('UPDATE posts SET likes = likes + 1 WHERE id = ?', [id]);
|
||||
}
|
||||
liked = true;
|
||||
}
|
||||
} catch (_) {
|
||||
// 容错兜底递增
|
||||
await pool.query('UPDATE posts SET likes = likes + 1 WHERE id = ?', [id]);
|
||||
liked = true;
|
||||
}
|
||||
const [rows]: any = await pool.query('SELECT likes FROM posts WHERE id = ?', [id]);
|
||||
return { id, likes: rows[0]?.likes || 1 };
|
||||
return { id, likes: rows[0]?.likes || 0, liked };
|
||||
}
|
||||
|
||||
// 13. 订单评价与评分业务
|
||||
|
||||
@@ -1694,7 +1694,8 @@ app.get('/api/users/:id/finance-records', async (req: Request, res: Response) =>
|
||||
app.get('/api/posts', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const category = req.query.category ? String(req.query.category) : undefined;
|
||||
const posts = await repo.getPosts(category);
|
||||
const userId = Number(req.query.userId || req.headers['x-user-id']) || 1001;
|
||||
const posts = await repo.getPosts(category, undefined, '正常', userId);
|
||||
res.json({
|
||||
code: 20000,
|
||||
data: posts
|
||||
@@ -1804,11 +1805,13 @@ app.post('/api/posts', async (req: Request, res: Response) => {
|
||||
|
||||
app.post('/api/posts/:id/like', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const result = await repo.likePost(String(req.params.id));
|
||||
const userId = Number(req.body?.userId || req.query.userId || req.headers['x-user-id']) || 1001;
|
||||
const action = req.body?.action as 'like' | 'unlike' | undefined;
|
||||
const result = await repo.likePost(String(req.params.id), userId, action);
|
||||
res.json({
|
||||
code: 20000,
|
||||
data: result,
|
||||
message: '点赞成功'
|
||||
message: result.liked ? '点赞成功' : '已取消点赞'
|
||||
});
|
||||
} catch (err: any) {
|
||||
res.status(400).json({ code: 40000, message: err.message });
|
||||
|
||||
在新工单中引用
屏蔽一个用户