初始化项目

This commit is contained in:
zwf
2026-06-02 17:46:38 +08:00
commit 646a4d02c0
240 changed files with 33662 additions and 0 deletions
+481
View File
@@ -0,0 +1,481 @@
# coding: utf-8
import datetime
import random
from typing import Union
import pandas as pd
from sqlalchemy import select, delete
from tornado_swagger.model import register_swagger_model
from wtforms import StringField, TextAreaField, IntegerField, DateTimeField
from wtforms.validators import Length
import models
from models.common_model import CommonModel
from models.db_models import TD3iGovsOrderMaster
from paste.core.logging import echo_log
from paste.rbac.rbac_user import RbacUser
from paste.util.pagination import Pagination
from paste.web.form import ModelForm
class GovsOrderMasterForm(ModelForm):
"""省12345工单主表表单验证类"""
id = IntegerField('工单唯一ID')
belong_dept = StringField('所属部门', validators=[Length(max=100)])
order_id = StringField('工单编号', validators=[Length(max=50)])
order_no = StringField('工单号', validators=[Length(max=50)])
order_type = IntegerField('表单类型')
order_source = StringField('诉求来源', validators=[Length(max=30)])
order_source_detail = StringField('诉求来源详情', validators=[Length(max=30)])
order_status = StringField('工单状态', validators=[Length(max=50)])
order_user_id = StringField('用户ID', validators=[Length(max=50)])
order_user_name = StringField('来电人姓名', validators=[Length(max=50)])
order_user_sex = StringField('来电人性别', validators=[Length(max=50)])
order_user_phone2 = StringField('备用联系电话', validators=[Length(max=20)])
order_handle_way = StringField('处理方式', validators=[Length(max=50)])
order_invalid_type = StringField('工单作废原因', validators=[Length(max=50)])
master_id = IntegerField('工单主表ID')
call_number = StringField('来电号码', validators=[Length(max=20)])
contact_number = StringField('联系电话', validators=[Length(max=20)])
title = StringField('工单标题', validators=[Length(max=100)])
call_time = DateTimeField('来电时间')
first_order_status = StringField('一级状态编码', validators=[Length(max=10)])
secord_order_status = StringField('二级状态编码', validators=[Length(max=10)])
atomic_order_status = StringField('原子状态编码', validators=[Length(max=10)])
area_code = StringField('区域代码', validators=[Length(max=10)])
area_code_city = StringField('市区域代码', validators=[Length(max=50)])
area_code_area = StringField('区区域代码', validators=[Length(max=50)])
area_code_street = StringField('街道区域代码', validators=[Length(max=50)])
address_detail = TextAreaField('详细地址')
case_lnglat = StringField('地理坐标', validators=[Length(max=50)])
case_accord_type_one_name = StringField('诉求归口一级', validators=[Length(max=50)])
case_accord_type_two_name = StringField('诉求归口二级', validators=[Length(max=50)])
case_accord_type_three_name = StringField('诉求归口三级', validators=[Length(max=50)])
case_accord_type_four_name = StringField('四级事项分类', validators=[Length(max=50)])
case_accord_type_five_name = StringField('五级事项分类', validators=[Length(max=50)])
case_content = TextAreaField('诉求内容')
case_goal = TextAreaField('诉求目的')
case_labels = TextAreaField('工单标签列表')
case_public = StringField('是否公开', validators=[Length(max=10)])
case_is_urgent = IntegerField('紧急程度')
case_comple_time = DateTimeField('案件办结时间')
first_level_affiliation = StringField('一级归属单位', validators=[Length(max=50)])
second_level_affiliation = StringField('二级归属单位', validators=[Length(max=50)])
third_level_affiliation = StringField('三级归属单位', validators=[Length(max=50)])
fourth_level_affiliation = StringField('四级归属单位', validators=[Length(max=50)])
fifth_level_affiliation = StringField('五级归属单位', validators=[Length(max=50)])
case_accord_code = StringField('事项编码', validators=[Length(max=50)])
sixth_level_affiliation = StringField('六级归属单位', validators=[Length(max=50)])
seventh_level_affiliation = StringField('七级归属单位', validators=[Length(max=50)])
info_protect = IntegerField('信息保护')
case_is_visit = IntegerField('是否回访')
service_object_type = IntegerField('服务对象类型')
hotspot = StringField('是否热点事件', validators=[Length(max=10)])
result_satisfied = StringField('结果满意度', validators=[Length(max=10)])
first_vist_satisfied = StringField('首次走访满意度', validators=[Length(max=10)])
contact_timely = StringField('是否及时联系', validators=[Length(max=50)])
distribute_type = StringField('分派类型', validators=[Length(max=50)])
active_dept_ids = StringField('当前处理部门ID列表', validators=[Length(max=255)])
active_dept_name = StringField('当前处理部门名称', validators=[Length(max=50)])
case_solve = TextAreaField('处理结果')
supervise_type = StringField('监督类型', validators=[Length(max=30)])
leader_indicate = TextAreaField('领导批示')
extension = TextAreaField('扩展字段')
org_id = StringField('组织ID', validators=[Length(max=50)])
org_name = StringField('组织名称', validators=[Length(max=50)])
knowledge_quote = TextAreaField('知识引用')
special_type = StringField('特殊类型', validators=[Length(max=30)])
attachment_ids = TextAreaField('附件ID列表')
file_exist = IntegerField('是否存在附件')
record_id = StringField('通话记录ID', validators=[Length(max=50)])
call_end_time = DateTimeField('通话结束时间')
call_total_time = StringField('通话总时长', validators=[Length(max=20)])
plan_finish_time = DateTimeField('计划完成时间')
remark = TextAreaField('备注')
tenant_id = IntegerField('租户ID')
process_instance_id = StringField('流程实例ID', validators=[Length(max=100)])
visit_count = IntegerField('走访次数')
residue_date = StringField('剩余天数', validators=[Length(max=30)])
whether_approval = StringField('是否审批', validators=[Length(max=10)])
over_time_warning_flag = StringField('超时预警标志', validators=[Length(max=10)])
create_no = StringField('创建编号', validators=[Length(max=20)])
belong_platform = StringField('所属平台', validators=[Length(max=50)])
next_task_id = StringField('下一个任务ID', validators=[Length(max=64)])
return_visit_reason = TextAreaField('回访原因')
back_count = StringField('回退次数', validators=[Length(max=100)])
visit_adv_content = TextAreaField('走访建议内容')
current_processing_platform = StringField('当前处理平台', validators=[Length(max=100)])
judgment_flag = StringField('判定标志', validators=[Length(max=10)])
thrid_order_id = StringField('第三方工单ID', validators=[Length(max=50)])
is_dispatch_accurate = StringField('是否精准分派', validators=[Length(max=10)])
is_coordination = StringField('是否协调', validators=[Length(max=10)])
coordination_time = DateTimeField('协调时间')
govs_sign = IntegerField('是否已在省12345签收,1:签收,0:未签收')
creator_id = IntegerField('创建人ID')
create_by = StringField('创建人姓名', validators=[Length(max=50)])
updator_id = IntegerField('更新人ID')
update_by = StringField('更新人姓名', validators=[Length(max=50)])
create_date = DateTimeField('工单创建时间')
update_date = DateTimeField('工单更新时间')
def process(self, formdata=None, obj=None, **kwargs):
if formdata:
for name, values in formdata.items():
if isinstance(values, list) and values:
formdata[name] = [v.strip() if isinstance(v, str) else v for v in values]
elif isinstance(values, str):
formdata[name] = values.strip()
super().process(formdata, obj, **kwargs)
class GovsOrderMasterBase(TD3iGovsOrderMaster, CommonModel):
"""省12345工单主表业务基类"""
FieldMapping = {
"id": "id",
'plan_sign_time': 'planSignTime',
'claim_status': 'claimStatus',
'plan_back_time': 'planBackTime',
'handle_time': 'handleTime',
'back_time': 'backTime',
'complete_time': 'completeTime',
"belong_dept": "belongDept",
"order_id": "orderId",
"order_no": "orderNo",
"order_type": "orderType",
"order_source": "orderSource",
"order_source_detail": "orderSourceDetail",
"order_status": "orderStatus",
"order_user_id": "orderUserId",
"order_user_name": "orderUserName",
"order_user_sex": "orderUserSex",
"order_user_phone2": "orderUserPhone2",
"order_handle_way": "orderHandleWay",
"order_invalid_type": "orderInvalidType",
"next_task_id": "nextTaskId",
"master_id": "masterId",
"call_number": "callNumber",
"contact_number": "contactNumber",
"title": "title",
"call_time": "callTime",
"first_order_status": "firstOrderStatus",
"secord_order_status": "secordOrderStatus",
"atomic_order_status": "atomicOrderStatus",
"area_code": "areaCode",
"area_code_city": "areaCodeCity",
"area_code_area": "areaCodeArea",
"area_code_street": "areaCodeStreet",
"address_detail": "addressDetail",
"case_lnglat": "caseLnglat",
"case_accord_type_one_name": "caseAccordTypeOneName",
"case_accord_type_two_name": "caseAccordTypeTwoName",
"case_accord_type_three_name": "caseAccordTypeThreeName",
"case_accord_type_four_name": "caseAccordTypeFourName",
"case_accord_type_five_name": "caseAccordTypeFiveName",
"case_accord_ext": "caseAccordExt",
"case_content": "caseContent",
"case_goal": "caseGoal",
"case_labels": "caseLabels",
"case_public": "casePublic",
"case_type": "caseType",
"case_is_urgent": "caseIsUrgent",
"case_comple_time": "caseCompleTime",
"first_level_affiliation": "firstLevelAffiliation",
"second_level_affiliation": "secondLevelAffiliation",
"third_level_affiliation": "thirdLevelAffiliation",
"fourth_level_affiliation": "fourthLevelAffiliation",
"fifth_level_affiliation": "fifthLevelAffiliation",
"case_accord_code": "caseAccordCode",
"sixth_level_affiliation": "sixthLevelAffiliation",
"seventh_level_affiliation": "seventhLevelAffiliation",
"info_protect": "infoProtect",
"case_is_visit": "caseIsVisit",
"service_object_type": "serviceObjectType",
"hotspot": "hotspot",
"result_satisfied": "resultSatisfied",
"first_vist_satisfied": "firstVistSatisfied",
"contact_timely": "contactTimely",
"distribute_type": "distributeType",
"dept_type": "deptType",
"dept_name": "deptName",
"active_dept_ids": "activeDeptIds",
"active_dept_name": "activeDeptName",
"case_solve": "caseSolve",
"supervise_type": "superviseType",
"leader_indicate": "leaderIndicate",
"extension": "extension",
"org_id": "orgId",
"org_name": "orgName",
"knowledge_quote": "knowledgeQuote",
"special_type": "specialType",
"attachment_ids": "attachmentIds",
"attachment_list": "attachmentList",
"file_exist": "fileExist",
"record_id": "recordId",
"call_end_time": "callEndTime",
"call_total_time": "callTotalTime",
"plan_finish_time": "planFinishTime",
"remark": "remark",
"tenant_id": "tenantId",
"erge_revoke_plug": "ergeRevokePlug",
"exist_quoto_info": "existQuotoInfo",
"process_instance_id": "processInstanceId",
"sound_recording_address_list": "soundRecordingAddressList",
"visit_count": "visitCount",
"residue_date": "residueDate",
"whether_approval": "whetherApproval",
"over_time_warning_flag": "overTimeWarningFlag",
"create_no": "createNo",
"belong_platform": "belongPlatform",
"return_visit_reason": "returnVisitReason",
"back_count": "backCount",
"visit_adv_content": "visitAdvContent",
"tripartite_call_record_info": "tripartiteCallRecordInfo",
"knowledge_references": "knowledgeReferences",
"current_processing_platform": "currentProcessingPlatform",
"judgment_flag": "judgmentFlag",
"thrid_order_id": "thridOrderId",
"is_dispatch_accurate": "isDispatchAccurate",
"is_coordination": "isCoordination",
"coordination_time": "coordinationTime",
"creator_id": "creatorId",
"create_by": "createBy",
"updator_id": "updatorId",
"update_by": "updateBy"
}
@classmethod
async def exist_other(cls, id: Union[str, int], order_id: str = None, order_no: str = None):
"""检查是否存在除当前工单外的其他同编号工单"""
_query = select(cls).where(cls.id != id)
if order_id:
_query = _query.where(cls.order_id == order_id)
if order_no:
_query = _query.where(cls.order_no == order_no)
_task: cls = await cls.query_first(_query)
return _task
@classmethod
async def find_by_ids(cls, ids: list[Union[str, int]]):
"""根据ID列表批量查找工单"""
_query = select(cls).where(cls.id.in_(ids))
_list: list[cls] = (await cls.orm_execute_scalars(_query)).all()
return _list
@classmethod
async def is_exist(cls, order_id: str = None, order_no: str = None):
"""检查工单是否已经存在"""
_query = select(cls)
if order_id:
_query = _query.where(cls.order_id == order_id)
if order_no:
_query = _query.where(cls.order_no == order_no)
_task: cls = await cls.query_first(_query)
return _task
@classmethod
async def search_base(cls, is_paging=True, **kwargs):
"""按参数搜索工单的基础方法"""
page_number = kwargs.get('page_number', random.randint(1, 100))
page_size = kwargs.get('page_size', 20)
kwargs.update({'page_number': page_number, 'page_size': page_size})
_name_likes = {
cls.order_status.key: '%{}%',
cls.order_source.key: '%{}%',
cls.case_accord_type_one_name.key: '%{}%',
}
_query = select(cls).where(
*cls.search_wheres(likes=_name_likes, **kwargs)
).group_by(cls.id)
_paging = None
if is_paging:
_row_count = await cls.query_count(_query)
_paging = Pagination(_row_count).paging(page_number, page_size)
_data_query = _query.limit(page_size).offset(_paging.offset_size)
else:
_data_query = _query.where()
_sort_clause = cls.sort_clauses(kwargs.get('sort_clause', {}))
if _sort_clause:
_data_query = _data_query.order_by(*_sort_clause)
else:
_data_query = _data_query.order_by(cls.create_date.desc())
_df = await cls.query_as_df(_data_query)
if not _df.empty:
_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
_df[cls.id.key] = _df[cls.id.key].astype(str)
return _df, _paging
@classmethod
async def search(cls, **kwargs):
"""按参数搜索工单,返回分页格式数据"""
_df, _paging = await cls.search_base(**kwargs)
return {
'total': _paging.row_count,
'rows': _df.to_dict('records'),
'pagination': {
'page_number': _paging.page_number,
'page_count': _paging.page_count,
'page_size': _paging.page_size,
},
}
@classmethod
async def exists_order_id(cls, data_df: pd.DataFrame):
"""根据 order_id 判断数据是否存在"""
if data_df.empty:
return pd.DataFrame(), pd.DataFrame()
order_ids = data_df[cls.order_id.key].unique().tolist()
if not order_ids:
return pd.DataFrame(), data_df.copy()
_query = select(cls.id, cls.order_id).where(cls.order_id.in_(order_ids))
existing_df = await cls.query_as_df(_query)
if existing_df.empty:
return pd.DataFrame(), data_df.copy()
order_id_to_id_map = dict(zip(existing_df[cls.order_id.key], existing_df[cls.id.key]))
mask_exists = data_df[cls.order_id.key].isin(existing_df[cls.order_id.key])
exists_df = data_df[mask_exists].copy()
exists_df[cls.id.key] = exists_df[cls.order_id.key].map(order_id_to_id_map)
latest_df = data_df[~mask_exists].copy()
return exists_df, latest_df
@register_swagger_model
class GovsOrderMaster(GovsOrderMasterBase):
"""省12345工单主表业务类"""
@classmethod
async def create(cls, user: RbacUser = None, **kwargs):
"""创建新工单"""
for _k, _v in kwargs.items():
if isinstance(_v, str):
kwargs[_k] = _v.strip()
_form = GovsOrderMasterForm(formdata=kwargs)
_form.validate_form()
_existing = await cls.is_exist(
order_id=_form.order_id.data,
order_no=_form.order_no.data
)
assert _existing is None, "工单编号或工单号已存在,不能重复创建。"
_task = cls().copy_from_dict(_form.data, skip_none=True)
if user:
_task.created_by = user.username
_task.updated_by = user.username
await _task.async_save()
return _task
@classmethod
async def delete(cls, task_id: Union[str, int]):
"""删除工单"""
_task: cls = await cls.async_find_by_id(task_id)
assert _task, f"根据 ID {task_id} 未找到工单。"
_del_query = delete(cls).where(cls.id == _task.id)
await cls.raw_execute(_del_query)
echo_log(f'已删除工单(工单号:{_task.order_no}ID{_task.id}.')
return _task
@classmethod
async def modify(cls, task_id: Union[str, int], user: RbacUser = None, **kwargs):
"""修改工单信息"""
for _k, _v in kwargs.items():
if isinstance(_v, str):
kwargs[_k] = _v.strip()
_form = GovsOrderMasterForm(formdata=kwargs)
_form.validate_form()
_other = await cls.exist_other(
task_id,
order_id=_form.order_id.data,
order_no=_form.order_no.data
)
assert _other is None, "工单编号或工单号已存在,不能重复修改。"
_task: cls = await cls.async_find_by_id(task_id)
assert _task, f'查无此工单信息。'
_task.copy_from_dict(_form.data, skip_none=True).before_save()
if user:
_task.updated_by = user.username
await _task.async_save()
return _task
@classmethod
async def create_batch(cls, data_df: pd.DataFrame, user: RbacUser = None):
"""批量创建工单"""
if data_df.empty:
return 0
if user:
data_df['created_by'] = user.username
data_df['updated_by'] = user.username
records = data_df.to_dict('records')
tasks = [cls().copy_from_dict(record, skip_none=True) for record in records]
session = cls.get_aio_session()
try:
session.add_all(tasks)
await session.commit()
except Exception as e:
await session.rollback()
raise e
finally:
await session.close()
echo_log(f"批量创建成功:创建 {len(tasks)} 条工单。")
return len(tasks)
@classmethod
async def modify_batch(cls, data_df: pd.DataFrame, user: RbacUser = None):
"""批量修改工单"""
if data_df.empty:
return 0
if 'id' not in data_df.columns:
echo_log(f"错误:modify_batch 要求输入数据必须包含 '{cls.id.key}'")
return 0
data_df['updated_at'] = datetime.datetime.now()
if user:
data_df['updated_by'] = user.username
update_data = data_df.to_dict('records')
session = cls.get_aio_session()
try:
await session.run_sync(
lambda sync_session: sync_session.bulk_update_mappings(cls, update_data)
)
await session.commit()
updated_count = len(update_data)
except Exception as e:
await session.rollback()
raise e
finally:
await session.close()
echo_log(f"批量修改成功:更新 {updated_count} 条工单。")
return updated_count
@classmethod
async def save_batch(cls, data_df: pd.DataFrame, user: RbacUser = None):
"""批量保存数据,自动处理新建和更新"""
_exists_df, _latest_df = await cls.exists_order_id(data_df)
_created_count = await cls.create_batch(_latest_df, user)
_updated_count = await cls.modify_batch(_exists_df, user)
return _created_count, _updated_count