用NocoBase插件机制改造任务管理系统:3个团队协作必备功能实战

张开发
2026/4/9 2:35:35 15 分钟阅读

分享文章

用NocoBase插件机制改造任务管理系统:3个团队协作必备功能实战
用NocoBase插件机制改造任务管理系统3个团队协作必备功能实战当团队规模超过10人时基础任务管理功能往往捉襟见肘。上周我们电商团队就遇到了典型问题运营主管需要实时查看各渠道任务进度但系统默认列表视图无法直观展示优先级和负责人市场部要求重要任务变更时自动同步到钉钉群管理层则希望看到任务完成率的趋势图表。这些需求恰恰展现了NocoBase插件开发的真正价值——用代码突破标准功能的边界。1. 开发看板视图插件告别扁平化任务列表传统列表视图最大的问题是无法直观反映任务状态。我们团队曾因此导致两个高优先级任务被遗漏直到客户投诉才发现。看板视图插件能彻底改变这一局面。1.1 插件脚手架搭建首先创建插件基础结构npx create-nocobase-app kanban-view-plugin cd kanban-view-plugin npm install nocobase/client nocobase/server --save关键依赖说明nocobase/client提供前端组件库nocobase/server包含后端API处理逻辑1.2 核心组件开发看板视图本质是对Collection数据的可视化重组。新建KanbanComponent.tsximport { useCollection } from nocobase/client; export default function KanbanComponent() { const { name, fields } useCollection(); // 按状态字段分组 const statusField fields.find(f f.name status); return ( div classNamekanban-container {statusField.uiSchema.enum.map(status ( div key{status} classNamekanban-column h3{status}/h3 RecordBlock collectionName{name} filter{{ status }} / /div ))} /div ); }样式优化技巧.kanban-column { min-width: 300px; border-right: 1px solid #eee; padding: 0 10px; } .kanban-card { background: white; margin: 10px 0; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }1.3 注册为系统视图在插件入口文件注册新视图类型app.pluginSettingsManager.add(task-manager, { kanban-view: { title: 看板视图, component: KanbanComponent, icon: AppstoreOutlined } });实际部署后发现当任务超过200条时前端渲染会明显卡顿。我们通过虚拟滚动技术优化性能import { VirtualList } from nocobase/client; function RecordBlock({ collectionName, filter }) { return ( VirtualList items{useRecords(collectionName, filter)} itemHeight{80} renderItem{record KanbanCard record{record} /} / ); }2. 钉钉机器人集成任务动态实时同步市场部经常抱怨明明系统里更新了需求但我们还在按旧版执行。通过钉钉机器人插件任何任务变更都能实时推送到群聊。2.1 机器人配置处理创建DingTalkService处理消息推送import axios from axios; class DingTalkService { private webhookUrl: string; constructor(config: { webhook: string; secret?: string }) { this.webhookUrl this.generateSignedUrl(config); } private generateSignedUrl({ webhook, secret }) { if (!secret) return webhook; const timestamp Date.now(); const sign crypto .createHmac(sha256, secret) .update(${timestamp}\n${secret}) .digest(base64); return ${webhook}timestamp${timestamp}sign${encodeURIComponent(sign)}; } async sendMarkdown(title: string, text: string) { return axios.post(this.webhookUrl, { msgtype: markdown, markdown: { title, text } }); } }2.2 事件监听与触发在插件中监听任务变更事件app.on(tasks.afterSave, async (ctx, next) { const { action, record } ctx; const dingtalk new DingTalkService(config); let actionMap { create: 创建了, update: 更新了, destroy: 删除了 }; await dingtalk.sendMarkdown( 任务${actionMap[action]}, **${record.title}**\n 状态: ${record.status}\n 负责人: ${record.assignee?.name}\n[查看详情](${app.getRouteUrl(/admin/tasks)}) ); return next(); });实际使用中我们发现频繁的更新通知会造成信息过载。最终添加了过滤逻辑// 只通知重要任务 if (record.priority ! high) return next(); // 相同状态不重复通知 if (action update !record.changed(status)) return next();3. 数据看板插件可视化任务统计管理层需要的不是原始数据而是能反映趋势的图表。我们开发的数据看板插件包含三个核心组件3.1 统计卡片组件展示关键指标function StatsCard({ title, value, trend }) { return ( div classNamestats-card h4{title}/h4 div classNamevalue{value}/div TrendIndicator percent{trend} / /div ); }对应的后端API接口router.get(/tasks/stats, async (ctx) { const repo ctx.db.getRepository(tasks); ctx.body { total: await repo.count(), completed: await repo.count({ filter: { status: done } }), overdue: await repo.count({ filter: { dueDate: { $lt: new Date() }, status: { $ne: done } } }) }; });3.2 ECharts集成展示任务状态分布import ReactECharts from echarts-for-react; function StatusPieChart() { const { data } useRequest(/tasks/stats-by-status); const option { tooltip: { trigger: item }, series: [{ type: pie, data: data?.map(item ({ value: item.count, name: item.status })) }] }; return ReactECharts option{option} /; }3.3 动态过滤器让用户自定义统计维度function DashboardFilter({ onChange }) { const [range, setRange] useState(week); return ( div classNamefilter-bar Select value{range} onChange{v { setRange(v); onChange({ range: v }); }} Option valueday本日/Option Option valueweek本周/Option Option valuemonth本月/Option /Select /div ); }4. 权限与性能优化实战当这些插件在30人团队中实际使用时我们遇到了两个关键问题4.1 细粒度权限控制市场部不应该看到技术部的任务详情。在插件中实现字段级权限app.resourcer.use(async (ctx, next) { const { actionName, resourceName } ctx.action; if (resourceName tasks actionName get) { const userRoles ctx.state.currentUser.roles; if (userRoles.includes(marketing)) { ctx.action.mergeParams({ fields: [title, status, dueDate], filter: { department: marketing } }); } } return next(); });4.2 大数据量优化当任务超过5000条时看板加载需要8秒以上。我们通过以下措施优化数据库索引db.collection(tasks).addIndex({ status: 1 }); db.collection(tasks).addIndex({ assigneeId: 1 });分页加载function useKanbanRecords(collectionName, filter) { const [page, setPage] useState(1); const { data } useRequest(/${collectionName}?page${page}pageSize50); return { data, loadMore: () setPage(p p 1) }; }缓存策略const client new QueryClient({ defaultOptions: { queries: { staleTime: 5 * 60 * 1000 // 5分钟缓存 } } });

更多文章