ledger_controller.js 18 KB

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