- 交易记录「支付方式」全链路重命名为「交易渠道」(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 - 收支记录页新增「刷新」按钮
125 lines
4.2 KiB
Groovy
125 lines
4.2 KiB
Groovy
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'
|
||
}
|
||
}
|