Files
X-Financial/web/src/views/scripts/ApprovalCenterView.js
caoxiaozhu 619281afc3 feat: 完善系统配置、安全增强与知识库功能
- .env.example: API基础路径改为相对路径 /api/v1,支持代理转发
- README.md: 完善项目结构与启动说明文档
- docker-compose.yml: 新增Docker编排配置,支持容器化部署
- docker/: 新增Docker部署相关文档与配置

- server_start.sh: 重构启动脚本,添加容器环境检测、隔离虚拟环境路径、环境变量覆盖机制
- deps.py: 完善API依赖注入,增强权限验证逻辑
- admin_secret.py: 优化管理员密钥加密存储与验证
- config.py: 扩展配置管理,支持多环境变量绑定
- security.py: 增强安全模块,完善加密与认证机制
- db/base.py: 优化数据库基础架构与连接管理
- main.py: 更新应用入口,整合新模块路由
- models/: 完善系统模型配置,支持模型设置持久化
- repositories/settings.py: 优化设置仓储层,增强数据持久化
- services/settings.py: 重构设置服务,精简代码结构
- router.py: 更新API路由配置

- endpoints/knowledge.py: 新增知识库API端点
- schemas/knowledge.py: 新增知识库数据模型
- services/knowledge.py: 新增知识库业务逻辑
- storage/knowledge/.index.json: 知识库索引存储

- api.js: 完善API服务层,增强错误处理
- bootstrap.js: 优化前端初始化与引导流程
- useSetupView.js / useSystemState.js: 重构组合式函数
- TopBar.vue: 优化顶部导航栏组件
- SettingsView.vue: 重构设置页面UI,增强用户体验
- SetupView.vue / SetupRouteView.vue: 完善引导流程页面
- PoliciesView.vue: 优化策略视图组件
- vite.config.js: 更新Vite构建配置
- web_start.sh: 完善前端启动脚本
- views/scripts/: 优化各业务视图JS逻辑

- settings-view.css: 重构设置页面样式
- setup-view.css: 完善引导页样式
- policies-view.css: 优化策略页样式

- test_auth_service.py: 完善认证服务测试
- test_settings_persistence.py: 增强设置持久化测试
- document/: 新增开发文档与工作日志
2026-05-09 03:04:40 +00:00

