102 行
3.0 KiB
JavaScript
102 行
3.0 KiB
JavaScript
/**
|
||
* 格式化工具集
|
||
*/
|
||
|
||
import config from '../config/index.js'
|
||
|
||
/** 金额分转元 */
|
||
export function fen2yuan(fen) {
|
||
return (Number(fen || 0) / 100).toFixed(2)
|
||
}
|
||
|
||
/** 金额元转分 */
|
||
export function yuan2fen(yuan) {
|
||
return Math.round(Number(yuan || 0) * 100)
|
||
}
|
||
|
||
/** 统一解析时间入参,避免 ISO / '-' / '/' 混用导致 Invalid Date */
|
||
function toDate(input) {
|
||
if (input instanceof Date) return input
|
||
const s = String(input)
|
||
let d = new Date(s)
|
||
if (isNaN(d.getTime())) d = new Date(s.replace(/-/g, '/'))
|
||
return d
|
||
}
|
||
|
||
/** 时间戳/日期串 -> YYYY-MM-DD HH:mm */
|
||
export function formatTime(input) {
|
||
if (!input) return ''
|
||
const d = toDate(input)
|
||
if (isNaN(d.getTime())) return String(input)
|
||
const p = (n) => String(n).padStart(2, '0')
|
||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`
|
||
}
|
||
|
||
/** 相对时间:刚刚 / N分钟前 / N小时前 / N天前 */
|
||
export function fromNow(input) {
|
||
|
||
if (!input) return ''
|
||
const d = toDate(input)
|
||
if (isNaN(d.getTime())) return String(input)
|
||
const diff = Math.floor((Date.now() - d.getTime()) / 1000)
|
||
if (diff < 60) return '刚刚'
|
||
if (diff < 3600) return `${Math.floor(diff / 60)}分钟前`
|
||
if (diff < 86400) return `${Math.floor(diff / 3600)}小时前`
|
||
if (diff < 86400 * 30) return `${Math.floor(diff / 86400)}天前`
|
||
return formatTime(input)
|
||
}
|
||
|
||
/** 手机号脱敏 */
|
||
export function maskPhone(phone) {
|
||
const s = String(phone || '')
|
||
return s.length === 11 ? s.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : s
|
||
}
|
||
|
||
/** 距离格式化(米) */
|
||
export function formatDistance(meters) {
|
||
const m = Number(meters || 0)
|
||
if (m < 1000) return `${Math.round(m)}m`
|
||
return `${(m / 1000).toFixed(1)}km`
|
||
}
|
||
|
||
/**
|
||
* 距离格式化(千米,一位小数)
|
||
* 契约 §2.1:feed / 详情下发的 distance 单位为 km(一位小数),无坐标时为 null。
|
||
*/
|
||
export function formatKm(km) {
|
||
if (km === null || km === undefined || km === '') return ''
|
||
const n = Number(km)
|
||
if (isNaN(n)) return ''
|
||
return `${n.toFixed(1)}km`
|
||
}
|
||
|
||
/**
|
||
* 资源地址:后端统一返回**相对路径**(/uploads/YYYYMMDD/xxx.jpg,与用户头像口径一致),
|
||
* 小程序 `<image src="/uploads/...">` 会被当成包内路径而裂图,因此展示前必须拼上后端域名。
|
||
* 已是 http(s)/data/blob 的地址原样返回。
|
||
* @param {string} url
|
||
* @returns {string}
|
||
*/
|
||
export function assetUrl(url) {
|
||
const s = String(url == null ? '' : url)
|
||
if (!s) return ''
|
||
if (/^(https?:)?\/\//i.test(s) || /^(data|blob):/i.test(s)) return s
|
||
// config.baseURL 形如 https://host/api,这里只取域名部分(uploads 挂在站点根目录)
|
||
const origin = String(config.baseURL || '').replace(/^(https?:\/\/[^/]+).*$/i, '$1')
|
||
return origin + (s.charAt(0) === '/' ? s : '/' + s)
|
||
}
|
||
|
||
export const formatRelativeTime = fromNow
|
||
|
||
export default {
|
||
formatRelativeTime,
|
||
fen2yuan,
|
||
yuan2fen,
|
||
formatTime,
|
||
fromNow,
|
||
maskPhone,
|
||
formatDistance,
|
||
formatKm,
|
||
assetUrl,
|
||
}
|