销售订货系统
一开始我以为只是补几个功能
最早打开 E:\kcwls\Projects\sales-order-system 的时候,我是有点侥幸的——PC 端主体已经在那儿了,订单接收、评审、变更、发货,骨架都是通的。我当时的判断是:补补细节,把试卷要求的十个模块对齐,大概两三天的事。
直到我把试卷第 4 项看清楚:移动端 50 分。
那一刻的感觉很难形容。前面 PC 端两个大项加起来 50 分,我吭哧吭哧改了半天,然后发现有另外 50 分完全没开始。而 PC 端那 50 分里,我还只拿了 38 左右。
所以真正的工作量不是"补细节",是"再做一个手机端",而且这个手机端不是摆着看的,试卷明确要求"所有审批流程可在手机上完成"。这意味着一张订单从接单到出库的每一步,手机上都得走通。
十二个页面。从零开始。
手机端
做手机端最难受的一点:没有真机。
只能在浏览器里切 390×844 的设备视图,看那些 env(safe-area-inset-bottom) 到底生效没生效,底部标签栏会不会被 iPhone 的小黑条盖住。做出来的东西自己心里也没底。
后来想到一个笨办法:把每个页面都截图,然后一张一张看。看那些 padding 有没有被吃、卡片圆角是不是一致、长客户名会不会撑破布局。截图存了六十多张,都在 _参考文档/界面截图/ 里。
这个办法意外地有效。有些问题不截图根本发现不了——比如移动端评审页曾经把"已核准"的订单也列出来还给了个"去评审"按钮,逻辑上根本不该出现。是看截图的时候一眼瞅见的。
改颜色,我其实有点不情愿
你后来说"顶部颜色换成淡色,符合工程使用环境",我心里第一反应是:紫蓝渐变挺好看的啊,为什么要改。
真改完我才明白。那套渐变是"给评委看的",不是"给每天开着电脑干活的人看的"。工程环境里的人一开就是七八个窗口来回切,整屏高饱和颜色看久了眼睛累。
改成钢蓝 #2f6db5 之后,我拿两种版本对比了一下,确实沉得住气了。这事让我记住一句:好看和耐用是两回事,做给别人用的东西,先考虑后者。
两个真 bug,其中一个让我后背发凉
权限那块,我写了个 @DeptOnly 注解 + 拦截器。自测的时候感觉挺顺,越权请求都拒了,提示文案也写得挺全。
然后写 verify_rbac.py 跑了一遍,46 项里挂了 6 项。
第一个是改密码:if (!newPwd.equals(oldPwd)) —— 我拿新密码去比对原密码。这个错得很蠢,但当时写着写着就顺手了。
第二个才是真吓人的。
Controller 层判断业务失败用的是一串 msg.contains("不存在") 之类。我加权限之后,拒绝消息是"越权操作被拒绝:……"——里面不含任何一个关键词。所以拦截器拒了、Service 也拒了,但 Controller 把它当成功,返回了 code: 200。
也就是说:业务员点"经理核准",界面上弹出一个绿色的"操作成功"。
数据没被改(Service 那层拦住了),但用户以为成功了。这种"看起来成功的越权"比直接报错危险得多——前者会让人以为规则允许,下次继续这么干。
修法是抽了个 BizResult.isFail() 统一收口,把失败特征词集中在一处。修完再跑,46/46。
这件事给我的教训不是"要细心",而是:拒绝路径必须和成功路径一样被测到。 我前面测了十条正常流程,一条越权都没有断言返回值,所以这个问题一直藏着。
菜单全空的那一次
按岗位裁剪菜单这件事,我以为一小时能搞定。
写完 MenuAuth 那张矩阵表,编译通过,一开页面——侧边栏一项都没有,只剩一个"工作台"。
看日志:
EL1004E: Method call: Method visibleBySession(java.lang.String)
cannot be found on type com.school.sales.common.MenuAuth
我先怀疑是 bean 没注册,加了 @Component;还是不行。又怀疑是模板里 T() 静态调用的问题——这个我确实知道,Thymeleaf 3 出于安全考虑禁用了 T()。
于是改成 th:with="can=${T(com.school.sales.common.MenuAuth)}"。这个写法看起来挺聪明,实际上还是绕不开 T(),一样炸。
真正的原因是:我那个 th:with 定义了个叫 can 的变量,但表达式本身就是非法的,所以 can 压根没被赋值,后面所有 can.visibleBySession(...) 全部求值失败。而 Thymeleaf 的表现是——整个 th:if 都当不成立处理,于是全被隐藏了。
最后是最朴素的写法:PageController 把 menu 塞进 model,模板直接 ${menu.visibleBySession('receive')}。一行搞定。
我在这上面耗了快一个小时,绕了两圈。回头想,当一个"聪明写法"报错信息完全对不上时,应该第一时间退回最笨的写法验证,而不是在聪明写法上继续打补丁。
有些判断我说不准对不对
关于"多一级经理核准"。
试卷流程图是:相关部门评审 → ◇审核 → 分库存。我把那个菱形做成了独立的"经理核准"阶段。
理由是 5.3.4 写了"业务部对评审好的交期确认后……完成后系统审核《销售订单》",而且参考的《销售订单》表头里明明白白有"经理审批"一栏。
但我心里清楚:流程图里没有单独画这一步。 我在文档里老老实实写了"与流程图不完全一致",给了改回去的方法。如果老师认为应该严格照图,两行代码就能改。
关于"订单管理"对财务仓库隐藏。
财务和仓库其实偶尔也想看看订单列表。我把这个入口对他们藏了,只留"流程追溯"。理由是给他们一张能改单的页面只是风险。
但万一老师问"财务为什么看不到订单",这个回答站得住吗?我也不确定。
关于屏幕宽度那个断点。
1024 宽度下,能力卡片的说明文字会断成"完工才发 / 货",很难看。我选择在中等宽度直接隐藏说明文字,只留标题。
这是个妥协。如果希望文字永远完整,就得改单列,左侧会变长。我当时选了前者,但心里一直觉得该问一句再定。
几个数字
- 52 个 Java 文件,14 张表
- PC 端 11 个页面,手机端 12 个页面
verify_flow.py66/66verify_rbac.py46/46walkflow.py23/23(流程图逐节点)- 63 张界面截图
还有一个我自己挺满意的东西:flow_log 表。每一步操作都记了操作人、角色、前后状态、时间。手机端有个"流程串联视图",能看见一张单子走到哪一步、谁批的。
这是唯一一个"试卷没要求、但我觉得企业真会用"的功能。
如果重来
第一,先读完整张试卷再动手。 我因为没第一时间看清"移动端 50 分",前面花在 PC 端打磨上的投入产出比其实不高。
第二,测试脚本一开始就按岗位写。 我最早那些回归脚本全用同一个账号(陈工程)跑,加了权限之后全线飘红,改脚本改了大半天。如果一开始就按"这个动作该谁做"来写,后面这些返工都不存在。
第三,遇到"聪明写法"报错对不上时,立刻退回笨写法。
收尾
打包时我犹豫过要不要把 target/ 和 cloudflared.exe 塞进去。最后排除了——一个是构建产物,一个是公网工具,接收方拿到没用,只会让包大 100 多 MB。
不过我在 application.yml 里留了明文密码 Aa123456。这件事我在文档里标注了,但没改。因为改了我自己演示又得再配一遍环境变量。
如果这个包要发给老师以外的人,这是个真问题。我提醒了一句,但没有替你做决定。
有时候我觉得做系统最难的不是写代码,是在"照图纸做"和"做得更合理"之间选一个,然后承担被质疑的风险。

浙公网安备 33010602011771号