Files
ONE-OS/web端/工作台.jsx
2026-03-23 09:35:39 +08:00

489 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 【重要】必须使用 const Component 作为组件变量名
// 数字化资产 ONEOS 运管平台 - 工作台(需求见文件内「查看需求说明」)
const Component = function () {
var useState = React.useState;
var useMemo = React.useMemo;
var useCallback = React.useCallback;
var antd = window.antd;
var App = antd.App;
var Row = antd.Row;
var Col = antd.Col;
var Card = antd.Card;
var Statistic = antd.Statistic;
var List = antd.List;
var Tag = antd.Tag;
var Tabs = antd.Tabs;
var Badge = antd.Badge;
var Button = antd.Button;
var Space = antd.Space;
var Divider = antd.Divider;
var Modal = antd.Modal;
var Table = antd.Table;
var Popover = antd.Popover;
var Typography = antd.Typography;
var message = antd.message;
var Text = Typography.Text;
var layoutStyle = { padding: '16px 20px 24px', background: '#f0f2f5', minHeight: '100vh' };
var cardStyle = { borderRadius: 8, boxShadow: '0 1px 2px rgba(0,0,0,0.06)' };
function protoNav(hint) {
message.info('跳转「' + hint + '」(原型,联调配置路由)');
}
var requirementOpenState = useState(false);
var requirementOpen = requirementOpenState[0];
var setRequirementOpen = requirementOpenState[1];
var auditModalState = useState(false);
var auditModalOpen = auditModalState[0];
var setAuditModalOpen = auditModalState[1];
var noticeModalState = useState(false);
var noticeModalOpen = noticeModalState[0];
var setNoticeModalOpen = noticeModalState[1];
var roleTabState = useState('ops');
var roleTab = roleTabState[0];
var setRoleTab = roleTabState[1];
var requirementDoc = [
'一个「数字化资产ONEOS运管平台」中的「工作台」模块',
'#面包屑:工作台',
'',
'1.顶部为关键指标,以多个指标卡片分别展示,分别为:',
'1.1.待办工作:显示待办工作数量,包括以下任务:',
' 1.1.1.运维侧:交车任务、调拨任务、异动任务、年审任务;',
' 1.1.2.业管侧:商业险到期、租赁账单生成、提车应收款、还车应结款;',
' 1.1.3.业管-能源部侧:氢费审核;',
' 权限分配规则:业管、运维基层员工:仅显示当前登录人作为处理人的任务;业管、运维主管:显示所属部门所有未完成任务;',
'1.2.已完成工作:显示已完成工作数量,包括当前用户所有已完成的待办工作;',
'1.3.待审批任务:显示所有待审批任务数量,点击弹出卡片,列表显示流程到达时间、流程类型、发起时间、发起人、操作(去处理);',
'1.4.已审批任务:显示所有已审批任务数量,包括当前用户所有已完成的审批任务;',
'1.5.通知消息:显示所有通知消息数量,点击弹出卡片,列表显示时间、通知类型、内容;(含运维/业管/审批侧各类提醒格式,见需求原文)',
'',
'2.中间分为几个单独卡片:',
'2.1.我的待办清单左侧2.2.数据统计(车辆+合同2.3.我的通知清单:右侧;',
'2.4.底部快速入口:按角色 Tab业管、业管-能源部、运维、财务、安全、法务),图标+名称。',
'',
'(原型:数据为示例;权限与接口联调时对接。)'
].join('\n');
var todoPopoverContent = React.createElement('div', { style: { maxWidth: 360, fontSize: 12, lineHeight: 1.6 } },
React.createElement(Text, { strong: true }, '包含任务类型'),
React.createElement('div', { style: { marginTop: 8 } },
React.createElement('div', null, '【运维】交车、调拨、异动、年审'),
React.createElement('div', null, '【业管】商业险到期、租赁账单生成、提车应收款、还车应结款'),
React.createElement('div', null, '【业管-能源】氢费审核')
),
React.createElement(Divider, { style: { margin: '8px 0' } }),
React.createElement(Text, { type: 'secondary' }, '基层员工:仅本人待办;主管:本部门全部未完成。')
);
var topMetrics = useMemo(function () {
return [
{ key: 'todo', title: '待办工作', value: 18, color: '#722ed1', pop: true },
{ key: 'done', title: '已完成工作', value: 126, color: '#52c41a', pop: false },
{ key: 'auditPending', title: '待审批任务', value: 7, color: '#f5222d', pop: false, modal: 'audit' },
{ key: 'auditDone', title: '已审批任务', value: 89, color: '#1677ff', pop: false },
{ key: 'notice', title: '通知消息', value: 12, color: '#fa8c16', pop: false, modal: 'notice' }
];
}, []);
var myTodoList = useMemo(function () {
return [
{ id: '1', name: '交车任务 · 粤A12345 待确认交车单', time: '2026-02-27 09:00', path: 'web端/运维管理/车辆业务/交车管理.jsx' },
{ id: '2', name: '调拨任务 · 调拨单 DB-2026-009 待接收', time: '2026-02-26 15:20', path: 'web端/运维管理/车辆业务/调拨管理.jsx' },
{ id: '3', name: '异动任务 · 异动单待结束登记', time: '2026-02-26 11:00', path: 'web端/运维管理/车辆业务/异动管理-结束异动.jsx' },
{ id: '4', name: '年审任务 · 粤B11111 年审材料待上传', time: '2026-02-25 10:30', path: 'web端/运维管理/车辆业务/异动管理.jsx' },
{ id: '5', name: '商业险到期 · 粤C22334 续保跟进', time: '2026-02-24 14:00', path: 'web端/车辆管理.jsx' },
{ id: '6', name: '租赁账单生成 · 项目「华南物流」2月账单', time: '2026-02-24 09:00', path: 'web端/业务管理/租赁账单.jsx' },
{ id: '7', name: '提车应收款 · TK-2026-018 待提交', time: '2026-02-23 16:00', path: 'web端/财务管理/提车应收款.jsx' },
{ id: '8', name: '还车应结款 · HC-2026-006 待核对', time: '2026-02-23 11:00', path: 'web端/财务管理/还车应结款.jsx' },
{ id: '9', name: '氢费审核 · 加氢订单待审核', time: '2026-02-22 08:30', path: 'web端/加氢站管理/加氢订单.jsx' }
];
}, []);
var noticeList = useMemo(function () {
return [
{ id: 'n1', time: '2026-02-27 08:00', type: '商业险到期提醒', content: '「粤A12345」商业险将在2026-04-15到期请尽快处理' },
{ id: 'n2', time: '2026-02-26 18:00', type: '营运证到期提醒', content: '「粤B88888」营运证还有90天到期请尽快更新营运证' },
{ id: 'n3', time: '2026-02-26 10:00', type: '行驶证到期提醒', content: '「浙A11111」行驶证还有90天到期请尽快进行年审' },
{ id: 'n4', time: '2026-02-25 14:00', type: '租赁合同到期提醒', content: '「HT-2025-088」「某某产业园项目」还有30天到期请尽快处理' },
{ id: 'n5', time: '2026-02-25 09:00', type: '租赁账单生成提醒', content: '「HT-2025-088」「某某产业园项目」「ZD-202602-031」已生成请尽快处理' },
{ id: 'n6', time: '2026-02-24 11:00', type: '氢费余额不足提醒', content: '「某某物流」「华南干线项目」氢费余额已不足500元请尽快通知客户处理' },
{ id: 'n7', time: '2026-02-24 08:30', type: '审批流程提醒', content: '「李四」「异动审核」审批节点已到达,请进行审批' }
];
}, []);
var pendingAuditList = useMemo(function () {
return [
{ id: 'a1', arriveAt: '2026-02-27 09:15', flowType: '异动审核(运维)', startAt: '2026-02-26 14:00', starter: '张三', path: 'web端/运维管理/车辆业务/异动管理.jsx' },
{ id: 'a2', arriveAt: '2026-02-27 08:40', flowType: '调拨审核(运维)', startAt: '2026-02-25 10:00', starter: '王五', path: 'web端/运维管理/车辆业务/调拨管理.jsx' },
{ id: 'a3', arriveAt: '2026-02-26 16:00', flowType: '替换车审核(运维)', startAt: '2026-02-26 09:30', starter: '赵六', path: 'web端/运维管理/车辆业务/替换车管理.jsx' },
{ id: 'a4', arriveAt: '2026-02-26 11:20', flowType: '租赁账单审核(财务)', startAt: '2026-02-25 17:00', starter: '业管-陈七', path: 'web端/财务管理/租赁账单.jsx' },
{ id: 'a5', arriveAt: '2026-02-25 15:00', flowType: '提车应收款审核(财务)', startAt: '2026-02-24 11:00', starter: '业管-周八', path: 'web端/财务管理/提车应收款.jsx' },
{ id: 'a6', arriveAt: '2026-02-25 10:00', flowType: '还车应结款审核(财务)', startAt: '2026-02-23 16:00', starter: '业管-吴九', path: 'web端/财务管理/还车应结款.jsx' },
{ id: 'a7', arriveAt: '2026-02-24 14:00', flowType: '氢费账单审核(财务)', startAt: '2026-02-23 09:00', starter: '能源-郑十', path: 'web端/财务管理/氢费账单.jsx' },
{ id: 'a8', arriveAt: '2026-02-24 09:00', flowType: '租赁合同审核(法务·附件)', startAt: '2026-02-22 10:00', starter: '业管-钱一', path: 'web端/车辆租赁合同/车辆租赁合同.jsx' },
{ id: 'a9', arriveAt: '2026-02-23 11:00', flowType: 'CEO · 提车应收款', startAt: '2026-02-20 15:00', starter: '财务-孙二', path: 'web端/财务管理/提车应收款.jsx' }
];
}, []);
var vehicleMonthBars = useMemo(function () {
return [
{ m: '3月', op: 62, idle: 18 }, { m: '4月', op: 65, idle: 16 }, { m: '5月', op: 68, idle: 15 },
{ m: '6月', op: 70, idle: 14 }, { m: '7月', op: 72, idle: 13 }, { m: '8月', op: 75, idle: 12 },
{ m: '9月', op: 78, idle: 12 }, { m: '10月', op: 80, idle: 11 }, { m: '11月', op: 82, idle: 11 },
{ m: '12月', op: 85, idle: 10 }, { m: '1月', op: 88, idle: 10 }, { m: '2月', op: 90, idle: 9 }
];
}, []);
var contractMonthBars = useMemo(function () {
return [
{ m: '3月', lease: 8, self: 3 }, { m: '4月', lease: 9, self: 3 }, { m: '5月', lease: 10, self: 4 },
{ m: '6月', lease: 10, self: 4 }, { m: '7月', lease: 11, self: 4 }, { m: '8月', lease: 12, self: 5 },
{ m: '9月', lease: 12, self: 5 }, { m: '10月', lease: 13, self: 5 }, { m: '11月', lease: 14, self: 6 },
{ m: '12月', lease: 14, self: 6 }, { m: '1月', lease: 15, self: 6 }, { m: '2月', lease: 16, self: 7 }
];
}, []);
function renderBarGroup(items, k1, k2, c1, c2) {
var max = 1;
items.forEach(function (it) { max = Math.max(max, it[k1] + it[k2]); });
return React.createElement('div', { style: { display: 'flex', alignItems: 'flex-end', gap: 4, height: 140, paddingTop: 8, overflowX: 'auto' } },
items.map(function (it) {
var h1 = Math.round((it[k1] / max) * 100);
var h2 = Math.round((it[k2] / max) * 100);
return React.createElement('div', { key: it.m, style: { display: 'flex', flexDirection: 'column', alignItems: 'center', minWidth: 26 } },
React.createElement('div', { style: { display: 'flex', alignItems: 'flex-end', gap: 2, height: 108 } },
React.createElement('div', { style: { width: 9, height: h1, background: c1, borderRadius: 2 } }),
React.createElement('div', { style: { width: 9, height: h2, background: c2, borderRadius: 2 } })
),
React.createElement('span', { style: { fontSize: 10, color: 'rgba(0,0,0,0.45)', marginTop: 4 } }, it.m)
);
})
);
}
var quickByRole = useMemo(function () {
return {
ye: {
label: '业管',
items: [
{ t: '租赁合同', p: 'web端/车辆租赁合同/车辆租赁合同.jsx' },
{ t: '交车任务', p: 'web端/业务管理/交车任务.jsx' },
{ t: '提车应收款', p: 'web端/财务管理/提车应收款.jsx' },
{ t: '租赁账单', p: 'web端/业务管理/租赁账单.jsx' },
{ t: '还车应结款', p: 'web端/财务管理/还车应结款.jsx' },
{ t: '能源账户', p: 'web端/业务管理/能源账户.jsx' },
{ t: '氢费账单', p: 'web端/财务管理/氢费账单.jsx' },
{ t: '电费账单', p: 'web端/财务管理/电费账单.jsx' },
{ t: 'ETC账单', p: 'web端/业务管理/ETC管理.jsx' },
{ t: '保险管理', p: 'web端/业务管理/保险管理.jsx' },
{ t: '审批中心', p: 'web端/审批中心.jsx' }
]
},
yeEnergy: {
label: '业管-能源部',
items: [
{ t: '加氢订单管理', p: 'web端/加氢站管理/加氢订单.jsx' }
]
},
ops: {
label: '运维',
items: [
{ t: '车辆管理', p: 'web端/车辆管理.jsx' },
{ t: '证照管理', p: 'web端/运维管理/车辆业务/证照管理.jsx' },
{ t: '备车管理', p: 'web端/运维管理/车辆业务/备车管理.jsx' },
{ t: '交车管理', p: 'web端/运维管理/车辆业务/交车管理.jsx' },
{ t: '还车管理', p: 'web端/运维管理/车辆业务/还车管理.jsx' },
{ t: '替换车管理', p: 'web端/运维管理/车辆业务/替换车管理.jsx' },
{ t: '调拨管理', p: 'web端/运维管理/车辆业务/调拨管理.jsx' },
{ t: '异动管理', p: 'web端/运维管理/车辆业务/异动管理.jsx' },
{ t: '备件库管理', p: 'web端/运维管理/备件管理/备件库存.jsx' }
]
},
finance: {
label: '财务',
items: [
{ t: '提车应收款', p: 'web端/财务管理/提车应收款.jsx' },
{ t: '租赁账单', p: 'web端/财务管理/租赁账单.jsx' },
{ t: '还车应结款', p: 'web端/财务管理/还车应结款.jsx' },
{ t: '审批中心', p: 'web端/审批中心.jsx' },
{ t: '充值单管理', p: 'web端/财务管理/充值单管理.jsx' }
]
},
safety: {
label: '安全',
items: [
{ t: '违章管理', p: 'web端/安全管理/违章管理.jsx' },
{ t: '事故管理', p: 'web端/安全管理/事故管理.jsx' },
{ t: '司机管理', p: 'web端/安全管理/司机管理.jsx' },
{ t: '安全培训资料', p: 'web端/安全管理/安全培训资料.jsx' },
{ t: '安全培训记录', p: 'web端/安全管理/安全培训记录.jsx' }
]
},
legal: {
label: '法务',
items: [
{ t: '审批中心', p: 'web端/审批中心.jsx' }
]
}
};
}, []);
var auditColumns = useMemo(function () {
return [
{ title: '流程到达时间', dataIndex: 'arriveAt', key: 'arriveAt', width: 150 },
{ title: '流程类型', dataIndex: 'flowType', key: 'flowType', ellipsis: true },
{ title: '发起时间', dataIndex: 'startAt', key: 'startAt', width: 140 },
{ title: '发起人', dataIndex: 'starter', key: 'starter', width: 100 },
{
title: '操作',
key: 'act',
width: 88,
render: function (_, r) {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function () { protoNav(r.path); } }, '去处理');
}
}
];
}, []);
var noticeColumns = useMemo(function () {
return [
{ title: '时间', dataIndex: 'time', key: 'time', width: 150 },
{ title: '通知类型', dataIndex: 'type', key: 'type', width: 160 },
{ title: '内容', dataIndex: 'content', key: 'content', ellipsis: true }
];
}, []);
function renderMetricCard(m) {
var inner = React.createElement(Card, {
size: 'small',
bordered: false,
style: Object.assign({}, cardStyle, { minHeight: 108, width: '100%', flex: 1, display: 'flex', flexDirection: 'column' }),
bodyStyle: {
padding: '16px 12px',
cursor: m.modal || m.pop ? 'pointer' : 'default',
flex: 1,
display: 'flex',
alignItems: 'flex-start',
justifyContent: 'center'
},
onClick: function () {
if (m.modal === 'audit') setAuditModalOpen(true);
else if (m.modal === 'notice') setNoticeModalOpen(true);
}
},
React.createElement(Statistic, {
title: React.createElement('span', { style: { fontSize: 13 } }, m.title),
value: m.value,
valueStyle: { color: m.color, fontWeight: 600, fontSize: 24 }
})
);
if (m.pop) {
return React.createElement(Popover, { content: todoPopoverContent, title: '待办工作说明', trigger: 'click' },
React.createElement('div', { style: { display: 'flex', flex: 1, width: '100%', minWidth: 0 } }, inner));
}
return inner;
}
var quickTabItems = useMemo(function () {
return ['ye', 'yeEnergy', 'ops', 'finance', 'safety', 'legal'].map(function (k) {
var g = quickByRole[k];
return {
key: k,
label: g.label,
children: React.createElement(Row, { gutter: [12, 12] },
g.items.map(function (it) {
return React.createElement(Col, { xs: 8, sm: 6, md: 4, lg: 3, key: it.t },
React.createElement(Card, {
size: 'small',
hoverable: true,
bodyStyle: { padding: '12px 8px', textAlign: 'center' },
onClick: function () { protoNav(it.p); }
},
React.createElement('div', {
style: {
width: 40, height: 40, margin: '0 auto 8px', borderRadius: 8,
background: 'linear-gradient(135deg,#e6f4ff,#bae0ff)', lineHeight: '40px', fontSize: 18
}
}, it.t.charAt(0)),
React.createElement('div', { style: { fontSize: 12, fontWeight: 500 } }, it.t)
)
);
})
)
};
});
}, [quickByRole]);
return React.createElement(App, null,
React.createElement('div', { style: layoutStyle },
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8, marginBottom: 8 } },
React.createElement(Space, null,
React.createElement('span', { style: { fontSize: 20, fontWeight: 600, color: 'rgba(0,0,0,0.85)' } }, '工作台'),
React.createElement(Tag, { color: 'default' }, '工作台')
),
React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { setRequirementOpen(true); } }, '查看需求说明')
),
React.createElement(Modal, {
title: '需求说明',
open: requirementOpen,
width: 760,
onCancel: function () { setRequirementOpen(false); },
footer: React.createElement(Button, { onClick: function () { setRequirementOpen(false); } }, '关闭'),
bodyStyle: { maxHeight: '72vh', overflow: 'auto' }
}, React.createElement('div', { style: { whiteSpace: 'pre-wrap', fontSize: 13, lineHeight: 1.65, color: 'rgba(0,0,0,0.85)' } }, requirementDoc)),
React.createElement(Modal, {
title: '待审批任务',
open: auditModalOpen,
width: 900,
onCancel: function () { setAuditModalOpen(false); },
footer: React.createElement(Button, { onClick: function () { setAuditModalOpen(false); } }, '关闭'),
destroyOnClose: true
},
React.createElement(Table, {
size: 'small',
rowKey: 'id',
columns: auditColumns,
dataSource: pendingAuditList,
pagination: { pageSize: 8, showSizeChanger: false }
})
),
React.createElement(Modal, {
title: '通知消息',
open: noticeModalOpen,
width: 860,
onCancel: function () { setNoticeModalOpen(false); },
footer: React.createElement(Button, { onClick: function () { setNoticeModalOpen(false); } }, '关闭'),
destroyOnClose: true
},
React.createElement(Table, {
size: 'small',
rowKey: 'id',
columns: noticeColumns,
dataSource: noticeList,
pagination: { pageSize: 8, showSizeChanger: false }
})
),
React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 16, marginBottom: 16, alignItems: 'stretch' } },
topMetrics.map(function (m) {
return React.createElement('div', { key: m.key, style: { flex: '1 1 160px', minWidth: 148, maxWidth: '100%', display: 'flex' } }, renderMetricCard(m));
})
),
React.createElement(Row, { gutter: [16, 16], style: { marginBottom: 16 } },
React.createElement(Col, { xs: 24, xl: 7 },
React.createElement(Card, {
title: React.createElement(Space, null, '我的待办清单', React.createElement(Badge, { count: myTodoList.length, style: { backgroundColor: '#1677ff' } })),
size: 'small',
bordered: false,
style: cardStyle,
bodyStyle: { maxHeight: 520, overflow: 'auto' }
},
React.createElement(List, {
size: 'small',
dataSource: myTodoList,
locale: { emptyText: '暂无待办' },
renderItem: function (item) {
return React.createElement(List.Item, {
actions: [
React.createElement(Button, { type: 'link', key: 'go', size: 'small', onClick: function () { protoNav(item.path); } }, '去处理')
]
},
React.createElement(List.Item.Meta, {
title: React.createElement('span', { style: { fontSize: 13 } }, item.name),
description: React.createElement(Text, { type: 'secondary', style: { fontSize: 12 } }, '生成时间:' + item.time)
})
);
}
})
)
),
React.createElement(Col, { xs: 24, xl: 10 },
React.createElement(Card, { title: '数据统计', size: 'small', bordered: false, style: Object.assign({ marginBottom: 16 }, cardStyle) },
React.createElement('div', { style: { fontWeight: 600, marginBottom: 12, fontSize: 13 } }, '车辆数据统计'),
React.createElement(Row, { gutter: 8 },
[
{ label: '车辆总数', v: 248 },
{ label: '自营车辆数', v: 32 },
{ label: '库存车辆数', v: 30 },
{ label: '待运营车辆数', v: 12 }
].map(function (s) {
return React.createElement(Col, { span: 12, key: s.label },
React.createElement(Card, { size: 'small', bodyStyle: { padding: '10px 8px' } },
React.createElement(Statistic, { title: s.label, value: s.v, valueStyle: { fontSize: 18 } })
)
);
})
),
React.createElement(Divider, { plain: true, style: { margin: '12px 0 8px', fontSize: 12 } }, '近12个月 · 运营车辆 / 闲置车辆'),
React.createElement('div', { style: { fontSize: 11, color: 'rgba(0,0,0,0.45)', marginBottom: 6 } }, '蓝色:运营 浅蓝:闲置(原型双柱示意)'),
renderBarGroup(vehicleMonthBars, 'op', 'idle', '#1677ff', '#91caff')
),
React.createElement(Card, { title: '合同数据统计', size: 'small', bordered: false, style: cardStyle },
React.createElement(Row, { gutter: 16 },
React.createElement(Col, { span: 12 }, React.createElement(Statistic, { title: '租赁合同总数', value: 58, valueStyle: { color: '#722ed1' } })),
React.createElement(Col, { span: 12 }, React.createElement(Statistic, { title: '自营合同总数', value: 14, valueStyle: { color: '#52c41a' } }))
),
React.createElement(Divider, { plain: true, style: { margin: '12px 0 8px', fontSize: 12 } }, '近12个月 · 租赁合同 / 自营合同'),
React.createElement('div', { style: { fontSize: 11, color: 'rgba(0,0,0,0.45)', marginBottom: 6 } }, '紫色:租赁 浅紫:自营(原型双柱示意)'),
renderBarGroup(contractMonthBars, 'lease', 'self', '#722ed1', '#b37feb')
)
),
React.createElement(Col, { xs: 24, xl: 7 },
React.createElement(Card, {
title: React.createElement(Space, null, '我的通知清单', React.createElement(Badge, { count: noticeList.length })),
size: 'small',
bordered: false,
style: cardStyle,
extra: React.createElement(Button, { type: 'link', size: 'small', style: { padding: 0 }, onClick: function () { setNoticeModalOpen(true); } }, '全部')
},
React.createElement('div', { style: { maxHeight: 480, overflow: 'auto' } },
React.createElement(List, {
size: 'small',
dataSource: noticeList.slice(0, 8),
renderItem: function (n) {
return React.createElement(List.Item, { style: { padding: '10px 0' } },
React.createElement(List.Item.Meta, {
title: React.createElement(Space, { wrap: true, size: 4 },
React.createElement(Text, { type: 'secondary', style: { fontSize: 12 } }, n.time),
React.createElement(Tag, null, n.type)
),
description: React.createElement('span', { style: { fontSize: 12, color: 'rgba(0,0,0,0.75)' } }, n.content)
})
);
}
})
)
)
)
),
React.createElement(Card, {
title: '快速入口(按角色)',
size: 'small',
bordered: false,
style: cardStyle,
extra: React.createElement(Text, { type: 'secondary', style: { fontSize: 12 } }, '多角色时 Tab 切换;联调按权限过滤')
},
React.createElement(Tabs, {
activeKey: roleTab,
onChange: setRoleTab,
items: quickTabItems
})
)
)
);
};