feat: 优化差旅报销预审流程与个人工作台 UI 体系

- 完善 user_agent_application 申请差旅报销预审槽位与消息组装
- 增强预算助理报告与风险建议卡片交互
- 重构登录页视觉样式与移动端响应式适配
- 优化个人工作台、文档中心、政策中心、员工管理等页面布局
- 拆分 travelRequestDetailPreReviewModel 为 advice/submit 模型
- 补充报销草稿、风险复核、Item Sync 与模板执行器测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-02 14:01:51 +08:00
parent 92444e7eae
commit ca691f3ee0
107 changed files with 5663 additions and 1542 deletions

View File

@@ -11,7 +11,7 @@ from pathlib import Path
from types import SimpleNamespace
from typing import Any
from sqlalchemy import func, or_, select
from sqlalchemy import delete, func, or_, select
from sqlalchemy import inspect as sqlalchemy_inspect
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session, selectinload
@@ -21,6 +21,8 @@ from app.core.agent_enums import AgentAssetDomain, AgentAssetStatus, AgentAssetT
from app.models.agent_asset import AgentAsset
from app.models.employee import Employee
from app.models.financial_record import ExpenseClaim, ExpenseClaimItem
from app.models.hermes_report import HermesRiskReport
from app.models.risk_observation import RiskObservation, RiskObservationFeedback
from app.schemas.ontology import OntologyEntity, OntologyParseResult
from app.schemas.reimbursement import (
ExpenseClaimItemCreate,
@@ -560,6 +562,9 @@ class ExpenseClaimService(
if claim is None:
return None
if self._is_expense_application_claim(claim) and not current_user.is_admin:
raise ValueError("申请单只有系统管理员可以删除。")
if self._access_policy.is_archived_claim(claim) and not current_user.is_admin:
raise ValueError("已归档单据不能删除,只有高级管理员可以执行删除。")
@@ -572,6 +577,7 @@ class ExpenseClaimService(
resource_id = claim.id
self._release_budget_for_delete(claim, current_user)
self._delete_claim_analysis_records(resource_id)
self._attachment_storage.delete_claim_files(claim)
self.db.delete(claim)
self.db.commit()
@@ -588,6 +594,16 @@ class ExpenseClaimService(
return claim
def _delete_claim_analysis_records(self, claim_id: str) -> None:
observation_ids = select(RiskObservation.id).where(RiskObservation.claim_id == claim_id)
self.db.execute(
delete(RiskObservationFeedback).where(
RiskObservationFeedback.observation_id.in_(observation_ids)
)
)
self.db.execute(delete(RiskObservation).where(RiskObservation.claim_id == claim_id))
self.db.execute(delete(HermesRiskReport).where(HermesRiskReport.claim_id == claim_id))
def return_claim(
self,
claim_id: str,
@@ -740,8 +756,6 @@ class ExpenseClaimService(