feat: 交易渠道重命名、账单来源统计默认值、AI 规则生成与统计搜索,AI 改用 openai-java SDK
- 交易记录「支付方式」全链路重命名为「交易渠道」(channel):DB 列、实体/DTO/VO、接口 /api/transaction/channels、统计维度 CHANNEL、AI 提示词与 JSON 字段、前端与中英日文案;新增 SchemaMigrator 在启动/切换数据源时幂等迁移列名(MySQL 用 information_schema、SQLite 用 PRAGMA) - 按账单来源设置「计入统计」默认值:AppConfig 持久化 + GET/PUT /api/app/bill-source-include-in-stats,导入解析按「解析器判定 && 来源默认」应用并覆盖上传与邮箱两条路径,设置页新增面板 - AI 生成规则:基于所选已打标签记录归纳分类/标签规则(POST /api/ai/rule/suggest、/api/ai/rule/apply),规则页两步弹窗(选择记录→预览创建),支持候选记录分页/搜索/筛选;按「类型+关键词+分类+标签」签名与已有规则去重,重复项标记「已存在」并禁止导入 - 规则列表新增分页与搜索:GET /api/rule/page(名称/关键词、启用状态、收支类型) - 统计面板 AI 搜索:POST /api/ai/statistics 将自然语言解析为时间/类型/分类/标签/渠道/金额/统计口径/趋势粒度并回填;交互对齐账单列表 AI 查询(弹窗 + 历史 + 示例 + 空条件守卫);统计后端补充标签筛选,仪表盘新增标签筛选与 AI 搜索 - AI 客户端改用 OpenAI 官方 Java SDK(com.openai:openai-java),自定义 baseUrl 指向 DeepSeek,保留 chat 签名与 DeepSeekResponse - AI 数据外发收敛:分类/标签建议与规则生成不再发送 rawData 与金额,仅发送类型/备注/渠道/分类/标签;新增 AiCallType.RULE / STATISTICS - 收支记录页新增「刷新」按钮
This commit is contained in:
+75
-4
@@ -16,7 +16,7 @@ export interface AiNewTag {
|
||||
color: string
|
||||
}
|
||||
|
||||
/** 单条 AI 建议(按类型、备注、支付方式聚合后的一组记录) */
|
||||
/** 单条 AI 建议(按类型、备注、交易渠道聚合后的一组记录) */
|
||||
export interface AiSuggestion {
|
||||
transactionId: number
|
||||
transactionIds: number[]
|
||||
@@ -78,7 +78,7 @@ export function parseTagByAi(text: string) {
|
||||
}
|
||||
|
||||
/** 根据表单当前内容生成单条分类与标签建议(调用大模型,超时放宽) */
|
||||
export function suggestOneByAi(data: { type: string; amount?: number | null; paymentMethod?: string; remark?: string }) {
|
||||
export function suggestOneByAi(data: { type: string; amount?: number | null; channel?: string; remark?: string }) {
|
||||
return request.post('/ai/suggest-one', data, { timeout: 60000 })
|
||||
}
|
||||
|
||||
@@ -92,6 +92,77 @@ export function suggestColor(name: string) {
|
||||
return request.post('/ai/color', { name }, { timeout: 60000 })
|
||||
}
|
||||
|
||||
/** AI 生成的规则建议 */
|
||||
export interface AiRuleSuggestion {
|
||||
name: string
|
||||
type: string | null
|
||||
keyword: string | null
|
||||
minAmount: number | null
|
||||
maxAmount: number | null
|
||||
categoryId: number | null
|
||||
categoryName: string | null
|
||||
newCategoryName: string | null
|
||||
newCategoryIcon: string | null
|
||||
tagIds: number[]
|
||||
tagNames: string[]
|
||||
newTags: AiNewTag[]
|
||||
reason: string
|
||||
/** 是否与已有规则重复:重复时默认不勾选且禁止导入 */
|
||||
duplicate: boolean
|
||||
}
|
||||
|
||||
/** AI 生成规则的结果 */
|
||||
export interface AiRuleSuggestResult {
|
||||
summary: string
|
||||
rules: AiRuleSuggestion[]
|
||||
}
|
||||
|
||||
/** AI 统计查询解析结果 */
|
||||
export interface AiStatisticsResult {
|
||||
summary: string
|
||||
types: string[]
|
||||
categoryIds: number[]
|
||||
categoryNames: string[]
|
||||
tagIds: number[]
|
||||
tagNames: string[]
|
||||
channels: string[]
|
||||
startTime: string | null
|
||||
endTime: string | null
|
||||
minAmount: number | null
|
||||
maxAmount: number | null
|
||||
remark: string | null
|
||||
statsScope: 'INCLUDED' | 'ALL' | 'EXCLUDED' | null
|
||||
dimension: 'day' | 'week' | 'month' | 'quarter' | 'year' | null
|
||||
unmatched: string[]
|
||||
}
|
||||
|
||||
/** 将自然语言统计查询解析为统计面板参数(调用大模型,超时放宽) */
|
||||
export function parseStatisticsByAi(query: string) {
|
||||
return request.post('/ai/statistics', { query }, { timeout: 120000 })
|
||||
}
|
||||
|
||||
/** 根据选中的已打标签记录生成规则建议(调用大模型,超时放宽) */
|
||||
export function suggestRulesByAi(transactionIds: number[]) {
|
||||
return request.post('/ai/rule/suggest', { transactionIds }, { timeout: 120000 })
|
||||
}
|
||||
|
||||
/** 批量创建 AI 生成的规则,必要时新建分类与标签 */
|
||||
export function applyAiRules(rules: {
|
||||
name: string
|
||||
enabled?: boolean
|
||||
type?: string | null
|
||||
keyword?: string | null
|
||||
minAmount?: number | null
|
||||
maxAmount?: number | null
|
||||
categoryId?: number | null
|
||||
newCategoryName?: string | null
|
||||
newCategoryIcon?: string | null
|
||||
tagIds?: number[]
|
||||
newTags?: AiNewTag[]
|
||||
}[]) {
|
||||
return request.post('/ai/rule/apply', { rules })
|
||||
}
|
||||
|
||||
/** 一键应用建议:覆盖分类并追加标签,标记为新建的分类/标签会先创建再关联 */
|
||||
export function applyAiSuggestions(suggestions: {
|
||||
transactionId: number
|
||||
@@ -111,7 +182,7 @@ export interface AiQueryResult {
|
||||
categoryIds: number[]
|
||||
categoryNames: string[]
|
||||
uncategorized: boolean
|
||||
paymentMethods: string[]
|
||||
channels: string[]
|
||||
startTime: string | null
|
||||
endTime: string | null
|
||||
includeInStats: boolean | null
|
||||
@@ -135,7 +206,7 @@ export interface AiRecordResult {
|
||||
amount: number | null
|
||||
categoryId: number | null
|
||||
categoryName: string | null
|
||||
paymentMethod: string | null
|
||||
channel: string | null
|
||||
transactionTime: string | null
|
||||
remark: string | null
|
||||
includeInStats: boolean | null
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// 应用级配置接口:按账单来源的「计入统计」默认值
|
||||
import request from './request'
|
||||
|
||||
/** 查询按账单来源的「计入统计」默认值(key 为账单来源编码) */
|
||||
export function getBillSourceIncludeInStats() {
|
||||
return request.get('/app/bill-source-include-in-stats')
|
||||
}
|
||||
|
||||
/** 更新按账单来源的「计入统计」默认值 */
|
||||
export function updateBillSourceIncludeInStats(defaults: Record<string, boolean>) {
|
||||
return request.put('/app/bill-source-include-in-stats', { defaults })
|
||||
}
|
||||
@@ -39,11 +39,25 @@ export interface RulePayload {
|
||||
tagIds?: number[]
|
||||
}
|
||||
|
||||
/** 规则分页查询参数 */
|
||||
export interface RulePageParams {
|
||||
page?: number
|
||||
size?: number
|
||||
keyword?: string
|
||||
enabled?: boolean
|
||||
type?: string
|
||||
}
|
||||
|
||||
/** 获取规则列表 */
|
||||
export function getRuleList() {
|
||||
return request.get('/rule/list')
|
||||
}
|
||||
|
||||
/** 分页查询规则(按名称/关键词、启用状态、收支类型筛选) */
|
||||
export function getRulePage(params: RulePageParams) {
|
||||
return request.get('/rule/page', { params })
|
||||
}
|
||||
|
||||
/** 创建规则 */
|
||||
export function createRule(data: RulePayload) {
|
||||
return request.post('/rule', data)
|
||||
|
||||
@@ -23,8 +23,9 @@ export interface StatisticsFilterParams {
|
||||
types?: string[]
|
||||
categoryIds?: number[]
|
||||
uncategorized?: boolean
|
||||
tagIds?: number[]
|
||||
untagged?: boolean
|
||||
paymentMethods?: string[]
|
||||
channels?: string[]
|
||||
minAmount?: number
|
||||
maxAmount?: number
|
||||
remark?: string
|
||||
@@ -37,7 +38,7 @@ export function getStatisticsSummary(params: StatisticsFilterParams) {
|
||||
return request.get('/statistics/summary', { params })
|
||||
}
|
||||
|
||||
/** 按维度获取分组统计数据(dimension:day/week/month/quarter/year/paymentMethod/category/type) */
|
||||
/** 按维度获取分组统计数据(dimension:day/week/month/quarter/year/channel/category/type) */
|
||||
export function getStatisticsGroup(params: StatisticsFilterParams & { dimension: string }) {
|
||||
return request.get('/statistics/group', { params })
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
// 收支记录相关 API 接口:交易记录的增删改查(分页)
|
||||
import request from './request'
|
||||
|
||||
/** 获取系统支持的支付方式编码列表(含账单导入来源与人工支付方式) */
|
||||
export function getPaymentMethods() {
|
||||
return request.get('/transaction/payment-methods')
|
||||
/** 获取系统支持的交易渠道编码列表(含账单导入来源与人工交易渠道) */
|
||||
export function getChannels() {
|
||||
return request.get('/transaction/channels')
|
||||
}
|
||||
|
||||
/** 分页获取交易记录列表,支持按类型、分类、支付方式、时间范围、计入统计、金额区间多选筛选 */
|
||||
/** 分页获取交易记录列表,支持按类型、分类、交易渠道、时间范围、计入统计、金额区间多选筛选 */
|
||||
export function getTransactionPage(params: {
|
||||
page?: number
|
||||
size?: number
|
||||
types?: string[]
|
||||
categoryIds?: number[]
|
||||
uncategorized?: boolean
|
||||
paymentMethods?: string[]
|
||||
channels?: string[]
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
includeInStats?: boolean
|
||||
@@ -24,6 +24,7 @@ export function getTransactionPage(params: {
|
||||
sortOrder?: string
|
||||
tagIds?: number[]
|
||||
untagged?: boolean
|
||||
tagged?: boolean
|
||||
}) {
|
||||
return request.get('/transaction/page', { params })
|
||||
}
|
||||
@@ -33,7 +34,7 @@ export function createTransaction(data: {
|
||||
categoryId: number
|
||||
type: string
|
||||
amount: number
|
||||
paymentMethod?: string
|
||||
channel?: string
|
||||
remark?: string
|
||||
transactionTime: string
|
||||
includeInStats?: boolean
|
||||
@@ -47,7 +48,7 @@ export function updateTransaction(id: number, data: {
|
||||
categoryId: number | null
|
||||
type: string
|
||||
amount: number
|
||||
paymentMethod?: string
|
||||
channel?: string
|
||||
remark?: string
|
||||
transactionTime: string
|
||||
includeInStats?: boolean
|
||||
@@ -163,7 +164,7 @@ export function exportTransaction(params: {
|
||||
types?: string[]
|
||||
categoryIds?: number[]
|
||||
uncategorized?: boolean
|
||||
paymentMethods?: string[]
|
||||
channels?: string[]
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
includeInStats?: boolean
|
||||
|
||||
Reference in New Issue
Block a user