feat: 账单导入、统计维度扩展与收支记录增强

- 账单导入:新增支付宝账单解析/导入接口,按 external_no 去重;前端拖拽上传 + 预览确认弹窗
- 分类可选:category_id 允许为空,支持「未分类」筛选,新增按类型一键批量设置分类
- 备注隐藏:新增 remark_hidden 与切换接口,列表默认显示 ****** 并可单格查看/取消隐藏,导出同步隐藏
- 统计扩展:新增 /statistics/summary、/statistics/group,支持日/周/月/季/年/支付方式/分类/类型维度与时间范围过滤
- 收支记录:金额区间过滤、金额/交易时间列排序、分页快速跳转、本页收支结余汇总、交易时间列前置并合并创建时间提示
- 用户偏好:统计面板与列表的筛选条件持久化到 localStorage,进入自动还原
- 其他:新增默认分类种子脚本(含美容美发)、commons-csv 依赖、上传大小限制 10MB、Vite 监听 0.0.0.0
This commit is contained in:
2026-09-17 13:19:59 +08:00
parent 733ed4bb86
commit 1df6e23510
35 changed files with 3016 additions and 1620 deletions
+23
View File
@@ -15,3 +15,26 @@ export function getCategoryStatistics(params: { year: number; month: number }) {
export function getTrendStatistics(params: { year: number; month: number }) {
return request.get('/statistics/trend', { params })
}
/** 统计过滤条件,供概览与分组统计复用 */
export interface StatisticsFilterParams {
startTime?: string
endTime?: string
types?: string[]
categoryIds?: number[]
uncategorized?: boolean
paymentMethods?: string[]
minAmount?: number
maxAmount?: number
remark?: string
}
/** 获取指定时间范围的统计概览(收支汇总、日均、最大单笔、平均每笔) */
export function getStatisticsSummary(params: StatisticsFilterParams) {
return request.get('/statistics/summary', { params })
}
/** 按维度获取分组统计数据(dimension:day/week/month/quarter/year/paymentMethod/category/type) */
export function getStatisticsGroup(params: StatisticsFilterParams & { dimension: string }) {
return request.get('/statistics/group', { params })
}
+73 -1
View File
@@ -3,16 +3,20 @@ import request from './request'
import axios from 'axios'
import { useUserStore } from '../store/user'
/** 分页获取交易记录列表,支持按类型、分类、支付方式、时间范围、计入统计多选筛选 */
/** 分页获取交易记录列表,支持按类型、分类、支付方式、时间范围、计入统计、金额区间多选筛选 */
export function getTransactionPage(params: {
page?: number
size?: number
types?: string[]
categoryIds?: number[]
uncategorized?: boolean
paymentMethods?: string[]
startTime?: string
endTime?: string
includeInStats?: boolean
minAmount?: number
maxAmount?: number
remark?: string
}) {
return request.get('/transaction/page', { params })
}
@@ -53,14 +57,82 @@ export function toggleTransactionStats(id: number, includeInStats: boolean) {
return request.put(`/transaction/${id}/stats`, { includeInStats })
}
/** 切换指定交易记录的备注隐藏标记 */
export function toggleRemarkHidden(id: number, remarkHidden: boolean) {
return request.put(`/transaction/${id}/remark-hidden`, { remarkHidden })
}
/** 支持的账单类型,当前仅支付宝 */
export type BillType = 'ALIPAY'
/** 账单解析结果行 */
export interface ParsedBillRow {
rowNo: number
externalNo: string
transactionTime: string
type: string
amount: number
counterparty: string
product: string
tradeStatus: string
direction: string
includeInStats: boolean
importable: boolean
selected: boolean
duplicate: boolean
error: string | null
}
/** 待导入账单行 */
export interface BillImportItem {
externalNo: string
transactionTime: string
type: string
amount: number
counterparty: string
product: string
includeInStats: boolean
}
/** 解析账单文件(不落库),返回预览数据 */
export function parseBill(file: File, billType: BillType) {
const formData = new FormData()
formData.append('file', file)
formData.append('billType', billType)
return request.post('/transaction/import/parse', formData)
}
/** 确认导入用户勾选的账单行 */
export function confirmImport(data: {
billType: BillType
expenseCategoryId?: number | null
incomeCategoryId?: number | null
items: BillImportItem[]
}) {
return request.post('/transaction/import/confirm', data)
}
/** 批量设置交易记录的分类(按类型分别应用支出/收入分类) */
export function batchUpdateCategory(data: {
ids: number[]
expenseCategoryId?: number | null
incomeCategoryId?: number | null
}) {
return request.put('/transaction/batch-category', data)
}
/** 导出交易记录为 Excel 文件,支持按条件筛选 */
export function exportTransaction(params: {
types?: string[]
categoryIds?: number[]
uncategorized?: boolean
paymentMethods?: string[]
startTime?: string
endTime?: string
includeInStats?: boolean
minAmount?: number
maxAmount?: number
remark?: string
}) {
const userStore = useUserStore()
return axios.get('/api/transaction/export', {