苍穹系统5.0/6.0版本中,单据字段F1、F2根据基础资料A的选定值动态设置必填。问题发生在用户在不同业务场景下新建单据时,非当前页面的字段必填设置影响了新页面。排查发现由于本地缓存机制,字段属性被全局共享,导致非当前页面字段也被错误设置为必填。结论建议动态设置字段必录时,应仅在前端设置,或通过页面缓存机制避免影响其他页面。后端操作需明确记录并校验字段。
1.问题描述
苍穹版本:5.0/6.0
单据上有字段F1和F2,默认隐藏非必填,只有当基础资料A选到某个值时,才会设置可见并必填,简化逻辑如下:
填完数据后用户会点击按钮(donothing操作类型,校验规则开启了字段值合规性校验),绑定的服务插件会调用单据的submit操作,操作成功会关闭单据页面。
然后问题来了,业务老师新建此单据,基础资料A选择了此特定值,那几个隐藏字段都会显示并校验必录,走完流程都没问题,但当再次打开一个新tab页新建此单据时,走别的业务场景(基础资料A不填值),点按钮会校验到字段F1F2没填值,校验不通过......这有点离谱了,我给前一个页面设置的字段必录,且页面都关闭了,居然会影响到我新页面的字段???
2.问题排查
【字段值合规性校验】的逻辑在kd.bos.service.operation.validate.MustInputValidator#validate,会先根据字段匹配相应的校验器。走异常流程时打了个条件断点监控那几个问题字段,结果发现匹配到了校验器,且字段属性中mustInput为true,突然反映过来之前设置必录时好像也有setMustInput的操作,难道是同一个对象???
为保证严谨性,再次打开一个新页面,触发设置必录的代码,还真是同一个对象......
MustInputValidator方法中的prop是从IDataEntityType里获取的,IDataEntityType最终是从EntityMetadataCache.getDataEntityType(this.entityName),继而调用EntityMetadataLocalCache.getDataEntityType(number)获取,看名字就知道是本地缓存,如果是分布式缓存,可能还需要反序列化为对象,那每次获取会是不同的对象引用,本地缓存那就是同一对象引用了,所以会影响全局......
3.结论
动态设置字段必录的正确方式应该是:
按钮开启【提交校验】,即打开这个选项
代码只需要给字段设置必录,不需要给prop,这样必录校验都在前端,只有这些必录字段都填值后前端才会发起请求
TextEdit textEdit = this.getControl("a2h6_textfield"); textEdit.setMustInput(true);
如果非要后端执行操作并校验,最好是抽公共方法,记录设置必录的字段(通过pagecache,这绝对是绑定页面的,不会影响其他),然后在执行操作前取出记录的字段,自己做必填校验
推荐阅读