diff --git a/api/app/lib/controllers/attendance/index.js b/api/app/lib/controllers/attendance/index.js new file mode 100644 index 0000000..c25dcca --- /dev/null +++ b/api/app/lib/controllers/attendance/index.js @@ -0,0 +1,141 @@ +'use strict'; +const moment = require('moment') + +async function overtimeStatistic (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) + }) + ctx.status = 200; + ctx.body = { + count: userRes.count, + rows: returnD + } + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { + message: typeof error == 'string' ? error : undefined + } + } +} + +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, packageUserData, vacateStatisticListDayType } = 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, + 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) + }) + ctx.status = 200; + ctx.body = { + count: userRes.count, + rows: returnD + } + } 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, + vacateStatistic, +}; \ No newline at end of file diff --git a/api/app/lib/controllers/member/index.js b/api/app/lib/controllers/member/index.js index 5235fc0..bd5af13 100644 --- a/api/app/lib/controllers/member/index.js +++ b/api/app/lib/controllers/member/index.js @@ -37,7 +37,7 @@ async function add (ctx) { ctx.status = 204; } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -77,7 +77,7 @@ async function edit (ctx) { ctx.status = 204; } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -161,7 +161,7 @@ async function searchPepMember (ctx) { ctx.status = 200; ctx.body = returnD } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -184,7 +184,7 @@ async function del (ctx) { ctx.status = 204; } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -208,7 +208,7 @@ async function nativePlaceList (ctx) { ctx.status = 200; ctx.body = nRes } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -232,7 +232,7 @@ async function workPlaceList (ctx) { ctx.status = 200; ctx.body = wRes } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -256,7 +256,7 @@ async function maritalList (ctx) { ctx.status = 200; ctx.body = mRes } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -267,82 +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 + 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 + 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; @@ -351,7 +290,7 @@ async function list (ctx) { rows: returnD } } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -369,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(` @@ -440,7 +379,7 @@ async function overTimeStatistics (ctx) { ctx.status = 200; ctx.body = returnD } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -458,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(` @@ -520,7 +459,7 @@ async function vacateStatistics (ctx) { ctx.status = 200; ctx.body = returnD } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined @@ -532,62 +471,15 @@ 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 }) + const userRes = await memberList({ keywordTarget, keyword, limit, page, state, nowAttendanceTime: true }) 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: '姓名', @@ -668,7 +560,7 @@ async function exportData (ctx) { ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName)); ctx.body = fileData; } catch (error) { - ctx.fs.logger.error(`path: ${ctx.path}, error: error`); + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined diff --git a/api/app/lib/models/member.js b/api/app/lib/models/member.js index 3171167..910bad5 100644 --- a/api/app/lib/models/member.js +++ b/api/app/lib/models/member.js @@ -2,213 +2,213 @@ 'use strict'; module.exports = dc => { - const DataTypes = dc.ORM; - const sequelize = dc.orm; - const Member = sequelize.define("member", { - pepUserId: { - type: DataTypes.INTEGER, - allowNull: false, - defaultValue: null, - comment: "项企用户id", - primaryKey: true, - field: "pep_user_id", - autoIncrement: false, - unique: "member_pep_user_id_uindex" - }, - idNumber: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "证件号", - primaryKey: false, - field: "id_number", - autoIncrement: false - }, - idPhoto: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "证件照", - primaryKey: false, - field: "id_photo", - autoIncrement: false - }, - gender: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "性别", - primaryKey: false, - field: "gender", - autoIncrement: false - }, - birthday: { - type: DataTypes.DATEONLY, - allowNull: true, - defaultValue: null, - comment: "出生年月", - primaryKey: false, - field: "birthday", - autoIncrement: false - }, - nativePlace: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "籍贯", - primaryKey: false, - field: "native_place", - autoIncrement: false - }, - marital: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "婚育状态", - primaryKey: false, - field: "marital", - autoIncrement: false - }, - politicsStatus: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "整治面貌", - primaryKey: false, - field: "politics_status", - autoIncrement: false - }, - phoneNumber: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "phone_number", - autoIncrement: false - }, - workPlace: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "工作地点", - primaryKey: false, - field: "work_place", - autoIncrement: false - }, - graduatedFrom: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "毕业院校", - primaryKey: false, - field: "graduated_from", - autoIncrement: false - }, - educationBackground: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "学历", - primaryKey: false, - field: "education_background", - autoIncrement: false - }, - specialty: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "专业", - primaryKey: false, - field: "specialty", - autoIncrement: false - }, - graduationDate: { - type: DataTypes.DATEONLY, - allowNull: true, - defaultValue: null, - comment: "毕业时间", - primaryKey: false, - field: "graduation_date", - autoIncrement: false - }, - hiredate: { - type: DataTypes.DATEONLY, - allowNull: true, - defaultValue: null, - comment: "入职时间", - primaryKey: false, - field: "hiredate", - autoIncrement: false - }, - turnProbationPeriod: { - type: DataTypes.DATEONLY, - allowNull: true, - defaultValue: null, - comment: "转试用期时间", - primaryKey: false, - field: "turn_probation_period", - autoIncrement: false - }, - regularDate: { - type: DataTypes.DATEONLY, - allowNull: true, - defaultValue: null, - comment: "转正时间", - primaryKey: false, - field: "regular_date", - autoIncrement: false - }, - dimissionDate: { - type: DataTypes.DATEONLY, - allowNull: true, - defaultValue: null, - comment: "离职时间", - primaryKey: false, - field: "dimission_date", - autoIncrement: false - }, - experienceYear: { - type: DataTypes.DOUBLE, - allowNull: true, - defaultValue: null, - comment: "工作经验/年", - primaryKey: false, - field: "experience_year", - autoIncrement: false - }, - occupationalHistory: { - type: DataTypes.TEXT, - allowNull: true, - defaultValue: null, - comment: "工作经历", - primaryKey: false, - field: "occupational_history", - autoIncrement: false - }, - vitae: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: "简历", - primaryKey: false, - field: "vitae", - autoIncrement: false - }, - del: { - type: DataTypes.BOOLEAN, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "del", - autoIncrement: false - } - }, { - tableName: "member", - comment: "", - indexes: [] - }); - dc.models.Member = Member; - return Member; + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const Member = sequelize.define("member", { + pepUserId: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: "项企用户id", + primaryKey: true, + field: "pep_user_id", + autoIncrement: false, + unique: "member_pep_user_id_uindex" + }, + idNumber: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "证件号", + primaryKey: false, + field: "id_number", + autoIncrement: false + }, + idPhoto: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "证件照", + primaryKey: false, + field: "id_photo", + autoIncrement: false + }, + gender: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "性别", + primaryKey: false, + field: "gender", + autoIncrement: false + }, + birthday: { + type: DataTypes.DATEONLY, + allowNull: true, + defaultValue: null, + comment: "出生年月", + primaryKey: false, + field: "birthday", + autoIncrement: false + }, + nativePlace: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "籍贯", + primaryKey: false, + field: "native_place", + autoIncrement: false + }, + marital: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "婚育状态", + primaryKey: false, + field: "marital", + autoIncrement: false + }, + politicsStatus: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "整治面貌", + primaryKey: false, + field: "politics_status", + autoIncrement: false + }, + phoneNumber: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: '联系方式', + primaryKey: false, + field: "phone_number", + autoIncrement: false + }, + workPlace: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "工作地点", + primaryKey: false, + field: "work_place", + autoIncrement: false + }, + graduatedFrom: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "毕业院校", + primaryKey: false, + field: "graduated_from", + autoIncrement: false + }, + educationBackground: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "学历", + primaryKey: false, + field: "education_background", + autoIncrement: false + }, + specialty: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "专业", + primaryKey: false, + field: "specialty", + autoIncrement: false + }, + graduationDate: { + type: DataTypes.DATEONLY, + allowNull: true, + defaultValue: null, + comment: "毕业时间", + primaryKey: false, + field: "graduation_date", + autoIncrement: false + }, + hiredate: { + type: DataTypes.DATEONLY, + allowNull: true, + defaultValue: null, + comment: "入职时间", + primaryKey: false, + field: "hiredate", + autoIncrement: false + }, + turnProbationPeriod: { + type: DataTypes.DATEONLY, + allowNull: true, + defaultValue: null, + comment: "转试用期时间", + primaryKey: false, + field: "turn_probation_period", + autoIncrement: false + }, + regularDate: { + type: DataTypes.DATEONLY, + allowNull: true, + defaultValue: null, + comment: "转正时间", + primaryKey: false, + field: "regular_date", + autoIncrement: false + }, + dimissionDate: { + type: DataTypes.DATEONLY, + allowNull: true, + defaultValue: null, + comment: "离职时间", + primaryKey: false, + field: "dimission_date", + autoIncrement: false + }, + experienceYear: { + type: DataTypes.DOUBLE, + allowNull: true, + defaultValue: null, + comment: "工作经验/年", + primaryKey: false, + field: "experience_year", + autoIncrement: false + }, + occupationalHistory: { + type: DataTypes.TEXT, + allowNull: true, + defaultValue: null, + comment: "工作经历", + primaryKey: false, + field: "occupational_history", + autoIncrement: false + }, + vitae: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "简历", + primaryKey: false, + field: "vitae", + autoIncrement: false + }, + del: { + type: DataTypes.BOOLEAN, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "del", + autoIncrement: false + } + }, { + tableName: "member", + comment: "", + indexes: [] + }); + dc.models.Member = Member; + return Member; }; \ No newline at end of file diff --git a/api/app/lib/routes/attendance/index.js b/api/app/lib/routes/attendance/index.js new file mode 100644 index 0000000..9448750 --- /dev/null +++ b/api/app/lib/routes/attendance/index.js @@ -0,0 +1,11 @@ +'use strict'; + +const attendance = require('../../controllers/attendance'); + +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/vacate'] = { content: '请假统计', visible: true }; + router.get('/attendance/vacate', attendance.vacateStatistic); +}; \ No newline at end of file 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 85d353d..d67295d 100644 --- a/api/app/lib/utils/member.js +++ b/api/app/lib/utils/member.js @@ -6,7 +6,13 @@ module.exports = function (app, opts) { async function memberList ({ keywordTarget, keyword, limit, page, state, - hiredateStart, hiredateEnd, marital, native, workPlace + hiredateStart, hiredateEnd, marital, native, workPlace, + orderBy, orderDirection, + nowAttendanceTime, + overtimeDayStatisticStartDate, overtimeDayStatisticendDate, + overtimeCountStatistic, overtimeCountStatisticStartDate, overtimeCountStatisticendDate, + vacateDayStatisticStartDate, vacateDayStatisticendDate, + vacateDurationStatistic, vacateCountStatistic, vacateCountStatisticStartDate, vacateCountStatisticendDate }) { const { judgeHoliday } = app.fs.utils const { clickHouse } = app.fs @@ -58,43 +64,141 @@ module.exports = function (app, opts) { } } + let overtimeDayStatisticWhere = [] + if (overtimeDayStatisticStartDate) { + overtimeDayStatisticWhere.push(`overtime_day.day >= '${moment(overtimeDayStatisticStartDate).format('YYYY-MM-DD')}'`) + } + if (overtimeDayStatisticendDate) { + overtimeDayStatisticWhere.push(`overtime_day.day <= '${moment(overtimeDayStatisticendDate).format('YYYY-MM-DD')}'`) + } + + let overtimeCountStatisticWhere = [] + if (overtimeCountStatisticStartDate) { + overtimeCountStatisticWhere.push(`overtime.start_time >= '${moment(overtimeCountStatisticStartDate).format('YYYY-MM-DD')}'`) + } + if (overtimeCountStatisticendDate) { + overtimeCountStatisticWhere.push(`overtime.end_time <= '${moment(overtimeCountStatisticendDate).format('YYYY-MM-DD')}'`) + } + + let vacateDayStatisticWhere = [] + if (vacateDayStatisticStartDate) { + vacateDayStatisticWhere.push(`vacate_day.day >= '${moment(vacateDayStatisticStartDate).format('YYYY-MM-DD')}'`) + } + if (vacateDayStatisticendDate) { + vacateDayStatisticWhere.push(`vacate_day.day <= '${moment(vacateDayStatisticendDate).format('YYYY-MM-DD')}'`) + } + + let vacateCountStatisticWhere = [] + if (vacateCountStatisticStartDate) { + vacateCountStatisticWhere.push(`vacate.start_time >= '${moment(vacateCountStatisticStartDate).format('YYYY-MM-DD')}'`) + } + if (vacateCountStatisticendDate) { + vacateCountStatisticWhere.push(`vacate.end_time <= '${moment(vacateCountStatisticendDate).format('YYYY-MM-DD')}'`) + } + // CRAZY const innerSelectQuery = ` FROM member INNER JOIN ${pepEmis}.user AS user ON member.pep_user_id = user.id ${keywordTarget == 'number' && keyword ? ` - AND toString(user.id) LIKE '%${keyword}%' + AND user.people_code LIKE '%${keyword}%' `: ''} ${keywordTarget == 'name' && keyword ? ` AND user.name LIKE '%${keyword}%' `: ''} - ${state == 'vacate' ? 'INNER' : 'LEFT'} JOIN ( - SELECT - pep_user_id, - any(start_time) AS vacateStartTime, - any(end_time) AS vacateEndTime - FROM vacate - WHERE - start_time <= '${nowTime.format('YYYY-MM-DD HH:mm:ss')}' - AND end_time > '${nowTime.format('YYYY-MM-DD HH:mm:ss')}' - GROUP BY pep_user_id - ) AS hrVacate - ON hrVacate.pep_user_id = member.pep_user_id - - LEFT JOIN ( - SELECT - pep_user_id, - any(start_time) AS overtimeStartTime, - any(end_time) AS overtimeEndTime - FROM overtime - WHERE - start_time <= '${nowTime.format('YYYY-MM-DD HH:mm:ss')}' - AND end_time > '${nowTime.format('YYYY-MM-DD HH:mm:ss')}' - GROUP BY pep_user_id - ) AS hrOvertime - ON hrOvertime.pep_user_id = member.pep_user_id - - WHERE + + ${nowAttendanceTime ? ` + ${state == 'vacate' ? 'INNER' : 'LEFT'} JOIN ( + SELECT + pep_user_id, + any(start_time) AS vacateStartTime, + any(end_time) AS vacateEndTime + FROM vacate + WHERE + start_time <= '${nowTime.format('YYYY-MM-DD HH:mm:ss')}' + AND end_time > '${nowTime.format('YYYY-MM-DD HH:mm:ss')}' + GROUP BY pep_user_id + ) AS hrVacate + ON hrVacate.pep_user_id = member.pep_user_id + `: ''} + ${nowAttendanceTime ? ` + LEFT JOIN ( + SELECT + pep_user_id, + any(start_time) AS overtimeStartTime, + any(end_time) AS overtimeEndTime + FROM overtime + WHERE + start_time <= '${nowTime.format('YYYY-MM-DD HH:mm:ss')}' + AND end_time > '${nowTime.format('YYYY-MM-DD HH:mm:ss')}' + GROUP BY pep_user_id + ) AS hrOvertime + ON hrOvertime.pep_user_id = member.pep_user_id + `: ''} + + ${orderBy == 'overtimeTakeRestSum' || + orderBy == 'overtimePaySum' || + orderBy == 'overtimeSum' ? + `LEFT JOIN ( + SELECT + overtime.pep_user_id AS pepUserId, + sum(overtime_day.duration) AS duration + FROM overtime_day + INNER JOIN overtime + ON overtime.id = overtime_day.overtime_id + ${orderBy == 'overtimeTakeRestSum' ? `AND overtime.compensate = '调休'` : ''} + ${orderBy == 'overtimePaySum' ? `AND overtime.compensate = '发放加班补偿'` : ''} + ${overtimeDayStatisticWhere.length ? ` + WHERE ${overtimeDayStatisticWhere.join(' AND ')} + `: ''} + GROUP BY overtime.pep_user_id + ) AS overtimeDayStatistic + ON overtimeDayStatistic.pepUserId = member.pep_user_id`: ''} + + ${overtimeCountStatistic ? ` + LEFT JOIN ( + SELECT + overtime.pep_user_id AS pepUserId, + count(pep_process_story_id) AS count + FROM overtime + ${overtimeCountStatisticWhere.length ? ` + WHERE ${overtimeCountStatisticWhere.join(' AND ')} + `: ''} + GROUP BY overtime.pep_user_id + ) AS overtimeCountStatistic + ON overtimeCountStatistic.pepUserId = member.pep_user_id + `: ''} + + ${vacateDurationStatistic || + orderBy == 'vacateSum' ? + `LEFT JOIN ( + SELECT + vacate.pep_user_id AS pepUserId, + sum(vacate_day.duration) AS duration + FROM vacate_day + INNER JOIN vacate + ON vacate.id = vacate_day.vacate_id + ${vacateDayStatisticWhere.length ? ` + WHERE ${vacateDayStatisticWhere.join(' AND ')} + `: ''} + GROUP BY vacate.pep_user_id + ) AS vacateDayStatistic + ON vacateDayStatistic.pepUserId = member.pep_user_id`: ''} + + ${vacateCountStatistic ? ` + LEFT JOIN ( + SELECT + vacate.pep_user_id AS pepUserId, + count(pep_process_story_id) AS count + FROM vacate + ${vacateCountStatisticWhere.length ? ` + WHERE ${vacateCountStatisticWhere.join(' AND ')} + `: ''} + GROUP BY vacate.pep_user_id + ) AS vacateCountStatistic + ON vacateCountStatistic.pepUserId = member.pep_user_id + `: ''} + WHERE member.del = 0 ${keywordTarget == 'role' && keyword ? ` AND user.id IN ( @@ -116,7 +220,7 @@ module.exports = function (app, opts) { ` : ''} ${state == 'dimission' ? `AND member.dimission_date IS NOT null` : ''} ${state == 'onJob' ? `AND member.dimission_date IS null` : ''} - ${whereFromSelectOption.length ? `AND ${whereFromSelectOption.join('AND')}` : ''} + ${whereFromSelectOption.length && nowAttendanceTime ? `AND ${whereFromSelectOption.join('AND')}` : ''} ${hiredateStart ? ` AND member.hiredate >= '${moment(hiredateStart).format('YYYY-MM-DD')}' `: ''} @@ -146,18 +250,39 @@ module.exports = function (app, opts) { department.id AS depId FROM ( SELECT - member.*, - hrVacate.vacateStartTime AS vacateStartTime, - hrVacate.vacateEndTime AS vacateEndTime, - hrOvertime.overtimeStartTime AS overtimeStartTime, - hrOvertime.overtimeEndTime AS overtimeEndTime + ${orderBy == 'overtimeTakeRestSum' + || orderBy == 'overtimePaySum' + || orderBy == 'overtimeSum' ? ` + overtimeDayStatistic.duration AS overtimeDayStatisticDuration + `: ''} + + ${overtimeCountStatistic ? ` + overtimeCountStatistic.count AS overtimeCount, + `: ''} + + ${orderBy == 'vacateSum' || vacateDurationStatistic ? ` + vacateDayStatistic.duration AS vacateDayStatisticDuration, + `: ''} + + ${vacateCountStatistic ? ` + vacateCountStatistic.count AS vacateCount, + `: ''} + + ${nowAttendanceTime ? ` + hrVacate.vacateStartTime AS vacateStartTime, + hrVacate.vacateEndTime AS vacateEndTime, + hrOvertime.overtimeStartTime AS overtimeStartTime, + hrOvertime.overtimeEndTime AS overtimeEndTime, + `: ''} + + member.* ${innerSelectQuery} ${limit ? `LIMIT ${limit}` : ''} ${limit && page ? 'OFFSET ' + parseInt(limit) * parseInt(page) : ''} ) AS hrMember LEFT JOIN ${pepEmis}.user AS user - ON hrMember."member.pep_user_id" = user.id + ON pepUserId = user.id LEFT JOIN ${pepEmis}.user_role AS user_role ON ${pepEmis}.user_role.user = user.id LEFT JOIN ${pepEmis}.role AS role @@ -167,12 +292,30 @@ module.exports = function (app, opts) { LEFT JOIN ${pepEmis}.department AS department ON department.id = department_user.department ${whereOption.length ? `WHERE ${whereOption.join(' AND ')}` : ''} + ORDER BY ${orderBy == 'code' ? + 'user.people_code' + : orderBy == 'hiredate' + ? 'hrMember."member.hiredate"' + : orderBy == 'age' + ? 'hrMember."member.birthday"' + : orderBy == 'overtimeTakeRestSum' + || orderBy == 'overtimePaySum' + || orderBy == 'overtimeSum' ? + 'hrMember."member.overtimeDayStatisticDuration"' + : orderBy == 'overtimeCount' ? + 'hrMember.overtimeCount' + : orderBy == 'vacateSum' ? + 'hrMember.vacateDayStatisticDuration' + : orderBy == 'vacateCount' ? + 'hrMember.vacateCount' + : 'user.people_code'} + ${orderDirection || 'ASC'} `).toPromise() const countRes = await clickHouse.hr.query(` SELECT - count(member.pep_user_id) AS count - ${innerSelectQuery} + count(member.pep_user_id) AS count + ${innerSelectQuery} `).toPromise() return { @@ -181,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 diff --git a/web/client/assets/images/hrImg/!.png b/web/client/assets/images/hrImg/!.png new file mode 100644 index 0000000..f9c334f Binary files /dev/null and b/web/client/assets/images/hrImg/!.png differ diff --git a/web/client/assets/images/hrImg/V.png b/web/client/assets/images/hrImg/V.png new file mode 100644 index 0000000..fd5a097 Binary files /dev/null and b/web/client/assets/images/hrImg/V.png differ diff --git a/web/client/assets/images/hrImg/setUp.png b/web/client/assets/images/hrImg/setUp.png new file mode 100644 index 0000000..ea73217 Binary files /dev/null and b/web/client/assets/images/hrImg/setUp.png differ diff --git a/web/client/index.ejs b/web/client/index.ejs index 54e5c56..49ff0b5 100644 --- a/web/client/index.ejs +++ b/web/client/index.ejs @@ -9,7 +9,7 @@ - + diff --git a/web/client/index.html b/web/client/index.html index b4cac35..cba0f37 100644 --- a/web/client/index.html +++ b/web/client/index.html @@ -2,23 +2,23 @@ - - + + - + - - + + -
+
- - + + - - + - + - + \ No newline at end of file diff --git a/web/client/src/components/setup.jsx b/web/client/src/components/setup.jsx index c4cd070..41d8792 100644 --- a/web/client/src/components/setup.jsx +++ b/web/client/src/components/setup.jsx @@ -1,124 +1,123 @@ import React, { useState, useEffect } from "react"; import { - Modal, - CheckboxGroup, - Checkbox, + Modal, + CheckboxGroup, + Checkbox, } from "@douyinfe/semi-ui"; -function Setup(props) { - const { - close, - tableType, - tableList - } = props; +function Setup (props) { + const { + close, + tableType, + tableList, + length + } = props; + const [check, setCheck] = useState([]); - console.log(tableType, - tableList); - const [check, setCheck] = useState([]); - - const checkboxcss = { width: "25%", height: 16, margin: "0 0 20px 0" }; + const checkboxcss = { width: "25%", height: 16, margin: "0 0 20px 0" }; - useEffect(() => { - //获取是否勾选信息 - const checkItem = localStorage.getItem(tableType); - setCheck(checkItem?JSON.parse(checkItem) : []) - ischeck(); - }, []); - function ischeck(value) { - if (check.length >= 8) { - if (check.includes(value)) { - return false; - } else { - return true; - } + useEffect(() => { + //获取是否勾选信息 + const checkItem = localStorage.getItem(tableType); + setCheck(checkItem ? JSON.parse(checkItem) : []) + ischeck(); + }, []); + function ischeck (value) { + if (check.length >= length) { + if (check.includes(value)) { + return false; + } else { + return true; + } + } } - } - return ( - - 表格属性设置 - + 表格属性设置 + + {check.length}/{length} + + + } + visible={true} + style={{ width: 600 }} + onOk={() => { + localStorage.setItem(tableType, JSON.stringify(check)); + close(); }} - > - {check.length}/8 - - - } - visible={true} - style={{ width: 600 }} - onOk={() => { - localStorage.setItem(tableType, JSON.stringify(check)); - close(); - }} - onCancel={() => { - close(); - }} - > - { - setCheck(check); - ischeck(); - }} - > - {tableList.map((item,index)=>{ - return( -
{ + close(); }} + > + { + setCheck(check); + ischeck(); + }} > -
- {item.title} -
-
- {item.list?.map((itm) => { + {tableList.map((item, index) => { return ( - - {itm.name} - - ); - })} -
-
- )})} -
-
- ); +
+ {item.title} +
+
+ {item.list?.map((itm) => { + return ( + + {itm.name} + + ); + })} +
+ + ) + })} + + + ); } export default Setup; diff --git a/web/client/src/sections/humanAffairs/actions/employeeInformation.js b/web/client/src/sections/humanAffairs/actions/employeeInformation.js new file mode 100644 index 0000000..419449d --- /dev/null +++ b/web/client/src/sections/humanAffairs/actions/employeeInformation.js @@ -0,0 +1,26 @@ +'use strict'; + +import { ApiTable, basicAction } from '$utils' + +export function getMemberNativePlace(query) {//查询籍贯列表 + return (dispatch) => basicAction({ + type: "get", + dispatch: dispatch, + actionType: "GET_MemberNativePlace", + query: query, + url: `${ApiTable.getMemberNativePlace}`, + msg: { option: "查询籍贯列表" }, + reducer: { name: "MemberNativePlace", params: { noClear: true } }, + }); +} +export function getMemberWorkPlace(query) {//查询工作地列表 + return (dispatch) => basicAction({ + type: "get", + dispatch: dispatch, + actionType: "GET_MemberWorkPlace", + query: query, + url: `${ApiTable.getMemberWorkPlace}`, + msg: { option: "查询工作地列表" }, + reducer: { name: "MemberWorkPlace", params: { noClear: true } }, + }); +} \ No newline at end of file diff --git a/web/client/src/sections/humanAffairs/actions/index.js b/web/client/src/sections/humanAffairs/actions/index.js index b996305..f2d429b 100644 --- a/web/client/src/sections/humanAffairs/actions/index.js +++ b/web/client/src/sections/humanAffairs/actions/index.js @@ -1,6 +1,9 @@ 'use strict'; import * as personnelFiles from './personnelFiles' +import * as employeeInformation from './employeeInformation' + export default { ...personnelFiles, + ...employeeInformation } \ No newline at end of file diff --git a/web/client/src/sections/humanAffairs/components/personnelModal.jsx b/web/client/src/sections/humanAffairs/components/personnelModal.jsx index b8760bc..5769d4b 100644 --- a/web/client/src/sections/humanAffairs/components/personnelModal.jsx +++ b/web/client/src/sections/humanAffairs/components/personnelModal.jsx @@ -93,7 +93,7 @@ function pushModal (props) { form.current .validate() .then((values) => { - if (peoplePro.userCode) { + if (peoplePro?.userCode) { if (values.userCode == peoplePro.userCode) { let obj = values if (values.nativePlace) { @@ -187,7 +187,9 @@ function pushModal (props) { rules={[{ required: true, message: "请输入人员编号" }]} />
{ let formList = form.current.getValues() - memberSeach(formList.userCode) + if(formList.userCode){ + memberSeach(formList.userCode) + } }}> 搜索
@@ -328,7 +330,7 @@ function pushModal (props) { label='籍贯:' showClear style={{ width: 184 }} - initValue={editObj?.nativePlace.split('-') || ""} + initValue={editObj?.nativePlace?.split('-') || ""} > @@ -371,7 +373,7 @@ function pushModal (props) { field='workPlace' label='工作地点:' showClear - initValue={editObj?.workPlace.split('-') || ""} + initValue={editObj?.workPlace?.split('-') || ""} style={{ width: 184 }} > @@ -547,7 +549,7 @@ function pushModal (props) { label='工作经验:' maxLength="2" style={{ width: 288 }} - initValue={editObj?.experienceYear || ""} + initValue={String(editObj?.experienceYear) || ""} placeholder="请输入工作经验,不超过2位数字" showClear rules={[{ pattern: "^[0-9]*[1-9][0-9]*$", message: "请输入工作经验,不超过2位数字" },]} diff --git a/web/client/src/sections/humanAffairs/containers/employeeInformation.jsx b/web/client/src/sections/humanAffairs/containers/employeeInformation.jsx new file mode 100644 index 0000000..740704c --- /dev/null +++ b/web/client/src/sections/humanAffairs/containers/employeeInformation.jsx @@ -0,0 +1,432 @@ +import React, { useEffect, useState, useRef } from 'react'; +import { connect } from 'react-redux'; +import { Table, Button, Pagination, Skeleton, Form, Tooltip } from '@douyinfe/semi-ui'; +import { IconSearch } from '@douyinfe/semi-icons'; +import { SkeletonScreen } from "$components"; +import '../style.less' +import { Setup } from "$components"; +import moment from 'moment' +import { set } from 'nprogress'; + +const employeeInformation = (props) => { + const { dispatch, actions, history, user, loading, socket, xqMembers } = props + + const { humanAffairs } = actions; + + const form = useRef();//表单 + let [archivesList, setArchivesList] = useState([]);//人员列表 + let [workPlaceList, setWorkPlaceList] = useState([]);//工作地点 + let [nativeList, setNativeList] = useState([]);//户籍地 + + const [setup, setSetup] = useState(false);//表格设置是否显现 + const [setupp, setSetupp] = useState([]);//实际显示的表格列表 + const [query, setQuery] = useState({ limit: 10, page: 0 }); //页码信息 + const [limits, setLimits] = useState()//每页实际条数 + + const EMPLOYEEINFORMATION = "employeeInformation"; + const tableList = [//表格属性 + { + title: '基础信息', + list: [ + { name: "员工编号", value: "userCode" }, + { name: "姓名", value: "userName" }, + { name: "所属部门", value: "departmrnt" }, + // { name: "监听设备数量", value: "monitorCount" }, + // { name: "累计推送次数", value: "logCount" }, + ] + } + ]; + useEffect(() => { + getMemberNativePlaceList()//查询籍贯列表 + getMemberWorkPlaceList()//查询工作地列表 + getMemberSearchList()//查询人员列表 + attribute(); + localStorage.getItem(EMPLOYEEINFORMATION) == null + ? localStorage.setItem( + EMPLOYEEINFORMATION, + JSON.stringify(['userCode', 'userName', 'departmrnt']) + ) + : ""; + }, []) + + function getMemberSearchList () {//查询人员列表 + let obj = form.current.getValues() + if (form.current.getValues().entryTime?.length > 1) { + obj.hiredateStart = moment(form.current.getValues().entryTime[0]).format('YYYY-MM-DD') + obj.hiredateEnd = moment(form.current.getValues().entryTime[1]).format('YYYY-MM-DD') + } + else { + obj.hiredateStart = '' + obj.hiredateEnd = '' + } + setQuery({ limit: 10, page: 0 }) + dispatch(humanAffairs.getMemberList({ ...obj, ...query })).then((res) => {//查询人员列表 + if (res.success) { + setArchivesList(res.payload?.data?.rows) + setLimits(res.payload?.data?.count) + } + }) + } + function getMemberNativePlaceList () { + dispatch(humanAffairs.getMemberNativePlace()).then((res) => {//查询籍贯列表 + if (res.success) { + setNativeList(res.payload?.data) + } + }) + } + function getMemberWorkPlaceList () { + dispatch(humanAffairs.getMemberWorkPlace()).then((res) => {//查询工作地列表 + if (res.success) { + setWorkPlaceList(res.payload?.data) + } + }) + } + const columns = []; + //获取表格属性设置 + function attribute () { + const arr = localStorage.getItem(EMPLOYEEINFORMATION) + ? JSON.parse(localStorage.getItem(EMPLOYEEINFORMATION)) + : []; + + const column = [ + { + title: ( +
+ 员工编号 +
+ ), + dataIndex: "userCode", + key: "userCode", + render: (_, r, index) => { + return r.userCode; + }, + }, { + title: ( +
+ 姓名 +
+ ), + dataIndex: "userName", + key: "userName", + render: (_, r, index) => { + return r.userName; + }, + }, { + title: ( +
+ 所属部门 +
+ ), + dataIndex: "departmrnt", + key: "departmrnt", + render: (_, r, index) => { + return ( +
+ { + r.departmrnt.map((ite, idx) => { + let departmentsArr = [] + for (let i = 0; i < r.departmrnt.length; i++) { + departmentsArr.push(r.departmrnt[i].name) + } + return ( +
+ {idx == 0 ? + (
+ {ite.name} +
) : ('') + + } + { + r.departmrnt.length > 1 && idx == 1 ? ( + +
+ ... +
+
+ ) : ('') + } +
+ ) + }) + } +
+ ) + }, + }, + // { + // title: "创建时间", + // dataIndex: "logCount", + // key: "logCount", + // render: (_, r, index) => { + // return (r.logCount + '次') + // }, + // }, + // { + // title: "接收人", + // dataIndex: "monitorCount", + // key: "monitorCount", + // render: (_, r, index) => { + // return r.monitorCount + // }, + // }, + // { + // title: "监听问题", + // dataIndex: "pushWay", + // key: "pushWay", + // render: (_, r, index) => { + // return r.pushWay == 'email' ? '邮件通知' : '短信通知'; + // }, + // }, + // { + // title: "通知时效", + // dataIndex: "text1", + // key: "text1", + // render: (_, r, index) => { + // return r.text1 + // }, + // }, + // { + // title: "启用状态", + // dataIndex: "text2", + // key: "text2", + // render: (_, r, index) => { + // return r.text2 + // }, + // }, + // { + // title: "推送次数", + // dataIndex: "time", + // key: "time", + // render: (_, r, index) => { + // return r.time + // }, + // }, + ]; + for (let i = 0; i < arr.length; i++) { + let colum = column.filter((item) => { + return item.key === arr[i]; + }); + columns.splice(i + 2, 0, colum[0]); + } + setSetupp(columns); + } + function handleRow (record, index) {//斑马条纹 + // 给偶数行设置斑马纹 + if (index % 2 === 0) { + return { + style: { + background: '#FAFCFF', + } + }; + } else { + return {}; + } + } + return ( + <> +
+
+
人事管理
+
/
+
档案中心
+
/
+
人员档案
+
+
+
+
+
+
员工信息
+
EMPLOYEE INFORMATION
+
+
+
+
{ + console.log('values', values); + }} + getFormApi={(formApi) => (form.current = formApi)} + > +
+
+ + 职位 + 部门 + 编号 + 姓名 + + } + field="keyword" + pure + showClear + style={{ width: 346, marginLeft: 12, marginRight: 12 }} + placeholder="请输入或选择关键词" + /> + + +
+
+
+ + + 全部 + + + 已婚已育 + + + 已婚 + + + 未婚 + + + + {nativeList.map((item) => { + return ( + + {item.nativePlace} + + ); + })} + + + {workPlaceList.map((item) => { + return ( + + {item.workPlace} + + ); + })} + +
+
+ setSetup(true)} + /> + setSetup(true)} + /> + +
+
+
+
+
+ + 表格中带有认证标识" + + "信息的为系统基础数据,来源于项企PEP、钉钉等系统,其他数据均为导入或自定义数据 +
+
+ + s)} + dataSource={archivesList} + bordered={false} + empty="暂无数据" + pagination={false} + onRow={handleRow} + /> + +
+
+
+
+ + 共{limits}条信息 + + { + setQuery({ limit: pageSize, page: currentPage - 1 }); + page.current = currentPage - 1 + }} + /> +
+
+ + + + + {setup ? ( + { + setSetup(false); + attribute(); + // setcameraSetup(false); + }} + /> + ) : ( + "" + )} + + ) +} + +function mapStateToProps (state) { + const { auth, global, MemberSearch, webSocket } = state; + return { + // loading: members.isRequesting, + user: auth.user, + actions: global.actions, + xqMembers: MemberSearch.data, + // socket: webSocket.socket + }; +} + +export default connect(mapStateToProps)(employeeInformation); diff --git a/web/client/src/sections/humanAffairs/containers/index.js b/web/client/src/sections/humanAffairs/containers/index.js index 59a3f85..eff5a17 100644 --- a/web/client/src/sections/humanAffairs/containers/index.js +++ b/web/client/src/sections/humanAffairs/containers/index.js @@ -2,5 +2,6 @@ import PersonnelFiles from './personnelFiles'; import PersonnelFilesDetail from './personnelFilesDetail'; +import EmployeeInformation from './employeeInformation'; -export { PersonnelFiles, PersonnelFilesDetail }; \ No newline at end of file +export { PersonnelFiles, PersonnelFilesDetail, EmployeeInformation }; \ No newline at end of file diff --git a/web/client/src/sections/humanAffairs/containers/personnelFiles.jsx b/web/client/src/sections/humanAffairs/containers/personnelFiles.jsx index f45095e..1ea6517 100644 --- a/web/client/src/sections/humanAffairs/containers/personnelFiles.jsx +++ b/web/client/src/sections/humanAffairs/containers/personnelFiles.jsx @@ -162,7 +162,7 @@ const Rest = (props) => {
- {item.pepUserId} + {item.userCode}
{ item.departmrnt.map((ite, idx) => { @@ -256,7 +256,7 @@ const Rest = (props) => {
diff --git a/web/client/src/sections/humanAffairs/containers/personnelFilesDetail.jsx b/web/client/src/sections/humanAffairs/containers/personnelFilesDetail.jsx index 4bd6cee..ea36eda 100644 --- a/web/client/src/sections/humanAffairs/containers/personnelFilesDetail.jsx +++ b/web/client/src/sections/humanAffairs/containers/personnelFilesDetail.jsx @@ -129,15 +129,17 @@ const Rest = (props) => { }, ]) + const [pepUserCode, setPepUserCode] = useState(''); const [pepUserId, setPepUserId] = useState(''); const [pepObj, setPepObj] = useState({}); const scroll = useMemo(() => ({ y: 248 }), []); - + const [startDate, setStartDate] = useState('');//开始时间 const [endDate, setEndDate] = useState('');//结束时间 useEffect(() => { - setPepUserId(history?.location?.search.slice(1)) + setPepUserCode(history?.location?.search.slice(1).split('-')[0]) + setPepUserId(history?.location?.search.slice(1).split('-')[1]) peopleDetail() }, []) useEffect(() => { @@ -145,106 +147,141 @@ const Rest = (props) => { getLeaveOption()//请假信息 }, [startDate, endDate]) function peopleDetail () { - dispatch(humanAffairs.getMemberList({ keywordTarget: 'number', keyword: history?.location?.search.slice(1) })).then((res) => {//搜索项企用户 + dispatch(humanAffairs.getMemberList({ keywordTarget: 'number', keyword: history?.location?.search.slice(1).split('-')[0] })).then((res) => {//搜索项企用户 if (res.success) { setPepObj(res.payload?.data?.rows[0]) } }) } - function getWorkOption () {//请假折线图 - dispatch(humanAffairs.getMemberOvertime({ pepUserId: history?.location?.search.slice(1), startDate: startDate, endDate: endDate })).then((res) => {//搜索项企用户 + function getWorkOption () {//加班折线图 + let date = []; + let showdate = [] + let showdate1 = [] + dispatch(humanAffairs.getMemberOvertime({ pepUserId: history?.location?.search.slice(1).split('-')[1], startDate: startDate, endDate: endDate })).then((res) => {//搜索项企用户 if (res.success) { setTableData(res.payload?.data?.data) setTableStatistic(res.payload?.data) - } - }) - var date = []; - date.push([2017, 6, 1].join("/")); - date.push([2017, 6, 2].join("/")); - date.push([2017, 6, 3].join("/")); - date.push([2017, 6, 4].join("/")); - date.push([2017, 6, 5].join("/")); - date.push([2017, 6, 6].join("/")); - date.push([2017, 6, 7].join("/")); - date.push([2017, 6, 8].join("/")); - date.push([2017, 6, 9].join("/")); - let data = { - legend: { - data: ["调休", "折算"], - left: 'right', - icon: 'roundRect', - itemHeight: 3, // 粗细 - }, - color: ['#0F7EFB', '#FE9812'], //两条折线的颜色 - xAxis: [ - { - boundaryGap: false, - data: date, - }, - ], - yAxis: [ - { - type: "value", - name: '小时' - }, - ], - dataZoom: [ - { - id: "dataZoomX", - type: "slider", - start: 0, - end: 100, - handleIcon: - "M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", - handleSize: "80%", - }, - ], - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'cross', - label: { - backgroundColor: '#6a7985' + let textdate = []; + for (let i = 0; i < res.payload?.data?.dayStatisticData?.length; i++) { + if (textdate.findIndex((ev) => { + return ev.time == moment(res.payload.data.dayStatisticData[i].day).format('YYYY/MM')&&ev.compensate == res.payload.data.dayStatisticData[i].compensate + }) !== -1) { + textdate[textdate.findIndex((ev) => { + return ev.time == moment(res.payload.data.dayStatisticData[i].day).format('YYYY/MM')&&ev.compensate == res.payload.data.dayStatisticData[i].compensate + })].num + = + textdate[textdate.findIndex((ev) => { + return ev.time == moment(res.payload.data.dayStatisticData[i].day).format('YYYY/MM')&&ev.compensate == res.payload.data.dayStatisticData[i].compensate + })].num + res.payload.data.dayStatisticData[i].duration / 3600 + } + else { + textdate.push({ + time: moment(res.payload.data.dayStatisticData[i].day).format('YYYY/MM'), + num: res.payload.data.dayStatisticData[i].duration / 3600, + compensate: res.payload.data.dayStatisticData[i].compensate + }) } + } - }, - series: [ - { - name: "调休", - type: "line", - areaStyle: { - color: 'rgba(14,156,255,0.5)', - opacity: 0.1 + console.log('textdate', textdate); + for (let l = 0; l < textdate.length; l++) { + if (textdate[l].compensate == '调休') { + showdate.push([textdate[l].time, textdate[l].num]) + } + else { + showdate1.push([textdate[l].time, textdate[l].num]) + } + + } + + if (!startDate && !endDate) { + for (let i = 0; i < 12; i++) { + date.unshift(moment(new Date()).subtract(i, 'months').format('YYYY/MM')); + } + } + else { + let nowdate = moment(startDate).format('YYYY/MM') + date.push(nowdate) + for (let o = 0; o < 10000; o++) { + if (nowdate !== moment(endDate).format('YYYY/MM')) { + nowdate = moment(nowdate).add(1, 'months').format('YYYY/MM') + date.push(nowdate) + } + else { + break + } + } + } + let data = { + legend: { + data: ["调休", "折算"], + left: 'right', + icon: 'roundRect', + itemHeight: 3, // 粗细 }, - smooth: true, - data: [ - ["2017/6/1", 1], - ["2017/6/3", 3], - ["2017/6/5", 5], - ["2017/6/7", 4], - ["2017/6/9", 4], + color: ['#0F7EFB', '#FE9812'], //两条折线的颜色 + xAxis: [ + { + boundaryGap: false, + data: date, + }, ], - }, - { - name: "折算", - type: "line", - areaStyle: { - color: 'rgba(254,152,18,0.2)', + yAxis: [ + { + type: "value", + name: '小时' + }, + ], + dataZoom: [ + { + id: "dataZoomX", + type: "slider", + start: 0, + end: 100, + handleIcon: + "M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", + handleSize: "80%", + }, + ], + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'cross', + label: { + backgroundColor: '#6a7985' + } + } }, - smooth: true, - data: [ - ["2017/6/2", 3], - ["2017/6/4", 1], - ["2017/6/6", 6], - ["2017/6/8", 3], + series: [ + { + name: "调休", + type: "line", + areaStyle: { + color: 'rgba(14,156,255,0.5)', + opacity: 0.1 + }, + smooth: true, + data: showdate, + }, + { + name: "折算", + type: "line", + areaStyle: { + color: 'rgba(254,152,18,0.2)', + }, + smooth: true, + data: showdate1, + }, ], - }, - ], - } - setOption(data) + } + setOption(data) + } + }) } function getLeaveOption () {//请假折线图 - dispatch(humanAffairs.getMemberVacate({ pepUserId: history?.location?.search.slice(1), startDate: startDate, endDate: endDate })).then((res) => {//搜索项企用户 + let date = []; + let showdate = [] + dispatch(humanAffairs.getMemberVacate({ pepUserId: history?.location?.search.slice(1).split('-')[1], startDate: startDate, endDate: endDate })).then((res) => {//搜索项企用户 if (res.success) { setLeaveData(res.payload?.data?.data) let year = 0; @@ -270,78 +307,109 @@ const Rest = (props) => { setLeaveStatistic({ compassionate, sick, year, other, all }) - } - }) - var date = []; - date.push([2017, 6, 1].join("/")); - date.push([2017, 6, 2].join("/")); - date.push([2017, 6, 3].join("/")); - date.push([2017, 6, 4].join("/")); - date.push([2017, 6, 5].join("/")); - date.push([2017, 6, 6].join("/")); - date.push([2017, 6, 7].join("/")); - date.push([2017, 6, 8].join("/")); - date.push([2017, 6, 9].join("/")); - let data = { - color: ['#0F7EFB', '#FE9812'], //两条折线的颜色 - xAxis: [ - { - boundaryGap: false, - data: date, - }, - ], - yAxis: [ - { - type: "value", - name: '小时' - }, - ], - dataZoom: [ - { - id: "dataZoomX", - type: "slider", - start: 0, - end: 100, - handleIcon: - "M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", - handleSize: "80%", - }, - ], - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'cross', - label: { - backgroundColor: '#6a7985' + let textdate = []; + for (let i = 0; i < res.payload?.data?.dayStatisticData?.length; i++) { + if (textdate.findIndex((ev) => { + return ev.time == moment(res.payload.data.dayStatisticData[i].day).format('YYYY/MM') + }) !== -1) { + textdate[textdate.findIndex((ev) => { + return ev.time == moment(res.payload.data.dayStatisticData[i].day).format('YYYY/MM') + })].num + = + textdate[textdate.findIndex((ev) => { + return ev.time == moment(res.payload.data.dayStatisticData[i].day).format('YYYY/MM') + })].num + res.payload.data.dayStatisticData[i].duration / 3600 + } + else { + textdate.push({ + time: moment(res.payload.data.dayStatisticData[i].day).format('YYYY/MM'), + num: res.payload.data.dayStatisticData[i].duration / 3600 + }) + } + + } + for (let l = 0; l < textdate.length; l++) { + showdate.push([textdate[l].time, textdate[l].num]) + } + + if (!startDate && !endDate) { + for (let i = 0; i < 12; i++) { + date.unshift(moment(new Date()).subtract(i, 'months').format('YYYY/MM')); } } - }, - series: [ - { - name: "调休", - type: "line", - areaStyle: { - color: 'rgba(14,156,255,0.5)', - opacity: 0.1 + else { + let nowdate = moment(startDate).format('YYYY/MM') + date.push(nowdate) + for (let o = 0; o < 10000; o++) { + if (nowdate !== moment(endDate).format('YYYY/MM')) { + nowdate = moment(nowdate).add(1, 'months').format('YYYY/MM') + date.push(nowdate) + } + else { + break + } + } + } + let data = { + color: ['#0F7EFB', '#FE9812'], //两条折线的颜色 + xAxis: [ + { + boundaryGap: false, + data: date, + }, + ], + yAxis: [ + { + type: "value", + name: '小时' + }, + ], + dataZoom: [ + { + id: "dataZoomX", + type: "slider", + start: 0, + end: 100, + handleIcon: + "M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", + handleSize: "80%", + }, + ], + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'cross', + label: { + backgroundColor: '#6a7985' + } + } }, - smooth: true, - data: [ - ["2017/6/1", 1], - ["2017/6/3", 3], - ["2017/6/5", 5], - ["2017/6/7", 4], - ["2017/6/9", 4], + series: [ + { + name: "调休", + type: "line", + areaStyle: { + color: 'rgba(14,156,255,0.5)', + opacity: 0.1 + }, + smooth: true, + data: showdate, + }, ], - }, - ], - } - setLeaveOption(data) + } + setLeaveOption(data) + } + }) } function handleChange (date) { - console.log('datedatedatedate', date); - setStartDate(moment(date[0]).format('YYYY-MM-DD')) - setEndDate(moment(date[1]).format('YYYY-MM-DD')) - + if (date.length > 1) { + setStartDate(moment(date[0]).format('YYYY-MM-DD')) + setEndDate(moment(date[1]).format('YYYY-MM-DD')) + } + else { + setStartDate('') + setEndDate('') + } } return ( <> @@ -364,7 +432,7 @@ const Rest = (props) => {
-
{pepObj.userName}的个人档案
+
{pepObj?.userName}的个人档案
{ 试用期:
- {pepObj.regularDate ? moment(pepObj.regularDate).diff(pepObj.hiredate, 'months', true) + '个月' : '暂无'} + {pepObj.regularDate ? moment(pepObj.regularDate).diff(pepObj.hiredate, 'months', true).toFixed(1) + '个月' : '暂无'}
{ @@ -635,7 +703,7 @@ const Rest = (props) => {
-
+
他/她的历史工作经历与职务
@@ -646,8 +714,8 @@ const Rest = (props) => {
-
- 基础动作 +
+ 基本动作
时间筛选: @@ -685,7 +753,7 @@ const Rest = (props) => { 工作日:
- {tableStatistic.sumPayWorkday / 60 / 60 + tableStatistic.sumTakeRestWorkday / 60 / 60||0}小时 + {tableStatistic.sumPayWorkday / 3600 + tableStatistic.sumTakeRestWorkday /3600 || 0}小时
@@ -693,7 +761,7 @@ const Rest = (props) => { 普通假日:
- {tableStatistic.sumTakeRestDayoff / 60 / 60 + tableStatistic.sumTakeRestDayoff / 60 / 60||0}小时 + {tableStatistic.sumTakeRestDayoff / 3600 + tableStatistic.sumPayDayoff / 3600 || 0}小时
@@ -701,7 +769,7 @@ const Rest = (props) => { 法定假日:
- {tableStatistic.sumPayFestivals / 60 / 60 + tableStatistic.sumTakeRestFestivals / 60 / 60||0}小时 + {tableStatistic.sumPayFestivals / 3600 + tableStatistic.sumTakeRestFestivals / 3600 || 0}小时
@@ -709,7 +777,7 @@ const Rest = (props) => { 累计加班时长:
- {tableStatistic.sumPayWorkday / 60 / 60 + tableStatistic.sumTakeRestWorkday / 60 / 60 + tableStatistic.sumTakeRestDayoff / 60 / 60 + tableStatistic.sumTakeRestDayoff / 60 / 60 + tableStatistic.sumPayFestivals / 60 / 60 + tableStatistic.sumTakeRestFestivals / 60 / 60||0}小时 + {(tableStatistic.sumPayWorkday / 3600 + tableStatistic.sumTakeRestWorkday / 3600 + tableStatistic.sumTakeRestDayoff / 3600 + tableStatistic.sumPayDayoff /3600 + tableStatistic.sumPayFestivals / 3600 + tableStatistic.sumTakeRestFestivals / 3600) || 0}小时
diff --git a/web/client/src/sections/humanAffairs/nav-item.jsx b/web/client/src/sections/humanAffairs/nav-item.jsx index e2f2869..a80967a 100644 --- a/web/client/src/sections/humanAffairs/nav-item.jsx +++ b/web/client/src/sections/humanAffairs/nav-item.jsx @@ -12,11 +12,19 @@ export function getNavItem (user, dispatch) { { itemKey: 'archivesCenter', text: '档案中心', - icon: , + icon: , to: '/humanAffairs/archivesCenter/personnelFiles', items: [{ itemKey: 'personnelFiles', to: '/humanAffairs/archivesCenter/personnelFiles', text: '人员档案' }] + },{ + itemKey: 'employeeRelations', + text: '员工关系', + icon: , + to: '/humanAffairs/employeeRelations/employeeInformation', + items: [{ + itemKey: 'employeeInformation', to: '/humanAffairs/employeeRelations/employeeInformation', text: '员工信息' + }] }, ] }, diff --git a/web/client/src/sections/humanAffairs/routes.js b/web/client/src/sections/humanAffairs/routes.js index 9fb9882..3e000e7 100644 --- a/web/client/src/sections/humanAffairs/routes.js +++ b/web/client/src/sections/humanAffairs/routes.js @@ -1,4 +1,4 @@ -import { PersonnelFiles,PersonnelFilesDetail } from './containers'; +import { PersonnelFiles, PersonnelFilesDetail, EmployeeInformation } from './containers'; export default [{ type: 'inner', @@ -17,9 +17,19 @@ export default [{ component: PersonnelFiles, breadcrumb: '人员档案', }] - },] + }, { + path: '/employeeRelations', + key: 'employeeRelations', + breadcrumb: '员工关系', + childRoutes: [{ + path: '/employeeInformation', + key: 'employeeInformation', + component: EmployeeInformation, + breadcrumb: '员工信息', + }] + }] } -},{ +}, { type: 'inner', route: { path: "/personnelFilesDetail", diff --git a/web/client/src/sections/humanAffairs/style.less b/web/client/src/sections/humanAffairs/style.less index e69de29..a1290ea 100644 --- a/web/client/src/sections/humanAffairs/style.less +++ b/web/client/src/sections/humanAffairs/style.less @@ -0,0 +1,9 @@ +.semi-table{ + .semi-table-row:first-child{ + .semi-table-row-head{ + background: #F2F3F5; + color: #4A4A4A; + font-size: 14px; + } + } +} diff --git a/web/client/src/utils/webapi.js b/web/client/src/utils/webapi.js index def05ea..b4caad9 100644 --- a/web/client/src/utils/webapi.js +++ b/web/client/src/utils/webapi.js @@ -26,7 +26,8 @@ export const ApiTable = { getMemberOvertime: 'member/overtime',//查询单个人员加班统计数据 getMemberVacate: 'member/vacate',//查询单个人员请假统计数据 getMemberExport: 'member/export',//导出员工信息 - + getMemberNativePlace: 'member/native_place',//查询籍贯列表 + getMemberWorkPlace: 'member/work_place',//查询工作地列表 }; export const RouteTable = { apiRoot: "/api/root",