/** * Web 路由 → 手机页。工作台 shortcuts / pendingItems 下发的是 Web path。 */ export function mobileUrl(webPath, extra = {}) { const raw = String(webPath || '').trim() if (!raw) return '' if (raw.startsWith('/pages/')) return raw const qIndex = raw.indexOf('?') const path = qIndex >= 0 ? raw.slice(0, qIndex) : raw const query = qIndex >= 0 ? raw.slice(qIndex + 1) : '' const no = extra.no || extra.id || extra.requestNo || '' if (path === '/apply') return '/pages/apply/list' const apply = path.match(/^\/apply\/([^/]+)$/) if (apply) return '/pages/apply/form?kind=' + encodeURIComponent(apply[1]) if (path.startsWith('/todo')) { if (no) return '/pages/todo/detail?no=' + encodeURIComponent(no) const tab = path.split('/')[2] || 'pending' return '/pages/todo/list?tab=' + encodeURIComponent(tab) } if (path === '/contacts') return '/pages/tabs/contacts' if (path === '/profile' || path === '/me') return '/pages/me/archive' if (path.startsWith('/hr/notice') || path === '/notice') return '/pages/notice/list' if (path.startsWith('/report')) return '/pages/reports/list' if (path.includes('clock') || path.includes('attend')) return '/pages/tabs/clock' if (path.startsWith('/work')) { if (no) return '/pages/coop/detail?id=' + encodeURIComponent(no) return '/pages/coop/list' } const erp = [ ['/project', 'project'], ['/bidding', 'bidding'], ['/finance', 'finance'], ['/hr', 'hr'], ['/contracts', 'contracts'], ['/seals', 'seals'], ['/crm', 'crm'], ['/system', 'system'] ] for (const [prefix, id] of erp) { if (path === prefix || path.startsWith(prefix + '/')) return '/pages/erp/hub?id=' + id } if (query) { const mapped = mobileUrl(path, extra) if (mapped && mapped.includes('?')) return mapped + '&' + query if (mapped) return mapped + '?' + query } return '' } export function openHref(webPath, extra = {}) { const url = mobileUrl(webPath, extra) if (!url) return false if (url.startsWith('/pages/tabs/')) { uni.switchTab({ url: url.split('?')[0] }) return true } uni.navigateTo({ url }) return true } const BLUE = ['#1677FF', '#E8F1FF'] const CYAN = ['#0891B2', '#E6F7FB'] const GREEN = ['#16A34A', '#E8F8EF'] const ORANGE = ['#EA580C', '#FFF1E8'] const AMBER = ['#D97706', '#FFF6E8'] const VIOLET = ['#7C3AED', '#F3EEFF'] const ROSE = ['#E11D48', '#FFE8EE'] const TEAL = ['#0D9488', '#E6F7F4'] function tile(name, pair) { return { name, color: pair[0], bg: pair[1] } } const TILES = { expense: tile('money-circle', ORANGE), loan: tile('wallet', AMBER), leave: tile('calendar', GREEN), trip: tile('location', BLUE), procurement: tile('cart', ORANGE), overtime: tile('time', AMBER), outing: tile('location', CYAN), card: tile('edit-1', ROSE), transfer: tile('swap', VIOLET), regularize: tile('check-circle', GREEN), resign: tile('logout', ROSE), layoff: tile('user-clear', ROSE), seal: tile('secured', AMBER), receive: tile('goods', TEAL), clock: tile('location', BLUE), todo: tile('check-circle', GREEN), apply: tile('edit', ORANGE), report: tile('note', VIOLET), salary: tile('creditcard', GREEN), perf: tile('chart-bar', BLUE), archive: tile('user', CYAN), notice: tile('notification', ROSE), coop: tile('usergroup', TEAL), contacts: tile('call', BLUE), bidding: tile('flag', ORANGE), project: tile('folder', BLUE), finance: tile('chart-pie', GREEN), hr: tile('usergroup', CYAN), contracts: tile('file', VIOLET), seals: tile('secured', VIOLET), crm: tile('shop', TEAL), system: tile('setting', BLUE) } const LABEL_TILES = [ ['报销', 'expense'], ['借支', 'loan'], ['请假', 'leave'], ['出差', 'trip'], ['采购', 'procurement'], ['加班', 'overtime'], ['外出', 'outing'], ['补卡', 'card'], ['转岗', 'transfer'], ['转正', 'regularize'], ['离职', 'resign'], ['裁员', 'layoff'], ['用章', 'seal'], ['领用', 'receive'], ['打卡', 'clock'], ['考勤', 'clock'], ['待办', 'todo'], ['审批', 'todo'], ['申请', 'apply'], ['汇报', 'report'], ['工资', 'salary'], ['绩效', 'perf'], ['资料', 'archive'], ['公告', 'notice'], ['协同', 'coop'], ['通讯', 'contacts'], ['投标', 'bidding'], ['项目', 'project'], ['财务', 'finance'], ['人事', 'hr'], ['合同', 'contracts'], ['证照', 'seals'], ['印章', 'seals'], ['客户', 'crm'], ['系统', 'system'] ] const FALLBACK = tile('app', BLUE) function applyKind(to) { const q = to.indexOf('kind=') if (q >= 0) { const rest = to.slice(q + 5) const end = rest.indexOf('&') return decodeURIComponent(end >= 0 ? rest.slice(0, end) : rest) } const mark = '/apply/' const p = to.indexOf(mark) if (p < 0) return '' const rest = to.slice(p + mark.length) const cut = rest.search(/[?#]/) return decodeURIComponent(cut >= 0 ? rest.slice(0, cut) : rest) } export function tileVisual(item) { const to = String((item && (item.to || item.url || item.path)) || '') const kind = applyKind(to) if (kind && TILES[kind]) return TILES[kind] const id = String((item && (item.id || item.kind || item.key)) || '') if (TILES[id]) return TILES[id] const label = String((item && (item.label || item.title)) || '') const hit = LABEL_TILES.find(([k]) => label.includes(k)) return hit && TILES[hit[1]] ? TILES[hit[1]] : FALLBACK } export function tileEmoji(item) { return tileVisual(item).name }