feat: 用户体验优化 — 首页加载/继续记账/登录恢复
## 首页加载优化 - 分级加载:首屏只请求 overview + recentTx(2个请求) - 数据新鲜度:30秒内不重复请求 - 次要数据异步加载:budget + todayData - 非关键数据后台加载:userInfo + notifications ## 继续记账功能 - SaveSuccess 组件新增「继续记一笔」按钮 - 新增模式显示继续按钮,编辑模式自动返回 - 继续记账时保留分类和日期,清空金额和备注 ## 登录失败恢复 - 登录重试机制:最多3次,间隔1秒 - 失败后显示提示而非静默等待 ## 群组账单逻辑修正 - 群组账单 = 所有群组成员的个人账单之和 - 修改查询:WHERE user_id IN (群组成员)
This commit is contained in:
@@ -31,7 +31,7 @@ CREATE TABLE IF NOT EXISTS transactions (
|
||||
category_id INT,
|
||||
note VARCHAR(200),
|
||||
date DATE NOT NULL,
|
||||
group_id INT DEFAULT NULL COMMENT '群组标签,NULL=纯个人记录',
|
||||
group_id INT DEFAULT NULL COMMENT '群组标签(仅标记,群组账单通过 user_id 关联 group_members 统计)',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_user_date (user_id, date),
|
||||
|
||||
@@ -22,9 +22,9 @@ async function buildWhereClause(
|
||||
)
|
||||
if ((memberCheck as any[]).length === 0) return null
|
||||
|
||||
// 群组视图:显示该群组所有记录(包括已退出成员的历史记录)
|
||||
// 群组视图:统计所有群组成员的个人账单
|
||||
params.push(groupId)
|
||||
let where = `WHERE t.group_id = ?`
|
||||
let where = `WHERE t.user_id IN (SELECT user_id FROM group_members WHERE group_id = ?)`
|
||||
if (extraConditions.length > 0) where += ' AND ' + extraConditions.join(' AND ')
|
||||
return { where, params }
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ function safeInt(val: any, fallback: number, min: number, max: number): number {
|
||||
|
||||
router.get('/:id', async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
// 用户可以查看:自己的记录 + 自己所在群组的所有记录(包括已退出成员的历史记录)
|
||||
// 用户可以查看:自己的记录 + 自己所在群组成员的所有记录
|
||||
const [rows] = await pool.query(
|
||||
`SELECT t.id, t.user_id, t.amount, t.type, t.category_id, t.note, DATE_FORMAT(t.date, '%Y-%m-%d') as date, t.created_at, t.updated_at, t.group_id,
|
||||
c.name as category_name, c.icon as category_icon, c.color as category_color,
|
||||
@@ -25,7 +25,7 @@ router.get('/:id', async (req: AuthRequest, res: Response) => {
|
||||
LEFT JOIN users u ON t.user_id = u.id
|
||||
WHERE t.id = ? AND (
|
||||
t.user_id = ?
|
||||
OR t.group_id IN (SELECT group_id FROM group_members WHERE user_id = ?)
|
||||
OR t.user_id IN (SELECT user_id FROM group_members WHERE group_id IN (SELECT group_id FROM group_members WHERE user_id = ?))
|
||||
)`,
|
||||
[req.params.id, req.userId, req.userId]
|
||||
)
|
||||
@@ -51,7 +51,7 @@ router.get('/', async (req: AuthRequest, res: Response) => {
|
||||
const params: any[] = []
|
||||
|
||||
if (group_id && group_id !== 'null') {
|
||||
// 群组视图:验证用户是群组成员,然后显示该群组所有记录(包括已退出成员的历史记录)
|
||||
// 群组视图:验证用户是群组成员,然后显示所有群组成员的记录
|
||||
const [memberCheck] = await pool.query(
|
||||
'SELECT id FROM group_members WHERE group_id = ? AND user_id = ?',
|
||||
[group_id, req.userId]
|
||||
@@ -59,7 +59,8 @@ router.get('/', async (req: AuthRequest, res: Response) => {
|
||||
if ((memberCheck as any[]).length === 0) {
|
||||
return res.status(403).json({ code: 40300, message: '无权访问此群组' })
|
||||
}
|
||||
where = 'WHERE t.group_id = ?'
|
||||
// 群组账单 = 所有群组成员的个人账单
|
||||
where = 'WHERE t.user_id IN (SELECT user_id FROM group_members WHERE group_id = ?)'
|
||||
params.push(group_id)
|
||||
} else {
|
||||
// 个人视图:我的所有记录(不管 group_id)
|
||||
|
||||
Reference in New Issue
Block a user