160 lines
3.9 KiB
JavaScript
160 lines
3.9 KiB
JavaScript
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
|
||
};
|