招聘趋势

This commit is contained in:
Àî×ÚÕñ 2022-07-25 18:13:17 +08:00
parent e79f61a6a6
commit 4b166150b8
10 changed files with 316 additions and 18 deletions

View File

@ -11,6 +11,7 @@ from .endpoints import query
from .endpoints import xquery
from .endpoints import interview
from .endpoints import forms
from .endpoints import worker_info
from .endpoints import data_auth
from .endpoints import event_mana
from .endpoints import test
@ -43,4 +44,5 @@ api_router.include_router(user_label.router, tags=["用户标签"], prefix='/use
api_router.include_router(interview.router, tags=["面试数据管理"], prefix='/itr')
api_router.include_router(forms.router, tags=["hr报表模板管理"], prefix='/forms')
api_router.include_router(worker_info.router, tags=["入职人员信息管理"], prefix='/worker')

View File

@ -8,6 +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
import crud, schemas
from datetime import datetime
from core.configuration import *
@ -271,6 +272,8 @@ async def every_stage_form(
res = interview.get_every_stage_form_sql(job_ids)
sql = res['sql']
data = await ck_db.execute(sql)
if not data:
return schemas.Msg(code=-9, msg='无数据', data=None)
for ck_data in data.values():
# 职位id不存在跳过
if ck_data['job_id'] not in job_id_to_name:
@ -304,6 +307,8 @@ async def hr_works_form(
res = interview.get_hr_works_form_sql()
sql = res['sql']
data = await ck_db.execute(sql)
if not data:
return schemas.Msg(code=-9, msg='无数据', data=None)
res_msg = {}
job_name_sector = {}
hr_names = [] # 查询面试数据
@ -437,6 +442,8 @@ async def stage_success_form(
res = interview.get_every_stage_form_sql(job_ids)
sql = res['sql']
data = await ck_db.execute(sql)
if not data:
return schemas.Msg(code=-9, msg='无数据', data=None)
for ck_data in data.values():
# 职位id不存在跳过
if ck_data['job_id'] not in job_id_to_name:
@ -505,14 +512,16 @@ async def interview_funnel_form(
res = interview.get_hr_works_form_sql()
sql = res['sql']
data = await ck_db.execute(sql)
if not data:
return schemas.Msg(code=-9, msg='无数据', data=None)
res_msg = {
'初筛': 0,
'复筛': 0,
'面试': 0,
'offer': 0,
'待入职': 0,
'已入职': 0
}
'初筛': 0,
'复筛': 0,
'面试': 0,
'offer': 0,
'待入职': 0,
'已入职': 0
}
for i_data in data.values():
stage = i_data['interview_stage']
if stage >= 1:
@ -543,6 +552,8 @@ async def owner_form(
res = interview.get_owner_form_sql()
sql = res['sql']
data = await db.execute(sql)
if not data:
return schemas.Msg(code=-9, msg='无数据', data=None)
# 简历渠道
owner_dict = {1: '前程无忧', 2: '人才库', 3: '智联招聘', 4: 'Boss直聘', 5: '58同城'}
chk_data = {
@ -597,3 +608,42 @@ async def owner_form(
return schemas.Msg(code=200, msg='ok', data=res_msg)
# 招聘趋势分析报表
@router.post("/interview_trend_form")
async def interview_trend_form(
request: Request,
interview: InterviewDo = Depends(InterviewDo),
ck_db: CKDrive = Depends(get_ck_db)
) -> schemas.Msg:
""" 招聘趋势分析报表 """
await interview.init()
res = interview.get_trend_form_sql()
sql = res['sql']
data = await ck_db.execute(sql)
if not data:
return schemas.Msg(code=-9, msg='无数据', data=None)
sdate = res['sdate']
edate = res['edate']
days = get_every_days(sdate, edate)
res_msg = {}
for i in days:
res_msg[str(i)] = {
'初筛简历数': 0,
'初筛': 0,
'创建面试的申请数': 0
}
for chk_data in data.values():
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']
if chk_stage >= 1:
res_msg[chk_date]['初筛简历数'] += 1 * count_num
if chk_stage >= 2:
res_msg[chk_date]['初筛'] += 1 * count_num
if chk_stage >= 3:
res_msg[chk_date]['创建面试的申请数'] += 1 * count_num
return schemas.Msg(code=200, msg='ok', data=res_msg)

View File

@ -0,0 +1,64 @@
import operator
import os
import re
import pandas as pd
from copy import deepcopy
from fastapi import APIRouter, Depends, Request, File, UploadFile
from motor.motor_asyncio import AsyncIOMotorDatabase
from utils.dingding import get_redis_alluid, send_dates
from utils.jianli import get_resume
import crud, schemas
from datetime import datetime
from core.configuration import *
from db import get_database
from db.ckdb import get_ck_db, CKDrive
from models.interview_zsgc import InterviewDo
from utils import get_time, qujian_time, Download_xlsx, send_str_mail
router = APIRouter()
# 增加入职人员
@router.post("/add_worker")
async def add_worker(
request: Request,
data_in: schemas.WorkerQuery,
db: AsyncIOMotorDatabase = Depends(get_database)
) -> schemas.Msg:
""" 增加入职人员信息 """
data = await crud.worker_info.insert_worker(db, data_in.data_in)
return schemas.Msg(code=200, msg='ok', data=data)
# 查询入职人员信息
@router.post("/find_worker")
async def add_worker(
request: Request,
data_in: schemas.WorkerQuery,
db: AsyncIOMotorDatabase = Depends(get_database)
) -> schemas.Msg:
""" 查询入职人员信息 """
data = await crud.worker_info.find_worker_some(db, findlist=data_in.find_filed)
return schemas.Msg(code=200, msg='ok', data=data)
# 修改入职人员信息
@router.post("/update_worker")
async def add_worker(
request: Request,
data_in: schemas.WorkerQuery,
db: AsyncIOMotorDatabase = Depends(get_database)
) -> schemas.Msg:
""" 修改入职人员信息 """
data = await crud.worker_info.update_worker(db, data_in.worker_query, data_in.data_in)
return schemas.Msg(code=200, msg='ok', data=data)

View File

@ -27,3 +27,4 @@ from .crud_interview_modes import api_interview_modes
from .crud_email_record import email_record
from .crud_operate_log import operate_log
from .crud_interview_record import interview_record
from .crud_worker_info import worker_info

34
crud/crud_worker_info.py Normal file
View File

@ -0,0 +1,34 @@
from motor.motor_asyncio import AsyncIOMotorDatabase
import schemas
from crud.base import CRUDBase
__all__ = 'worker_info',
class CRUDWorkerInfo(CRUDBase):
# 获取所有入职人员信息
async def all_worker(self, db: AsyncIOMotorDatabase):
return await self.find_many(db, {}, {'_id': 0})
# 获取指定字段
async def find_worker_some(self, db: AsyncIOMotorDatabase, findlist=[]):
findWhere = {'_id': 0}
if findlist:
for key in findlist:
findWhere.update({
key: 1
})
return await self.find_many(db, {}, findWhere)
# 更新一条入职人员信息
async def update_worker(self, db: AsyncIOMotorDatabase, where, updatedata):
await self.update_one(db, where, {'$set': updatedata})
# 插入一条新的面试数据数据
async def insert_worker(self, db: AsyncIOMotorDatabase, insertdata):
await self.insert_one(db, insertdata)
worker_info = CRUDWorkerInfo('worker_info')

View File

@ -412,9 +412,12 @@ class InterviewDo:
end_time = self.where.get('end_time', '')
sql = f"select {findStr} from HR.resumes where {whereStr}"
if start_time:
sql += f" and toDate(event_time) >= {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(event_time) <= {end_time}"
sql += f" and toDate(addHours(`event_time`, 0)) <= '{end_time}'"
# 没有日期条件
else:
sql = f"select {findStr} from HR.resumes where {whereStr}"
@ -453,10 +456,15 @@ class InterviewDo:
sql = f"select {findStr} from HR.resumes where {whereStr}"
else:
sql = f"select {findStr} from HR.resumes"
if start_time or end_time:
sql += f" where"
if start_time:
sql += f" and toDate(event_time) >= {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(event_time) <= {end_time}"
sql += f" and toDate(addHours(`event_time`, 0)) <= '{end_time}'"
# 没有日期条件
else:
if whereStr:
@ -498,10 +506,15 @@ class InterviewDo:
sql = f"select {findStr} from HR.resumes where {whereStr}"
else:
sql = f"select {findStr} from HR.resumes where '1'"
if start_time or end_time:
sql += f" where"
if start_time:
sql += f" and toDate(event_time) >= {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(event_time) <= {end_time}"
sql += f" and toDate(addHours(`event_time`, 0)) <= '{end_time}'"
# 没有日期条件
else:
if whereStr:
@ -542,10 +555,15 @@ class InterviewDo:
sql = f"select {findStr} from HR.resumes where {whereStr} and job_id in {job_ids}"
else:
sql = f"select {findStr} from HR.resumes where job_id in {job_ids}"
if start_time or end_time:
sql += f" where"
if start_time:
sql += f" and toDate(event_time) >= {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(event_time) <= {end_time}"
sql += f" and toDate(addHours(`event_time`, 0)) <= '{end_time}'"
# 没有日期条件
else:
if whereStr:
@ -586,10 +604,15 @@ class InterviewDo:
sql = f"select {findStr} from HR.resumes where {whereStr}"
else:
sql = f"select {findStr} from HR.resumes"
if start_time or end_time:
sql += f" where"
if start_time:
sql += f" and toDate(event_time) >= {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(event_time) <= {end_time}"
sql += f" and toDate(addHours(`event_time`, 0)) <= '{end_time}'"
# 没有日期条件
else:
if whereStr:
@ -601,6 +624,52 @@ class InterviewDo:
'sql': sql
}
# 招聘趋势分析sql
def get_trend_form_sql(self):
whereStr = ''
is_date = 0
if self.where:
for key, value in self.where.items():
if key in ['start_time', 'end_time']:
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', '')
if is_date:
if whereStr:
sql = f"select toDate(addHours(`event_time`, 0)) as date,interview_stage, count() as value from HR.resumes where {whereStr}"
else:
sql = f"select toDate(addHours(`event_time`, 0)) as date,interview_stage, count() as value from HR.resumes"
if start_time or end_time:
sql += f" where"
if start_time:
if whereStr:
sql += f" and date >= '{start_time}'"
else:
sql += f" date >= '{start_time}'"
if end_time:
sql += f" and date <= '{end_time}'"
# 没有日期条件
else:
if whereStr:
sql = f"select toDate(addHours(`event_time`, 0)) as date,interview_stage, count() as value from HR.resumes where {whereStr}"
else:
sql = f"select toDate(addHours(`event_time`, 0)) as date,interview_stage, count() as value from HR.resumes"
sql += f" group by date, interview_stage"
print(sql)
return {
'sql': sql,
'sdate': start_time,
'edate': end_time,
}
if __name__ == '__main__':
find = re.search(r"\d+\.?\d*", "18岁")

View File

@ -33,3 +33,4 @@ from .email_record import *
from .operate_log import *
from .interview_modes import *
from .interview_record import *
from .worker import *

14
schemas/worker.py Normal file
View File

@ -0,0 +1,14 @@
from typing import Dict, List, Union, Any
from pydantic import BaseModel
# 面试数据包含字段样式
class WorkerModel(BaseModel):
pass
# 面试查询格式
class WorkerQuery(BaseModel):
data_in: Any
worker_query: dict = dict() # 查询删选条件
find_filed: List[str] = None # 显示列名

View File

@ -279,4 +279,18 @@ def start_end_month(time):
this_month_start = datetime.datetime(now.year, now.month, 1)
this_month_end = datetime.datetime(now.year, now.month, calendar.monthrange(now.year, now.month)[1])
this_month_end1 = this_month_end + timedelta(hours=23, minutes=59, seconds=59)
return this_month_start, this_month_end1
return this_month_start, this_month_end1
# 获取两个日期之间的所有天数
def get_every_days(sdate, edate):
days = []
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
for i in range(day_num + 1):
day = start_date + timedelta(days=i)
true_day = datetime.datetime.strftime(day, '%Y-%m-%d')
days.append(true_day)
return days

View File

@ -0,0 +1,49 @@
路由: /api/v1/itr/interview_trend_form
参数:
{
"data_in": "string", 可为空字符串 ""
"interview_query": {"start_time":"2022-07-10", "end_time":"2022-07-15"}, 条件查询区间 开始结束时间 "年-月-日"格式字符串
"find_column": [ 可为空列表[]
"string"
]
}
返回值:
{
"code": 200,
"msg": "ok",
"data": { 日期对应的数据
"2022-07-10": {
"初筛简历数": 0,
"初筛": 0,
"创建面试的申请数": 0
},
"2022-07-11": {
"初筛简历数": 0,
"初筛": 0,
"创建面试的申请数": 0
},
"2022-07-12": {
"初筛简历数": 2,
"初筛": 2,
"创建面试的申请数": 2
},
"2022-07-13": {
"初筛简历数": 0,
"初筛": 0,
"创建面试的申请数": 0
},
"2022-07-14": {
"初筛简历数": 0,
"初筛": 0,
"创建面试的申请数": 0
},
"2022-07-15": {
"初筛简历数": 0,
"初筛": 0,
"创建面试的申请数": 0
}
}
}