| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079 | 
							- 'use strict';
 
- /**
 
-  * 台账相关控制器
 
-  *
 
-  * @author CaiAoLin
 
-  * @date 2017/11/30
 
-  * @version
 
-  */
 
- const stdDataAddType = {
 
-     withParent: 1,
 
-     child: 2,
 
-     next: 3,
 
- };
 
- const audit = require('../const/audit');
 
- const moment = require('moment');
 
- const auditConst = audit.ledger;
 
- const tenderMenu = require('../../config/menu').tenderMenu;
 
- const measureType = require('../const/tender').measureType;
 
- const shenpiConst = require('../const/shenpi');
 
- const fs = require('fs');
 
- const LzString = require('lz-string');
 
- const accountGroup = require('../const/account_group').group;
 
- const path = require('path');
 
- const exportExcel = require('../lib/export_excel');
 
- const billsPosConvert = require('../lib/bills_pos_convert');
 
- const xlsx = require('js-xlsx');
 
- const stdConst = require('../const/standard');
 
- const sendToWormhole = require('stream-wormhole');
 
- const spreadSetting = require('../lib/spread_setting');
 
- module.exports = app => {
 
-     class LedgerController extends app.BaseController {
 
-         /**
 
-          * 构造函数
 
-          *
 
-          * @param {Object} ctx - egg全局变量
 
-          * @return {void}
 
-          */
 
-         constructor(ctx) {
 
-             super(ctx);
 
-             ctx.showProject = true;
 
-             ctx.showTitle = true;
 
-             ctx.showTender = true;
 
-         }
 
-         /**
 
-          * 检查标段是否只读(审核中,审核完成)
 
-          * @param {Object} tenderData
 
-          * @return {boolean}
 
-          * @private
 
-          */
 
-         _ledgerReadOnly() {
 
-             const tender = this.ctx.tender.data;
 
-             return tender.user_id !== this.ctx.session.sessionUser.accountId ||
 
-                 (tender.ledger_status === auditConst.status.checking || tender.ledger_status === auditConst.status.checked);
 
-         }
 
-         _canUpdateDealBills(tender, auditors) {
 
-             const isUser = tender.user_id === this.ctx.session.sessionUser.accountId;
 
-             const auditorsId = this.ctx.helper._.map(auditors, 'audit_id');
 
-             const isAuditor  = auditorsId.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
 
-             const upPermission = this.ctx.session.sessionUser.permission && this.ctx.session.sessionUser.permission.tender
 
-                 ? this.ctx.session.sessionUser.permission.tender.indexOf('3') >= 0
 
-                 : false;
 
-             return ((tender.ledger_status === auditConst.status.uncheck || tender.ledger_status === auditConst.status.checkNo) && isUser) ||
 
-                 (tender.ledger_status === auditConst.status.checking && isAuditor) ||
 
-                 (tender.ledger_status === auditConst.status.checked && upPermission);
 
-         }
 
-         _getLedgerColumn(sjsRela) {
 
-             const tender = this.ctx.tender;
 
-             const ledgerColumn = [
 
-                 'id', 'tender_id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf',
 
-                 'code', 'b_code', 'name', 'unit', 'unit_price', 'quantity', 'total_price',
 
-                 'sgfh_qty', 'sgfh_expr', 'sgfh_tp', 'memo', 'drawing_code', 'node_type'];
 
-             if (tender.info.display.ledger.deal) ledgerColumn.push('deal_qty', 'deal_tp');
 
-             if (tender.info.display.ledger.dgnQty) ledgerColumn.push('dgn_qty1', 'dgn_qty2');
 
-             if (tender.info.display.ledger.clQty) ledgerColumn.push('sjcl_qty', 'qtcl_qty', 'sjcl_expr', 'qtcl_expr', 'sjcl_tp', 'qtcl_tp');
 
-             const posColumn = ['id', 'tid', 'lid', 'name', 'position', 'porder', 'sgfh_qty', 'sgfh_expr', 'add_stage_order', 'drawing_code', 'quantity'];
 
-             if (tender.info.display.ledger.clQty) posColumn.push('sjcl_qty', 'qtcl_qty', 'sjcl_expr', 'qtcl_expr');
 
-             for (const field of sjsRela.ledgerCol) {
 
-                 if (field.show) {
 
-                     ledgerColumn.push(field.field);
 
-                     posColumn.push(field.field);
 
-                 }
 
-             }
 
-             return [ledgerColumn, posColumn];
 
-         }
 
-         /**
 
-          * 台账分解页面 (Get)
 
-          *
 
-          * @param {Object} ctx - egg全局变量
 
-          * @return {void}
 
-          */
 
-         async explode(ctx) {
 
-             try {
 
-                 const tender = ctx.tender;
 
-                 const [ledgerSpread, posSpread] = await spreadSetting.getLedgerSpreadSetting(ctx, tender.id,
 
-                     this._ledgerReadOnly(tender.data));
 
-                 const times = tender.data.ledger_status === auditConst.status.checkNo ? tender.data.ledger_times - 1 : tender.data.ledger_times;
 
-                 const curAuditor = await ctx.service.ledgerAudit.getCurAuditor(tender.id, tender.data.ledger_times);
 
-                 const auditors = tender.data.ledger_status === auditConst.status.checkNo && tender.data.user_id !== ctx.session.sessionUser.accountId && !ctx.tender.isTourist ?
 
-                     await ctx.service.ledgerAudit.getAuditorsWithOwner(tender.id, times) :
 
-                     await ctx.service.ledgerAudit.getAuditorsWithOwner(tender.id, tender.data.ledger_times);
 
-                 const user = await ctx.service.projectAccount.getAccountInfoById(ctx.tender.data.user_id);
 
-                 const auditHistory = [];
 
-                 if (times >= 1) {
 
-                     for (let i = 1; i <= times; i++) {
 
-                         auditHistory.push(await ctx.service.ledgerAudit.getAuditors(ctx.tender.id, i));
 
-                     }
 
-                 }
 
-                 const [stdBills, stdChapters] = await this.ctx.service.valuation.getValuationStdList(
 
-                     ctx.tender.data.valuation, ctx.tender.data.measure_type);
 
-                     // 获取附件列表
 
-                 const attData = await ctx.service.ledgerAtt.getDataByTenderId(ctx.tender.id);
 
-                 for (const index in attData) {
 
-                     attData[index].in_time = moment(attData[index].in_time * 1000).format('YYYY-MM-DD');
 
-                     attData[index].orginpath = ctx.app.config.fujianOssPath + attData[index].filepath;
 
-                     delete attData[index].filepath;
 
-                 }
 
-                 const whiteList = this.ctx.app.config.multipart.whitelist;
 
-                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
 
-                 const syncLedger = await this.ctx.service.specPull.syncLedger(this.ctx.session.sessionProject.id);
 
-                 // 是否已验证手机短信
 
-                 const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
 
-                 const revise = await this.ctx.service.ledgerRevise.getLastestRevise(tender.id);
 
-                 tender.data.hasRevise = !!revise;
 
-                 const stage = await this.ctx.service.stage.getDataByCondition({ tid: tender.id });
 
-                 tender.data.hasStage = !!stage;
 
-                 const renderData = {
 
-                     tender: tender.data,
 
-                     tenderInfo: tender.info,
 
-                     auditConst,
 
-                     auditors,
 
-                     curAuditor,
 
-                     user,
 
-                     attData,
 
-                     whiteList,
 
-                     auditHistory,
 
-                     ledgerSpreadSetting: JSON.stringify(ledgerSpread),
 
-                     posSpreadSetting: JSON.stringify(posSpread),
 
-                     tenderMenu,
 
-                     preUrl: '/tender/' + tender.id,
 
-                     measureType,
 
-                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.ledger.explode),
 
-                     stdBills,
 
-                     stdChapters,
 
-                     dealBillsPermission: this._canUpdateDealBills(tender.data, auditors.filter(x => {return x.audit_order > 0})),
 
-                     shenpiConst,
 
-                     categoryData,
 
-                     syncLedgerUrl: syncLedger ? `${ctx.app.config.url3f}/${syncLedger.pull_class}/sync-tz/${tender.id}` : '',
 
-                     nodeType: stdConst.nodeType,
 
-                     authMobile: pa.auth_mobile,
 
-                 };
 
-                 if ((tender.data.ledger_status === auditConst.status.uncheck || tender.data.ledger_status === auditConst.status.checkNo) && tender.data.user_id === ctx.session.sessionUser.accountId) {
 
-                     // renderData.accountGroup = accountGroup;
 
-                     // 获取所有项目参与者
 
-                     const accountList = await ctx.service.projectAccount.getAllDataByCondition({
 
-                         where: { project_id: ctx.session.sessionProject.id, enable: 1 },
 
-                         columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'],
 
-                     });
 
-                     renderData.accountList = accountList;
 
-                     const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
 
-                     renderData.accountGroup = unitList.map(item => {
 
-                         const groupList = accountList.filter(item1 => item1.company === item.name);
 
-                         return { groupName: item.name, groupList };
 
-                     });
 
-                     renderData.auditorList = await ctx.service.ledgerAudit.getAuditors(tender.id, tender.data.ledger_times);
 
-                 }
 
-                 await this.layout('ledger/explode.ejs', renderData, 'ledger/explode_modal.ejs');
 
-             } catch (err) {
 
-                 ctx.helper.log(err);
 
-                 this.postError(err, '标段数据错误');
 
-                 // await this.redirect('/dashboard');
 
-                 ctx.redirect(ctx.request.header.referer);
 
-             }
 
-         }
 
-         /**
 
-          * 获取子节点 (Ajax)
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async getChildren(ctx) {
 
-             const responseData = {
 
-                 err: 0,
 
-                 msg: '',
 
-                 data: [],
 
-             };
 
-             try {
 
-                 const data = JSON.parse(ctx.request.body.data);
 
-                 const id = data.ledger_id;
 
-                 if (isNaN(id) || id <= 0) {
 
-                     throw '参数错误';
 
-                 }
 
-                 responseData.data = await ctx.service.ledger.getChildrenByParentId(ctx.tender.id, id);
 
-             } catch (err) {
 
-                 responseData.err = 1;
 
-                 responseData.msg = err;
 
-             }
 
-             ctx.body = responseData;
 
-         }
 
-         /**
 
-          * 树结构基本操作(增、删、上下移、升降级)
 
-          * @param {Object} ctx - egg全局变量
 
-          * @return {Promise<void>}
 
-          */
 
-         async _base(ctx, type, data) {
 
-             if (isNaN(data.id) || data.id <= 0) throw '数据错误';
 
-             if (type !== 'add') {
 
-                 if (isNaN(data.count) || data.count <= 0) data.count = 1;
 
-             }
 
-             switch (type) {
 
-                 case 'add':
 
-                     return await ctx.service.ledger.addNodeBatch(ctx.tender.id, data.id, {}, data.count);
 
-                 case 'delete':
 
-                     return await ctx.service.ledger.delete(ctx.tender.id, data.id, data.count);
 
-                 case 'up-move':
 
-                     return await ctx.service.ledger.upMoveNode(ctx.tender.id, data.id, data.count);
 
-                 case 'down-move':
 
-                     return await ctx.service.ledger.downMoveNode(ctx.tender.id, data.id, data.count);
 
-                 case 'up-level':
 
-                     return await ctx.service.ledger.upLevelNode(ctx.tender.id, data.id, data.count);
 
-                 case 'down-level':
 
-                     return await ctx.service.ledger.downLevelNode(ctx.tender.id, data.id, data.count);
 
-             }
 
-         }
 
-         /**
 
-          * 复制粘贴整块
 
-          *
 
-          * @param ctx
 
-          * @return {Promise<void>
 
-          */
 
-         async _pasteBlock(ctx, data) {
 
-             if ((isNaN(data.id) || data.id <= 0) ||
 
-                 (!data.tid && data.tid <= 0) ||
 
-                 (!data.block || data.block.length <= 0)) throw '参数错误';
 
-             return await ctx.service.ledger.pasteBlockData(ctx.tender.id, data.id, data.block);
 
-         }
 
-         /**
 
-          * 从标准项目表添加数据
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async _addStd(ctx, data) {
 
-             if ((isNaN(data.id) || data.id <= 0) || !data.stdType || !data.stdNode) throw '参数错误';
 
-             // todo 校验项目是否使用该库的权限
 
-             let stdLib,
 
-                 addType;
 
-             switch (data.stdType) {
 
-                 case 'xmj':
 
-                     stdLib = ctx.service.stdXmj;
 
-                     addType = stdDataAddType.withParent;
 
-                     break;
 
-                 case 'gcl':
 
-                     stdLib = ctx.service.stdGcl;
 
-                     const selectNode = await ctx.service.ledger.getDataByNodeId(ctx.tender.id, data.id);
 
-                     if (selectNode.b_code) {
 
-                         addType = stdDataAddType.next;
 
-                     } else {
 
-                         addType = stdDataAddType.child;
 
-                     }
 
-                     break;
 
-                 default:
 
-                     throw '未知标准库';
 
-             }
 
-             const stdData = await stdLib.getDataByDataId(data.stdLibId, data.stdNode);
 
-             switch (addType) {
 
-                 case stdDataAddType.child:
 
-                     return await ctx.service.ledger.addStdNodeAsChild(ctx.tender.id, data.id, stdData);
 
-                 case stdDataAddType.next:
 
-                     return await ctx.service.ledger.addStdNode(ctx.tender.id, data.id, stdData);
 
-                 case stdDataAddType.withParent:
 
-                     return await ctx.service.ledger.addStdNodeWithParent(ctx.tender.id, stdData, stdLib);
 
-                 default:
 
-                     throw '未知添加方式';
 
-             }
 
-         }
 
-         /**
 
-          * 从签约清单添加节点
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async _addDeal(ctx, data) {
 
-             if (!data.type || !data.dealBills) throw '数据错误';
 
-             data.dealBills.unit_price = this.ctx.helper.round(data.dealBills.unit_price, ctx.tender.info.decimal.up);
 
-             if (data.type === 'child') {
 
-                 return await ctx.service.ledger.addChild(ctx.tender.id, data.id, data.dealBills);
 
-             } else if (data.type === 'next') {
 
-                 return await ctx.service.ledger.addNode(ctx.tender.id, data.id, data.dealBills);
 
-             }
 
-             throw '数据错误';
 
-         }
 
-         /**
 
-          * 批量插入数据
 
-          *
 
-          * data = {id, batchData, batchType}
 
-          * data.batchType = 'batchInsertChild'/'batchInsertNext'
 
-          * data.batchData = [{name, children}] -- 项目节列表
 
-          * data.batchData.children = [{code, name, unit, unit_price, quantity}] -- 工程量清单列表
 
-          *
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async _batchInsert(ctx, data) {
 
-             if ((isNaN(data.id) || data.id <= 0) || !data.batchType) throw '参数错误';
 
-             switch (data.batchType) {
 
-                 case 'child':
 
-                     return await ctx.service.ledger.batchInsertChild(ctx.tender.id, data.id, data.batchData);
 
-                 case 'next':
 
-                     return await ctx.service.ledger.batchInsertNext(ctx.tender.id, data.id, data.batchData);
 
-                 default:
 
-                     throw '参数错误';
 
-             }
 
-         }
 
-         /**
 
-          * 更新清单相关 (Ajax)
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async update(ctx) {
 
-             try {
 
-                 if (!ctx.tender.data) throw '标段数据错误';
 
-                 if (ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) throw '您无权进行该操作';
 
-                 const data = JSON.parse(ctx.request.body.data);
 
-                 if (!data.postType || !data.postData) throw '数据错误';
 
-                 const responseData = {
 
-                     err: 0,
 
-                     msg: '',
 
-                     data: [],
 
-                 };
 
-                 switch (data.postType) {
 
-                     case 'add':
 
-                     case 'delete':
 
-                     case 'up-move':
 
-                     case 'down-move':
 
-                     case 'up-level':
 
-                     case 'down-level':
 
-                         responseData.data = await this._base(ctx, data.postType, data.postData);
 
-                         break;
 
-                     case 'update':
 
-                         ctx.helper.checkDgnQtyPrecision(data.postData);
 
-                         responseData.data = await ctx.service.ledger.updateCalc(ctx.tender.id, data.postData);
 
-                         break;
 
-                     case 'paste-block':
 
-                         responseData.data = await this._pasteBlock(ctx, data.postData);
 
-                         break;
 
-                     case 'add-std':
 
-                         responseData.data = await this._addStd(ctx, data.postData);
 
-                         break;
 
-                     case 'add-deal':
 
-                         responseData.data = await this._addDeal(ctx, data.postData);
 
-                         break;
 
-                     case 'batch-insert':
 
-                         responseData.data = await this._batchInsert(ctx, data.postData);
 
-                         break;
 
-                     default:
 
-                         throw '未知操作';
 
-                 }
 
-                 ctx.body = responseData;
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = this.ajaxErrorBody(err);
 
-             }
 
-         }
 
-         /**
 
-          * 定位
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async locate(ctx) {
 
-             const responseData = {
 
-                 err: 0,
 
-                 msg: '',
 
-                 data: [],
 
-             };
 
-             try {
 
-                 const tenderId = ctx.params.id;
 
-                 if (!tenderId) {
 
-                     throw '当前未打开标段';
 
-                 }
 
-                 const data = JSON.parse(ctx.request.body.data);
 
-                 if ((isNaN(data.id) || data.id <= 0)) {
 
-                     throw '参数错误';
 
-                 }
 
-                 responseData.data = await ctx.service.ledger.locateNode(tenderId, data.id);
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 responseData.err = 1;
 
-                 responseData.msg = err;
 
-             }
 
-             ctx.body = responseData;
 
-         }
 
-         /**
 
-          * 获取全部子节点
 
-          *
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async posterity(ctx) {
 
-             const responseData = {
 
-                 err: 0,
 
-                 msg: '',
 
-                 data: [],
 
-             };
 
-             try {
 
-                 const tenderId = ctx.params.id;
 
-                 if (!tenderId) {
 
-                     throw '当前未打开标段';
 
-                 }
 
-                 const data = JSON.parse(ctx.request.body.data);
 
-                 if ((isNaN(data.id) || data.id <= 0)) {
 
-                     throw '参数错误';
 
-                 }
 
-                 const expandData = await ctx.service.ledger.getPosterityByParentId(tenderId, data.id);
 
-                 responseData.data = { expand: expandData };
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 responseData.err = 1;
 
-                 responseData.msg = err;
 
-             }
 
-             ctx.body = responseData;
 
-         }
 
-         /**
 
-          * 获取部位明细数据(Ajax)
 
-          *
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async loadExplodeData(ctx) {
 
-             try {
 
-                 const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id, ctx.tender.info.display.exMemo);
 
-                 const [ledgerColumn, posColumn] = this._getLedgerColumn(sjsRela);
 
-                 const ledgerData = ctx.tender.ledgerReadOnly && ctx.tender.his
 
-                     ? await ctx.helper.loadLedgerDataFromOss(ctx.tender.his.bills_file)
 
-                     : await ctx.service.ledger.getAllDataByCondition({ columns: ledgerColumn, where: { tender_id: ctx.tender.id } });
 
-                 const posData = this.ctx.tender.data.measure_type === measureType.tz.value
 
-                     ? (ctx.tender.ledgerReadOnly && ctx.tender.his
 
-                         ? await ctx.helper.loadLedgerDataFromOss(ctx.tender.his.pos_file)
 
-                         : await ctx.service.pos.getPosData({tid: ctx.tender.id}, posColumn))
 
-                     : [];
 
-                 const ledgerTags = await this.ctx.service.ledgerTag.getDatas(ctx.tender.id);
 
-                 //ctx.body = { err: 0, msg: '', data: { bills: this.ctx.helper.hpackArr(ledgerData), pos: this.ctx.helper.hpackArr(posData), tags: ledgerTags }, hpack: ['bills', 'pos'] };
 
-                 ctx.body = { err: 0, msg: '', data: { bills: ledgerData, pos: posData, tags: ledgerTags } };
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = { err: 1, msg: err.toString(), data: [] };
 
-             }
 
-         }
 
-         async check(ctx) {
 
-             try {
 
-                 const ledgerData = await ctx.service.ledger.getData(ctx.tender.id);
 
-                 const posData = this.ctx.tender.data.measure_type === measureType.tz.value
 
-                     ? await ctx.service.pos.getPosData({ tid: ctx.tender.id }) : [];
 
-                 const checkDataModel = require('../lib/ledger').checkData;
 
-                 const checkData = new checkDataModel(ctx, measureType);
 
-                 checkData.loadData(ledgerData, posData);
 
-                 ctx.tender.info.ledger_check.same_code && checkData.checkSameCode();
 
-                 ctx.tender.info.ledger_check.sibling && checkData.checkSibling();
 
-                 if (ctx.tender.data.measure_type === measureType.tz.value) checkData.checkBillsQty(['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity']);
 
-                 checkData.checkBillsTp([
 
-                     {qty: 'sgfh_qty', tp: 'sgfh_tp'}, {qty: 'qtcl_qty', tp: 'qtcl_tp'},
 
-                     {qty: 'sjcl_qty', tp: 'sjcl_tp'}, {qty: 'quantity', tp: 'total_price'}
 
-                 ], this.ctx.tender.info.decimal);
 
-                 ctx.body = { err: 0, msg: '', data: checkData.checkResult };
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = this.ajaxErrorBody(err, '检查数据错误');
 
-             }
 
-         }
 
-         /**
 
-          * 更新 部位明细数据
 
-          *
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async posUpdate(ctx) {
 
-             try {
 
-                 await this.checkMeasureType(measureType.tz.value);
 
-                 const data = JSON.parse(ctx.request.body.data);
 
-                 const responseData = await ctx.service.pos.savePosData(data, ctx.tender.id);
 
-                 ctx.body = { err: 0, msg: '', data: responseData };
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = { err: 1, msg: err.toString(), data: null };
 
-             }
 
-         }
 
-         /**
 
-          * 复制粘贴 部位明细
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async posPaste(ctx) {
 
-             try {
 
-                 await this.checkMeasureType(measureType.tz.value);
 
-                 const data = JSON.parse(ctx.request.body.data);
 
-                 const result = await ctx.service.pos.pastePosData(data, ctx.tender.id);
 
-                 ctx.body = { err: 0, msg: '', data: result };
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = { err: 1, msg: err.toString(), data: null };
 
-             }
 
-         }
 
-         /**
 
-          * 上传 清单Excel 并导入
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async uploadExcel(ctx) {
 
-             try {
 
-                 const ueType = ctx.params.ueType;
 
-                 const compressData = ctx.request.body.data;
 
-                 const data = JSON.parse(LzString.decompressFromUTF16(compressData));
 
-                 const responseData = { err: 0, msg: '', data: {} };
 
-                 switch (ueType) {
 
-                     case 'tz':
 
-                         const templateId = await this.ctx.service.valuation.getValuationTemplate(
 
-                             this.ctx.tender.data.valuation, this.ctx.tender.data.measure_type);
 
-                         responseData.data = await ctx.service.ledger.importExcel(templateId, data.sheet, data.filter);
 
-                         break;
 
-                     case 'gcl2xmj':
 
-                         responseData.data = await ctx.service.ledger.importGclExcel(data.id, data.sheet);
 
-                         break;
 
-                     default:
 
-                         throw '数据错误';
 
-                 }
 
-                 ctx.body = responseData;
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = { err: 1, msg: err.toString(), data: null };
 
-             }
 
-         }
 
-         // async uploadExcel(ctx) {
 
-         //     let stream;
 
-         //     try {
 
-         //         const responseData = { err: 0, msg: '', data: {}, };
 
-         //         // 保存文件
 
-         //         stream = await ctx.getFileStream();
 
-         //         const create_time = Date.parse(new Date());
 
-         //         const fileInfo = path.parse(stream.filename);
 
-         //         const fileName = this.app.config.filePath + '/cache/ledger/uploads/' + create_time + fileInfo.ext;
 
-         //         await ctx.helper.saveStreamFile(stream, fileName);
 
-         //         // 读取excel
 
-         //         console.log(ctx.query);
 
-         //         const name = ctx.query.sheetName;
 
-         //         if (!name) throw '未选择需要导入的工作簿';
 
-         //         const wb = xlsx.readFile(fileName);
 
-         //         const sheetData = {
 
-         //             rows: xlsx.utils.sheet_to_json(wb.Sheets[name], {header: 1}),
 
-         //             merge: wb.Sheets[name]["!merges"],
 
-         //         };
 
-         //         if (!sheetData.rows) throw '读取工作簿数据错误';
 
-         //         const ueType = ctx.query.ueType;
 
-         //         switch (ueType) {
 
-         //             case 'tz':
 
-         //                 const templateId = await this.ctx.service.valuation.getValuationTemplate(
 
-         //                     this.ctx.tender.data.valuation, this.ctx.tender.data.measure_type);
 
-         //                 responseData.data = await ctx.service.ledger.importExcel(templateId, sheetData);
 
-         //                 break;
 
-         //             case 'gcl2xmj':
 
-         //                 responseData.data = await ctx.service.ledger.importGclExcel(ctx.tender.id, sheetData);
 
-         //                 break;
 
-         //             default:
 
-         //                 throw '数据错误';
 
-         //         }
 
-         //         ctx.body = responseData;
 
-         //     } catch (err) {
 
-         //         console.log(err);
 
-         //         this.log(err);
 
-         //         // 失败需要消耗掉stream 以防卡死
 
-         //         if (stream) await sendToWormhole(stream);
 
-         //         ctx.body = {err: 1, msg: err.toString(), data: null};
 
-         //     }
 
-         // }
 
-         /**
 
-          * 填设计量(Ajax)
 
-          *
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async deal2sgfh(ctx) {
 
-             try {
 
-                 if (!ctx.tender.data) throw '标段数据错误';
 
-                 if (ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) throw '您无权进行该操作';
 
-                 if (this.ctx.tender.measure_type === measureType.tz.value) throw '该功能仅工程量清单模式可用';
 
-                 await this.ctx.service.ledger.deal2sgfh(ctx.tender.id);
 
-                 const ledgerData = await ctx.service.ledger.getData(ctx.tender.id);
 
-                 ctx.body = { err: 0, msg: '', data: { bills: ledgerData } };
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = { err: 1, msg: err.toString(), data: null };
 
-             }
 
-         }
 
-         /**
 
-          * 下载(清单Excel模板 or 导出项目台账Excel)
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async download(ctx) {
 
-             const file = ctx.params.file;
 
-             if (file) {
 
-                 try {
 
-                     let fileName;
 
-                     if (file === '导入分项清单EXCEL格式.xlsx') {
 
-                         fileName = path.join(this.app.baseDir, 'app', 'public', 'files', 'template', 'ledger', '导入分项清单EXCEL格式.xlsx');
 
-                         ctx.body = await fs.readFileSync(fileName);
 
-                     } else if (file === '台账分解.xlsx') {
 
-                         const create_time = Date.parse(new Date()) / 1000;
 
-                         fileName = this.app.baseDir + '/app/public/files/ledger' + ctx.tender.id + '-' + create_time + '.xlsx';
 
-                         const exportor = new exportExcel.exportLedger2Excel(ctx);
 
-                         await exportor.export2File(fileName);
 
-                         ctx.body = await fs.readFileSync(fileName);
 
-                         // 输出文件后删除
 
-                         fs.unlinkSync(fileName);
 
-                     }
 
-                 } catch (err) {
 
-                     this.log(err);
 
-                     this.setMessage(err.toString(), this.messageType.ERROR);
 
-                 }
 
-             }
 
-         }
 
-         /**
 
-          * 部位台账 页面 (Get)
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async bwtz(ctx) {
 
-             try {
 
-                 const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id, ctx.tender.info.display.exMemo);
 
-                 const renderData = {
 
-                     tender: ctx.tender.data,
 
-                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.ledger.bwtz),
 
-                     ex_memo1: sjsRela.ledgerCol.find(x => { return x.field === 'ex_memo1'; }),
 
-                     ex_memo2: sjsRela.ledgerCol.find(x => { return x.field === 'ex_memo2'; }),
 
-                     ex_memo3: sjsRela.ledgerCol.find(x => { return x.field === 'ex_memo3'; }),
 
-                 };
 
-                 await this.layout('ledger/bwtz.ejs', renderData);
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.redirect(ctx.request.header.referer);
 
-             }
 
-         }
 
-         async loadBwtz(ctx) {
 
-             try {
 
-                 const ledgerData = await ctx.service.ledger.getData(ctx.tender.id);
 
-                 const posData = this.ctx.tender.data.measure_type === measureType.tz.value
 
-                     ? await ctx.service.pos.getPosData({ tid: ctx.tender.id }) : [];
 
-                 const convert = new billsPosConvert(ctx);
 
-                 convert.loadData(ledgerData, posData, []);
 
-                 const result = await convert.convert();
 
-                 // const wbsCodeHis = await ctx.service.externalData.getExValue(ctx.tender.id, -1,
 
-                 //     externalDataConst.FuLong.exType, externalDataConst.FuLong.exFields.wbsCode) || [];
 
-                 // const [result, needUpdate] = convert.convertByWbsCode(wbsCodeHis);
 
-                 // if (needUpdate) {
 
-                 //     await ctx.service.externalData.saveExValue(ctx.tender.id, -1,
 
-                 //         externalDataConst.FuLong.exType, externalDataConst.FuLong.exFields.wbsCode, wbsCodeHis);
 
-                 // }
 
-                 ctx.body = { err: 0, msg: '', data: result };
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = this.ajaxErrorBody(err, '加载合同支付数据错误');
 
-             }
 
-         }
 
-         /**
 
-          * 台账对比 页面 (Get)
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async gather(ctx) {
 
-             try {
 
-                 const renderData = {
 
-                     measureType,
 
-                     tender: ctx.tender.data,
 
-                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.ledger.gather),
 
-                 };
 
-                 await this.layout('ledger/gather.ejs', renderData);
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 await this.redirect(ctx.request.header.referer);
 
-             }
 
-         }
 
-         /**
 
-          * 获取 台账对比 数据 (Ajax)
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async loadGatherData(ctx) {
 
-             try {
 
-                 const billsData = await ctx.service.ledger.getData(ctx.tender.id);
 
-                 const posData = this.ctx.tender.data.measure_type === measureType.tz.value
 
-                     ? await ctx.service.pos.getPosData({ tid: ctx.tender.id }) : [];
 
-                 const dealBills = await ctx.service.dealBills.getAllDataByCondition({ where: { tender_id: this.ctx.tender.id } });
 
-                 const zlj = JSON.parse(JSON.stringify(stdConst.zlj));
 
-                 zlj.deal_bills_tp = ctx.tender.info.deal_param.zanLiePrice;
 
-                 ctx.body = { err: 0, msg: '', data: {
 
-                     bills: billsData, pos: posData, dealBills, spec: {zlj: zlj, jrg: stdConst.jrg},
 
-                 }};
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 ctx.body = { err: 1, msg: err.toString(), data: [] };
 
-             }
 
-         }
 
-         /**
 
-          * 计量台账页面 (Get)
 
-          *
 
-          * @param {object} ctx - egg全局变量
 
-          * @return {void}
 
-          */
 
-         async index(ctx) {
 
-             const renderData = {};
 
-             await this.layout('ledger/index.ejs', renderData);
 
-         }
 
-         /**
 
-          * 审批流程(Get)
 
-          * @param ctx
 
-          * @return {Promise<void>}
 
-          */
 
-         async ledgerAuditors(ctx) {
 
-             try {
 
-                 const responseData = {
 
-                     err: 0, msg: '', data: {},
 
-                 };
 
-                 const tender = ctx.tender;
 
-                 const times = tender.data.ledger_status === auditConst.status.checkNo ? tender.data.ledger_times - 1 : tender.data.ledger_times;
 
-                 const auditors = tender.data.ledger_status === auditConst.status.checkNo && tender.data.user_id !== ctx.session.sessionUser.accountId && !ctx.tender.isTourist ?
 
-                     await ctx.service.ledgerAudit.getAuditorsWithOwner(tender.id, times) :
 
-                     await ctx.service.ledgerAudit.getAuditorsWithOwner(tender.id, tender.data.ledger_times);
 
-                 const user = await ctx.service.projectAccount.getAccountInfoById(ctx.tender.data.user_id);
 
-                 const auditHistory = [];
 
-                 if (times >= 1) {
 
-                     for (let i = 1; i <= times; i++) {
 
-                         auditHistory.push(await ctx.service.ledgerAudit.getAuditors(ctx.tender.id, i));
 
-                     }
 
-                 }
 
-                 responseData.data.auditHistory = auditHistory;
 
-                 // 获取审批流程中左边列表
 
-                 responseData.data.auditors = auditors;
 
-                 responseData.data.user = user;
 
-                 ctx.body = responseData;
 
-             } catch (error) {
 
-                 this.log(error);
 
-                 ctx.body = { err: 1, msg: error.toString(), data: null };
 
-             }
 
-         }
 
-         /**
 
-          * 上传附件
 
-          * @param {Object} ctx - egg全局变量
 
-          * @return {void}
 
-          */
 
-         async uploadFile(ctx) {
 
-             const responseData = {
 
-                 err: 0,
 
-                 msg: '',
 
-                 data: [],
 
-             };
 
-             let stream;
 
-             try {
 
-                 const parts = ctx.multipart({ autoFields: true });
 
-                 const files = [];
 
-                 let index = 0;
 
-                 const extra_upload = ctx.tender.data.ledger_status === auditConst.status.checked;
 
-                 while ((stream = await parts()) !== undefined) {
 
-                     // 判断用户是否选择上传文件
 
-                     if (!stream.filename) {
 
-                         throw '请选择上传的文件!';
 
-                     }
 
-                     const fileInfo = path.parse(stream.filename);
 
-                     const create_time = Date.parse(new Date()) / 1000;
 
-                     const filepath = `app/public/upload/${this.ctx.tender.id}/ledger/fujian_${create_time + index.toString() + fileInfo.ext}`;
 
-                     // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
 
-                     await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
 
-                     if (stream) {
 
-                         await sendToWormhole(stream);
 
-                     }
 
-                     // 保存数据到att表
 
-                     const fileData = {
 
-                         tid: ctx.params.id,
 
-                         in_time: create_time,
 
-                         filename: fileInfo.name,
 
-                         fileext: fileInfo.ext,
 
-                         filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size,
 
-                         filepath,
 
-                         extra_upload,
 
-                     };
 
-                     const result = await ctx.service.ledgerAtt.save(parts.field, fileData, ctx.session.sessionUser.accountId);
 
-                     if (!result) {
 
-                         throw '导入数据库保存失败';
 
-                     }
 
-                     const attData = await ctx.service.ledgerAtt.getDataByFid(result.insertId);
 
-                     attData.in_time = moment(create_time * 1000).format('YYYY-MM-DD');
 
-                     files.length !== 0 ? files.unshift(attData) : files.push(attData);
 
-                     ++index;
 
-                 }
 
-                 responseData.data = files;
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 // 失败需要消耗掉stream 以防卡死
 
-                 if (stream) {
 
-                     await sendToWormhole(stream);
 
-                 }
 
-                 this.setMessage(err.toString(), this.messageType.ERROR);
 
-                 responseData.err = 1;
 
-                 responseData.msg = err.toString();
 
-             }
 
-             ctx.body = responseData;
 
-         }
 
-         /**
 
-          * 下载附件
 
-          * @param {Object} ctx - egg全局变量
 
-          * @return {void}
 
-          */
 
-         async downloadFile(ctx) {
 
-             const id = ctx.params.fid;
 
-             if (id) {
 
-                 try {
 
-                     const fileInfo = await ctx.service.ledgerAtt.getDataById(id);
 
-                     if (fileInfo !== undefined && fileInfo !== '') {
 
-                         // const fileName = path.join(this.app.baseDir, fileInfo.filepath);
 
-                         // 解决中文无法下载问题
 
-                         const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
 
-                         let disposition = '';
 
-                         if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
 
-                             disposition = 'attachment; filename=' + encodeURIComponent(fileInfo.filename + fileInfo.fileext);
 
-                         } else if (userAgent.indexOf('firefox') >= 0) {
 
-                             disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(fileInfo.filename + fileInfo.fileext) + '"';
 
-                         } else {
 
-                             /* safari等其他非主流浏览器只能自求多福了 */
 
-                             disposition = 'attachment; filename=' + new Buffer(fileInfo.filename + fileInfo.fileext).toString('binary');
 
-                         }
 
-                         ctx.response.set({
 
-                             'Content-Type': 'application/octet-stream',
 
-                             'Content-Disposition': disposition,
 
-                             'Content-Length': fileInfo.filesize,
 
-                         });
 
-                         // ctx.body = await fs.createReadStream(fileName);
 
-                         ctx.body = await ctx.helper.ossFileGet(fileInfo.filepath);
 
-                     } else {
 
-                         throw '不存在该文件';
 
-                     }
 
-                 } catch (err) {
 
-                     this.log(err);
 
-                     this.setMessage(err.toString(), this.messageType.ERROR);
 
-                 }
 
-             }
 
-         }
 
