ERP/frontend/js/api.js

132 lines
5.6 KiB
JavaScript

const API = (() => {
const base = '/api';
async function request(path, opts = {}) {
const overlay = document.getElementById('overlay');
overlay.classList.remove('hidden');
try {
const res = await fetch(base + path, {
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
...opts
});
if (!res.ok) throw new Error(await res.text());
return await res.json();
} catch (e) {
toast(e.message || '请求失败');
throw e;
} finally {
overlay.classList.add('hidden');
}
}
async function requestQuiet(path, opts = {}) {
// 创建超时控制器
const controller = opts.signal ? null : new AbortController();
const timeoutId = controller ? setTimeout(() => {
controller.abort();
console.warn('[API] 请求超时:', path);
}, 10000) : null; // 10秒超时
try {
const res = await fetch(base + path, {
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
signal: opts.signal || (controller ? controller.signal : undefined),
...opts
});
if (timeoutId) clearTimeout(timeoutId);
if (!res.ok) throw new Error(await res.text());
return await res.json();
} catch (e) {
if (timeoutId) clearTimeout(timeoutId);
// 忽略取消的请求
if (e.name === 'AbortError') {
return { list: [] };
}
throw e;
}
}
async function uploadFile(path, formData) {
const overlay = document.getElementById('overlay');
overlay.classList.remove('hidden');
try {
const res = await fetch(base + path, {
method: 'POST',
body: formData,
credentials: 'include'
});
if (!res.ok) throw new Error(await res.text());
return await res.json();
} catch (e) {
toast(e.message || '上传失败');
throw e;
} finally {
overlay.classList.add('hidden');
}
}
function toast(msg) {
const t = document.getElementById('toast');
t.textContent = msg;
t.classList.add('show');
setTimeout(() => t.classList.remove('show'), 2000);
}
return {
login: (username, password) => request('/auth/login', { method: 'POST', body: JSON.stringify({ username, password }) }),
me: () => request('/auth/me'),
logout: () => request('/auth/logout', { method: 'POST' }),
dashboard: () => request('/dashboard'),
overview: () => request('/overview'),
uploadMac: data => request('/upload/mac', { method: 'POST', body: JSON.stringify(data) }),
uploadMacFile: file => {
const fd = new FormData();
fd.append('file', file);
return uploadFile('/upload/mac-file', fd);
},
uploadStats: data => request('/upload/stats', { method: 'POST', body: JSON.stringify(data) }),
uploadRepairs: data => request('/upload/repairs', { method: 'POST', body: JSON.stringify(data) }),
uploadDefects: data => request('/upload/defects', { method: 'POST', body: JSON.stringify(data) }),
uploadDefectsFile: file => {
const fd = new FormData();
fd.append('file', file);
return uploadFile('/upload/defects-file', fd);
},
uploadShipments: data => request('/upload/shipments', { method: 'POST', body: JSON.stringify(data) }),
devices: () => request('/collect/devices'),
environment: () => request('/collect/environment'),
personnel: () => request('/collect/personnel'),
qa: () => request('/collect/qa'),
production: () => request('/collect/production'),
addPersonnel: (name, role) => request('/collect/personnel', { method: 'POST', body: JSON.stringify({ name, role }) }),
listMac: () => request('/list/mac'),
listStats: () => request('/list/stats'),
listRepairs: () => request('/list/repairs'),
listDefects: () => request('/list/defects'),
listShipments: () => request('/list/shipments'),
auditPdd: (params={}) => request('/audit/pdd' + buildQuery(params)),
auditYt: (params={}) => request('/audit/yt' + buildQuery(params)),
auditPddQuiet: (params={}) => requestQuiet('/audit/pdd' + buildQuery(params)),
auditYtQuiet: (params={}) => requestQuiet('/audit/yt' + buildQuery(params)),
exportExcel: params => request('/export/excel', { method: 'POST', body: JSON.stringify(params) }),
exportPdf: params => request('/export/pdf', { method: 'POST', body: JSON.stringify(params) }),
toast,
adminUsers: () => request('/admin/users'),
resetPassword: (username, new_password) => request('/admin/reset-password', { method: 'POST', body: JSON.stringify({ username, new_password }) }),
changePassword: (username, new_password) => request('/admin/change-password', { method: 'POST', body: JSON.stringify({ username, new_password }) }),
clearModule: module => request('/admin/clear', { method: 'POST', body: JSON.stringify({ module }) }),
getNotifications: () => requestQuiet('/notifications'),
getUnreadCount: () => requestQuiet('/notifications/unread-count'),
markNotificationRead: id => requestQuiet('/notifications/mark-read', { method: 'POST', body: JSON.stringify({ id }) }),
markAllNotificationsRead: () => requestQuiet('/notifications/mark-all-read', { method: 'POST' }),
deleteReadNotifications: () => requestQuiet('/notifications/delete-read', { method: 'POST' }),
updateShipmentsPlatform: () => request('/shipments/update-platform', { method: 'POST' })
};
})();
function buildQuery(params){
const q = new URLSearchParams();
if(params.start) q.set('start', params.start);
if(params.end) q.set('end', params.end);
if(params.limit) q.set('limit', params.limit);
if(params.order) q.set('order', params.order);
const s = q.toString();
return s ? ('?' + s) : '';
}