fix(expenses): refine operation record audit UI
This commit is contained in:
@@ -6,7 +6,8 @@ import { effectScope, nextTick, ref } from 'vue'
|
||||
|
||||
import {
|
||||
buildExpenseCaseTimelineViewModel,
|
||||
isExpenseCaseNotAvailableError
|
||||
isExpenseCaseNotAvailableError,
|
||||
orderExpenseCaseEventsForDisplay
|
||||
} from '../src/utils/expenseCaseTimeline.js'
|
||||
import { fetchExpenseCaseTimeline } from '../src/services/expenseCases.js'
|
||||
import { useExpenseCaseTimeline } from '../src/composables/requests/useExpenseCaseTimeline.js'
|
||||
@@ -69,6 +70,7 @@ test('expense case timeline maps and sorts the real business event chain', () =>
|
||||
assert.equal(timeline.linkCount, 2)
|
||||
assert.deepEqual(timeline.events.map((event) => event.id), ['event-1', 'event-2'])
|
||||
assert.equal(timeline.events[0].label, '费用申请已提交')
|
||||
assert.equal(timeline.events[0].icon, 'mdi mdi-file-send-outline')
|
||||
assert.match(timeline.events[0].summary, /草稿 → 已提交/)
|
||||
assert.match(timeline.events[0].summary, /直属领导审批/)
|
||||
assert.equal(timeline.events[0].actorLabel, 'employee@example.com')
|
||||
@@ -139,6 +141,7 @@ test('expense case timeline explains receipt collection, association and AI pre-
|
||||
assert.match(timeline.events[0].summary, /上海出差高铁票\.pdf/)
|
||||
assert.match(timeline.events[1].summary, /BX-20260713-001/)
|
||||
assert.equal(timeline.events[2].tone, 'warning')
|
||||
assert.equal(timeline.events[2].icon, 'mdi mdi-shield-check-outline')
|
||||
assert.match(timeline.events[2].summary, /1 条重大风险/)
|
||||
})
|
||||
|
||||
@@ -246,6 +249,37 @@ test('expense case timeline keeps equal-time server order and hides unknown even
|
||||
assert.doesNotMatch(JSON.stringify(timeline.events[0]), /private-correlation|pending/)
|
||||
})
|
||||
|
||||
test('expense case records show newer events first and preserve equal-time server order', () => {
|
||||
const timeline = buildExpenseCaseTimelineViewModel({
|
||||
events: [
|
||||
{
|
||||
id: 'older',
|
||||
event_type: 'application_submitted',
|
||||
occurred_at: '2026-07-17T14:54:00Z'
|
||||
},
|
||||
{
|
||||
id: 'newer-first',
|
||||
event_type: 'application_pre_review_completed',
|
||||
occurred_at: '2026-07-18T02:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 'newer-second',
|
||||
event_type: 'claim_submitted',
|
||||
occurred_at: '2026-07-18T02:00:00Z'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const displayedEvents = orderExpenseCaseEventsForDisplay(timeline.events)
|
||||
|
||||
assert.deepEqual(
|
||||
displayedEvents.map((event) => event.id),
|
||||
['newer-first', 'newer-second', 'older']
|
||||
)
|
||||
assert.equal(displayedEvents[0].icon, 'mdi mdi-shield-check-outline')
|
||||
assert.deepEqual(timeline.events.map((event) => event.id), ['older', 'newer-first', 'newer-second'])
|
||||
})
|
||||
|
||||
test('expense case service safely encodes claim identifiers', async () => {
|
||||
const originalFetch = globalThis.fetch
|
||||
let requestedUrl = ''
|
||||
@@ -351,7 +385,11 @@ test('travel request detail consumes the real expense case endpoint', () => {
|
||||
assert.match(detailView, /:refresh-key="expenseCaseTimelineRefreshKey"/)
|
||||
assert.match(progressCard, /<TravelRequestExpenseCaseTimeline/)
|
||||
assert.match(progressCard, /TravelRequestExpenseCaseTimeline/)
|
||||
assert.match(timelineComponent, /费用事件时间线/)
|
||||
assert.match(timelineComponent, /费用操作记录/)
|
||||
assert.match(timelineComponent, /发生时间/)
|
||||
assert.match(timelineComponent, /操作人/)
|
||||
assert.doesNotMatch(timelineComponent, /expense-case-latest/)
|
||||
assert.match(timelineComponent, /orderExpenseCaseEventsForDisplay/)
|
||||
assert.match(timelineComponent, /当前单据尚未纳入统一费用事件/)
|
||||
assert.match(expenseCaseService, /\/expense-cases\/by-claim\//)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user