Initial commit: AARS backend + frontend + holiday/leave phase 1+2

This commit is contained in:
IT Dog
2026-07-19 20:10:15 +08:00
commit bbc0048c24
49 changed files with 13375 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
import axios from 'axios'
import { setCurrentRequestId } from './lib/logger.js'
const api = axios.create({
baseURL: '',
timeout: 30000,
})
// Generate a request id per outgoing call (for cross-correlation)
function newRequestId() {
// RFC4122-ish: use crypto if available
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
return crypto.randomUUID()
}
return 'req-' + Math.random().toString(36).slice(2) + Date.now().toString(36)
}
// Request interceptor: auth + X-Request-ID
api.interceptors.request.use(
config => {
const token = localStorage.getItem('aars_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
config.headers['X-Request-ID'] = newRequestId()
return config
},
error => Promise.reject(error)
)
// Response interceptor: capture server's X-Request-ID for log correlation + 401 handling
api.interceptors.response.use(
response => {
const rid = response.headers['x-request-id']
if (rid) setCurrentRequestId(rid)
return response
},
error => {
const rid = error.response?.headers?.['x-request-id']
if (rid) setCurrentRequestId(rid)
if (error.response?.status === 401) {
localStorage.removeItem('aars_token')
// Avoid loop if already on /login
if (!window.location.pathname.startsWith('/login')) {
window.location.href = '/login'
}
}
return Promise.reject(error)
}
)
export default api