feat(web): 优化差旅详情、风险建议卡片与文档中心交互
- 拆分阶段风险建议卡片样式到独立文件 - 完善差旅申请审批对话框与详情视图交互 - 调整文档中心列表共享样式与状态筛选 - 同步应用外壳、视图初始化与系统状态 composables
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
v-if="openFilterKey === 'status'"
|
||||
class="document-filter-menu status-filter-menu"
|
||||
role="listbox"
|
||||
aria-label="单据状态"
|
||||
aria-label="风险等级"
|
||||
>
|
||||
<button
|
||||
v-for="option in statusFilterOptions"
|
||||
@@ -187,7 +187,7 @@
|
||||
<col class="col-title">
|
||||
<col class="col-amount">
|
||||
<col class="col-node">
|
||||
<col class="col-status">
|
||||
<col class="col-risk">
|
||||
<col class="col-updated">
|
||||
</colgroup>
|
||||
<thead>
|
||||
@@ -201,7 +201,7 @@
|
||||
<th>事项</th>
|
||||
<th>金额</th>
|
||||
<th>当前环节</th>
|
||||
<th>状态</th>
|
||||
<th>风险等级</th>
|
||||
<th>更新时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -219,7 +219,18 @@
|
||||
<td data-label="事项">{{ row.reason }}</td>
|
||||
<td data-label="金额">{{ row.amountDisplay }}</td>
|
||||
<td data-label="当前环节">{{ row.node }}</td>
|
||||
<td data-label="状态"><span class="status-tag" :class="row.statusTone">{{ row.statusLabel }}</span></td>
|
||||
<td data-label="风险等级">
|
||||
<span class="risk-level-tags">
|
||||
<span
|
||||
v-for="tag in row.riskTags"
|
||||
:key="tag.label"
|
||||
class="risk-level-tag"
|
||||
:class="tag.tone"
|
||||
>
|
||||
{{ tag.label }}
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td data-label="更新时间">{{ row.updatedAtDisplay }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -253,6 +264,7 @@ import {
|
||||
fetchAllApprovalExpenseClaims,
|
||||
fetchAllArchivedExpenseClaims
|
||||
} from '../services/reimbursements.js'
|
||||
import { countClaimRisks, resolveArchiveRiskTone } from '../utils/archiveCenterListFilters.js'
|
||||
import { fetchNotificationStates, patchNotificationStates } from '../services/notificationStates.js'
|
||||
import {
|
||||
buildDocumentViewedStatePatch,
|
||||
@@ -292,46 +304,52 @@ const DOCUMENT_CENTER_QUERY_KEYS = new Set([
|
||||
'dc_start',
|
||||
'dc_end'
|
||||
])
|
||||
const statusTabs = ['全部', '草稿', '待提交', '审批中', '待补充', '待付款', '已完成']
|
||||
const riskLevelTabs = ['全部', '高风险', '中风险', '低风险', '无风险']
|
||||
const RISK_TONE_META = {
|
||||
high: { label: '高风险', tone: 'high' },
|
||||
medium: { label: '中风险', tone: 'medium' },
|
||||
low: { label: '低风险', tone: 'low' },
|
||||
none: { label: '无风险', tone: 'none' }
|
||||
}
|
||||
const FILTER_CONFIG_BY_SCOPE = {
|
||||
[DOCUMENT_SCOPE_ALL]: {
|
||||
searchPlaceholder: '搜索单号、事项、费用场景...',
|
||||
sceneFallbackLabel: '单据场景',
|
||||
dateLabel: '单据时间',
|
||||
statusTitle: '单据状态',
|
||||
statusTabs,
|
||||
statusTitle: '风险等级',
|
||||
statusTabs: riskLevelTabs,
|
||||
showDocumentType: true
|
||||
},
|
||||
[DOCUMENT_SCOPE_APPLICATION]: {
|
||||
searchPlaceholder: '搜索申请单号、申请事项、申请场景...',
|
||||
sceneFallbackLabel: '申请场景',
|
||||
dateLabel: '申请时间',
|
||||
statusTitle: '申请状态',
|
||||
statusTabs: ['全部', '草稿', '审批中', '已完成'],
|
||||
statusTitle: '风险等级',
|
||||
statusTabs: riskLevelTabs,
|
||||
showDocumentType: false
|
||||
},
|
||||
[DOCUMENT_SCOPE_REIMBURSEMENT]: {
|
||||
searchPlaceholder: '搜索报销单号、报销事由、费用场景...',
|
||||
sceneFallbackLabel: '费用场景',
|
||||
dateLabel: '报销时间',
|
||||
statusTitle: '报销状态',
|
||||
statusTabs,
|
||||
statusTitle: '风险等级',
|
||||
statusTabs: riskLevelTabs,
|
||||
showDocumentType: false
|
||||
},
|
||||
[DOCUMENT_SCOPE_REVIEW]: {
|
||||
searchPlaceholder: '搜索审核单号、事项、当前环节...',
|
||||
sceneFallbackLabel: '审核场景',
|
||||
dateLabel: '审核时间',
|
||||
statusTitle: '审核状态',
|
||||
statusTabs: ['全部', '审批中', '待补充', '已完成'],
|
||||
statusTitle: '风险等级',
|
||||
statusTabs: riskLevelTabs,
|
||||
showDocumentType: false
|
||||
},
|
||||
[DOCUMENT_SCOPE_ARCHIVE]: {
|
||||
searchPlaceholder: '搜索归档单号、事项、费用场景...',
|
||||
sceneFallbackLabel: '归档场景',
|
||||
dateLabel: '归档时间',
|
||||
statusTitle: '归档状态',
|
||||
statusTabs: ['全部', '已付款', '已完成'],
|
||||
statusTitle: '风险等级',
|
||||
statusTabs: riskLevelTabs,
|
||||
showDocumentType: false
|
||||
}
|
||||
}
|
||||
@@ -458,7 +476,7 @@ const documentTypeFilterLabel = computed(() =>
|
||||
const statusFilterOptions = computed(() =>
|
||||
activeFilterConfig.value.statusTabs.map((tab) => ({
|
||||
value: tab,
|
||||
label: tab === '全部' ? '全部状态' : tab
|
||||
label: tab === '全部' ? '全部风险' : tab
|
||||
}))
|
||||
)
|
||||
|
||||
@@ -546,7 +564,7 @@ const sceneFilterLabel = computed(() =>
|
||||
)
|
||||
|
||||
const statusFilterLabel = computed(() =>
|
||||
statusFilterOptions.value.find((item) => item.value === activeStatusTab.value)?.label || '全部状态'
|
||||
statusFilterOptions.value.find((item) => item.value === activeStatusTab.value)?.label || '全部风险'
|
||||
)
|
||||
|
||||
const filteredRows = computed(() => {
|
||||
@@ -560,7 +578,8 @@ const filteredRows = computed(() => {
|
||||
row.initiatorName,
|
||||
row.reason,
|
||||
row.node,
|
||||
row.statusLabel
|
||||
row.statusLabel,
|
||||
row.riskLabel
|
||||
].filter(Boolean).join('').toLowerCase().includes(keyword)
|
||||
|
||||
const matchesDocumentType =
|
||||
@@ -569,10 +588,10 @@ const filteredRows = computed(() => {
|
||||
|| row.documentTypeCode === activeDocumentType.value
|
||||
|
||||
const matchesScene = activeScene.value === SCENE_ALL || row.typeCode === activeScene.value
|
||||
const matchesStatus = matchesStatusTab(row, activeStatusTab.value)
|
||||
const matchesRiskLevel = matchesRiskLevelTab(row, activeStatusTab.value)
|
||||
const matchesDateRange = matchesAppliedDateRange(row)
|
||||
|
||||
return matchesKeyword && matchesDocumentType && matchesScene && matchesStatus && matchesDateRange
|
||||
return matchesKeyword && matchesDocumentType && matchesScene && matchesRiskLevel && matchesDateRange
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -674,6 +693,7 @@ function buildDocumentRow(request, options = {}) {
|
||||
const archived = Boolean(options.archived)
|
||||
const statusGroup = resolveStatusGroup(normalized, archived)
|
||||
const statusLabel = archived ? resolveArchivedStatusLabel(normalized) : resolveStatusLabel(normalized, statusGroup)
|
||||
const riskMeta = buildDocumentRiskMeta(normalized)
|
||||
const documentNo = normalized.documentNo || normalized.id || normalized.claimId || '待生成'
|
||||
const claimId = normalized.claimId || normalized.id || documentNo
|
||||
const createdAtSource = normalized.createdAt || normalized.submittedAt || normalized.applyTime || normalized.updatedAt
|
||||
@@ -708,6 +728,10 @@ function buildDocumentRow(request, options = {}) {
|
||||
statusGroup,
|
||||
statusLabel,
|
||||
statusTone: archived ? 'archived' : resolveStatusTone(normalized, statusGroup),
|
||||
riskTone: riskMeta.tone,
|
||||
riskLabel: riskMeta.label,
|
||||
riskCount: riskMeta.count,
|
||||
riskTags: riskMeta.tags,
|
||||
source: options.source || 'owned',
|
||||
archived,
|
||||
createdAtDisplay: formatDocumentListTime(createdAtSource),
|
||||
@@ -744,19 +768,48 @@ function resolveStatusTone(row, statusGroup) {
|
||||
return row.approvalTone || 'neutral'
|
||||
}
|
||||
|
||||
function matchesStatusTab(row, tab) {
|
||||
function resolveDocumentRiskFlags(row) {
|
||||
if (Array.isArray(row?.riskFlags)) {
|
||||
return row.riskFlags
|
||||
}
|
||||
if (Array.isArray(row?.risk_flags_json)) {
|
||||
return row.risk_flags_json
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
function buildDocumentRiskMeta(row) {
|
||||
const riskFlags = resolveDocumentRiskFlags(row)
|
||||
const riskSummary = row?.riskSummary || row?.risk
|
||||
const count = countClaimRisks(riskFlags, riskSummary)
|
||||
if (!count) {
|
||||
const meta = RISK_TONE_META.none
|
||||
return {
|
||||
...meta,
|
||||
count: 0,
|
||||
tags: [{ ...meta }]
|
||||
}
|
||||
}
|
||||
|
||||
const tone = resolveArchiveRiskTone(riskFlags, riskSummary)
|
||||
const meta = RISK_TONE_META[tone] || RISK_TONE_META.medium
|
||||
return {
|
||||
...meta,
|
||||
count,
|
||||
tags: [{ tone: meta.tone, label: `${meta.label} ${count}项` }]
|
||||
}
|
||||
}
|
||||
|
||||
function matchesRiskLevelTab(row, tab) {
|
||||
if (activeScopeTab.value !== DOCUMENT_SCOPE_ARCHIVE && isArchivedDocumentRow(row)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (tab === '全部') return true
|
||||
if (tab === '草稿') return row.statusGroup === 'draft'
|
||||
if (tab === '待提交') return row.statusGroup === 'pending_submit'
|
||||
if (tab === '审批中') return row.statusGroup === 'in_progress'
|
||||
if (tab === '待补充') return row.statusGroup === 'supplement'
|
||||
if (tab === '待付款') return row.statusGroup === 'pending_payment'
|
||||
if (tab === '已付款') return row.statusLabel === '已付款' || row.node === '已付款'
|
||||
if (tab === '已完成') return row.statusGroup === 'completed'
|
||||
if (tab === '高风险') return row.riskTone === 'high'
|
||||
if (tab === '中风险') return row.riskTone === 'medium'
|
||||
if (tab === '低风险') return row.riskTone === 'low'
|
||||
if (tab === '无风险') return row.riskTone === 'none'
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user