Files
X-Financial/web/src/views/scripts/RequestsView.js

158 lines
4.5 KiB
JavaScript
Raw Normal View History

import { computed, ref, watch } from 'vue'
import { normalizeRequestForUi } from '../../utils/requestViewModel.js'
function extractRowDate(value) {
const matched = String(value || '').match(/\d{4}-\d{2}-\d{2}/)
return matched ? matched[0] : ''
}
export default {
name: 'RequestsView',
props: {
filteredRequests: { type: Array, required: true },
hasData: { type: Boolean, default: false },
loading: { type: Boolean, default: false },
error: { type: String, default: '' }
},
emits: ['ask', 'approve', 'reject', 'create-request', 'reload'],
setup(props, { emit }) {
const activeTab = ref('全部')
const tabs = ['全部', '草稿', '审批中', '待补充', '已完成']
const filters = ['报销状态', '报销类型', '所属主体']
const listKeyword = ref('')
const datePopover = ref(false)
const rangeStart = ref('')
const rangeEnd = ref('')
const appliedStart = ref('')
const appliedEnd = ref('')
const dateRangeLabel = computed(() => {
if (appliedStart.value && appliedEnd.value) {
return `${appliedStart.value} ~ ${appliedEnd.value}`
}
return '选择时间段'
})
function applyDateRange() {
if (!rangeStart.value || !rangeEnd.value) {
return
}
appliedStart.value = rangeStart.value
appliedEnd.value = rangeEnd.value
datePopover.value = false
}
const rows = computed(() =>
props.filteredRequests
.map((item) => normalizeRequestForUi(item))
.filter(Boolean)
)
const currentPage = ref(1)
const pageSize = ref(10)
const pageSizes = [10, 20, 50]
const pageSizeOpen = ref(false)
function changePageSize(size) {
pageSize.value = size
pageSizeOpen.value = false
currentPage.value = 1
}
const filteredRows = computed(() => {
const keyword = listKeyword.value.trim().toLowerCase()
return rows.value.filter((row) => {
const matchesKeyword =
!keyword
|| [
row.id,
row.documentNo,
row.typeLabel,
row.reason,
row.sceneTarget,
row.relatedCustomer,
row.riskSummary
]
.filter(Boolean)
.join('')
.toLowerCase()
.includes(keyword)
const applyDate = extractRowDate(row.applyTime)
const matchesDateRange =
!appliedStart.value
|| !appliedEnd.value
|| (applyDate && applyDate >= appliedStart.value && applyDate <= appliedEnd.value)
const matchesTab =
activeTab.value === '全部'
|| (activeTab.value === '草稿' && row.approvalKey === 'draft')
|| (activeTab.value === '审批中' && row.approvalKey === 'in_progress')
|| (activeTab.value === '待补充' && row.approvalKey === 'supplement')
|| (activeTab.value === '已完成' && row.approvalKey === 'completed')
return matchesKeyword && matchesDateRange && matchesTab
})
})
const totalCount = computed(() => filteredRows.value.length)
const totalPages = computed(() => Math.max(1, Math.ceil(totalCount.value / pageSize.value)))
const visibleRows = computed(() => {
const start = (currentPage.value - 1) * pageSize.value
return filteredRows.value.slice(start, start + pageSize.value)
})
const showTable = computed(() => !props.loading && !props.error && visibleRows.value.length > 0)
const showEmpty = computed(() => !props.loading && !props.error && visibleRows.value.length === 0)
const emptyState = computed(() => {
if (!props.hasData) {
return {
title: '暂无真实报销单据',
desc: '数据库里还没有可见的个人报销数据。保存草稿或提交报销后,会显示在这里。'
}
}
return {
title: '没有匹配结果',
desc: '当前筛选条件下没有可展示的报销单据。'
}
})
watch([activeTab, rows, listKeyword, appliedStart, appliedEnd], () => {
currentPage.value = 1
})
return {
emit,
activeTab,
tabs,
filters,
listKeyword,
datePopover,
rangeStart,
rangeEnd,
appliedStart,
appliedEnd,
dateRangeLabel,
applyDateRange,
rows,
currentPage,
pageSize,
pageSizes,
pageSizeOpen,
changePageSize,
filteredRows,
totalCount,
totalPages,
visibleRows,
showTable,
showEmpty,
emptyState
}
}
}