cardFormatTransform.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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: (curPageDom) => {
  61. let tops = [];
  62. curPageDom.querySelector(".page-locator-top").childNodes.forEach((item) => {
  63. tops.push(getOffsetInfo(item));
  64. });
  65. let bottoms = [];
  66. curPageDom
  67. .querySelector(".page-locator-bottom")
  68. .childNodes.forEach((item) => {
  69. bottoms.push(getOffsetInfo(item));
  70. });
  71. return {
  72. top: tops,
  73. bottom: bottoms,
  74. };
  75. },
  76. BARCODE: (element) => {
  77. return {
  78. barcode: [
  79. {
  80. field: element.fields[0] && element.fields[0].code,
  81. area: getOffsetInfo(getPreviewElementById(element.id)),
  82. },
  83. ],
  84. };
  85. },
  86. FILL_QUESTION: (element) => {
  87. const dom = getPreviewElementById(element.id);
  88. const single = !element.isMultiply;
  89. const horizontal = element.optionDirection === "horizontal";
  90. let fillAreas = [];
  91. dom.querySelectorAll(".group-item").forEach((groupItem) => {
  92. let listInfos = [];
  93. groupItem
  94. .querySelectorAll(".question-item")
  95. .forEach((questionItem, questionIndex) => {
  96. let options = [];
  97. questionItem.childNodes.forEach((optionItem, optionIndex) => {
  98. if (optionIndex)
  99. options[optionIndex - 1] = getOffsetInfo(optionItem);
  100. });
  101. listInfos[questionIndex] = {
  102. main_number: element.topicNo,
  103. sub_number: questionItem.firstChild.textContent * 1,
  104. options,
  105. recog_info: [],
  106. };
  107. });
  108. fillAreas.push({
  109. field: "question",
  110. index: getFillAreaIndex("question"),
  111. single,
  112. horizontal,
  113. items: listInfos,
  114. });
  115. });
  116. return {
  117. fill_area: fillAreas,
  118. };
  119. },
  120. FILL_LINE: (element) => {
  121. const dom = getPreviewElementById(element.id);
  122. let sub_numbers = [];
  123. for (
  124. let i = element.startNumber,
  125. len = element.startNumber + element.questionsCount;
  126. i < len;
  127. i++
  128. ) {
  129. sub_numbers.push(i);
  130. }
  131. return {
  132. answer_area: [
  133. {
  134. main_number: element.topicNo,
  135. sub_number: sub_numbers.join(),
  136. area: getOffsetInfo(dom),
  137. },
  138. ],
  139. };
  140. },
  141. FILL_NUMBER: (element) => {
  142. let listInfos = [];
  143. const dom = getPreviewElementById(element.id);
  144. dom
  145. .querySelectorAll(".fill-number-list")
  146. .forEach((questionItem, questionIndex) => {
  147. let options = [];
  148. questionItem.childNodes.forEach((optionItem, optionIndex) => {
  149. options[optionIndex] = getOffsetInfo(optionItem);
  150. });
  151. listInfos[questionIndex] = {
  152. main_number: null,
  153. sub_number: null,
  154. options,
  155. recog_info: [],
  156. };
  157. });
  158. return {
  159. fill_area: [
  160. {
  161. field: "examNumber",
  162. index: getFillAreaIndex("examNumber"),
  163. single: true,
  164. horizontal: false,
  165. items: listInfos,
  166. },
  167. ],
  168. };
  169. },
  170. FILL_FIELD: (element) => {
  171. const dom = getPreviewElementById(element.id);
  172. return {
  173. info_area: [getOffsetInfo(dom)],
  174. };
  175. },
  176. FILL_TABLE: (element) => {
  177. const dom = getPreviewElementById(element.id);
  178. return {
  179. info_area: [getOffsetInfo(dom)],
  180. };
  181. },
  182. LINES: (element) => {
  183. const dom = getPreviewElementById(element.id);
  184. return {
  185. answer_area: [
  186. {
  187. main_number: null,
  188. sub_number: null,
  189. area: getOffsetInfo(dom),
  190. },
  191. ],
  192. };
  193. },
  194. GRIDS: (element) => {
  195. const dom = getPreviewElementById(element.id);
  196. return {
  197. answer_area: [
  198. {
  199. main_number: null,
  200. sub_number: null,
  201. area: getOffsetInfo(dom),
  202. },
  203. ],
  204. };
  205. },
  206. };
  207. function getPageNumberInfo() {
  208. const dom = document.getElementById(`preview-page-box-0`);
  209. let options = [];
  210. dom
  211. .querySelector(".page-number-rect-list")
  212. .childNodes.forEach((item, index) => {
  213. options[index] = getOffsetInfo(item);
  214. });
  215. return [
  216. {
  217. field: "pageNumber",
  218. index: 1,
  219. single: true,
  220. horizontal: true,
  221. items: [
  222. {
  223. main_number: null,
  224. sub_number: null,
  225. options,
  226. recog_info: [],
  227. },
  228. ],
  229. },
  230. ];
  231. }
  232. function parsePageExchange(pages) {
  233. initFillAreaIndex();
  234. const npages = deepCopy(pages);
  235. curPageOffsetInfo = document
  236. .getElementById(`preview-page-box-0`)
  237. .getBoundingClientRect();
  238. const pageNumberInfo = pages.length > 2 ? getPageNumberInfo() : null;
  239. npages.forEach((page, pindex) => {
  240. curPageOffsetInfo = document
  241. .getElementById(`preview-page-box-${pindex}`)
  242. .getBoundingClientRect();
  243. let exchange = {
  244. card_type: 2,
  245. page_size: page.pageSize,
  246. page_image: "",
  247. locator: elementInfoFunc.LOCATOR(
  248. document.getElementById(`preview-page-box-${pindex}`)
  249. ),
  250. fill_locator: [],
  251. check_area: {
  252. black_line: [],
  253. white_line: [],
  254. },
  255. barcode: [],
  256. qrcode: [],
  257. ocr_area: [],
  258. info_area: [],
  259. fill_area: [],
  260. answer_area: [],
  261. extension: {
  262. barcode: [],
  263. fill_area: [],
  264. ocr_area: [],
  265. qrcode: [],
  266. },
  267. };
  268. const elements = [
  269. page.globals,
  270. ...page.columns.map((column) => column.elements),
  271. ];
  272. elements.forEach((elemGroup) => {
  273. elemGroup.forEach((element) => {
  274. if (!VALID_ELEMENTS_FOR_EXTERNAL.includes(element.type)) return;
  275. const info = elementInfoFunc[element.type](element);
  276. Object.entries(info).forEach(([key, vals]) => {
  277. exchange[key] = exchange[key].concat(vals);
  278. });
  279. });
  280. });
  281. if (!(pindex % 2) && pageNumberInfo) {
  282. let pnoInfo = deepCopy(pageNumberInfo);
  283. pnoInfo[0].index = getFillAreaIndex("pageNumber");
  284. exchange.fill_area = exchange.fill_area.concat(pnoInfo);
  285. }
  286. page.exchange = exchange;
  287. });
  288. return npages;
  289. }
  290. export function getPageModel({ cardConfig, pages }) {
  291. let npages = parsePageExchange(pages);
  292. return JSON.stringify(
  293. {
  294. version: CARD_VERSION,
  295. cardType: "FREE",
  296. cardConfig,
  297. pages: npages,
  298. },
  299. (k, v) => (k.startsWith("_") ? undefined : v)
  300. );
  301. }