// BASE_URL configured via manifest.json or build-time env // For production, update this to your actual server URL const BASE_URL = 'http://172.31.12.249:18080/api/hss'; function getHeaders() { const token = uni.getStorageSync('token'); return { 'Authorization': token ? 'Bearer ' + token : '', 'X-User-Role': 'STAFF', 'Content-Type': 'application/json' }; } function generateIdempotencyKey() { return 'idem-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9); } function apiGet(path, params = {}) { return uni.request({ url: BASE_URL + path, method: 'GET', data: params, header: getHeaders() }); } function apiPost(path, data = {}) { const headers = getHeaders(); headers['Idempotency-Key'] = generateIdempotencyKey(); return uni.request({ url: BASE_URL + path, method: 'POST', data, header: headers }); } // ==================== GPS ==================== function getLocation() { return new Promise((resolve, reject) => { // #ifdef MP-WEIXIN uni.getLocation({ type: 'gcj02', success: resolve, fail: reject }); // #endif // #ifdef APP-PLUS uni.getLocation({ type: 'gcj02', geocode: true, success: resolve, fail: reject }); // #endif }); } let trajectoryTimer = null; function startTrajectory(workOrderId) { stopTrajectory(); trajectoryTimer = setInterval(async () => { try { const loc = await getLocation(); await apiPost('/gps/trajectory', { workOrderId, latitude: loc.latitude, longitude: loc.longitude, timestamp: new Date().toISOString() }); } catch (e) {} }, 30000); } function stopTrajectory() { if (trajectoryTimer) { clearInterval(trajectoryTimer); trajectoryTimer = null; } } // ==================== 拍照 ==================== function chooseImage(count = 1) { return new Promise((resolve, reject) => { uni.chooseImage({ count, sizeType: ['compressed'], // #ifdef MP-WEIXIN sourceType: ['camera'], // #endif // #ifdef APP-PLUS sourceType: ['camera', 'album'], // #endif success: resolve, fail: reject }); }); } // ==================== 文件上传 ==================== async function uploadEvidence(filePath, entityType, entityId) { const fileName = filePath.split('/').pop() || 'photo.jpg'; const ft = fileName.endsWith('.mp4') ? 'VIDEO' : fileName.endsWith('.mp3') ? 'AUDIO' : 'PHOTO'; const presignRes = await apiPost('/evidence/presign-upload', { fileName, fileType: ft, entityType, entityId }); if (presignRes.data.code !== 200) throw new Error('PreSign failed'); const { fileKey } = presignRes.data.data; return new Promise((resolve, reject) => { uni.uploadFile({ url: BASE_URL + '/evidence/commit', filePath, name: 'file', formData: { fileKey, fileName, fileHash: '', fileSize: '0', contentType: 'image/jpeg' }, header: getHeaders(), success: (r) => { try { resolve({ fileKey, response: JSON.parse(r.data) }); } catch (e) { resolve({ fileKey, response: r.data }); } }, fail: reject }); }); } module.exports = { addWatermark, BASE_URL, apiGet, apiPost, generateIdempotencyKey, getLocation, startTrajectory, stopTrajectory, chooseImage, uploadEvidence, };