diff --git a/api/api_v1/endpoints/forms.py b/api/api_v1/endpoints/forms.py index 914a6fe..be35c95 100644 --- a/api/api_v1/endpoints/forms.py +++ b/api/api_v1/endpoints/forms.py @@ -555,13 +555,14 @@ async def owner_form( if not data: return schemas.Msg(code=-9, msg='无数据', data=None) # 简历渠道 - owner_dict = {1: '前程无忧', 2: '人才库', 3: '智联招聘', 4: 'Boss直聘', 5: '58同城'} + owner_dict = {1: '前程无忧', 2: '人才库', 3: '智联招聘', 4: 'Boss直聘', 5: '58同城', 6: '拉勾'} chk_data = { '前程无忧': [], '人才库': [], '智联招聘': [], 'Boss直聘': [], '58同城': [], + '拉勾': [] } for i in data.values(): owner_name = owner_dict[i['owner_name']] @@ -584,11 +585,14 @@ async def owner_form( '58同城': { 'count': 0 }, + '拉勾': { + 'count': 0 + } } for key, data_list in chk_data.items(): count_num = len(data_list) - offer_num = len([1 for i in data_list if i['interview_stage'] >= 5]) + offer_num = len([1 for i in data_list if i['interview_stage'] >= 4]) work_num = len([1 for i in data_list if i['interview_stage'] >= 7]) if offer_num: @@ -609,6 +613,79 @@ async def owner_form( return schemas.Msg(code=200, msg='ok', data=res_msg) +# 渠道质量报表 +@router.post("/owner_effect") +async def owner_effect( + 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.get_owner_form_sql() + sql = res['sql'] + data = await ck_db.execute(sql) + if not data: + return schemas.Msg(code=-9, msg='无数据', data=None) + # 简历渠道 + owner_dict = {1: '前程无忧', 2: '人才库', 3: '智联招聘', 4: 'Boss直聘', 5: '58同城', 6: '拉勾'} + chk_data = { + '前程无忧': [], + '人才库': [], + '智联招聘': [], + 'Boss直聘': [], + '58同城': [], + '拉勾': [], + } + for i in data.values(): + owner_name = owner_dict[i['owner_name']] + i_data = deepcopy(i) + chk_data[owner_name].append(i_data) + + res_msg = { + '前程无忧': { + 'count': 0 + }, + '人才库': { + 'count': 0 + }, + '智联招聘': { + 'count': 0 + }, + 'Boss直聘': { + 'count': 0 + }, + '58同城': { + 'count': 0 + }, + '拉勾': { + 'count': 0 + } + } + + for key, data_list in chk_data.items(): + count_num = len(data_list) + star_num = len([1 for i in data_list if i['interview_stage'] >= 1]) # 初筛 + screen_num = len([1 for i in data_list if i['interview_stage'] >= 2]) # 复筛 + exam_num = len([1 for i in data_list if i['interview_stage'] >= 3]) # 面试 + offer_num = len([1 for i in data_list if i['interview_stage'] >= 4]) # offer + work_num = len([1 for i in data_list if i['interview_stage'] >= 7]) # 入职 + res_msg[key]['count'] = count_num + res_msg[key]['star_num'] = star_num + res_msg[key]['screen_num'] = screen_num + res_msg[key]['exam_num'] = exam_num + res_msg[key]['offer_num'] = offer_num + res_msg[key]['work_num'] = work_num + + owner_info = await crud.owner_info.find_owner_some(db, findlist=['owner_name', 'year_money', 'year']) + res_data = { + 'res_msg': res_msg, + 'owner_info': owner_info + } + return schemas.Msg(code=200, msg='ok', data=res_data) + + # 招聘趋势分析报表 @router.post("/interview_trend_form") async def interview_trend_form( diff --git a/api/api_v1/endpoints/worker_info.py b/api/api_v1/endpoints/worker_info.py index 8afd12f..b577926 100644 --- a/api/api_v1/endpoints/worker_info.py +++ b/api/api_v1/endpoints/worker_info.py @@ -24,19 +24,37 @@ router = APIRouter() @router.post("/add_worker") async def add_worker( request: Request, - data_in: schemas.WorkerQuery, + data_in: schemas.InWorkerQuery, db: AsyncIOMotorDatabase = Depends(get_database) ) -> schemas.Msg: """ 增加入职人员信息 """ + insert_data = data_in.data_in + insert_data.update({ + 'worker_id': data_in.worker_id + }) + data = await crud.worker_info.insert_worker(db, insert_data) + return schemas.Msg(code=200, msg='ok', data=data) - data = await crud.worker_info.insert_worker(db, data_in.data_in) +# 增加渠道 +@router.post("/add_owner") +async def add_owner( + request: Request, + data_in: schemas.InOwnerQuery, + db: AsyncIOMotorDatabase = Depends(get_database) +) -> schemas.Msg: + """ 增加渠道信息 """ + insert_data = data_in.data_in + insert_data.update({ + 'owner_id': data_in.owner_id + }) + data = await crud.owner_info.insert_owner(db, insert_data) return schemas.Msg(code=200, msg='ok', data=data) # 查询入职人员信息 @router.post("/find_worker") -async def add_worker( +async def find_worker( request: Request, data_in: schemas.WorkerQuery, db: AsyncIOMotorDatabase = Depends(get_database) @@ -44,13 +62,43 @@ async def add_worker( """ 查询入职人员信息 """ data = await crud.worker_info.find_worker_some(db, findlist=data_in.find_filed) - + if not data: + return schemas.Msg(code=-9, msg='无数据', data=None) return schemas.Msg(code=200, msg='ok', data=data) +# 查询入职人员信息 +@router.post("/find_worker_form") +async def find_worker_form( + 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) + if not data: + return schemas.Msg(code=-9, msg='无数据', data=None) + res_msg = { + 'p1-p3': [i['name'] for i in data if i['job_level'] in ['p1', 'p2', 'p3']], + 'p4': [i['name'] for i in data if i['job_level'] == 'p4'], + 'p5': [i['name'] for i in data if i['job_level'] == 'p5'], + 'p6': [i['name'] for i in data if i['job_level'] == 'p6'], + 'p7': [i['name'] for i in data if i['job_level'] == 'p7'], + 'p8': [i['name'] for i in data if i['job_level'] == 'p8'], + 'm1': [i['name'] for i in data if i['job_level'] == 'm1'], + 'm2': [i['name'] for i in data if i['job_level'] == 'm2'], + 'm3': [i['name'] for i in data if i['job_level'] == 'm3'], + 'm4': [i['name'] for i in data if i['job_level'] == 'm4'], + '总人数': len(data) + } + + return schemas.Msg(code=200, msg='ok', data=res_msg) + + # 修改入职人员信息 @router.post("/update_worker") -async def add_worker( +async def update_worker( request: Request, data_in: schemas.WorkerQuery, db: AsyncIOMotorDatabase = Depends(get_database) @@ -58,7 +106,4 @@ async def add_worker( """ 修改入职人员信息 """ 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) - - diff --git a/crud/__init__.py b/crud/__init__.py index 8383b69..6feea1e 100644 --- a/crud/__init__.py +++ b/crud/__init__.py @@ -28,3 +28,4 @@ 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 +from .crud_owner_info import owner_info diff --git a/crud/crud_owner_info.py b/crud/crud_owner_info.py new file mode 100644 index 0000000..4db019c --- /dev/null +++ b/crud/crud_owner_info.py @@ -0,0 +1,34 @@ +from motor.motor_asyncio import AsyncIOMotorDatabase +import schemas +from crud.base import CRUDBase + +__all__ = 'owner_info', + + +class CRUDOwnerInfo(CRUDBase): + # 获取所有渠道信息 + async def all_owner(self, db: AsyncIOMotorDatabase): + return await self.find_many(db, {}, {'_id': 0}) + + # 获取指定字段 + async def find_owner_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_owner(self, db: AsyncIOMotorDatabase, where, updatedata): + + await self.update_one(db, where, {'$set': updatedata}) + + # 插入一条新的渠道数据 + async def insert_owner(self, db: AsyncIOMotorDatabase, insertdata): + + await self.insert_one(db, insertdata) + + +owner_info = CRUDOwnerInfo('owner_info') diff --git a/models/interview_zsgc.py b/models/interview_zsgc.py index edc31c0..8d79012 100644 --- a/models/interview_zsgc.py +++ b/models/interview_zsgc.py @@ -47,65 +47,23 @@ class InterviewDo: filters = [] for col, value in where.items(): + # 以下值跳过 + if col in ['time', 'start_time', 'end_time']: + continue + # 最大值 + if col in ['max_interview_stage', 'max_education']: + key = col.split('_', 1)[-1] + filters.append(key <= value) + continue + # 最小值 + if col in ['min_interview_stage', 'min_education']: + key = col.split('_', 1)[-1] + filters.append(key >= value) + continue + # 相等 filters.append(col == value) return filters - async def scatter_model_sql(self): - time = self.where.get('time', '') - start_time0 = self.where.get('start_time', '') - end_time0 = self.where.get('end_time', '') - global where - # 判断是分布分析里面的分组详情,改时间范围,其他情况都走else - if time != '': - timeParticleSize = self.where.get('timeParticleSize', 'P1M') # 筛选是按周,按月,合计等情况,用不同的时间 - if timeParticleSize == 'P1W': # 按周 - start_date, end_date = get_week(time) - if start_date < strptime(start_time0): # 开头的时间 - where = [ - func.addHours("event_time") >= start_time0, - func.addHours("event_time") <= end_date, - ] - elif end_date < strptime(end_time0): # 中间的时间 - where = [ - func.addHours("event_time") >= start_date, - func.addHours("event_time") <= end_date, ] - else: # 结尾的时间 - where = [ - func.addHours("event_time") >= start_date, - func.addHours("event_time") <= end_time0, ] - elif timeParticleSize == 'P1M': # 按月 - start_date, end_date = start_end_month(time) - if strptime(start_time0) > strptime1(time): - where = [ - func.addHours("event_time") >= start_time0, - func.addHours("event_time") <= end_date, - ] - else: - where = [ - func.addHours("event_time") >= start_date, - func.addHours("event_time") <= end_time0, - ] - else: - where = [ - func.addHours("event_time") >= start_time0, - func.addHours("event_time") <= end_time0, ] - else: - where = [ - func.addHours("event_time") >= start_time0, - func.addHours("event_time") <= end_time0, - ] - - filter = self.handler_filts(self.where) - where.extend(filter) - - qry = sa.select(*self.find_column).where(and_(*where)) - - sql = str(qry.compile(compile_kwargs={"literal_binds": True})) - print(sql) - return { - 'sql': sql - } - # 插入面试数据 def insert_interview_sql(self): # 简历初始文档 @@ -505,7 +463,7 @@ class InterviewDo: if whereStr: sql = f"select {findStr} from HR.resumes where {whereStr}" else: - sql = f"select {findStr} from HR.resumes where '1'" + sql = f"select {findStr} from HR.resumes" if start_time or end_time: sql += f" where" if start_time: @@ -670,7 +628,58 @@ class InterviewDo: 'edate': end_time, } + # 渠道效果sql + def get_owner_effect_sql(self): + findStr = '' + whereStr = '' + # 查询字段 + self.find_column = ["name", "owner_name", "interview_stage"] + for fstr in self.find_column: + findStr += fstr + ', ' + 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() + findStr = findStr.strip().strip(',') + + # 有日期条件 + if is_date: + start_time = self.where.get('start_time', '') + end_time = self.where.get('end_time', '') + if whereStr: + 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: + 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 {findStr} from HR.resumes where {whereStr}" + else: + sql = f"select {findStr} from HR.resumes" + print(sql) + return { + 'sql': sql + } + if __name__ == '__main__': - find = re.search(r"\d+\.?\d*", "18岁") - print(len(find.group())) + col = 'max_interview_stage' + if col in ['max_interview_stage', 'max_education']: + key = col.split('_', 1)[-1] + print(key) diff --git a/schemas/__init__.py b/schemas/__init__.py index 3a6468c..4639be1 100644 --- a/schemas/__init__.py +++ b/schemas/__init__.py @@ -34,3 +34,4 @@ from .operate_log import * from .interview_modes import * from .interview_record import * from .worker import * +from .owner_info import * diff --git a/schemas/interview_remark.py b/schemas/interview_remark.py index 95277cf..3a2f9fa 100644 --- a/schemas/interview_remark.py +++ b/schemas/interview_remark.py @@ -6,7 +6,7 @@ from pydantic import BaseModel # 备注信息 class BaseRemark(BaseModel): - remark_id: str = int(time.time()) # 备注的唯一id + remark_id: str = str(time.time()) # 备注的唯一id remark_from: str # 编写备注的人 comment: str # 备注内容 stage_num: int = 0 # 备注查看权限 diff --git a/schemas/owner_info.py b/schemas/owner_info.py new file mode 100644 index 0000000..c2f0810 --- /dev/null +++ b/schemas/owner_info.py @@ -0,0 +1,25 @@ +from typing import Dict, List, Union, Any +from pydantic import BaseModel +import time, random + + +def get_id(): + return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:] + + +# +class OwnerModel(BaseModel): + pass + + +# 渠道查询格式 +class OwnerQuery(BaseModel): + data_in: Any + owner_query: dict = dict() # 查询删选条件 + find_filed: List[str] = None # 显示列名 + + +# 渠道添加格式 +class InOwnerQuery(BaseModel): + data_in: dict = dict() + owner_id: str = get_id() # 渠道id diff --git a/schemas/worker.py b/schemas/worker.py index bfa9adc..7e0e4a7 100644 --- a/schemas/worker.py +++ b/schemas/worker.py @@ -1,8 +1,13 @@ from typing import Dict, List, Union, Any from pydantic import BaseModel +import time, random -# 面试数据包含字段样式 +def get_id(): + return hex(int(time.time() * 10 ** 7) + random.randint(0, 10000))[2:] + + +# class WorkerModel(BaseModel): pass @@ -12,3 +17,9 @@ class WorkerQuery(BaseModel): data_in: Any worker_query: dict = dict() # 查询删选条件 find_filed: List[str] = None # 显示列名 + + +# 入职人员添加格式 +class InWorkerQuery(BaseModel): + data_in: dict = dict() + worker_id: str = get_id() diff --git a/接口文档/人才密度接口文档.txt b/接口文档/人才密度接口文档.txt new file mode 100644 index 0000000..4d1d5d1 --- /dev/null +++ b/接口文档/人才密度接口文档.txt @@ -0,0 +1,37 @@ +·: /api/v1/worker/find_worker_form + +: +{ + "data_in": "string", Ϊַ "" + "worker_query": {}, ѯ Ϊ{} + "find_filed": [ ӿڹ̶ֵ["name", "job_level"] + "name", "job_level" + ] +} + + +ֵ: +{ + "code": 200, + "msg": "ok", + "data": { + "p1-p3": [ # Ӧְȡб + "", + "ΰ" + ], + "p4": [], + "p5": [], + "p6": [ + "ǿ" + ], + "p7": [], + "p8": [], + "m1": [], + "m2": [], + "m3": [], + "m4": [ + "չ" + ], + "": 4 # + } +} \ No newline at end of file diff --git a/接口文档/添加渠道信息接口文档.txt b/接口文档/添加渠道信息接口文档.txt new file mode 100644 index 0000000..56430d9 --- /dev/null +++ b/接口文档/添加渠道信息接口文档.txt @@ -0,0 +1,18 @@ +·: /api/v1/worker/add_owner + +: +{ + "data_in": { # ݸʽҪЩֶ + "owner_name":"Ƹ", # + "year_money":480, # + "month_money":40 # · + } +} + + +ֵ: +{ + "code": 200, + "msg": "ok", + "data": null +} \ No newline at end of file diff --git a/接口文档/渠道效果接口文档.txt b/接口文档/渠道效果接口文档.txt new file mode 100644 index 0000000..998ce8e --- /dev/null +++ b/接口文档/渠道效果接口文档.txt @@ -0,0 +1,81 @@ +·: /api/v1/forms/owner_effect + +: +{ + "data_in": "string", # Ϊ"" + "interview_query": {"start_time":"2022-01-01", "end_time":"2022-12-31"}, # ʱ ʽ -- ַ + "find_column": [ + "string" # Ϊ [] + ] +} + + +ֵ: +{ + "code": 200, + "msg": "ok", + "data": { + "res_msg": { # + "ǰ": { # + "count": 0, # + "star_num": 0, # Ƽ + "screen_num": 0, # Ч + "exam_num": 0, # + "offer_num": 0, # ͨ + "work_num": 0 # ְ + }, + "˲ſ": { + "count": 23, + "star_num": 23, + "screen_num": 23, + "exam_num": 23, + "offer_num": 23, + "work_num": 0 + }, + "Ƹ": { + "count": 0, + "star_num": 0, + "screen_num": 0, + "exam_num": 0, + "offer_num": 0, + "work_num": 0 + }, + "BossֱƸ": { + "count": 0, + "star_num": 0, + "screen_num": 0, + "exam_num": 0, + "offer_num": 0, + "work_num": 0 + }, + "58ͬ": { + "count": 0, + "star_num": 0, + "screen_num": 0, + "exam_num": 0, + "offer_num": 0, + "work_num": 0 + }, + "": { + "count": 0, + "star_num": 0, + "screen_num": 0, + "exam_num": 0, + "offer_num": 0, + "work_num": 0 + } + }, + "owner_info": [ # Ϣ + { + "owner_name": "ǰ", # + "year_money": 240, # + "year": "2022" # + }, + { + "owner_name": "Ƹ", + "year_money": 480, + "year": "2022" + } + ] + } +} \ No newline at end of file