ledger_controller.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. 'use strict';
  2. /**
  3. * 台账相关控制器
  4. *
  5. * @author CaiAoLin
  6. * @date 2017/11/30
  7. * @version
  8. */
  9. const stdDataAddType = {
  10. self: 1,
  11. withParent: 2
  12. }
  13. const auditConst = require('../const/audit').flow;
  14. const tenderMenu = require('../../config/menu').tenderMenu;
  15. const measureType = require('../const/tender').measureType;
  16. const spreadConst = require('../const/spread');
  17. module.exports = app => {
  18. class LedgerController extends app.BaseController {
  19. /**
  20. * 构造函数
  21. *
  22. * @param {Object} ctx - egg全局变量
  23. * @return {void}
  24. */
  25. constructor(ctx) {
  26. super(ctx);
  27. ctx.showProject = true;
  28. ctx.showTitle = true;
  29. ctx.showTender = true;
  30. }
  31. /**
  32. * 检查标段是否只读(审核中,审核完成)
  33. * @param {Object} tenderData
  34. * @returns {boolean}
  35. * @private
  36. */
  37. _ledgerReadOnly () {
  38. const tender = this.ctx.tender.data;
  39. return tender.ledger_status === auditConst.status.checking || tender.ledger_status === auditConst.status.checked;
  40. }
  41. /**
  42. * 获取SpreadSetting
  43. * @private
  44. */
  45. _getSpreadSetting() {
  46. const _ = this.app._;
  47. function removeFieldCols(setting, cols) {
  48. _.remove(setting.cols, function (c) {
  49. return cols.indexOf(c.field) > -1;
  50. });
  51. }
  52. const ledger = JSON.parse(JSON.stringify(spreadConst.ledgerSpread));
  53. const pos = JSON.parse(JSON.stringify(spreadConst.ledgerPosSpread));
  54. const tender = this.ctx.tender;
  55. if (this._ledgerReadOnly(tender.data)) {
  56. ledger.readOnly = true;
  57. pos.readOnly = true;
  58. }
  59. if (tender.data.measure_type === measureType.tz.value) {
  60. removeFieldCols(ledger, spreadConst.filterCols.tzWithoutCols);
  61. }
  62. if (!tender.info.display.ledger.dgnQty) {
  63. removeFieldCols(ledger, spreadConst.filterCols.dgnCols);
  64. }
  65. return [ledger, pos];
  66. }
  67. /**
  68. * 台账分解页面 (Get)
  69. *
  70. * @param {Object} ctx - egg全局变量
  71. * @return {void}
  72. */
  73. async explode(ctx) {
  74. try {
  75. const tender = ctx.tender;
  76. const [ledgerSpread, posSpread] = this._getSpreadSetting();
  77. const curAuditor = await ctx.service.ledgerAudit.getCurAuditor(tender.id, tender.data.ledger_times);
  78. const times = tender.data.ledger_status === auditConst.status.checkNo ? tender.data.ledger_times - 1 : tender.data.ledger_times;
  79. const auditors = await ctx.service.ledgerAudit.getAuditors(tender.id, times);
  80. const content = auditors.length > 0 ? await ctx.service.ledgerAuditContent.getAllDataByCondition({
  81. where: {tender_id: tender.id, times: times, audit_id: auditors[0].audit_id}
  82. }) : null;
  83. const ledgerData = await ctx.service.ledger.getDataByTenderId(tender.id, -1);
  84. const user = await ctx.service.projectAccount.getAccountInfoById(ctx.tender.data.user_id);
  85. const auditHistory = [];
  86. if (ctx.tender.data.ledger_times > 1) {
  87. for (let i = 1; i < ctx.tender.data.ledger_times; i++) {
  88. auditHistory.push(await ctx.service.ledgerAudit.getAuditors(ctx.tender.id, i));
  89. }
  90. }
  91. const renderData = {
  92. tender: tender.data,
  93. tenderInfo: tender.info,
  94. auditConst,
  95. auditors,
  96. curAuditor,
  97. user,
  98. auditHistory,
  99. content,
  100. ledger: JSON.stringify(ledgerData),
  101. ledgerSpreadSetting: JSON.stringify(ledgerSpread),
  102. posSpreadSetting: JSON.stringify(posSpread),
  103. tenderMenu,
  104. preUrl: '/tender/' + tender.id,
  105. measureType,
  106. };
  107. await this.layout('ledger/explode.ejs', renderData, 'ledger/explode_modal.ejs');
  108. } catch (err) {
  109. this.log(err);
  110. await this.layout('/dashboard');
  111. }
  112. }
  113. /**
  114. * 获取子节点 (Ajax)
  115. * @param ctx
  116. * @return {Promise<void>}
  117. */
  118. async getChildren(ctx) {
  119. const responseData = {
  120. err: 0,
  121. msg: '',
  122. data: [],
  123. };
  124. try {
  125. const data = JSON.parse(ctx.request.body.data);
  126. const id = data.ledger_id;
  127. if (isNaN(id) || id <= 0) {
  128. throw '参数错误';
  129. }
  130. responseData.data = await ctx.service.ledger.getChildrenByParentId(ctx.tender.id, id);
  131. } catch (err) {
  132. responseData.err = 1;
  133. responseData.msg = err;
  134. }
  135. ctx.body = responseData;
  136. }
  137. /**
  138. * 树结构基本操作(增、删、上下移、升降级)(Ajax)
  139. * @param {Object} ctx - egg全局变量
  140. * @return {Promise<void>}
  141. */
  142. async baseOperation(ctx) {
  143. const responseData = {
  144. err: 0,
  145. msg: '',
  146. data: [],
  147. };
  148. try {
  149. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  150. throw '标段数据错误';
  151. }
  152. const data = JSON.parse(ctx.request.body.data);
  153. switch (data.postType) {
  154. case 'add':
  155. responseData.data = await ctx.service.ledger.addNode(ctx.tender.id, data.id);
  156. break;
  157. case 'delete':
  158. responseData.data = await ctx.service.ledger.deleteNode(ctx.tender.id, data.id);
  159. break;
  160. case 'up-move':
  161. responseData.data = await ctx.service.ledger.upMoveNode(ctx.tender.id, data.id);
  162. break;
  163. case 'down-move':
  164. responseData.data = await ctx.service.ledger.downMoveNode(ctx.tender.id, data.id);
  165. break;
  166. case 'up-level':
  167. responseData.data = await ctx.service.ledger.upLevelNode(ctx.tender.id, data.id);
  168. break;
  169. case 'down-level':
  170. responseData.data = await ctx.service.ledger.downLevelNode(ctx.tender.id, data.id);
  171. break;
  172. default:
  173. throw '未知操作';
  174. }
  175. } catch (err) {
  176. responseData.err = 1;
  177. responseData.msg = err;
  178. this.log(err);
  179. }
  180. ctx.body = responseData;
  181. }
  182. /**
  183. * 提交更新数据 (Ajax)
  184. * @param ctx
  185. * @return {Promise<void>}
  186. */
  187. async updateInfo(ctx) {
  188. const responseData = {
  189. err: 0,
  190. msg: '',
  191. data: [],
  192. };
  193. try {
  194. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  195. throw '标段数据错误';
  196. }
  197. const data = JSON.parse(ctx.request.body.data);
  198. if (data instanceof Array) {
  199. responseData.data = await ctx.service.ledger.updateInfos(ctx.tender.id, data);
  200. } else {
  201. responseData.data = await ctx.service.ledger.updateInfo(ctx.tender.id, data);
  202. }
  203. } catch (err) {
  204. responseData.err = 1;
  205. responseData.msg = err;
  206. }
  207. ctx.body = responseData;
  208. }
  209. async update(ctx) {
  210. const responseData = {
  211. err: 0,
  212. msg: '',
  213. data: [],
  214. };
  215. try {
  216. const tenderId = parseInt(ctx.params.id);
  217. if (!tenderId) {
  218. throw '当前未打开标段';
  219. }
  220. const tenderData = await ctx.service.tender.getDataById(tenderId);
  221. if (!tenderData || tenderData.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly(tenderData)) {
  222. throw '标段数据错误';
  223. }
  224. const data = JSON.parse(ctx.request.body.data);
  225. responseData.data = await ctx.service.ledger.updateCalc(ctx.tender.id, data);
  226. console.log(responseData.data);
  227. } catch (err) {
  228. this.log(err);
  229. responseData.err = 1;
  230. responseData.msg = err;
  231. }
  232. ctx.body = responseData;
  233. }
  234. /**
  235. * 复制粘贴整块 (Ajax)
  236. *
  237. * @param ctx
  238. * @return {Promise<void>}
  239. */
  240. async pasteBlock(ctx) {
  241. const responseData = {
  242. err: 0,
  243. msg: '',
  244. data: [],
  245. };
  246. try {
  247. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  248. throw '标段数据错误';
  249. }
  250. const data = JSON.parse(ctx.request.body.data);
  251. if ((isNaN(data.id) || data.id <= 0) || (!data.block || data.block.length <= 0)) {
  252. throw '参数错误';
  253. }
  254. responseData.data = await ctx.service.ledger.pasteBlock(ctx.tender.id, data.id, data.block);
  255. } catch (err) {
  256. responseData.err = 1;
  257. responseData.msg = err;
  258. }
  259. ctx.body = responseData;
  260. }
  261. /**
  262. * 从标准项目表添加数据 (Ajax)
  263. * @param ctx
  264. * @returns {Promise<void>}
  265. */
  266. async addFromStandardLib(ctx) {
  267. const responseData = {
  268. err: 0,
  269. msg: '',
  270. data: [],
  271. };
  272. try {
  273. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  274. throw '标段数据错误';
  275. }
  276. const data = JSON.parse(ctx.request.body.data);
  277. if ((isNaN(data.id) || data.id <= 0) || !data.stdType || !data.stdNode) {
  278. throw '参数错误';
  279. }
  280. //todo 校验项目是否使用该库的权限
  281. let stdLib;
  282. switch (data.stdType) {
  283. case 'chapter':
  284. stdLib = ctx.service.stdChapter;
  285. break;
  286. case 'bills':
  287. stdLib = ctx.service.stdBills;
  288. break;
  289. default:
  290. throw '未知标准库';
  291. }
  292. const stdData = await stdLib.getDataByDataId(data.stdLibId, data.stdNode);
  293. const addType = stdDataAddType.withParent;
  294. switch (addType) {
  295. case stdDataAddType.self:
  296. responseData.data = await ctx.service.ledger.addStdNode(ctx.tender.id, data.id, stdData);
  297. break;
  298. case stdDataAddType.withParent:
  299. responseData.data = await ctx.service.ledger.addStdNodeWithParent(ctx.tender.id, stdData, stdLib);
  300. break;
  301. default:
  302. throw '未知添加方法';
  303. }
  304. } catch (err) {
  305. responseData.err = 1;
  306. responseData.msg = err;
  307. }
  308. ctx.body = responseData;
  309. }
  310. /**
  311. * 批量插入数据 (Ajax)
  312. *
  313. * data = {id, batchData, batchType}
  314. * data.batchType = 'batchInsertChild'/'batchInsertNext'
  315. * data.batchData = [{name, children}] -- 项目节列表
  316. * data.batchData.children = [{code, name, unit, unit_price, quantity}] -- 工程量清单列表
  317. *
  318. * @param ctx
  319. * @returns {Promise<void>}
  320. */
  321. async batchInsert(ctx) {
  322. const responseData = {
  323. err: 0,
  324. msg: '',
  325. data: [],
  326. };
  327. try {
  328. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  329. throw '标段数据错误';
  330. }
  331. const data = JSON.parse(ctx.request.body.data);
  332. if ((isNaN(data.id) || data.id <= 0) || !data.batchType) {
  333. throw '参数错误';
  334. }
  335. switch (data.batchType) {
  336. case 'child':
  337. responseData.data = await ctx.service.ledger.batchInsertChild(ctx.tender.id, data.id, data.batchData);
  338. break;
  339. case 'next':
  340. responseData.data = await ctx.service.ledger.batchInsertNext(ctx.tender.id, data.id, data.batchData);
  341. break;
  342. default:
  343. throw '参数错误';
  344. }
  345. } catch (err) {
  346. this.log(err);
  347. responseData.err = 1;
  348. responseData.msg = err;
  349. }
  350. ctx.body = responseData;
  351. }
  352. /**
  353. * 查询
  354. *
  355. * @param ctx
  356. * @returns {Promise<void>}
  357. */
  358. async search(ctx) {
  359. const responseData = {
  360. err: 0,
  361. msg: '',
  362. data: [],
  363. };
  364. try {
  365. const tenderId = ctx.params.id;
  366. if (!tenderId) {
  367. throw '当前未打开标段';
  368. }
  369. const data = JSON.parse(ctx.request.body.data);
  370. if (!data.keyword || data.keyword === '') {
  371. throw '参数错误';
  372. }
  373. responseData.data = await ctx.service.ledger.search(tenderId, {
  374. value: ctx.app.mysql.escape('%' + data.keyword + '%'),
  375. operate: 'Like',
  376. fields: ['code', 'b_code', 'name'],
  377. });
  378. } catch (err) {
  379. this.log(err);
  380. responseData.err = 1;
  381. responseData.msg = err;
  382. }
  383. ctx.body = responseData;
  384. }
  385. /**
  386. * 定位
  387. * @param ctx
  388. * @returns {Promise<void>}
  389. */
  390. async locate(ctx) {
  391. const responseData = {
  392. err: 0,
  393. msg: '',
  394. data: [],
  395. };
  396. try {
  397. const tenderId = ctx.params.id;
  398. if (!tenderId) {
  399. throw '当前未打开标段';
  400. }
  401. const data = JSON.parse(ctx.request.body.data);
  402. if ((isNaN(data.id) || data.id <= 0)) {
  403. throw '参数错误';
  404. }
  405. responseData.data = await ctx.service.ledger.locateNode(tenderId, data.id);
  406. } catch (err) {
  407. this.log(err);
  408. responseData.err = 1;
  409. responseData.msg = err;
  410. }
  411. ctx.body = responseData;
  412. }
  413. /**
  414. * 获取全部子节点
  415. *
  416. * @param ctx
  417. * @returns {Promise<void>}
  418. */
  419. async posterity(ctx) {
  420. const responseData = {
  421. err: 0,
  422. msg: '',
  423. data: [],
  424. };
  425. try {
  426. const tenderId = ctx.params.id;
  427. if (!tenderId) {
  428. throw '当前未打开标段';
  429. }
  430. const data = JSON.parse(ctx.request.body.data);
  431. if ((isNaN(data.id) || data.id <= 0)) {
  432. throw '参数错误';
  433. }
  434. const expandData = await ctx.service.ledger.getPosterityByParentId(tenderId, data.id);
  435. responseData.data = { expand: expandData };
  436. } catch (err) {
  437. this.log(err);
  438. responseData.err = 1;
  439. responseData.msg = err;
  440. }
  441. ctx.body = responseData;
  442. }
  443. /**
  444. * 获取部位明细数据(Ajax)
  445. *
  446. * @param ctx
  447. * @returns {Promise<void>}
  448. */
  449. async pos(ctx) {
  450. try {
  451. await this.checkMeasureType(measureType.tz.value);
  452. const condition = JSON.parse(ctx.request.body.data) || {};
  453. condition.tid = ctx.tender.id;
  454. const posData = await ctx.service.pos.getPosData(condition);
  455. ctx.body = {err: 0, msg: '', data: posData};
  456. } catch (err) {
  457. this.log(err);
  458. ctx.body = {err: 1, msg: err.toString(), data: []};
  459. }
  460. }
  461. /**
  462. * 更新部位明细数据
  463. *
  464. * @param ctx
  465. * @returns {Promise<void>}
  466. */
  467. async posUpdate(ctx) {
  468. try {
  469. await this.checkMeasureType(measureType.tz.value);
  470. const data = JSON.parse(ctx.request.body.data);
  471. const responseData = await ctx.service.pos.savePosData(data, ctx.tender.id);
  472. ctx.body = { err: 0, msg: '', data: responseData };
  473. } catch(err) {
  474. this.log(err);
  475. ctx.body = { err: 1, msg: err.toString(), data: null };
  476. }
  477. }
  478. /**
  479. * 台账变更页面 (Get)
  480. *
  481. * @param {object} ctx - egg全局变量
  482. * @return {void}
  483. */
  484. async change(ctx) {
  485. try {
  486. const renderData = {
  487. tender: ctx.tender.data,
  488. tenderMenu: this.menu.tenderMenu,
  489. preUrl: '/tender/' + ctx.tender.id,
  490. };
  491. await this.layout('ledger/change.ejs', renderData, 'ledger/change_modal.ejs');
  492. } catch(err) {
  493. this.log(err);
  494. ctx.redirect(ctx.request.header.referer);
  495. }
  496. }
  497. /**
  498. * 计量台账页面 (Get)
  499. *
  500. * @param {object} ctx - egg全局变量
  501. * @return {void}
  502. */
  503. async index(ctx) {
  504. const renderData = {};
  505. await this.layout('ledger/index.ejs', renderData);
  506. }
  507. }
  508. return LedgerController;
  509. };