feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
import { computed, reactive, ref } from 'vue'
|
|
|
|
|
|
2026-06-09 08:32:00 +00:00
|
|
|
import { fetchAllExpenseClaims } from '../services/reimbursements.js'
|
2026-06-22 11:58:53 +08:00
|
|
|
import { formatDate, toDate } from './requests/requestShared.js'
|
|
|
|
|
import { mapExpenseClaimToRequest } from './requests/requestClaimMapper.js'
|
2026-05-13 03:29:10 +00:00
|
|
|
|
2026-06-22 11:58:53 +08:00
|
|
|
export { mapExpenseClaimToRequest } from './requests/requestClaimMapper.js'
|
2026-05-13 03:29:10 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-13 15:38:59 +00:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-13 03:29:10 +00:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-13 15:38:59 +00:00
|
|
|
if (activeRange === '近10日') {
|
|
|
|
|
const recentStart = getRecentDaysStart(now, 10)
|
|
|
|
|
return targetDate >= recentStart && targetDate <= now
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-13 03:29:10 +00:00
|
|
|
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)
|
2026-05-29 13:17:39 +08:00
|
|
|
const loaded = ref(false)
|
2026-05-13 03:29:10 +00:00
|
|
|
const error = ref('')
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
const search = ref('')
|
2026-05-13 03:29:10 +00:00
|
|
|
const filters = reactive({ entity: '全部主体', category: '全部类型', risk: '全部状态' })
|
2026-05-13 15:38:59 +00:00
|
|
|
const ranges = ['今日', '近10日', '本周', '本月']
|
|
|
|
|
const activeRange = ref('近10日')
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
|
|
|
|
|
const filteredRequests = computed(() => {
|
|
|
|
|
const key = search.value.trim().toLowerCase()
|
2026-05-13 03:29:10 +00:00
|
|
|
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
return requests.value.filter((item) => {
|
2026-05-13 03:29:10 +00:00
|
|
|
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
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
2026-06-09 08:32:00 +00:00
|
|
|
async function reload(options = {}) {
|
|
|
|
|
const silent = Boolean(options?.silent)
|
|
|
|
|
if (!silent) {
|
|
|
|
|
loading.value = true
|
|
|
|
|
error.value = ''
|
|
|
|
|
}
|
2026-05-13 03:29:10 +00:00
|
|
|
|
|
|
|
|
try {
|
2026-06-09 08:32:00 +00:00
|
|
|
const payload = await fetchAllExpenseClaims()
|
2026-05-13 03:29:10 +00:00
|
|
|
requests.value = Array.isArray(payload) ? payload.map((item) => mapExpenseClaimToRequest(item)) : []
|
2026-05-29 13:17:39 +08:00
|
|
|
loaded.value = true
|
2026-05-13 03:29:10 +00:00
|
|
|
} catch (nextError) {
|
2026-06-09 08:32:00 +00:00
|
|
|
if (!silent) {
|
|
|
|
|
requests.value = []
|
|
|
|
|
}
|
2026-05-13 03:29:10 +00:00
|
|
|
error.value = nextError instanceof Error ? nextError.message : '个人报销列表加载失败。'
|
|
|
|
|
} finally {
|
2026-06-09 08:32:00 +00:00
|
|
|
if (!silent) {
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
2026-05-13 03:29:10 +00:00
|
|
|
}
|
2026-04-29 23:35:56 +08:00
|
|
|
}
|
|
|
|
|
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
function approveRequest(request) {
|
2026-05-13 03:29:10 +00:00
|
|
|
return `${request.id} 未执行本地状态变更,列表当前只展示后端真实数据。`
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function rejectRequest(request) {
|
2026-05-13 03:29:10 +00:00
|
|
|
return `${request.id} 未执行本地状态变更,列表当前只展示后端真实数据。`
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-29 13:17:39 +08:00
|
|
|
function ensureLoaded() {
|
|
|
|
|
return loaded.value ? Promise.resolve() : reload()
|
|
|
|
|
}
|
2026-05-13 03:29:10 +00:00
|
|
|
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
return {
|
2026-05-13 03:29:10 +00:00
|
|
|
requests,
|
|
|
|
|
loading,
|
2026-05-29 13:17:39 +08:00
|
|
|
loaded,
|
2026-05-13 03:29:10 +00:00
|
|
|
error,
|
|
|
|
|
search,
|
|
|
|
|
filters,
|
|
|
|
|
ranges,
|
|
|
|
|
activeRange,
|
|
|
|
|
filteredRequests,
|
|
|
|
|
approveRequest,
|
|
|
|
|
rejectRequest,
|
2026-05-29 13:17:39 +08:00
|
|
|
ensureLoaded,
|
2026-05-13 03:29:10 +00:00
|
|
|
reload
|
feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00
|
|
|
}
|
|
|
|
|
}
|