yingsa/server/src/utils/helper.js

160 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.protocolExpress 会自动处理)
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
};