|
@@ -0,0 +1,141 @@
|
|
|
+'use strict';
|
|
|
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
|
|
|
+const { BusinessError, ErrorCode } = require('naf-core').Error;
|
|
|
+const _ = require('lodash');
|
|
|
+const assert = require('assert');
|
|
|
+const moment = require('moment');
|
|
|
+
|
|
|
+//
|
|
|
+class StatisticsService extends CrudService {
|
|
|
+ constructor(ctx) {
|
|
|
+ super(ctx, 'statistics');
|
|
|
+ this.billModel = this.ctx.model.Business.Bill;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 羽校总收入
|
|
|
+ * 统计账单的 收入(类型为-1/-2) - 退款(至余额,2) 且 is_pay 为 1
|
|
|
+ * m:当前这个月; 3m: 往前推3个月; 6m:往前推6个月; 1y:当前年
|
|
|
+ * @param {Object} query 查询条件
|
|
|
+ * @property {String} school_id 学校id
|
|
|
+ * @property {String} time 时间 m:月;3m:3月;6m:6个月; 1y:1年
|
|
|
+ */
|
|
|
+ async schoolTotalIn({ school_id, time }) {
|
|
|
+ assert(school_id, '缺少羽校信息');
|
|
|
+ assert(time, '缺少时间范围');
|
|
|
+ let query = { is_pay: '1', $or: [{ type: '-1' }, { type: '-2' }, { type: '2' }], school_id };
|
|
|
+ const { year, month, lastDate } = this.getPartsOfNow();
|
|
|
+ const timeQuery = (start, end) => ({ $and: [{ time: { $gte: start } }, { time: { $lte: end } }] });
|
|
|
+ let xList;
|
|
|
+ const yList = [];
|
|
|
+ if (time === 'm') {
|
|
|
+ // 这个月,按天查
|
|
|
+ const start = `${year}-${month}-01`;
|
|
|
+ const end = `${year}-${month}-${lastDate}`;
|
|
|
+ query = { ...query, ...timeQuery(start, end) };
|
|
|
+ xList = this.getEachDay(start, end);
|
|
|
+ } else if ([ '3m', '6m' ].includes(time)) {
|
|
|
+ const ms = _.head(time.split('')); // 月份数量 3/6/...
|
|
|
+ xList = this.getMonthList(ms);
|
|
|
+ const start = _.last(xList);
|
|
|
+ const { year, month, lastDate } = this.getPartsOfNow(_.head(xList));
|
|
|
+ const end = `${year}-${month}-${lastDate}`;
|
|
|
+ query = { ...query, ...timeQuery(start, end) };
|
|
|
+ } else if (time === '1y') {
|
|
|
+ const { year } = this.getPartsOfNow();
|
|
|
+ const start = `${year}-01-01`;
|
|
|
+ const end = `${year}-12-31`;
|
|
|
+ xList = this.getMonthList(12, end);
|
|
|
+ query = { ...query, ...timeQuery(start, end) };
|
|
|
+ }
|
|
|
+
|
|
|
+ let billList = await this.billModel.find(query);
|
|
|
+ if (billList.length > 0) billList = JSON.parse(JSON.stringify(billList));
|
|
|
+ for (const i of billList) {
|
|
|
+ const { time } = i;
|
|
|
+ const date = this.getDate(time);
|
|
|
+ i.date = date;
|
|
|
+ }
|
|
|
+ if (time === 'm') {
|
|
|
+ for (const x of xList) {
|
|
|
+ const date = x;
|
|
|
+ const list = billList.filter(f => f.date === date);
|
|
|
+ const inList = list.filter(f => f.type !== '2');
|
|
|
+ const outList = list.filter(f => f.type === '2');
|
|
|
+ const inTotal = inList.reduce((p, n) => p + (n.money || 0), 0);
|
|
|
+ const outTotal = outList.reduce((p, n) => p + (n.money || 0), 0);
|
|
|
+ const total = inTotal - outTotal;
|
|
|
+ yList.push(total);
|
|
|
+ }
|
|
|
+ xList = xList.map(i => {
|
|
|
+ const { date } = this.getPartsOfNow(i);
|
|
|
+ return date;
|
|
|
+ });
|
|
|
+ } else if ([ '3m', '6m', '1y' ].includes(time)) {
|
|
|
+ for (const x of xList) {
|
|
|
+ const start = x;
|
|
|
+ const { year, month, lastDate } = this.getPartsOfNow(x);
|
|
|
+ const end = `${year}-${month}-${lastDate}`;
|
|
|
+ const list = billList.filter(f => moment(f.date).isBetween(start, end, null, '[]'));
|
|
|
+ const inList = list.filter(f => f.type !== '2');
|
|
|
+ const outList = list.filter(f => f.type === '2');
|
|
|
+ const inTotal = inList.reduce((p, n) => p + (n.money || 0), 0);
|
|
|
+ const outTotal = outList.reduce((p, n) => p + (n.money || 0), 0);
|
|
|
+ const total = inTotal - outTotal;
|
|
|
+ yList.unshift(total);
|
|
|
+ }
|
|
|
+ xList = xList.map(i => {
|
|
|
+ const { month } = this.getPartsOfNow(i);
|
|
|
+ return parseInt(month);
|
|
|
+ });
|
|
|
+ xList = _.reverse(xList);
|
|
|
+ }
|
|
|
+
|
|
|
+ return { x: xList, y: yList };
|
|
|
+ }
|
|
|
+ // 获取现在时间的各个部分 年月日时分秒 和 当月最后一天是几号
|
|
|
+ getPartsOfNow(time = new Date()) {
|
|
|
+ const year = moment(time).year();
|
|
|
+ let month = moment(time).month() + 1;
|
|
|
+ if (month < 10) month = `0${month}`;
|
|
|
+ const date = moment(time).date();
|
|
|
+ const hour = moment(time).hour();
|
|
|
+ const minute = moment(time).minute();
|
|
|
+ const second = moment(time).second();
|
|
|
+ const lastDate = moment(`${year}-${month}-01`).add(1, 'months').subtract(1, 'days')
|
|
|
+ .date();
|
|
|
+ return { year, month, date, hour, minute, second, lastDate };
|
|
|
+ }
|
|
|
+ // 获取两个时间点内的每天
|
|
|
+ getEachDay(start, end) {
|
|
|
+ const arr = [];
|
|
|
+ let i = 0;
|
|
|
+ const addDay = (s, i) => moment(s).add(i, 'days').format('YYYY-MM-DD');
|
|
|
+ while (!moment(addDay(start, i)).isAfter(end, 'day')) {
|
|
|
+ arr.push(addDay(start, i));
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ return arr;
|
|
|
+ }
|
|
|
+ // 根据数据获取日期
|
|
|
+ getDate(time) {
|
|
|
+ const year = moment(time).year();
|
|
|
+ let month = moment(time).month() + 1;
|
|
|
+ if (month < 10) month = `0${month}`;
|
|
|
+ const date = moment(time).date();
|
|
|
+ return `${year}-${month}-${date}`;
|
|
|
+ }
|
|
|
+ // 获取月份第一天的列表, 往前推 pushNum 个月
|
|
|
+ getMonthList(pushNum, date) {
|
|
|
+ if (!_.isNumber(pushNum)) pushNum = parseInt(pushNum);
|
|
|
+ const arr = [];
|
|
|
+ const { year, month } = this.getPartsOfNow(date);
|
|
|
+ const sDate = `${year}-${month}-01`;
|
|
|
+ for (let i = 0; i < pushNum; i++) {
|
|
|
+ const { year, month } = this.getPartsOfNow(moment(sDate).subtract(i, 'months'));
|
|
|
+ arr.push(`${year}-${month}-01`);
|
|
|
+ }
|
|
|
+ return arr;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = StatisticsService;
|