feat: 添加 AI 分类功能,支持交易自动分类与标签生成
This commit is contained in:
@@ -1,12 +1,20 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { DEFAULT_CATEGORY_BUDGETS } from '../config/transactionCategories.js'
|
||||
import { AI_MODEL_OPTIONS, AI_PROVIDER_OPTIONS } from '../config/transactionTags.js'
|
||||
|
||||
const AI_PROVIDER_VALUES = AI_PROVIDER_OPTIONS.map((item) => item.value)
|
||||
const AI_MODEL_VALUES = AI_MODEL_OPTIONS.map((item) => item.value)
|
||||
|
||||
export const useSettingsStore = defineStore(
|
||||
'settings',
|
||||
() => {
|
||||
const notificationCaptureEnabled = ref(true)
|
||||
const aiAutoCategoryEnabled = ref(false)
|
||||
const aiProvider = ref('deepseek')
|
||||
const aiApiKey = ref('')
|
||||
const aiModel = ref('deepseek-chat')
|
||||
const aiAutoApplyThreshold = ref(0.9)
|
||||
const monthlyBudget = ref(12000)
|
||||
const budgetResetCycle = ref('monthly')
|
||||
const budgetMonthlyResetDay = ref(1)
|
||||
@@ -24,6 +32,27 @@ export const useSettingsStore = defineStore(
|
||||
aiAutoCategoryEnabled.value = !!value
|
||||
}
|
||||
|
||||
const setAiProvider = (value) => {
|
||||
aiProvider.value = AI_PROVIDER_VALUES.includes(value) ? value : 'deepseek'
|
||||
}
|
||||
|
||||
const setAiApiKey = (value) => {
|
||||
aiApiKey.value = String(value || '').trim()
|
||||
}
|
||||
|
||||
const setAiModel = (value) => {
|
||||
aiModel.value = AI_MODEL_VALUES.includes(value) ? value : 'deepseek-chat'
|
||||
}
|
||||
|
||||
const setAiAutoApplyThreshold = (value) => {
|
||||
const numeric = Number(value)
|
||||
if (!Number.isFinite(numeric)) {
|
||||
aiAutoApplyThreshold.value = 0.9
|
||||
return
|
||||
}
|
||||
aiAutoApplyThreshold.value = Math.min(Math.max(numeric, 0), 1)
|
||||
}
|
||||
|
||||
const setMonthlyBudget = (value) => {
|
||||
const numeric = Number(value)
|
||||
monthlyBudget.value = Number.isFinite(numeric) && numeric >= 0 ? numeric : 0
|
||||
@@ -72,6 +101,10 @@ export const useSettingsStore = defineStore(
|
||||
return {
|
||||
notificationCaptureEnabled,
|
||||
aiAutoCategoryEnabled,
|
||||
aiProvider,
|
||||
aiApiKey,
|
||||
aiModel,
|
||||
aiAutoApplyThreshold,
|
||||
monthlyBudget,
|
||||
budgetResetCycle,
|
||||
budgetMonthlyResetDay,
|
||||
@@ -82,6 +115,10 @@ export const useSettingsStore = defineStore(
|
||||
profileAvatar,
|
||||
setNotificationCaptureEnabled,
|
||||
setAiAutoCategoryEnabled,
|
||||
setAiProvider,
|
||||
setAiApiKey,
|
||||
setAiModel,
|
||||
setAiAutoApplyThreshold,
|
||||
setMonthlyBudget,
|
||||
setBudgetResetCycle,
|
||||
setBudgetMonthlyResetDay,
|
||||
@@ -97,6 +134,10 @@ export const useSettingsStore = defineStore(
|
||||
paths: [
|
||||
'notificationCaptureEnabled',
|
||||
'aiAutoCategoryEnabled',
|
||||
'aiProvider',
|
||||
'aiApiKey',
|
||||
'aiModel',
|
||||
'aiAutoApplyThreshold',
|
||||
'monthlyBudget',
|
||||
'budgetResetCycle',
|
||||
'budgetMonthlyResetDay',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { maybeEnrichTransactionWithAi } from '../services/ai/aiService.js'
|
||||
import {
|
||||
deleteTransaction,
|
||||
fetchTransactions,
|
||||
@@ -26,6 +27,9 @@ const formatDayLabel = (dayKey) => {
|
||||
}).format(localDate)
|
||||
}
|
||||
|
||||
const replaceTransaction = (list, nextTransaction) =>
|
||||
list.map((tx) => (tx.id === nextTransaction.id ? nextTransaction : tx))
|
||||
|
||||
export const useTransactionStore = defineStore(
|
||||
'transactions',
|
||||
() => {
|
||||
@@ -113,6 +117,12 @@ export const useTransactionStore = defineStore(
|
||||
}
|
||||
}
|
||||
|
||||
const enrichTransactionInBackground = async (transaction) => {
|
||||
const enriched = await maybeEnrichTransactionWithAi(transaction)
|
||||
if (!enriched || enriched.id !== transaction.id) return
|
||||
transactions.value = replaceTransaction(transactions.value, enriched)
|
||||
}
|
||||
|
||||
const addTransaction = async (payload) => {
|
||||
const normalized = {
|
||||
...payload,
|
||||
@@ -120,6 +130,7 @@ export const useTransactionStore = defineStore(
|
||||
}
|
||||
const created = await insertTransaction(normalized)
|
||||
transactions.value = [created, ...transactions.value]
|
||||
void enrichTransactionInBackground(created)
|
||||
return created
|
||||
}
|
||||
|
||||
@@ -130,7 +141,8 @@ export const useTransactionStore = defineStore(
|
||||
}
|
||||
const updated = await updateTransaction(normalized)
|
||||
if (updated) {
|
||||
transactions.value = transactions.value.map((tx) => (tx.id === updated.id ? updated : tx))
|
||||
transactions.value = replaceTransaction(transactions.value, updated)
|
||||
void enrichTransactionInBackground(updated)
|
||||
}
|
||||
return updated
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user