285 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { computed, ref } from 'vue'
export default {
name: 'ApprovalCenterView' ,
setup(props, { emit }) {
const activeTab = ref('全部待审')
const selectedRow = ref(null)
const expandedExpenseId = ref(null)
const tabs = ['全部待审', '高风险', '即将超时', '已处理']
const filters = ['法人主体', '费用类型', '风险等级', '金额区间', '所属部门']
const rows = [
{ id: 'RE240712001', applicant: '李文静', avatar: '李', department: '市场部', type: '差旅报销', amount: '¥3,680', time: '07-12 09:20', risk: '中风险', riskTone: 'medium', sla: '4.2h', slaTone: 'safe', node: '财务审批', status: '待审批', statusTone: 'pending' },
{ id: 'RE240712002', applicant: '王志强', avatar: '王', department: '销售部', type: '招待费', amount: '¥1,280', time: '07-12 08:15', risk: '低风险', riskTone: 'low', sla: '8.5h', slaTone: 'safe', node: '部门负责人', status: '待审批', statusTone: 'pending' },
{ id: 'RE240711098', applicant: '刘思雨', avatar: '刘', department: '市场部', type: '差旅报销', amount: '¥6,920', time: '07-11 18:46', risk: '高风险', riskTone: 'high', sla: '0.8h', slaTone: 'danger', node: '财务审批', status: '即将超时', statusTone: 'urgent', spotlight: true },
{ id: 'RE240711087', applicant: '陈晓琳', avatar: '陈', department: '行政部', type: '办公采购', amount: '¥860', time: '07-11 17:32', risk: '低风险', riskTone: 'low', sla: '6.1h', slaTone: 'safe', node: '预算校验', status: '待审批', statusTone: 'pending' },
{ id: 'RE240711076', applicant: '赵明', avatar: '赵', department: '研发中心', type: '其他费用', amount: '¥4,250', time: '07-11 15:10', risk: '中风险', riskTone: 'medium', sla: '2.4h', slaTone: 'warning', node: '部门负责人', status: '待审批', statusTone: 'pending' },
{ id: 'RE240711065', applicant: '孙楠', avatar: '孙', department: '财务部', type: '招待费', amount: '¥560', time: '07-11 13:42', risk: '低风险', riskTone: 'low', sla: '5.7h', slaTone: 'safe', node: '财务审批', status: '待审批', statusTone: 'pending' },
{ id: 'RE240711054', applicant: '周晓彤', avatar: '周', department: '市场部', type: '办公采购', amount: '¥2,150', time: '07-11 11:28', risk: '中风险', riskTone: 'medium', sla: '1.9h', slaTone: 'warning', node: '预算校验', status: '即将超时', statusTone: 'urgent' },
{ id: 'RE240711043', applicant: '吴磊', avatar: '吴', department: '销售部', type: '其他费用', amount: '¥980', time: '07-11 09:05', risk: '低风险', riskTone: 'low', sla: '7.3h', slaTone: 'safe', node: '部门负责人', status: '待审批', statusTone: 'pending' }
]
const visibleRows = computed(() => {
if (activeTab.value === '全部待审') return rows
if (activeTab.value === '高风险') return rows.filter((row) => row.risk === '高风险')
if (activeTab.value === '即将超时') return rows.filter((row) => row.status === '即将超时')
return rows.slice(0, 3).map((row) => ({ ...row, status: '已处理', statusTone: 'done' }))
})
const approvalSteps = [
{ index: 1, label: '提交申请', time: '07-11 08:46', done: true, active: true },
{ index: 2, label: '票据识别', time: '07-11 08:48', done: true, active: true },
{ index: 3, label: '费用归类', time: '07-11 08:49', done: true, active: true },
{ index: 4, label: '部门负责人审批', time: '07-11 11:28', done: true, active: true },
{ index: 5, label: '财务审批', time: '进行中', active: true, current: true },
{ index: 6, label: '归档入账', time: '待处理' }
]
const summaryItems = [
{ label: '行程', value: '北京 → 上海', icon: 'mdi mdi-map-marker-path' },
{ label: '出差区间', value: '07-10 至 07-11', icon: 'mdi mdi-clock-outline' },
{ label: '票据关联', value: '8 条明细 / 7 份材料', icon: 'mdi mdi-file-document-multiple-outline' },
{ label: '成本归属', value: '市场部 · CC-MKT-01', icon: 'mdi mdi-account-group-outline' },
{ label: '支付方式', value: '企业垫付', icon: 'mdi mdi-credit-card-outline' }
]
const heroSummaryItems = computed(() => [
{ label: '单号', value: selectedRow.value?.id ?? '-', icon: 'mdi mdi-pound-box-outline' },
{ label: '报销类型', value: selectedRow.value?.type ?? '-', icon: 'mdi mdi-briefcase-outline' },
...summaryItems
])
const currentProgressRingMotion = {
initial: {
scale: 1,
opacity: 0.34,
},
enter: {
scale: [1, 1.42, 1.78],
opacity: [0.34, 0.16, 0],
transition: {
duration: 3.2,
repeat: Infinity,
repeatType: 'loop',
repeatDelay: 0.85,
ease: 'easeOut',
times: [0, 0.5, 1],
},
},
}
const expenseItems = [
{
id: 'flight-1',
time: '07-10 07:25',
dayLabel: '周三',
name: '机票',
category: '交通',
desc: '北京首都 → 上海虹桥',
detail: 'MU5103 往返经济舱,含行程单',
amount: '¥2,180',
status: '未超标',
tone: 'ok',
attachmentStatus: '已上传',
attachmentTone: 'ok',
attachmentHint: '电子行程单与机票发票齐全',
attachments: ['电子行程单.pdf', '机票发票.pdf'],
riskLabel: '低风险',
riskTone: 'low',
riskText: '票面信息与行程匹配。'
},
{
id: 'taxi-1',
time: '07-10 10:35',
dayLabel: '周三',
name: '出租车',
category: '市内交通',
desc: '虹桥机场 → 静安酒店',
detail: '落地后前往酒店,含过路费',
amount: '¥86',
status: '未超标',
tone: 'ok',
attachmentStatus: '已上传',
attachmentTone: 'ok',
attachmentHint: '已上传 1 张发票',
attachments: ['出租车发票-0710-01.jpg'],
riskLabel: '中风险',
riskTone: 'medium',
riskText: '高峰加价较高,建议顺带核对上车点。'
},
{
id: 'metro-1',
time: '07-10 18:20',
dayLabel: '周三',
name: '地铁',
category: '市内交通',
desc: '静安酒店 → 客户园区',
detail: '2 号线换乘,通勤交通',
amount: '¥12',
status: '未超标',
tone: 'ok',
attachmentStatus: '已上传',
attachmentTone: 'ok',
attachmentHint: '已上传电子票据',
attachments: ['地铁电子票据-0710.png'],
riskLabel: '低风险',
riskTone: 'low',
riskText: '路线与拜访行程一致。'
},
{
id: 'taxi-2',
time: '07-11 08:40',
dayLabel: '周四',
name: '出租车',
category: '市内交通',
desc: '静安酒店 → 客户园区',
detail: '次日早会前往客户现场',
amount: '¥42',
status: '未超标',
tone: 'ok',
attachmentStatus: '未上传',
attachmentTone: 'missing',
attachmentHint: '缺少对应发票',
attachments: [],
riskLabel: '高风险',
riskTone: 'high',
riskText: '票据缺失,当前无法完成交通费核验。'
},
{
id: 'taxi-3',
time: '07-11 20:55',
dayLabel: '周四',
name: '出租车',
category: '返程交通',
desc: '客户园区 → 虹桥机场',
detail: '夜间返程,触发超标校验',
amount: '¥136',
status: '超标 ¥28',
tone: 'bad',
attachmentStatus: '已上传',
attachmentTone: 'ok',
attachmentHint: '已上传 1 张发票',
attachments: ['出租车发票-0711-02.jpg'],
riskLabel: '中风险',
riskTone: 'medium',
riskText: '金额超差旅标准 ¥28需补充业务说明。'
},
{
id: 'hotel-1',
time: '07-10 至 07-11',
dayLabel: '2 晚',
name: '酒店',
category: '住宿',
desc: '上海静安商务酒店',
detail: '标准大床房 2 晚,含早餐',
amount: '¥2,480',
status: '未超标',
tone: 'ok',
attachmentStatus: '部分上传',
attachmentTone: 'partial',
attachmentHint: '发票已上传,入住清单缺失',
attachments: ['酒店发票.jpg'],
riskLabel: '高风险',
riskTone: 'high',
riskText: '缺少入住清单,住宿真实性待补证。'
},
{
id: 'meal-1',
time: '07-10 至 07-11',
dayLabel: '2 天',
name: '餐补',
category: '补贴',
desc: '差旅餐补',
detail: '按差旅制度自动计算',
amount: '¥372',
status: '未超标',
tone: 'ok',
attachmentStatus: '免上传',
attachmentTone: 'neutral',
attachmentHint: '制度型补贴无需票据',
attachments: [],
riskLabel: '低风险',
riskTone: 'low',
riskText: '系统自动核算,无额外异常。'
},
{
id: 'other-1',
time: '07-11 09:10',
dayLabel: '周四',
name: '其他',
category: '杂费',
desc: '行李寄存 / 打印费',
detail: '客户提案资料打印与寄存服务',
amount: '¥1,612',
status: '未超标',
tone: 'ok',
attachmentStatus: '已上传',
attachmentTone: 'ok',
attachmentHint: '已上传 2 份附件',
attachments: ['打印服务发票.jpg', '行李寄存凭证.jpg'],
riskLabel: '低风险',
riskTone: 'low',
riskText: '用途清晰,金额在授权范围内。'
}
]
const expenseTotal = '¥6,920'
const uploadedExpenseCount = computed(() => expenseItems.filter((item) => item.attachments.length).length)
const showExpenseRisk = (item) => item.riskTone === 'medium' || item.riskTone === 'high'
const toggleExpenseAttachments = (id) => {
expandedExpenseId.value = expandedExpenseId.value === id ? null : id
}
const attachments = [
{ name: '机票.pdf', size: '256 KB', icon: 'mdi mdi-file-pdf-box', iconClass: 'pdf' },
{ name: '酒店发票.jpg', size: '412 KB', icon: 'mdi mdi-image', iconClass: 'img' },
{ name: '行程单.pdf', size: '198 KB', icon: 'mdi mdi-file-pdf-box', iconClass: 'pdf' },
{ name: '出租车发票1.jpg', size: '128 KB', icon: 'mdi mdi-image', iconClass: 'img' },
{ name: '出租车发票2.jpg', size: '132 KB', icon: 'mdi mdi-image', iconClass: 'img' },
{ name: '酒店入住清单', size: '缺失', icon: 'mdi mdi-minus-circle', iconClass: 'miss', missing: true }
]
const riskItems = [
{ text: '酒店入住清单缺失', level: '高', tone: 'high', icon: 'mdi mdi-alert-circle' },
{ text: '1 笔出租车费用超差旅标准 ¥28', level: '中', tone: 'medium', icon: 'mdi mdi-alert' },
{ text: '发票抬头识别为个人,建议核对', level: '中', tone: 'medium', icon: 'mdi mdi-lightbulb-on' }
]
const flowItems = [
{ label: '提交申请', desc: '刘思雨 提交申请', time: '07-11 08:46', icon: 'mdi mdi-check' },
{ label: '票据识别', desc: 'AI 自动识别完成', time: '07-11 08:48', icon: 'mdi mdi-check' },
{ label: '费用归类', desc: '费用归类完成', time: '07-11 08:49', icon: 'mdi mdi-check' },
{ label: '部门负责人审批', desc: '李文静 已通过', time: '07-11 11:28', icon: 'mdi mdi-check' },
{ label: '财务审批', desc: '张晓明 审批中', time: '进行中', icon: 'mdi mdi-circle-slice-8', current: true },
{ label: '归档入账', desc: '待处理', time: '-', icon: 'mdi mdi-circle-outline', pending: true }
]
return {
activeTab,
selectedRow,
expandedExpenseId,
tabs,
filters,
rows,
visibleRows,
approvalSteps,
summaryItems,
heroSummaryItems,
currentProgressRingMotion,
expenseItems,
expenseTotal,
uploadedExpenseCount,
showExpenseRisk,
toggleExpenseAttachments,
attachments,
riskItems,
flowItems
}
}
}