glj_index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /**
  2. * 工料机汇总相关
  3. *
  4. * @author CaiAoLin
  5. * @date 2017/6/15
  6. * @version
  7. */
  8. let header = [];
  9. let gljSheet = null;
  10. let sourceData = [];
  11. let spread = null;
  12. let isChanging = false;
  13. let firstMixRatioRow = -1;
  14. let firstMachineRow = -1;
  15. $(document).ready(function () {
  16. // 初始化表格
  17. initGLJExcel();
  18. // 是否主动更改数据
  19. $("#message").on('click', '#load-data', function() {
  20. $("#notify").slideUp('fast');
  21. if (changeInfo.length > 0) {
  22. for (let index in changeInfo) {
  23. let cell = gljSheet.getCell(changeInfo[index].row, changeInfo[index].col, GC.Spread.Sheets.SheetArea.viewport);
  24. cell.value(changeInfo[index].newValue);
  25. }
  26. }
  27. changeInfo = [];
  28. });
  29. });
  30. /**
  31. * 初始化表格
  32. *
  33. */
  34. function initGLJExcel() {
  35. header = [
  36. {name: '编码', field: 'code', visible: true},
  37. {name: '名称', field: 'name', visible: true},
  38. {name: '规格型号', field: 'unit_price.specs', visible: true},
  39. {name: '单位', field: 'unit_price.unit', visible: true},
  40. {name: 'ID', field: 'id', visible: false},
  41. {name: '类型', field: 'unit_price.type', visible: false},
  42. {name: '总消耗量', field: 'quantity', visible: true},
  43. {name: '基价单价', field: "unit_price.base_price", visible: true},
  44. {name: '调整基价', field: 'adjust_price', visible: true},
  45. {name: '市场单价', field: "unit_price.market_price", visible: true, validator: 'number'},
  46. {name: '是否暂估', field: 'is_evaluate', visible: true, cellType: new GC.Spread.Sheets.CellTypes.CheckBox(), validator: 'boolean'},
  47. {name: '供货方式', field: 'supply', visible: true},
  48. {name: '甲供数量', field: 'supply_quantity', visible: true},
  49. {name: '交货方式', field: 'delivery', visible: true},
  50. {name: '送达地点', field: 'delivery_address', visible: true},
  51. {name: '不调价', field: 'is_adjust_price', visible: true, cellType: new GC.Spread.Sheets.CellTypes.CheckBox(), validator: 'boolean'},
  52. {name: 'UID', field: 'unit_price.id', visible: false},
  53. {name: '工料机ID', field: 'glj_id', visible: false},
  54. {name: '组成物消耗量', field: 'consumption', visible: false},
  55. {name: '父级关联编码', field: 'connect_code', visible: false},
  56. {name: '消耗量', field: 'ratio_data', visible: false},
  57. ];
  58. // 数据转换格式
  59. sourceData = JSON.parse(jsonData);
  60. let columnInfo = [];
  61. let setting = {
  62. header: []
  63. };
  64. for(let tmp of header) {
  65. setting.header.push({headerName: tmp.name, headerWidth: 120});
  66. columnInfo.push({name: tmp.field, displayName: tmp.name, visible: tmp.visible, cellType: tmp.cellType, size: 120});
  67. }
  68. spread = sheetCommonObj.buildSheet(document.getElementById("project-glj"), setting, sourceData.length);
  69. spread.options.scrollbarShowMax = true;
  70. spread.options.scrollbarMaxAlign = true;
  71. spread.options.showHorizontalScrollbar = true;
  72. gljSheet = spread.getActiveSheet();
  73. // 设置表单不可编辑
  74. gljSheet.options.isProtected = true;
  75. // 居中样式
  76. let centerStyleSetting = {hAlign: 1};
  77. gljSheet.setStyle(-1, 10, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
  78. gljSheet.setStyle(-1, 15, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
  79. gljSheet.setStyle(-1, 3, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
  80. // 向右对齐样式
  81. let rightStyleSetting = {hAlign: GC.Spread.Sheets.HorizontalAlign.right};
  82. gljSheet.setStyle(-1, 6, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
  83. gljSheet.setStyle(-1, 7, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
  84. gljSheet.setStyle(-1, 8, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
  85. gljSheet.setStyle(-1, 9, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
  86. // 设置可编辑列
  87. gljSheet.getRange(-1, 9, -1, 1).locked(false);
  88. gljSheet.getRange(-1, 10, -1, 1).locked(false);
  89. gljSheet.getRange(-1, 15, -1, 1).locked(false);
  90. // 设置数据
  91. gljSheet.autoGenerateColumns = false;
  92. gljSheet.bindColumns(columnInfo);
  93. gljSheet.setDataSource(sourceData);
  94. specialColumn(sourceData);
  95. // 绑定事件
  96. gljSheet.bind(GC.Spread.Sheets.Events.ValueChanged, updateBindEvent);
  97. // 绑定双击事件
  98. gljSheet.bind(GC.Spread.Sheets.Events.CellDoubleClick, function (element, info) {
  99. let column = info.col;
  100. let row = info.row;
  101. let field = header[column] !== undefined && header[column].field !== undefined ?
  102. header[column].field : '';
  103. // 获取类型
  104. let typeColumn = getFieldColumn(header, 'unit_price.type');
  105. let type = gljSheet.getValue(row, typeColumn);
  106. // 如果类型为混凝土、砂浆、配合比、机械,则提示
  107. if (field === 'unit_price.market_price' && canNotChangeTypeId.indexOf(type + '') >= 0) {
  108. alert('当前工料机的市场单价由组成物计算得出,不可直接修改');
  109. }
  110. });
  111. // 绑定单击事件
  112. gljSheet.bind(GC.Spread.Sheets.Events.CellClick, function (element, info) {
  113. if (currentTag === 'mix-ratio') {
  114. let projectGLJId = getActiveProjectGLJId();
  115. // 获取数据
  116. getMixRatioData(projectGLJId);
  117. }
  118. });
  119. }
  120. /**
  121. * 成功事件
  122. *
  123. * @param {string} field
  124. * @param {object} info
  125. * @return {void}
  126. */
  127. function successTrigger(field, info) {
  128. switch (field) {
  129. case 'unit_price.market_price':
  130. let row = info.row;
  131. // 获取类型
  132. let typeColumn = getFieldColumn(header, 'unit_price.type');
  133. let type = gljSheet.getValue(row, typeColumn);
  134. // 基价单价的计算
  135. basePriceCalculate(type, info);
  136. // 调整基价的计算
  137. adjustPriceCalculate(type, info);
  138. // 市场单价的计算
  139. marketPriceCalculate(type, info);
  140. // 触发websocket通知
  141. socket.emit('dataNotify', JSON.stringify(info));
  142. break;
  143. }
  144. }
  145. /**
  146. * 设置特殊单元格数据
  147. *
  148. * @param {object} sourceData
  149. * @return {void}
  150. */
  151. function specialColumn(sourceData) {
  152. let rowCounter = 0;
  153. // 获取是否暂估的列号
  154. let isEvaluateColumn = getFieldColumn(header, 'is_evaluate');
  155. // 获取市场单价列号
  156. let marketPriceColumn = getFieldColumn(header, 'unit_price.market_price');
  157. let connectCodeColumn = getFieldColumn(header, 'connect_code');
  158. let consumptionColumn = getFieldColumn(header, 'consumption');
  159. for(let data of sourceData) {
  160. // 只有材料才显示是否暂估
  161. if (materialIdList.indexOf(data.unit_price.type + '') < 0) {
  162. let string = new GC.Spread.Sheets.CellTypes.Text();
  163. gljSheet.setCellType(rowCounter, isEvaluateColumn, string, GC.Spread.Sheets.SheetArea.viewport);
  164. // 锁定该单元格
  165. gljSheet.getRange(rowCounter, isEvaluateColumn, 1, 1).locked(true);
  166. gljSheet.setValue(rowCounter, isEvaluateColumn, '');
  167. }
  168. // 如果类型为混凝土、砂浆、配合比、机械,则市场单价不能修改
  169. if (canNotChangeTypeId.indexOf(data.unit_price.type + '') >= 0) {
  170. firstMixRatioRow = firstMixRatioRow === -1 && data.unit_price.type !== GLJTypeConst.GENERAL_MACHINE ?
  171. rowCounter : firstMixRatioRow;
  172. firstMachineRow = firstMachineRow === -1 && data.unit_price.type === GLJTypeConst.GENERAL_MACHINE ?
  173. rowCounter : firstMachineRow;
  174. // 锁定该单元格
  175. gljSheet.getRange(rowCounter, marketPriceColumn, 1, 1).locked(true);
  176. }
  177. // 处理数据
  178. if (data.ratio_data.length > 0) {
  179. let connectCode = [];
  180. let consumption = [];
  181. for (let tmp of data.ratio_data) {
  182. connectCode.push(tmp.connect_code);
  183. consumption.push(tmp.consumption);
  184. }
  185. let connectCodeString = connectCode.join(',');
  186. let consumptionString = consumption.join(',');
  187. gljSheet.setValue(rowCounter, connectCodeColumn, connectCodeString);
  188. gljSheet.setValue(rowCounter, consumptionColumn, consumptionString);
  189. }
  190. rowCounter++;
  191. }
  192. }
  193. /**
  194. * 组成物父级价格计算
  195. *
  196. * @param {Number} row
  197. * @return {Object}
  198. */
  199. function compositionParentCalculate(row) {
  200. // 获取关联编码
  201. let connectCodeColumn = getFieldColumn(header, 'connect_code');
  202. let activeConnectCode = gljSheet.getValue(row, connectCodeColumn);
  203. // 不属于组成物则忽略
  204. if (activeConnectCode === '' || activeConnectCode === undefined) {
  205. return null;
  206. }
  207. activeConnectCode = activeConnectCode.split(',');
  208. // 计算同级组成物的价格
  209. // 遍历所有记录
  210. let maxRow = gljSheet.getRowCount();
  211. let consumptionColumn = getFieldColumn(header, 'consumption');
  212. let marketPriceColumn = getFieldColumn(header, 'unit_price.market_price');
  213. let parentMarketPrice = {};
  214. for (let i = 0; i < maxRow; i++) {
  215. let connectCode = gljSheet.getValue(i, connectCodeColumn);
  216. if (connectCode === null) {
  217. continue;
  218. }
  219. connectCode = connectCode.split(',');
  220. // 消耗量
  221. let consumption = gljSheet.getValue(i, consumptionColumn);
  222. consumption = consumption.split(',');
  223. // 获取市场价
  224. let marketPrice = gljSheet.getValue(i, marketPriceColumn);
  225. for (let active of activeConnectCode) {
  226. let index = connectCode.indexOf(active);
  227. if (index < 0) {
  228. continue;
  229. }
  230. let rowConsumption = consumption[index] === undefined ? 0 : consumption[index];
  231. // 计算价格
  232. let rowMarketPrice = (marketPrice * rowConsumption).toDecimal(2);
  233. parentMarketPrice[active] = parentMarketPrice[active] === undefined ?
  234. rowMarketPrice : (parentMarketPrice[active] + rowMarketPrice).toDecimal(2);
  235. }
  236. }
  237. return parentMarketPrice;
  238. }
  239. /**
  240. * 组成物父类数据更新
  241. *
  242. * @param {Object} parentMarketPrice
  243. * @return {void}
  244. */
  245. function compositionParentUpdate(parentMarketPrice) {
  246. let marketPriceColumn = getFieldColumn(header, 'unit_price.market_price');
  247. // 定位到父节点,然后更新
  248. for (let code in parentMarketPrice) {
  249. let changeRow = searchKeyword(code);
  250. gljSheet.setValue(changeRow, marketPriceColumn, parentMarketPrice[code]);
  251. }
  252. }
  253. /**
  254. * 查找指定数据并返回行号
  255. *
  256. * @param {String} keyword
  257. * @param {Number} rowStart
  258. * @param {Number} columnStart
  259. * @return {Number}
  260. */
  261. function searchKeyword(keyword, rowStart = 0, columnStart = 0) {
  262. let condition = new GC.Spread.Sheets.Search.SearchCondition();
  263. condition.searchString = keyword;
  264. condition.startSheetIndex = 0;
  265. condition.endSheetIndex = 0;
  266. condition.searchFlags = GC.Spread.Sheets.Search.SearchFlags.ignoreCase | GC.Spread.Sheets.Search.SearchFlags.blockRange;
  267. condition.searchOrder = GC.Spread.Sheets.Search.SearchOrder.nOrder;
  268. condition.searchTarget = GC.Spread.Sheets.Search.SearchFoundFlags.cellText;
  269. condition.sheetArea = GC.Spread.Sheets.SheetArea.viewport;
  270. condition.rowStart = rowStart;
  271. condition.columnStart = columnStart;
  272. let result = spread.search(condition);
  273. return result.foundRowIndex;
  274. }
  275. /**
  276. * 基价单价计算
  277. *
  278. * @param {Number} type
  279. * @param {object} info
  280. * @return {void}
  281. */
  282. function basePriceCalculate(type, info) {
  283. let basePriceColumn = getFieldColumn(header, 'unit_price.base_price');
  284. switch (type) {
  285. // 主材、设备自动赋值基价单价=市场单价
  286. case GLJTypeConst.MAIN_MATERIAL:
  287. case GLJTypeConst.EQUIPMENT:
  288. gljSheet.setValue(info.row, basePriceColumn, info.newValue);
  289. break;
  290. }
  291. }
  292. /**
  293. * 调整基价计算
  294. *
  295. * @param {Number} type
  296. * @param {object} info
  297. * @return {void}
  298. */
  299. function adjustPriceCalculate(type, info) {
  300. let basePriceColumn = getFieldColumn(header, 'unit_price.base_price');
  301. let adjustPriceColumn = getFieldColumn(header, 'adjust_price');
  302. switch (type) {
  303. // 材料、主材、设备 调整基价=基价单价
  304. case GLJTypeConst.MAIN_MATERIAL:
  305. case GLJTypeConst.EQUIPMENT:
  306. let basePrice = gljSheet.getValue(info.row, basePriceColumn);
  307. gljSheet.setValue(info.row, adjustPriceColumn, basePrice);
  308. break;
  309. }
  310. }
  311. /**
  312. * 市场单价计算
  313. *
  314. * @param {Number} type
  315. * @param {object} info
  316. * @return {void}
  317. */
  318. function marketPriceCalculate(type, info) {
  319. switch (type) {
  320. // 人工、材料(普通材料)触发 需计算混凝土、砂浆、配合比、机械的市场单价
  321. case GLJTypeConst.LABOUR:
  322. case GLJTypeConst.GENERAL_MATERIAL:
  323. // 计算
  324. compositionParentUpdate(info.parentMarketPrice);
  325. break;
  326. }
  327. }
  328. /**
  329. * 筛选数据
  330. *
  331. * @param {Array} typeList
  332. * @return {void}
  333. */
  334. function filterDataByType(typeList) {
  335. let typeColumn = getFieldColumn(header, 'unit_price.type');
  336. typeColumn = parseInt(typeColumn);
  337. let filter = new GC.Spread.Sheets.Filter.HideRowFilter(new GC.Spread.Sheets.Range(-1, typeColumn, -1, 1));
  338. gljSheet.rowFilter(filter);
  339. filter.filterButtonVisible(false);
  340. for (let type of typeList) {
  341. let condition = new GC.Spread.Sheets.ConditionalFormatting.Condition(GC.Spread.Sheets.ConditionalFormatting.ConditionType.numberCondition, {
  342. compareType: GC.Spread.Sheets.ConditionalFormatting.GeneralComparisonOperators.equalsTo,
  343. expected: type
  344. });
  345. filter.addFilterItem(typeColumn, condition);
  346. }
  347. filter.filter(typeColumn);
  348. gljSheet.invalidateLayout();
  349. gljSheet.repaint();
  350. let filterRow = typeList.indexOf(GLJTypeConst.GENERAL_MACHINE) >= 0 ? firstMachineRow : firstMixRatioRow;
  351. // 筛选后选中第一个符合类型的单元格
  352. gljSheet.setSelection(filterRow, 0, 1, 1);
  353. }
  354. /**
  355. * 绑定事件
  356. *
  357. * @param {object} element
  358. * @param {object} info
  359. * @return {void|boolean}
  360. */
  361. function updateBindEvent(element, info) {
  362. // 获取修改的数据
  363. let column = info.col;
  364. let row = info.row;
  365. let idString = 'id';
  366. let field = header[column] !== undefined && header[column].field !== undefined ?
  367. header[column].field : '';
  368. if (field === '') {
  369. return false;
  370. }
  371. // 切割字段
  372. let fieldArray = field.split('.');
  373. idString = fieldArray.length > 1 ? 'unit_price.id' : idString;
  374. // 防止快速同时提交
  375. if (isChanging) {
  376. return false;
  377. }
  378. // 校验数据
  379. let validator = header[column].validator !== undefined ? header[column].validator : null;
  380. let value = info.newValue;
  381. if (validator && !checkData(validator, value)) {
  382. alert('数据格式错误,请重新输入!');
  383. gljSheet.setValue(row, column, info.oldValue);
  384. return false;
  385. }
  386. // 获取id
  387. let idColumn = getFieldColumn(header, idString);
  388. if (idColumn < 0) {
  389. return false;
  390. }
  391. let id = gljSheet.getValue(row, idColumn);
  392. // 直接在前端计算后传值后台改
  393. let extend = {};
  394. let parentMarketPrice = compositionParentCalculate(row);
  395. if (Object.keys(parentMarketPrice).length > 0) {
  396. for (let activeCode in parentMarketPrice) {
  397. let tmpObject = {
  398. market_price: parentMarketPrice[activeCode],
  399. };
  400. extend[activeCode] = tmpObject;
  401. }
  402. }
  403. extend = Object.keys(extend).length > 0 ? JSON.stringify(extend) : '';
  404. $.ajax({
  405. url: '/glj/update',
  406. type: 'post',
  407. data: {id: id, field: field, value: value, extend: extend},
  408. dataType: 'json',
  409. error: function() {
  410. alert('数据传输有误!');
  411. isChanging = false;
  412. },
  413. beforeSend: function() {
  414. isChanging = true;
  415. },
  416. success: function(response) {
  417. isChanging = false;
  418. // 修改失败则恢复原值
  419. if (response.err !== 0) {
  420. gljSheet.setValue(row, column, info.oldValue);
  421. alert('更改数据失败!');
  422. } else {
  423. // 成功则触发相应事件
  424. if (parentMarketPrice !== null) {
  425. info.parentMarketPrice = parentMarketPrice;
  426. }
  427. successTrigger(field, info);
  428. }
  429. }
  430. });
  431. }
  432. /**
  433. * 获取当前行的项目工料机id
  434. *
  435. * @param {Number} activeRow
  436. * @return {Number}
  437. */
  438. function getActiveProjectGLJId() {
  439. let activeGLJRow = gljSheet.getActiveRowIndex();
  440. // 获取当前行的工料机id
  441. let gljIdColumn = getFieldColumn(header, 'id');
  442. let gljId = gljSheet.getValue(activeGLJRow, gljIdColumn);
  443. return gljId;
  444. }
  445. /**
  446. * 设置总消耗量
  447. *
  448. * @param {Number} row
  449. * @param {Number} change
  450. * @return {void}
  451. */
  452. function setGLJQuantity(row, change) {
  453. let quantityColumn = getFieldColumn(header, 'quantity');
  454. let oldValue = gljSheet.getValue(row, quantityColumn);
  455. change = (oldValue + change).toDecimal(2);
  456. gljSheet.setValue(row, quantityColumn, change);
  457. }
  458. /**
  459. * 设置对应字段数值
  460. *
  461. * @param {Number} row
  462. * @param {String} field
  463. * @param {Number} value
  464. * @param {boolean} appendMode
  465. * @return {void}
  466. */
  467. function setGLJCellByField(row, field, value, appendMode) {
  468. let columnIndex = getFieldColumn(header, field);
  469. if (appendMode) {
  470. let oldValue = gljSheet.getValue(row, columnIndex);
  471. value = (oldValue + value).toDecimal(2);
  472. }
  473. gljSheet.setValue(row, columnIndex, value);
  474. }