feat: 群组管理页面优化 + 分类管理图标修复
- 创建/加入群组合并为 Tab 切换卡片 - 群主可刷新邀请码(后端+前端完整链路) - 群主可管理成员:查看列表、移除成员 - 新增后端 API:refresh-code / members / remove-member - 修复分类管理页 FAB 按钮缺少 plus 图标 - 新增 plus/refresh 图标资源
This commit is contained in:
@@ -208,4 +208,125 @@ router.delete('/:id', async (req: AuthRequest, res: Response) => {
|
||||
}
|
||||
})
|
||||
|
||||
/** 刷新邀请码(仅 owner) */
|
||||
router.post('/:id/refresh-code', async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const groupId = req.params.id
|
||||
|
||||
// 验证是否是群主
|
||||
const [groupRows] = await pool.query(
|
||||
'SELECT created_by FROM `groups` WHERE id = ?',
|
||||
[groupId]
|
||||
)
|
||||
const group = (groupRows as any[])[0]
|
||||
if (!group) {
|
||||
return res.status(404).json({ code: 40400, message: '群组不存在' })
|
||||
}
|
||||
if (group.created_by !== req.userId) {
|
||||
return res.status(403).json({ code: 40300, message: '仅群主可刷新邀请码' })
|
||||
}
|
||||
|
||||
// 生成新的唯一邀请码
|
||||
let inviteCode = generateInviteCode()
|
||||
let attempts = 0
|
||||
while (attempts < 10) {
|
||||
const [existing] = await pool.query('SELECT id FROM `groups` WHERE invite_code = ?', [inviteCode])
|
||||
if ((existing as any[]).length === 0) break
|
||||
inviteCode = generateInviteCode()
|
||||
attempts++
|
||||
}
|
||||
|
||||
await pool.query('UPDATE `groups` SET invite_code = ? WHERE id = ?', [inviteCode, groupId])
|
||||
res.json({ code: 0, data: { invite_code: inviteCode } })
|
||||
} catch (err) {
|
||||
console.error('[Group] refresh-code error:', err)
|
||||
res.status(500).json({ code: 50000, message: '服务器错误' })
|
||||
}
|
||||
})
|
||||
|
||||
/** 获取成员列表 */
|
||||
router.get('/:id/members', async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const groupId = req.params.id
|
||||
|
||||
// 验证用户是否是群组成员
|
||||
const [memberCheck] = await pool.query(
|
||||
'SELECT id FROM group_members WHERE group_id = ? AND user_id = ?',
|
||||
[groupId, req.userId]
|
||||
)
|
||||
if ((memberCheck as any[]).length === 0) {
|
||||
return res.status(403).json({ code: 40300, message: '无权访问此群组' })
|
||||
}
|
||||
|
||||
const [members] = await pool.query(
|
||||
`SELECT gm.user_id, gm.role, gm.created_at as joined_at,
|
||||
u.nickname, u.avatar_url
|
||||
FROM group_members gm
|
||||
LEFT JOIN users u ON gm.user_id = u.id
|
||||
WHERE gm.group_id = ?
|
||||
ORDER BY gm.role DESC, gm.created_at ASC`,
|
||||
[groupId]
|
||||
)
|
||||
|
||||
res.json({ code: 0, data: members })
|
||||
} catch (err) {
|
||||
console.error('[Group] members error:', err)
|
||||
res.status(500).json({ code: 50000, message: '服务器错误' })
|
||||
}
|
||||
})
|
||||
|
||||
/** 移除成员(仅 owner) */
|
||||
router.delete('/:id/members/:userId', async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const groupId = req.params.id
|
||||
const targetUserId = Number(req.params.userId)
|
||||
|
||||
// 不能移除自己
|
||||
if (targetUserId === req.userId) {
|
||||
return res.status(400).json({ code: 40001, message: '不能移除自己' })
|
||||
}
|
||||
|
||||
// 验证是否是群主
|
||||
const [groupRows] = await pool.query(
|
||||
'SELECT created_by FROM `groups` WHERE id = ?',
|
||||
[groupId]
|
||||
)
|
||||
const group = (groupRows as any[])[0]
|
||||
if (!group) {
|
||||
return res.status(404).json({ code: 40400, message: '群组不存在' })
|
||||
}
|
||||
if (group.created_by !== req.userId) {
|
||||
return res.status(403).json({ code: 40300, message: '仅群主可移除成员' })
|
||||
}
|
||||
|
||||
const conn = await pool.getConnection()
|
||||
try {
|
||||
await conn.beginTransaction()
|
||||
|
||||
// 清除该成员在群组的记录标签
|
||||
await conn.query(
|
||||
'UPDATE transactions SET group_id = NULL WHERE user_id = ? AND group_id = ?',
|
||||
[targetUserId, groupId]
|
||||
)
|
||||
|
||||
// 删除成员关系
|
||||
await conn.query(
|
||||
'DELETE FROM group_members WHERE group_id = ? AND user_id = ?',
|
||||
[groupId, targetUserId]
|
||||
)
|
||||
|
||||
await conn.commit()
|
||||
res.json({ code: 0 })
|
||||
} catch (err) {
|
||||
await conn.rollback()
|
||||
throw err
|
||||
} finally {
|
||||
conn.release()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Group] remove member error:', err)
|
||||
res.status(500).json({ code: 50000, message: '服务器错误' })
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
Reference in New Issue
Block a user