lrf402788946 4 gadi atpakaļ
vecāks
revīzija
51dc165bbd

+ 1 - 0
.gitignore

@@ -12,3 +12,4 @@ run/
 *.un~
 typings/
 .nyc_output/
+export/

+ 2 - 0
app/controller/car/.car.js

@@ -74,6 +74,7 @@ module.exports = {
       "b_solve",
       "b_sign_date",
       "remark",
+      "status",
     ],
   },
   show: {
@@ -88,6 +89,7 @@ module.exports = {
         onwer: "%onwer%",
         car_no: "%car_no%",
         id_number: "%id_number%",
+        status: "status",
       },
     },
     service: "query",

+ 3 - 1
app/controller/order/.transport.js

@@ -51,9 +51,11 @@ module.exports = {
         client: "client",
         "send_time@start": "send_time@start",
         "send_time@end": "send_time@end",
-        "rq_arrive_time@start": "rq_arrive_time@start",
+        "sign_time@start": "sign_time@start",
+        "sign_time@end": "sign_time@end",
         is_js: "is_js",
         status: "status",
+        car: "supplier.car_no",
       },
     },
     service: "query",

+ 28 - 0
app/controller/order/transport.js

@@ -13,16 +13,44 @@ class TransportController extends Controller {
     this.service = this.ctx.service.order.transport;
   }
 
+  /**
+   * 运输签收
+   */
   async sign() {
     const res = await this.service.sign(this.ctx.request.body);
     this.ctx.ok(res);
   }
 
+  /**
+   * 获取运输单号
+   */
   async getNo() {
     const no = `t_${moment().format('YYYYMMDDHHmmss')}_${_.random(100, 999)}`;
     this.ctx.ok({ data: no });
   }
+  /**
+   * 单趟核算
+   */
+  async calculate() {
+    const data = await this.service.calculate(this.ctx.request.body);
+    this.ctx.ok({ data });
+  }
+
+  /**
+   * 单车核算
+   */
+  async carCalculate() {
+    const data = await this.service.carCalculate(this.ctx.request.body);
+    this.ctx.ok({ data });
+  }
 
+  /**
+   * 核算导出
+   */
+  async toExport() {
+    const data = await this.service.toExport(this.ctx.request.body);
+    this.ctx.ok({ data });
+  }
 }
 
 module.exports = CrudController(TransportController, meta);

+ 1 - 1
app/controller/util.js

