/** * 工料机汇总相关 * * @author CaiAoLin * @date 2017/6/15 * @version */ let header = []; let gljSheet = null; let sourceData = []; let spread = null; let isChanging = false; let firstMixRatioRow = -1; let firstMachineRow = -1; $(document).ready(function () { // 初始化表格 initGLJExcel(); // 是否主动更改数据 $("#message").on('click', '#load-data', function() { $("#notify").slideUp('fast'); if (changeInfo.length > 0) { for (let index in changeInfo) { let cell = gljSheet.getCell(changeInfo[index].row, changeInfo[index].col, GC.Spread.Sheets.SheetArea.viewport); cell.value(changeInfo[index].newValue); } } changeInfo = []; }); }); /** * 初始化表格 * */ function initGLJExcel() { header = [ {name: '编码', field: 'code', visible: true}, {name: '名称', field: 'name', visible: true}, {name: '规格型号', field: 'unit_price.specs', visible: true}, {name: '单位', field: 'unit_price.unit', visible: true}, {name: 'ID', field: 'id', visible: false}, {name: '类型', field: 'unit_price.type', visible: false}, {name: '总消耗量', field: 'quantity', visible: true}, {name: '基价单价', field: "unit_price.base_price", visible: true}, {name: '调整基价', field: 'adjust_price', visible: true}, {name: '市场单价', field: "unit_price.market_price", visible: true, validator: 'number'}, {name: '是否暂估', field: 'is_evaluate', visible: true, cellType: new GC.Spread.Sheets.CellTypes.CheckBox(), validator: 'boolean'}, {name: '供货方式', field: 'supply', visible: true}, {name: '甲供数量', field: 'supply_quantity', visible: true}, {name: '交货方式', field: 'delivery', visible: true}, {name: '送达地点', field: 'delivery_address', visible: true}, {name: '不调价', field: 'is_adjust_price', visible: true, cellType: new GC.Spread.Sheets.CellTypes.CheckBox(), validator: 'boolean'}, {name: 'UID', field: 'unit_price.id', visible: false}, {name: '工料机ID', field: 'glj_id', visible: false}, {name: '组成物消耗量', field: 'consumption', visible: false}, {name: '父级关联编码', field: 'connect_code', visible: false}, {name: '消耗量', field: 'ratio_data', visible: false}, ]; // 数据转换格式 sourceData = JSON.parse(jsonData); let columnInfo = []; let setting = { header: [] }; for(let tmp of header) { setting.header.push({headerName: tmp.name, headerWidth: 120}); columnInfo.push({name: tmp.field, displayName: tmp.name, visible: tmp.visible, cellType: tmp.cellType, size: 120}); } spread = sheetCommonObj.buildSheet(document.getElementById("project-glj"), setting, sourceData.length); spread.options.scrollbarShowMax = true; spread.options.scrollbarMaxAlign = true; spread.options.showHorizontalScrollbar = true; gljSheet = spread.getActiveSheet(); // 设置表单不可编辑 gljSheet.options.isProtected = true; // 居中样式 let centerStyleSetting = {hAlign: 1}; gljSheet.setStyle(-1, 10, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport); gljSheet.setStyle(-1, 15, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport); gljSheet.setStyle(-1, 3, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport); // 向右对齐样式 let rightStyleSetting = {hAlign: GC.Spread.Sheets.HorizontalAlign.right}; gljSheet.setStyle(-1, 6, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport); gljSheet.setStyle(-1, 7, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport); gljSheet.setStyle(-1, 8, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport); gljSheet.setStyle(-1, 9, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport); // 设置可编辑列 gljSheet.getRange(-1, 9, -1, 1).locked(false); gljSheet.getRange(-1, 10, -1, 1).locked(false); gljSheet.getRange(-1, 15, -1, 1).locked(false); // 设置数据 gljSheet.autoGenerateColumns = false; gljSheet.bindColumns(columnInfo); gljSheet.setDataSource(sourceData); specialColumn(sourceData); // 绑定事件 gljSheet.bind(GC.Spread.Sheets.Events.ValueChanged, updateBindEvent); // 绑定双击事件 gljSheet.bind(GC.Spread.Sheets.Events.CellDoubleClick, function (element, info) { let column = info.col; let row = info.row; let field = header[column] !== undefined && header[column].field !== undefined ? header[column].field : ''; // 获取类型 let typeColumn = getFieldColumn(header, 'unit_price.type'); let type = gljSheet.getValue(row, typeColumn); // 如果类型为混凝土、砂浆、配合比、机械,则提示 if (field === 'unit_price.market_price' && canNotChangeTypeId.indexOf(type + '') >= 0) { alert('当前工料机的市场单价由组成物计算得出,不可直接修改'); } }); // 绑定单击事件 gljSheet.bind(GC.Spread.Sheets.Events.CellClick, function (element, info) { if (currentTag === 'mix-ratio') { let projectGLJId = getActiveProjectGLJId(); // 获取数据 getMixRatioData(projectGLJId); } }); } /** * 成功事件 * * @param {string} field * @param {object} info * @return {void} */ function successTrigger(field, info) { switch (field) { case 'unit_price.market_price': let row = info.row; // 获取类型 let typeColumn = getFieldColumn(header, 'unit_price.type'); let type = gljSheet.getValue(row, typeColumn); // 基价单价的计算 basePriceCalculate(type, info); // 调整基价的计算 adjustPriceCalculate(type, info); // 市场单价的计算 marketPriceCalculate(type, info); // 触发websocket通知 socket.emit('dataNotify', JSON.stringify(info)); break; } } /** * 设置特殊单元格数据 * * @param {object} sourceData * @return {void} */ function specialColumn(sourceData) { let rowCounter = 0; // 获取是否暂估的列号 let isEvaluateColumn = getFieldColumn(header, 'is_evaluate'); // 获取市场单价列号 let marketPriceColumn = getFieldColumn(header, 'unit_price.market_price'); let connectCodeColumn = getFieldColumn(header, 'connect_code'); let consumptionColumn = getFieldColumn(header, 'consumption'); for(let data of sourceData) { // 只有材料才显示是否暂估 if (materialIdList.indexOf(data.unit_price.type + '') < 0) { let string = new GC.Spread.Sheets.CellTypes.Text(); gljSheet.setCellType(rowCounter, isEvaluateColumn, string, GC.Spread.Sheets.SheetArea.viewport); // 锁定该单元格 gljSheet.getRange(rowCounter, isEvaluateColumn, 1, 1).locked(true); gljSheet.setValue(rowCounter, isEvaluateColumn, ''); } // 如果类型为混凝土、砂浆、配合比、机械,则市场单价不能修改 if (canNotChangeTypeId.indexOf(data.unit_price.type + '') >= 0) { firstMixRatioRow = firstMixRatioRow === -1 && data.unit_price.type !== GLJTypeConst.GENERAL_MACHINE ? rowCounter : firstMixRatioRow; firstMachineRow = firstMachineRow === -1 && data.unit_price.type === GLJTypeConst.GENERAL_MACHINE ? rowCounter : firstMachineRow; // 锁定该单元格 gljSheet.getRange(rowCounter, marketPriceColumn, 1, 1).locked(true); } // 处理数据 if (data.ratio_data.length > 0) { let connectCode = []; let consumption = []; for (let tmp of data.ratio_data) { connectCode.push(tmp.connect_code); consumption.push(tmp.consumption); } let connectCodeString = connectCode.join(','); let consumptionString = consumption.join(','); gljSheet.setValue(rowCounter, connectCodeColumn, connectCodeString); gljSheet.setValue(rowCounter, consumptionColumn, consumptionString); } rowCounter++; } } /** * 组成物父级价格计算 * * @param {Number} row * @return {Object} */ function compositionParentCalculate(row) { // 获取关联编码 let connectCodeColumn = getFieldColumn(header, 'connect_code'); let activeConnectCode = gljSheet.getValue(row, connectCodeColumn); // 不属于组成物则忽略 if (activeConnectCode === '' || activeConnectCode === undefined) { return null; } activeConnectCode = activeConnectCode.split(','); // 计算同级组成物的价格 // 遍历所有记录 let maxRow = gljSheet.getRowCount(); let consumptionColumn = getFieldColumn(header, 'consumption'); let marketPriceColumn = getFieldColumn(header, 'unit_price.market_price'); let parentMarketPrice = {}; for (let i = 0; i < maxRow; i++) { let connectCode = gljSheet.getValue(i, connectCodeColumn); if (connectCode === null) { continue; } connectCode = connectCode.split(','); // 消耗量 let consumption = gljSheet.getValue(i, consumptionColumn); consumption = consumption.split(','); // 获取市场价 let marketPrice = gljSheet.getValue(i, marketPriceColumn); for (let active of activeConnectCode) { let index = connectCode.indexOf(active); if (index < 0) { continue; } let rowConsumption = consumption[index] === undefined ? 0 : consumption[index]; // 计算价格 let rowMarketPrice = (marketPrice * rowConsumption).toDecimal(2); parentMarketPrice[active] = parentMarketPrice[active] === undefined ? rowMarketPrice : (parentMarketPrice[active] + rowMarketPrice).toDecimal(2); } } return parentMarketPrice; } /** * 组成物父类数据更新 * * @param {Object} parentMarketPrice * @return {void} */ function compositionParentUpdate(parentMarketPrice) { let marketPriceColumn = getFieldColumn(header, 'unit_price.market_price'); // 定位到父节点,然后更新 for (let code in parentMarketPrice) { let changeRow = searchKeyword(code); gljSheet.setValue(changeRow, marketPriceColumn, parentMarketPrice[code]); } } /** * 查找指定数据并返回行号 * * @param {String} keyword * @param {Number} rowStart * @param {Number} columnStart * @return {Number} */ function searchKeyword(keyword, rowStart = 0, columnStart = 0) { let condition = new GC.Spread.Sheets.Search.SearchCondition(); condition.searchString = keyword; condition.startSheetIndex = 0; condition.endSheetIndex = 0; condition.searchFlags = GC.Spread.Sheets.Search.SearchFlags.ignoreCase | GC.Spread.Sheets.Search.SearchFlags.blockRange; condition.searchOrder = GC.Spread.Sheets.Search.SearchOrder.nOrder; condition.searchTarget = GC.Spread.Sheets.Search.SearchFoundFlags.cellText; condition.sheetArea = GC.Spread.Sheets.SheetArea.viewport; condition.rowStart = rowStart; condition.columnStart = columnStart; let result = spread.search(condition); return result.foundRowIndex; } /** * 基价单价计算 * * @param {Number} type * @param {object} info * @return {void} */ function basePriceCalculate(type, info) { let basePriceColumn = getFieldColumn(header, 'unit_price.base_price'); switch (type) { // 主材、设备自动赋值基价单价=市场单价 case GLJTypeConst.MAIN_MATERIAL: case GLJTypeConst.EQUIPMENT: gljSheet.setValue(info.row, basePriceColumn, info.newValue); break; } } /** * 调整基价计算 * * @param {Number} type * @param {object} info * @return {void} */ function adjustPriceCalculate(type, info) { let basePriceColumn = getFieldColumn(header, 'unit_price.base_price'); let adjustPriceColumn = getFieldColumn(header, 'adjust_price'); switch (type) { // 材料、主材、设备 调整基价=基价单价 case GLJTypeConst.MAIN_MATERIAL: case GLJTypeConst.EQUIPMENT: let basePrice = gljSheet.getValue(info.row, basePriceColumn); gljSheet.setValue(info.row, adjustPriceColumn, basePrice); break; } } /** * 市场单价计算 * * @param {Number} type * @param {object} info * @return {void} */ function marketPriceCalculate(type, info) { switch (type) { // 人工、材料(普通材料)触发 需计算混凝土、砂浆、配合比、机械的市场单价 case GLJTypeConst.LABOUR: case GLJTypeConst.GENERAL_MATERIAL: // 计算 compositionParentUpdate(info.parentMarketPrice); break; } } /** * 筛选数据 * * @param {Array} typeList * @return {void} */ function filterDataByType(typeList) { let typeColumn = getFieldColumn(header, 'unit_price.type'); typeColumn = parseInt(typeColumn); let filter = new GC.Spread.Sheets.Filter.HideRowFilter(new GC.Spread.Sheets.Range(-1, typeColumn, -1, 1)); gljSheet.rowFilter(filter); filter.filterButtonVisible(false); for (let type of typeList) { let condition = new GC.Spread.Sheets.ConditionalFormatting.Condition(GC.Spread.Sheets.ConditionalFormatting.ConditionType.numberCondition, { compareType: GC.Spread.Sheets.ConditionalFormatting.GeneralComparisonOperators.equalsTo, expected: type }); filter.addFilterItem(typeColumn, condition); } filter.filter(typeColumn); gljSheet.invalidateLayout(); gljSheet.repaint(); let filterRow = typeList.indexOf(GLJTypeConst.GENERAL_MACHINE) >= 0 ? firstMachineRow : firstMixRatioRow; // 筛选后选中第一个符合类型的单元格 gljSheet.setSelection(filterRow, 0, 1, 1); } /** * 绑定事件 * * @param {object} element * @param {object} info * @return {void|boolean} */ function updateBindEvent(element, info) { // 获取修改的数据 let column = info.col; let row = info.row; let idString = 'id'; let field = header[column] !== undefined && header[column].field !== undefined ? header[column].field : ''; if (field === '') { return false; } // 切割字段 let fieldArray = field.split('.'); idString = fieldArray.length > 1 ? 'unit_price.id' : idString; // 防止快速同时提交 if (isChanging) { return false; } // 校验数据 let validator = header[column].validator !== undefined ? header[column].validator : null; let value = info.newValue; if (validator && !checkData(validator, value)) { alert('数据格式错误,请重新输入!'); gljSheet.setValue(row, column, info.oldValue); return false; } // 获取id let idColumn = getFieldColumn(header, idString); if (idColumn < 0) { return false; } let id = gljSheet.getValue(row, idColumn); // 直接在前端计算后传值后台改 let extend = {}; let parentMarketPrice = compositionParentCalculate(row); if (Object.keys(parentMarketPrice).length > 0) { for (let activeCode in parentMarketPrice) { let tmpObject = { market_price: parentMarketPrice[activeCode], }; extend[activeCode] = tmpObject; } } extend = Object.keys(extend).length > 0 ? JSON.stringify(extend) : ''; $.ajax({ url: '/glj/update', type: 'post', data: {id: id, field: field, value: value, extend: extend}, dataType: 'json', error: function() { alert('数据传输有误!'); isChanging = false; }, beforeSend: function() { isChanging = true; }, success: function(response) { isChanging = false; // 修改失败则恢复原值 if (response.err !== 0) { gljSheet.setValue(row, column, info.oldValue); alert('更改数据失败!'); } else { // 成功则触发相应事件 if (parentMarketPrice !== null) { info.parentMarketPrice = parentMarketPrice; } successTrigger(field, info); } } }); } /** * 获取当前行的项目工料机id * * @param {Number} activeRow * @return {Number} */ function getActiveProjectGLJId() { let activeGLJRow = gljSheet.getActiveRowIndex(); // 获取当前行的工料机id let gljIdColumn = getFieldColumn(header, 'id'); let gljId = gljSheet.getValue(activeGLJRow, gljIdColumn); return gljId; } /** * 设置总消耗量 * * @param {Number} row * @param {Number} change * @return {void} */ function setGLJQuantity(row, change) { let quantityColumn = getFieldColumn(header, 'quantity'); let oldValue = gljSheet.getValue(row, quantityColumn); change = (oldValue + change).toDecimal(2); gljSheet.setValue(row, quantityColumn, change); } /** * 设置对应字段数值 * * @param {Number} row * @param {String} field * @param {Number} value * @param {boolean} appendMode * @return {void} */ function setGLJCellByField(row, field, value, appendMode) { let columnIndex = getFieldColumn(header, field); if (appendMode) { let oldValue = gljSheet.getValue(row, columnIndex); value = (oldValue + value).toDecimal(2); } gljSheet.setValue(row, columnIndex, value); }