|
@@ -0,0 +1,346 @@
|
|
|
+import {
|
|
|
+ getExplainChildren,
|
|
|
+ getNewPage,
|
|
|
+ getTopicHead,
|
|
|
+ getElementId
|
|
|
+} from "../elementModel";
|
|
|
+import { deepCopy, calcSum } from "@/plugins/utils";
|
|
|
+
|
|
|
+const state = {
|
|
|
+ curElement: {},
|
|
|
+ curDragElement: {},
|
|
|
+ curPageNo: 0,
|
|
|
+ pages: [],
|
|
|
+ cardConfig: {},
|
|
|
+ openElementEditDialog: false
|
|
|
+};
|
|
|
+
|
|
|
+const mutations = {
|
|
|
+ setCurElement(state, curElement) {
|
|
|
+ state.curElement = curElement;
|
|
|
+ },
|
|
|
+ setCurDragElement(state, curDragElement) {
|
|
|
+ state.curDragElement = curDragElement;
|
|
|
+ },
|
|
|
+ setPages(state, pages) {
|
|
|
+ state.pages = pages;
|
|
|
+ },
|
|
|
+ setCardConfig(state, cardConfig) {
|
|
|
+ state.cardConfig = Object.assign({}, state.cardConfig, cardConfig);
|
|
|
+ },
|
|
|
+ setCurPageNo(state, curPageNo) {
|
|
|
+ state.curPageNo = curPageNo;
|
|
|
+ },
|
|
|
+ addPage(state, page) {
|
|
|
+ state.pages.push(page);
|
|
|
+ },
|
|
|
+ modifyPage(state, page) {
|
|
|
+ state.pages.splice(page._pageNo, 1, page);
|
|
|
+ },
|
|
|
+ setOpenElementEditDialog(state, openElementEditDialog) {
|
|
|
+ state.openElementEditDialog = openElementEditDialog;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const fetchElementPositionInfos = (element, pages) => {
|
|
|
+ let postionInfos = [];
|
|
|
+ for (let i = 0, ilen = pages.length; i < ilen; i++) {
|
|
|
+ for (let j = 0, jlen = pages[i].columns.length; j < jlen; j++) {
|
|
|
+ pages[i].columns[j].elements.forEach((item, eindex) => {
|
|
|
+ const itemId =
|
|
|
+ item.type === "EXPLAIN" ? item.parent && item.parent.id : item.id;
|
|
|
+
|
|
|
+ if (itemId === element.id) {
|
|
|
+ postionInfos.push({ _pageNo: i, _columnNo: j, _elementNo: eindex });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return postionInfos;
|
|
|
+};
|
|
|
+
|
|
|
+const fetchFirstSubjectiveTopicPositionInfo = pages => {
|
|
|
+ for (let i = 0, ilen = pages.length; i < ilen; i++) {
|
|
|
+ for (let j = 0, jlen = pages[i].columns.length; j < jlen; j++) {
|
|
|
+ const index = pages[i].columns[j].elements.findIndex(item => {
|
|
|
+ return item.sign === "subjective";
|
|
|
+ });
|
|
|
+ if (index !== -1) return { _pageNo: i, _columnNo: j, _elementNo: index };
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const fetchPageLastColumnPositionInfo = pages => {
|
|
|
+ return {
|
|
|
+ _pageNo: pages.length - 1,
|
|
|
+ _columnNo: pages[pages.length - 1].columns.length - 1
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+const findElementById = (id, pages) => {
|
|
|
+ let curElement = null;
|
|
|
+ pages.forEach(page => {
|
|
|
+ page.columns.forEach(column => {
|
|
|
+ column.elements.forEach(element => {
|
|
|
+ if (curElement) return;
|
|
|
+ if (element.id === id) {
|
|
|
+ curElement = element;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (element["elements"]) {
|
|
|
+ element["elements"].forEach(elem => {
|
|
|
+ if (element.id === id) curElement = elem;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return curElement;
|
|
|
+};
|
|
|
+
|
|
|
+const actions = {
|
|
|
+ modifyElement({ state, commit, dispatch }, element) {
|
|
|
+ // 解答题
|
|
|
+ if (element.type === "EXPLAIN") {
|
|
|
+ const positionInfos = fetchElementPositionInfos(element, state.pages);
|
|
|
+ if (positionInfos.length) {
|
|
|
+ // 删除所有解答题
|
|
|
+ positionInfos.forEach(pos => {
|
|
|
+ const elems =
|
|
|
+ state.pages[pos._pageNo].columns[pos._columnNo].elements;
|
|
|
+ elems.splice(pos._elementNo, 1);
|
|
|
+ });
|
|
|
+ // 创建新的解答题元素
|
|
|
+ const newElements = getExplainChildren(element);
|
|
|
+ const pos = positionInfos[0];
|
|
|
+ newElements.forEach(newElement => {
|
|
|
+ state.pages[pos._pageNo].columns[pos._columnNo].elements.splice(
|
|
|
+ pos._elementNo,
|
|
|
+ 0,
|
|
|
+ newElement
|
|
|
+ );
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ dispatch("addElement", element);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const positionInfos = fetchElementPositionInfos(element, state.pages);
|
|
|
+ if (positionInfos.length) {
|
|
|
+ const pos = positionInfos[0];
|
|
|
+ const elements =
|
|
|
+ state.pages[pos._pageNo].columns[pos._columnNo].elements;
|
|
|
+ elements.splice(pos._elementNo, 1, element);
|
|
|
+ } else {
|
|
|
+ dispatch("addElement", element);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ commit("setCurElement", element);
|
|
|
+ },
|
|
|
+ addElement({ state, commit }, element) {
|
|
|
+ let pos = null;
|
|
|
+ // 客观题和主观题分别对待
|
|
|
+ if (element.type === "FILL_QUESTION") {
|
|
|
+ pos =
|
|
|
+ fetchFirstSubjectiveTopicPositionInfo(state.pages) ||
|
|
|
+ fetchPageLastColumnPositionInfo(state.pages);
|
|
|
+ } else {
|
|
|
+ pos = fetchPageLastColumnPositionInfo(state.pages);
|
|
|
+ }
|
|
|
+
|
|
|
+ const elements = state.pages[pos._pageNo].columns[pos._columnNo].elements;
|
|
|
+ const preElements =
|
|
|
+ element.type === "EXPLAIN" ? getExplainChildren(element) : [element];
|
|
|
+ preElements.forEach(preElement => {
|
|
|
+ elements.push(preElement);
|
|
|
+ });
|
|
|
+
|
|
|
+ commit("setCurElement", element);
|
|
|
+ },
|
|
|
+ modifyCardHead({ state }, element) {
|
|
|
+ state.pages[0].columns[0].elements.splice(0, 1, element);
|
|
|
+ },
|
|
|
+ removeElement({ state, commit }, element) {
|
|
|
+ const positionInfos = fetchElementPositionInfos(element, state.pages);
|
|
|
+ if (!positionInfos.length) return;
|
|
|
+ positionInfos.forEach(pos => {
|
|
|
+ const elements = state.pages[pos._pageNo].columns[pos._columnNo].elements;
|
|
|
+ elements.splice(pos._elementNo, 1);
|
|
|
+ });
|
|
|
+
|
|
|
+ commit("setCurElement", {});
|
|
|
+ },
|
|
|
+ removeElementChild({ state, commit }, element) {
|
|
|
+ // 删除解答题小题和作文题的子元素
|
|
|
+ const positionInfos = fetchElementPositionInfos(
|
|
|
+ element.container,
|
|
|
+ state.pages
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!positionInfos.length) return;
|
|
|
+ positionInfos.forEach(pos => {
|
|
|
+ const columnElement =
|
|
|
+ state.pages[pos._pageNo].columns[pos._columnNo].elements[
|
|
|
+ pos._elementNo
|
|
|
+ ];
|
|
|
+ const childIndex = columnElement.elements.findIndex(
|
|
|
+ item => item.id === element.id
|
|
|
+ );
|
|
|
+ columnElement.elements.splice(childIndex, 1);
|
|
|
+ });
|
|
|
+ commit("setCurElement", {});
|
|
|
+ },
|
|
|
+ modifyElementChild({ state, commit }, element) {
|
|
|
+ // 修改解答题小题和作文题的子元素
|
|
|
+ const positionInfos = fetchElementPositionInfos(
|
|
|
+ element.container,
|
|
|
+ state.pages
|
|
|
+ );
|
|
|
+ if (!positionInfos.length) return;
|
|
|
+ positionInfos.forEach(pos => {
|
|
|
+ const columnElement =
|
|
|
+ state.pages[pos._pageNo].columns[pos._columnNo].elements[
|
|
|
+ pos._elementNo
|
|
|
+ ];
|
|
|
+ const childIndex = columnElement.elements.findIndex(
|
|
|
+ item => item.id === element.id
|
|
|
+ );
|
|
|
+ columnElement.elements.splice(childIndex, 1, element);
|
|
|
+ });
|
|
|
+ commit("setCurElement", element);
|
|
|
+ },
|
|
|
+ rebuildPages({ state, commit }) {
|
|
|
+ const columnNumber = state.cardConfig.columnNumber;
|
|
|
+ // 更新元件最新的高度信息
|
|
|
+ // 整理所有元件
|
|
|
+ const objectiveElements = [];
|
|
|
+ const subjectiveElements = [];
|
|
|
+ const cardHeadElement = state.pages[0].columns[0].elements[0];
|
|
|
+ state.pages.forEach(page => {
|
|
|
+ page.columns.forEach(column => {
|
|
|
+ column.elements.forEach(element => {
|
|
|
+ const elementDom = document.getElementById(element.id);
|
|
|
+ element.h = elementDom.offsetHeight;
|
|
|
+ element.w = elementDom.offsetWidth;
|
|
|
+ // 过滤掉所有topic-head元素,这个元素是动态加的,页面重排时可能会添加重复元件。
|
|
|
+ if (element.sign && element.type !== "TOPIC_HEAD") {
|
|
|
+ if (element.sign === "objective") objectiveElements.push(element);
|
|
|
+ if (element.sign === "subjective") subjectiveElements.push(element);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 动态计算每列可以分配的元件
|
|
|
+ const columnHeight = document.getElementById("column-0-0").offsetHeight;
|
|
|
+ const simpleCardHeadHeight = document.getElementById("simple-card-head")
|
|
|
+ .offsetHeight;
|
|
|
+ let pages = [];
|
|
|
+ let page = {};
|
|
|
+ let columns = [];
|
|
|
+ let curColumnElements = [];
|
|
|
+ let curColumnHeight = 0;
|
|
|
+
|
|
|
+ const initCurColumnElements = () => {
|
|
|
+ curColumnElements = [];
|
|
|
+ curColumnHeight = 0;
|
|
|
+ const groupColumnNumber = columnNumber * 2;
|
|
|
+ // 奇数页第一栏;
|
|
|
+ if (!(columns.length % groupColumnNumber)) {
|
|
|
+ // 非第一页奇数页第一栏
|
|
|
+ if (columns.length) {
|
|
|
+ const cardHeadSimpleElement = {
|
|
|
+ ...cardHeadElement
|
|
|
+ };
|
|
|
+ cardHeadSimpleElement.id = getElementId();
|
|
|
+ cardHeadSimpleElement.isSimple = true;
|
|
|
+ cardHeadSimpleElement.h = simpleCardHeadHeight;
|
|
|
+ curColumnElements.push(cardHeadSimpleElement);
|
|
|
+ curColumnHeight += simpleCardHeadHeight;
|
|
|
+ } else {
|
|
|
+ curColumnElements.push(cardHeadElement);
|
|
|
+ curColumnHeight += cardHeadElement.h;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const checkElementIsCurColumnFirstType = element => {
|
|
|
+ const topicHeadIndex = curColumnElements.findIndex(
|
|
|
+ elem => elem.type === "TOPIC_HEAD" && elem.sign === element.sign
|
|
|
+ );
|
|
|
+ return topicHeadIndex === -1;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 放入元素通用流程
|
|
|
+ const pushElement = element => {
|
|
|
+ // 当前栏中第一个题型之前新增题型头元素(topic-head)。
|
|
|
+ // 题型头和当前题要组合加入栏中,不可拆分。
|
|
|
+ let elementList = [element];
|
|
|
+ if (checkElementIsCurColumnFirstType(element)) {
|
|
|
+ elementList.unshift(
|
|
|
+ getTopicHead(state.cardConfig[`${element.sign}Notice`], element.sign)
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ const elementHeight = calcSum(elementList.map(elem => elem.h));
|
|
|
+ if (curColumnHeight + elementHeight > columnHeight) {
|
|
|
+ // 当前栏第一个元素高度超过一栏时,不拆分,直接放在当前栏。
|
|
|
+ // 解决可能空栏的情况
|
|
|
+ const curElementIsFirst = !curColumnElements.length;
|
|
|
+ if (curElementIsFirst) {
|
|
|
+ curColumnElements = [...curColumnElements, ...elementList];
|
|
|
+ curColumnHeight += elementHeight;
|
|
|
+ } else {
|
|
|
+ columns.push([...curColumnElements]);
|
|
|
+ initCurColumnElements();
|
|
|
+ pushElement(element);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ curColumnElements = [...curColumnElements, ...elementList];
|
|
|
+ curColumnHeight += elementHeight;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 批量添加所有元素。
|
|
|
+ initCurColumnElements();
|
|
|
+ [...objectiveElements, ...subjectiveElements].map((element, eindex) => {
|
|
|
+ element.serialNo = eindex;
|
|
|
+ pushElement(element);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 最后一栏的处理。
|
|
|
+ columns.push([...curColumnElements]);
|
|
|
+ // 构建pages
|
|
|
+ columns.forEach((column, cindex) => {
|
|
|
+ const columnNo = cindex % columnNumber;
|
|
|
+ if (!columnNo) {
|
|
|
+ page = getNewPage(pages.length, columnNumber);
|
|
|
+ }
|
|
|
+ page.columns[columnNo].elements = column;
|
|
|
+
|
|
|
+ if (columnNo + 1 === columnNumber || cindex === columns.length - 1) {
|
|
|
+ pages.push(deepCopy(page));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 保证页面总是偶数页
|
|
|
+ if (pages.length % 2) {
|
|
|
+ pages.push(getNewPage(pages.length, columnNumber));
|
|
|
+ }
|
|
|
+
|
|
|
+ commit("setPages", pages);
|
|
|
+ },
|
|
|
+ actElementById({ state, commit }, id) {
|
|
|
+ const curElement = findElementById(id, state.pages);
|
|
|
+ if (!curElement) return;
|
|
|
+
|
|
|
+ commit("setCurElement", curElement);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+export default {
|
|
|
+ namespaced: true,
|
|
|
+ state,
|
|
|
+ mutations,
|
|
|
+ actions
|
|
|
+};
|