From 478c2184a62c397edef4057fac589267827adff6 Mon Sep 17 00:00:00 2001 From: "gao.zhiyuan" Date: Wed, 19 Oct 2022 17:22:55 +0800 Subject: [PATCH] =?UTF-8?q?fix=20=E5=AE=9E=E9=99=85=E8=AF=B7=E5=81=87?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=B0=91=E4=BA=8E=E8=AE=A4=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E7=9A=84=E8=AE=A1=E7=AE=97=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/lib/controllers/attendance/index.js | 143 +++++++++++++++++++- api/app/lib/routes/attendance/index.js | 6 + api/app/lib/schedule/attendance.js | 11 ++ api/app/lib/utils/constant.js | 20 +++ api/app/lib/utils/xlsxDownload.js | 2 +- 5 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 api/app/lib/utils/constant.js diff --git a/api/app/lib/controllers/attendance/index.js b/api/app/lib/controllers/attendance/index.js index c25dcca..dcf1a7f 100644 --- a/api/app/lib/controllers/attendance/index.js +++ b/api/app/lib/controllers/attendance/index.js @@ -1,5 +1,6 @@ 'use strict'; const moment = require('moment') +const fs = require('fs'); async function overtimeStatistic (ctx) { try { @@ -48,7 +49,7 @@ async function exportOvertimeStatistic (ctx) { try { const { models } = ctx.fs.dc; const { clickHouse } = ctx.app.fs - const { memberList, packageUserData, overtimeStatisticListDayType } = ctx.app.fs.utils + const { memberList, packageUserData, overtimeStatisticListDayType, simpleExcelDown, dayType, overtimeType } = ctx.app.fs.utils const { keywordTarget, keyword, limit, page, orderBy, orderDirection, startDate, endDate, @@ -70,12 +71,67 @@ async function exportOvertimeStatistic (ctx) { startDate, endDate, pepUserIds }) - returnD.forEach(u => { - u.overtimeStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId) + returnD.forEach(d => { + d.departmrnt = d.departmrnt.map(dep => dep.name).join('、') + d.role = d.role.map(r => r.name).join('、') + let overtimeStatistic = sumRes.filter(s => s.pepUserId == d.pepUserId) + for (let dayTypeKey in dayType) { + for (let overtimeTypeKey in overtimeType) { + let corOverTimeSta = overtimeStatistic.find(o => o.compensate == overtimeTypeKey && o.dayType == dayTypeKey) + if (corOverTimeSta) { + d[overtimeTypeKey + dayTypeKey] = (corOverTimeSta.duration / 3600) + // .toFixed(1) + } + } + } + for (let overtimeTypeKey in overtimeType) { + d['sum' + overtimeTypeKey] = overtimeStatistic.reduce((sum, o) => { + if (o.compensate == overtimeTypeKey) { + sum += o.duration / 3600 + } + return sum + }, 0) + } }) - const fileName = `人员信息_${moment().format('YYYYMMDDHHmmss')}` + '.csv' - const filePath = await simpleExcelDown({ data: exportD, header, fileName: fileName }) + let overtimeTypeHeader = [] + let sumOvertimeTypeHeader = [] + for (let overtimeTypeKey in overtimeType) { + sumOvertimeTypeHeader.push({ + title: `合计${overtimeType[overtimeTypeKey]}加班时长(小时)`, + key: 'sum' + overtimeTypeKey, + defaultValue: 0 + }) + for (let dayTypeKey in dayType) { + overtimeTypeHeader.push({ + title: dayType[dayTypeKey] + '-' + overtimeType[overtimeTypeKey], + key: overtimeTypeKey + dayTypeKey, + defaultValue: 0 + }) + } + } + + const header = [{ + title: '员工编号', + key: 'userCode', + }, { + title: '姓名', + key: 'userName', + }, { + title: '所属部门', + key: 'departmrnt', + }, { + title: '职位', + key: 'role', + }, { + title: '加班次数(次)', + key: 'overtimeCount', + },] + .concat(overtimeTypeHeader) + .concat(sumOvertimeTypeHeader) + + const fileName = `加班统计_${startDate ? moment(startDate).format('YYYY-MM-DD') : ''}-${endDate ? moment(endDate).format('YYYY-MM-DD') : ''}_${moment().format('YYYYMMDDHHmmss')}` + '.csv' + const filePath = await simpleExcelDown({ data: returnD, header, fileName: fileName }) const fileData = fs.readFileSync(filePath); ctx.status = 200; @@ -135,7 +191,84 @@ async function vacateStatistic (ctx) { } } +async function exportVacateStatistic (ctx) { + try { + const { models } = ctx.fs.dc; + const { clickHouse } = ctx.app.fs + const { memberList, packageUserData, vacateStatisticListDayType, overtimeStatisticListDayType, simpleExcelDown, dayType, overtimeType } = ctx.app.fs.utils + const { + keywordTarget, keyword, limit, page, orderBy, orderDirection, + startDate, endDate, + } = ctx.query + + const vacateTypeRes = await clickHouse.hr.query(` + SELECT type FROM vacate GROUP BY type + `).toPromise() + + const userRes = await memberList({ + keywordTarget, keyword, limit, page, + orderBy, orderDirection, + vacateDayStatisticStartDate: startDate, + vacateDayStatisticendDate: endDate, + vacateDurationStatistic: true, + vacateCountStatistic: true, + vacateCountStatisticStartDate: startDate, + vacateCountStatisticendDate: endDate, + }) + + let { packageUser: returnD, pepUserIds } = await packageUserData(userRes) + + const sumRes = await vacateStatisticListDayType({ + startDate, endDate, pepUserIds + }) + + returnD.forEach(u => { + u.vacateStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId) + u.vacateDayStatisticDuration = (u.vacateDayStatisticDuration) || 0 / 3600 + }) + + const header = [{ + title: '员工编号', + key: 'userCode', + }, { + title: '姓名', + key: 'userName', + }, { + title: '所属部门', + key: 'departmrnt', + }, { + title: '职位', + key: 'role', + }, { + title: '合计请假次数(次)', + key: 'vacateCount', + defaultValue: 0, + }, { + title: '合计请假时长(小时)', + key: 'vacateDayStatisticDuration', + defaultValue: 0, + }] + + const fileName = `请假统计_${startDate ? moment(startDate).format('YYYY-MM-DD') : ''}-${endDate ? moment(endDate).format('YYYY-MM-DD') : ''}_${moment().format('YYYYMMDDHHmmss')}` + '.csv' + const filePath = await simpleExcelDown({ data: returnD, header, fileName: fileName }) + const fileData = fs.readFileSync(filePath); + + ctx.status = 200; + ctx.set('Content-Type', 'application/x-xls'); + ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName)); + ctx.body = fileData; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.status = 400; + ctx.body = { + message: typeof error == 'string' ? error : undefined + } + } +} + module.exports = { overtimeStatistic, + exportOvertimeStatistic, vacateStatistic, + exportVacateStatistic, }; \ No newline at end of file diff --git a/api/app/lib/routes/attendance/index.js b/api/app/lib/routes/attendance/index.js index 9448750..075c6e1 100644 --- a/api/app/lib/routes/attendance/index.js +++ b/api/app/lib/routes/attendance/index.js @@ -6,6 +6,12 @@ module.exports = function (app, router, opts) { app.fs.api.logAttr['GET/attendance/overtime'] = { content: '加班统计', visible: true }; router.get('/attendance/overtime', attendance.overtimeStatistic); + app.fs.api.logAttr['GET/attendance/overtime/export'] = { content: '加班统计导出', visible: true }; + router.get('/attendance/overtime/export', attendance.exportOvertimeStatistic); + app.fs.api.logAttr['GET/attendance/vacate'] = { content: '请假统计', visible: true }; router.get('/attendance/vacate', attendance.vacateStatistic); + + app.fs.api.logAttr['GET/attendance/vacate/export'] = { content: '请假统计导出', visible: true }; + router.get('/attendance/vacate/export', attendance.exportVacateStatistic); }; \ No newline at end of file diff --git a/api/app/lib/schedule/attendance.js b/api/app/lib/schedule/attendance.js index e0ef75d..d209a3a 100644 --- a/api/app/lib/schedule/attendance.js +++ b/api/app/lib/schedule/attendance.js @@ -330,6 +330,14 @@ module.exports = function (app, opts) { curTime = curTime.add(1, 'day').startOf('day') } + if (durationDayAddDay < durationSec) { + console.log(`请假每日持续时间之和少于认定时间,补偿之`); + // 每日持续时间比认定时间少 + if (packageDay.length) { + packageDay[packageDay.length - 1].duration += durationSec - durationDayAddDay + } + } + let typeStorage = '' if (hrAffirmType.value) { typeStorage = hrAffirmType.value @@ -477,6 +485,9 @@ module.exports = function (app, opts) { } curday = curday.add(1, 'day').startOf('day') } + + + if (packageSuccess) { const existRes = await models.Overtime.findOne({ diff --git a/api/app/lib/utils/constant.js b/api/app/lib/utils/constant.js new file mode 100644 index 0000000..8012eca --- /dev/null +++ b/api/app/lib/utils/constant.js @@ -0,0 +1,20 @@ +'use strict'; + +module.exports = function (app, opts) { + + const dayType = { + dayoff: '普假', + workday: '工作日', + festivals: '法定假', + } + + const overtimeType = { + '发放加班补偿': '折算', + '调休': '调休' + } + + return { + dayType, + overtimeType, + } +} \ No newline at end of file diff --git a/api/app/lib/utils/xlsxDownload.js b/api/app/lib/utils/xlsxDownload.js index a31df31..bcd060a 100644 --- a/api/app/lib/utils/xlsxDownload.js +++ b/api/app/lib/utils/xlsxDownload.js @@ -59,7 +59,7 @@ module.exports = function (app, opts) { indexCell.style = headerStyle for (let h of header) { const cell = row.addCell(); - cell.value = data[i][h.key]; + cell.value = data[i][h.key] || h.defaultValue || ''; cell.style = style } }