整体设计
组件结构图
- 父: 发票列表页 InvoiceListModal
- 父: 发票明细匹配情况(未匹配 和 已匹配) InvoiceMatch
- 子:NeedManualMatchTable(未匹配列表)
- 子:InvoiceMatchedTable (已匹配列表)
- 父:手动匹配 InvoiceManualMatch
- 子:SoureceManualMatchTable(单据明细列表)
- 子:InvoiceManualMatchTable (发票明细列表)
- 父: 用户待确认明细 InvoiceUniqueness
- 子:ConfirmManualMatchTable (待确认单据列表)
- 子:InvoiceManualMatchTable (待确认发票明细列表)
组件数据交互流图
虚线代表数据传输 实线代表实际交互流程
方框代表组件(对应上图组件) / 数据结构
菱形代表数据处理 / 用户动作 / 判断条件
气泡框代表解释
主要设计思想:
- 所有数据初始化过后不再进行修改,直接有用的参数全部挂在发票对象上
- 对应发票匹配的单据挂发票上,
发票明细匹配的单据挂发票明细上
,多对多匹配的用groupId确认分组 - 可逆操作的数据全都使用备份
- 共同数据全部使用全局数据管理
- 容差在需要的顶层配置好,把对应配置项传下去根据配置数据结构直接渲染
发票redux数据模型设计
核心是高阶reducer的复用以及业务action的拆分
- 高阶reducer好处1:同样的单据集的处理不用处理多套
- 高阶reducer好处2:对于备份的发票和单据,也可以复用对应的处理方式(useReducer)
- action拆分好处:action不但可以用于生成新的全局state,还可以用于普通单据的增删改
容差设计
顶层根据配置返回如下结构
1 | { |
- 后续对容差的操作直接通过 invoiceUtil.js 下对应的容差方法修改
- 所有操作都是基于此数据结构(计算和渲染),如有可逆操作将此结构备份
强弱校验设计
强弱校验相关的全部基于以下二进制进行操作
1 | export const NoStatus = /* */ 0b00000000000000000000000000; // 不校验 |
以强校验举例
- 初始化为 NoStatus,如果遇到了某强校验, 则使用
NoStatus | ForbiddenStatus
- 判断某校验是否为强校验(假设此变量x的二进制为ForbiddenStatus), 则:
1
(x & ForbiddenStatus) !== NoStatus 代表变量x是强校验
- 通常后端会返回对应好字段
"FORBIDDEN"
、"WARNING"
、"IGNORE"
,invoiceUtil做好映射如下:1
2
3
4
5export const resultStringMapStatus = {
'FORBIDDEN': ForbiddenStatus,
'WARNING': WarningStatus,
'IGNORE': IgnoreStatus,
}; - 针对匹配错误相关的映射,invoiceUtil文件下做好映射如下:
1
2
3
4[errorCode/matchStatus]: {
text: '错误提示文字',
status: ForbiddenStatus,
},
测试
前端对测试的减负点:
- 现
容差
整体顶层配置,只需要详细测一个纬度即可,其他纬度挑一个点测 - 发票
手动匹配流程
只需要测一个纬度就行,其他纬度挑一个情况测 - 抬头联动的测试,只需要测
有强有弱/无强有弱/无强无弱
三种情况,分别是红/黄/白
,现逻辑都是有红则红,没红有黄则黄, 都没有则白
产品
产品设计对前端的影响点:
- 不要让前端在发票列表页计算容差,影响性能(有些发票相关信息未必是发票上直接获取,需要去累加发票明细,如数量)。目前卡死在发票明细匹配情况页面,
- 减少跨发票的操作(所有操作都是A发票的,操作完修改另一张发票匹配的相关数据),实现成本极大
- 设计时减少跨级操作,例如:发票列表页直接跳过发票明细匹配情况页面,直接进入手动匹配页面,属于比较特殊的代码(目前有且只有未验真可以有如此操作),会让前端代码变得复杂难以维护
- 尽可能按照组件结构图的流程走,匹配流程不要再整体的匹配过程中插入新的页面