import { computed, reactive, ref } from 'vue' import { fetchAllExpenseClaims } from '../services/reimbursements.js' import { formatDate, toDate } from './requests/requestShared.js' import { mapExpenseClaimToRequest } from './requests/requestClaimMapper.js' export { mapExpenseClaimToRequest } from './requests/requestClaimMapper.js' function getWeekStart(date) { const nextDate = new Date(date) const day = nextDate.getDay() || 7 nextDate.setHours(0, 0, 0, 0) nextDate.setDate(nextDate.getDate() - day + 1) return nextDate } function getRecentDaysStart(date, days) { const nextDate = new Date(date) nextDate.setHours(0, 0, 0, 0) nextDate.setDate(nextDate.getDate() - Math.max(0, Number(days || 1) - 1)) return nextDate } function resolveRangeMatch(activeRange, item) { if (activeRange === 'custom' || activeRange === '本月') { if (activeRange !== '本月') { return true } } const targetDate = toDate(item?.submittedAt || item?.createdAt || item?.occurredAt) if (!targetDate) { return true } const now = new Date() const targetDay = formatDate(targetDate) if (activeRange === '今日') { return targetDay === formatDate(now) } if (activeRange === '近10日') { const recentStart = getRecentDaysStart(now, 10) return targetDate >= recentStart && targetDate <= now } if (activeRange === '本周') { const weekStart = getWeekStart(now) const nextWeekStart = new Date(weekStart) nextWeekStart.setDate(nextWeekStart.getDate() + 7) return targetDate >= weekStart && targetDate < nextWeekStart } if (activeRange === '本月') { return ( targetDate.getFullYear() === now.getFullYear() && targetDate.getMonth() === now.getMonth() ) } return true } export function useRequests() { const requests = ref([]) const loading = ref(false) const loaded = ref(false) const error = ref('') const search = ref('') const filters = reactive({ entity: '全部主体', category: '全部类型', risk: '全部状态' }) const ranges = ['今日', '近10日', '本周', '本月'] const activeRange = ref('近10日') const filteredRequests = computed(() => { const key = search.value.trim().toLowerCase() return requests.value.filter((item) => { const searchText = [ item.id, item.person, item.typeLabel, item.title, item.sceneTarget, item.riskSummary ] .filter(Boolean) .join('') .toLowerCase() const matchesSearch = !key || searchText.includes(key) const matchesRange = resolveRangeMatch(activeRange.value, item) return matchesSearch && matchesRange }) }) async function reload(options = {}) { const silent = Boolean(options?.silent) if (!silent) { loading.value = true error.value = '' } try { const payload = await fetchAllExpenseClaims() requests.value = Array.isArray(payload) ? payload.map((item) => mapExpenseClaimToRequest(item)) : [] loaded.value = true } catch (nextError) { if (!silent) { requests.value = [] } error.value = nextError instanceof Error ? nextError.message : '个人报销列表加载失败。' } finally { if (!silent) { loading.value = false } } } function approveRequest(request) { return `${request.id} 未执行本地状态变更,列表当前只展示后端真实数据。` } function rejectRequest(request) { return `${request.id} 未执行本地状态变更,列表当前只展示后端真实数据。` } function ensureLoaded() { return loaded.value ? Promise.resolve() : reload() } return { requests, loading, loaded, error, search, filters, ranges, activeRange, filteredRequests, approveRequest, rejectRequest, ensureLoaded, reload } }