Files
ledgerly/build.gradle
T
rosercode 2976b85967 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
- 收支记录页新增「刷新」按钮
2026-09-20 17:13:24 +08:00

125 lines
4.2 KiB
Groovy
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.6'
id 'io.spring.dependency-management' version '1.1.7'
id 'com.diffplug.spotless' version '8.10.2'
}
group = 'cn.rosercode'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.security:spring-security-crypto'
implementation 'com.baomidou:mybatis-plus-spring-boot3-starter:3.5.12'
implementation 'com.baomidou:mybatis-plus-jsqlparser:3.5.12'
runtimeOnly 'com.mysql:mysql-connector-j'
// SQLite 驱动,用于本地文件数据库
runtimeOnly 'org.xerial:sqlite-jdbc:3.46.1.3'
implementation 'com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:4.5.0'
implementation 'com.alibaba:easyexcel:4.0.3'
implementation 'org.apache.commons:commons-csv:1.12.0'
// zip 压缩包解析(支持带密码的 ZipCrypto / AES 加密压缩包)
implementation 'net.lingala.zip4j:zip4j:2.11.5'
// PDF 账单解析(招商银行「交易流水」PDF 为文本型,按字符坐标还原表格)
implementation 'org.apache.pdfbox:pdfbox:3.0.3'
// OpenAI Java SDK:调用 DeepSeek 等 OpenAI 兼容接口(通过自定义 baseUrl 兼容)
implementation 'com.openai:openai-java:4.65.0'
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// MapStruct:编译期生成实体与视图对象之间的属性映射实现
implementation 'org.mapstruct:mapstruct:1.6.3'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.6.3'
// 使 MapStruct 能识别 Lombok 生成的 getter/setter
annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
// ===== 代码格式规范 =====
// 统一 Java 导入顺序:java/javax -> 第三方库 -> 项目包,组间空行分隔
spotless {
java {
target 'src/main/java/**/*.java', 'src/test/java/**/*.java'
// '|' 表示同组导入不插入空行;'' 为未显式指定导入的兜底组(即所有第三方库)
importOrder('java|javax', '', 'cn.rosercode')
}
}
// ===== 前端构建与打包 =====
def frontendDir = file("${projectDir}/frontend")
def frontendDistDir = file("${frontendDir}/dist")
// 解析 npm 可执行文件:优先使用 NODE_HOME,其次使用 PATH 中的 npm
def resolveNpm = {
def nodeHome = System.getenv('NODE_HOME')
return nodeHome ? "${nodeHome}/bin/npm" : 'npm'
}
// 安装前端依赖(node_modules 存在且 package.json 未变化时自动跳过)
tasks.register('npmInstall', Exec) {
group = 'frontend'
description = '安装前端依赖'
workingDir frontendDir
commandLine resolveNpm(), 'install'
inputs.file("${frontendDir}/package.json")
outputs.dir("${frontendDir}/node_modules")
}
// 构建前端产物
tasks.register('frontendBuild', Exec) {
group = 'frontend'
description = '构建前端产物(npm run build)'
dependsOn 'npmInstall'
workingDir frontendDir
commandLine resolveNpm(), 'run', 'build'
inputs.dir("${frontendDir}/src")
inputs.file("${frontendDir}/package.json")
inputs.file("${frontendDir}/index.html")
inputs.file("${frontendDir}/vite.config.ts")
outputs.dir(frontendDistDir)
}
// 将前端产物打入可执行 jar 的静态资源目录,实现前后端一体化部署
tasks.named('bootJar') {
dependsOn 'frontendBuild'
from(frontendDistDir) {
into 'BOOT-INF/classes/static'
}
}