/** * 配速:每公里用时(秒) * 支持 390、6:30、6'30"、6′30″、3"00"(分+秒直引号) */ const MANUAL_PACE_MIN_SEC = 180 // 3'00"/km const MANUAL_PACE_MAX_SEC = 600 // 10'00"/km function parsePaceToSecPerKm(input) { if (input === '' || input === null || input === undefined) { throw new Error('缺少配速') } const s = String(input).trim() if (/^\d+(\.\d+)?$/.test(s)) { const n = parseFloat(s) if (n < 10) { throw new Error('纯数字配速表示每公里秒数,例如 390 表示 6:30/km') } return n } const colon = s.match(/^(\d+)[::](\d{1,2}(?:\.\d+)?)$/) if (colon) { return parseInt(colon[1], 10) * 60 + parseFloat(colon[2]) } const quote = s.match(/^(\d+)['′『](\d{1,2}(?:\.\d+)?)[""″』]?$/) if (quote) { return parseInt(quote[1], 10) * 60 + parseFloat(quote[2]) } const weirdQuote = s.match(/^(\d+)"(\d{2})"$/) if (weirdQuote) { return parseInt(weirdQuote[1], 10) * 60 + parseInt(weirdQuote[2], 10) } throw new Error(`无法解析配速「${s}」,请使用 5:30、5'30" 或每公里秒数如 330`) } function clampManualPaceSec(sec) { const n = Number(sec) if (!Number.isFinite(n)) { throw new Error('配速无效') } if (n < MANUAL_PACE_MIN_SEC || n > MANUAL_PACE_MAX_SEC) { throw new Error(`单次乐跑配速需在 3:00–10:00 /km(${MANUAL_PACE_MIN_SEC}–${MANUAL_PACE_MAX_SEC} 秒/公里)`) } return n } /** 自动乐跑:闭区间随机秒/公里 */ function randomPaceSecPerKm(minSec, maxSec) { const lo = Math.max(120, Math.min(minSec, maxSec)) const hi = Math.max(lo, Math.max(minSec, maxSec)) return Math.round(lo + Math.random() * (hi - lo)) } module.exports = { parsePaceToSecPerKm, clampManualPaceSec, randomPaceSecPerKm, MANUAL_PACE_MIN_SEC, MANUAL_PACE_MAX_SEC }