feat: 群组管理页面优化 + 分类管理图标修复

- 创建/加入群组合并为 Tab 切换卡片
- 群主可刷新邀请码(后端+前端完整链路)
- 群主可管理成员:查看列表、移除成员
- 新增后端 API:refresh-code / members / remove-member
- 修复分类管理页 FAB 按钮缺少 plus 图标
- 新增 plus/refresh 图标资源
This commit is contained in:
wangxiaogang
2026-06-04 21:28:22 +08:00
parent 114263e4b2
commit 9764b5626b
8 changed files with 541 additions and 40 deletions

View File

@@ -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