Browse Source

加班数据统计接口

master
巴林闲侠 2 years ago
parent
commit
97c1f52f27
  1. 132
      api/app/lib/controllers/attendance/index.js
  2. 28
      api/app/lib/controllers/member/index.js
  3. 418
      api/app/lib/models/member.js
  4. 8
      api/app/lib/routes/attendance/index.js
  5. 52
      api/app/lib/utils/member.js

132
api/app/lib/controllers/attendance/index.js

@ -0,0 +1,132 @@
'use strict';
async function overtimeStatistic (ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
const { judgeHoliday, memberList } = 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
})
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,
"vacateStartTime": undefined,
"vacateEndTime": undefined,
"overtimeStartTime": undefined,
"overtimeEndTime": undefined,
})
}
})
// 查加班总数
const countRes = await clickHouse.hr.query(`
SELECT
overtime.pep_user_id AS pepUserId,
count(pep_process_story_id) AS count
FROM overtime
WHERE overtime.pep_user_id IN (${pepUserIds.join(',')})
${startDate ? `
AND overtime.start_time >= '${moment(startDate).format('YYYY-MM-DD')}'
`: ''}
${endDate ? `
AND overtime.start_time <= '${moment(endDate).format('YYYY-MM-DD')}'
` : ''}
GROUP BY overtime.pep_user_id
`).toPromise()
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()
returnD.forEach(u => {
u.overtimeCount = (countRes.find(c => c.pepUserId == u.pepUserId) || {}).count || 0
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
}
}
}
module.exports = {
overtimeStatistic,
};

28
api/app/lib/controllers/member/index.js

