cardFormatTransform.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import { CARD_VERSION } from "../../enumerate";
  2. import { deepCopy } from "../../plugins/utils";
  3. const initIndex = {
  4. question: 1,
  5. absent: 1,
  6. paperType: 1,
  7. examNumber: 1,
  8. selective: 1,
  9. pageNumber: 1,
  10. };
  11. let fillAreaIndex = { ...initIndex };
  12. let curPageOffsetInfo = {};
  13. const VALID_ELEMENTS_FOR_EXTERNAL = [
  14. "LOCATOR",
  15. "BARCODE",
  16. "FILL_QUESTION",
  17. "FILL_LINE",
  18. "FILL_NUMBER",
  19. "FILL_FIELD",
  20. "FILL_TABLE",
  21. "LINES",
  22. "GRIDS",
  23. ];
  24. function initFillAreaIndex() {
  25. fillAreaIndex = { ...initIndex };
  26. }
  27. function getFillAreaIndex(type) {
  28. return fillAreaIndex[type]++;
  29. }
  30. function getPreviewElementById(id) {
  31. return document.getElementById(`preview-${id}`);
  32. }
  33. function getOffsetInfo(dom) {
  34. const {
  35. width: domW,
  36. height: domH,
  37. left: domL,
  38. top: domT,
  39. } = dom.getBoundingClientRect();
  40. const {
  41. width: pageW,
  42. height: pageH,
  43. left: pageL,
  44. top: pageT,
  45. } = curPageOffsetInfo;
  46. const infos = [
  47. (domL - pageL) / pageW,
  48. (domT - pageT) / pageH,
  49. domW / pageW,
  50. domH / pageH,
  51. ];
  52. return infos.map((num) => num.toFixed(10) * 1);
  53. }
  54. // locator: [],
  55. // barcode: [],
  56. // info_area: [],
  57. // fill_area: [],
  58. // answer_area: []
  59. const elementInfoFunc = {
  60. LOCATOR: (locators) => {
  61. const tops = locators.top.map((locator) => {
  62. return getOffsetInfo(document.getElementById(locator.id));
  63. });
  64. const bottoms = locators.bottom.map((locator) => {
  65. return getOffsetInfo(document.getElementById(locator.id));
  66. });
  67. return { top: tops, bottom: bottoms };
  68. },
  69. BARCODE: (element) => {
  70. return {
  71. barcode: [
  72. {
  73. field: element.fields[0] && element.fields[0].code,
  74. area: getOffsetInfo(getPreviewElementById(element.id)),
  75. },
  76. ],
  77. };
  78. },
  79. FILL_QUESTION: (element) => {
  80. const dom = getPreviewElementById(element.id);
  81. const single = !element.isMultiply;
  82. const horizontal = element.optionDirection === "horizontal";
  83. let fillAreas = [];
  84. dom.querySelectorAll(".group-item").forEach((groupItem) => {
  85. let listInfos = [];
  86. groupItem
  87. .querySelectorAll(".question-item")
  88. .forEach((questionItem, questionIndex) => {
  89. let options = [];
  90. questionItem.childNodes.forEach((optionItem, optionIndex) => {
  91. if (optionIndex)
  92. options[optionIndex - 1] = getOffsetInfo(optionItem);
  93. });
  94. listInfos[questionIndex] = {
  95. main_number: element.topicNo,
  96. sub_number: questionItem.firstChild.textContent * 1,
  97. options,
  98. recog_info: [],
  99. };
  100. });
  101. fillAreas.push({
  102. field: "question",
  103. index: getFillAreaIndex("question"),
  104. single,
  105. horizontal,
  106. items: listInfos,
  107. });
  108. });
  109. return {
  110. fill_area: fillAreas,
  111. };
  112. },
  113. FILL_LINE: (element) => {
  114. const dom = getPreviewElementById(element.id);
  115. let sub_numbers = [];
  116. for (
  117. let i = element.startNumber,
  118. len = element.startNumber + element.questionsCount;
  119. i < len;
  120. i++
  121. ) {
  122. sub_numbers.push(i);
  123. }
  124. return {
  125. answer_area: [
  126. {
  127. main_number: element.topicNo,
  128. sub_number: sub_numbers.join(),
  129. area: getOffsetInfo(dom),
  130. },
  131. ],
  132. };
  133. },
  134. FILL_NUMBER: (element) => {
  135. let listInfos = [];
  136. const dom = getPreviewElementById(element.id);
  137. dom
  138. .querySelectorAll(".fill-number-list")
  139. .forEach((questionItem, questionIndex) => {
  140. let options = [];
  141. questionItem.childNodes.forEach((optionItem, optionIndex) => {
  142. options[optionIndex] = getOffsetInfo(optionItem);
  143. });
  144. listInfos[questionIndex] = {
  145. main_number: null,
  146. sub_number: null,
  147. options,
  148. recog_info: [],
  149. };
  150. });
  151. return {
  152. fill_area: [
  153. {
  154. field: "examNumber",
  155. index: getFillAreaIndex("examNumber"),
  156. single: true,
  157. horizontal: false,
  158. items: listInfos,
  159. },
  160. ],
  161. };
  162. },
  163. FILL_FIELD: (element) => {
  164. const dom = getPreviewElementById(element.id);
  165. return {
  166. info_area: [getOffsetInfo(dom)],
  167. };
  168. },
  169. FILL_TABLE: (element) => {
  170. const dom = getPreviewElementById(element.id);
  171. return {
  172. info_area: [getOffsetInfo(dom)],
  173. };
  174. },
  175. LINES: (element) => {
  176. const dom = getPreviewElementById(element.id);
  177. return {
  178. answer_area: [
  179. {
  180. main_number: null,
  181. sub_number: null,
  182. area: getOffsetInfo(dom),
  183. },
  184. ],
  185. };
  186. },
  187. GRIDS: (element) => {
  188. const dom = getPreviewElementById(element.id);
  189. return {
  190. answer_area: [
  191. {
  192. main_number: null,
  193. sub_number: null,
  194. area: getOffsetInfo(dom),
  195. },
  196. ],
  197. };
  198. },
  199. };
  200. function getPageNumberInfo() {
  201. const dom = document.querySelector(".page-box-0");
  202. let options = [];
  203. dom
  204. .querySelector(".page-number-rect-list")
  205. .childNodes.forEach((item, index) => {
  206. options[index] = getOffsetInfo(item);
  207. });
  208. return [
  209. {
  210. field: "pageNumber",
  211. index: 1,
  212. single: true,
  213. horizontal: true,
  214. items: [
  215. {
  216. main_number: null,
  217. sub_number: null,
  218. options,
  219. recog_info: [],
  220. },
  221. ],
  222. },
  223. ];
  224. }
  225. function parsePageExchange(pages) {
  226. initFillAreaIndex();
  227. const npages = deepCopy(pages);
  228. curPageOffsetInfo = document
  229. .getElementById(`preview-page-box-0`)
  230. .getBoundingClientRect();
  231. const pageNumberInfo = pages.length > 2 ? getPageNumberInfo() : null;
  232. npages.forEach((page, pindex) => {
  233. curPageOffsetInfo = document
  234. .getElementById(`preview-page-box-${pindex}`)
  235. .getBoundingClientRect();
  236. let exchange = {
  237. card_type: 2,
  238. page_size: page.pageSize,
  239. page_image: "",
  240. locator: elementInfoFunc.LOCATOR(page.locators),
  241. fill_locator: [],
  242. check_area: {
  243. black_line: [],
  244. white_line: [],
  245. },
  246. barcode: [],
  247. qrcode: [],
  248. ocr_area: [],
  249. info_area: [],
  250. fill_area: [],
  251. answer_area: [],
  252. extension: {
  253. barcode: [],
  254. fill_area: [],
  255. ocr_area: [],
  256. qrcode: [],
  257. },
  258. };
  259. const elements = [
  260. page.globals,
  261. ...page.columns.map((column) => column.elements),
  262. ];
  263. elements.forEach((elemGroup) => {
  264. elemGroup.forEach((element) => {
  265. if (!VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) return;
  266. const info = elementInfoFunc[element.type](element);
  267. Object.entries(info).forEach(([key, vals]) => {
  268. exchange[key] = exchange[key].concat(vals);
  269. });
  270. });
  271. });
  272. if (!(pindex % 2) && pageNumberInfo) {
  273. let pnoInfo = deepCopy(pageNumberInfo);
  274. pnoInfo[0].index = getFillAreaIndex("pageNumber");
  275. exchange.fill_area = exchange.fill_area.concat(pnoInfo);
  276. }
  277. page.exchange = exchange;
  278. });
  279. return npages;
  280. }
  281. export function getPageModel({ cardConfig, paperParams, pages }) {
  282. let npages = parsePageExchange(pages);
  283. return JSON.stringify(
  284. {
  285. version: CARD_VERSION,
  286. cardConfig,
  287. paperParams,
  288. pages: npages,
  289. },
  290. (k, v) => (k.startsWith("_") ? undefined : v)
  291. );
  292. }