我在一家做工业配套的企业管数字化,前年把六个部门的审批入口收进一个待办中心。收拢之后数字很好看:日均新增待办四百二十条,平均审批时长从两天半压到一天一。但积压条数一路涨到三千七百条,厂长打开列表往下翻了十几屏,回头问我一句,这里面哪三件是今天必须定的。我答不上来。
那次问话之后,我把"分类"这件事整个重做了一遍。结论先放在这里:待办不需要更聪明的标签体系,需要的是一条能算出先后的规则,而且这条规则要写在系统里,不能留在某个人的脑子里。
原来列表按创建时间倒序,谁提得晚谁在上面。条目少的时候这套逻辑没毛病,条目一多就变成了嗓门大的先办。真正卡着交付的那几条,沉在第二页第三页。我后来做的事,说穿了就是把"要紧"这两个字拆成三个能打分的量。
一、待办为什么越堆越乱
1.1 一个入口收进了七类事
原来六个部门各有各的审批单:采购申请、合同会签、付款、用章、请假、出差、异常放行。收进一个入口之后表单统一了,但七类事的时间尺度完全不同。用章当天要,合同会签三天内要,请假提前一天提,异常放行是随时可能来的。
把它们摆进一个列表按时间排,等于把不同量纲的东西硬凑在一行。付款单的"三天"和请假的"三天"不是一回事,一个是资金占用,一个是排班安排。
1.2 排序失灵的三种样子
一种是新单压旧单。昨天下午提的付款,被今天早上提的用章顶到第二页。一种是急单不显眼,业务在标题里写"急",写的人多了就没人看。还有一种是跨部门断线,采购卡在财务那一环,采购经办以为还在自己手上,实际已经躺了四天。
这三种都不是界面问题。界面再怎么美化,底下没有排序依据,翻起来还是靠人眼扫。
1.3 分类不是打标签
起初我们做的是标签,给每条待办打上"财务""合同""紧急"。做了两周发现没用,标签只解决了筛选,没解决先后。筛选回答的是"我想看哪一类",排序回答的是"我该先看哪一条"。
这两个问题经常被混在一起谈。经办要的是把手上十几条排个序,领导要的是从几百条里挑出三条。两者的界面可以共用,排序逻辑不能共用。
二、把"要紧"拆成能算的量
2.1 三个维度
我们把要紧程度归到三个维度。时限,距离要求完成还有多少小时。牵连,这条卡住之后下游还有多少条在等。分量,涉及金额处于哪个档位,或者是否属于不可逆动作。三个维度各自归一化到零到一,再加权求和。
归一化这一步不能省。金额是几十万,牵连是几条,时限是几十小时,三个数不加处理直接相加,等于让金额一个维度说了算。
2.2 权重不能靠讨论定
权重起初是拍的:时限零点四五,牵连零点三,分量零点二五。跑了三周发现不对,异常放行这类单子金额可能是零,但放错一次要整批返工,被算到了末位。改法是把不可逆动作拎出来做硬阈值,直接加基础分,不参与加权。
权重表每个季度拿实际处理记录回归一次。做法很土:抽出上季度所有逾期的单子,看它们在提交时的分值排在第几位,如果大量排在前二十之外,说明权重偏了。这一步不需要算法,只需要一张导出表。
2.3 排序规则写成的伪代码
真正跑在系统里的是一段打分逻辑,代码不长,但每一行都对应过一次争论:
// 待办打分:返回 0 到 1 之间的优先级分值
function score(todo, now) {
const HOUR = 3600 * 1000;
// 时限:越临近分值越高,超出 72 小时按 72 小时算
const left = Math.max(0, todo.dueAt - now) / HOUR;
const urgency = 1 - Math.min(left, 72) / 72;
// 牵连:下游等待条数,10 条封顶
const impact = Math.min(todo.blockedCount / 10, 1);
// 分量:金额档位已在前端归到 0 到 4
const weight = todo.amountLevel / 4;
let s = 0.45 * urgency + 0.30 * impact + 0.25 * weight;
if (todo.irreversible) s += 0.35; // 用章、对外承诺、异常放行
if (todo.overdue) s += 0.20; // 已逾期,单独提一档
if (todo.status === 'waiting_other') s -= 0.50; // 等别人,不进我首屏
return Math.round(s * 1000) / 1000;
}
// 首屏:按分值倒序,同分按到期时间正序
const firstScreen = todos
.filter(t => t.ownerId === me.id && t.status !== 'waiting_other')
.sort((a, b) => score(b) - score(a) || a.dueAt - b.dueAt)
.slice(0, 20);
写完之后我把这段逻辑打印出来,拿去给六个科室的负责人各看了一遍,让他们指出哪一行不符合自己的实际。收回来十一条意见,其中七条是关于牵连怎么算的。
2.4 分值要能解释
只给一个数字,经办会怀疑。所以我们把分值拆开显示,界面上是一行小字:这条排前面,是因为还有四小时到期,或者因为下游压着六条。字数不多,但省掉了大量"凭什么"的追问。
解释这一行还带来一个副作用。业务开始主动补下游关联,因为关联上去之后分值会涨。以前这个字段是空的,现在是七成满。
三、规则落到列表上
3.1 两条视图分开
默认视图按分值排,只显示前二十条。另外给一个"我提的"视图,按状态分组,让提交人看进度。两个视图共用一张表,只是过滤和排序不同。分开之后,领导看首屏,经办看全量,互不干扰。
这一刀切下去,首屏平均条数从三十四条降到十一条。不是因为单子少了,是因为等别人的单子被移走了。
3.2 逾期单不该一直往上爬
按原规则,逾期单加零点二分,会一直往上爬,把正常单挤下去。改法是逾期单进单独一栏,标题上标出逾期天数,不参与首屏排序。等待他人的单子同理,从"我的待办"移到"我跟进的"。
这两栏加起来每天四十条上下,由一个专人每天上午过一遍,该催的催,该退的退。这活以前没人干,因为藏在列表深处看不见。
3.3 规则要允许被推翻
规则一定有算错的时候。界面上留了两个动作:置顶,持续二十四小时;稍后,推两天。两个动作都记日志,每月看一次。如果某一类单子被大量置顶,说明权重不对,回去调权重,而不是让每个人各自置顶。
三个月下来,置顶的日均次数从三十一次降到七次。降下来的那部分,基本都被权重调整吸收掉了。
四、跑了一个季度的观察
4.1 数字上的变化
首屏平均条数稳定在十一条上下,逾期未处理的比例从一成一降到百分之四。审批时长的中位数没有明显变化,但长尾短了很多,超过五天的单子从每月六十几条降到十几条。
厂长那边反馈很直接:早会前看一屏,能点到当天要定的事,不用再问一句还有没有别的。
4.2 反效果
也出过岔子。有一段时间各科室学会在标题里写"厂级""领导关注",试图影响排序。后来我们把标题字段从评分里彻底摘掉,只看结构化字段,这股风才停。
另一个问题是权重调整没留版本。调完之后和历史数据对比失真,报表上出现"上季度平均分比这季度高"这种没意义的结论。补了一列规则版本号,问题才消。
4.3 要紧由谁定义
这件事我想了很久。要紧的标准不该由IT定,也不该由提交人自己定,应该由"卡住之后的代价"定。所以牵连维度的统计口径,从"直接下游条数"改成了"下游两跳内的条数",权重没动,排序准了不少。
代价这个词有点抽象,落到具体就是三个问句:这条卡住,谁在等;等的人能不能自己绕过去;绕不过去要多久。三个问句答完,分值大概就出来了。
五、这套做法适合什么样的团队
5.1 适合的情形
待办日均过百、跨三个以上部门、有明确的时限要求,这三条占两条就值得做。反过来,一天十几条单子、都在一个科室内部流转,用标签加筛选就够了,上打分属于给自己找事。
5.2 不适合的情形
如果审批本身没有时限,也没有下游依赖,那"要紧"就没有可算的依据,硬算出来的分值只是把人的偏好换了个形式。还有一种情况是流程本身混乱,同一件事有三条路径,这时候应该先理流程,排序解决不了路径问题。
5.3 一年后该看什么
不要看分值准不准,那个没法验证。看两个东西:首屏被点开的比例,和逾期单的处置时长。前者说明排序有没有用,后者说明规则有没有把该冒头的冒出来。
常见问题
问:这套分类要不要上模型?
答:条目过千、字段齐全、有半年以上的处理记录,可以考虑用历史数据学一版权重。多数场景用不上,四个维度的加权和已经能解释八成的排序需求,模型带来的提升很难覆盖维护成本。真要做,也建议先做权重回归,别直接上分类模型。
问:权重被业务质疑怎么办?
答:不要开会讨论,去看数据。抽出上季度逾期的单子,看它们提交时的分位,再看被置顶的单子集中在哪一类。数据摆出来,争议一般会从"我觉得"变成"这一类确实偏低"。
问:分类规则多久调一次?
答:跟着业务节奏走。业务稳定的,一个季度一次;有旺季淡季的,换季前调一次。调之前把旧规则跑一遍留底,调之后对比同一批历史单子的排序变化,别凭感觉说这次准多了。
问:只做排序不做分类行不行?
答:行,而且多数团队应该这么做。分类的价值在于批量处理,如果你的待办没有整批审批的需求,分类只是多一层维护。先把排序做对,等出现"同一类单子要一起看"的声音,再补分类。