From 9eef1571bd75768d25983f98241fcbd72733a9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80=C3=AE=C3=97=C3=9A=C3=95=C3=B1?= Date: Wed, 27 Jul 2022 16:54:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=A5=E7=A6=BB=E8=81=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/api_v1/endpoints/forms.py | 127 +++++++++++++++++++++++++++- crud/crud_jobs.py | 4 +- models/interview_zsgc.py | 114 +++++++++++++++++++++++-- utils/func.py | 28 ++++++ 接口文档/各岗位招聘数据接口文档.txt | 110 ++++++++++++++++++++++++ 接口文档/年度入离职数据接口文档.txt | 39 +++++++++ 6 files changed, 411 insertions(+), 11 deletions(-) create mode 100644 接口文档/各岗位招聘数据接口文档.txt create mode 100644 接口文档/年度入离职数据接口文档.txt diff --git a/api/api_v1/endpoints/forms.py b/api/api_v1/endpoints/forms.py index c11bfb5..348afed 100644 --- a/api/api_v1/endpoints/forms.py +++ b/api/api_v1/endpoints/forms.py @@ -8,7 +8,7 @@ from motor.motor_asyncio import AsyncIOMotorDatabase from utils.dingding import get_redis_alluid, send_dates from utils.jianli import get_resume -from utils.func import get_every_days, get_every_months +from utils.func import get_every_days, get_every_weeks, get_every_months import crud, schemas from datetime import datetime from core.configuration import * @@ -778,11 +778,132 @@ async def year_trend_form( res_msg[chk_date]['入职人数'] += 1 * count_num if chk_stage >= 8: res_msg[chk_date]['转正人数'] += 1 * count_num - if chk_stage >= 9: + if chk_stage == 9: res_msg[chk_date]['离职人数'] += 1 * count_num res_msg[chk_date]['主动离职'] += 1 * count_num - if chk_stage >= 10: + if chk_stage == 10: res_msg[chk_date]['离职人数'] += 1 * count_num res_msg[chk_date]['被动离职'] += 1 * count_num return schemas.Msg(code=200, msg='ok', data=res_msg) + + +# 年度岗位招聘数据报表 +@router.post("/year_job_form") +async def year_job_form( + request: Request, + interview: InterviewDo = Depends(InterviewDo), + ck_db: CKDrive = Depends(get_ck_db), + db: AsyncIOMotorDatabase = Depends(get_database) +) -> schemas.Msg: + """ 岗位招聘数据分析报表 """ + await interview.init() + res = interview.year_job_form_sql() + sql = res['sql'] + data = await ck_db.execute(sql) + if not data: + return schemas.Msg(code=-9, msg='无数据', data=None) + # 取出job和部门 + job_ids = set([j_data['job_id'] for j_data in data.values()]) + job_ids = list(job_ids) + job_datas = await crud.jobs.find_job_some(db, job_ids) + job_dict = {job['job_id']: {'name': job['job_name'], 'sector': job['job_sector']} for job in job_datas} + sdate = res['sdate'] + edate = res['edate'] + chk_type = res['chk_type'] + if chk_type == 'day': + months = get_every_days(sdate, edate) + elif chk_type == 'week': + months = get_every_weeks(sdate, edate) + else: + months = get_every_months(sdate, edate) + res_msg = {} + for i in months: + res_msg[str(i)] = {} + for job_id in job_ids: + res_msg[str(i)][job_id] = { + '简历推荐数': 0, + '有效简历数': 0, + '到场面试数': 0, + '面试通过': 0, + 'offer发出数': 0, + '入职人数': 0, + '离职人数': 0 + } + + for chk_data in data.values(): + if chk_type == 'month': + chk_date = datetime.strftime(chk_data['date'], '%Y-%m') + else: + chk_date = datetime.strftime(chk_data['date'], '%Y-%m-%d') + + if chk_date not in res_msg: + continue + chk_stage = chk_data['interview_stage'] + count_num = chk_data['value'] + chk_job_id = chk_data['job_id'] + if chk_stage >= 1: + res_msg[chk_date][chk_job_id]['简历推荐数'] += 1 * count_num + if chk_stage >= 2: + res_msg[chk_date][chk_job_id]['有效简历数'] += 1 * count_num + if chk_stage >= 3: + res_msg[chk_date][chk_job_id]['到场面试数'] += 1 * count_num + if chk_stage >= 4: + res_msg[chk_date][chk_job_id]['面试通过'] += 1 * count_num + if chk_stage >= 5: + res_msg[chk_date][chk_job_id]['offer发出数'] += 1 * count_num + if chk_stage >= 7: + res_msg[chk_date][chk_job_id]['入职人数'] += 1 * count_num + if chk_stage >= 9: + res_msg[chk_date][chk_job_id]['离职人数'] += 1 * count_num + res_data = { + 'res_msg': res_msg, + 'job_data': job_dict + } + return schemas.Msg(code=200, msg='ok', data=res_data) + + +# 年度入离职数据报表 +@router.post("/year_in_out") +async def year_in_out( + request: Request, + interview: InterviewDo = Depends(InterviewDo), + ck_db: CKDrive = Depends(get_ck_db) +) -> schemas.Msg: + """ 年度入离职数据报表 """ + await interview.init() + res = interview.year_in_out_sql() + sql_in = res['sql_in'] + sql_out = res['sql_out'] + data_in = await ck_db.execute(sql_in) + data_out = await ck_db.execute(sql_out) + if not data_in and data_out: + return schemas.Msg(code=-9, msg='无数据', data=None) + sdate = res['sdate'] + edate = res['edate'] + months = get_every_months(sdate, edate) + res_msg = { + '入职': {}, + '离职': {} + } + for i in months: + res_msg['入职'][str(i)] = 0 + res_msg['离职'][str(i)] = 0 + + # 入职数据处理 + for in_data in data_in.values(): + in_date = datetime.strftime(in_data['date'], '%Y-%m') + if in_date not in res_msg['入职']: + continue + value = in_data['value'] + res_msg['入职'][in_date] += value + + # 离职数据处理 + for out_data in data_out.values(): + out_date = datetime.strftime(out_data['date'], '%Y-%m') + if out_date not in res_msg['离职']: + continue + value = out_data['value'] + res_msg['离职'][out_date] += value + + return schemas.Msg(code=200, msg='ok', data=res_msg) diff --git a/crud/crud_jobs.py b/crud/crud_jobs.py index 9112477..7edfd1e 100644 --- a/crud/crud_jobs.py +++ b/crud/crud_jobs.py @@ -51,8 +51,8 @@ class CRUDJobs(CRUDBase): # 获取对应job_id的名字,以及部门, 招聘数量 async def find_job_some(self, db: AsyncIOMotorDatabase, job_ids): return await self.find_many(db, {'job_id': {"$in": job_ids}}, - {'_id': 0, 'job_name': 1, 'job_sector': 1, 'job_num': 1, 'job_id': 1, - 'principal': 1}) + {'_id': 0, 'job_name': 1, 'job_sector': 1, 'job_num': 1, 'job_id': 1, + 'principal': 1}) jobs = CRUDJobs('jobs') diff --git a/models/interview_zsgc.py b/models/interview_zsgc.py index f28595d..e7c9e31 100644 --- a/models/interview_zsgc.py +++ b/models/interview_zsgc.py @@ -609,11 +609,11 @@ class InterviewDo: sql += f" where" if start_time: if whereStr: - sql += f" and date >= '{start_time}'" + sql += f" and toDate(addHours(`event_time`, 0)) >= '{start_time}'" else: - sql += f" date >= '{start_time}'" + sql += f" toDate(addHours(`event_time`, 0)) >= '{start_time}'" if end_time: - sql += f" and date <= '{end_time}'" + sql += f" and toDate(addHours(`event_time`, 0)) <= '{end_time}'" # 没有日期条件 else: if whereStr: @@ -704,11 +704,11 @@ class InterviewDo: sql += f" where" if start_time: if whereStr: - sql += f" and date >= '{start_time}'" + sql += f" and toDate(addHours(`event_time`, 0)) >= '{start_time}'" else: - sql += f" date >= '{start_time}'" + sql += f" toDate(addHours(`event_time`, 0)) >= '{start_time}'" if end_time: - sql += f" and date <= '{end_time}'" + sql += f" and toDate(addHours(`event_time`, 0)) <= '{end_time}'" # 没有日期条件 else: if whereStr: @@ -723,6 +723,108 @@ class InterviewDo: 'edate': end_time, } + # 年度招聘数据sql + def year_job_form_sql(self): + whereStr = '' + is_date = 0 + if self.where: + for key, value in self.where.items(): + if key in ['start_time', 'end_time', 'chk_type']: + is_date = 1 + continue + if isinstance(value, str): + whereStr += str(key) + ' = ' + "'" + value + "'" + ' ' + continue + whereStr += str(key) + ' = ' + str(value) + ' ' + whereStr = whereStr.strip() + + # 有日期条件 + start_time = self.where.get('start_time', '') + end_time = self.where.get('end_time', '') + chk_type = self.where.get('chk_type', 'day') + if chk_type == 'day': + select_str = f"toDate(addHours(`event_time`, 0))" + if chk_type == 'week': + select_str = f"toStartOfWeek(addHours(`event_time`, 0))" + if chk_type == 'month': + select_str = f"toStartOfMonth(addHours(`event_time`, 0))" + if is_date: + if whereStr: + sql = f"select {select_str} as date,interview_stage, job_id, count() as value from HR.resumes where {whereStr}" + else: + sql = f"select {select_str} as date,interview_stage, job_id, count() as value from HR.resumes" + if start_time or end_time: + sql += f" where" + if start_time: + if whereStr: + sql += f" and toDate(addHours(`event_time`, 0)) >= '{start_time}'" + else: + sql += f" toDate(addHours(`event_time`, 0)) >= '{start_time}'" + if end_time: + sql += f" and toDate(addHours(`event_time`, 0)) <= '{end_time}'" + # 没有日期条件 + else: + if whereStr: + sql = f"select {select_str} as date,interview_stage, job_id, count() as value from HR.resumes where {whereStr}" + else: + sql = f"select {select_str} as date,interview_stage, job_id, count() as value from HR.resumes" + sql += f" group by date, interview_stage, job_id" + print(sql) + return { + 'sql': sql, + 'sdate': start_time, + 'edate': end_time, + 'chk_type': chk_type, + } + + # 年度入离值数据sql + def year_in_out_sql(self): + whereStr = '' + if self.where: + for key, value in self.where.items(): + if key in ['start_time', 'end_time']: + continue + if isinstance(value, str): + whereStr += str(key) + ' = ' + "'" + value + "'" + ' ' + continue + whereStr += str(key) + ' = ' + str(value) + ' ' + whereStr = whereStr.strip() + + # 有日期条件 + start_time = self.where.get('start_time', '') + end_time = self.where.get('end_time', '') + select_in_str = f"toStartOfMonth(addHours(`in_time`, 0))" + select_out_str = f"toStartOfMonth(addHours(`out_time`, 0))" + if whereStr: + sql_in = f"select {select_in_str} as date, count() as value from HR.resumes where {whereStr}" + sql_out = f"select {select_out_str} as date, count() as value from HR.resumes where {whereStr}" + else: + sql_in = f"select {select_in_str} as date, count() as value from HR.resumes" + sql_out = f"select {select_out_str} as date, count() as value from HR.resumes" + if start_time or end_time: + sql_in += f" where" + sql_out += f" where" + if start_time: + if whereStr: + sql_in += f" and toDate(addHours(`in_time`, 0)) >= '{start_time}'" + sql_out += f" and toDate(addHours(`out_time`, 0)) >= '{start_time}'" + else: + sql_in += f" toDate(addHours(`in_time`, 0)) >= '{start_time}'" + sql_out += f" toDate(addHours(`out_time`, 0)) >= '{start_time}'" + if end_time: + sql_in += f" and toDate(addHours(`in_time`, 0)) <= '{end_time}'" + sql_out += f" and toDate(addHours(`out_time`, 0)) <= '{end_time}'" + + sql_in += f" group by date" + sql_out += f" group by date" + print(sql_in, sql_out) + return { + 'sql_in': sql_in, + 'sql_out': sql_out, + 'sdate': start_time, + 'edate': end_time, + } + if __name__ == '__main__': col = 'max_interview_stage' diff --git a/utils/func.py b/utils/func.py index a117add..701f4c8 100644 --- a/utils/func.py +++ b/utils/func.py @@ -1,6 +1,7 @@ import random import time import datetime +from math import ceil import pandas as pd import smtplib from email.mime.text import MIMEText @@ -307,5 +308,32 @@ def get_every_months(sdate, edate): return month_range +# 获取两个日期之间所有的周日日期 +def get_every_weeks(sdate, edate): + start_date = datetime.datetime.strptime(sdate, '%Y-%m-%d') + end_date = datetime.datetime.strptime(edate, '%Y-%m-%d') + different_day = end_date - start_date + day_num = different_day.days + weeks = int(ceil(day_num / 7)) + week_days = [] + # 当前周的周末的日期 + start_day = get_current_week(start_date) + for i in range(weeks + 1): + day = start_day + timedelta(days=i * 7) + true_day = datetime.datetime.strftime(day, '%Y-%m-%d') + week_days.append(true_day) + return week_days + + +# 获取当前日期的周日日期 +def get_current_week(s_date): + sunday = s_date + one_day = datetime.timedelta(days=1) + while sunday.weekday() != 6: + sunday += one_day + + return sunday + + if __name__ == '__main__': get_every_months('2022-01-01', '2022-12-31') diff --git a/接口文档/各岗位招聘数据接口文档.txt b/接口文档/各岗位招聘数据接口文档.txt new file mode 100644 index 0000000..79a1f4d --- /dev/null +++ b/接口文档/各岗位招聘数据接口文档.txt @@ -0,0 +1,110 @@ +·: /api/v1/forms/year_job_form + +: +{ + "data_in": "string", # '' + "interview_query": { # ѯ + "start_time":"2022-07-10", # ѯ俪ʼʱ ʽ̶--ַ + "end_time":"2022-07-27", + "chk_type":"week" # 'day'ʾ, 'week'ʾ, 'month'ʾ ֵĬϰ + }, + "find_column": [ # [] + "string" + ] +} + +ֵ: +{ + "code": 200, + "msg": "ok", + "data": { + "res_msg": { # + "2022-07-10": { # Ӧµķ + "123": { # job_id + "Ƽ": 1, # Ӧjob_idӦķ + "Ч": 1, + "": 1, + "ͨ": 1, + "offer": 1, + "ְ": 0, + "ְ": 0 + }, + "123456": { + "Ƽ": 15, + "Ч": 14, + "": 14, + "ͨ": 13, + "offer": 13, + "ְ": 2, + "ְ": 1 + } + }, + "2022-07-17": { + "123": { + "Ƽ": 0, + "Ч": 0, + "": 0, + "ͨ": 0, + "offer": 0, + "ְ": 0, + "ְ": 0 + }, + "123456": { + "Ƽ": 3, + "Ч": 3, + "": 3, + "ͨ": 3, + "offer": 3, + "ְ": 2, + "ְ": 2 + } + }, + "2022-07-24": { + "123": { + "Ƽ": 0, + "Ч": 0, + "": 0, + "ͨ": 0, + "offer": 0, + "ְ": 0, + "ְ": 0 + }, + "123456": { + "Ƽ": 0, + "Ч": 0, + "": 0, + "ͨ": 0, + "offer": 0, + "ְ": 0, + "ְ": 0 + } + }, + "2022-07-31": { + "123": { + "Ƽ": 0, + "Ч": 0, + "": 0, + "ͨ": 0, + "offer": 0, + "ְ": 0, + "ְ": 0 + }, + "123456": { + "Ƽ": 0, + "Ч": 0, + "": 0, + "ͨ": 0, + "offer": 0, + "ְ": 0, + "ְ": 0 + } + } + }, + "job_data": { # job_idӦ,Ϣ + "123": { + "name": "߼ϷԹʦ", + "sector": "з" + } + } + } +} \ No newline at end of file diff --git a/接口文档/年度入离职数据接口文档.txt b/接口文档/年度入离职数据接口文档.txt new file mode 100644 index 0000000..d9c49c5 --- /dev/null +++ b/接口文档/年度入离职数据接口文档.txt @@ -0,0 +1,39 @@ +·: /api/v1/forms/year_in_out + +: +{ + "data_in": "string", # '' + "interview_query": { # ѯ + "start_time":"2022-01-01", # ѯ俪ʼʱ ʽ̶--ַ + "end_time":"2022-07-27", + }, + "find_column": [ # [] + "string" + ] +} + +ֵ: +{ + "code": 200, + "msg": "ok", + "data": { + "ְ": { # ְӦ + "2022-01": 0, # ·ݶӦ + "2022-02": 2, + "2022-03": 1, + "2022-04": 1, + "2022-05": 1, + "2022-06": 1, + "2022-07": 0 + }, + "ְ": { + "2022-01": 0, + "2022-02": 0, + "2022-03": 1, + "2022-04": 0, + "2022-05": 1, + "2022-06": 2, + "2022-07": 2 + } + } +} \ No newline at end of file