@ -37,7 +37,7 @@ async function add (ctx) {
ctx.status = 204; ctx.status = 204;
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -77,7 +77,7 @@ async function edit (ctx) {
ctx.status = 204; ctx.status = 204;
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -161,7 +161,7 @@ async function searchPepMember (ctx) {
ctx.status = 200; ctx.status = 200;
ctx.body = returnD ctx.body = returnD
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -184,7 +184,7 @@ async function del (ctx) {
ctx.status = 204; ctx.status = 204;
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -208,7 +208,7 @@ async function nativePlaceList (ctx) {
ctx.status = 200; ctx.status = 200;
ctx.body = nRes ctx.body = nRes
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -232,7 +232,7 @@ async function workPlaceList (ctx) {
ctx.status = 200; ctx.status = 200;
ctx.body = wRes ctx.body = wRes
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -256,7 +256,7 @@ async function maritalList (ctx) {
ctx.status = 200; ctx.status = 200;
ctx.body = mRes ctx.body = mRes
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -270,7 +270,8 @@ async function list (ctx) {
const { judgeHoliday, memberList } = ctx.app.fs.utils const { judgeHoliday, memberList } = ctx.app.fs.utils
const { const {
keywordTarget, keyword, limit, page, state, keywordTarget, keyword, limit, page, state,
hiredateStart, hiredateEnd, marital, native, workPlace hiredateStart, hiredateEnd, marital, native, workPlace,
orderBy, orderDirection,
} = ctx.query } = ctx.query
const curDay = moment().format('YYYY-MM-DD') const curDay = moment().format('YYYY-MM-DD')
@ -291,7 +292,8 @@ async function list (ctx) {
} }
const userRes = await memberList({ const userRes = await memberList({
keywordTarget, keyword, limit, page, state, keywordTarget, keyword, limit, page, state,
hiredateStart, hiredateEnd, marital, native, workPlace hiredateStart, hiredateEnd, marital, native, workPlace,
orderBy, orderDirection,
}) })
let returnD = [] let returnD = []
@ -351,7 +353,7 @@ async function list (ctx) {
rows: returnD rows: returnD
} }
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -440,7 +442,7 @@ async function overTimeStatistics (ctx) {
ctx.status = 200; ctx.status = 200;
ctx.body = returnD ctx.body = returnD
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -520,7 +522,7 @@ async function vacateStatistics (ctx) {
ctx.status = 200; ctx.status = 200;
ctx.body = returnD ctx.body = returnD
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -668,7 +670,7 @@ async function exportData (ctx) {
ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName)); ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName));
ctx.body = fileData; ctx.body = fileData;
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined

418
api/app/lib/models/member.js

@ -2,213 +2,213 @@
'use strict'; 'use strict';
module.exports = dc => { module.exports = dc => {
const DataTypes = dc.ORM; const DataTypes = dc.ORM;
const sequelize = dc.orm; const sequelize = dc.orm;
const Member = sequelize.define("member", { const Member = sequelize.define("member", {
pepUserId: { pepUserId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: "项企用户id", comment: "项企用户id",
primaryKey: true, primaryKey: true,
field: "pep_user_id", field: "pep_user_id",
autoIncrement: false, autoIncrement: false,
unique: "member_pep_user_id_uindex" unique: "member_pep_user_id_uindex"
}, },
idNumber: { idNumber: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "证件号", comment: "证件号",
primaryKey: false, primaryKey: false,
field: "id_number", field: "id_number",
autoIncrement: false autoIncrement: false
}, },
idPhoto: { idPhoto: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "证件照", comment: "证件照",
primaryKey: false, primaryKey: false,
field: "id_photo", field: "id_photo",
autoIncrement: false autoIncrement: false
}, },
gender: { gender: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "性别", comment: "性别",
primaryKey: false, primaryKey: false,
field: "gender", field: "gender",
autoIncrement: false autoIncrement: false
}, },
birthday: { birthday: {
type: DataTypes.DATEONLY, type: DataTypes.DATEONLY,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "出生年月", comment: "出生年月",
primaryKey: false, primaryKey: false,
field: "birthday", field: "birthday",
autoIncrement: false autoIncrement: false
}, },
nativePlace: { nativePlace: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "籍贯", comment: "籍贯",
primaryKey: false, primaryKey: false,
field: "native_place", field: "native_place",
autoIncrement: false autoIncrement: false
}, },
marital: { marital: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "婚育状态", comment: "婚育状态",
primaryKey: false, primaryKey: false,
field: "marital", field: "marital",
autoIncrement: false autoIncrement: false
}, },
politicsStatus: { politicsStatus: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "整治面貌", comment: "整治面貌",
primaryKey: false, primaryKey: false,
field: "politics_status", field: "politics_status",
autoIncrement: false autoIncrement: false
}, },
phoneNumber: { phoneNumber: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: null, comment: '联系方式',
primaryKey: false, primaryKey: false,
field: "phone_number", field: "phone_number",
autoIncrement: false autoIncrement: false
}, },
workPlace: { workPlace: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "工作地点", comment: "工作地点",
primaryKey: false, primaryKey: false,
field: "work_place", field: "work_place",
autoIncrement: false autoIncrement: false
}, },
graduatedFrom: { graduatedFrom: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "毕业院校", comment: "毕业院校",
primaryKey: false, primaryKey: false,
field: "graduated_from", field: "graduated_from",
autoIncrement: false autoIncrement: false
}, },
educationBackground: { educationBackground: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "学历", comment: "学历",
primaryKey: false, primaryKey: false,
field: "education_background", field: "education_background",
autoIncrement: false autoIncrement: false
}, },
specialty: { specialty: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "专业", comment: "专业",
primaryKey: false, primaryKey: false,
field: "specialty", field: "specialty",
autoIncrement: false autoIncrement: false
}, },
graduationDate: { graduationDate: {
type: DataTypes.DATEONLY, type: DataTypes.DATEONLY,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "毕业时间", comment: "毕业时间",
primaryKey: false, primaryKey: false,
field: "graduation_date", field: "graduation_date",
autoIncrement: false autoIncrement: false
}, },
hiredate: { hiredate: {
type: DataTypes.DATEONLY, type: DataTypes.DATEONLY,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "入职时间", comment: "入职时间",
primaryKey: false, primaryKey: false,
field: "hiredate", field: "hiredate",
autoIncrement: false autoIncrement: false
}, },
turnProbationPeriod: { turnProbationPeriod: {
type: DataTypes.DATEONLY, type: DataTypes.DATEONLY,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "转试用期时间", comment: "转试用期时间",
primaryKey: false, primaryKey: false,
field: "turn_probation_period", field: "turn_probation_period",
autoIncrement: false autoIncrement: false
}, },
regularDate: { regularDate: {
type: DataTypes.DATEONLY, type: DataTypes.DATEONLY,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "转正时间", comment: "转正时间",
primaryKey: false, primaryKey: false,
field: "regular_date", field: "regular_date",
autoIncrement: false autoIncrement: false
}, },
dimissionDate: { dimissionDate: {
type: DataTypes.DATEONLY, type: DataTypes.DATEONLY,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "离职时间", comment: "离职时间",
primaryKey: false, primaryKey: false,
field: "dimission_date", field: "dimission_date",
autoIncrement: false autoIncrement: false
}, },
experienceYear: { experienceYear: {
type: DataTypes.DOUBLE, type: DataTypes.DOUBLE,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "工作经验/年", comment: "工作经验/年",
primaryKey: false, primaryKey: false,
field: "experience_year", field: "experience_year",
autoIncrement: false autoIncrement: false
}, },
occupationalHistory: { occupationalHistory: {
type: DataTypes.TEXT, type: DataTypes.TEXT,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "工作经历", comment: "工作经历",
primaryKey: false, primaryKey: false,
field: "occupational_history", field: "occupational_history",
autoIncrement: false autoIncrement: false
}, },
vitae: { vitae: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "简历", comment: "简历",
primaryKey: false, primaryKey: false,
field: "vitae", field: "vitae",
autoIncrement: false autoIncrement: false
}, },
del: { del: {
type: DataTypes.BOOLEAN, type: DataTypes.BOOLEAN,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: null, comment: null,
primaryKey: false, primaryKey: false,
field: "del", field: "del",
autoIncrement: false autoIncrement: false
} }
}, { }, {
tableName: "member", tableName: "member",
comment: "", comment: "",
indexes: [] indexes: []
}); });
dc.models.Member = Member; dc.models.Member = Member;
return Member; return Member;
}; };

