| 292 | } |
| 293 | |
| 294 | private parseTimeString(timeStr: string): number | null { |
| 295 | // 支持多种格式: |
| 296 | // 英文全称/复数:30 second(s), 5 minute(s), 2 hour(s), 1 day(s) |
| 297 | // 英文简写:30s, 5m, 2h, 1d, sec/secs, min/mins, hr/hrs |
| 298 | // 中文单位:30秒, 5分, 5分钟, 2小时/2时, 1天(大小写与空格均可忽略) |
| 299 | if (!timeStr) return null; |
| 300 | const str = String(timeStr).trim(); |
| 301 | |
| 302 | // 统一移除多余空格 |
| 303 | const compact = str.replace(/\s+/g, ""); |
| 304 | |
| 305 | // 先尝试英文“数字+单位(可空格)”形式 |
| 306 | const matchLoose = str.match(/^\s*(\d+)\s*(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d)\s*$/i); |
| 307 | if (matchLoose) { |
| 308 | const value = parseInt(matchLoose[1], 10); |
| 309 | const unitRaw = matchLoose[2].toLowerCase(); |
| 310 | const unit = unitRaw as string; |
| 311 | |
| 312 | const multipliers: Record<string, number> = { |
| 313 | s: 1, sec: 1, secs: 1, second: 1, seconds: 1, |
| 314 | m: 60, min: 60, mins: 60, minute: 60, minutes: 60, |
| 315 | h: 3600, hr: 3600, hrs: 3600, hour: 3600, hours: 3600, |
| 316 | d: 86400, day: 86400, days: 86400 |
| 317 | }; |
| 318 | |
| 319 | // 归一化到键 |
| 320 | const key = ( |
| 321 | unit === 's' || unit === 'sec' || unit === 'secs' || unit === 'second' || unit === 'seconds' ? 'seconds' : |
| 322 | unit === 'm' || unit === 'min' || unit === 'mins' || unit === 'minute' || unit === 'minutes' ? 'minutes' : |
| 323 | unit === 'h' || unit === 'hr' || unit === 'hrs' || unit === 'hour' || unit === 'hours' ? 'hours' : |
| 324 | unit === 'd' || unit === 'day' || unit === 'days' ? 'days' : unit |
| 325 | ); |
| 326 | |
| 327 | const mul = multipliers[key]; |
| 328 | return Number.isFinite(mul) ? value * mul : null; |
| 329 | } |
| 330 | |
| 331 | // 再尝试英文“紧凑简写”形式(如 30s/5m/2h/1d) |
| 332 | const matchCompact = compact.match(/^(\d+)(s|sec|secs|m|min|mins|h|hr|hrs|d)$/i); |
| 333 | if (matchCompact) { |
| 334 | const value = parseInt(matchCompact[1], 10); |
| 335 | const unit = matchCompact[2].toLowerCase(); |
| 336 | const multipliers: Record<string, number> = { |
| 337 | s: 1, sec: 1, secs: 1, |
| 338 | m: 60, min: 60, mins: 60, |
| 339 | h: 3600, hr: 3600, hrs: 3600, |
| 340 | d: 86400 |
| 341 | }; |
| 342 | const mul = multipliers[unit]; |
| 343 | return Number.isFinite(mul) ? value * mul : null; |
| 344 | } |
| 345 | |
| 346 | // 中文单位(支持:秒/分/分钟/小时/时/天),也兼容中英混写无空格 |
| 347 | const zhMatch = compact.match(/^(\d+)(秒|分|分钟|小时|时|天)$/); |
| 348 | if (zhMatch) { |
| 349 | const value = parseInt(zhMatch[1], 10); |
| 350 | const unit = zhMatch[2]; |
| 351 | const multipliers: Record<string, number> = { |