feat: 风险可见性控制与差旅详情页交互优化
- 新增风险可见性工具函数与风险日趋势图表组件 - 优化差旅请求详情页费用模型与视图交互 - 完善顶部导航栏样式与应用壳路由逻辑 - 补充风险可见性、风险看板与差旅详情测试覆盖
This commit is contained in:
@@ -2,9 +2,10 @@ import { computed, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { useNavigation, navItems } from './useNavigation.js'
|
||||
import { useRequests } from './useRequests.js'
|
||||
import { useSystemState } from './useSystemState.js'
|
||||
import { mapExpenseClaimToRequest, useRequests } from './useRequests.js'
|
||||
import { useSystemState } from './useSystemState.js'
|
||||
import { useToast } from './useToast.js'
|
||||
import { fetchExpenseClaimDetail } from '../services/reimbursements.js'
|
||||
import { fetchOntologyParse } from '../services/ontology.js'
|
||||
import { fetchLatestConversation } from '../services/orchestrator.js'
|
||||
import { clearAssistantSessionSnapshotForDraftClaim } from '../utils/assistantSessionSnapshot.js'
|
||||
@@ -16,6 +17,7 @@ import {
|
||||
resolveWorkbenchSessionTypeFromOntology
|
||||
} from '../utils/workbenchAssistantIntent.js'
|
||||
import { buildWorkbenchSummary } from '../utils/workbenchSummary.js'
|
||||
import { createCurrentYearDateRange } from '../utils/dateRangeDefaults.js'
|
||||
|
||||
const SESSION_TYPE_EXPENSE = 'expense'
|
||||
const SMART_ENTRY_SOURCE_APPLICATION = 'application'
|
||||
@@ -62,36 +64,29 @@ export function useAppShell() {
|
||||
const { currentUser } = useSystemState()
|
||||
const { toast } = useToast()
|
||||
|
||||
const customRange = ref({ start: '2024-07-06', end: '2024-07-12' })
|
||||
const customRange = ref(createCurrentYearDateRange())
|
||||
|
||||
const selectedRequest = computed(() => {
|
||||
const requestId = String(route.params.requestId || '')
|
||||
|
||||
if (!requestId) {
|
||||
return null
|
||||
}
|
||||
|
||||
const rawRequest = requests.value.find(
|
||||
(item) => String(item.claimId || '').trim() === requestId || String(item.id || '').trim() === requestId
|
||||
)
|
||||
const normalizedRequest = normalizeRequestForUi(rawRequest)
|
||||
if (normalizedRequest) {
|
||||
return normalizedRequest
|
||||
}
|
||||
|
||||
const snapshot = normalizeRequestForUi(selectedRequestSnapshot.value)
|
||||
if (
|
||||
snapshot
|
||||
&& (
|
||||
String(snapshot.claimId || '').trim() === requestId
|
||||
|| String(snapshot.id || '').trim() === requestId
|
||||
|| String(snapshot.documentNo || '').trim() === requestId
|
||||
)
|
||||
) {
|
||||
return snapshot
|
||||
}
|
||||
|
||||
return null
|
||||
const selectedRequest = computed(() => {
|
||||
const requestId = String(route.params.requestId || '')
|
||||
|
||||
if (!requestId) {
|
||||
return null
|
||||
}
|
||||
|
||||
const snapshot = normalizeRequestForUi(selectedRequestSnapshot.value)
|
||||
if (isSameRequestIdentity(snapshot, requestId)) {
|
||||
return snapshot
|
||||
}
|
||||
|
||||
const rawRequest = requests.value.find(
|
||||
(item) => String(item.claimId || '').trim() === requestId || String(item.id || '').trim() === requestId
|
||||
)
|
||||
const normalizedRequest = normalizeRequestForUi(rawRequest)
|
||||
if (normalizedRequest) {
|
||||
return normalizedRequest
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
const detailMode = computed(() => route.name === 'app-document-detail')
|
||||
@@ -110,9 +105,81 @@ export function useAppShell() {
|
||||
return reloadRequests()
|
||||
}
|
||||
|
||||
function isSameRequestIdentity(request, requestId) {
|
||||
const normalizedId = String(requestId || '').trim()
|
||||
if (!request || !normalizedId) {
|
||||
return false
|
||||
}
|
||||
return [
|
||||
request.claimId,
|
||||
request.id,
|
||||
request.claimNo,
|
||||
request.documentNo
|
||||
].some((value) => String(value || '').trim() === normalizedId)
|
||||
}
|
||||
|
||||
function resolveRequestDetailLookupId(requestOrId = selectedRequestSnapshot.value) {
|
||||
if (typeof requestOrId === 'string') {
|
||||
return requestOrId.trim()
|
||||
}
|
||||
return String(
|
||||
requestOrId?.claimId
|
||||
|| requestOrId?.claim_id
|
||||
|| requestOrId?.id
|
||||
|| requestOrId?.claimNo
|
||||
|| requestOrId?.claim_no
|
||||
|| ''
|
||||
).trim()
|
||||
}
|
||||
|
||||
function upsertRequestSnapshot(nextRequest) {
|
||||
if (!nextRequest) {
|
||||
return
|
||||
}
|
||||
selectedRequestSnapshot.value = nextRequest
|
||||
const nextIdValues = [
|
||||
nextRequest.claimId,
|
||||
nextRequest.id,
|
||||
nextRequest.claimNo,
|
||||
nextRequest.documentNo
|
||||
].map((item) => String(item || '').trim()).filter(Boolean)
|
||||
const nextIdSet = new Set(nextIdValues)
|
||||
const index = requests.value.findIndex((item) => [
|
||||
item.claimId,
|
||||
item.id,
|
||||
item.claimNo,
|
||||
item.documentNo
|
||||
].some((value) => nextIdSet.has(String(value || '').trim())))
|
||||
if (index >= 0) {
|
||||
requests.value.splice(index, 1, nextRequest)
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshSelectedRequestDetail(requestOrId = selectedRequestSnapshot.value) {
|
||||
const lookupId = resolveRequestDetailLookupId(requestOrId)
|
||||
if (!lookupId) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const payload = await fetchExpenseClaimDetail(lookupId)
|
||||
const mappedRequest = mapExpenseClaimToRequest(payload)
|
||||
const routeRequestId = String(route.params.requestId || '').trim()
|
||||
if (!routeRequestId || isSameRequestIdentity(mappedRequest, routeRequestId) || routeRequestId === lookupId) {
|
||||
upsertRequestSnapshot(mappedRequest)
|
||||
}
|
||||
} catch {
|
||||
// 保留当前快照,避免详情刷新失败时把页面置空。
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [activeView.value, route.name],
|
||||
([view]) => {
|
||||
if (route.name === 'app-document-detail') {
|
||||
void ensureRequestsLoaded()
|
||||
void refreshSelectedRequestDetail(String(route.params.requestId || ''))
|
||||
return
|
||||
}
|
||||
if (view === 'documents') {
|
||||
void reloadDocumentCenterRequests()
|
||||
return
|
||||
@@ -425,6 +492,7 @@ export function useAppShell() {
|
||||
params: { requestId: request.claimId || request.id },
|
||||
query: buildDocumentDetailQuery(options)
|
||||
})
|
||||
void refreshSelectedRequestDetail(request)
|
||||
}
|
||||
|
||||
function closeRequestDetail() {
|
||||
@@ -438,6 +506,7 @@ export function useAppShell() {
|
||||
|
||||
async function handleRequestUpdated() {
|
||||
await reloadRequests()
|
||||
await refreshSelectedRequestDetail(String(route.params.requestId || ''))
|
||||
}
|
||||
|
||||
async function handleRequestDeleted(payload = {}) {
|
||||
|
||||
Reference in New Issue
Block a user