-         /**
 
-          * 查看附件
 
-          * @param {Object} ctx - egg全局变量
 
-          * @return {void}
 
-          */
 
-         async checkFile(ctx) {
 
-             const responseData = { err: 0, msg: '' };
 
-             const { id = '' } = JSON.parse(ctx.request.body.data);
 
-             if (id) {
 
-                 try {
 
-                     const fileInfo = await ctx.service.ledgerAtt.getDataById(id);
 
-                     if (fileInfo && Object.keys(fileInfo).length) {
 
-                         let filepath = fileInfo.filepath;
 
-                         if (!ctx.helper.canPreview(fileInfo.fileext)) {
 
-                             filepath = `/tender/${ctx.tender.id}/ledger/download/file/${fileInfo.id}`;
 
-                         } else {
 
-                             // filepath = filepath.replace(/^app|\/app/, '');
 
-                             filepath = ctx.app.config.fujianOssPath + filepath;
 
-                         }
 
-                         fileInfo.filepath && (responseData.data = { filepath });
 
-                     }
 
-                 } catch (error) {
 
-                     this.log(error);
 
-                     this.setMessage(error.toString(), this.messageType.ERROR);
 
-                     responseData.err = 1;
 
-                     responseData.msg = error.toString();
 
-                 }
 
-             }
 
-             ctx.body = responseData;
 
-         }
 
