main.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. /**
  2. * Created by Syusuke on 2017/3/17.
  3. */
  4. //暂时不在养护云中开放,已以工具形式开放(打包了自己一份工程)
  5. //转换excel相关
  6. //Excel中人材机的数据不存在合并列
  7. const TransferExcel = (function () {
  8. const $transferModal = $('#transfer');
  9. const $file = $('#transfer-file');
  10. const $transfer = $('#transferConfirm');
  11. const $exportSpread = $('#exportSpread');
  12. let exportSpread = null;
  13. let transferData = [];
  14. //--以防需要可配置的情况
  15. const fixedCount = 4; //固定列数(顺序号、项目、单位、代号)
  16. const beginCol = 0;//起始的列
  17. //固定的这几列的列号映射是动态的,因为有一些子表,这些列进行了合并列的处理
  18. let colMapping = {
  19. serialNo: 0,
  20. name: 1,
  21. unit: 2,
  22. code: 3,
  23. consumeAmt: 4, //消耗量开始的列
  24. };
  25. //---
  26. function isUnDef(v) {
  27. return typeof v === 'undefined' || v === null;
  28. }
  29. //取消所有空格
  30. function trimAll(v) {
  31. return typeof v === 'string' ? v.replace(/\s/g, '') : v;
  32. }
  33. //单元格是否有数据
  34. function cellHasData(cell) {
  35. return cell && cell.value;
  36. }
  37. //行是否有数据
  38. //@param {Object}rowData(行数据) {Array}deduct(排除的列)
  39. function rowHasData(rowData, deduct = null) {
  40. for (let col in rowData) {
  41. if (deduct && deduct.includes(col)) {
  42. continue;
  43. }
  44. let cell = rowData[col];
  45. if (cell && cell.value) {
  46. return true;
  47. }
  48. }
  49. return false;
  50. }
  51. //行为列头行 //第一列为数值,且后面其他列有数据(不单纯认为是第二列,因为怕有合并序号列)
  52. function headerRow(rowData) {
  53. return rowData[0] && rowData[0].value && /^\d+$/.test(rowData[0].value) && rowHasData(rowData, ['0']);
  54. }
  55. //去除定额子表数组中的空行(有的表格是在 单位:xx 下面还跟着一些垃圾数据,导致subRation的range范围判定变大了,但是四列后面的数据是空的)
  56. function simplifyRationTable(arr) {
  57. let target = [];
  58. for (let subArr of arr) {
  59. let emptyRow = subArr.every(function (ele) {
  60. return ele === null;
  61. });
  62. if (emptyRow) {
  63. continue;
  64. }
  65. target.push(subArr);
  66. }
  67. return target;
  68. }
  69. //将二维数组转换成每个元素都有值的二维数据(去没值元素,因为前四列有可能合并列)
  70. function simplifyGljTable(arr) {
  71. let target = [];
  72. for (let subArr of arr) {
  73. let subTarget = [];
  74. for (let ele of subArr) {
  75. if (ele !== null) {
  76. subTarget.push(ele);
  77. }
  78. }
  79. target.push(subTarget);
  80. }
  81. return target;
  82. }
  83. //获取前固定四列的动态列映射(解决这几列可能有合并列的问题)
  84. function getColMapping(rowData, colCount) {
  85. function getUndefinedField(obj) {
  86. let needFields = ['serialNo', 'name', 'unit', 'code', 'consumeAmt'];
  87. for (let field of needFields) {
  88. if (!obj.hasOwnProperty(field)) {
  89. return field;
  90. }
  91. }
  92. return null;
  93. }
  94. //假定序号列为第一列
  95. let mapping = {serialNo: 0};
  96. for (let i = 1; i < colCount; i++) {
  97. let col = beginCol + i,
  98. cell = rowData[col];
  99. //还没设置的字段(必须要有的是serialNo, name, unit, code, consumeAmt)
  100. if (cell && cell.value) {
  101. let field = getUndefinedField(mapping);
  102. if (field) {
  103. mapping[field] = col;
  104. }
  105. if (typeof mapping.consumeAmt !== 'undefined') {
  106. return mapping;
  107. }
  108. }
  109. }
  110. return null;
  111. }
  112. //获取表头定额名称数据(最后一行为定额末位编码)
  113. //合并的单元格处理:为了更好的让定额获得对应的定额名称,将合并单元格做填值处理, eg: [a]['合并'] = [a][a]
  114. //@param {Object}dataTable {Object}range(表头的范围,row, col, rowCount, colCount) {Array}spans(spread解析Excel后的合并数组)
  115. //@return {Array}
  116. function getSubRationTable(dataTable, range, spans) {
  117. let subTable = [];
  118. for (let i = 0; i < range.rowCount; i++) {
  119. subTable.push(Array(range.colCount).fill(null));
  120. }
  121. //获取合并的单元格填充数据
  122. let fillArr = [];
  123. for (let i = 0; i < range.rowCount; i++) {
  124. let row = range.row + i;
  125. if (!dataTable[row]) {
  126. continue;
  127. }
  128. for (let j = 0; j < range.colCount; j++) {
  129. let col = range.col + j;
  130. let cell = dataTable[row][col];
  131. //只有有值的单元格,判断合并才有意义,有值且合并列的单元格,每列的值认为都是一样的
  132. if (cellHasData(cell)) {
  133. //是否合并了单元格
  134. let span = spans.find(function (data) {
  135. return data.row === row && data.col === col;
  136. });
  137. //这个fillData给subData填值用
  138. let fillData = {value: trimAll(cell.value), range: {row: i, col: j}};
  139. if (span) {
  140. fillData.range.rowCount = span.rowCount;
  141. fillData.range.colCount = span.colCount;
  142. } else {
  143. fillData.range.rowCount = 1;
  144. fillData.range.colCount = 1;
  145. }
  146. fillArr.push(fillData);
  147. }
  148. }
  149. }
  150. //将数据填充到subData中
  151. for (let fillData of fillArr) {
  152. //合并行不需要向下填值(否则会重复)
  153. let row = fillData.range.row;
  154. //合并列需要向右填值
  155. for (let j = 0; j < fillData.range.colCount; j++) {
  156. let col = fillData.range.col + j;
  157. subTable[row][col] = trimAll(fillData.value);
  158. }
  159. }
  160. return simplifyRationTable(subTable);
  161. }
  162. //获取工料机子表数据(序号至最末消耗量)
  163. //@param {Object}dataTable {Object}range(工料机子表的范围,row, col, rowCount, colCount)
  164. //@return {Array}
  165. function getSubGljTable(dataTable, range) {
  166. let gljTable = [];
  167. for (let i = 0; i < range.rowCount; i++) {
  168. gljTable.push(Array(range.colCount).fill(null));
  169. }
  170. for (let i = 0; i < range.rowCount; i++) {
  171. let row = range.row + i;
  172. if (!dataTable[row]) {
  173. continue;
  174. }
  175. for (let j = 0; j < range.colCount; j++) {
  176. let col = range.col + j;
  177. let cell = dataTable[row][col];
  178. if (cellHasData(cell)) {
  179. gljTable[i][j] = cell.value;
  180. }
  181. }
  182. }
  183. //工料机数据每个单元格应该都有值,没有的为合并列造成,这里将没值的单元格去除
  184. return simplifyGljTable(gljTable);
  185. }
  186. /*
  187. * 从原本的excel中提取数据
  188. * 需要的数据结构:eg: [{code: '1-1-1', name: '伐树', unit: '表列单位', subTable: [{subGlj: [], subRation: []}]}]
  189. * subTable为定额数据对应的子表数据,其中有定额名称子表、工料机子表
  190. * */
  191. function extractDataFromExcel(sheetData) {
  192. let dataTable = sheetData.data.dataTable,
  193. spans = sheetData.spans;
  194. //行数据是定额行 eg: 1-1-1 人工挖土方
  195. //@param {Number}row
  196. //@return {Object || Null} eg: {code: '1-1-1', name: '人工挖土方'}
  197. function rationRow(row) {
  198. let cell = dataTable[row][beginCol];
  199. if (!cell || !cell.value || typeof cell.value !== 'string') {
  200. return false;
  201. }
  202. let v = trimAll(cell.value);
  203. //[\-,—,一] 这里是因为pdf转出来的excel(需要转换的excel)会吧"-"显示成各种奇怪的横杆
  204. //第一数值限制在3位以内,防止有: 2019-05-01等日期干扰
  205. let reg = /^(\d{1,3}[\-,_,—,一]{1}\d+[\-,_,—,一]{1}\d+)(\w{0,}[\u4e00-\u9fa5]{1,})/;
  206. let match = reg.exec(v);
  207. if (match && match.length === 3 && match[0] && match[1] && match[2]) {
  208. return {code: match[1].replace(/[_,—,一]/g, '-'), name: match[2]};
  209. }
  210. return null;
  211. }
  212. //单位数据行 eg: 单位:表列单位
  213. //@return {String || Null} eg: '表列单位'
  214. function unitRow(row) {
  215. let cell = dataTable[row][beginCol];
  216. if (!cell || !cell.value || typeof cell.value !== 'string') {
  217. return false;
  218. }
  219. let v = trimAll(cell.value);
  220. let reg = /单位[\:, :]([\w+, \u4e00-\u9fa5]{0,})/;
  221. let match = reg.exec(v);
  222. if (match && match.length === 2 && match[0] && match[1]) {
  223. return match[1];
  224. }
  225. return null;
  226. }
  227. //行数据是人材机数据行
  228. //表头后,某行第一列为数值,第二列有值,则该行为紧接着表头的人材机数据行
  229. //@return {Boolean}
  230. function rowIsGlj(rowData) {
  231. let numberCell = rowData[colMapping.serialNo],
  232. valueCell = rowData[colMapping.name];
  233. return numberCell && numberCell.value && /^\d+$/.test(numberCell.value) && valueCell && Boolean(valueCell.value);
  234. }
  235. //连续有数据的列数(每个子表格中工料机的数据列数)
  236. //由于序号、项目、单位、代号可能存在合并列,因此从消耗量列(消耗量列不会合并列,消耗量对应的列号已在getColMapping获取)开始统计
  237. function getDataCount(row) {
  238. let consumeAmtCol = colMapping.consumeAmt;
  239. for (let col = consumeAmtCol; col < sheetData.columnCount; col++) {
  240. let cell = dataTable[row][col];
  241. if (!cell || !cell.value) {
  242. return col;
  243. }
  244. }
  245. return sheetData.columnCount;
  246. }
  247. //获取表格的子表范围(定额名称表头范围、工料机数据范围)
  248. //遇到单位:xx行rowA后,获取紧跟其后的表格,该表格最少要有一行工料机数据行rowB,表头范围则为rowA至rowB
  249. //@param {Number}beginRow
  250. function getTableRange(beginRow) {
  251. let hasTHead = false,
  252. hasTable = false,
  253. hasMapping = false; //是否获取过固定列映射
  254. let range = {
  255. subRation: {},
  256. subGlj: {},
  257. };
  258. for (let row = beginRow; row < sheetData.rowCount; row++) {
  259. if (!dataTable[row]) {
  260. continue;
  261. }
  262. //第一个有数据的行,为表头第一行
  263. if (rowHasData(dataTable[row]) && !hasTHead) {
  264. hasTHead = true;
  265. range.subRation.row = row;
  266. }
  267. //获取当前子表的固定列映射
  268. if (hasTHead && !hasTable && !hasMapping && headerRow(dataTable[row])) {
  269. hasMapping = true;
  270. colMapping = getColMapping(dataTable[row], sheetData.columnCount);
  271. if (!colMapping) {
  272. return null;
  273. }
  274. }
  275. //第一条工料机数据行
  276. if (hasTHead && !hasTable && colMapping && rowIsGlj(dataTable[row])) {
  277. hasTable = true;
  278. range.subGlj.row = row;
  279. range.subGlj.col = 0;
  280. range.subRation.col = colMapping.consumeAmt;
  281. range.subRation.rowCount = range.subGlj.row - range.subRation.row;
  282. range.subGlj.colCount = getDataCount(row);
  283. range.subRation.colCount = range.subGlj.colCount - colMapping.consumeAmt;
  284. }
  285. if (hasTable && !rowIsGlj(dataTable[row])) {
  286. range.subGlj.rowCount = row - range.subGlj.row;
  287. return range;
  288. }
  289. if (hasTable && (row === sheetData.rowCount - 1 || !dataTable[row + 1])) {
  290. range.subGlj.rowCount = row - range.subGlj.row + 1;
  291. return range;
  292. }
  293. }
  294. return null;
  295. }
  296. //分析整个表
  297. let extractData = [];
  298. //定额行后必须要跟着单位行
  299. let hasUnit = false;
  300. for (let row = 0; row < sheetData.rowCount; row++) {
  301. if (!dataTable[row] || !rowHasData(dataTable[row])) {
  302. continue;
  303. }
  304. let rationData = rationRow(row);
  305. if (rationData) {
  306. if (!hasUnit) {
  307. extractData.pop();
  308. }
  309. hasUnit = false;
  310. //转换数据数组的每个元素,为定额基本数据:不完整的code、不完整的name、unit、和子表门构成
  311. //subTable: [{subRation: [], subGlj: []}],subRation为每个子表表头数据(排除掉了顺序号至代号),
  312. //subGlj为每个子表工料机数据
  313. let basicData = {
  314. code: rationData.code,
  315. name: rationData.name,
  316. unit: null,
  317. subTable: []
  318. };
  319. extractData.push(basicData);
  320. }
  321. let unitData = unitRow(row);
  322. if (unitData) {
  323. hasUnit = true;
  324. let thisBasicData = extractData[extractData.length - 1];
  325. if (thisBasicData) {
  326. if (!thisBasicData.unit) {
  327. thisBasicData.unit = unitData;
  328. }
  329. //获取表格数据
  330. let range = getTableRange(row + 1);
  331. if (range) {
  332. let subRationTable = getSubRationTable(dataTable, range.subRation, spans),
  333. subGljTable = getSubGljTable(dataTable, range.subGlj);
  334. thisBasicData.subTable.push({subRation: subRationTable, subGlj: subGljTable});
  335. //跳过其中的行
  336. row = range.subGlj.row + range.subGlj.rowCount - 1;
  337. }
  338. }
  339. }
  340. }
  341. return extractData;
  342. }
  343. /*
  344. * 转换数据,将提取出来的数据转换成另外一种数据结构,便于转化Excel的结构
  345. * 需要的数据结构: eg: [{code: '1-1-1-1', name: '伐树xxx', unit: '表列单位', gljList: [{code,name,unit,comsumeAmt}]}]
  346. * */
  347. function transferDataFromExtract(extractData) {
  348. //从一个提取的数据(1定额数据及其子表数据)中获取一份转换数据
  349. function transfer(source) {
  350. //以完整定额编码为属性,因为1个定额可能会有多张子表,且完整定额编码相同,子工料机不同,方便直接添加后续的工料机
  351. let temp = {},
  352. target = [];
  353. let basicCode = source.code,
  354. basicName = source.name,
  355. basicUnit = source.unit;
  356. //处理消耗量,可能有(3.5) 和 - 的情况, 处理:(3.5) => 3.5 - => 0
  357. function handleConsumeAmt(consumeAmt) {
  358. if (typeof consumeAmt === 'string') {
  359. consumeAmt = trimAll(consumeAmt);
  360. consumeAmt = consumeAmt.replace(/[\-,_,—,一,\(,\),(,)]/g, '');
  361. if (!consumeAmt) {
  362. return 0;
  363. }
  364. }
  365. return consumeAmt;
  366. }
  367. //从工料机子表中获取工料机数据, index为定额编码对应的下标索引
  368. function getGljList(gljTable, index) {
  369. let gljList = [];
  370. //获取的工料机对应列
  371. let gljColMapping = {
  372. name: 1,
  373. unit: 2,
  374. code: 3,
  375. consumeAmtCol: fixedCount + index
  376. };
  377. for (let rowData of gljTable) {
  378. //工料机数据必须要有名称、单位、编码
  379. if (!rowData[gljColMapping.name] ||
  380. !rowData[gljColMapping.unit] ||
  381. !rowData[gljColMapping.code]) {
  382. continue;
  383. }
  384. let consumeAmt = isUnDef(rowData[gljColMapping.consumeAmtCol]) ? 0 : handleConsumeAmt(rowData[gljColMapping.consumeAmtCol]);
  385. gljList.push({
  386. name: rowData[gljColMapping.name],
  387. unit: rowData[gljColMapping.unit],
  388. code: rowData[gljColMapping.code],
  389. consumeAmt: consumeAmt,
  390. });
  391. }
  392. return gljList;
  393. }
  394. //拼接定额工料机数据
  395. for (let table of source.subTable) {
  396. let rationTable = table.subRation;
  397. if (!rationTable || rationTable.length === 0) {
  398. continue;
  399. }
  400. let lastRationCodes = rationTable.pop(); //定额子表,最后一行是末位定额编码
  401. for (let i = 0; i < lastRationCodes.length; i++) {
  402. let lastCode = lastRationCodes[i];
  403. //拼接定额编码
  404. let compleCode = `${basicCode}-${lastCode}`,
  405. gljList = getGljList(table.subGlj, i);
  406. if (!temp[compleCode]) { //该定额不存在
  407. temp[compleCode] = {
  408. code: compleCode,
  409. unit: basicUnit,
  410. name: basicName,
  411. gljList: gljList
  412. };
  413. } else { //该定额已存在,则追加工料机
  414. temp[compleCode].gljList = temp[compleCode].gljList.concat(gljList);
  415. }
  416. //拼接定额名称
  417. for (let rationNameRow of rationTable) {
  418. if (rationNameRow[i]) {
  419. temp[compleCode].name += ` ${rationNameRow[i]}`;
  420. }
  421. }
  422. }
  423. }
  424. //将temp对象转换为数据
  425. for (let code in temp) {
  426. target.push(temp[code]);
  427. }
  428. return target;
  429. }
  430. let transferData = [];
  431. for (let data of extractData) {
  432. let unitTargetData = transfer(data);
  433. transferData = transferData.concat(unitTargetData);
  434. }
  435. return transferData;
  436. }
  437. //导入Excel
  438. function exportToExcel(transferData, fileName) {
  439. $.bootstrapLoading.start();
  440. setTimeout(function () {
  441. if (exportSpread) {
  442. exportSpread.destroy();
  443. }
  444. exportSpread = new GC.Spread.Sheets.Workbook($exportSpread[0], {sheetCount: 1});
  445. let sheet = exportSpread.getSheet(0);
  446. sheet.suspendPaint();
  447. sheet.suspendEvent();
  448. //往表格填值
  449. let curRow = 0,
  450. fillCol = {
  451. code: 1,
  452. name: 2,
  453. unit: 3,
  454. consumeAmt: 4
  455. };
  456. function getRowCount() {
  457. let count = 0;
  458. for (let data of transferData) {
  459. count += 1 + data.gljList.length;
  460. }
  461. return count;
  462. }
  463. sheet.setRowCount(getRowCount());
  464. for (let data of transferData) {
  465. sheet.setValue(curRow, 0, '定额');
  466. sheet.setValue(curRow, fillCol.code, data.code);
  467. sheet.setValue(curRow, fillCol.name, data.name);
  468. sheet.setValue(curRow, fillCol.unit, data.unit);
  469. curRow++;
  470. for (let glj of data.gljList) {
  471. sheet.setValue(curRow, fillCol.code, glj.code);
  472. sheet.setValue(curRow, fillCol.name, glj.name);
  473. sheet.setValue(curRow, fillCol.unit, glj.unit);
  474. sheet.setValue(curRow, fillCol.consumeAmt, glj.consumeAmt);
  475. curRow++;
  476. }
  477. }
  478. sheet.resumeEvent();
  479. sheet.resumePaint();
  480. let json = exportSpread.toJSON();
  481. let excelIo = new GC.Spread.Excel.IO();
  482. excelIo.save(json, function(blob) {
  483. saveAs(blob, fileName);
  484. $.bootstrapLoading.end();
  485. $transferModal.modal('hide');
  486. }, function(e) {
  487. $.bootstrapLoading.end();
  488. $transferModal.modal('hide');
  489. console.log(e);
  490. });
  491. }, 200);
  492. }
  493. function eventListener() {
  494. $transferModal.on('hidden.bs.modal', function () {
  495. $file.val('');
  496. transferData = [];
  497. });
  498. //导入excel,提取并转换定额数据
  499. $file.change(function () {
  500. $transfer.addClass('disabled');
  501. let file = $(this)[0];
  502. let excelFile = file.files[0];
  503. if(excelFile) {
  504. let xlsReg = /xls$/g;
  505. if(excelFile.name && xlsReg.test(excelFile.name)){
  506. alert('请选择xlsx文件');
  507. $(this).val('');
  508. return;
  509. }
  510. $.bootstrapLoading.start();
  511. $('#loadingPage').css('z-index', '2000');
  512. //前端解析excel数据
  513. let excelIo = new GC.Spread.Excel.IO();
  514. let sDate = +new Date();
  515. excelIo.open(excelFile, function (json) {
  516. console.log(json);
  517. let extractData = extractDataFromExcel(json.sheets.Sheet1);
  518. transferData = transferDataFromExtract(extractData);
  519. console.log(`解析Excel文件时间:${+new Date() - sDate}`);
  520. $.bootstrapLoading.end();
  521. $transfer.removeClass('disabled');
  522. }, function (e) {
  523. $.bootstrapLoading.end();
  524. $transfer.removeClass('disabled');
  525. alert(e.errorMessage);
  526. });
  527. }
  528. });
  529. //确认转换,导出转换的Excel
  530. $transfer.click(function () {
  531. if (!transferData || transferData.length === 0) {
  532. //没有转换数据
  533. alert('没有转换数据');
  534. return;
  535. }
  536. let fileName = '转换数据.xlsx';
  537. if ($file[0].files && $file[0].files[0] && $file[0].files[0].name) {
  538. fileName = '转换数据' + $file[0].files[0].name;
  539. }
  540. exportToExcel(transferData, fileName);
  541. });
  542. }
  543. return {eventListener}
  544. })();
  545. $(function () {
  546. //TransferExcel.eventListener();
  547. let dispNameArr;
  548. let preDeleteId = null;
  549. let deleteCount = 0;
  550. let selCompilationId,
  551. compilationsArr = [];
  552. $('#del').on('hidden.bs.modal', function () {
  553. deleteCount = 0;
  554. });
  555. getAllRationLib(function (dispNames) {
  556. dispNameArr = dispNames;
  557. //添加
  558. $('#addBtn').click(function () {
  559. let compilationName = $('#compilationSels option:selected').text();
  560. let compilationId = $('#compilationSels option:selected').val();
  561. let gljLibName = $('#gljLibSels option:selected').text();
  562. let gljLibId = $('#gljLibSels option:selected').val();
  563. let libName = $('#libNameTxt').val();
  564. if(libName.trim().length === 0){
  565. alert('名称不可为空!');
  566. $('#libNameTxt').val('')
  567. }
  568. else if(dispNames.indexOf(libName) !== -1){
  569. alert('此定额库已存在!');
  570. $('#libNameTxt').val('')
  571. }
  572. else if(compilationName.trim().length === 0){
  573. alert('编办不可为空!');
  574. }
  575. else if(gljLibName.trim().length === 0){
  576. alert("请选择工料机库!");
  577. }
  578. else{
  579. let newRationLib = {};
  580. newRationLib.dispName = libName;
  581. newRationLib.compilationId = compilationId;
  582. newRationLib.compilationName = compilationName;
  583. newRationLib.gljLib = gljLibId;
  584. newRationLib.creator = userAccount;
  585. newRationLib.appType = "建筑";
  586. $('#libNameTxt').val('');
  587. createRationLib(newRationLib, dispNameArr);
  588. }
  589. });
  590. //重命名
  591. $("#showArea").on("click", "[data-target = '#edit']", function(){
  592. let renameId = $(this).parent().parent().attr("id");
  593. $('#renameText').val($(this).parent().parent().find('td:first-child').text());
  594. $("#renameA").attr("renameId", renameId);
  595. });
  596. $("#renameA").click(function(){
  597. let newName = $("#renameText").val();
  598. let libId = $(this).attr("renameId");
  599. let jqSel = "#" + libId + " td:first" + " a";
  600. let orgName = $(jqSel).text();
  601. if(newName.trim().length === 0){
  602. alert("名称不可为空!");
  603. $("#renameText").val('');
  604. }
  605. else if(dispNameArr.indexOf(newName) !== -1){
  606. alert("该定额库已存在!");
  607. $("#renameText").val('');
  608. }
  609. else{
  610. renameRationLib({ID: libId, newName: newName, orgName: orgName}, dispNameArr);
  611. }
  612. });
  613. $('#edit').on('shown.bs.modal', function () {
  614. setTimeout(function () {
  615. $('#renameText').focus();
  616. }, 100);
  617. });
  618. $('#add').on('shown.bs.modal', function () {
  619. setTimeout(function () {
  620. $('#libNameTxt').focus();
  621. }, 100);
  622. });
  623. $('#add').on('hidden.bs.modal', function () {
  624. $('#libNameTxt').val('');
  625. });
  626. //删除
  627. $("#showArea").on("click", "[data-target = '#del']", function(){
  628. let deleteId = $(this).parent().parent().attr("id");
  629. $("#deleteA").attr("deleteId", deleteId);
  630. let delLibName = $(`#${deleteId}`).find('td:first').text();
  631. $('#del').find('.modal-body h5').text(`准备删除 “${delLibName}”,会导致已引用此库的地方出错,确定要删除吗?`);
  632. });
  633. $("#deleteA").click(function(){
  634. let deleteId = $(this).attr("deleteId");
  635. if(preDeleteId && preDeleteId !== deleteId){
  636. deleteCount = 0;
  637. }
  638. preDeleteId = deleteId;
  639. deleteCount++;
  640. let jqSel = "#" + deleteId + " td:first" + " a";
  641. let libName = $(jqSel).text();
  642. if(deleteCount === 3){
  643. deleteCount = 0;
  644. removeRationLib({libId: deleteId, libName: libName}, dispNameArr);
  645. $('#del').modal('hide');
  646. }
  647. });
  648. //全部计算
  649. $("#showArea").on("click", "[data-target = '#reCalcAll']", function(){
  650. let recalcId = $(this).parent().parent().attr("id");
  651. $("#reCalcConfirm").attr("recalcId", recalcId);
  652. });
  653. $("#reCalcConfirm").click(function(){
  654. $('#reCalcConfirm').addClass('disabled');
  655. $.bootstrapLoading.start();
  656. let recalcId = $(this).attr("recalcId");
  657. CommonAjax.post('/rationRepository/api/reCalcAll', {rationRepId: recalcId}, function (rstData) {
  658. $.bootstrapLoading.end();
  659. $('#reCalcAll').modal('hide');
  660. $('#reCalcConfirm').removeClass('disabled');
  661. }, function () {
  662. $.bootstrapLoading.end();
  663. $('#reCalcAll').modal('hide');
  664. $('#reCalcConfirm').removeClass('disabled')
  665. });
  666. });
  667. });
  668. getCompilationList(function (data) {
  669. compilationsArr = data.compilation;
  670. });
  671. // 导入原始数据按钮
  672. let rationRepId = 0;
  673. $("#showArea").on("click", ".import-source", function () {
  674. let id = $(this).data("id");
  675. id = parseInt(id);
  676. if (isNaN(id) || id <= 0) {
  677. return false;
  678. }
  679. rationRepId = id;
  680. $("#import").modal("show");
  681. });
  682. // 导入内部数据
  683. $("#showArea").on("click", ".import-data", function () {
  684. let id = $(this).data("id");
  685. id = parseInt(id);
  686. if (isNaN(id) || id <= 0) {
  687. return false;
  688. }
  689. rationRepId = id;
  690. $("#import2").modal("show");
  691. });
  692. // 导入原始数据确认
  693. $("#source-import,#data-import").click(function() {
  694. $.bootstrapLoading.start();
  695. const self = $(this);
  696. const type = self.is("#source-import") ? 'source_file' : 'import_data';
  697. const dialog = type === 'source_file' ? $("#import") : $("#import2");
  698. try {
  699. let formData = new FormData();
  700. let file = $("input[name='"+ type +"']")[0];
  701. if (file.files.length <= 0) {
  702. throw '请选择文件!';
  703. }
  704. formData.append('file', file.files[0]);
  705. // 获取定额库id
  706. if (rationRepId <= 0) {
  707. return false;
  708. }
  709. formData.append('rationRepId', rationRepId);
  710. formData.append('type', type);
  711. $.ajax({
  712. url: '/rationRepository/api/upload',
  713. type: 'POST',
  714. data: formData,
  715. cache: false,
  716. contentType: false,
  717. processData: false,
  718. beforeSend: function() {
  719. self.attr('disabled', 'disabled');
  720. self.text('上传中...');
  721. },
  722. success: function(response){
  723. self.removeAttr('disabled');
  724. self.text('确定导入');
  725. if (response.err === 0) {
  726. $.bootstrapLoading.end();
  727. const message = response.msg !== undefined ? response.msg : '';
  728. if (message !== '') {
  729. alert(message);
  730. }
  731. // 成功则关闭窗体
  732. dialog.modal("hide");
  733. } else {
  734. $.bootstrapLoading.end();
  735. const message = response.msg !== undefined ? response.msg : '上传失败!';
  736. alert(message);
  737. }
  738. },
  739. error: function(){
  740. $.bootstrapLoading.end();
  741. alert("与服务器通信发生错误");
  742. self.removeAttr('disabled');
  743. self.text('确定导入');
  744. }
  745. });
  746. } catch(error) {
  747. alert(error);
  748. }
  749. });
  750. // 导出数据
  751. $("#showArea").on("click", ".export", function () {
  752. let id = $(this).data("id");
  753. id = parseInt(id);
  754. if (isNaN(id) || id <= 0) {
  755. return false;
  756. }
  757. window.location.href = '/rationRepository/api/export?rationRepId=' + id;
  758. });
  759. //设置补充定额库章节树模板
  760. $("#showArea").on("click", ".set-comple", function () {
  761. let id = $(this).data("id");
  762. id = parseInt(id);
  763. if (isNaN(id) || id <= 0) {
  764. return false;
  765. }
  766. rationRepId = id;
  767. $('#templateA').addClass('disabled');
  768. $('#template').modal('show');
  769. $('#compilations').empty();
  770. for (let data of compilationsArr) {
  771. let $opt = $(`<option value="${data._id}">${data.name}</option>`);
  772. $('#compilations').append($opt);
  773. }
  774. $('#compilations').change();
  775. });
  776. $('#compilations').change(function () {
  777. selCompilationId = $(this).select().val();
  778. CommonAjax.get(`api/sectionTemplateCount/${selCompilationId}`, function (rstData) {
  779. rstData.data.count > 0 ?
  780. $('#templateText').text('该费用定额下已有定额章节树模板数据,是否确认覆盖数据?') :
  781. $('#templateText').text('确认是否将此库的章节树设置成该费用定额下补充定额章节树模板?');
  782. $('#templateA').removeClass('disabled');
  783. });
  784. });
  785. $('#templateA').click(function () {
  786. if (rationRepId <= 0 && selCompilationId) {
  787. return false;
  788. }
  789. $.bootstrapLoading.start();
  790. CommonAjax.post('api/initSectionTemplate', {rationLibId: rationRepId, compilationId: selCompilationId}, function () {
  791. $.bootstrapLoading.end();
  792. $('#template').modal('hide');
  793. }, function () {
  794. $.bootstrapLoading.end();
  795. $('#template').modal('hide');
  796. });
  797. });
  798. });
  799. function getAllRationLib(callback){
  800. $.ajax({
  801. type: 'post',
  802. url: 'api/getRationDisplayNames',
  803. dataType: 'json',
  804. success: function (result) {
  805. let dispNames = [];
  806. if(result.data.length > 0){
  807. for(let i = 0; i < result.data.length; i++){
  808. storageUtil.setSessionCache("RationGrp","repositoryID_" + result.data[i].ID, result.data[i].dispName);
  809. if(result.data[i].gljLib){
  810. storageUtil.setSessionCache("gljLib","repositoryID_" + result.data[i].ID, result.data[i].gljLib);
  811. }
  812. let id = result.data[i].ID;
  813. let libName = result.data[i].dispName;
  814. let createDate = result.data[i].createDate.split(' ')[0];
  815. let compilationName = result.data[i].compilationName;
  816. dispNames.push(result.data[i].dispName);
  817. $("#showArea").append(
  818. "<tr id='"+id+"'>" +
  819. "<td><a href='/rationRepository/ration?repository=" + id +"'>"+libName+"</a></td>" +
  820. "<td>"+compilationName+" </td>" +
  821. "<td>"+createDate+" </td>" +
  822. "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
  823. "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
  824. "<i class='fa fa-remove'></i></a>" +
  825. " <a href='javascript:void(0);' data-toggle='modal' data-target='#reCalcAll' title='全部计算'><i class='fa fa-calculator'></i></a></td>"+
  826. "<td><a class='btn btn-secondary btn-sm import-source' href='javacript:void(0);' data-id='"+ id +"' title='导入原始数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
  827. "<td><a class='btn btn-success btn-sm export' href='javacript:void(0);' data-toggle='modal' data-id='"+ id +"' data-target='#emport' title='导出内部数据'><i class='fa fa-sign-out fa-rotate-270'></i>导出</a> " +
  828. "<a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入内部数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
  829. // "<td><a class='btn btn-secondary btn-sm transfer-excel' data-toggle='modal' data-target='#transfer' href='javacript:void(0);' data-id='"+ id +"' title='转换Excel'><i class='fa fa-sign-in fa-rotate-90'></i>转换</a></td>" +
  830. "<td><a class='btn btn-secondary btn-sm set-comple' href='javacript:void(0);' data-id='"+ id +"' title='将章节树设为补充模板数据'><i class='fa fa-sign-in fa-rotate-90'></i>设置</a></td>" +
  831. "</tr>");
  832. $("#tempId").attr("id", id);
  833. }
  834. }
  835. callback(dispNames);
  836. }
  837. });
  838. }
  839. function getCompilationList(callback){
  840. $.ajax({
  841. type: 'post',
  842. url: 'api/getCompilationList',
  843. dataType: 'json',
  844. success: function (result) {
  845. //addoptions
  846. for(let i = 0; i < result.data.compilation.length; i++){
  847. let $option = $("<option >"+ result.data.compilation[i].name +"</option>");
  848. $option.val( result.data.compilation[i]._id);
  849. $('#compilationSels').append($option);
  850. }
  851. //初始工料机库选项
  852. if(result.data.compilation.length > 0 && result.data.gljLibs.length > 0){
  853. let compilationId = result.data.compilation[0]._id;
  854. //console.log(compilationId);
  855. let gljLibOps = getGljLibOps(compilationId, result.data.gljLibs);
  856. for(let i = 0; i < gljLibOps.length; i++){
  857. let $option = $("<option >"+ gljLibOps[i].dispName +"</option>");
  858. $option.val(gljLibOps[i].ID);
  859. $('#gljLibSels').append($option);
  860. }
  861. }
  862. $('#compilationSels').on("change", function () {
  863. //刷新工料机库选项
  864. $('#gljLibSels').children().remove();
  865. let newGljLibOps = getGljLibOps(this.selectedOptions[0].value, result.data.gljLibs);
  866. for(let i = 0; i < newGljLibOps.length; i++){
  867. let $option = $("<option >"+ newGljLibOps[i].dispName +"</option>");
  868. $option.val(newGljLibOps[i].ID);
  869. $('#gljLibSels').append($option);
  870. }
  871. });
  872. callback(result.data);
  873. }
  874. });
  875. }
  876. function getGljLibOps(compilationId, gljLibs){
  877. let rst = [];
  878. for(let i = 0; i < gljLibs.length; i++){
  879. if(gljLibs[i]){
  880. if(compilationId === gljLibs[i].compilationId){
  881. rst.push(gljLibs[i]);
  882. }
  883. }
  884. }
  885. return rst;
  886. }
  887. function createRationLib(rationObj, dispNamesArr){
  888. $.ajax({
  889. type: 'post',
  890. url: 'api/addRationRepository',
  891. data: {rationRepObj: JSON.stringify(rationObj)},
  892. dataType: 'json',
  893. success: function (result) {
  894. if(result.data){
  895. storageUtil.setSessionCache("RationGrp","repositoryID_" + result.data.ID, result.data.dispName);
  896. if(result.data.gljLib){
  897. storageUtil.setSessionCache("gljLib","repositoryID_" + result.data.ID, result.data.gljLib);
  898. }
  899. let id = result.data.ID;
  900. let libName = result.data.dispName;
  901. let createDate = result.data.createDate.split(' ')[0];
  902. let compilationName = result.data.compilationName;
  903. dispNamesArr.push(libName);
  904. $("#showArea").append(
  905. "<tr id='"+id+"'>" +
  906. "<td><a href='/rationRepository/ration?repository=" + id +"'>"+libName+"</a></td>" +
  907. "<td>"+compilationName+" </td>" +
  908. "<td>"+createDate+" </td>" +
  909. "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
  910. "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
  911. "<i class='fa fa-remove'></i></a>" +
  912. " <a href='javascript:void(0);' data-toggle='modal' data-target='#reCalcAll' title='全部计算'><i class='fa fa-calculator'></i></a>"+
  913. "<td><a class='btn btn-secondary btn-sm import-source' href='javacript:void(0);' data-id='"+ id +"' title='导入原始数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
  914. "<td><a class='btn btn-success btn-sm export' href='javacript:void(0);' data-toggle='modal' data-id='"+ id +"' data-target='#emport' title='导出内部数据'><i class='fa fa-sign-out fa-rotate-270'></i>导出</a> " +
  915. "<a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入内部数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
  916. //"<td><a class='btn btn-secondary btn-sm transfer-excel' data-toggle='modal' data-target='#transfer' href='javacript:void(0);' data-id='"+ id +"' title='转换Excel'><i class='fa fa-sign-in fa-rotate-90'></i>转换</a></td>" +
  917. "<td><a class='btn btn-secondary btn-sm set-comple' href='javacript:void(0);' data-id='"+ id +"' title='将章节树设为补充模板数据'><i class='fa fa-sign-in fa-rotate-90'></i>设置</a></td>" +
  918. "</tr>");
  919. }
  920. $('#cancelBtn').click();
  921. }
  922. })
  923. }
  924. function renameRationLib(renameObj, dispNames){
  925. $.ajax({
  926. type: 'post',
  927. url: 'api/editRationLibs',
  928. data: {oprtor: userAccount, renameObj: JSON.stringify(renameObj)},
  929. dataType: 'json',
  930. success: function (result) {
  931. if(!result.error){
  932. let jqSel = "#" + renameObj.ID + " td:first" + " a";
  933. $(jqSel).text(renameObj.newName);
  934. let index = dispNames.indexOf(renameObj.orgName);
  935. dispNames.splice(index, 1);
  936. dispNames.splice(index, 0, renameObj.newName);
  937. }
  938. $('#editCancelBtn').click();
  939. $('#renameText').val('');
  940. }
  941. })
  942. }
  943. function removeRationLib(delObj, dispNames){
  944. $.bootstrapLoading.start();
  945. $.ajax({
  946. type: 'post',
  947. url: 'api/deleteRationLibs',
  948. data: {oprtor: userAccount, libId: delObj.libId},
  949. dataType: 'json',
  950. success: function (result) {
  951. if(!result.error){
  952. var jqSel = "#"+ delObj.libId;
  953. $(jqSel).remove();
  954. let index = dispNames.indexOf(delObj.libName);
  955. dispNames.splice(index, 1);
  956. $('#delCancelBtn').click();
  957. }
  958. $.bootstrapLoading.end();
  959. },
  960. error: function () {
  961. alert('删除失败');
  962. $.bootstrapLoading.end();
  963. }
  964. })
  965. }