招聘趋势
This commit is contained in:
parent
e79f61a6a6
commit
4b166150b8
@ -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')
|
||||
|
||||
|
@ -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)
|
||||
|
64
api/api_v1/endpoints/worker_info.py
Normal file
64
api/api_v1/endpoints/worker_info.py
Normal 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)
|
||||
|
||||
|
@ -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
34
crud/crud_worker_info.py
Normal 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')
|
@ -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岁")
|
||||
|
@ -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
14
schemas/worker.py
Normal 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 # 显示列名
|
@ -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
|
||||
|
49
接口文档/招聘趋势分析接口文档.txt
Normal file
49
接口文档/招聘趋势分析接口文档.txt
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user