-         /**
 
-          * 删除附件
 
-          * @param {Object} ctx - egg全局变量
 
-          * @return {void}
 
-          */
 
-         async deleteFile(ctx) {
 
-             const responseData = {
 
-                 err: 0,
 
-                 msg: '',
 
-                 data: '',
 
-             };
 
-             try {
 
-                 // this._checkStageCanModifyRe(ctx);
 
-                 const data = JSON.parse(ctx.request.body.data);
 
-                 const fileInfo = await ctx.service.ledgerAtt.getDataById(data.id);
 
-                 if (!fileInfo || !Object.keys(fileInfo).length) {
 
-                     throw '该文件不存在';
 
-                 }
 
-                 if (!fileInfo.extra_upload && ctx.tender.status === auditConst.status.checked) {
 
-                     throw '无权限删除';
 
-                 }
 
-                 if (fileInfo !== undefined && fileInfo !== '') {
 
-                     // 先删除文件
 
-                     // await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
 
-                     await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
 
-                     // 再删除数据库
 
-                     await ctx.service.ledgerAtt.deleteById(data.id);
 
-                     responseData.data = '';
 
-                 } else {
 
-                     throw '不存在该文件';
 
-                 }
 
-             } catch (err) {
 
-                 responseData.err = 1;
 
-                 responseData.msg = err;
 
-             }
 
-             ctx.body = responseData;
 
-         }
 
