feat: 迭代三大模块 + 全系统 Bug 修复

新功能:
- 账单筛选统计:多维度筛选面板 + 保存方案 + 结果统计
- 通知公告:系统公告/群组通知/个人提醒 + 通知中心页面
- 管理员后台:数据看板 + 用户管理 + 发布公告

Bug 修复:
- 统计页 fetchPrevMonthData/fetchMaxSingle 添加 group_id
- 群组视图添加 t.group_id 过滤,防止私人数据泄露
- 通知列表添加群组通知条件
- 通知标记已读添加错误处理
- 管理员 API 添加 affectedRows 检查
- 筛选面板金额为 0 时正确回填
- profile onShow 补充 userStore.fetchUserInfo
- 全系统样式修复(overflow/box-sizing)
This commit is contained in:
wangxiaogang
2026-06-06 17:55:29 +08:00
parent bc6eca1e9b
commit 83571de723
35 changed files with 2255 additions and 37 deletions

52
client/src/api/admin.ts Normal file
View File

@@ -0,0 +1,52 @@
import { request } from '@/utils/request'
/** 数据看板 */
export interface Dashboard {
totalUsers: number
monthlyTxCount: number
monthlyTxAmount: number
dailyActive: number
monthlyActive: number
growthPercent: number
lastMonthTxCount: number
lastMonthTxAmount: number
}
/** 用户信息(管理员视角) */
export interface AdminUser {
id: number
nickname: string
avatar_url: string
role: 'user' | 'admin'
created_at: string
tx_count: number
group_count: number
}
/** 用户列表响应 */
export interface AdminUserList {
list: AdminUser[]
total: number
page: number
pageSize: number
}
/** 获取数据看板 */
export function getDashboard() {
return request<Dashboard>({ url: '/admin/dashboard' })
}
/** 获取用户列表 */
export function getUsers(params?: { page?: number; pageSize?: number; keyword?: string }) {
return request<AdminUserList>({ url: '/admin/users', data: params })
}
/** 更新用户角色 */
export function updateUserRole(id: number, role: 'user' | 'admin') {
return request({ url: `/admin/users/${id}/status`, method: 'PUT', data: { role } })
}
/** 删除用户 */
export function deleteUser(id: number) {
return request({ url: `/admin/users/${id}`, method: 'DELETE' })
}

35
client/src/api/filter.ts Normal file
View File

@@ -0,0 +1,35 @@
import { request } from '@/utils/request'
/** 保存的筛选方案 */
export interface SavedFilter {
id: number
name: string
filters: FilterParams
created_at: string
}
/** 筛选参数 */
export interface FilterParams {
type?: string
category_ids?: number[]
startDate?: string
endDate?: string
minAmount?: number
maxAmount?: number
keyword?: string
}
/** 获取保存的筛选方案 */
export function getSavedFilters() {
return request<SavedFilter[]>({ url: '/filters' })
}
/** 保存筛选方案 */
export function saveFilter(data: { name: string; filters: FilterParams }) {
return request<{ id: number }>({ url: '/filters', method: 'POST', data })
}
/** 删除筛选方案 */
export function deleteFilter(id: number) {
return request({ url: `/filters/${id}`, method: 'DELETE' })
}

View File

@@ -0,0 +1,45 @@
import { request } from '@/utils/request'
/** 通知 */
export interface Notification {
id: number
type: 'system' | 'group' | 'personal'
title: string
content: string
is_read: number
created_at: string
group_id?: number | null
}
/** 通知列表响应 */
export interface NotificationList {
list: Notification[]
total: number
page: number
pageSize: number
}
/** 获取通知列表 */
export function getNotifications(params?: { type?: string; page?: number; pageSize?: number }) {
return request<NotificationList>({ url: '/notifications', data: params })
}
/** 获取未读数量 */
export function getUnreadCount() {
return request<{ count: number }>({ url: '/notifications/unread-count' })
}
/** 标记单条已读 */
export function markRead(id: number) {
return request({ url: `/notifications/${id}/read`, method: 'PUT' })
}
/** 全部标记已读 */
export function markAllRead() {
return request({ url: '/notifications/read-all', method: 'PUT' })
}
/** 发布系统公告(管理员) */
export function publishNotification(data: { title: string; content?: string }) {
return request({ url: '/notifications', method: 'POST', data })
}

View File

@@ -23,6 +23,8 @@ export interface TransactionList {
total: number
page: number
pageSize: number
filteredExpense?: number
filteredIncome?: number
}
/** 获取交易列表参数 */
@@ -34,6 +36,10 @@ export interface TransactionParams {
endDate?: string
sortBy?: string
group_id?: number | null
category_id?: number
minAmount?: number
maxAmount?: number
keyword?: string
}
/** 获取交易列表 */

View File

@@ -6,6 +6,7 @@ export interface UserInfo {
id: number
nickname: string
avatar_url: string
role: 'user' | 'admin'
created_at: string
}