Files
X-Financial/docs/plans/phase-4-frontend-pages/README.md
WIN-JHFT4D3SIVT\caoxiaozhu 7141e1d11a feat: refactor monolithic App.vue into modular Vue component architecture
- 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
2026-04-28 17:20:52 +08:00

17 KiB
Raw Blame History

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 → 绿色 green
  • medium → 橙色 orange
  • high → 红色 red
  • blocked → 深红 #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 无报错