tabledatahelper.dart 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. import 'package:flyinsonolite/consultation/reports/reportinfo/input_text_info.dart';
  2. import 'package:flyinsonolite/consultation/reports/reportinfo/rt_cell_info.dart';
  3. import 'package:flyinsonolite/consultation/reports/reportinfo/rt_table_info.dart';
  4. import 'package:flyinsonolite/consultation/reports/reporttemplate/cell_postion.dart';
  5. import 'package:flyinsonolite/consultation/reports/reporttemplate/input_text.dart';
  6. import 'package:flyinsonolite/consultation/reports/reporttemplate/interfaces/cell.dart';
  7. import 'package:flyinsonolite/consultation/reports/reporttemplate/rt_Cell.dart';
  8. import 'package:flyinsonolite/consultation/reports/reporttemplate/rt_table.dart';
  9. /// 表格数据过滤器
  10. class TableDataHelper {
  11. /// 数据过滤器,过滤空数据
  12. static RTTableInfo removeEmptyCells(RTTableInfo rtTableInfo) {
  13. RTTableInfo newRtTableInfo = rtTableInfo.clone();
  14. if (newRtTableInfo.cells == null) {
  15. return newRtTableInfo;
  16. }
  17. int tableWidth = newRtTableInfo.columnDefinitions!.length;
  18. Map<CellPostion, RTCellInfo> newCells = {};
  19. Map<CellPostion, ICell> newElementCells = {};
  20. Map<String, GroupFieldArgs> groupFieldMap = {};
  21. /// 遍历 cells 输出
  22. for (MapEntry<CellPostion, RTCellInfo> cell
  23. in newRtTableInfo.cells!.entries) {
  24. RTCellInfo cellInfo = cell.value;
  25. CellPostion cellPostion = cell.key;
  26. RTCell cellElement = cellInfo.element as RTCell;
  27. if (cellElement.groupField == null || cellElement.groupField!.isEmpty) {
  28. continue;
  29. } else {
  30. if (groupFieldMap[cellElement.groupField!] != null) {
  31. groupFieldMap[cellElement.groupField!]!
  32. .addSize(cellPostion.columnSpan!);
  33. groupFieldMap[cellElement.groupField!]!
  34. .addCell(cellPostion, cellInfo);
  35. } else {
  36. groupFieldMap[cellElement.groupField!] =
  37. GroupFieldArgs(cellPostion.columnSpan!, {cellPostion: cellInfo});
  38. }
  39. }
  40. }
  41. if (groupFieldMap.isEmpty) {
  42. return newRtTableInfo;
  43. }
  44. /// 是否为特殊模式
  45. final isSpecialMode = _isSpecialMode(groupFieldMap);
  46. /// 带有输入框的分组字段
  47. List<String> inputGroupFieldList = [];
  48. /// 带有值的分组字段
  49. List<String> valueGroupFieldList = [];
  50. /// 再次遍历 cells,存在空值就移除对应 map
  51. for (MapEntry<CellPostion, RTCellInfo> cell
  52. in newRtTableInfo.cells!.entries) {
  53. RTCellInfo cellInfo = cell.value;
  54. RTCell cellElement = cellInfo.element as RTCell;
  55. if (cellInfo.blocks == null || cellInfo.blocks!.isEmpty) {
  56. continue;
  57. }
  58. if (cellInfo.blocks![0].elementInfos == null ||
  59. cellInfo.blocks![0].elementInfos!.isEmpty) {
  60. continue;
  61. }
  62. if (cellInfo.blocks![0].elementInfos![0] is InputTextInfo) {
  63. InputTextInfo inputText =
  64. cellInfo.blocks![0].elementInfos![0] as InputTextInfo;
  65. if (!inputGroupFieldList.contains(cellElement.groupField!)) {
  66. inputGroupFieldList.add(cellElement.groupField!);
  67. }
  68. if (inputText.text.isNotEmpty) {
  69. if (!valueGroupFieldList.contains(cellElement.groupField!)) {
  70. // 如果是特殊模式的函数字段,需要判断内容是否正确【函数字段的宽度为 2 ,使用宽度来判断】
  71. if (isSpecialMode && cell.key.columnSpan == 2) {
  72. // 如果函数值无前缀,则删除 valueGroupFieldList 中的该字段
  73. int firstIndex = inputText.text.indexOf('[');
  74. int lastIndex = inputText.text.lastIndexOf(']');
  75. if (firstIndex < lastIndex && firstIndex > 0) {
  76. valueGroupFieldList.add(cellElement.groupField!);
  77. }
  78. } else {
  79. // 非特殊模式,直接添加
  80. valueGroupFieldList.add(cellElement.groupField!);
  81. }
  82. }
  83. }
  84. }
  85. }
  86. // 无任何输入,直接返回空
  87. if (valueGroupFieldList.isEmpty) {
  88. newRtTableInfo.cells = null;
  89. return newRtTableInfo;
  90. }
  91. /// inputGroupFieldMap 和 valueGroupFieldMap 取差集
  92. List<String> emptyGroupFieldList = [];
  93. for (String inputGroupField in inputGroupFieldList) {
  94. if (!valueGroupFieldList.contains(inputGroupField)) {
  95. emptyGroupFieldList.add(inputGroupField);
  96. }
  97. }
  98. /// 如果是特殊模式,需要特殊对齐处理,此时记录左上角单元格 LeftTopPos,还需要将函数字段的空值也移除
  99. int specialGroupsTopPos = -1;
  100. int specialGroupsLeftPos = -1;
  101. if (isSpecialMode) {
  102. for (GroupFieldArgs groupField in groupFieldMap.values) {
  103. if (groupField.cellsCount == 1) {
  104. continue;
  105. }
  106. if (specialGroupsTopPos == -1 ||
  107. groupField.topPos < specialGroupsTopPos) {
  108. specialGroupsTopPos = groupField.topPos;
  109. }
  110. if (specialGroupsLeftPos == -1 ||
  111. groupField.leftPos < specialGroupsLeftPos) {
  112. specialGroupsLeftPos = groupField.leftPos;
  113. }
  114. }
  115. }
  116. /// 遍历 emptyGroupFieldList,移除对应的 map
  117. for (String emptyGroupField in emptyGroupFieldList) {
  118. if (groupFieldMap[emptyGroupField] != null) {
  119. groupFieldMap.remove(emptyGroupField);
  120. }
  121. }
  122. for (MapEntry<CellPostion, RTCellInfo> cell
  123. in newRtTableInfo.cells!.entries) {
  124. RTCellInfo cellInfo = cell.value;
  125. RTCell cellElement = cellInfo.element as RTCell;
  126. if (cellElement.groupField == null || cellElement.groupField!.isEmpty) {
  127. newCells.addEntries([cell]);
  128. } else if (groupFieldMap.keys.contains(cellElement.groupField!)) {
  129. newCells.addEntries([cell]);
  130. }
  131. }
  132. for (MapEntry<CellPostion, ICell> cell
  133. in (newRtTableInfo.element as RTTable).cells!.entries) {
  134. ICell cellInfo = cell.value;
  135. if (cellInfo.groupField == null || cellInfo.groupField!.isEmpty) {
  136. newElementCells.addEntries([cell]);
  137. } else if (groupFieldMap.keys.contains(cellInfo.groupField!)) {
  138. newElementCells.addEntries([cell]);
  139. }
  140. }
  141. /// 移除尾部空格,然后重排序
  142. removeTailEmptyCells(newCells);
  143. if (isSpecialMode) {
  144. newRtTableInfo.cells = specialSortCells(
  145. newCells, groupFieldMap, specialGroupsLeftPos, specialGroupsTopPos);
  146. } else {
  147. newRtTableInfo.cells = sortCells(newCells, groupFieldMap, tableWidth);
  148. }
  149. (newRtTableInfo.element as RTTable).cells = newElementCells;
  150. return newRtTableInfo;
  151. }
  152. /// 重排序
  153. static Map<CellPostion, RTCellInfo> sortCells(
  154. Map<CellPostion, RTCellInfo> cells,
  155. Map<String, GroupFieldArgs> groupFieldMap,
  156. int tableWidth) {
  157. Map<CellPostion, RTCellInfo> newCells = {};
  158. MapEntry<CellPostion, RTCellInfo>? headGrid;
  159. int currTop = 0;
  160. int currLeft = 0;
  161. int availableWidth = tableWidth;
  162. // int lastCellHeight = 1;
  163. CellPostion previousGridPos = CellPostion();
  164. while ((headGrid = _getFirstGrid(cells)) != null) {
  165. CellPostion headGridPos = headGrid!.key;
  166. RTCell cellElement = headGrid.value.element as RTCell;
  167. int groupFieldWidth = groupFieldMap[cellElement.groupField!] == null
  168. ? headGridPos.columnSpan!
  169. : groupFieldMap[cellElement.groupField!]!.size;
  170. if (cellElement.blocks != null &&
  171. cellElement.blocks!.isNotEmpty &&
  172. cellElement.blocks![0].elements!.isNotEmpty &&
  173. cellElement.blocks![0].elements![0] is InputText) {
  174. groupFieldWidth = headGridPos.columnSpan!;
  175. }
  176. if (groupFieldWidth > availableWidth) {
  177. /// 换行前需要补全剩余空间
  178. if (availableWidth > 0) {
  179. Map<CellPostion, RTCellInfo> lostCells = _getEmptyCells(
  180. currTop, currLeft, previousGridPos.rowSpan!, availableWidth);
  181. newCells.addAll(lostCells);
  182. }
  183. currTop += previousGridPos.rowSpan!;
  184. currLeft = 0;
  185. availableWidth = tableWidth;
  186. }
  187. CellPostion newGridPos = CellPostion();
  188. newGridPos.row = currTop;
  189. newGridPos.column = currLeft;
  190. newGridPos.rowSpan = headGridPos.rowSpan;
  191. newGridPos.columnSpan = headGridPos.columnSpan;
  192. currLeft += newGridPos.columnSpan!;
  193. availableWidth -= newGridPos.columnSpan!;
  194. /// 如果追加的后一格高于前一格,需要补齐前一格下方空缺
  195. if (newGridPos.column! > 0 &&
  196. newGridPos.rowSpan! > previousGridPos.rowSpan!) {
  197. // print("如果追加的后一格高于前一格,需要补齐前一格下方空缺 ++++");
  198. newCells.addAll(_getLostCell(previousGridPos, newGridPos.rowSpan!));
  199. }
  200. /// 如果追加的后一格低于前一格,需要补齐后一格下方空缺
  201. if (newGridPos.column! > 0 &&
  202. newGridPos.rowSpan! < previousGridPos.rowSpan!) {
  203. // print("如果追加的后一格低于前一格,需要补齐后一格下方空缺");
  204. newCells.addAll(_getLostCell(newGridPos, previousGridPos.rowSpan!));
  205. }
  206. previousGridPos = newGridPos;
  207. newCells.addAll({newGridPos: headGrid.value});
  208. }
  209. if (availableWidth > 0) {
  210. Map<CellPostion, RTCellInfo> lostCells = _getEmptyCells(
  211. currTop, currLeft, previousGridPos.rowSpan!, availableWidth);
  212. newCells.addAll(lostCells);
  213. }
  214. return newCells;
  215. }
  216. /// 特殊模式重排序
  217. static Map<CellPostion, RTCellInfo> specialSortCells(
  218. Map<CellPostion, RTCellInfo> cells,
  219. Map<String, GroupFieldArgs> groupFieldMap,
  220. int groupStartPosX,
  221. int groupStartPosY,
  222. ) {
  223. Map<CellPostion, RTCellInfo> newCells = {};
  224. List<String> titleGroupFieldList = [];
  225. for (MapEntry<String, GroupFieldArgs> group in groupFieldMap.entries) {
  226. if (group.value.cellsCount == 1) {
  227. newCells.addAll(group.value.cells);
  228. group.value.cells.forEach((key, value) {
  229. cells.remove(key);
  230. });
  231. titleGroupFieldList.add(group.key);
  232. }
  233. }
  234. groupFieldMap
  235. .removeWhere((key, value) => titleGroupFieldList.contains(key));
  236. /// 按左上优先的顺序写入 groups
  237. MapEntry<String, GroupFieldArgs>? headGroupField =
  238. _getFirstGroupField(groupFieldMap);
  239. int layoutX = groupStartPosX;
  240. int layoutY = groupStartPosY;
  241. while (headGroupField != null) {
  242. GroupFieldArgs groupArgs = headGroupField.value;
  243. Map<CellPostion, RTCellInfo> groupCells = groupArgs.cells;
  244. List<CellPostion> originPosList = groupCells.keys.toList();
  245. originPosList.sort((a, b) {
  246. if (a.row! == b.row!) {
  247. return a.column!.compareTo(b.column!);
  248. } else {
  249. return a.row!.compareTo(b.row!);
  250. }
  251. });
  252. if (originPosList.length == 3) {
  253. // 处理第一个格
  254. CellPostion firstCellPos = originPosList[0];
  255. firstCellPos.row = layoutY;
  256. firstCellPos.column = layoutX;
  257. newCells.addAll({firstCellPos: groupCells[originPosList[0]]!});
  258. // 处理第二个格
  259. CellPostion secondCellPos = originPosList[1];
  260. secondCellPos.row = layoutY;
  261. secondCellPos.column = layoutX + 1;
  262. newCells.addAll({secondCellPos: groupCells[originPosList[1]]!});
  263. // 处理第三个格
  264. CellPostion thirdCellPos = originPosList[2];
  265. thirdCellPos.row = layoutY + 1;
  266. thirdCellPos.column = layoutX;
  267. newCells.addAll({thirdCellPos: groupCells[originPosList[2]]!});
  268. layoutX += 2;
  269. if (layoutX >= 4) {
  270. layoutX = 0;
  271. layoutY += 2;
  272. }
  273. }
  274. cells.removeWhere((key, value) => originPosList.contains(key));
  275. groupFieldMap.remove(headGroupField.key);
  276. headGroupField = _getFirstGroupField(groupFieldMap);
  277. }
  278. if (layoutX != 0) {
  279. Map<CellPostion, RTCellInfo> lostCells =
  280. _getEmptyCells(layoutY, layoutX, 2, 2);
  281. newCells.addAll(lostCells);
  282. }
  283. return newCells;
  284. }
  285. /// 移除尾部的占位格
  286. static removeTailEmptyCells(Map<CellPostion, RTCellInfo> cells) {
  287. MapEntry<CellPostion, RTCellInfo>? lastGrid = _getLastGrid(cells);
  288. while (lastGrid != null && lastGrid.value.blocks != null) {
  289. if (lastGrid.value.blocks![0].elementInfos!.isEmpty) {
  290. cells.remove(lastGrid.key);
  291. lastGrid = _getLastGrid(cells);
  292. } else {
  293. break;
  294. }
  295. }
  296. }
  297. /// 获取补缺口的单元格
  298. static Map<CellPostion, RTCellInfo> _getLostCell(
  299. CellPostion gridPos, int maxHeight) {
  300. Map<CellPostion, RTCellInfo> lostCells = _getEmptyCells(
  301. gridPos.row! + gridPos.rowSpan!,
  302. 0,
  303. maxHeight - gridPos.rowSpan!,
  304. gridPos.column! + gridPos.columnSpan!);
  305. return lostCells;
  306. }
  307. static Map<CellPostion, RTCellInfo> _getEmptyCells(
  308. int startRow, int startColumn, int rowSpan, int columnSpan) {
  309. // 根据传入位置及尺寸,生成 1x1 的空单元格,返回
  310. Map<CellPostion, RTCellInfo> emptyCells = {};
  311. for (int i = 0; i < rowSpan; i++) {
  312. for (int j = 0; j < columnSpan; j++) {
  313. CellPostion newGridPos = CellPostion();
  314. RTCell emptyICell = RTCell.fromJson(_emptyCellJson);
  315. RTCellInfo emptyCell = RTCellInfo.fromElement(emptyICell);
  316. newGridPos.rowSpan = 1;
  317. newGridPos.columnSpan = 1;
  318. newGridPos.row = startRow + i;
  319. newGridPos.column = startColumn + j;
  320. emptyCells.addAll({newGridPos: emptyCell});
  321. }
  322. }
  323. return emptyCells;
  324. }
  325. /// 遍历 cells 找出最左上角的单元格
  326. static MapEntry<CellPostion, RTCellInfo>? _getFirstGrid(
  327. Map<CellPostion, RTCellInfo> cells) {
  328. if (cells.isEmpty) return null;
  329. MapEntry<CellPostion, RTCellInfo> headGrid = cells.entries.first;
  330. for (MapEntry<CellPostion, RTCellInfo> cell in cells.entries) {
  331. if (cell.key.row! < headGrid.key.row!) {
  332. headGrid = cell;
  333. } else if (cell.key.row! == headGrid.key.row!) {
  334. if (cell.key.column! < headGrid.key.column!) {
  335. headGrid = cell;
  336. }
  337. }
  338. }
  339. cells.removeWhere((key, value) => key == headGrid.key);
  340. return headGrid;
  341. }
  342. /// 遍历 cells 找出最右下的单元格
  343. static MapEntry<CellPostion, RTCellInfo>? _getLastGrid(
  344. Map<CellPostion, RTCellInfo> cells) {
  345. if (cells.isEmpty) return null;
  346. MapEntry<CellPostion, RTCellInfo> tailGrid = cells.entries.first;
  347. for (MapEntry<CellPostion, RTCellInfo> cell in cells.entries) {
  348. if (cell.key.row! + cell.key.rowSpan! >
  349. tailGrid.key.row! + tailGrid.key.rowSpan!) {
  350. tailGrid = cell;
  351. } else if (cell.key.row! + cell.key.rowSpan! ==
  352. tailGrid.key.row! + tailGrid.key.rowSpan!) {
  353. if (cell.key.column! + cell.key.columnSpan! >
  354. tailGrid.key.column! + tailGrid.key.columnSpan!) {
  355. tailGrid = cell;
  356. }
  357. }
  358. }
  359. return tailGrid;
  360. }
  361. /// 遍历 groupFields 找出最左上角的 groupField
  362. static MapEntry<String, GroupFieldArgs>? _getFirstGroupField(
  363. Map<String, GroupFieldArgs> groupFields) {
  364. if (groupFields.isEmpty) return null;
  365. MapEntry<String, GroupFieldArgs> headGroupField = groupFields.entries.first;
  366. for (MapEntry<String, GroupFieldArgs> groupField in groupFields.entries) {
  367. if (groupField.value.topPos < headGroupField.value.topPos) {
  368. headGroupField = groupField;
  369. } else if (groupField.value.topPos == headGroupField.value.topPos) {
  370. if (groupField.value.leftPos < headGroupField.value.leftPos) {
  371. headGroupField = groupField;
  372. }
  373. }
  374. }
  375. return headGroupField;
  376. }
  377. static final Map<String, dynamic> _emptyCellJson = {
  378. "Blocks": [],
  379. "Background": {
  380. "RGB": "rgb(255,255,255)",
  381. "R": 255,
  382. "G": 255,
  383. "B": 255,
  384. "A": 255
  385. },
  386. "WidthType": "FixedValue",
  387. "HeightType": "MinValue",
  388. "Borders": {
  389. "Left": {
  390. "BorderStyle": "Solid",
  391. "Color": {"RGB": "rgb(0,0,0)", "R": 0, "G": 0, "B": 0, "A": 255},
  392. "Thickness": 1
  393. },
  394. "Top": {
  395. "BorderStyle": "Solid",
  396. "Color": {"RGB": "rgb(0,0,0)", "R": 0, "G": 0, "B": 0, "A": 255},
  397. "Thickness": 1
  398. },
  399. "Right": {
  400. "BorderStyle": "Solid",
  401. "Color": {"RGB": "rgb(0,0,0)", "R": 0, "G": 0, "B": 0, "A": 255},
  402. "Thickness": 1
  403. },
  404. "Bottom": {
  405. "BorderStyle": "Solid",
  406. "Color": {"RGB": "rgb(0,0,0)", "R": 0, "G": 0, "B": 0, "A": 255},
  407. "Thickness": 1
  408. }
  409. },
  410. "GroupField": "",
  411. "HorizontalAlignment": "Left",
  412. "VerticalAlignment": "Center",
  413. "Margin": {"Left": 0, "Top": 0, "Right": 0, "Bottom": 0},
  414. "ElementType": {"Name": "RTCell"}
  415. };
  416. /// 是否是特殊模式,形如:
  417. /// |--------------------|
  418. /// | | |
  419. /// |--------------------|
  420. /// | |
  421. /// |--------------------|
  422. /// TODO 该模式的匹配还需要细化
  423. static bool _isSpecialMode(Map<String, GroupFieldArgs> groupFieldMap) {
  424. // 如果所有的 groupFieldMap 的值都是 4,那么就是特殊模式
  425. for (GroupFieldArgs value in groupFieldMap.values) {
  426. if (value.cellsCount == 1) {
  427. continue;
  428. }
  429. if (value.size != 4 || value.cellsCount != 3) {
  430. return false;
  431. }
  432. }
  433. return true;
  434. }
  435. }
  436. class GroupFieldArgs {
  437. int size;
  438. Map<CellPostion, RTCellInfo> cells = {};
  439. int topPos = -1;
  440. int leftPos = -1;
  441. GroupFieldArgs(this.size, this.cells) {
  442. for (MapEntry<CellPostion, RTCellInfo> cell in cells.entries) {
  443. CellPostion pos = cell.key;
  444. if (topPos == -1 || pos.row! < topPos) {
  445. topPos = pos.row!;
  446. }
  447. if (leftPos == -1 || pos.column! < leftPos) {
  448. leftPos = pos.column!;
  449. }
  450. }
  451. }
  452. get cellsCount => cells.length;
  453. addSize(int add) {
  454. size += add;
  455. }
  456. addCell(CellPostion cellPos, RTCellInfo cellInfo) {
  457. cells.addAll({cellPos: cellInfo});
  458. if (topPos == -1 || cellPos.row! < topPos) {
  459. topPos = cellPos.row!;
  460. }
  461. if (leftPos == -1 || cellPos.column! < leftPos) {
  462. leftPos = cellPos.column!;
  463. }
  464. }
  465. }