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 }) }