feat: 完善文档中心与报销申请交互及侧边栏重构
后端优化编排器报销查询和本体检测精度,增强报销单草稿保 存和附件回填逻辑,前端重构侧边栏组件支持折叠和图标导 航,完善文档中心状态筛选和详情提示,报销创建和审批详情 页优化会话管理和费用明细交互,新增助手应用服务和预设动 作工具函数,补充单元测试覆盖。
This commit is contained in:
@@ -12,7 +12,9 @@ import { buildDetailAlerts } from '../utils/detailAlerts.js'
|
||||
import { normalizeRequestForUi } from '../utils/requestViewModel.js'
|
||||
import { buildWorkbenchSummary } from '../utils/workbenchSummary.js'
|
||||
|
||||
const SESSION_TYPE_EXPENSE = 'expense'
|
||||
const SESSION_TYPE_EXPENSE = 'expense'
|
||||
const SMART_ENTRY_SOURCE_APPLICATION = 'application'
|
||||
const SMART_ENTRY_SOURCE_REIMBURSEMENT = 'topbar'
|
||||
|
||||
export function useAppShell() {
|
||||
const route = useRoute()
|
||||
@@ -111,13 +113,18 @@ export function useAppShell() {
|
||||
buildWorkbenchSummary(requests.value, currentUser.value)
|
||||
)
|
||||
|
||||
const topBarView = computed(() => {
|
||||
if (detailMode.value) {
|
||||
return {
|
||||
title: '报销单详情',
|
||||
desc: '查看报销明细、票据材料、审批进度与风险提示。'
|
||||
}
|
||||
}
|
||||
const topBarView = computed(() => {
|
||||
if (detailMode.value) {
|
||||
const request = selectedRequest.value || {}
|
||||
const claimNo = request.claimNo || request.claim_no || request.documentNo || request.id || ''
|
||||
const isApplicationDocument = isApplicationDocumentPayload(request, claimNo)
|
||||
return {
|
||||
title: isApplicationDocument ? '申请单详情' : '报销单详情',
|
||||
desc: isApplicationDocument
|
||||
? '查看申请信息、预计金额、审批进度与预算管理口径。'
|
||||
: '查看报销明细、票据材料、审批进度与风险提示。'
|
||||
}
|
||||
}
|
||||
|
||||
if (logDetailMode.value) {
|
||||
return {
|
||||
@@ -170,18 +177,26 @@ export function useAppShell() {
|
||||
setView(view)
|
||||
}
|
||||
|
||||
function openTravelCreate() {
|
||||
smartEntryOpen.value = true
|
||||
smartEntryContext.value = {
|
||||
prompt: '',
|
||||
source: 'topbar',
|
||||
request: null,
|
||||
files: [],
|
||||
conversation: null,
|
||||
scope: null
|
||||
}
|
||||
smartEntrySessionId.value += 1
|
||||
}
|
||||
function openFinancialAssistantCreate(source) {
|
||||
smartEntryOpen.value = true
|
||||
smartEntryContext.value = {
|
||||
prompt: '',
|
||||
source,
|
||||
request: null,
|
||||
files: [],
|
||||
conversation: null,
|
||||
scope: null
|
||||
}
|
||||
smartEntrySessionId.value += 1
|
||||
}
|
||||
|
||||
function openTravelCreate() {
|
||||
openFinancialAssistantCreate(SMART_ENTRY_SOURCE_REIMBURSEMENT)
|
||||
}
|
||||
|
||||
function openExpenseApplicationCreate() {
|
||||
openFinancialAssistantCreate(SMART_ENTRY_SOURCE_APPLICATION)
|
||||
}
|
||||
|
||||
function resolveCurrentUserId() {
|
||||
const user = currentUser.value || {}
|
||||
@@ -204,9 +219,27 @@ export function useAppShell() {
|
||||
return { type: 'claim', claimId }
|
||||
}
|
||||
|
||||
function isDetailClaimScopedPayload(payload = {}) {
|
||||
return String(payload.source || '').trim() === 'detail' && Boolean(resolveSmartEntryClaimScope(payload))
|
||||
}
|
||||
function isDetailClaimScopedPayload(payload = {}) {
|
||||
return String(payload.source || '').trim() === 'detail' && Boolean(resolveSmartEntryClaimScope(payload))
|
||||
}
|
||||
|
||||
function isApplicationDocumentPayload(payload = {}, claimNo = '') {
|
||||
const documentType = String(
|
||||
payload.documentType
|
||||
|| payload.document_type
|
||||
|| payload.documentTypeCode
|
||||
|| payload.document_type_code
|
||||
|| payload.draftType
|
||||
|| payload.draft_type
|
||||
|| ''
|
||||
).trim()
|
||||
const normalizedClaimNo = String(claimNo || payload.claimNo || payload.claim_no || '').trim().toUpperCase()
|
||||
return (
|
||||
documentType === 'application'
|
||||
|| documentType === 'expense_application'
|
||||
|| normalizedClaimNo.startsWith('APP-')
|
||||
)
|
||||
}
|
||||
|
||||
async function resolveSmartEntryConversation(payload = {}) {
|
||||
if (payload.conversation) {
|
||||
@@ -254,19 +287,28 @@ export function useAppShell() {
|
||||
}
|
||||
|
||||
async function handleDraftSaved(payload = {}) {
|
||||
const claimNo = String(payload.claimNo || payload.claim_no || '').trim()
|
||||
const status = String(payload.status || payload.claimStatus || '').trim()
|
||||
const approvalStage = String(payload.approvalStage || payload.approval_stage || '').trim()
|
||||
await reloadRequests()
|
||||
if (status === 'submitted') {
|
||||
smartEntryOpen.value = false
|
||||
void refreshApprovalInbox()
|
||||
toast(`${claimNo || '该'}单据已完成 AI预审${approvalStage ? `,当前节点:${approvalStage}` : ',并已提交审批'}。`)
|
||||
router.push({ name: activeView.value === 'documents' ? 'app-documents' : 'app-requests' })
|
||||
return
|
||||
}
|
||||
toast(`${claimNo || '该'}单据已保存为草稿,可继续上传票据或补充信息。`)
|
||||
}
|
||||
const claimNo = String(payload.claimNo || payload.claim_no || '').trim()
|
||||
const status = String(payload.status || payload.claimStatus || '').trim()
|
||||
const approvalStage = String(payload.approvalStage || payload.approval_stage || '').trim()
|
||||
const isApplicationDocument = isApplicationDocumentPayload(payload, claimNo)
|
||||
await reloadRequests()
|
||||
if (status === 'submitted') {
|
||||
smartEntryOpen.value = false
|
||||
void refreshApprovalInbox()
|
||||
toast(
|
||||
isApplicationDocument
|
||||
? `${claimNo || '该'}申请单已提交${approvalStage ? `,当前节点:${approvalStage}` : ',等待直属领导审批'}。`
|
||||
: `${claimNo || '该'}单据已完成 AI预审${approvalStage ? `,当前节点:${approvalStage}` : ',并已提交审批'}。`
|
||||
)
|
||||
router.push({ name: activeView.value === 'documents' ? 'app-documents' : 'app-requests' })
|
||||
return
|
||||
}
|
||||
toast(
|
||||
isApplicationDocument
|
||||
? `${claimNo || '该'}申请单已保存为草稿,可继续补充申请信息。`
|
||||
: `${claimNo || '该'}单据已保存为草稿,可继续上传票据或补充信息。`
|
||||
)
|
||||
}
|
||||
|
||||
function openRequestDetail(request) {
|
||||
selectedRequestSnapshot.value = request || null
|
||||
@@ -315,10 +357,11 @@ export function useAppShell() {
|
||||
handleNavigate,
|
||||
handleReject,
|
||||
handleRequestDeleted,
|
||||
handleRequestUpdated,
|
||||
navItems,
|
||||
openRequestDetail,
|
||||
openSmartEntry,
|
||||
handleRequestUpdated,
|
||||
navItems,
|
||||
openExpenseApplicationCreate,
|
||||
openRequestDetail,
|
||||
openSmartEntry,
|
||||
openTravelCreate,
|
||||
ranges,
|
||||
requestSummary,
|
||||
|
||||
Reference in New Issue
Block a user