- Extract 711-line App.vue into 15+ focused files across 5 directories - Add data layer (icons, metrics, policies, auditTrail, requests) - Add composables (useNavigation, useRequests, useChat, useToast) - Add layout components (SidebarRail, TopBar, FilterBar) - Add shared components (PanelHead, InfoRow, ToastNotification) - Add business component (RequestTable) and 5 view components - Extract global CSS to assets/styles/global.css - Add start.sh with WSL/Windows cross-platform support - Add .gitignore for node_modules, dist, and IDE dirs
Phase 4: 前端核心页面(W4-W5)
目标: 实现所有核心前端页面和组件,完成用户交互界面。
周期: 第 4 ~ 5 周
任务数: 4 个
可并行: 4 个任务可由 1-2 名前端工程师并行开发
前置依赖: Phase 1(前端骨架)
备注: 可与 Phase 3 后半段并行开始
本阶段交付物
| 交付物 | 说明 |
|---|---|
| 报销入口页 | 对话式报销入口 + 快捷操作 |
| 票据上传页 | 文件上传组件 + 票据类型选择 |
| 报销草稿页 | 费用明细表格 + 可编辑字段 |
| 预审结果页 | 风险展示 + 规则命中详情 |
| 补件交互页 | 补件清单 + 上传/回复 |
| 提交确认页 | 最终确认 + 同步状态 |
| 审计日志页 | 操作时间线 |
任务清单
Task 4.1: 报销入口页 + 上传组件
负责人: 前端工程师
预计工时: 2 天
前置依赖: Phase 1(前端骨架)
Files:
-
Create:
frontend/src/views/HomeView.vue -
Create:
frontend/src/views/UploadView.vue -
Create:
frontend/src/components/FileUpload.vue -
Create:
frontend/src/stores/task.ts -
Create:
frontend/src/api/task.ts -
Create:
frontend/src/api/document.ts -
Step 1: 实现 API 调用层
frontend/src/api/task.ts:
import api from './index'
export const createTask = (data: {
userId: string
companyId: string
userIntent: string
entryChannel?: string
}) => api.post('/reimbursement/tasks', data)
export const getTask = (taskId: string) =>
api.get(`/reimbursement/tasks/${taskId}`)
export const listTasks = (params?: { userId?: string; status?: string; page?: number; size?: number }) =>
api.get('/reimbursement/tasks', { params })
export const runAgent = (taskId: string, startFrom = 'intake', mode = 'precheck') =>
api.post(`/reimbursement/tasks/${taskId}/agent/run`, { start_from: startFrom, mode })
frontend/src/api/document.ts:
import api from './index'
export const uploadDocument = (taskId: string, file: File, documentType: string) => {
const formData = new FormData()
formData.append('file', file)
formData.append('document_type', documentType)
return api.post(`/reimbursement/tasks/${taskId}/documents`, formData, {
headers: { 'Content-Type': 'multipart/form-data' },
})
}
export const listDocuments = (taskId: string) =>
api.get(`/reimbursement/tasks/${taskId}/documents`)
- Step 2: 实现 Pinia Store
frontend/src/stores/task.ts:
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { createTask, getTask, listTasks, runAgent } from '@/api/task'
export const useTaskStore = defineStore('task', () => {
const currentTask = ref<any>(null)
const taskList = ref<any[]>([])
const loading = ref(false)
async function create(userIntent: string) {
loading.value = true
try {
const { data } = await createTask({
userId: 'U001', // TODO: 从登录态获取
companyId: 'C001',
userIntent,
})
currentTask.value = data
return data
} finally {
loading.value = false
}
}
async function fetchTask(taskId: string) {
const { data } = await getTask(taskId)
currentTask.value = data
return data
}
async function startAgent(taskId: string, startFrom = 'intake') {
loading.value = true
try {
const { data } = await runAgent(taskId, startFrom)
return data
} finally {
loading.value = false
}
}
return { currentTask, taskList, loading, create, fetchTask, startAgent }
})
- Step 3: 实现报销入口页 HomeView
按开发文档 9.2 节:
- 对话输入框:用户输入报销意图(如"我要报这次北京出差的费用")
- 上传按钮:直接跳转到上传页
- 最近任务列表:显示用户最近的报销任务和状态
- 常用报销类型快捷按钮:
- "报差旅"
- "看发票能不能报"
- "帮我生成报销单"
- "这张发票为什么不合规?"
- 智能引导提示:根据用户输入实时提示
交互流程:用户输入意图 → 调用 taskStore.create() → 跳转到 /task/{taskId}/upload
- Step 4: 实现文件上传组件 FileUpload
frontend/src/components/FileUpload.vue:
Ant Design Vue 的 a-upload-dragger 封装:
- 支持拖拽上传
- 支持多文件选择
- 文件类型校验(PDF、JPG、PNG、OFD)
- 单文件大小限制(默认 10MB)
- 上传进度条
- 预览缩略图
- 已上传文件列表
- 删除已上传文件
Props:
interface Props {
taskId: string
accept?: string // 默认 '.pdf,.jpg,.jpeg,.png,.ofd'
maxFileSize?: number // MB,默认 10
maxCount?: number // 默认 10
}
-
Step 5: 实现票据上传页 UploadView
-
引用 FileUpload 组件
-
票据类型下拉选择(Ant Design Select):
- 增值税发票 (vat_invoice)
- 火车票 (train_ticket)
- 机票行程单 (flight_itinerary)
- 打车票据 (taxi_receipt)
- 酒店流水 (hotel_bill)
- 支付截图 (payment_screenshot)
- 其他附件 (other_attachment)
-
已上传文件列表展示
-
"开始识别" 按钮 → 调用
taskStore.startAgent()→ 跳转到草稿页 -
返回按钮 → 回到首页
-
Step 6: Commit
git add frontend/
git commit -m "feat: 实现报销入口页和票据上传页"
Task 4.2: 报销草稿页
负责人: 前端工程师
预计工时: 2 天
前置依赖: Task 4.1
可并行于: Task 4.3(如果两人并行)
Files:
-
Create:
frontend/src/views/DraftView.vue -
Create:
frontend/src/components/ExpenseTable.vue -
Create:
frontend/src/api/precheck.ts -
Step 1: 添加预审 API
frontend/src/api/precheck.ts:
import api from './index'
export const getDraft = (taskId: string) =>
api.get(`/reimbursement/tasks/${taskId}/draft`)
export const getPrecheckResult = (taskId: string) =>
api.get(`/reimbursement/tasks/${taskId}/precheck-result`)
- Step 2: 实现 ExpenseTable 组件
frontend/src/components/ExpenseTable.vue:
Ant Design Table 展示费用明细:
| 列名 | 字段 | 可编辑 | 说明 |
|---|---|---|---|
| 费用类型 | expense_type | ✅ | 下拉选择 |
| 金额 | amount | ✅ | 数字输入 |
| 税额 | tax_amount | ✅ | 数字输入 |
| 发生日期 | occurred_at | ✅ | 日期选择 |
| 城市 | city | ✅ | 文本输入 |
| 商户 | vendor_name | ✅ | 文本输入 |
| 风险等级 | risk_level | ❌ | 彩色标签 |
风险等级标签颜色映射:
low→ 绿色greenmedium→ 橙色orangehigh→ 红色redblocked→ 深红#cf1322
支持行内编辑(点击单元格进入编辑模式)。
- Step 3: 实现报销草稿页 DraftView
按开发文档 9.3 节布局:
┌─────────────────────────────────────────────┐
│ 报销草稿 [预审按钮] │
├─────────────────────────────────────────────┤
│ 基本信息 │
│ ┌──────────┬──────────┬──────────┐ │
│ │ 报销人 │ 部门 │ 成本中心 │ │
│ └──────────┴──────────┴──────────┘ │
│ ┌──────────┬──────────┐ │
│ │ 项目 │ 报销事由 │ │
│ └──────────┴──────────┘ │
├─────────────────────────────────────────────┤
│ 费用明细 │
│ ┌─────────────────────────────────────────┐ │
│ │ ExpenseTable 组件 │ │
│ └─────────────────────────────────────────┘ │
│ 总金额:¥ 2,380.00 │
├─────────────────────────────────────────────┤
│ 票据附件 │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │ 📄 │ │ 📄 │ │ 📄 │ (缩略图 + 文件名) │
│ └────┘ └────┘ └────┘ │
├─────────────────────────────────────────────┤
│ 预审状态:⏳ 待预审 │
│ [执行预审] │
└─────────────────────────────────────────────┘
交互:
-
页面加载时调用
getDraft(taskId)获取草稿数据 -
编辑字段后暂存到本地 state
-
点击"执行预审" → 调用
taskStore.startAgent(taskId, 'precheck')→ 跳转到预审结果页 -
Step 4: Commit
git add frontend/
git commit -m "feat: 实现报销草稿页和费用明细表格组件"
Task 4.3: 预审结果页 + 补件交互页
负责人: 前端工程师
预计工时: 2.5 天
前置依赖: Task 4.1
可并行于: Task 4.2(如果两人并行)
Files:
-
Create:
frontend/src/views/PrecheckView.vue -
Create:
frontend/src/views/SupplementView.vue -
Create:
frontend/src/components/RuleHitCard.vue -
Create:
frontend/src/api/supplement.ts -
Step 1: 添加补件 API
frontend/src/api/supplement.ts:
import api from './index'
export const respondSupplement = (taskId: string, supplementRequestId: string, data: {
responseText: string
documentIds?: string[]
}) => api.post(`/reimbursement/tasks/${taskId}/supplements`, {
supplement_request_id: supplementRequestId,
...data,
})
export const submitTask = (taskId: string, submitTo: string = 'expense_system') =>
api.post(`/reimbursement/tasks/${taskId}/submit`, { confirmed: true, submit_to: submitTo })
export const getSyncStatus = (taskId: string) =>
api.get(`/reimbursement/tasks/${taskId}/sync-status`)
- Step 2: 实现 RuleHitCard 组件
frontend/src/components/RuleHitCard.vue:
Ant Design Card 展示单条规则命中:
┌─────────────────────────────────────────┐
│ 🔴 住宿费超标 TRAVEL_HOTEL_LIMIT │
├─────────────────────────────────────────┤
│ 问题:住宿费超出当前城市和职级标准 │
│ 制度依据:差旅报销制度-住宿标准 │
│ 建议:请补充超标说明或发起特殊审批 │
│ [展开详情] │
└─────────────────────────────────────────┘
Props:
interface Props {
ruleCode: string
ruleName: string
severity: string // low / medium / high / blocked
action: string
message: string
suggestion: string
policyRef: string
hitDetail?: object
}
- Step 3: 实现预审结果页 PrecheckView
按开发文档 9.4 节:
- 总体结论卡片:
- ✅ 通过 → 绿色
- ⚠️ 需补件 → 橙色
- 🚫 有阻断 → 红色
- 风险等级指示:彩色 Badge
- 通过项列表:绿色勾选图标 + 规则名称
- 风险项列表:使用 RuleHitCard 组件
- 缺件项列表:橙色提示 + 补件按钮
- 操作按钮:
- "一键补件" → 跳转到补件页(仅在有缺件时显示)
- "确认提交" → 跳转到确认页(仅预审通过时可用)
交互:
-
页面加载时调用
getPrecheckResult(taskId)获取预审结果 -
根据结果渲染不同状态
-
Step 4: 实现补件交互页 SupplementView
-
待补件清单:从预审结果的 rule_hits 中过滤出
require_attachment/require_explanation类型 -
每个补件项:
- 类型标签(补充附件 / 补充说明 / 修改字段)
- 提示文案
- 操作区域:
- 补充附件:调用 FileUpload 组件
- 补充说明:文本输入框
-
提交补件按钮 → 调用
respondSupplement()→ 跳转回预审页重新预审 -
Step 5: Commit
git add frontend/
git commit -m "feat: 实现预审结果页和补件交互页"
Task 4.4: 提交确认页 + 审计日志页
负责人: 前端工程师
预计工时: 1.5 天
前置依赖: Task 4.3
Files:
-
Create:
frontend/src/views/ConfirmView.vue -
Create:
frontend/src/views/AuditView.vue -
Create:
frontend/src/api/audit.ts -
Step 1: 添加审计 API
frontend/src/api/audit.ts:
import api from './index'
export const getAuditLogs = (params?: {
target_type?: string
target_id?: string
actor?: string
page?: number
size?: number
}) => api.get('/audit/logs', { params })
- Step 2: 实现提交确认页 ConfirmView
┌─────────────────────────────────────────────┐
│ 提交确认 │
├─────────────────────────────────────────────┤
│ 报销单摘要(不可编辑) │
│ ┌───────────────────────────────────────┐ │
│ │ 报销人:张三 部门:技术部 │ │
│ │ 事由:北京出差 总金额:¥2,380.00 │ │
│ └───────────────────────────────────────┘ │
│ │
│ 费用明细汇总: │
│ ┌───────────────────────────────────────┐ │
│ │ 差旅住宿费 ¥1,200.00 │ │
│ │ 差旅交通费 ¥ 553.00 │ │
│ │ 差旅餐补 ¥ 627.00 │ │
│ └───────────────────────────────────────┘ │
│ │
│ 附件清单:3 个文件 │
│ 同步目标:费控系统 │
│ │
│ [返回修改] [确认提交] │
├─────────────────────────────────────────────┤
│ 同步状态:⏳ 提交中... │
└─────────────────────────────────────────────┘
交互:
-
"确认提交" → 调用
submitTask(taskId) -
提交后轮询
getSyncStatus(taskId),展示同步进度 -
同步成功 → 显示后端单据号
-
同步失败 → 显示错误信息 + 重试按钮
-
Step 3: 实现审计日志页 AuditView
按开发文档 9.5 节(简化版):
- Ant Design Timeline 展示操作记录
- 筛选栏:按任务ID、操作类型、时间范围筛选
- 每条日志:
- 时间戳
- 操作人
- 操作类型(彩色标签)
- 详情(可展开)
操作类型颜色映射:
-
file_upload→ 蓝色 -
ocr_recognize→ 青色 -
agent_call→ 紫色 -
rule_hit→ 橙色 -
supplement_request/supplement_respond→ 绿色 -
user_confirm→ 金色 -
backend_sync→ 灰色 -
Step 4: Commit
git add frontend/
git commit -m "feat: 实现提交确认页和审计日志页"
本阶段完成检查
- 首页能创建任务并跳转到上传页
- 上传页能上传文件并开始识别
- 草稿页能展示费用明细并支持编辑
- 预审结果页能展示风险项和缺件项
- 补件页能上传附件和填写说明
- 确认页能展示摘要和同步状态
- 审计日志页能展示操作时间线
- 所有页面响应式布局正常
- 前端
npm run build无报错