工作台图标
This commit is contained in:
+11
-11
@@ -8,25 +8,25 @@ export const PERSONAL_APPS = [
|
||||
{ id: 'todo', title: '待办审批', icon: '☑', menu: 'personal', action: 'approve', url: '/pages/todo/list', badge: 'todo' },
|
||||
{ id: 'apply', title: '发起申请', icon: '✎', menu: 'personal', action: 'apply', url: '/pages/apply/list' },
|
||||
{ id: 'expense', title: '我的报销', icon: '🧾', menu: 'personal', action: 'view', url: '/pages/bills/list?type=expense&title=我的报销' },
|
||||
{ id: 'loan', title: '我的借支', icon: '¥', menu: 'personal', action: 'view', url: '/pages/bills/list?type=loan&title=我的借支' },
|
||||
{ id: 'report', title: '工作汇报', icon: '▤', menu: 'personal', action: 'report', url: '/pages/reports/list' },
|
||||
{ id: 'loan', title: '我的借支', icon: '💰', menu: 'personal', action: 'view', url: '/pages/bills/list?type=loan&title=我的借支' },
|
||||
{ id: 'report', title: '工作汇报', icon: '📝', menu: 'personal', action: 'report', url: '/pages/reports/list' },
|
||||
{ id: 'salary', title: '工资条', icon: '💳', menu: 'personal', action: 'view', url: '/pages/me/payslip' },
|
||||
{ id: 'perf', title: '我的绩效', icon: '↗', menu: 'personal', action: 'view', url: '/pages/me/performance' },
|
||||
{ id: 'perf', title: '我的绩效', icon: '📈', menu: 'personal', action: 'view', url: '/pages/me/performance' },
|
||||
{ id: 'archive', title: '我的资料', icon: '👤', menu: 'personal', action: 'view', url: '/pages/me/archive' },
|
||||
{ id: 'notice', title: '公告', icon: '📢', menu: 'personal', action: 'view', url: '/pages/notice/list' },
|
||||
{ id: 'coop', title: '工作协同', icon: '🤝', menu: 'personal', action: 'view', url: '/pages/coop/list' },
|
||||
{ id: 'seals', title: '我的用章', icon: '©', menu: 'personal', action: 'view', url: '/pages/bills/list?type=seal&title=我的用章' },
|
||||
{ id: 'seals', title: '我的用章', icon: '🔖', menu: 'personal', action: 'view', url: '/pages/bills/list?type=seal&title=我的用章' },
|
||||
{ id: 'contacts', title: '通讯录', icon: '☎', menu: 'personal', action: 'view', url: '/pages/tabs/contacts' }
|
||||
]
|
||||
|
||||
export const ERP_MODULES = [
|
||||
{ id: 'bidding', title: '投标管理', icon: '◎', menu: 'bidding', action: 'view', url: '/pages/erp/hub?id=bidding' },
|
||||
{ id: 'project', title: '项目管理', icon: '▣', menu: 'project', action: 'view', url: '/pages/erp/hub?id=project' },
|
||||
{ id: 'finance', title: '财务管理', icon: '◈', menu: 'finance', action: 'view', url: '/pages/erp/hub?id=finance' },
|
||||
{ id: 'hr', title: '人事管理', icon: '☰', menu: 'hr', action: 'view', url: '/pages/erp/hub?id=hr' },
|
||||
{ id: 'contracts', title: '合同管理', icon: '▤', menu: 'contracts', action: 'view', url: '/pages/erp/hub?id=contracts' },
|
||||
{ id: 'seals', title: '证照用章', icon: '◆', menu: 'seals', action: 'view', url: '/pages/erp/hub?id=seals' },
|
||||
{ id: 'crm', title: '客户管理', icon: '◇', menu: 'crm', action: 'view', url: '/pages/erp/hub?id=crm' },
|
||||
{ id: 'bidding', title: '投标管理', icon: '🎯', menu: 'bidding', action: 'view', url: '/pages/erp/hub?id=bidding' },
|
||||
{ id: 'project', title: '项目管理', icon: '📁', menu: 'project', action: 'view', url: '/pages/erp/hub?id=project' },
|
||||
{ id: 'finance', title: '财务管理', icon: '💹', menu: 'finance', action: 'view', url: '/pages/erp/hub?id=finance' },
|
||||
{ id: 'hr', title: '人事管理', icon: '👥', menu: 'hr', action: 'view', url: '/pages/erp/hub?id=hr' },
|
||||
{ id: 'contracts', title: '合同管理', icon: '📄', menu: 'contracts', action: 'view', url: '/pages/erp/hub?id=contracts' },
|
||||
{ id: 'seals', title: '证照用章', icon: '🔏', menu: 'seals', action: 'view', url: '/pages/erp/hub?id=seals' },
|
||||
{ id: 'crm', title: '客户管理', icon: '🏢', menu: 'crm', action: 'view', url: '/pages/erp/hub?id=crm' },
|
||||
{ id: 'system', title: '系统管理', icon: '⚙', menu: 'system', action: 'view', url: '/pages/erp/hub?id=system' }
|
||||
]
|
||||
|
||||
|
||||
+85
-16
@@ -63,23 +63,92 @@ export function openHref(webPath, extra = {}) {
|
||||
return true
|
||||
}
|
||||
|
||||
const EMOJI = {
|
||||
expense: '🧾', loan: '¥', leave: '休', trip: '✈', procurement: '购',
|
||||
overtime: '加', outing: '出', card: '补', transfer: '转', regularize: '正',
|
||||
resign: '离', layoff: '裁', seal: '章', receive: '领', clock: '📍',
|
||||
todo: '☑', apply: '✎', report: '▤', salary: '💳', perf: '↗',
|
||||
archive: '👤', notice: '📢', coop: '🤝', contacts: '☎',
|
||||
bidding: '◎', project: '▣', finance: '◈', hr: '☰', contracts: '▤',
|
||||
seals: '◆', crm: '◇', system: '⚙'
|
||||
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) {
|
||||
if (item && item.emoji) return item.emoji
|
||||
const to = String((item && (item.to || item.url || item.path)) || '')
|
||||
const m = to.match(/\/apply\/([^/?]+)/)
|
||||
if (m && EMOJI[m[1]]) return EMOJI[m[1]]
|
||||
const id = String((item && (item.id || item.kind || item.key)) || '')
|
||||
if (EMOJI[id]) return EMOJI[id]
|
||||
const label = String((item && (item.label || item.title)) || '')
|
||||
return label ? label.slice(0, 1) : '·'
|
||||
return tileVisual(item).name
|
||||
}
|
||||
|
||||
+17
-4
@@ -73,7 +73,7 @@ function mapMsg(raw, meId, typeu) {
|
||||
href: String((raw && raw.href) || p.href || ''),
|
||||
duration: Number((raw && raw.duration) || p.duration) || 0,
|
||||
quote: p.quote || raw.quote || null,
|
||||
read: !!(raw && (raw.read === true || raw.readAt || raw.isRead)),
|
||||
read: !!(raw && (raw.read === true || raw.read === 1 || raw.read === '1' || raw.readAt || raw.isRead === true || raw.isRead === 1)),
|
||||
readReceipt: (raw && raw.readReceipt) || p.readReceipt || null
|
||||
}
|
||||
}
|
||||
@@ -394,8 +394,14 @@ export const store = {
|
||||
return
|
||||
}
|
||||
if (typeu === ImTypeu.read) {
|
||||
const sid = String(data.sessionId || pack.to || '')
|
||||
const conv = this.findConv(sid) || this.findConv(this.dmIdOf(pack.from))
|
||||
const from = String(pack.from || data.from || '')
|
||||
const me = this.me ? String(this.me.id) : ''
|
||||
if (!from || from === me) {
|
||||
this.emit()
|
||||
return
|
||||
}
|
||||
const sid = String(data.sessionId || '') || this.dmIdOf(from)
|
||||
const conv = this.findConv(sid)
|
||||
if (conv) {
|
||||
;(conv.messages || []).forEach((m) => {
|
||||
if (m.mine && !m.recalled) m.read = true
|
||||
@@ -472,7 +478,14 @@ export const store = {
|
||||
this.activeSid = conv.id
|
||||
try {
|
||||
const rows = await api.messages(conv.id, this.token)
|
||||
const incoming = asList(rows && rows.messages ? rows.messages : rows).map((m) => mapMsg(m, this.me && this.me.id, m.typeu))
|
||||
const prev = new Map((conv.messages || []).filter((m) => m.id).map((m) => [m.id, m]))
|
||||
const incoming = asList(rows && rows.messages ? rows.messages : rows).map((m) => {
|
||||
const msg = mapMsg(m, this.me && this.me.id, m.typeu)
|
||||
const old = prev.get(msg.id)
|
||||
if (old && old.read) msg.read = true
|
||||
if (old && old.readReceipt && !msg.readReceipt) msg.readReceipt = old.readReceipt
|
||||
return msg
|
||||
})
|
||||
const seen = new Set(incoming.map((m) => m.id).filter(Boolean))
|
||||
const extras = (conv.messages || []).filter((m) => m.mine && m.id && !seen.has(m.id) && Date.now() - Number(m.time) < 120000)
|
||||
conv.messages = incoming.concat(extras)
|
||||
|
||||
Reference in New Issue
Block a user