8
api/app/lib/routes/attendance/index.js

@ -0,0 +1,8 @@
'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);
};

52
api/app/lib/utils/member.js

@ -6,7 +6,9 @@ module.exports = function (app, opts) {
async function memberList ({ async function memberList ({
keywordTarget, keyword, limit, page, state, keywordTarget, keyword, limit, page, state,
hiredateStart, hiredateEnd, marital, native, workPlace hiredateStart, hiredateEnd, marital, native, workPlace,
orderBy, orderDirection,
overtimeDayStatisticStartDate, overtimeDayStatisticendDate
}) { }) {
const { judgeHoliday } = app.fs.utils const { judgeHoliday } = app.fs.utils
const { clickHouse } = app.fs const { clickHouse } = app.fs
@ -58,19 +60,27 @@ module.exports = function (app, opts) {
} }
} }
let overtimeDayStatisticWhere = []
if (overtimeDayStatisticStartDate) {
overtimeDayStatisticWhere.push(`overtime_day.day >= '${moment(startDate).format('YYYY-MM-DD')}'`)
}
if (overtimeDayStatisticendDate) {
overtimeDayStatisticWhere.push(`overtime_day.day <= '${moment(endDate).format('YYYY-MM-DD')}'`)
}
// CRAZY
const innerSelectQuery = ` const innerSelectQuery = `
FROM member FROM member
INNER JOIN ${pepEmis}.user AS user INNER JOIN ${pepEmis}.user AS user
ON member.pep_user_id = user.id ON member.pep_user_id = user.id
${keywordTarget == 'number' && keyword ? ` ${keywordTarget == 'number' && keyword ? `
AND toString(user.id) LIKE '%${keyword}%' AND user.people_code LIKE '%${keyword}%'
`: ''} `: ''}
${keywordTarget == 'name' && keyword ? ` ${keywordTarget == 'name' && keyword ? `
AND user.name LIKE '%${keyword}%' AND user.name LIKE '%${keyword}%'
`: ''} `: ''}
${state == 'vacate' ? 'INNER' : 'LEFT'} JOIN ( ${state == 'vacate' ? 'INNER' : 'LEFT'} JOIN (
SELECT SELECT
pep_user_id, pep_user_id,
any(start_time) AS vacateStartTime, any(start_time) AS vacateStartTime,
any(end_time) AS vacateEndTime any(end_time) AS vacateEndTime
FROM vacate FROM vacate
@ -94,7 +104,24 @@ module.exports = function (app, opts) {
) AS hrOvertime ) AS hrOvertime
ON hrOvertime.pep_user_id = member.pep_user_id ON hrOvertime.pep_user_id = member.pep_user_id
WHERE ${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`: ''}
WHERE
member.del = 0 member.del = 0
${keywordTarget == 'role' && keyword ? ` ${keywordTarget == 'role' && keyword ? `
AND user.id IN ( AND user.id IN (
@ -147,6 +174,11 @@ module.exports = function (app, opts) {
FROM ( FROM (
SELECT SELECT
member.*, member.*,
${orderBy == 'overtimeTakeRestSum' || orderBy == 'overtimePaySum' || orderBy == 'overtimeSum' ? `
overtimeDayStatistic.duration AS overtimeDayStatisticDuration
`: ''}
hrVacate.vacateStartTime AS vacateStartTime, hrVacate.vacateStartTime AS vacateStartTime,
hrVacate.vacateEndTime AS vacateEndTime, hrVacate.vacateEndTime AS vacateEndTime,
hrOvertime.overtimeStartTime AS overtimeStartTime, hrOvertime.overtimeStartTime AS overtimeStartTime,
@ -167,12 +199,18 @@ module.exports = function (app, opts) {
LEFT JOIN ${pepEmis}.department AS department LEFT JOIN ${pepEmis}.department AS department
ON department.id = department_user.department ON department.id = department_user.department
${whereOption.length ? `WHERE ${whereOption.join(' AND ')}` : ''} ${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"'
: 'user.people_code'}
${orderDirection || 'ASC'}
`).toPromise() `).toPromise()
const countRes = await clickHouse.hr.query(` const countRes = await clickHouse.hr.query(`
SELECT SELECT
count(member.pep_user_id) AS count count(member.pep_user_id) AS count
${innerSelectQuery} ${innerSelectQuery}
`).toPromise() `).toPromise()
return { return {

Loading…
Cancel
Save