card.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. import {
  2. getExplainElements,
  3. getFillQuesitonElements,
  4. getFillLineElements,
  5. getCompositionElements,
  6. getNewPage,
  7. getTopicHeadModel
  8. } from "../elementModel";
  9. import { objAssign, deepCopy, calcSum, getElementId } from "../plugins/utils";
  10. const state = {
  11. cardConfig: {},
  12. paperParams: {},
  13. curElement: {},
  14. curDragElement: {},
  15. curPage: {},
  16. curPageNo: 0,
  17. pages: [],
  18. topics: [],
  19. topicSeries: [], // 大题顺序号
  20. insetTarget: {}, // 需要在其后面插入大题的大题
  21. openElementEditDialog: false
  22. };
  23. const mutations = {
  24. setCardConfig(state, cardConfig) {
  25. state.cardConfig = Object.assign({}, state.cardConfig, cardConfig);
  26. },
  27. setPaperParams(state, paperParams) {
  28. state.paperParams = paperParams;
  29. },
  30. setCurElement(state, curElement) {
  31. state.curElement = curElement;
  32. },
  33. setCurDragElement(state, curDragElement) {
  34. state.curDragElement = curDragElement;
  35. },
  36. setCurPage(state, curPageNo) {
  37. state.curPage = state.pages[curPageNo];
  38. state.curPageNo = curPageNo;
  39. },
  40. setCurPageNo(state, curPageNo) {
  41. state.curPageNo = curPageNo;
  42. },
  43. setPages(state, pages) {
  44. state.pages = pages;
  45. },
  46. setTopics(state, topics) {
  47. state.topics = topics;
  48. },
  49. setTopicSeries(state, topicSeries) {
  50. state.topicSeries = topicSeries;
  51. },
  52. setInsetTarget(state, insetTarget) {
  53. state.insetTarget = insetTarget;
  54. },
  55. addPage(state, page) {
  56. state.pages.push(page);
  57. },
  58. modifyPage(state, page) {
  59. state.pages.splice(page._pageNo, 1, page);
  60. },
  61. setOpenElementEditDialog(state, openElementEditDialog) {
  62. state.openElementEditDialog = openElementEditDialog;
  63. },
  64. initState(state) {
  65. state.curElement = {};
  66. state.curDragElement = {};
  67. state.curPage = {};
  68. state.curPageNo = 0;
  69. state.topics = [];
  70. state.pages = [];
  71. state.cardConfig = {};
  72. state.paperParams = {};
  73. state.openElementEditDialog = false;
  74. state.topicSeries = [];
  75. }
  76. };
  77. const fetchElementPositionInfos = (element, topics) => {
  78. return topics.findIndex(item => item.id === element.id);
  79. };
  80. const fetchAllRelateParentElementPositionInfos = (parentElement, topics) => {
  81. // 当为解答题时,parentElement传入的值是EXPLAIN
  82. let postionInfos = [];
  83. topics.forEach((item, eindex) => {
  84. if (item["parent"] && item.parent.id === parentElement.id) {
  85. let pos = { _elementNo: eindex };
  86. if (parentElement.type === "EXPLAIN") {
  87. pos.serialNumber = item.serialNumber;
  88. }
  89. postionInfos.push(pos);
  90. }
  91. });
  92. return postionInfos;
  93. };
  94. const fetchFirstSubjectiveTopicPositionInfo = topics => {
  95. return topics.findIndex(item => item.sign === "subjective");
  96. };
  97. const fetchSameSerialNumberChildrenPositionInfo = (
  98. elementChildernElement,
  99. topics
  100. ) => {
  101. let postionInfos = [];
  102. const elementId = elementChildernElement.parent.id;
  103. const serialNumber = elementChildernElement.serialNumber;
  104. topics.forEach((item, eindex) => {
  105. if (
  106. item.parent &&
  107. item.parent.id === elementId &&
  108. item.serialNumber === serialNumber
  109. ) {
  110. postionInfos.push({
  111. _elementNo: eindex,
  112. _elementId: item.id
  113. });
  114. }
  115. });
  116. return postionInfos;
  117. };
  118. const groupByParams = (datas, paramKey) => {
  119. let elementGroupInfos = [];
  120. for (let i = 0, len = datas.length; i < len; i++) {
  121. if (i === 0 || datas[i][paramKey] !== datas[i - 1][paramKey]) {
  122. elementGroupInfos.push([datas[i]]);
  123. } else {
  124. elementGroupInfos[elementGroupInfos.length - 1].push(datas[i]);
  125. }
  126. }
  127. return elementGroupInfos;
  128. };
  129. const findElementById = (id, topics) => {
  130. let curElement = null;
  131. topics.forEach(element => {
  132. if (curElement) return;
  133. if (element.id === id) {
  134. curElement = element;
  135. return;
  136. }
  137. if (element["elements"]) {
  138. element["elements"].forEach(elem => {
  139. if (elem.id === id) curElement = elem;
  140. });
  141. }
  142. });
  143. return curElement;
  144. };
  145. const checkElementisCovered = (id, type) => {
  146. const elementDom = document.getElementById(id);
  147. if (type === "EXPLAIN") {
  148. const elemTitleDome = elementDom.querySelector(".elem-title");
  149. const limitHeight = elemTitleDome
  150. ? elementDom.offsetHeight - elemTitleDome.offsetHeight
  151. : elementDom.offsetHeight;
  152. let elementHeights = [];
  153. elementDom
  154. .querySelector(".elem-explain-elements")
  155. .childNodes.forEach(node => {
  156. if (!node.className.includes("elem-explain-element")) return;
  157. elementHeights.push(
  158. node.firstChild.offsetHeight + node.firstChild.offsetTop
  159. );
  160. });
  161. return elementHeights.some(item => item > limitHeight);
  162. }
  163. if (type === "COMPOSITION") {
  164. const elemTitleDome = elementDom.querySelector(".elem-title");
  165. const limitHeight = elemTitleDome
  166. ? elementDom.offsetHeight - elemTitleDome.offsetHeight
  167. : elementDom.offsetHeight;
  168. let elementHeights = [];
  169. elementDom
  170. .querySelector(".elem-composition-elements")
  171. .childNodes.forEach(node => {
  172. if (!node.className.includes("elem-composition-element")) return;
  173. elementHeights.push(
  174. node.firstChild.offsetHeight + node.firstChild.offsetTop
  175. );
  176. });
  177. return elementHeights.some(item => item > limitHeight);
  178. }
  179. return elementDom.offsetHeight < elementDom.firstChild.offsetHeight;
  180. };
  181. const createFunc = {
  182. EXPLAIN(element) {
  183. return getExplainElements(element);
  184. },
  185. FILL_QUESTION(element) {
  186. return getFillQuesitonElements(element, state.cardConfig.columnNumber);
  187. },
  188. FILL_LINE(element) {
  189. return getFillLineElements(element);
  190. },
  191. COMPOSITION(element) {
  192. return [getCompositionElements(element)];
  193. }
  194. };
  195. const actions = {
  196. initTopicsFromPages({ state, commit }) {
  197. let topics = [];
  198. state.pages.forEach(page => {
  199. page.columns.forEach(column => {
  200. column.elements.forEach(element => {
  201. if (
  202. element.type === "TOPIC_HEAD" ||
  203. (element.type === "CARD_HEAD" && element.isSimple)
  204. )
  205. return;
  206. topics.push(element);
  207. });
  208. });
  209. });
  210. commit("setTopics", topics);
  211. },
  212. actElementById({ state, commit }, id) {
  213. const curElement = findElementById(id, state.topics);
  214. if (!curElement) return;
  215. commit("setCurElement", curElement);
  216. },
  217. resetTopicSeries({ state, commit }) {
  218. let curTopicId = "",
  219. curTopicNo = 0,
  220. topicSeries = [];
  221. state.topics.forEach(topic => {
  222. if (!topic.parent) return;
  223. if (curTopicId !== topic.parent.id) {
  224. curTopicId = topic.parent.id;
  225. curTopicNo++;
  226. topicSeries.push({
  227. id: curTopicId,
  228. topicNo: curTopicNo,
  229. type: topic.type,
  230. sign: topic.sign
  231. });
  232. }
  233. topic.topicNo = curTopicNo;
  234. });
  235. commit("setTopicSeries", topicSeries);
  236. },
  237. // 新增试题 --------------->
  238. addElement({ state, commit, dispatch }, element) {
  239. let pos = null;
  240. // 客观题和主观题分别对待
  241. if (state.insetTarget.id) {
  242. // 存在插入目标元素
  243. if (
  244. state.insetTarget.type === "FILL_QUESTION" &&
  245. element.type !== "FILL_QUESTION"
  246. ) {
  247. pos = fetchFirstSubjectiveTopicPositionInfo(state.topics);
  248. } else {
  249. let relateTopicPos = [];
  250. state.topics.forEach((item, index) => {
  251. if (item.parent && item.parent.id === state.insetTarget.id)
  252. relateTopicPos.push(index);
  253. });
  254. pos = relateTopicPos.slice(-1)[0] + 1;
  255. }
  256. } else {
  257. // 不存在插入目标元素
  258. if (element.sign === "objective") {
  259. pos = fetchFirstSubjectiveTopicPositionInfo(state.topics);
  260. }
  261. }
  262. let preElements = createFunc[element.type](element);
  263. preElements.forEach((preElement, index) => {
  264. if (pos && pos !== -1) {
  265. state.topics.splice(pos + index, 0, preElement);
  266. } else {
  267. state.topics.push(preElement);
  268. }
  269. });
  270. dispatch("resetTopicSeries");
  271. commit("setInsetTarget", {});
  272. commit("setCurElement", element);
  273. },
  274. // 修改试题 --------------->
  275. modifyTopic({ state }, element) {
  276. // 单独编辑某个细分题
  277. const pos = fetchElementPositionInfos(element, state.topics);
  278. state.topics.splice(pos, 1, element);
  279. },
  280. modifyComposition({ state }, element) {
  281. const positionInfos = fetchAllRelateParentElementPositionInfos(
  282. element,
  283. state.topics
  284. );
  285. positionInfos.forEach(({ _elementNo }) => {
  286. state.topics[_elementNo].topicNo = element.topicNo;
  287. state.topics[_elementNo].parent = objAssign(
  288. state.topics[_elementNo].parent,
  289. element
  290. );
  291. });
  292. },
  293. modifyExplain({ state }, element) {
  294. // 解答题既是拆分题,又是可复制题
  295. const positionInfos = fetchAllRelateParentElementPositionInfos(
  296. element,
  297. state.topics
  298. );
  299. const elementGroupPosInfos = groupByParams(positionInfos, "serialNumber");
  300. const orgElementCount = elementGroupPosInfos.length;
  301. if (orgElementCount > element.questionsCount) {
  302. // 原小题数多于新小题数,要删除原多于的小题;
  303. let needDeleteInfos = elementGroupPosInfos.splice(
  304. element.questionsCount,
  305. orgElementCount - element.questionsCount
  306. );
  307. needDeleteInfos.reverse().forEach(item => {
  308. item.reverse().forEach(pos => {
  309. state.topics.splice(pos._elementNo, 1);
  310. });
  311. });
  312. }
  313. const newElements = getExplainElements(element);
  314. const lastPos = elementGroupPosInfos.slice(-1)[0].slice(-1)[0];
  315. for (let i = 0; i < element.questionsCount; i++) {
  316. if (elementGroupPosInfos[i]) {
  317. elementGroupPosInfos[i].forEach(pos => {
  318. let child = state.topics[pos._elementNo];
  319. child.serialNumber = i + element.startNumber;
  320. child.parent = { ...element };
  321. child.topicNo = element.topicNo;
  322. });
  323. } else {
  324. state.topics.splice(lastPos._elementNo + 1, 0, newElements[i]);
  325. }
  326. }
  327. },
  328. modifySplitTopic({ state }, element) {
  329. // 非作文题都是拆分题,即同一个题拆分成多个小题展示
  330. const positionInfos = fetchAllRelateParentElementPositionInfos(
  331. element,
  332. state.topics
  333. );
  334. // 缓存已编辑的小题高度信息。
  335. const elementHeights = positionInfos.map(
  336. pos => state.topics[pos._elementNo].h
  337. );
  338. // 删除所有小题
  339. positionInfos.reverse().forEach(pos => {
  340. state.topics.splice(pos._elementNo, 1);
  341. });
  342. // 创建新的小题元素
  343. const newElements = createFunc[element.type](element);
  344. const pos = positionInfos.pop();
  345. newElements.forEach((newElement, index) => {
  346. newElement.h = Math.max(elementHeights[index] || 0, newElement.h);
  347. state.topics.splice(pos._elementNo + index, 0, newElement);
  348. });
  349. },
  350. modifyElement({ commit, dispatch }, element) {
  351. if (element.type === "COMPOSITION") {
  352. dispatch("modifyComposition", element);
  353. } else if (element.type === "EXPLAIN") {
  354. dispatch("modifyExplain", element);
  355. } else {
  356. dispatch("modifySplitTopic", element);
  357. }
  358. dispatch("resetTopicSeries");
  359. commit("setCurElement", element);
  360. },
  361. modifyCardHead({ state }, element) {
  362. state.topics.splice(0, 1, element);
  363. },
  364. // 修改试题包含元素
  365. modifyElementChild({ state, commit }, element) {
  366. // 修改解答题小题和作文题的子元素
  367. const pos = fetchElementPositionInfos(element.container, state.topics);
  368. const columnElements = state.topics[pos].elements;
  369. const childIndex = columnElements.findIndex(item => item.id === element.id);
  370. element.id = getElementId();
  371. // 作文题中的多线条和网格元素重新计算高度。
  372. if (element.container.type === "COMPOSITION") {
  373. if (element.type === "LINES") {
  374. element.h = element.lineCount * (element.lineSpacing + 1);
  375. }
  376. if (element.type === "GRIDS") {
  377. element.h =
  378. element.rowCount * (element.columnSize + 1 + element.rowSpace) + 1;
  379. }
  380. }
  381. if (childIndex === -1) {
  382. columnElements.push(element);
  383. } else {
  384. columnElements.splice(childIndex, 1, element);
  385. }
  386. commit("setCurElement", element);
  387. },
  388. // 粘贴试题内的元素
  389. pasteExplainElementChild({ state }, { curElement, pasteElement }) {
  390. let element = {
  391. id: curElement.container ? curElement.container.id : curElement.id
  392. };
  393. const pos = fetchElementPositionInfos(element, state.topics);
  394. if (pos === -1) return;
  395. element = state.topics[pos];
  396. const newElement = Object.assign({}, pasteElement, {
  397. id: getElementId(),
  398. container: {
  399. id: element.id,
  400. type: element.type
  401. }
  402. });
  403. element.elements.push(newElement);
  404. },
  405. // 删除试题 --------------->
  406. removeElement({ state, commit, dispatch }, element) {
  407. const positionInfos = fetchAllRelateParentElementPositionInfos(
  408. element.parent,
  409. state.topics
  410. );
  411. positionInfos.reverse().forEach(pos => {
  412. state.topics.splice(pos._elementNo, 1);
  413. });
  414. dispatch("resetTopicSeries");
  415. commit("setCurElement", {});
  416. },
  417. // 删除试题包含元素 --------------->
  418. removeElementChild({ state, commit }, element) {
  419. // 删除解答题小题和作文题的子元素
  420. const pos = fetchElementPositionInfos(element.container, state.topics);
  421. const columnElements = state.topics[pos].elements;
  422. const childIndex = columnElements.findIndex(item => item.id === element.id);
  423. columnElements.splice(childIndex, 1);
  424. commit("setCurElement", {});
  425. },
  426. // 扩展答题区操作 --------------->
  427. copyExplainChildren({ state }, element) {
  428. let curElement = {
  429. id: element.container ? element.container.id : element.id
  430. };
  431. const pos = fetchElementPositionInfos(curElement, state.topics);
  432. curElement = state.topics[pos];
  433. let newElement = Object.assign({}, curElement, {
  434. id: getElementId(),
  435. elements: [],
  436. h: 200,
  437. isExtend: true,
  438. showTitle: false
  439. });
  440. state.topics.splice(pos + 1, 0, newElement);
  441. // 更新小题答题区isLast
  442. let positionInfos = fetchSameSerialNumberChildrenPositionInfo(
  443. curElement,
  444. state.topics
  445. );
  446. positionInfos.forEach((pos, pindex) => {
  447. state.topics[pos._elementNo].isLast = pindex + 1 === positionInfos.length;
  448. });
  449. },
  450. deleteExplainChildren({ state }, element) {
  451. let curElement = {
  452. id: element.container ? element.container.id : element.id
  453. };
  454. const curPos = fetchElementPositionInfos(curElement, state.topics);
  455. curElement = state.topics[curPos];
  456. let positionInfos = fetchSameSerialNumberChildrenPositionInfo(
  457. curElement,
  458. state.topics
  459. );
  460. if (positionInfos.length < 2) return;
  461. const pindex = positionInfos.findIndex(
  462. item => item._elementId === curElement.id
  463. );
  464. const pos = positionInfos[pindex]._elementNo;
  465. positionInfos.splice(pindex, 1);
  466. const nextPos = positionInfos[0]._elementNo;
  467. // 当删除的是非扩展区域时,则下一个答题区要被设置成非扩展区
  468. if (!curElement.isExtend) {
  469. state.topics[nextPos].isExtend = false;
  470. }
  471. // 当删除的是含有标题答题区时,则需要将下一个答题区开启显示标题。
  472. if (curElement.showTitle) {
  473. state.topics[nextPos].showTitle = true;
  474. }
  475. state.topics.splice(pos, 1);
  476. // 更新小题答题区isLast
  477. positionInfos = fetchSameSerialNumberChildrenPositionInfo(
  478. curElement,
  479. state.topics
  480. );
  481. positionInfos.forEach((pos, pindex) => {
  482. state.topics[pos._elementNo].isLast = pindex + 1 === positionInfos.length;
  483. });
  484. },
  485. // 大题顺序操作 --------------->
  486. topicMoveUp({ state, dispatch }, topicId) {
  487. const curTopicPos = state.topicSeries.findIndex(
  488. item => item.id === topicId
  489. );
  490. const prevTopicId = state.topicSeries[curTopicPos - 1].id;
  491. let relateTopicPos = [];
  492. state.topics.forEach((item, index) => {
  493. if (item.parent && item.parent.id === topicId) relateTopicPos.push(index);
  494. });
  495. const prevTopicFirstIndex = state.topics.findIndex(
  496. item => item.parent && item.parent.id === prevTopicId
  497. );
  498. const relateTopics = state.topics.splice(
  499. relateTopicPos[0],
  500. relateTopicPos.length
  501. );
  502. relateTopics.reverse().forEach(topic => {
  503. state.topics.splice(prevTopicFirstIndex, 0, topic);
  504. });
  505. dispatch("resetTopicSeries");
  506. },
  507. // 重构页面
  508. resetElementProp({ state }, isResetId = false) {
  509. state.topics.forEach(element => {
  510. const elementDom = document.getElementById(element.id);
  511. if (elementDom) {
  512. element.h = elementDom.offsetHeight;
  513. element.w = elementDom.offsetWidth;
  514. }
  515. if (isResetId) {
  516. element.id = getElementId();
  517. }
  518. });
  519. },
  520. rebuildPages({ state, commit }) {
  521. const columnNumber = state.cardConfig.columnNumber;
  522. // 更新元件最新的高度信息
  523. // 整理所有元件
  524. const cardHeadElement = state.topics[0];
  525. state.topics.forEach(element => {
  526. const elementDom = document.getElementById(`preview-${element.id}`);
  527. if (elementDom) {
  528. element.h = elementDom.offsetHeight;
  529. element.w = elementDom.offsetWidth;
  530. // 解答题小题与其他题有些区别。
  531. // 其他题都是通过内部子元素自动撑高元件,而解答题则需要手动设置高度。
  532. const ESCAPE_ELEMENTS = ["CARD_HEAD"];
  533. element.isCovered =
  534. !ESCAPE_ELEMENTS.includes(element.type) &&
  535. checkElementisCovered(`preview-${element.id}`, element.type);
  536. }
  537. });
  538. // 动态计算每列可以分配的元件
  539. const columnHeight = document.getElementById("topic-column").offsetHeight;
  540. const simpleCardHeadHeight = document.getElementById("simple-card-head")
  541. .offsetHeight;
  542. let pages = [];
  543. let page = {};
  544. let columns = [];
  545. let curColumnElements = [];
  546. let curColumnHeight = 0;
  547. const initCurColumnElements = () => {
  548. curColumnElements = [];
  549. curColumnHeight = 0;
  550. const groupColumnNumber = columnNumber * 2;
  551. // 奇数页第一栏;
  552. if (!(columns.length % groupColumnNumber)) {
  553. // 非第一页奇数页第一栏
  554. if (columns.length) {
  555. const cardHeadSimpleElement = Object.assign({}, cardHeadElement, {
  556. id: getElementId(),
  557. isSimple: true,
  558. h: simpleCardHeadHeight
  559. });
  560. curColumnElements.push(cardHeadSimpleElement);
  561. curColumnHeight += simpleCardHeadHeight;
  562. } else {
  563. curColumnElements.push(cardHeadElement);
  564. curColumnHeight += cardHeadElement.h;
  565. }
  566. }
  567. };
  568. const checkElementIsCurColumnFirstType = element => {
  569. const topicHeadIndex = curColumnElements.findIndex(
  570. elem => elem.type === "TOPIC_HEAD" && elem.sign === element.sign
  571. );
  572. return topicHeadIndex === -1;
  573. };
  574. // 放入元素通用流程
  575. const pushElement = element => {
  576. // 当前栏中第一个题型之前新增题型头元素(topic-head)。
  577. // 题型头和当前题要组合加入栏中,不可拆分。
  578. let elementList = [element];
  579. if (checkElementIsCurColumnFirstType(element)) {
  580. elementList.unshift(
  581. getTopicHeadModel(
  582. state.cardConfig[`${element.sign}Attention`],
  583. element.sign,
  584. !curColumnElements.length
  585. )
  586. );
  587. }
  588. const elementHeight = calcSum(elementList.map(elem => elem.h));
  589. if (curColumnHeight + elementHeight > columnHeight) {
  590. // 当前栏第一个元素高度超过一栏时,不拆分,直接放在当前栏。
  591. // 解决可能空栏的情况
  592. const curElementIsFirst = !curColumnElements.length;
  593. if (curElementIsFirst) {
  594. curColumnElements = [...curColumnElements, ...elementList];
  595. curColumnHeight += elementHeight;
  596. } else {
  597. columns.push([...curColumnElements]);
  598. initCurColumnElements();
  599. pushElement(element);
  600. }
  601. } else {
  602. curColumnElements = [...curColumnElements, ...elementList];
  603. curColumnHeight += elementHeight;
  604. }
  605. };
  606. // 批量添加所有元素。
  607. initCurColumnElements();
  608. state.topics.slice(1).forEach((element, eindex) => {
  609. element.elementSerialNo = eindex;
  610. pushElement(element);
  611. });
  612. // 最后一栏的处理。
  613. columns.push([...curColumnElements]);
  614. // 构建pages
  615. columns.forEach((column, cindex) => {
  616. const columnNo = cindex % columnNumber;
  617. if (!columnNo) {
  618. page = getNewPage(pages.length, columnNumber);
  619. }
  620. page.columns[columnNo].elements = column;
  621. if (columnNo + 1 === columnNumber || cindex === columns.length - 1) {
  622. pages.push(deepCopy(page));
  623. }
  624. });
  625. // 保证页面总是偶数页
  626. if (pages.length % 2) {
  627. pages.push(getNewPage(pages.length, columnNumber));
  628. }
  629. commit("setPages", pages);
  630. commit("setCurPage", state.curPageNo);
  631. }
  632. };
  633. export { fetchSameSerialNumberChildrenPositionInfo, checkElementisCovered };
  634. export default {
  635. namespaced: true,
  636. state,
  637. mutations,
  638. actions
  639. };