- 新增邮箱配置、发件人规则、待处理账单三张表(SQLite/MySQL 双脚本)及 CRUD 接口 - 按邮件发件人匹配账单类型,未命中忽略;发件人规则可配置解压密码与默认分类/标签 - 支持 IMAP IDLE 实时监听、定时兜底与手动立即检查;拉取范围可配置(仅新邮件/最近 N 天/最近 N 封) - 附件保存至本地 data/email-bill,解析预览后手动导入,复用账单解析与规则引擎 - 立即检查通过 SSE 实时推送执行进度 - 前端新增「邮箱账单」页(邮箱配置/发件人规则/待处理账单三 Tab),支持子路由与 Tab 偏好记忆,配置弹窗提供常用 IMAP 服务器候选项 - 新用户注册自动初始化默认发件人规则(支付宝/微信/美团/招商银行/交通银行) - 抽取共用账单预览与结果组件,供上传导入与邮箱账单复用 同时包含: - 统计新增口径筛选(仅计入/全部/仅不计入),支付方式改为后端动态获取 - 统一实体 createdAt/updatedAt 位置至 id 之后,调整部分日志级别
151 lines
5.0 KiB
TypeScript
151 lines
5.0 KiB
TypeScript
// 路由配置文件:定义应用的所有路由及导航守卫
|
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
import { useUserStore } from '../store/user'
|
|
import { useDatabaseStore } from '../store/database'
|
|
import { useRegistrationStore } from '../store/registration'
|
|
|
|
// 创建路由实例,使用 HTML5 History 模式
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes: [
|
|
{
|
|
path: '/database-setup',
|
|
name: 'DatabaseSetup',
|
|
component: () => import('../views/DatabaseSettings.vue'), // 首次数据库配置引导页(无需登录)
|
|
},
|
|
{
|
|
path: '/login',
|
|
name: 'Login',
|
|
component: () => import('../views/Login.vue'), // 登录页
|
|
},
|
|
{
|
|
path: '/register',
|
|
name: 'Register',
|
|
component: () => import('../views/Register.vue'), // 注册页
|
|
},
|
|
{
|
|
path: '/bill-import',
|
|
name: 'BillImport',
|
|
component: () => import('../views/BillImport.vue'), // 账单导入(独立页,无侧边栏)
|
|
},
|
|
{
|
|
path: '/',
|
|
component: () => import('../views/Layout.vue'), // 主布局(带侧边栏)
|
|
redirect: '/dashboard', // 默认跳转到统计面板
|
|
children: [
|
|
{
|
|
path: 'dashboard',
|
|
name: 'Dashboard',
|
|
component: () => import('../views/Dashboard.vue'), // 统计面板
|
|
},
|
|
{
|
|
path: 'transactions',
|
|
name: 'Transactions',
|
|
component: () => import('../views/TransactionList.vue'), // 收支记录
|
|
},
|
|
{
|
|
path: 'categories',
|
|
name: 'Categories',
|
|
component: () => import('../views/CategoryManage.vue'), // 分类管理
|
|
},
|
|
{
|
|
path: 'tags',
|
|
name: 'Tags',
|
|
component: () => import('../views/TagManage.vue'), // 标签管理
|
|
},
|
|
{
|
|
path: 'rules',
|
|
name: 'Rules',
|
|
component: () => import('../views/RuleManage.vue'), // 规则管理(自定义分类与标签规则)
|
|
},
|
|
{
|
|
path: 'email-bills',
|
|
// 跳转到上次访问的标签页,无记录时默认邮箱配置
|
|
redirect: () => {
|
|
const tabs = ['configs', 'senderRules', 'messages']
|
|
const saved = typeof localStorage !== 'undefined' ? localStorage.getItem('emailBill.tab') : null
|
|
return `/email-bills/${saved && tabs.includes(saved) ? saved : 'configs'}`
|
|
},
|
|
},
|
|
{
|
|
path: 'email-bills/:tab(configs|senderRules|messages)',
|
|
name: 'EmailBills',
|
|
component: () => import('../views/EmailBillManage.vue'), // 邮箱账单(邮箱配置/发件人规则/待处理账单)
|
|
},
|
|
{
|
|
path: 'settings',
|
|
name: 'Settings',
|
|
component: () => import('../views/Settings.vue'), // 系统设置(数据库 + AI 模型)
|
|
},
|
|
{
|
|
path: 'ai-usage',
|
|
name: 'AiUsage',
|
|
component: () => import('../views/AiUsage.vue'), // 模型使用情况
|
|
},
|
|
{
|
|
path: 'logs',
|
|
// 跳转到上次访问的日志标签页,无记录时默认访问日志
|
|
redirect: () => {
|
|
const tabs = ['http', 'login', 'app']
|
|
const saved = typeof localStorage !== 'undefined' ? localStorage.getItem('logs.tab') : null
|
|
return `/logs/${saved && tabs.includes(saved) ? saved : 'http'}`
|
|
},
|
|
},
|
|
{
|
|
path: 'logs/:tab(http|login|app)',
|
|
name: 'Logs',
|
|
component: () => import('../views/Logs.vue'), // 系统日志(访问日志/登录日志/运行日志)
|
|
},
|
|
],
|
|
},
|
|
],
|
|
})
|
|
|
|
// 全局前置守卫:优先校验数据库配置,再校验登录状态
|
|
router.beforeEach(async (to, _from, next) => {
|
|
const databaseStore = useDatabaseStore()
|
|
// 首次进入时从后端加载数据库配置状态
|
|
if (!databaseStore.loaded) {
|
|
await databaseStore.load()
|
|
}
|
|
|
|
// 数据库未配置:强制引导到配置页,避免用户卡在无法登录的状态
|
|
if (!databaseStore.configured) {
|
|
if (to.path === '/database-setup') {
|
|
next()
|
|
} else {
|
|
next('/database-setup')
|
|
}
|
|
return
|
|
}
|
|
|
|
// 已配置数据库:配置引导页不再需要,跳转到登录或首页
|
|
if (to.path === '/database-setup') {
|
|
const userStore = useUserStore()
|
|
next(userStore.token ? '/dashboard' : '/login')
|
|
return
|
|
}
|
|
|
|
// 注册功能关闭且已有用户时,不允许访问注册页
|
|
if (to.path === '/register') {
|
|
const registrationStore = useRegistrationStore()
|
|
if (!registrationStore.loaded) {
|
|
await registrationStore.load()
|
|
}
|
|
if (!registrationStore.status?.allowed) {
|
|
next('/login')
|
|
return
|
|
}
|
|
}
|
|
|
|
const userStore = useUserStore()
|
|
// 如果目标页面不是登录/注册页,且没有 token,则重定向到登录页并记录来源,登录后可回跳
|
|
if (to.path !== '/login' && to.path !== '/register' && !userStore.token) {
|
|
next({ path: '/login', query: { redirect: to.fullPath } })
|
|
} else {
|
|
next()
|
|
}
|
|
})
|
|
|
|
export default router
|