182 lines
5.0 KiB
JavaScript
182 lines
5.0 KiB
JavaScript
export function asList(raw) {
|
||
if (Array.isArray(raw)) return raw.filter((x) => x && typeof x === 'object')
|
||
if (raw && typeof raw === 'object') {
|
||
const nested = raw.records || raw.list || raw.items || raw.messages || raw.projects || raw.data
|
||
if (Array.isArray(nested)) return nested.filter((x) => x && typeof x === 'object')
|
||
return [raw]
|
||
}
|
||
return []
|
||
}
|
||
|
||
export function firstText(row, keys, fallback = '') {
|
||
for (const k of keys) {
|
||
const v = row && row[k]
|
||
if (v != null && String(v).trim() && String(v) !== 'null') return String(v).trim()
|
||
}
|
||
return fallback
|
||
}
|
||
|
||
export function initial(name) {
|
||
const s = String(name || '').trim()
|
||
return s ? s.slice(0, 1) : '?'
|
||
}
|
||
|
||
export function maskPhone(phone) {
|
||
const s = String(phone || '')
|
||
if (s.length < 7) return s
|
||
return s.slice(0, 3) + '****' + s.slice(-4)
|
||
}
|
||
|
||
function asDate(t) {
|
||
if (t == null || t === '') return null
|
||
let d
|
||
const n = Number(t)
|
||
if (!Number.isNaN(n) && String(t).length >= 10) {
|
||
d = new Date(n < 1e12 ? n * 1000 : n)
|
||
} else {
|
||
d = new Date(t)
|
||
}
|
||
if (Number.isNaN(d.getTime())) return null
|
||
return d
|
||
}
|
||
|
||
function dayStart(d) {
|
||
return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime()
|
||
}
|
||
|
||
function period(d) {
|
||
const h = d.getHours()
|
||
if (h < 6) return '凌晨'
|
||
if (h < 12) return '上午'
|
||
if (h < 13) return '中午'
|
||
if (h < 18) return '下午'
|
||
return '晚上'
|
||
}
|
||
|
||
function hm12(d) {
|
||
const h = d.getHours() % 12 || 12
|
||
const m = String(d.getMinutes()).padStart(2, '0')
|
||
return `${h}:${m}`
|
||
}
|
||
|
||
export function fmtTime(t) {
|
||
const d = asDate(t)
|
||
if (!d) return t == null ? '' : String(t)
|
||
const label = period(d) + hm12(d)
|
||
const now = new Date()
|
||
const diff = (dayStart(now) - dayStart(d)) / 86400000
|
||
if (diff === 0) return label
|
||
if (diff === 1) return '昨天 ' + label
|
||
if (diff < 7) {
|
||
const week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
|
||
return week[d.getDay()] + ' ' + label
|
||
}
|
||
return `${d.getMonth() + 1}月${d.getDate()}日 ${label}`
|
||
}
|
||
|
||
export function fmtListTime(t) {
|
||
const d = asDate(t)
|
||
if (!d) return t == null ? '' : String(t)
|
||
const now = new Date()
|
||
const diff = (dayStart(now) - dayStart(d)) / 86400000
|
||
if (diff === 0) return period(d) + hm12(d)
|
||
if (diff === 1) return '昨天'
|
||
if (diff < 7) {
|
||
const week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
|
||
return week[d.getDay()]
|
||
}
|
||
return `${d.getMonth() + 1}月${d.getDate()}日`
|
||
}
|
||
|
||
export function pad2(n) {
|
||
return String(n).padStart(2, '0')
|
||
}
|
||
|
||
/** 弹性:9:00–9:30 上班,18:00–18:30 下班。早于 9:00、晚于 18:30 的分钟计入调休。 */
|
||
export function flexCreditMinutes(inTime, outTime) {
|
||
const inn = hmMinutes(inTime)
|
||
const out = hmMinutes(outTime)
|
||
let extra = 0
|
||
if (inn != null && inn < 9 * 60) extra += 9 * 60 - inn
|
||
if (out != null && out > 18 * 60 + 30) extra += out - (18 * 60 + 30)
|
||
return extra
|
||
}
|
||
|
||
export function flexCreditText(minutes) {
|
||
const n = Math.max(0, Math.round(Number(minutes) || 0))
|
||
if (!n) return '0 分钟'
|
||
const h = Math.floor(n / 60)
|
||
const m = n % 60
|
||
if (h && m) return h + ' 小时 ' + m + ' 分钟'
|
||
if (h) return h + ' 小时'
|
||
return m + ' 分钟'
|
||
}
|
||
|
||
function hmMinutes(value) {
|
||
const m = String(value || '').match(/(\d{1,2}):(\d{2})/)
|
||
if (!m) return null
|
||
const h = Number(m[1])
|
||
const min = Number(m[2])
|
||
if (h > 23 || min > 59) return null
|
||
return h * 60 + min
|
||
}
|
||
|
||
export function clockText(date) {
|
||
const d = date || new Date()
|
||
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`
|
||
}
|
||
|
||
export function yuan(v) {
|
||
const n = Number(v)
|
||
if (Number.isNaN(n)) return ''
|
||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||
}
|
||
|
||
export function dmId(a, b) {
|
||
const pair = [String(a), String(b)].sort()
|
||
return `dm:${pair[0]}:${pair[1]}`
|
||
}
|
||
|
||
export function convType(s) {
|
||
const t = String((s && s.type) || '')
|
||
if (t === 'dm') return 'direct'
|
||
if (t === 'group' || t === 'work' || t === 'files' || t === 'direct') return t
|
||
const id = String((s && s.id) || '')
|
||
if (id.startsWith('g:')) return 'group'
|
||
if (id.startsWith('work:')) return 'work'
|
||
if (id.startsWith('files:')) return 'files'
|
||
return 'direct'
|
||
}
|
||
|
||
const FLOW_STATUS = {
|
||
pending: '待审批',
|
||
waiting: '待处理',
|
||
processing: '审批中',
|
||
reviewing: '审阅中',
|
||
review: '待审阅',
|
||
approved: '已通过',
|
||
passed: '已通过',
|
||
rejected: '已驳回',
|
||
refused: '已拒绝',
|
||
denied: '已拒绝',
|
||
cancelled: '已撤销',
|
||
canceled: '已撤销',
|
||
withdrawn: '已撤回',
|
||
draft: '草稿',
|
||
done: '已完成',
|
||
completed: '已完成',
|
||
handled: '已处理',
|
||
reviewed: '已审阅',
|
||
running: '进行中'
|
||
}
|
||
|
||
export function flowStatus(status) {
|
||
const raw = String(status || '').trim()
|
||
if (!raw) return '待处理'
|
||
return FLOW_STATUS[raw.toLowerCase()] || raw
|
||
}
|
||
|
||
export function toast(title, icon = 'none') {
|
||
uni.showToast({ title: String(title || ''), icon, duration: 2200 })
|
||
}
|