ledger_controller.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  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. switch (data.postType) {
  153. case 'add':
  154. responseData.data = await ctx.service.ledger.addNode(ctx.tender.id, data.id);
  155. break;
  156. case 'delete':
  157. responseData.data = await ctx.service.ledger.deleteNode(ctx.tender.id, data.id);
  158. break;
  159. case 'up-move':
  160. responseData.data = await ctx.service.ledger.upMoveNode(ctx.tender.id, data.id);
  161. break;
  162. case 'down-move':
  163. responseData.data = await ctx.service.ledger.downMoveNode(ctx.tender.id, data.id);
  164. break;
  165. case 'up-level':
  166. responseData.data = await ctx.service.ledger.upLevelNode(ctx.tender.id, data.id);
  167. break;
  168. case 'down-level':
  169. responseData.data = await ctx.service.ledger.downLevelNode(ctx.tender.id, data.id);
  170. break;
  171. default:
  172. throw '未知操作';
  173. }
  174. } catch (err) {
  175. responseData.err = 1;
  176. responseData.msg = err;
  177. this.log(err);
  178. }
  179. ctx.body = responseData;
  180. }
  181. /**
  182. * 提交更新数据 (Ajax)
  183. * @param ctx
  184. * @return {Promise<void>}
  185. */
  186. async updateInfo(ctx) {
  187. const responseData = {
  188. err: 0,
  189. msg: '',
  190. data: [],
  191. };
  192. try {
  193. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  194. throw '标段数据错误';
  195. }
  196. const data = JSON.parse(ctx.request.body.data);
  197. if (data instanceof Array) {
  198. responseData.data = await ctx.service.ledger.updateInfos(ctx.tender.id, data);
  199. } else {
  200. responseData.data = await ctx.service.ledger.updateInfo(ctx.tender.id, data);
  201. }
  202. } catch (err) {
  203. responseData.err = 1;
  204. responseData.msg = err;
  205. }
  206. ctx.body = responseData;
  207. }
  208. async update(ctx) {
  209. const responseData = {
  210. err: 0,
  211. msg: '',
  212. data: [],
  213. };
  214. try {
  215. const tenderId = parseInt(ctx.params.id);
  216. if (!tenderId) {
  217. throw '当前未打开标段';
  218. }
  219. const tenderData = await ctx.service.tender.getDataById(tenderId);
  220. if (!tenderData || tenderData.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly(tenderData)) {
  221. throw '标段数据错误';
  222. }
  223. const data = JSON.parse(ctx.request.body.data);
  224. responseData.data = await ctx.service.ledger.updateCalc(ctx.tender.id, data);
  225. } catch (err) {
  226. this.log(err);
  227. responseData.err = 1;
  228. responseData.msg = err;
  229. }
  230. ctx.body = responseData;
  231. }
  232. /**
  233. * 复制粘贴整块 (Ajax)
  234. *
  235. * @param ctx
  236. * @return {Promise<void>}
  237. */
  238. async pasteBlock(ctx) {
  239. const responseData = {
  240. err: 0,
  241. msg: '',
  242. data: [],
  243. };
  244. try {
  245. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  246. throw '标段数据错误';
  247. }
  248. const data = JSON.parse(ctx.request.body.data);
  249. if ((isNaN(data.id) || data.id <= 0) || (!data.block || data.block.length <= 0)) {
  250. throw '参数错误';
  251. }
  252. responseData.data = await ctx.service.ledger.pasteBlock(ctx.tender.id, data.id, data.block);
  253. } catch (err) {
  254. responseData.err = 1;
  255. responseData.msg = err;
  256. }
  257. ctx.body = responseData;
  258. }
  259. /**
  260. * 从标准项目表添加数据 (Ajax)
  261. * @param ctx
  262. * @returns {Promise<void>}
  263. */
  264. async addFromStandardLib(ctx) {
  265. const responseData = {
  266. err: 0,
  267. msg: '',
  268. data: [],
  269. };
  270. try {
  271. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  272. throw '标段数据错误';
  273. }
  274. const data = JSON.parse(ctx.request.body.data);
  275. if ((isNaN(data.id) || data.id <= 0) || !data.stdType || !data.stdNode) {
  276. throw '参数错误';
  277. }
  278. //todo 校验项目是否使用该库的权限
  279. let stdLib;
  280. switch (data.stdType) {
  281. case 'chapter':
  282. stdLib = ctx.service.stdChapter;
  283. break;
  284. case 'bills':
  285. stdLib = ctx.service.stdBills;
  286. break;
  287. default:
  288. throw '未知标准库';
  289. }
  290. const stdData = await stdLib.getDataByDataId(data.stdLibId, data.stdNode);
  291. const addType = stdDataAddType.withParent;
  292. switch (addType) {
  293. case stdDataAddType.self:
  294. responseData.data = await ctx.service.ledger.addStdNode(ctx.tender.id, data.id, stdData);
  295. break;
  296. case stdDataAddType.withParent:
  297. responseData.data = await ctx.service.ledger.addStdNodeWithParent(ctx.tender.id, stdData, stdLib);
  298. break;
  299. default:
  300. throw '未知添加方法';
  301. }
  302. } catch (err) {
  303. responseData.err = 1;
  304. responseData.msg = err;
  305. }
  306. ctx.body = responseData;
  307. }
  308. /**
  309. * 批量插入数据 (Ajax)
  310. *
  311. * data = {id, batchData, batchType}
  312. * data.batchType = 'batchInsertChild'/'batchInsertNext'
  313. * data.batchData = [{name, children}] -- 项目节列表
  314. * data.batchData.children = [{code, name, unit, unit_price, quantity}] -- 工程量清单列表
  315. *
  316. * @param ctx
  317. * @returns {Promise<void>}
  318. */
  319. async batchInsert(ctx) {
  320. const responseData = {
  321. err: 0,
  322. msg: '',
  323. data: [],
  324. };
  325. try {
  326. if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) {
  327. throw '标段数据错误';
  328. }
  329. const data = JSON.parse(ctx.request.body.data);
  330. if ((isNaN(data.id) || data.id <= 0) || !data.batchType) {
  331. throw '参数错误';
  332. }
  333. switch (data.batchType) {
  334. case 'child':
  335. responseData.data = await ctx.service.ledger.batchInsertChild(ctx.tender.id, data.id, data.batchData);
  336. break;
  337. case 'next':
  338. responseData.data = await ctx.service.ledger.batchInsertNext(ctx.tender.id, data.id, data.batchData);
  339. break;
  340. default:
  341. throw '参数错误';
  342. }
  343. } catch (err) {
  344. this.log(err);
  345. responseData.err = 1;
  346. responseData.msg = err;
  347. }
  348. ctx.body = responseData;
  349. }
  350. /**
  351. * 查询
  352. *
  353. * @param ctx
  354. * @returns {Promise<void>}
  355. */
  356. async search(ctx) {
  357. const responseData = {
  358. err: 0,
  359. msg: '',
  360. data: [],
  361. };
  362. try {
  363. const tenderId = ctx.params.id;
  364. if (!tenderId) {
  365. throw '当前未打开标段';
  366. }
  367. const data = JSON.parse(ctx.request.body.data);
  368. if (!data.keyword || data.keyword === '') {
  369. throw '参数错误';
  370. }
  371. responseData.data = await ctx.service.ledger.search(tenderId, {
  372. value: ctx.app.mysql.escape('%' + data.keyword + '%'),
  373. operate: 'Like',
  374. fields: ['code', 'b_code', 'name'],
  375. });
  376. } catch (err) {
  377. this.log(err);
  378. responseData.err = 1;
  379. responseData.msg = err;
  380. }
  381. ctx.body = responseData;
  382. }
  383. /**
  384. * 定位
  385. * @param ctx
  386. * @returns {Promise<void>}
  387. */
  388. async locate(ctx) {
  389. const responseData = {
  390. err: 0,
  391. msg: '',
  392. data: [],
  393. };
  394. try {
  395. const tenderId = ctx.params.id;
  396. if (!tenderId) {
  397. throw '当前未打开标段';
  398. }
  399. const data = JSON.parse(ctx.request.body.data);
  400. if ((isNaN(data.id) || data.id <= 0)) {
  401. throw '参数错误';
  402. }
  403. responseData.data = await ctx.service.ledger.locateNode(tenderId, data.id);
  404. } catch (err) {
  405. this.log(err);
  406. responseData.err = 1;
  407. responseData.msg = err;
  408. }
  409. ctx.body = responseData;
  410. }
  411. /**
  412. * 获取全部子节点
  413. *
  414. * @param ctx
  415. * @returns {Promise<void>}
  416. */
  417. async posterity(ctx) {
  418. const responseData = {
  419. err: 0,
  420. msg: '',
  421. data: [],
  422. };
  423. try {
  424. const tenderId = ctx.params.id;
  425. if (!tenderId) {
  426. throw '当前未打开标段';
  427. }
  428. const data = JSON.parse(ctx.request.body.data);
  429. if ((isNaN(data.id) || data.id <= 0)) {
  430. throw '参数错误';
  431. }
  432. const expandData = await ctx.service.ledger.getPosterityByParentId(tenderId, data.id);
  433. responseData.data = { expand: expandData };
  434. } catch (err) {
  435. this.log(err);
  436. responseData.err = 1;
  437. responseData.msg = err;
  438. }
  439. ctx.body = responseData;
  440. }
  441. /**
  442. * 获取部位明细数据(Ajax)
  443. *
  444. * @param ctx
  445. * @returns {Promise<void>}
  446. */
  447. async pos(ctx) {
  448. try {
  449. await this.checkMeasureType(measureType.tz.value);
  450. const condition = JSON.parse(ctx.request.body.data) || {};
  451. condition.tid = ctx.tender.id;
  452. const posData = await ctx.service.pos.getPosData(condition);
  453. ctx.body = {err: 0, msg: '', data: posData};
  454. } catch (err) {
  455. this.log(err);
  456. ctx.body = {err: 1, msg: err.toString(), data: []};
  457. }
  458. }
  459. /**
  460. * 更新部位明细数据
  461. *
  462. * @param ctx
  463. * @returns {Promise<void>}
  464. */
  465. async posUpdate(ctx) {
  466. try {
  467. await this.checkMeasureType(measureType.tz.value);
  468. const data = JSON.parse(ctx.request.body.data);
  469. const responseData = await ctx.service.pos.savePosData(data, ctx.tender.id);
  470. ctx.body = { err: 0, msg: '', data: responseData };
  471. } catch(err) {
  472. this.log(err);
  473. ctx.body = { err: 1, msg: err.toString(), data: null };
  474. }
  475. }
  476. /**
  477. * 台账变更页面 (Get)
  478. *
  479. * @param {object} ctx - egg全局变量
  480. * @return {void}
  481. */
  482. async change(ctx) {
  483. try {
  484. const renderData = {
  485. tender: ctx.tender.data,
  486. tenderMenu: this.menu.tenderMenu,
  487. preUrl: '/tender/' + ctx.tender.id,
  488. };
  489. await this.layout('ledger/change.ejs', renderData, 'ledger/change_modal.ejs');
  490. } catch(err) {
  491. this.log(err);
  492. ctx.redirect(ctx.request.header.referer);
  493. }
  494. }
  495. /**
  496. * 计量台账页面 (Get)
  497. *
  498. * @param {object} ctx - egg全局变量
  499. * @return {void}
  500. */
  501. async index(ctx) {
  502. const renderData = {};
  503. await this.layout('ledger/index.ejs', renderData);
  504. }
  505. }
  506. return LedgerController;
  507. };