const { v4: uuidv4 } = require('uuid'); const crypto = require('crypto'); /** * 生成唯一会员码 */ function generateMemberCode() { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substring(2, 8); return `M${timestamp}${random}`.toUpperCase(); } /** * 生成比赛码 */ function generateMatchCode() { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substring(2, 6); return `G${timestamp}${random}`.toUpperCase(); } /** * 生成订单号 */ function generateOrderNo() { const date = new Date(); const dateStr = date.getFullYear().toString() + (date.getMonth() + 1).toString().padStart(2, '0') + date.getDate().toString().padStart(2, '0'); const random = Math.random().toString().substring(2, 10); return `PO${dateStr}${random}`; } /** * 生成兑换码 */ function generateExchangeCode() { return uuidv4().replace(/-/g, '').toUpperCase().substring(0, 16); } /** * 计算两点之间的距离(米) */ function calculateDistance(lat1, lon1, lat2, lon2) { const R = 6371000; // 地球半径(米) const dLat = toRad(lat2 - lat1); const dLon = toRad(lon2 - lon1); const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; } function toRad(value) { return value * Math.PI / 180; } /** * 分页参数处理 */ function getPagination(page = 1, pageSize = 10) { const limit = Math.min(parseInt(pageSize) || 10, 100); const offset = (Math.max(parseInt(page) || 1, 1) - 1) * limit; return { limit, offset }; } /** * 统一响应格式 */ function success(data = null, message = '操作成功') { return { code: 0, message, data }; } function error(message = '操作失败', code = 500) { return { code, message }; } function pageResult(list, total, page, pageSize) { return { code: 0, data: { list, pagination: { total, page: parseInt(page), pageSize: parseInt(pageSize), totalPages: Math.ceil(total / pageSize) } } }; } /** * 获取完整URL(处理头像等资源路径) * @param {string} path - 相对路径或完整URL * @param {object} req - Express request对象(用于获取host) * @returns {string} 完整URL */ function getFullUrl(path, req) { if (!path) return ''; // 已经是完整URL,直接返回 if (path.startsWith('http://') || path.startsWith('https://')) { return path; } // 相对路径,拼接服务器地址 // 支持反向代理(nginx等)的 HTTPS 检测 let protocol = 'http'; if (req) { // 优先使用 X-Forwarded-Proto 头(反向代理设置) const forwardedProto = req.get('X-Forwarded-Proto'); if (forwardedProto) { protocol = forwardedProto; } else { // 使用 req.protocol(Express 会自动处理) protocol = req.protocol; } // 如果设置了环境变量强制使用 HTTPS if (process.env.FORCE_HTTPS === 'true') { protocol = 'https'; } } // 获取主机地址 let host = `localhost:${process.env.PORT || 3000}`; if (req) { // 优先使用 X-Forwarded-Host(反向代理设置) const forwardedHost = req.get('X-Forwarded-Host'); if (forwardedHost) { host = forwardedHost; } else { host = req.get('host') || host; } } // 如果设置了 BASE_URL 环境变量,直接使用 if (process.env.BASE_URL) { const baseUrl = process.env.BASE_URL.replace(/\/$/, ''); // 移除末尾斜杠 const pathWithoutLeadingSlash = path.startsWith('/') ? path : `/${path}`; return `${baseUrl}${pathWithoutLeadingSlash}`; } return `${protocol}://${host}${path}`; } module.exports = { generateMemberCode, generateMatchCode, generateOrderNo, generateExchangeCode, calculateDistance, getPagination, success, error, pageResult, getFullUrl };