@@ -6,7 +6,7 @@ const Controller = require('egg').Controller;
 class UtilController extends Controller {
   constructor(ctx) {
     super(ctx);
-    this.service = this.ctx.service.util;
+    this.service = this.ctx.service.util.util;
   }
   async findModel() {
     const data = await this.service.findModel(this.ctx.params);

+ 6 - 7
app/model/transport.js

@@ -16,13 +16,11 @@ const goodsList = new Schema({
   split_id: { type: String, maxLength: 200, required: true }, // 拆分的货物id
 });
 // 运输支出(单车,单趟)
-const bill = new Schema({
+const out_bill = new Schema({
   item: { type: String, maxlength: 200 }, // 支出项
-  taxes: { type: String, maxLength: 200 }, // 税率
-  sq_ys: { type: Number, maxLength: 200 }, // 税前应收
-  sq_ss: { type: Number, maxLength: 200 }, // 税前实收
-  sh_ys: { type: Number, maxLength: 200 }, // 税后应收
-  sh_ss: { type: Number, maxLength: 200 }, // 税后实收
+  money: { type: Number, maxLength: 200 }, // 金额
+  opera: { type: String, maxLength: 200 }, // 操作人
+  remark: { type: String, maxlength: 200 }, // 备注
 });
 // 运输方信息
 const supplier = new Schema({
@@ -89,8 +87,9 @@ const transport = {
     field: { label: '线路' },
   },
   out_bill: {
-    type: [ bill ],
+    type: Array,
     maxLength: 200,
+    default: () => [],
     field: { label: '运输支出单据' },
   },
   remark: {

+ 8 - 1
app/router/transport.js

@@ -6,8 +6,15 @@ module.exports = app => {
   const prefix = '/api/servicezhwl';
   const index = 'order';
   const { router, controller } = app;
-
+  // 核算导出
+  router.post('transport', `${prefix}/transport/calculate/export`, controller[index].transport.toExport);
+  // 单趟核算
+  router.post('transport', `${prefix}/transport/calculate`, controller[index].transport.calculate);
+  // 单车核算
+  router.post('transport', `${prefix}/transport/carCalculate`, controller[index].transport.carCalculate);
+  // 签收
   router.post('transport', `${prefix}/transport/sign`, controller[index].transport.sign);
+  // 获取运输单号
   router.get('transport', `${prefix}/transport/no`, controller[index].transport.getNo);
   // 运输
   router.resources(`${prefix}/transport`, controller[index].transport); // index、create、show、destroy

+ 0 - 4
app/service/car/car.js

@@ -1,10 +1,6 @@
 'use strict';
 
-const assert = require('assert');
-const _ = require('lodash');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
 
 class CarService extends CrudService {
   constructor(ctx) {

+ 0 - 5
app/service/car/daily.js

@@ -1,17 +1,12 @@
 'use strict';
 
-const assert = require('assert');
-const _ = require('lodash');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require("naf-core").Error;
 
 class DailyService extends CrudService {
   constructor(ctx) {
     super(ctx, 'daily');
     this.model = this.ctx.model.Daily;
   }
-
 }
 
 module.exports = DailyService;

+ 0 - 4
app/service/client/item.js

@@ -1,10 +1,6 @@
 'use strict';
 
-const assert = require('assert');
-const _ = require('lodash');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
 
 class ItemService extends CrudService {
   constructor(ctx) {

+ 0 - 5
app/service/client/route.js

@@ -1,11 +1,6 @@
 'use strict';
 
-const assert = require('assert');
-const _ = require('lodash');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
-
 class RouteService extends CrudService {
   constructor(ctx) {
     super(ctx, 'route');

+ 0 - 4
app/service/client/treaty.js

@@ -1,10 +1,6 @@
 'use strict';
 
-const assert = require('assert');
-const _ = require('lodash');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
 
 class TreatyService extends CrudService {
   constructor(ctx) {

+ 0 - 2
app/service/order/bill.js

@@ -1,8 +1,6 @@
 'use strict';
-const _ = require('lodash');
 const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
 class BillService extends CrudService {
   constructor(ctx) {
     super(ctx, 'in');

+ 0 - 1
app/service/order/order.js

@@ -1,6 +1,5 @@
 'use strict';
 
-const assert = require('assert');
 const _ = require('lodash');
 const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');

+ 0 - 2
app/service/order/split.js

@@ -1,8 +1,6 @@
 'use strict';
-const _ = require('lodash');
 const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
 class SplitService extends CrudService {
   constructor(ctx) {
     super(ctx, 'split');

+ 155 - 4
app/service/order/transport.js

@@ -1,4 +1,5 @@
 'use strict';
+const assert = require('assert');
 const _ = require('lodash');
 const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
@@ -18,7 +19,6 @@ class TransportService extends CrudService {
     return res;
   }
 
-
   /**
    * 签收
    * @param {Object} data 运输单数据
@@ -26,15 +26,166 @@ class TransportService extends CrudService {
   async sign(data) {
     const { id, sign_time } = data;
     const transport = await this.model.find({ _id: ObjectId(id) });
-    if (!transport) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到运输单信息');
-    const { split, no } = data;
+    if (!transport) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到运输单信息');
+    }
+    const { goods, no } = data;
     // 修改订单部分
-    await this.os.arriveGoods(split, no);
+    await this.os.arriveGoods(goods, no);
     // 修改运输单部分
     transport.status = '1';
     if (sign_time) transport.sign_time = sign_time;
     return await transport.save();
   }
 
+  /**
+   * 运输核算信息组织
+   * @param {Object} { ids, type }  ids:运输单id集合; type:once=>单趟 ; car=> 单车
+   */
+  async calculate({ ids }) {
+    // 获取要核算的运输列表
+    let tList = await this.model.find({ _id: ids.map(i => ObjectId(i)) });
+    if (tList.length > 0) tList = JSON.parse(JSON.stringify(tList));
+    const res = { inBill: await this.getInBill(tList), outBill: this.getOutBill(tList) };
+    // 计算合计
+    const count = {};
+    // 收入采用税后实收
+    count.im = _.round(
+      res.inBill.reduce((p, n) => p + (n.sh_ss || 0), 0),
+      2
+    );
+    // 运输支出合计
+    count.om = _.round(
+      res.outBill.reduce((p, n) => p + (n.money || 0), 0),
+      2
+    );
+    // 总计
+    count.total = _.round(count.im - count.om, 2);
+    res.count = count;
+    return res;
+  }
+
+  /**
+   * 单车核算
+   * @param {Object} { car_no, start, end } 车id, 开始时间, 结束时间: 时间默认为发货时间
+   */
+  async carCalculate({ car_no, start, end }) {
+    assert(start, '缺少时间范围-开始时间');
+    assert(end, '缺少时间范围-结束时间');
+    let query = { 'send_time@start': start, 'send_time@end': end, 'supplier.car_no': car_no };
+    let tList = await this.query(query);
+    if (tList.length > 0) tList = JSON.parse(JSON.stringify(tList));
+    const res = { inBill: await this.getInBill(tList), outBill: this.getOutBill(tList) };
+    // 日常维护部分
+    query = { 'date@start': start, 'date@end': end };
+    const daily = await this.ctx.service.car.daily.query({ car_no, ...query });
+    res.daily = daily;
+    // 计算合计
+    const count = {};
+    // 收入采用税后实收
+    count.im = _.round(
+      res.inBill.reduce((p, n) => p + (n.sh_ss || 0), 0),
+      2
+    );
+    // 运输支出合计
+    count.om = _.round(
+      res.outBill.reduce((p, n) => p + (n.money || 0), 0),
+      2
+    );
+    // 日常支出
+    count.dm = _.round(
+      res.daily.reduce((p, n) => p + (n.money || 0), 0),
+      2
+    );
+    // 总计
+    count.total = _.round(count.im - count.om - count.dm, 2);
+    res.count = count;
+    return res;
+  }
+
+  /**
+   * 将所选的运输单的收入整合至一个列表
+   * @param {Array} list 运输列表
+   */
+  async getInBill(list) {
+    // 原则,少查询,多操作
+    const split_ids = list.map(i => i.goods.map(g => g.split_id)).flat();
+    const orders = await this.ctx.model.Order.find({
+      'split._id': split_ids.map(i => ObjectId(i)),
+    });
+    list = list.map(i => {
+      const { no, route } = i;
+      i.goods = i.goods.map(g => {
+        const order = orders.find(f =>
+          f.split.find(s => ObjectId(s._id).equals(g.split_id))
+        );
+        if (order) {
+          g.order_no = _.get(order, 'order_no');
+          g.no = no;
+          g.route = route;
+        }
+        return g;
+      });
+      return i.goods;
+    });
+    return _.flattenDeep(list);
+  }
+
+  /**
+   * 将所选的运输单的运输支出整合至一个列表
+   * @param {Array} list 运输列表
+   */
+  getOutBill(list) {
+    list = list.map(i => {
+      const { no, route } = i;
+      i.out_bill = i.out_bill.map(o => {
+        o.no = no;
+        o.route = route;
+        return o;
+      });
+      return i.out_bill;
+    });
+    return _.flattenDeep(list);
+  }
+
+  /**
+   * 核算准备导出
+   * @param {Object} { type, ...query } type:单车(car)/单趟(once); query:查询条件
+   */
+  async toExport({ type, ...query }) {
+    let data = {};
+    if (type === 'car') data = await this.carCalculate(query);
+    else data = await this.calculate(query);
+    const res = await this.export({ data, ...query });
+  }
+
+
+  /**
+   * 核算整理数据导出
+   * @param {Object} Object { data } data:数据
+   */
+  async export({ data, car_no }) {
+    // console.log(data);
+    // 获取车牌号
+    const car = await this.ctx.model.Car.findById(car_no);
+    if (car) car_no = car.car_no;
+    const arr = [];
+    const alignStyle = { vertical: 'middle', horizontal: 'center' };
+    // 根据内容,计算标题单元格结束位置的字母
+    const keys = Object.keys(data);
+    let ecell = '';
+    if (keys.includes('daily')) ecell = 'L1';
+    else ecell = '';
+    const headObj = {
+      content: '核算单',
+      scell: 'A1',
+      ecell,
+      alignment: alignStyle,
+    };
+    arr.push(headObj);
+    // 先拼count
+
+    await this.ctx.service.util.excel.toExcel({ data: arr });
+  }
 }
 module.exports = TransportService;

+ 0 - 4
app/service/personnel/driver.js

@@ -1,10 +1,6 @@
 'use strict';
 
-const assert = require('assert');
-const _ = require('lodash');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
 
 class DriverService extends CrudService {
   constructor(ctx) {

+ 0 - 1
app/service/system/dictionary.js

@@ -1,6 +1,5 @@
 'use strict';
 
-const assert = require('assert');
 const _ = require('lodash');
 const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');

+ 0 - 6
app/service/system/notice.js

@@ -1,12 +1,6 @@
 'use strict';
 
-const assert = require('assert');
-const _ = require('lodash');
-const moment = require('moment');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
-
 class NoticeService extends CrudService {
   constructor(ctx) {
     super(ctx, 'notice');

+ 1 - 4
app/service/system/schedule.js

@@ -1,11 +1,8 @@
 'use strict';
 
-const assert = require('assert');
 const _ = require('lodash');
 const moment = require('moment');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
 
 class ScheduleService extends CrudService {
   constructor(ctx) {
@@ -49,7 +46,7 @@ class ScheduleService extends CrudService {
         // 过滤出没有发送过消息的人员(可能有后加的情况)
         const not_send_user = user_ids.filter(f => !noticeList.find(nf => nf.user_id === f));
         // 拼message,然后发消息
-        const meta = await this.ctx.service.util.getModel(table);
+        const meta = await this.ctx.service.util.util.getModel(table);
         obj.message = this.getMessage(i, col, meta);
         this.addNotice(obj, not_send_user);
       }

+ 69 - 0
app/service/util/excel.js

@@ -0,0 +1,69 @@
+'use strict';
+const _ = require('lodash');
+const { sep } = require('path');
+const fs = require('fs');
+const Excel = require('exceljs');
+const moment = require('moment');
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+
+
+class ExcelService extends CrudService {
+  constructor(ctx) {
+    super(ctx);
+    this.root_path = _.get(this.ctx.app.config.export, 'root_path');
+    this.file_type = 'export';
+    if (!fs.existsSync(`${this.root_path}${this.file_type}`)) {
+      // 如果不存在文件夹,就创建
+      fs.mkdirSync(`${this.root_path}${this.file_type}`);
+    }
+    this.excel_path = `${sep}excel${sep}`;
+  }
+
+
+  /**
+   * 导出excel;
+   * @param {Object} param  { data, meta, fn }
+   * @property Object data 数据;有meta的形式就是正常数据直接用;没有meta情况,需要整理成行数据
+   * @property meta 列设置; 若meta不存在,则逐行解析. meta存在,则直接自动解析
+   * @property fn 文件名
+   */
+  async toExcel({ data = [], meta, fn = 'excel导出结果' } = {}) {
+    console.log('in function:');
+    const nowDate = new Date().getTime();
+    const filename = `${fn}.xlsx`; // -${nowDate}
+    const path = `${this.root_path}${this.file_type}${this.excel_path}`;
+    if (!path) {
+      throw new BusinessError(ErrorCode.BUSINESS, '服务端没有设置存储路径');
+    }
+    if (!fs.existsSync(path)) {
+      // 如果不存在文件夹,就创建
+      fs.mkdirSync(path);
+    }
+    const workbook = new Excel.Workbook();
+    const sheet = workbook.addWorksheet('sheet');
+    if (meta) {
+      sheet.columns = meta;
+      sheet.addRows(data);
+    } else {
+      console.log(data);
+      for (const row of data) {
+        const { scell, ecell, content, alignment } = row;
+        if (scell && ecell) sheet.mergeCells(scell, ecell);
+        sheet.getCell(ecell).value = content;
+        if (alignment) sheet.getCell(ecell).alignment = alignment;
+      }
+      // sheet.mergeCells(1,1,1,2); //合并单元格,起始行,列 ,终止行,列
+    }
+    // 导出
+    const filepath = `${path}${filename}`;
+    if (data.length <= 0) return;
+    await workbook.xlsx.writeFile(filepath);
+  }
+
+  numberToLetter(num) {
+    const arr = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'Y', 'Z' ];
+    return arr[num];
+  }
+}
+module.exports = ExcelService;

+ 0 - 2
app/service/http-util.js

@@ -1,7 +1,5 @@
 'use strict';
-const assert = require('assert');
 const _ = require('lodash');
-const { ObjectId } = require('mongoose').Types;
 const { AxiosService } = require('naf-framework-mongoose/lib/service');
 const { BusinessError, ErrorCode } = require('naf-core').Error;
 const { isNullOrUndefined } = require('naf-core').Util;

+ 3 - 5
app/service/util.js

@@ -1,10 +1,6 @@
 'use strict';
-const assert = require('assert');
 const _ = require('lodash');
-const moment = require('moment');
-const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
-const { BusinessError, ErrorCode } = require('naf-core').Error;
 
 class UtilService extends CrudService {
   constructor(ctx) {
@@ -75,6 +71,8 @@ class UtilService extends CrudService {
     };
     return obj[_.lowerCase(model)];
   }
-  async utilMethod(query, body) {}
+  async utilMethod(query, body) {
+    console.log(query, body);
+  }
 }
 module.exports = UtilService;

+ 0 - 47
app/utils/utils.js

@@ -1,47 +0,0 @@
-'use strict';
-
-// 获取字典是否
-exports.getIsNot = function(value) {
-  let isNot = '';
-  // eslint-disable-next-line default-case
-  switch (value) {
-    case '0':
-      isNot = '否';
-      break;
-    case '1':
-      isNot = '是';
-      break;
-    case '2':
-      isNot = '无资格';
-      break;
-  }
-
-  return isNot;
-};
-
-// 获取两个时间差
-exports.begindateEnddateSum = function(begindate, enddate) {
-  const sumDate = [];
-  const startTime = getDate(begindate);
-  const endTime = getDate(enddate);
-  while (endTime.getTime() - startTime.getTime() >= 0) {
-    const year = startTime.getFullYear();
-    const month = startTime.getMonth().toString().length === 1 ? '0' + startTime.getMonth().toString() : startTime.getMonth();
-    const day = startTime.getDate().toString().length === 1 ? '0' + startTime.getDate() : startTime.getDate();
-    sumDate.push(year + '-' + month + '-' + day);
-    startTime.setDate(startTime.getDate() + 1);
-  }
-  // console.log(sumDate);
-  return sumDate;
-};
-function getDate(datestr) {
-  const temp = datestr.split('-');
-  // new Date()的月份入参实际都是当前值-1
-  const date = new Date(temp[0], temp[1], temp[2]);
-  return date;
-
-
-  // const temp = datestr.split('-');
-  // const date = new Date(temp[0], temp[1], temp[2]);
-  // return date;
-}

+ 6 - 0
config/config.default.js

@@ -1,6 +1,7 @@
 /* eslint valid-jsdoc: "off" */
 
 'use strict';
+const { sep } = require('path');
 const { jwt } = require('./config.secret');
 /**
  * @param {Egg.EggAppInfo} appInfo app info
@@ -42,6 +43,7 @@ module.exports = appInfo => {
 
   config.project = {
     userAuth: 'http://127.0.0.1:7003/api/role/auth',
+    mission: 'http://127.0.0.1:7003/api/mission',
   };
 
   config.jwt = {
@@ -69,6 +71,10 @@ module.exports = appInfo => {
   //   agent: true,
   // };
 
+  config.export = {
+    root_path: `${appInfo.baseDir}${sep}`,
+  };
+
   return {
     ...config,
     ...userConfig,

+ 1 - 0
config/config.prod.js

@@ -32,6 +32,7 @@ module.exports = () => {
 
   config.project = {
     userAuth: 'http://127.0.0.1:4000/api/role/auth',
+    mission: 'http://127.0.0.1:4001/api/mission',
   };
 
   return config;

+ 1 - 0
package.json

@@ -13,6 +13,7 @@
     "egg-redis": "^2.4.0",
     "egg-scripts": "^2.11.0",
     "egg-view-nunjucks": "^2.2.0",
+    "exceljs": "^4.2.0",
     "jsonwebtoken": "^8.5.1",
     "lodash": "^4.17.15",
     "moment": "^2.27.0",