这个页面的使用者是客户企业的 IT 管理员,他管的是自己公司几千到上万人的组织架构。这个规模和「我们内部后台管几十个运营账号」完全不是一回事。
第一版直接用了组件库的树组件,一次性把整棵树的数据拉下来渲染。
一是万级节点直接卡死。一万个成员加八百个部门,全部渲染出来是上万个 DOM 节点,浏览器要卡好几秒,展开收起也不流畅。客户的反馈是「你们这个页面打不开」。
二是拖拽调部门是高危操作但没有任何保护。管理员想把一个人从 A 部门拖到 B 部门,手一抖拖的是整个 A 部门,连带几十个子部门和几百人的归属和权限全变了,而且没有提示、没有预览、没法撤销。
三是权限说不清。最高频的支持工单是「为什么张三能看到财务数据」或者反过来「为什么李四看不到他部门的数据」。权限来自角色、来自部门继承、来自单独授权,几条来源叠在一起,连我们自己都要查半天才能说清,客户完全没法自助排查。
所以三个设计:虚拟渲染加懒加载扛住规模、拖拽前预览影响范围、生效权限可溯源。第三点是这个模块最有价值的部分——它把一类高频工单彻底消掉了。
懒加载带来了「搜索和定位变复杂」的代价。数据不在本地,所以搜索要走服务端、定位要逐层展开、「全部展开」这类操作变得不可行(会触发大量请求)。我们的处理是砍掉「全部展开」功能——对万人组织来说这个功能本身也没有意义(展开了也看不完)。承认某些功能在大规模下不该提供,比硬做出一个会卡死的功能好。
为什么不用组件库的树。组件库的树组件通常支持懒加载,但很少同时支持虚拟滚动,而两者必须同时有。而且我们需要自定义节点渲染(成员和部门显示不同信息、要显示权限标记)、需要自定义拖拽校验规则。但我保留了组件库的基础交互模式(展开箭头、缩进、选中态),不重新发明交互,只重写渲染和数据管理。
拖拽 vs 表单选择上级部门,我们两个都留。拖拽直观但精度差(大树里拖到目标要滚半天),表单选择精确但要多几步。判断是「操作距离」——目标在附近就拖拽,隔很远就用「移动到…」的表单选择。硬只留一种都会有场景很难用。
踩过的坑:拖拽形成环导致整棵树渲染死循环。早期的合法性校验只判断了「不能拖到自己身上」,漏了「不能拖到自己的后代下」。管理员把一个部门拖进了它自己的子部门,数据层面形成了环,前端渲染树时无限递归,页面直接崩溃,而且这条脏数据存进了数据库,之后每次打开都崩。修法两处:前端拖拽时校验目标不是当前节点的后代;服务端也要独立校验并拒绝(前端校验能被绕过,而这条脏数据的破坏性极大)。树形结构的移动操作必须防环,这是必考点。
踩过的坑二:权限溯源算出来的来源链和实际生效不一致。溯源逻辑是前端根据授权数据自己推导的,而实际鉴权是后端算的,两套逻辑对继承规则的理解有细微差异,结果溯源说「他没有这个权限」但他实际能操作。修法是溯源结果由后端计算并返回,前端只负责展示——鉴权和溯源必须是同一份逻辑,否则溯源功能反而会误导人。这和「预览必须和执行走同一套计算」是同一个原则。
没做的部分:没做组织变更的批量导入(Excel 导入组织架构)。客户初次接入时要手动建几百个部门,很痛苦。这需要处理导入模板、校验、部分失败的回滚,工作量不小,当时用的是我们帮客户导。
组织树首屏耗时:造一个 1 万成员 / 800 部门的测试数据,量「进入页面 → 树可交互」。约 200ms。关键是要说明这 200ms 里实际渲染了多少节点——因为懒加载,首屏只加载了根节点和第一层(可能几十个),虚拟滚动又只渲染可视区的几十行。报「组织总规模」和「首屏实际渲染节点数」两个数字,才能说明设计而不只是报一个好看的耗时。
展开深层节点的耗时:要单独报,因为这是懒加载的代价(每次展开一次请求)。只报首屏是选择性呈现,面试官会问「那我展开呢」。
「误操作被拦下」怎么验证:构造场景演练——拖动一个有大量子节点的部门,验证影响范围预览的数字正确、超阈值时要求输入名称确认、取消后数据未变更。还要测防环:尝试把部门拖到自己的子部门下,验证前端标记禁止且服务端也拒绝。
「权限咨询转为自助」怎么量化:报支持工单里「权限为什么生效」这一类的数量变化,以及溯源功能的使用频次。后者更有说服力——如果功能上线了但没人用,说明它没解决真问题。
不要报「权限配置效率提升 N 倍」。算不出来。也不要报「零误操作」——误操作一定会发生,我们做的是让它在提交前被看见。
这个模块的起因和房态后台那个监控模块一样:支持工单把人拖垮了。客户接入开放 API 的过程中,问题高度集中在三类。
一是签名算不对,占了支持工单的一大半。客户开发者按文档实现签名,服务端返回「签名不匹配」,然后他就来问了。而这个问题只能靠对比才能定位——他的待签字符串和我们的差在哪。以前的流程是:客户把代码贴过来 → 我们看 → 猜他哪一步错了 → 让他打印中间值 → 来回三五轮。一次接入要折腾两三天。
二是密钥靠人工发放。客户签约后我们生成密钥,用邮件或者聊天工具发过去。这本身就是安全问题(明文密钥在邮箱里躺着),而且客户想轮换密钥要找我们,我们改完他再上线,中间的窗口期怎么处理没人管。
三是用量不透明。客户不知道自己调了多少、离配额还差多少,直到被限流了才发现,然后来质问「你们为什么限我」。而我们也说不清是他哪个接口调多了。
四是 Webhook 收不到。客户配了回调地址但收不到事件,可能是他的地址不通、可能是他返回了非 2xx、可能是他验签失败。这些他自己完全看不到。
所以四个设计:密钥自助管理且只展示一次、用量看板加预警、在线签名调试器、Webhook 测试推送与死信自助重投。其中签名调试器的投入产出比最高,它直接消掉了最大的一类工单。
「只展示一次」会带来客户投诉,但必须坚持。一定会有客户没保存就关了弹窗,然后来问能不能找回。答案是不能,只能重新生成。缓解手段是把提示做得足够醒目、提供一键复制、创建成功后弹窗不允许点外部区域关闭(必须点「我已保存」)。安全上的硬约束不能因为体验投诉而妥协,但可以通过交互设计减少发生率。
签名调试器涉及密钥,安全设计要想清楚。理想方案是纯前端计算(SecretKey 不离开浏览器),这样最安全,客户也敢用。代价是前端要实现一套和服务端完全一致的签名算法——两边算法有任何差异,调试器就会误导人(这比没有调试器更糟)。我们的处理是前端计算 + 提供「校验我的签名」让服务端复核,两条路互相印证。如果团队没把握保证两边算法一致,那就只做服务端校验、不做前端计算器。
踩过的坑:调试器的签名算法和线上服务不一致。线上服务对查询参数做了排序,调试器的实现漏了排序,结果客户按调试器的输出算出来的签名在线上通不过,客户被误导了整整一天,比没有调试器更糟。修法是把签名逻辑抽成一份共享实现(同一份规范文档 + 双方各自实现后用测试向量对齐),并且加了一组测试用例:给定固定输入,前端计算结果必须等于服务端结果,进 CI 每次跑。「调试工具和被调试对象必须严格一致」是这类工具的生死线。
踩过的坑二:用量看板的数字和限流实际用的计数不一致。看板读的是预聚合的统计数据(有分钟级延迟),限流用的是实时计数器,客户看到「还剩 3000 次」但实际已经被限流了,来投诉数据不准。修法是在看板上明确标注数据延迟,并且把「当前是否处于限流状态」做成一个实时查询的独立指标。不同数据源的数字放在同一个页面上,必须标注各自的时效性,否则用户会认为系统在骗他。
没做的部分:没做沙箱环境。客户只能在生产环境调试,容易产生脏数据(测试订单、测试事件)。理想是提供独立的沙箱租户和测试数据集,但要维护一套额外环境,成本不小。
「签名类工单转为自助」怎么量化:报支持工单里「签名不匹配」这一类的数量变化,以及调试器的使用频次。两个一起看才有意义——如果工单降了但调试器没人用,说明是别的原因(比如接入的客户少了)。要能说出改造前一次签名问题的排查周期(客户贴代码、我们猜、让他打印中间值,来回三五轮,两三天),这个描述比任何百分比都有说服力。
调试器的正确性怎么保证与验证:这比使用量更重要。做法是一组固定的测试向量(给定 AccessKey、路径、时间戳、随机串、请求体,期望的待签字符串和签名值),前端和服务端各跑一遍,结果必须一致,进 CI。可以报「测试向量覆盖了哪些边界」——空请求体、含中文的参数、需要 URL 编码的字符、参数顺序打乱。
Webhook 死信重投的使用情况:报重投次数。这个数字证明客户真的在用这个功能自助恢复,而不是继续找我们。
不要报「接入周期缩短 N 天」。接入周期受客户自身排期、技术能力、需求复杂度影响,我们只影响其中一部分。可以报的是「我们这边参与排查的次数」——这个是我们能观测且能归因的。
也不要报「密钥安全性提升」这类无法度量的表述。可以说的是具体做法:不再通过邮件传递、服务端只存哈希、支持轮换与吊销。能力描述比效果吹嘘可信。
审批流是企业服务里最不可能标准化的东西——每家客户的审批规则都不一样,报销超过多少要总经理签、请假分几级、采购要不要走并行会签。
第一版是写死在代码里的,按客户做条件分支。接了十几个客户之后代码里全是 if (tenantId == xxx),加一个客户要改代码、要回归测试、要发版。客户想改自己的流程也要提需求等排期,一个「加一级审批」的需求要等两周。
这个模块的必要性没有争议,难点在三个地方。
一是画布交互本身有难度。节点拖拽、连线、缩放平移、自动布局,这些不是常规表单页的复杂度。
二是客户会配出错误的流程。最典型的是条件分支没有兜底——配了「金额大于 1000 走总经理」,没配小于等于 1000 走哪里,结果金额 500 的单据流转到这个节点就卡死了,既不通过也不驳回,用户以为系统坏了。还有配出环的(A 审完到 B,B 审完又回 A)、配出不可达节点的。
三是改流程会影响正在审批的单据。客户中途改了流程,那些已经走到第二步的单据该按新流程还是旧流程走?如果直接切到新流程,节点对不上就会卡死。
所以三个设计:自绘画布支持必要的编排交互、发布前做图结构校验把错误挡在上线前、流程版本化让在途实例继续走旧版。
自绘 SVG 画布还是引入流程图库。成熟的流程图库功能强大,但体积大(几百 KB)、定制成本高——我们需要自定义节点样式、自定义校验、和权限系统联动选审批人。评估后选了自绘:只用 SVG 画节点和连线,交互逻辑自己写。代价是要处理坐标变换(缩放平移下的鼠标位置换算)、连线路径计算、性能(节点多时)这些细节,工作量不小。判断依据是「流程规模」——审批流通常十几个节点,自绘完全撑得住;如果是要画几百个节点的复杂图,应该用专业库。
节点类型收敛的取舍。只做六种类型意味着有些需求配不出来(比如「超过三天未审批自动通过」需要定时节点)。处理方式是留一个「联系我们定制」的出口,而不是硬把所有节点类型都做出来。节点类型每多一种,校验规则的组合就复杂一截,而且大部分客户用不上——这和之前配置化表单的判断一致:可配置性要有边界。
踩过的坑:条件分支没兜底导致单据卡死,人工改库。客户配了「金额大于 1000 走总经理审批」,忘了配另一条分支。金额 500 的报销单流转到条件节点,没有任何出边的条件满足,单据就停在那里,状态是「审批中」但没有任何人的待办里有它。用户投诉「我的单子不见了」,我们只能去数据库把单据状态手工推到下一个节点。修法就是把「条件分支必须有 else」做成强校验,不允许发布。这个坑是这个模块所有校验规则的来源——每一条校验背后都是一次事故或者一次差点出的事故。
踩过的坑二:改流程导致在途单据卡死。早期没有版本化,客户改了流程之后,那些已经走到「部门经理审批」的单据,在新流程里这个节点被删掉了,单据的当前节点在新图里找不到,流转逻辑直接抛异常。修法是版本化 + 在途单据绑定版本号。通用教训是:任何「运行中的实例依赖某个可变配置」的场景,配置必须版本化且实例要绑定版本——这和退改规则快照到订单、计费规则快照到账单是完全同一个模式。
没做的部分:没做流程的模拟运行(输入一组数据,看单据会走哪条路径)。这对客户验证条件配置是否正确很有价值,但需要把条件表达式的求值逻辑在前端实现一遍(又会遇到「和后端不一致」的风险),当时没做。
「配置错误被拦下」怎么量化:统计发布校验失败的次数与错误类型分布。这是个绝对数、口径清晰,而且错误类型分布很有信息量——如果「条件分支没兜底」占了大头,说明这个概念对客户不直观,可能要在交互上做引导(比如新建条件节点时默认就带一条 else 分支)。
「从提需求到自助」怎么说:改造前是提需求走排期改代码发版(以周计),改造后是客户自己在画布上配(以分钟计)。要说清改造前那个周期里包含什么(需求沟通、开发、测试、发版排期),否则「两周变十分钟」听起来像夸大。
画布性能:报「多少个节点下拖拽仍然流畅」。审批流通常十几个节点,要说明这个规模下自绘方案是够的,并且诚实说明节点上百时会需要优化(连线路径重算是主要开销)。
「改流程不影响在途单据」怎么验证:构造场景演练——发起一批单据走到中间节点,然后修改流程并发布(删掉那个中间节点),验证在途单据仍能按旧版本正常流转到结束。这类兼容性必须演练过,因为它正是我们踩过坑的地方。
不要报「审批效率提升 N%」。那取决于客户的组织和审批人响应速度,和编排器无关。也不要报「零卡死」——绝对化断言,而且只要有一个漏掉的校验规则就被推翻。正确表述是「哪些错误被校验覆盖、拦下过多少次」。
没有匹配的内容,换个关键词试试。
项目拆解 · 租户控制台(Vue)· 共 3 个模块 · 数字均为示例,需替换成自己项目的真实数据