feat: 支持数据库运行时配置与多数据库,重构设置页并完善打包

- 数据库支持 SQLite / MySQL 运行时配置与切换,未配置时仍可启动,配置后自动建表
- 新增默认分类与标签初始化,注册用户自动创建
- 新增注册开关(默认关闭,可在系统设置开启;无用户时允许创建首个账号)
- 合并数据库、注册与 AI 配置为「系统设置」页,拆分「模型使用情况」独立页面
- AI 一键设置支持新建分类与标签
- 前端构建产物打包进可执行 jar,后端增加 SPA 路由回退
- jar 更名为 finance-app,补全 Gradle Wrapper,移除 archive 任务
- 更新 DeepSeek 模型说明文案
This commit is contained in:
2026-09-18 12:33:41 +08:00
parent 16e4c30456
commit c1f5d02564
63 changed files with 3783 additions and 573 deletions
+18 -2
View File
@@ -10,6 +10,12 @@ export interface AiConfig {
model: string
}
/** AI 建议新建的标签 */
export interface AiNewTag {
name: string
color: string
}
/** 单条 AI 建议(按类型、备注、支付方式聚合后的一组记录) */
export interface AiSuggestion {
transactionId: number
@@ -17,8 +23,11 @@ export interface AiSuggestion {
count: number
categoryId: number | null
categoryName: string | null
newCategoryName: string | null
newCategoryIcon: string | null
tagIds: number[]
tagNames: string[]
newTags: AiNewTag[]
reason: string
}
@@ -83,8 +92,15 @@ export function suggestColor(name: string) {
return request.post('/ai/color', { name }, { timeout: 60000 })
}
/** 一键应用建议:覆盖分类并追加标签 */
export function applyAiSuggestions(suggestions: { transactionId: number; categoryId: number | null; tagIds: number[] }[]) {
/** 一键应用建议:覆盖分类并追加标签,标记为新建的分类/标签会先创建再关联 */
export function applyAiSuggestions(suggestions: {
transactionId: number
categoryId: number | null
newCategoryName?: string | null
newCategoryIcon?: string | null
tagIds: number[]
newTags?: AiNewTag[]
}[]) {
return request.post('/ai/apply', { suggestions })
}
+45
View File
@@ -0,0 +1,45 @@
// 数据库配置接口封装:状态查询、连接测试与配置保存
import request from './request'
/** 数据库类型 */
export type DatabaseType = 'MYSQL' | 'SQLITE'
/** 数据库配置请求参数 */
export interface DatabaseConfigPayload {
type: DatabaseType
sqlitePath?: string
host?: string
port?: number
database?: string
username?: string
password?: string
}
/** 数据库状态 */
export interface DatabaseStatus {
configured: boolean
type?: DatabaseType
typeName?: string
summary?: string
configFile?: string
host?: string
port?: number
database?: string
username?: string
sqlitePath?: string
}
/** 查询当前数据库配置状态 */
export function getDatabaseStatus() {
return request.get('/database/status')
}
/** 测试数据库连接是否可用 */
export function testDatabaseConnection(data: DatabaseConfigPayload) {
return request.post('/database/test', data)
}
/** 保存数据库配置并切换到新数据源 */
export function saveDatabaseConfig(data: DatabaseConfigPayload) {
return request.post('/database/config', data)
}
+10
View File
@@ -24,6 +24,16 @@ request.interceptors.response.use(
const data = response.data
// 如果业务状态码不是 200,视为请求失败
if (data.code !== 200) {
// 5031:数据库未配置,更新本地状态并跳转到配置引导页
if (data.code === 5031) {
import('../store/database').then(({ useDatabaseStore }) => {
const databaseStore = useDatabaseStore()
databaseStore.setStatus(null)
if (router.currentRoute.value.path !== '/database-setup') {
router.push('/database-setup')
}
})
}
return Promise.reject(new Error(data.message || '请求失败'))
}
return data
+17
View File
@@ -15,3 +15,20 @@ export function register(data: { username: string; password: string; nickname?:
export function getUserInfo() {
return request.get('/user/info')
}
/** 注册状态 */
export interface RegistrationStatus {
enabled: boolean
firstUser: boolean
allowed: boolean
}
/** 查询注册状态(无需登录) */
export function getRegistrationStatus() {
return request.get('/user/registration-status')
}
/** 更新注册开关(需登录) */
export function updateRegistration(enabled: boolean) {
return request.put('/user/registration', { enabled })
}