weapp_tender_controller.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. 'use strict';
  2. const auditConst = require('../const/audit');
  3. const measureType = require('../const/tender').measureType;
  4. const advanceConst = require('../const/advance');
  5. const shenpiConst = require('../const/shenpi');
  6. const stdConst = require('../const/standard');
  7. const _ = require('lodash');
  8. module.exports = app => {
  9. class WeappTenderController extends app.BaseController {
  10. async listManage(ctx) {
  11. try {
  12. const projectId = ctx.query.projectId;
  13. if (!projectId) {
  14. ctx.body = { err: 1, msg: '缺少projectId参数', data: null };
  15. return;
  16. }
  17. const accountInfo = ctx.session.sessionUser;
  18. const userPermission = accountInfo !== undefined && accountInfo.permission !== '' ? JSON.parse(accountInfo.permission) : null;
  19. if (userPermission !== null && userPermission.tender !== undefined && userPermission.tender.indexOf('1') !== -1) {
  20. const subProject = await this.ctx.service.subProject.getDataById(projectId);
  21. const tenderList = await this.ctx.service.tender.getList('', userPermission, ctx.session.sessionUser.is_admin, '', subProject);
  22. for (const tender of tenderList) {
  23. // 查询当前审批期以及状态
  24. const stage = await this.ctx.service.stage.getLastestStage(tender.id, true);
  25. tender.stage_order = stage && stage.order ? stage.order : null;
  26. tender.stage_status = stage && stage.status ? stage.status : null;
  27. }
  28. const categoryData = await this.ctx.service.category.getAllCategory(subProject);
  29. const renderData = {
  30. categoryData,
  31. tenderList,
  32. };
  33. ctx.body = { err: 0, msg: '', data: renderData };
  34. } else {
  35. ctx.body = { err: 1, msg: '您没有管理权限', data: null };
  36. }
  37. } catch (err) {
  38. this.log(err);
  39. ctx.body = { err: 1, msg: err.toString(), data: null };
  40. }
  41. }
  42. async detail(ctx) {
  43. try {
  44. const tender = ctx.tender.data;
  45. let bCalcTp = ctx.tender.data.user_id === ctx.session.sessionUser.accountId && (
  46. ctx.tender.ledger_status === auditConst.ledger.status.checkNo || ctx.tender.ledger_status === auditConst.ledger.status.uncheck);
  47. const stages = await ctx.service.stage.getValidStages(ctx.tender.id);
  48. const lastStage = stages.length > 0 ? stages[0] : null; // await ctx.service.stage.getLastestStage(ctx.tender.id);
  49. const [change_tp, change_p_tp, change_n_tp, change_valuation_tp, change_unvaluation_tp] = await ctx.service.change.getChangeTp(ctx.tender.id);
  50. tender.change_tp = change_tp;
  51. tender.change_p_tp = change_p_tp;
  52. tender.change_n_tp = change_n_tp;
  53. tender.change_valuation_tp = change_valuation_tp;
  54. tender.change_unvaluation_tp = change_unvaluation_tp;
  55. if (lastStage) {
  56. await this.ctx.service.stage.checkStageGatherData(lastStage, ctx.session.sessionUser.is_admin);
  57. if ((!bCalcTp) && tender.measure_type === measureType.gcl.value) {
  58. bCalcTp = lastStage.status !== auditConst.stage.status.checked && !lastStage.readOnly;
  59. }
  60. if (bCalcTp) {
  61. const sum = await this.ctx.service.ledger.addUp({ tender_id: ctx.tender.id/* , is_leaf: true*/ });
  62. tender.total_price = sum.total_price;
  63. tender.deal_tp = sum.deal_tp;
  64. }
  65. tender.sum = ctx.tender.info.calc_type === 'tp' ? ctx.helper.add(tender.total_price, tender.change_valuation_tp) : ctx.helper.add(tender.total_price, tender.change_tp);
  66. tender.gather_tp = ctx.helper.sum([lastStage.contract_tp, lastStage.qc_tp, lastStage.pc_tp]);
  67. tender.end_contract_tp = ctx.helper.sum([lastStage.contract_tp, lastStage.pre_contract_tp, lastStage.contract_pc_tp]);
  68. tender.end_qc_tp = ctx.helper.sum([lastStage.qc_tp, lastStage.pre_qc_tp, lastStage.qc_pc_tp]);
  69. tender.end_positive_qc_tp = ctx.helper.sum([lastStage.positive_qc_tp, lastStage.pre_positive_qc_tp, lastStage.positive_qc_pc_tp]);
  70. tender.end_negative_qc_tp = ctx.helper.sum([lastStage.negative_qc_tp, lastStage.pre_negative_qc_tp, lastStage.negative_qc_pc_tp]);
  71. tender.end_gather_tp = ctx.helper.add(tender.end_contract_tp, tender.end_qc_tp);
  72. tender.pre_gather_tp = ctx.helper.add(lastStage.pre_contract_tp, lastStage.pre_qc_tp);
  73. tender.yf_tp = lastStage.yf_tp;
  74. tender.sf_tp = lastStage.sf_tp;
  75. tender.qc_ratio = ctx.helper.mul(ctx.helper.div(tender.end_qc_tp, ctx.tender.info.deal_param.contractPrice, 2), 100);
  76. tender.pre_ratio = ctx.helper.mul(ctx.helper.div(tender.pre_gather_tp, tender.sum, 2), 100);
  77. tender.cur_ratio = ctx.helper.mul(ctx.helper.div(tender.gather_tp, tender.sum, 2), 100);
  78. tender.other_tp = ctx.helper.sub(ctx.helper.sub(tender.sum, tender.pre_gather_tp), tender.gather_tp);
  79. tender.other_ratio = Math.max(0, 100 - tender.pre_ratio - tender.cur_ratio);
  80. tender.end_yf_tp = ctx.helper.add(lastStage.yf_tp, lastStage.pre_yf_tp);
  81. tender.end_sf_tp = ctx.helper.add(lastStage.sf_tp, lastStage.pre_sf_tp);
  82. tender.undone_tp = ctx.helper.sub(ctx.helper.sub(ctx.helper.add(tender.total_price, change_tp), tender.end_contract_tp), tender.end_qc_tp);
  83. } else {
  84. if (bCalcTp) {
  85. const sum = await this.ctx.service.ledger.addUp({ tender_id: ctx.tender.id/* , is_leaf: true*/ });
  86. tender.total_price = sum.total_price;
  87. tender.deal_tp = sum.deal_tp;
  88. }
  89. tender.sum = ctx.helper.add(tender.total_price, tender.change_tp);
  90. }
  91. // const monthProgress = [];
  92. // for (const s of stages) {
  93. // if (s.s_time) {
  94. // let progress = monthProgress.find(function(x) {
  95. // return x.month === s.s_time;
  96. // });
  97. // if (!progress) {
  98. // progress = { month: s.s_time };
  99. // monthProgress.push(progress);
  100. // }
  101. // progress.tp = ctx.helper.add(ctx.helper.add(progress.tp, s.contract_tp), s.qc_tp);
  102. // }
  103. // }
  104. // monthProgress.sort(function(x, y) {
  105. // return Date.parse(x.month) - Date.parse(y.month);
  106. // });
  107. // let sum = 0;
  108. // for (const p of monthProgress) {
  109. // p.ratio = ctx.helper.mul(ctx.helper.div(p.tp, tender.sum, 4), 100);
  110. // sum = ctx.helper.add(sum, p.tp);
  111. // p.end_tp = sum;
  112. // p.end_ratio = ctx.helper.mul(ctx.helper.div(p.end_tp, tender.sum, 4), 100);
  113. // }
  114. ctx.body = {
  115. code: 0, msg: '', data: {
  116. tender,
  117. // monthProgress,
  118. // stagesEcharts: JSON.parse(JSON.stringify(stages)).reverse(),
  119. },
  120. };
  121. } catch (error) {
  122. this.log(error);
  123. ctx.body = { code: -1, msg: error.toString(), data: null };
  124. }
  125. }
  126. async advanceList(ctx) {
  127. try {
  128. const { advanceType } = ctx.query;
  129. const typeCol = advanceConst.typeCol.find(x => x.type === Number(advanceType));
  130. if (!typeCol) {
  131. ctx.body = { code: -1, msg: '预付款类型错误', data: null };
  132. return;
  133. }
  134. const { decimal } = ctx.tender.info;
  135. const advancePayTotal = ctx.tender.info.deal_param[typeCol.key + 'Advance'];
  136. const advances = await ctx.service.advance.getAdvanceList(ctx.tender.id, typeCol.type, decimal.pay ? decimal.payTp : decimal.tp, advancePayTotal);
  137. ctx.body = { code: 0, msg: '', data: advances };
  138. } catch (error) {
  139. this.log(error);
  140. ctx.body = { code: -1, msg: error.toString(), data: null };
  141. }
  142. }
  143. async advanceCheck(advance) {
  144. if (!advance) {
  145. throw '预付款数据错误';
  146. }
  147. const times = advance.status === auditConst.advance.status.checkNo ? advance.times - 1 : advance.times;
  148. advance.user = await this.service.projectAccount.getAccountInfoById(advance.uid);
  149. // 读取审核人列表数据
  150. advance.auditors = await this.service.advanceAudit.getAuditorsWithOwner(advance.id, advance.status === auditConst.advance.status.checkNo && this.ctx.session.sessionUser.accountId !== advance.uid ? times : advance.times);
  151. advance.auditHistory = await this.service.advanceAudit.getAuditors(advance.id, advance.times);
  152. advance.curAuditor = await this.service.advanceAudit.getCurAuditor(advance.id, advance.times);
  153. // 根据状态判断是否需要更新审批人列表
  154. if ((advance.status === auditConst.advance.status.uncheck || advance.status === auditConst.advance.status.checkNo) && this.ctx.tender.info.shenpi.advance !== shenpiConst.sp_status.sqspr) {
  155. const shenpi_status = this.ctx.tender.info.shenpi.advance;
  156. // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
  157. const auditList = await this.service.advanceAudit.getAllDataByCondition({ where: { vid: advance.id, times: advance.times }, orders: [['order', 'asc']] });
  158. const auditIdList = _.map(auditList, 'audit_id');
  159. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  160. const shenpiList = await this.service.shenpiAudit.getAllDataByCondition({ where: { tid: advance.tid, sp_type: shenpiConst.sp_type.advance, sp_status: shenpi_status } });
  161. const shenpiIdList = _.map(shenpiList, 'audit_id');
  162. // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
  163. if (!_.isEqual(auditIdList, shenpiIdList)) {
  164. await this.service.advanceAudit.updateNewAuditList(advance, shenpiIdList);
  165. }
  166. } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
  167. const shenpiInfo = await this.service.shenpiAudit.getDataByCondition({ tid: advance.tid, sp_type: shenpiConst.sp_type.advance, sp_status: shenpi_status });
  168. // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
  169. if (shenpiInfo && shenpiInfo.audit_id !== _.last(auditIdList)) {
  170. await this.service.advanceAudit.updateLastAudit(advance, auditList, shenpiInfo.audit_id);
  171. } else if (!shenpiInfo) {
  172. // 不存在终审人的状态下这里恢复为授权审批人
  173. this.ctx.tender.info.shenpi.advance = shenpiConst.sp_status.sqspr;
  174. }
  175. }
  176. }
  177. advance.advancePayTotal = this.ctx.tender.info.deal_param[ advanceConst.typeCol[advance.type].key + 'Advance'];
  178. if (advance.status === auditConst.advance.status.checkNo) {
  179. advance.curAuditor = await this.service.advanceAudit.getAuditorByStatus(advance.id, advance.status, times);
  180. advance.auditHistory = await this.service.advanceAudit.getAuditors(advance.id, times);
  181. }
  182. }
  183. async advanceDetail(ctx) {
  184. try {
  185. const { id } = ctx.query;
  186. const advance = await this.service.advance.getDataById(id);
  187. if (!advance) {
  188. throw '预付款数据错误';
  189. }
  190. await this.advanceCheck(advance);
  191. advance.auditHistory = advance.auditHistory.reduce((prev, curr, idx) => {
  192. if (idx === 0) {
  193. const reportor = {
  194. audit_id: advance.uid,
  195. audit_order: 0,
  196. audit_type: 1,
  197. status: advance.status === auditConst.advance.status.uncheck ? auditConst.advance.status.uncheck : auditConst.advance.status.checked,
  198. times: curr.times,
  199. begin_time: advance.pay_time,
  200. end_time: advance.auditHistory.length ? advance.auditHistory[0].create_time : null,
  201. name: advance.user.name,
  202. company: advance.user.company,
  203. role: advance.user.role,
  204. mobile: '',
  205. opinion: '',
  206. };
  207. prev.push({
  208. name: '原报',
  209. status: reportor.status,
  210. audit_type: reportor.audit_type,
  211. auditors: [reportor],
  212. });
  213. }
  214. const currentOrder = advance.auditors.find(auditor => auditor.audit_id === curr.audit_id).order;
  215. prev.push(
  216. {
  217. name: currentOrder === curr.max_sort ? '终审' : `${currentOrder}审`,
  218. status: curr.status,
  219. audit_type: 1,
  220. auditors: [{
  221. audit_id: curr.audit_id,
  222. audit_order: curr.order,
  223. audit_type: curr.type,
  224. status: curr.status,
  225. max_sort: curr.max_sort,
  226. begin_time: curr.create_time,
  227. end_time: curr.end_time,
  228. name: curr.name,
  229. company: curr.company,
  230. mobile: curr.mobile,
  231. opinion: curr.opinion,
  232. role: curr.role,
  233. times: curr.times,
  234. }],
  235. }
  236. );
  237. return prev;
  238. }, []);
  239. if (advance.curAuditor) {
  240. advance.curAuditor.audit_order = advance.auditors.find(auditor => auditor.audit_id === advance.curAuditor.audit_id).order;
  241. }
  242. ctx.body = { code: 0, msg: '', data: { advance } };
  243. } catch (error) {
  244. this.log(error);
  245. ctx.body = { code: -1, msg: error.toString(), data: null };
  246. }
  247. }
  248. async advanceAudit(ctx) {
  249. try {
  250. const advance = await this.service.advance.getDataById(ctx.request.body.id);
  251. await this.advanceCheck(advance);
  252. ctx.advance = advance;
  253. const data = {
  254. checkType: parseInt(ctx.request.body.checkType),
  255. opinion: ctx.request.body.opinion,
  256. };
  257. if (!advance || advance.status !== auditConst.advance.status.checking) {
  258. throw '当前预付款数据有误';
  259. }
  260. if (!advance.curAuditor || advance.curAuditor.audit_id !== ctx.session.sessionUser.accountId) {
  261. throw '您无权进行该操作';
  262. }
  263. if (!data.checkType || isNaN(data.checkType)) {
  264. throw '提交数据错误';
  265. }
  266. if (data.checkType === auditConst.advance.status.checkNo) {
  267. if (!data.checkType || isNaN(data.checkType)) {
  268. throw '提交数据错误';
  269. }
  270. }
  271. await ctx.service.advanceAudit.check(advance.id, data, advance.times, advance.type);
  272. ctx.body = { code: 0, msg: '操作成功', data: null };
  273. } catch (error) {
  274. this.log(error);
  275. ctx.body = { code: -1, msg: error.toString(), data: null };
  276. }
  277. }
  278. async reviseDetail(ctx) {
  279. try {
  280. const { rid } = ctx.query;
  281. const revise = rid
  282. ? await ctx.service.ledgerRevise.getRevise(ctx.tender.id, rid)
  283. : ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
  284. revise.preHis = revise.pre_his_id ? await ctx.service.ledgerHistory.getDataById(revise.pre_his_id) : null;
  285. revise.curHis = revise.his_id ? await ctx.service.ledgerHistory.getDataById(revise.his_id) : null;
  286. await ctx.service.reviseAudit.loadReviseUser(revise);
  287. await ctx.service.reviseAudit.loadReviseAuditViewData(revise);
  288. const GclGather = require('../lib/gcl_gather');
  289. const gclGatherModal = new GclGather.gclCompareGather(this.ctx);
  290. const spec = { zlj: stdConst.zlj, jrg: stdConst.jrg };
  291. spec.zlj.deal_bills_tp = ctx.tender.info.deal_param.zanLiePrice;
  292. gclGatherModal.init(ctx.tender.info.chapter, spec);
  293. const reviseBillsData = revise.readOnly && revise.curHis
  294. ? await ctx.helper.loadLedgerDataFromOss(revise.curHis.bills_file)
  295. : await ctx.service.reviseBills.getAllDataByCondition({ where: { tender_id: ctx.tender.id } });
  296. const revisePosData = revise.readOnly && revise.curHis
  297. ? await this.ctx.helper.loadLedgerDataFromOss(revise.curHis.pos_file)
  298. : await ctx.service.revisePos.getAllDataByCondition({ where: { tid: ctx.tender.id } });
  299. const price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: revise.id } });
  300. gclGatherModal.gatherReviseLedgerData(reviseBillsData, revisePosData, { prefix: 'new_' }, price, ctx.tender.info.decimal);
  301. const billsData = revise.preHis ? await this.ctx.helper.loadLedgerDataFromOss(revise.preHis.bills_file) : [];
  302. const posData = revise.preHis ? await this.ctx.helper.loadLedgerDataFromOss(revise.preHis.pos_file) : [];
  303. gclGatherModal.gatherLedgerData(billsData, posData, { prefix: 'org_' });
  304. revise.chapterList = gclGatherModal.chapterData();
  305. revise.new_tp = gclGatherModal.otherChapter.hj.new_total_price || 0;
  306. revise.org_tp = gclGatherModal.otherChapter.hj.org_total_price || 0;
  307. ctx.body = { code: 0, msg: '', data: { revise } };
  308. } catch (error) {
  309. ctx.log(error);
  310. ctx.body = { code: -1, msg: error.toString(), data: null };
  311. }
  312. }
  313. async ledgerAuditCheck(ctx) {
  314. const tender = ctx.tender.data;
  315. const info = ctx.tender.info;
  316. if (info.shenpi.ledger === shenpiConst.sp_status.sqspr) return;
  317. if (tender.ledger_status !== auditConst.ledger.status.uncheck && tender.ledger_status !== auditConst.ledger.status.checkNo) return;
  318. const shenpi_status = info.shenpi.ledger;
  319. // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
  320. const auditList = await ctx.service.ledgerAudit.getAuditors(tender.id, tender.ledger_times);
  321. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  322. const shenpiList = await ctx.service.shenpiAudit.getAllDataByCondition({ where: { tid: tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status } });
  323. // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
  324. let sameAudit = auditList.length === shenpiList.length;
  325. if (sameAudit) {
  326. for (const audit of auditList) {
  327. const shenpi = shenpiList.find(x => { return x.audit_id === audit.audit_id; });
  328. if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type || shenpi.audit_ledger_id !== audit.audit_ledger_id) {
  329. sameAudit = false;
  330. break;
  331. }
  332. }
  333. }
  334. if (!sameAudit) await ctx.service.ledgerAudit.updateNewAuditList(tender, shenpiList);
  335. } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
  336. const shenpiInfo = await ctx.service.shenpiAudit.getDataByCondition({ tid: tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status });
  337. // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
  338. const lastAuditors = auditList.filter(x => { x.audit_order === auditList[auditList.length - 1].audit_order; });
  339. if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].audit_id))) {
  340. await ctx.service.ledgerAudit.updateLastAudit(tender, auditList, shenpiInfo.audit_id);
  341. } else if (!shenpiInfo) {
  342. // 不存在终审人的状态下这里恢复为授权审批人
  343. info.shenpi.ledger = shenpiConst.sp_status.sqspr;
  344. }
  345. }
  346. }
  347. async ledgerDetail(ctx) {
  348. try {
  349. await this.ledgerAuditCheck(ctx);
  350. const tender = ctx.tender.data;
  351. await ctx.service.ledgerAudit.loadLedgerUser(tender);
  352. await ctx.service.ledgerAudit.loadLedgerAuditViewData(tender);
  353. const auditHistory = tender.auditHistory && tender.auditHistory.length && tender.auditHistory[tender.auditHistory.length - 1].reduce((prev, curr, idx) => {
  354. if (idx === 0) {
  355. const reportor = {
  356. audit_id: tender.user.id,
  357. audit_order: 0,
  358. audit_type: 1,
  359. status: tender.ledger_status === auditConst.ledger.status.uncheck ? auditConst.ledger.status.uncheck : auditConst.ledger.status.checked,
  360. times: tender.ledger_status === auditConst.ledger.status.checkNo ? tender.ledger_times - 1 : tender.ledger_times,
  361. begin_time: curr.begin_time,
  362. end_time: curr.begin_time,
  363. name: tender.user.name,
  364. company: tender.user.company,
  365. role: tender.user.role,
  366. mobile: '',
  367. opinion: '',
  368. };
  369. prev.push({
  370. name: '原报',
  371. status: reportor.status,
  372. audit_type: reportor.audit_type,
  373. auditors: [reportor],
  374. });
  375. }
  376. prev.push({
  377. name: curr.is_final ? '终审' : `${curr.order}审`,
  378. audit_type: curr.audit_type,
  379. status: curr.status,
  380. auditors: curr.auditors,
  381. });
  382. return prev;
  383. }, []);
  384. const curAuditors = tender.curAuditors;
  385. const ledger = {
  386. contractPrice: ctx.tender.info.deal_param.contractPrice,
  387. totalPrice: tender.total_price || 0,
  388. auditHistory,
  389. curAuditors,
  390. };
  391. ctx.body = { code: 0, msg: '', data: { ledger } };
  392. } catch (error) {
  393. this.log(error);
  394. ctx.body = { code: -1, msg: error.toString(), data: null };
  395. }
  396. }
  397. async ledgerAudit(ctx) {
  398. try {
  399. await this.ledgerAuditCheck(ctx);
  400. const tender = ctx.tender;
  401. if (!tender.data || tender.data.ledger_status !== auditConst.ledger.status.checking) {
  402. throw '当前标段数据有误';
  403. }
  404. const curAudits = await ctx.service.ledgerAudit.getCurAuditors(tender.id, tender.data.ledger_times);
  405. const curAuditIds = curAudits.map(x => { return x.audit_id; });
  406. if (curAuditIds.indexOf(ctx.session.sessionUser.accountId) < 0) {
  407. throw '审批失败';
  408. }
  409. const checkType = parseInt(ctx.request.body.checkType);
  410. if (!checkType || isNaN(checkType)) {
  411. throw '提交数据错误';
  412. }
  413. await ctx.service.ledgerAudit.check(tender.id, checkType, ctx.request.body.opinion, tender.data.ledger_times);
  414. ctx.body = { code: 0, msg: '操作成功', data: null };
  415. } catch (error) {
  416. this.log(error);
  417. ctx.body = { code: -1, msg: error.toString(), data: null };
  418. }
  419. }
  420. }
  421. return WeappTenderController;
  422. };