card.js 22 KB

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