import { getExplainChildren, getFillQuesitons, getFillLine, getNewPage, getTopicHead, getElementId } from "./elementModel"; import { deepCopy, calcSum } from "@/plugins/utils"; const state = { curElement: {}, curDragElement: {}, curPageNo: 0, pages: [], topicNos: [], cardConfig: {}, paperParams: {}, openElementEditDialog: false }; const mutations = { setCurElement(state, curElement) { state.curElement = curElement; }, setCurDragElement(state, curDragElement) { state.curDragElement = curDragElement; }, setPages(state, pages) { state.pages = pages; }, setTopicNos(state, topicNos) { topicNos.sort((a, b) => a - b); state.topicNos = topicNos; }, setCardConfig(state, cardConfig) { state.cardConfig = Object.assign({}, state.cardConfig, cardConfig); }, setPaperParams(state, paperParams) { state.paperParams = paperParams; }, 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; }, initTopicNos(state) { state.topicNos = getPageTopicNos(state.pages); }, initState(state) { state.curElement = {}; state.curDragElement = {}; state.curPageNo = 0; state.pages = []; state.cardConfig = {}; state.paperParams = {}; state.openElementEditDialog = false; state.topicNos = []; } }; /** * 获取所有相同元素的位置信息 * @param {Object} element 元素 * @param {Object} pages 页面结构 */ 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) => { if (item.id === element.id) { postionInfos.push({ _pageNo: i, _columnNo: j, _elementNo: eindex }); } }); } } return postionInfos; }; /** * 获取所有含有相同parent属性的元素位置信息 * @param {Object} parentElement 父元素 * @param {Object} pages 页面结构 */ const fetchAllRelateParentElementPositionInfos = (parentElement, pages) => { // 当为解答题时,parentElement传入的值是EXPLAIN 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) => { if (item["parent"] && item.parent.id === parentElement.id) { let pos = { _pageNo: i, _columnNo: j, _elementNo: eindex }; if (parentElement.type === "EXPLAIN") { pos.explainNumber = item.explainNumber; } postionInfos.push(pos); } }); } } 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 fetchSameExplainNumberExplainChildernPositionInfo = ( explainChildernElement, pages ) => { let postionInfos = []; const explainId = explainChildernElement.parent.id; const explainNumber = explainChildernElement.explainNumber; 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) => { if ( item.parent && item.parent.id === explainId && item.explainNumber === explainNumber ) { postionInfos.push({ _pageNo: i, _columnNo: j, _elementNo: eindex, _elementId: item.id }); } }); } } return postionInfos; }; function groupByParams(datas, paramKey) { let elementGroupInfos = []; for (let i = 0, len = datas.length; i < len; i++) { if (i === 0 || datas[i][paramKey] !== datas[i - 1][paramKey]) { elementGroupInfos.push([datas[i]]); } else { elementGroupInfos[elementGroupInfos.length - 1].push(datas[i]); } } return elementGroupInfos; } const getPageTopicNos = pages => { let topicNos = []; pages.forEach(page => { page.columns.forEach(column => { column.elements.forEach(element => { if (element["topicNo"] && !topicNos.includes(element["topicNo"])) topicNos.push(element["topicNo"]); }); }); }); return topicNos; }; 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 createFunc = { EXPLAIN(element) { return getExplainChildren(element); }, FILL_QUESTION(element) { return getFillQuesitons(element, state.cardConfig.columnNumber); }, FILL_LINE(element) { return getFillLine(element); }, COMPOSITION(element) { return [element]; } }; const actions = { modifyElement({ state, commit, dispatch }, element) { if (element.type === "COMPOSITION") { 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); } } else if (element.type === "EXPLAIN") { const positionInfos = fetchAllRelateParentElementPositionInfos( element, state.pages ); if (positionInfos.length) { const elementGroupPosInfos = groupByParams( positionInfos, "explainNumber" ); const orgElementCount = elementGroupPosInfos.length; if (orgElementCount > element.questionsCount) { // 原小题数多于新小题数,要删除原多于的小题; let needDeleteInfos = elementGroupPosInfos.splice( element.questionsCount, orgElementCount - element.questionsCount ); needDeleteInfos.reverse().forEach(item => { item.reverse().forEach(pos => { const elems = state.pages[pos._pageNo].columns[pos._columnNo].elements; elems.splice(pos._elementNo, 1); }); }); } const newElements = getExplainChildren(element); const lastPos = elementGroupPosInfos.slice(-1)[0].slice(-1)[0]; for (var i = 0; i < element.questionsCount; i++) { if (elementGroupPosInfos[i]) { elementGroupPosInfos[i].forEach(pos => { let child = state.pages[pos._pageNo].columns[pos._columnNo].elements[ pos._elementNo ]; child.explainNumber = i + element.startNumber; child.parent = { ...element }; }); } else { state.pages[lastPos._pageNo].columns[ lastPos._columnNo ].elements.splice(lastPos._elementNo + 1, 0, newElements[i]); } } } else { dispatch("addElement", element); } } else { // 非作文题都是拆分题,即同一个题拆分成多个小题展示 const positionInfos = fetchAllRelateParentElementPositionInfos( element, state.pages ); if (positionInfos.length) { // 缓存已编辑的小题高度信息。 const elementHeights = positionInfos.map(pos => { return state.pages[pos._pageNo].columns[pos._columnNo].elements[ pos._elementNo ].h; }); // 删除所有小题 positionInfos.reverse().forEach(pos => { const elems = state.pages[pos._pageNo].columns[pos._columnNo].elements; elems.splice(pos._elementNo, 1); }); // 创建新的小题元素 const newElements = createFunc[element.type](element); const pos = positionInfos.pop(); newElements.forEach((newElement, index) => { newElement.h = elementHeights[index] || newElement.h; state.pages[pos._pageNo].columns[pos._columnNo].elements.splice( pos._elementNo + index, 0, newElement ); }); } 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; let preElements = createFunc[element.type](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) { if (element.type === "COMPOSITION") { 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); }); } else { // 非作文题,删除所有小题。 const positionInfos = fetchAllRelateParentElementPositionInfos( element.parent, state.pages ); if (positionInfos.length) { positionInfos.reverse().forEach(pos => { const elems = state.pages[pos._pageNo].columns[pos._columnNo].elements; elems.splice(pos._elementNo, 1); }); } } // 删除大题题号 state.topicNos.splice(state.topicNos.indexOf(element.topicNo), 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); }, resetElementProp({ state }, isResetId = false) { state.pages.forEach(page => { page.columns.forEach(column => { column.elements.forEach(element => { const elementDom = document.getElementById(element.id); if (elementDom) { element.h = elementDom.offsetHeight; element.w = elementDom.offsetWidth; } if (isResetId) { element.id = getElementId(); } }); }); }); }, rebuildPages({ state, commit }) { const columnNumber = state.cardConfig.columnNumber; // 更新元件最新的高度信息 // 整理所有元件 let objectiveElements = []; let 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); if (elementDom) { element.h = elementDom.offsetHeight; element.w = elementDom.offsetWidth; // 解答题小题与其他题有些区别。 // 其他题都是通过内部子元素自动撑高元件,而解答题则需要手动设置高度。 element.isCovered = element.type !== "EXPLAIN_CHILDREN" && elementDom.offsetHeight < elementDom.firstChild.offsetHeight; } // 过滤掉所有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, !curColumnElements.length ) ); } 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); }, copyExplainChildren({ state }, element) { let newElement = deepCopy(element); newElement.id = getElementId(); newElement.elements = []; newElement.h = 200; newElement.showTitle = false; const positionInfos = fetchElementPositionInfos(element, state.pages); if (!positionInfos.length) return; const pos = positionInfos[0]; state.pages[pos._pageNo].columns[pos._columnNo].elements.splice( pos._elementNo + 1, 0, newElement ); }, deleteExplainChildren({ state }, element) { const positionInfos = fetchSameExplainNumberExplainChildernPositionInfo( element, state.pages ); if (positionInfos.length < 2) return; const pindex = positionInfos.findIndex( item => item._elementId === element.id ); const pos = positionInfos[pindex]; state.pages[pos._pageNo].columns[pos._columnNo].elements.splice( pos._elementNo, 1 ); // 当删除的是含有标题解答题小题时,则需要将下一个答题区开启显示标题。 // element.explainNumber === element.parent.startNumber && pindex === 0 if (element.showTitle) { const nextPos = positionInfos[pindex + 1]; state.pages[nextPos._pageNo].columns[nextPos._columnNo].elements[ nextPos._elementNo ].showTitle = true; } } }; export { fetchSameExplainNumberExplainChildernPositionInfo }; export default { namespaced: true, state, mutations, actions };