-         /**
 
-          * 保存附件(或替换)
 
-          * @param {Object} ctx - egg全局变量
 
-          * @return {void}
 
-          */
 
-         async saveFile(ctx) {
 
-             const responseData = {
 
-                 err: 0,
 
-                 msg: '',
 
-                 data: [],
 
-             };
 
-             let stream;
 
-             try {
 
-                 // this._checkStageCanModifyRe(ctx);
 
-                 stream = await ctx.getFileStream({ requireFile: false });
 
-                 let fileData = {};
 
-                 if (stream.filename !== undefined) {
 
-                     const create_time = Date.parse(new Date()) / 1000;
 
-                     const fileInfo = path.parse(stream.filename);
 
-                     const dirName = `app/public/upload/${this.ctx.tender.id}/ledger`;
 
-                     const fileName = 'fujian_' + create_time + fileInfo.ext;
 
-                     // 判断文件夹是否存在,不存在则直接创建文件夹
 
-                     // if (!fs.existsSync(path.join(this.app.baseDir, dirName))) {
 
-                     //     await fs.mkdirSync(path.join(this.app.baseDir, dirName));
 
-                     // }
 
-                     // 保存文件
 
-                     // await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
 
-                     await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + path.join(dirName, fileName), stream);
 
-                     // 保存数据到att表
 
-                     fileData = {
 
-                         filesize: stream.fields.size,
 
-                         filepath: path.join(dirName, fileName),
 
-                     };
 
-                 }
 
-                 const result = await ctx.service.ledgerAtt.updateByID(stream.fields, fileData);
 
-                 if (!result) {
 
-                     throw '导入数据库保存失败';
 
-                 }
 
-                 const attData = await ctx.service.ledgerAtt.getDataByFid(stream.fields.id);
 
-                 attData.in_time = moment(attData.in_time * 1000).format('YYYY-MM-DD');
 
-                 responseData.data = attData;
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 // 失败需要消耗掉stream 以防卡死
 
-                 if (stream) {
 
-                     await sendToWormhole(stream);
 
-                 }
 
-                 this.setMessage(err.toString(), this.messageType.ERROR);
 
-                 responseData.err = 1;
 
-                 responseData.msg = err.toString();
 
-             }
 
