feat:添加AI功能

This commit is contained in:
2025-11-13 14:43:48 +08:00
parent bce8bdf9ef
commit 5cf6de697b
11 changed files with 408 additions and 14 deletions

View File

@@ -5,6 +5,7 @@ import LucideIcon from '../../../components/common/LucideIcon.vue';
import { useTransactionQuery } from '../../../composables/useTransaction';
import { useUpdateTransactionMutation } from '../../../composables/useTransactions';
import { PRESET_CATEGORIES } from '../../../lib/categories';
import { apiClient } from '../../../lib/api/client';
const route = useRoute();
const router = useRouter();
@@ -27,6 +28,53 @@ const saveCategory = async () => {
await updateMutation.mutateAsync({ id: txn.value.id, payload: { category: editing.category || '未分类' } });
await query.refetch();
};
const feedback = ref<string | null>(null);
const show = (msg: string) => {
feedback.value = msg;
setTimeout(() => (feedback.value = null), 2000);
};
const useAiClassify = async () => {
if (!txn.value?.id) return;
try {
await apiClient.post(`/transactions/${txn.value.id}/ai-classify`);
await query.refetch();
show('已使用 AI 分类');
} catch (e) {
show('AI 分类失败');
}
};
const createBlacklistRule = async () => {
if (!txn.value?.id) return;
try {
await apiClient.post(`/transactions/${txn.value.id}/rules/blacklist`);
show('已加入黑名单规则');
} catch (e) {
show('创建黑名单失败');
}
};
const createRuleFromNotification = async () => {
if (!txn.value?.id) return;
try {
await apiClient.post(`/transactions/${txn.value.id}/rules/from-notification`);
show('已根据该通知创建规则');
} catch (e) {
show('创建规则失败');
}
};
const aiSuggestRule = async () => {
if (!txn.value?.id) return;
try {
await apiClient.post(`/transactions/${txn.value.id}/rules/ai-suggest`);
show('已创建 AI 规则草案');
} catch (e) {
show('AI 规则分析失败');
}
};
</script>
<template>
@@ -78,7 +126,7 @@ const saveCategory = async () => {
</div>
</div>
<div v-if="isNotification" class="bg-white rounded-2xl p-6 border border-gray-100">
<div v-if="isNotification" class="bg-white rounded-2xl p-6 border border-gray-100 space-y-4">
<h3 class="text-base font-semibold text-gray-900 mb-4">手工分类</h3>
<div class="space-y-3">
<div class="flex items-center space-x-3">
@@ -97,6 +145,16 @@ const saveCategory = async () => {
</button>
</div>
</div>
<div class="h-px bg-gray-100"></div>
<h3 class="text-base font-semibold text-gray-900">快捷操作</h3>
<div class="grid grid-cols-2 gap-3">
<button class="px-3 py-2 border border-gray-200 rounded-xl text-sm" @click="useAiClassify">使用 AI 分类</button>
<button class="px-3 py-2 border border-gray-200 rounded-xl text-sm" @click="createBlacklistRule">避免此类通知</button>
<button class="px-3 py-2 border border-gray-200 rounded-xl text-sm" @click="createRuleFromNotification">使用该通知生成规则</button>
<button class="px-3 py-2 border border-gray-200 rounded-xl text-sm" @click="aiSuggestRule">AI 分析规则</button>
</div>
<p v-if="feedback" class="text-xs text-emerald-600 text-right">{{ feedback }}</p>
</div>
<div v-if="txn.metadata && Object.keys(txn.metadata).length" class="bg-white rounded-2xl p-6 border border-gray-100">