diff --git a/api/app/lib/controllers/attendance/index.js b/api/app/lib/controllers/attendance/index.js index d3d56b5..c25dcca 100644 --- a/api/app/lib/controllers/attendance/index.js +++ b/api/app/lib/controllers/attendance/index.js @@ -5,7 +5,7 @@ async function overtimeStatistic (ctx) { try { const { models } = ctx.fs.dc; const { clickHouse } = ctx.app.fs - const { judgeHoliday, memberList } = ctx.app.fs.utils + const { memberList, packageUserData, overtimeStatisticListDayType } = ctx.app.fs.utils const { keywordTarget, keyword, limit, page, orderBy, orderDirection, startDate, endDate, @@ -21,76 +21,11 @@ async function overtimeStatistic (ctx) { overtimeCountStatisticendDate: endDate, }) - let returnD = [] - let pepUserIds = [] - userRes.rows.forEach(u => { - let existUser = returnD.find(r => r.pepUserId == u.pepUserId) - if (existUser) { - if (u.depId && !existUser.departmrnt.some(d => d.id == u.depId)) { - existUser.departmrnt.push({ - id: u.depId, - name: u.depName - }) - } - if (u.roleId && !existUser.role.some(r => r.id == u.roleId)) { - existUser.role.push({ - id: u.roleId, - name: u.roleName - }) - } - } else { - let obj = {} - for (let k in u) { - let nextKey = k.replace('hrMember.', '') - .replace('member.', '') - if (nextKey.includes('_')) { - nextKey = nextKey.toLowerCase() - .replace( - /(_)[a-z]/g, - (L) => L.toUpperCase() - ) - .replace(/_/g, '') - } - obj[nextKey] = u[k] - } - pepUserIds.push(u.pepUserId) - returnD.push({ - ...obj, - departmrnt: u.depId ? [{ - id: u.depId, - name: u.depName - }] : [], - role: u.roleId ? [{ - id: u.roleId, - name: u.roleName - }] : [], - del: undefined, - pepuserid: undefined, - }) - } - }) + let { packageUser: returnD, pepUserIds } = await packageUserData(userRes) - const sumRes = await clickHouse.hr.query(` - SELECT - overtime.pep_user_id AS pepUserId, - holiday.type AS dayType, - overtime.compensate AS compensate, - sum(overtime_day.duration) AS duration - FROM overtime_day - INNER JOIN overtime - ON overtime.id = overtime_day.overtime_id - AND overtime.pep_user_id IN (${pepUserIds.join(',')}) - LEFT JOIN holiday - ON holiday.day = overtime_day.day - WHERE overtime.pep_user_id IN (${pepUserIds.join(',')}) - ${startDate ? ` - AND overtime_day.day >= '${moment(startDate).format('YYYY-MM-DD')}' - `: ''} - ${endDate ? ` - AND overtime_day.day <= '${moment(endDate).format('YYYY-MM-DD')}' - ` : ''} - GROUP BY holiday.type, overtime.compensate, overtime.pep_user_id - `).toPromise() + const sumRes = await overtimeStatisticListDayType({ + startDate, endDate, pepUserIds + }) returnD.forEach(u => { u.overtimeStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId) @@ -109,11 +44,58 @@ async function overtimeStatistic (ctx) { } } +async function exportOvertimeStatistic (ctx) { + try { + const { models } = ctx.fs.dc; + const { clickHouse } = ctx.app.fs + const { memberList, packageUserData, overtimeStatisticListDayType } = ctx.app.fs.utils + const { + keywordTarget, keyword, limit, page, orderBy, orderDirection, + startDate, endDate, + } = ctx.query + + const userRes = await memberList({ + keywordTarget, keyword, limit, page, + orderBy, orderDirection, + overtimeDayStatisticStartDate: startDate, + overtimeDayStatisticendDate: endDate, + overtimeCountStatistic: true, + overtimeCountStatisticStartDate: startDate, + overtimeCountStatisticendDate: endDate, + }) + + let { packageUser: returnD, pepUserIds } = await packageUserData(userRes) + + const sumRes = await overtimeStatisticListDayType({ + startDate, endDate, pepUserIds + }) + + returnD.forEach(u => { + u.overtimeStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId) + }) + + const fileName = `人员信息_${moment().format('YYYYMMDDHHmmss')}` + '.csv' + const filePath = await simpleExcelDown({ data: exportD, 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 + } + } +} + async function vacateStatistic (ctx) { try { const { models } = ctx.fs.dc; const { clickHouse } = ctx.app.fs - const { judgeHoliday, memberList } = ctx.app.fs.utils + const { judgeHoliday, memberList, packageUserData, vacateStatisticListDayType } = ctx.app.fs.utils const { keywordTarget, keyword, limit, page, orderBy, orderDirection, startDate, endDate, @@ -130,73 +112,11 @@ async function vacateStatistic (ctx) { vacateCountStatisticendDate: endDate, }) - let returnD = [] - let pepUserIds = [] - userRes.rows.forEach(u => { - let existUser = returnD.find(r => r.pepUserId == u.pepUserId) - if (existUser) { - if (u.depId && !existUser.departmrnt.some(d => d.id == u.depId)) { - existUser.departmrnt.push({ - id: u.depId, - name: u.depName - }) - } - if (u.roleId && !existUser.role.some(r => r.id == u.roleId)) { - existUser.role.push({ - id: u.roleId, - name: u.roleName - }) - } - } else { - let obj = {} - for (let k in u) { - let nextKey = k.replace('hrMember.', '') - .replace('member.', '') - if (nextKey.includes('_')) { - nextKey = nextKey.toLowerCase() - .replace( - /(_)[a-z]/g, - (L) => L.toUpperCase() - ) - .replace(/_/g, '') - } - obj[nextKey] = u[k] - } - pepUserIds.push(u.pepUserId) - returnD.push({ - ...obj, - departmrnt: u.depId ? [{ - id: u.depId, - name: u.depName - }] : [], - role: u.roleId ? [{ - id: u.roleId, - name: u.roleName - }] : [], - del: undefined, - pepuserid: undefined, - }) - } - }) + let { packageUser: returnD, pepUserIds } = await packageUserData(userRes) - const sumRes = await clickHouse.hr.query(` - SELECT - vacate.pep_user_id AS pepUserId, - vacate.type AS type, - sum(vacate_day.duration) AS duration - FROM vacate_day - INNER JOIN vacate - ON vacate.id = vacate_day.vacate_id - AND vacate.pep_user_id IN (${pepUserIds.join(',')}) - WHERE vacate.pep_user_id IN (${pepUserIds.join(',')}) - ${startDate ? ` - AND vacate_day.day >= '${moment(startDate).format('YYYY-MM-DD')}' - `: ''} - ${endDate ? ` - AND vacate_day.day <= '${moment(endDate).format('YYYY-MM-DD')}' - ` : ''} - GROUP BY vacate.type, vacate.pep_user_id - `).toPromise() + const sumRes = await vacateStatisticListDayType({ + startDate, endDate, pepUserIds + }) returnD.forEach(u => { u.vacateStatistic = sumRes.filter(s => s.pepUserId == u.pepUserId) diff --git a/api/app/lib/controllers/member/index.js b/api/app/lib/controllers/member/index.js index 2d887d2..79faf03 100644 --- a/api/app/lib/controllers/member/index.js +++ b/api/app/lib/controllers/member/index.js @@ -267,84 +267,21 @@ async function maritalList (ctx) { async function list (ctx) { try { const { models } = ctx.fs.dc; - const { judgeHoliday, memberList } = ctx.app.fs.utils + const { judgeHoliday, memberList, packageUserData } = ctx.app.fs.utils const { keywordTarget, keyword, limit, page, state, hiredateStart, hiredateEnd, marital, native, workPlace, orderBy, orderDirection, } = ctx.query - const curDay = moment().format('YYYY-MM-DD') - const nowTime = moment() - const holidayJudge = await judgeHoliday(curDay) - let workTime = false - let dayoffTime = false - if (holidayJudge) { - if ( - holidayJudge.workday - && nowTime.isAfter(moment(curDay + ' 08:30')) - && nowTime.isBefore(moment(curDay + ' 17:30')) - ) { - workTime = true - } else if (holidayJudge.dayoff || holidayJudge.festivals) { - dayoffTime = true - } - } const userRes = await memberList({ keywordTarget, keyword, limit, page, state, hiredateStart, hiredateEnd, marital, native, workPlace, orderBy, orderDirection, nowAttendanceTime: true }) - let returnD = [] - userRes.rows.forEach(u => { - let existUser = returnD.find(r => r.pepUserId == u.pepUserId) - if (existUser) { - if (u.depId && !existUser.departmrnt.some(d => d.id == u.depId)) { - existUser.departmrnt.push({ - id: u.depId, - name: u.depName - }) - } - if (u.roleId && !existUser.role.some(r => r.id == u.roleId)) { - existUser.role.push({ - id: u.roleId, - name: u.roleName - }) - } - } else { - let obj = {} - for (let k in u) { - let nextKey = k.replace('hrMember.', '') - .replace('member.', '') - if (nextKey.includes('_')) { - nextKey = nextKey.toLowerCase() - .replace( - /(_)[a-z]/g, - (L) => L.toUpperCase() - ) - .replace(/_/g, '') - } - obj[nextKey] = u[k] == '1970-01-01 00:00:00.000000' ? null : u[k] - } - returnD.push({ - ...obj, - departmrnt: u.depId ? [{ - id: u.depId, - name: u.depName - }] : [], - role: u.roleId ? [{ - id: u.roleId, - name: u.roleName - }] : [], - state: obj['dimissionDate'] ? 'dimission' : - obj['vacateStartTime'] ? 'vacate' : - workTime ? 'inOffice' : - dayoffTime ? 'dayoff' : 'rest', - del: undefined, - pepuserid: undefined, - }) - } + let { packageUser: returnD, pepUserIds } = await packageUserData(userRes, { + state: true, }) ctx.status = 200; @@ -371,8 +308,8 @@ async function overTimeStatistics (ctx) { const timeOption = [] if (startDate && endDate) { timeOption.push( - `wpStory.create_at <= '${moment(endDate).format('YYYY-MM-DD HH:mm:ss')}' - AND wpStory.create_at > '${moment(startDate).format('YYYY-MM-DD HH:mm:ss')}'` + `wpStory.create_at <= '${moment(endDate).endOf('day').format('YYYY-MM-DD HH:mm:ss')}' + AND wpStory.create_at >= '${moment(startDate).startOf('day').format('YYYY-MM-DD HH:mm:ss')}'` ) } const dataRes = await clickHouse.hr.query(` @@ -460,12 +397,12 @@ async function vacateStatistics (ctx) { const timeOption = [] if (startDate) { timeOption.push( - `wpStory.create_at > '${moment(startDate).format('YYYY-MM-DD HH:mm:ss')}'` + `wpStory.create_at > '${moment(startDate).startOf('day').format('YYYY-MM-DD HH:mm:ss')}'` ) } if (endDate) { timeOption.push( - `wpStory.create_at <= '${moment(endDate).format('YYYY-MM-DD HH:mm:ss')}'` + `wpStory.create_at <= '${moment(endDate).endOf('day').format('YYYY-MM-DD HH:mm:ss')}'` ) } const dataRes = await clickHouse.hr.query(` @@ -534,7 +471,7 @@ async function exportData (ctx) { try { const { models } = ctx.fs.dc; const { clickHouse, opts: { qiniu } } = ctx.app.fs - const { simpleExcelDown, memberList } = ctx.app.fs.utils + const { simpleExcelDown, memberList, packageUserData } = ctx.app.fs.utils const { keywordTarget, keyword, limit, page, state, keys = '' } = ctx.query const userRes = await memberList({ keywordTarget, keyword, limit, page, state, nowAttendanceTime: true }) @@ -542,54 +479,7 @@ async function exportData (ctx) { const tableAttributes = models['Member'].tableAttributes const optionKeys = keys.split(',') - let exportD = [] - let pepUserIds = [] - userRes.rows.forEach(u => { - let existUser = exportD.find(r => r.pepUserId == u.pepUserId) - if (existUser) { - if (u.depId && !existUser.departmrnt.some(d => d.id == u.depId)) { - existUser.departmrnt.push({ - id: u.depId, - name: u.depName - }) - } - if (u.roleId && !existUser.role.some(r => r.id == u.roleId)) { - existUser.role.push({ - id: u.roleId, - name: u.roleName - }) - } - } else { - let obj = {} - for (let k in u) { - let nextKey = k.replace('hrMember.', '') - .replace('member.', '') - if (nextKey.includes('_')) { - nextKey = nextKey.toLowerCase() - .replace( - /(_)[a-z]/g, - (L) => L.toUpperCase() - ) - .replace(/_/g, '') - } - obj[nextKey] = u[k] == '1970-01-01 00:00:00.000000' ? null : u[k] - } - pepUserIds.push(u.pepUserId) - exportD.push({ - ...obj, - departmrnt: u.depId ? [{ - id: u.depId, - name: u.depName - }] : [], - role: u.roleId ? [{ - id: u.roleId, - name: u.roleName - }] : [], - del: undefined, - pepuserid: undefined - }) - } - }) + let { packageUser: exportD, pepUserIds } = await packageUserData(userRes) let preHeader = [{ title: '姓名', diff --git a/api/app/lib/utils/attendance.js b/api/app/lib/utils/attendance.js new file mode 100644 index 0000000..03aac20 --- /dev/null +++ b/api/app/lib/utils/attendance.js @@ -0,0 +1,68 @@ +'use strict'; +const moment = require('moment') +const request = require('superagent'); + +module.exports = function (app, opts) { + + async function overtimeStatisticListDayType ({ + startDate, endDate, pepUserIds = [] + }) { + const { clickHouse } = app.fs + + const sumRes = await clickHouse.hr.query(` + SELECT + overtime.pep_user_id AS pepUserId, + holiday.type AS dayType, + overtime.compensate AS compensate, + sum(overtime_day.duration) AS duration + FROM overtime_day + INNER JOIN overtime + ON overtime.id = overtime_day.overtime_id + AND overtime.pep_user_id IN (${pepUserIds.join(',')}) + LEFT JOIN holiday + ON holiday.day = overtime_day.day + WHERE overtime.pep_user_id IN (${pepUserIds.join(',')}) + ${startDate ? ` + AND overtime_day.day >= '${moment(startDate).format('YYYY-MM-DD')}' + `: ''} + ${endDate ? ` + AND overtime_day.day <= '${moment(endDate).format('YYYY-MM-DD')}' + ` : ''} + GROUP BY holiday.type, overtime.compensate, overtime.pep_user_id + `).toPromise() + + return sumRes + } + + async function vacateStatisticListDayType ({ + startDate, endDate, pepUserIds = [] + }) { + const { clickHouse } = app.fs + + const sumRes = await clickHouse.hr.query(` + SELECT + vacate.pep_user_id AS pepUserId, + vacate.type AS type, + sum(vacate_day.duration) AS duration + FROM vacate_day + INNER JOIN vacate + ON vacate.id = vacate_day.vacate_id + AND vacate.pep_user_id IN (${pepUserIds.join(',')}) + WHERE vacate.pep_user_id IN (${pepUserIds.join(',')}) + ${startDate ? ` + AND vacate_day.day >= '${moment(startDate).format('YYYY-MM-DD')}' + `: ''} + ${endDate ? ` + AND vacate_day.day <= '${moment(endDate).format('YYYY-MM-DD')}' + ` : ''} + GROUP BY vacate.type, vacate.pep_user_id + `).toPromise() + + return sumRes + } + + return { + overtimeStatisticListDayType, + vacateStatisticListDayType, + } +} \ No newline at end of file diff --git a/api/app/lib/utils/member.js b/api/app/lib/utils/member.js index 40673be..d67295d 100644 --- a/api/app/lib/utils/member.js +++ b/api/app/lib/utils/member.js @@ -324,7 +324,87 @@ module.exports = function (app, opts) { } } + async function packageUserData (userRes, option = {}) { + + const { judgeHoliday, } = app.fs.utils + let workTime = false + let dayoffTime = false + if (option.state) { + const curDay = moment().format('YYYY-MM-DD') + const nowTime = moment() + const holidayJudge = await judgeHoliday(curDay) + if (holidayJudge) { + if ( + holidayJudge.workday + && nowTime.isAfter(moment(curDay + ' 08:30')) + && nowTime.isBefore(moment(curDay + ' 17:30')) + ) { + workTime = true + } else if (holidayJudge.dayoff || holidayJudge.festivals) { + dayoffTime = true + } + } + } + + let returnD = [] + let pepUserIds = [] + userRes.rows.forEach(u => { + let existUser = returnD.find(r => r.pepUserId == u.pepUserId) + if (existUser) { + if (u.depId && !existUser.departmrnt.some(d => d.id == u.depId)) { + existUser.departmrnt.push({ + id: u.depId, + name: u.depName + }) + } + if (u.roleId && !existUser.role.some(r => r.id == u.roleId)) { + existUser.role.push({ + id: u.roleId, + name: u.roleName + }) + } + } else { + let obj = {} + for (let k in u) { + let nextKey = k.replace('hrMember.', '') + .replace('member.', '') + if (nextKey.includes('_')) { + nextKey = nextKey.toLowerCase() + .replace( + /(_)[a-z]/g, + (L) => L.toUpperCase() + ) + .replace(/_/g, '') + } + obj[nextKey] = u[k] == '1970-01-01 00:00:00.000000' ? null : u[k] + } + pepUserIds.push(u.pepUserId) + returnD.push({ + ...obj, + departmrnt: u.depId ? [{ + id: u.depId, + name: u.depName + }] : [], + role: u.roleId ? [{ + id: u.roleId, + name: u.roleName + }] : [], + state: option.state ? + obj['dimissionDate'] ? 'dimission' : + obj['vacateStartTime'] ? 'vacate' : + workTime ? 'inOffice' : + dayoffTime ? 'dayoff' : 'rest' + : undefined, + del: undefined, + pepuserid: undefined + }) + } + }) + return { packageUser: returnD, pepUserIds } + } + return { - memberList + memberList, + packageUserData } } \ No newline at end of file