-             ctx.body = responseData;
 
-         }
 
-         /**
 
-          * 批量下载 - 压缩成zip文件返回
 
-          * @param {Object} ctx - 全局上下文
 
-          */
 
-         async downloadZip(ctx) {
 
-             const zipFilename = `${ctx.tender.data.name}-台账分解-附件.zip`;
 
-             const time = Date.now();
 
-             const zipPath = `app/public/upload/${ctx.tender.id}/ledger/fu_jian_zip${time}.zip`;
 
-             const responseData = {
 
-                 err: 0,
 
-                 msg: '',
 
-             };
 
-             try {
 
-                 const { fileIds = [] } = JSON.parse(ctx.request.body.data);
 
-                 const size = await ctx.service.ledgerAtt.compressedFile(fileIds, zipPath);
 
-                 // 解决中文无法下载问题
 
-                 const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
 
-                 let disposition = '';
 
-                 if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
 
-                     disposition = 'attachment; filename=' + encodeURIComponent(zipFilename);
 
-                 } else if (userAgent.indexOf('firefox') >= 0) {
 
-                     disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(zipFilename) + '"';
 
-                 } else {
 
-                     /* safari等其他非主流浏览器只能自求多福了 */
 
-                     disposition = 'attachment; filename=' + new Buffer(zipFilename).toString('binary');
 
-                 }
 
-                 ctx.response.set({
 
-                     'Content-Type': 'application/octet-stream',
 
-                     'Content-Disposition': disposition,
 
-                     'Content-Length': size,
 
-                 });
 
-                 const readStream = fs.createReadStream(path.join(this.app.baseDir, zipPath));
 
-                 ctx.body = readStream;
 
-                 readStream.on('close', () => {
 
-                     if (fs.existsSync(path.resolve(this.app.baseDir, zipPath))) {
 
-                         fs.unlinkSync(path.resolve(this.app.baseDir, zipPath));
 
-                     }
 
-                 });
 
-                 // fs的错误不能被try catch捕捉
 
-                 readStream.on('error', err => {
 
-                     this.log(err);
 
-                     if (fs.existsSync(path.resolve(this.app.baseDir, zipPath))) {
 
-                         fs.unlinkSync(path.resolve(this.app.baseDir, zipPath));
 
-                     }
 
-                     responseData.err = 1;
 
-                     responseData.msg = err.toString();
 
-                     ctx.body = responseData;
 
-                 });
 
-             } catch (err) {
 
-                 this.log(err);
 
-                 if (fs.existsSync(path.resolve(this.app.baseDir, zipPath))) {
 
-                     fs.unlinkSync(path.resolve(this.app.baseDir, zipPath));
 
-                 }
 
-                 this.setMessage(err.toString(), this.messageType.ERROR);
 
-                 responseData.err = 1;
 
-                 responseData.msg = err.toString();
 
-                 ctx.body = responseData;
 
-             }
 
-         }
 
-     }
 
-     return LedgerController;
 
- };
 
 
  |