初始化项目

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
+32
View File
@@ -0,0 +1,32 @@
"""
全局参数。
"""
from paste.core import config
__package_name__ = "D3I"
__version__ = config.get_config('version')
__author__ = "苏州皓楷信息技术有限公司"
__email__ = "waynezwf@qq.com"
def get_version(ver = __version__):
"""
系统版本。
:param ver:
:return:
"""
return f"{__package_name__} version: V{ver}, written by {__author__}."
def get_active_env():
"""
取得激活的环境。
:return:
"""
return config.get_config('active_env')
Binary file not shown.
Binary file not shown.
View File
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
"""
数字城管接口。
"""
ApiPrefix = "/system/digital/city/management"
"""
API 前缀。
"""
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+102
View File
@@ -0,0 +1,102 @@
"""
接受OA请求,操作数字城管工单延期
"""
import logging
from typing import Optional
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_push_apply_postpone
from models.dcm_apply_delay import DcmApplyPostpone
from models.dcm_task import DcmTask
from paste.core import aio_pool
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/applyDelay')
class ApplyPostponeHandler(AppHandler):
"""
申请延期接口。
对接数字城管系统的申请延期接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dcm_task: Optional[DcmTask] = None
self.dcm_apply_postpone: Optional[DcmApplyPostpone] = None
def _params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
DcmApplyPostpone.flow_token.key: kwargs.get('flowToken', ''),
DcmApplyPostpone.dcm_task_id.key: kwargs.get('gdId', ''),
DcmApplyPostpone.task_number.key: kwargs.get('taskNumber', ''),
DcmApplyPostpone.apply_act_id.key: self.dcm_task.act_id,
DcmApplyPostpone.reply_part_id.key: kwargs.get('replyPartID', 39),
DcmApplyPostpone.ard_level.key: kwargs.get('ardLevel', 0),
DcmApplyPostpone.ard_type_id.key: kwargs.get('ardTypeId', 12),
DcmApplyPostpone.apply_memo.key: kwargs.get('opinion', ''),
DcmApplyPostpone.apply_type.key: kwargs.get('applyType', '延期'),
DcmApplyPostpone.attachments.key: kwargs.get('attachments', ''),
DcmApplyPostpone.delay_multiple.key: kwargs.get('delayMultiple', 2),
DcmApplyPostpone.time_num.key: kwargs.get('timeNum', 48),
DcmApplyPostpone.time_unit.key: kwargs.get('timeUnit', 4),
DcmApplyPostpone.postpone_date.key: kwargs.get('postponeDate', ''),
}
async def apply_postpone(self, **kwargs) -> dict:
# 必填参数校验
required_keys = [
'gdId', 'taskNumber', 'applyType', 'opinion', 'delayMultiple', 'flowToken'
]
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
if kwargs.get('delayMultiple') not in (1, 2, '1', '2'):
raise ValueError('延期倍数只能为1或2')
# 读取待办任务对象
dcm_task_id = kwargs.get('gdId', '')
self.dcm_task = await DcmTask.async_find_by_id(dcm_task_id)
# 保存请求数据
params = self._params_for_db(**kwargs)
self.dcm_apply_postpone = DcmApplyPostpone().copy_from_dict(params)
self.dcm_apply_postpone.status = 0
await self.dcm_apply_postpone.async_save()
# 后台执行提交申请延期请求到数字城管
await aio_pool.run_background_task(
dcm_push_apply_postpone.push_apply_postpone(self.dcm_apply_postpone, self.dcm_task)
)
return {
'msg': '申请延期成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 申请延期接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.apply_postpone(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+97
View File
@@ -0,0 +1,97 @@
"""
接受OA请求,操作数字城管的申请回退接口
"""
import logging
from typing import Optional
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_push_apply_rollback
from models.dcm_apply_rollback import DcmApplyRollback
from models.dcm_task import DcmTask
from paste.core import aio_pool
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/applyRollback')
class ApplyRollbackHandler(AppHandler):
"""
申请回退接口。
对接数字城管系统的申请回退接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dcm_task: Optional[DcmTask] = None
self.dcm_apply_rollback: Optional[DcmApplyRollback] = None
def _extract_params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
DcmApplyRollback.flow_token.key: kwargs.get('flowToken', ''),
DcmApplyRollback.dcm_task_id.key: kwargs.get('gdId', ''),
DcmApplyRollback.act_id.key: self.dcm_task.act_id,
DcmApplyRollback.task_number.key: kwargs.get('taskNumber', ''),
DcmApplyRollback.reply_part_id.key: kwargs.get('replyPartID', 39),
DcmApplyRollback.ard_level.key: kwargs.get('ardLevel', 0),
DcmApplyRollback.ard_type_id.key: 18 if kwargs.get('applyType', '拒签') == '拒签' else 62,
DcmApplyRollback.opinion.key: kwargs.get('opinion', ''),
DcmApplyRollback.apply_type.key: kwargs.get('applyType', '拒签'),
DcmApplyRollback.trans_info.key: kwargs.get('transInfo', '52,254,0'),
DcmApplyRollback.attachments.key: kwargs.get('attachments', '')
}
async def apply_rollback(self, **kwargs) -> dict:
# 必填参数校验
required_keys = ['gdId', 'taskNumber', 'opinion', 'applyType', 'flowToken']
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
if kwargs['applyType'] not in ('拒签', '处置阶段照片未公开'):
raise ValueError('申请类型只能为拒签或处置阶段照片未公开')
# 读取待办任务对象
dcm_task_id = kwargs.get('gdId', '')
self.dcm_task = await DcmTask.async_find_by_id(dcm_task_id)
# 保存请求数据
params = self._extract_params_for_db(**kwargs)
self.dcm_apply_rollback = DcmApplyRollback().copy_from_dict(params)
self.dcm_apply_rollback.status = 0
await self.dcm_apply_rollback.async_save()
# 后台执行提交申请回退请求到数字城管
await aio_pool.run_background_task(
dcm_push_apply_rollback.push_apply_rollback(self.dcm_apply_rollback, self.dcm_task)
)
return {
'msg': '申请回退成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 申请回退接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.apply_rollback(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+96
View File
@@ -0,0 +1,96 @@
"""
接受OA请求,操作数字城管的工单批转接口
"""
import logging
from typing import Optional
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_push_dispose
from models.dcm_dispose import DcmDispose
from models.dcm_task import DcmTask
from paste.core import aio_pool
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/transfer')
class DisposeHandler(AppHandler):
"""
批转接口。
对接数字城管系统的批转接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dcm_task: Optional[DcmTask] = None
self.dcm_dispose: Optional[DcmDispose] = None
def _params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
DcmDispose.flow_token.key: kwargs.get('flowToken', ''),
DcmDispose.dcm_task_id.key: kwargs.get('gdId', ''),
DcmDispose.act_id.key: self.dcm_task.act_id,
DcmDispose.task_number.key: kwargs.get('taskNumber', ''),
DcmDispose.opinion.key: kwargs.get('opinion', ''),
DcmDispose.attachments.key: kwargs.get('attachments', ''),
DcmDispose.send_message.key: kwargs.get('sendMessage', '1'),
DcmDispose.trans_info.key: '52,254,0,0',
DcmDispose.add_num.key: kwargs.get('addNum', '0'),
DcmDispose.task_list_id.key: kwargs.get('taskListId', '600058'),
DcmDispose.undertake_user_name.key: kwargs.get('undertakeUserName', ''),
DcmDispose.undertake_phone.key: kwargs.get('undertakePhone', '')
}
async def dispose(self, **kwargs) -> dict:
# 必填参数校验
required_keys = ['gdId', 'taskNumber', 'opinion', 'attachments', 'flowToken']
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
# 读取待办任务对象
dcm_task_id = kwargs.get('gdId', '')
self.dcm_task = await DcmTask.async_find_by_id(dcm_task_id)
# 保存请求数据
params = self._params_for_db(**kwargs)
self.dcm_dispose = DcmDispose().copy_from_dict(params)
self.dcm_dispose.status = 0
await self.dcm_dispose.async_save()
# 后台执行提交批转请求到数字城管
await aio_pool.run_background_task(
dcm_push_dispose.push_dispose(self.dcm_dispose, self.dcm_task)
)
return {
'msg': '批转成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 批转接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.dispose(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+58
View File
@@ -0,0 +1,58 @@
"""
接受OA请求,读取数字城管的是否允许申请延期。
"""
import logging
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_scrape_allow_postpone
from models.dcm_task import DcmTask
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/fetchAllowPostpone')
class AllowPostponeHandler(AppHandler):
"""
获取是否允许申请延期接口。
对接数字城管系统的获取是否允许申请延期接口,用于判断工单有哪些是否允许申请延期。
"""
async def fetch_allow_postpone(self, **kwargs) -> dict:
# 必填参数校验
required_keys = ['gdId']
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
dcm_task_id = kwargs.get('gdId', '')
dcm_task = await DcmTask(id=dcm_task_id).async_find_first()
assert dcm_task, f"未找到待办工单,工单ID{dcm_task_id}"
success, message = await dcm_scrape_allow_postpone.fetch_allow_postpone(dcm_task)
return {
'success': success,
'msg': message,
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 获取是否允许申请延期接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.fetch_allow_postpone(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+59
View File
@@ -0,0 +1,59 @@
"""
接受OA请求,读取数字城管的便民表单。
"""
import logging
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_scrape_conv_dispose
from models.dcm_task import DcmTask
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/fetchDisposeForm')
class FetchConvenientFormHandler(AppHandler):
"""
获取便民表单接口。
对接数字城管系统的获取便民表单接口,用于判断工单有哪些便民表单。
"""
async def fetch_form(self, **kwargs) -> dict:
# 必填参数校验
required_keys = ['gdId', 'formId']
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
dcm_task_id = kwargs.get('gdId', '')
dcm_task = await DcmTask(id=dcm_task_id).async_find_first()
assert dcm_task, f"未找到待办工单,工单ID{dcm_task_id}"
form = await dcm_scrape_conv_dispose.fetch_form(dcm_task)
return {
'msg': '获取便民批转表单成功.',
'form': form,
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 获取便民表单接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.fetch_form(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+58
View File
@@ -0,0 +1,58 @@
"""
接受OA请求,读取数字城管的可用操作。
"""
import logging
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_scrape_operation
from models.dcm_task import DcmTask
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/fetchOperation')
class FetchOperationHandler(AppHandler):
"""
获取可用操作接口。
对接数字城管系统的获取可用操作接口,用于判断工单有哪些可用操作。
"""
async def fetch_operations(self, **kwargs) -> dict:
# 必填参数校验
required_keys = ['gdId']
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
dcm_task_id = kwargs.get('gdId', '')
dcm_task = await DcmTask(id=dcm_task_id).async_find_first()
assert dcm_task, f"未找到待办工单,工单ID{dcm_task_id}"
operations = await dcm_scrape_operation.fetch_operation(dcm_task)
return {
'msg': '获取可用操作成功.',
'operations': operations,
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 获取可用操作接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.fetch_operations(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+59
View File
@@ -0,0 +1,59 @@
"""
接受OA请求,读取数字城管的便民表单。
"""
import logging
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_scrape_conv_rollback
from models.dcm_task import DcmTask
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/fetchRollbackForm')
class FetchRollbackFormHandler(AppHandler):
"""
获取便民表单接口。
对接数字城管系统的获取便民表单接口,用于判断工单有哪些便民表单。
"""
async def fetch_form(self, **kwargs) -> dict:
# 必填参数校验
required_keys = ['gdId', 'formId']
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
dcm_task_id = kwargs.get('gdId', '')
dcm_task = await DcmTask(id=dcm_task_id).async_find_first()
assert dcm_task, f"未找到待办工单,工单ID{dcm_task_id}"
form = await dcm_scrape_conv_rollback.fetch_form(dcm_task)
return {
'msg': '获取便民回退表单成功.',
'form': form,
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 获取便民表单接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.fetch_form(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+98
View File
@@ -0,0 +1,98 @@
"""
接受OA请求,操作数字城管的回退接口
"""
import logging
from typing import Optional
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_push_rollback
from models.dcm_rollback import DcmRollback
from models.dcm_task import DcmTask
from paste.core import aio_pool
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/rollback')
class RollbackHandler(AppHandler):
"""
回退接口。
对接数字城管系统的回退接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dcm_task: Optional[DcmTask] = None
self.dcm_rollback: Optional[DcmRollback] = None
def _extract_params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
DcmRollback.flow_token.key: kwargs.get('flowToken', ''),
DcmRollback.dcm_task_id.key: kwargs.get('gdId', ''),
DcmRollback.act_id.key: self.dcm_task.act_id,
DcmRollback.task_number.key: kwargs.get('taskNumber', ''),
DcmRollback.opinion.key: kwargs.get('opinion', ''),
DcmRollback.attachments.key: kwargs.get('attachments', ''),
DcmRollback.send_message.key: kwargs.get('sendMessage', '1'),
DcmRollback.trans_info.key: kwargs.get('transInfo', '50,254,0'),
DcmRollback.save_old_act_flag.key: kwargs.get('saveOldActFlag', False),
DcmRollback.rollback_reason_id.key: kwargs.get('rollbackReasonId', -1),
DcmRollback.not_assigned.key: kwargs.get('notAssigned', '0'),
DcmRollback.not_assigned_reason.key: kwargs.get('notAssignedReason', ''),
DcmRollback.undertake_user_name.key: kwargs.get('undertakeUserName', ''),
DcmRollback.undertake_phone.key: kwargs.get('undertakePhone', '')
}
async def rollback(self, **kwargs) -> dict:
# 必填参数校验
required_keys = ['gdId', 'taskNumber', 'opinion', 'flowToken']
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
# 读取待办任务对象
dcm_task_id = kwargs.get('gdId', '')
self.dcm_task = await DcmTask.async_find_by_id(dcm_task_id)
# 保存请求数据
params = self._extract_params_for_db(**kwargs)
self.dcm_rollback = DcmRollback().copy_from_dict(params)
self.dcm_rollback.status = 0
await self.dcm_rollback.async_save()
# 后台执行提交回退请求到数字城管
await aio_pool.run_background_task(
dcm_push_rollback.push_rollback(self.dcm_rollback, self.dcm_task)
)
return {
'msg': '回退成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 回退接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.rollback(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+91
View File
@@ -0,0 +1,91 @@
"""
接受OA请求,操作数字城管的阶段回复接口
"""
import logging
from typing import Optional
from apps.api import dcm
from apps.app_handler import AppHandler
from dock.dcm import dcm_push_stage_reply
from models.dcm_stage_reply import DcmStageReply
from models.dcm_task import DcmTask
from paste.core import aio_pool
from paste.core.logging import echo_log
from paste.web.decorators import route
@route(f'{dcm.ApiPrefix}/stageReply')
class StageReplyHandler(AppHandler):
"""
阶段回复接口。
对接数字城管系统的阶段回复接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dcm_task: Optional[DcmTask] = None
self.dcm_stage_reply: Optional[DcmStageReply] = None
def _params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
DcmStageReply.flow_token.key: kwargs.get('flowToken', ''),
DcmStageReply.dcm_task_id.key: kwargs.get('gdId', ''),
DcmStageReply.rec_id.key: self.dcm_task.rec_id,
DcmStageReply.act_id.key: self.dcm_task.act_id,
DcmStageReply.content.key: kwargs.get('content', ''),
DcmStageReply.task_number.key: kwargs.get('taskNumber', ''),
DcmStageReply.item_type.key: kwargs.get('itemType', 'stage_reply'),
}
async def stage_reply(self, **kwargs) -> dict:
# 必填参数校验
required_keys = ['gdId', 'taskNumber', 'content', 'flowToken']
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
# 读取待办任务对象
dcm_task_id = kwargs.get('gdId', '')
self.dcm_task = await DcmTask.async_find_by_id(dcm_task_id)
# 保存请求数据
params = self._params_for_db(**kwargs)
self.dcm_stage_reply = DcmStageReply().copy_from_dict(params)
self.dcm_stage_reply.status = 1
await self.dcm_stage_reply.async_save()
# 后台执行提交阶段回复请求到数字城管
await aio_pool.run_background_task(
dcm_push_stage_reply.push_stage_reply(self.dcm_stage_reply, self.dcm_task)
)
return {
'msg': '阶段回复成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 阶段回复接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.stage_reply(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
View File
+8
View File
@@ -0,0 +1,8 @@
"""
省12345接口。
"""
ApiPrefix = "/system"
"""
API 前缀。
"""
Binary file not shown.
+101
View File
@@ -0,0 +1,101 @@
from typing import Optional
import logging
from apps.api import govs
from apps.app_handler import AppHandler
from paste.web.decorators import route
from paste.core import aio_pool
from paste.core.logging import echo_log
from dock.govs import govs_create_order_delay
from models.govs_order_master import GovsOrderMaster
from models.govs_create_delay import GovsApplicationForDelay
@route(f'{govs.ApiPrefix}/application-for-delay-formal/create')
class CreateDelayHandler(AppHandler):
"""
申请延期接口。
对接省12345的申请延期接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.govs_order: Optional[GovsOrderMaster] = None
self.govs_delay: Optional[GovsApplicationForDelay] = None
def _params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
GovsApplicationForDelay.master_id.key: kwargs.get('gdId', ''),
GovsApplicationForDelay.gd_id.key: kwargs.get('gdId', ''),
GovsApplicationForDelay.finally_time_after_approve.key: kwargs.get('finallyTimeAfterApprove', ''),
GovsApplicationForDelay.finally_time_before_approve.key: kwargs.get('finallyTimeBeforeApprove', ''),
GovsApplicationForDelay.request_delay.key: kwargs.get('requestDelay', ''),
GovsApplicationForDelay.is_nature_day.key: kwargs.get('isNatureDay', ''),
GovsApplicationForDelay.already_notify_order_user.key: kwargs.get('alreadyNotifyOrderUser', ''),
GovsApplicationForDelay.request_reason.key: kwargs.get('requestReason', ''),
GovsApplicationForDelay.remarks.key: kwargs.get('remarks', ''),
GovsApplicationForDelay.contact_name.key: kwargs.get('contactName', ''),
GovsApplicationForDelay.contact_time.key: kwargs.get('contactTime', ''),
GovsApplicationForDelay.contact_type.key: kwargs.get('contactType', ''),
GovsApplicationForDelay.contact_type_name.key: kwargs.get('contactTypeName', ''),
GovsApplicationForDelay.reply_script.key: kwargs.get('replyScript', ''),
GovsApplicationForDelay.file_id_str.key: kwargs.get('fileIdStr', ''),
GovsApplicationForDelay.request_delay_time.key: kwargs.get('requestDelayTime', ''),
GovsApplicationForDelay.flow_token.key: kwargs.get('flowToken', '')
}
async def create_delay(self, **kwargs) -> dict:
# 必填参数校验
required_keys = [
'gdId', 'flowToken', 'finallyTimeAfterApprove', 'requestDelay', 'isNatureDay',
'alreadyNotifyOrderUser', 'requestReason'
]
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
# 读取待办任务对象
govs_task_id = kwargs.get('gdId', '')
self.govs_order = await GovsOrderMaster.async_find_by_id(govs_task_id)
# 保存请求数据
params = self._params_for_db(**kwargs)
self.govs_delay = GovsApplicationForDelay().copy_from_dict(params)
self.govs_delay.status = 0
await self.govs_delay.async_save()
# 后台执行提交申请延期请求到省12345
await aio_pool.run_background_task(
govs_create_order_delay.create_delay(self.govs_delay, self.govs_order)
)
return {
'msg': '申请延期成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 申请延期接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.create_delay(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+102
View File
@@ -0,0 +1,102 @@
from typing import Optional
import logging
from apps.api import govs
from apps.app_handler import AppHandler
from paste.web.decorators import route
from paste.core import aio_pool
from paste.core.logging import echo_log
from dock.govs import govs_create_order_return
from models.govs_order_master import GovsOrderMaster
from models.govs_create_return import GovsWorkOrderReturnFormal
@route(f'{govs.ApiPrefix}/work-order-return-formal/create')
class CreateDelayHandler(AppHandler):
"""
申请工单退回接口。
对接省12345的申请退回接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.govs_order: Optional[GovsOrderMaster] = None
self.govs_return: Optional[GovsWorkOrderReturnFormal] = None
def _params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
GovsWorkOrderReturnFormal.master_id.key: kwargs.get('gdId', ''),
GovsWorkOrderReturnFormal.flow_token.key: kwargs.get('flowToken', ''),
GovsWorkOrderReturnFormal.gd_id.key: kwargs.get('gdId', ''),
GovsWorkOrderReturnFormal.return_reason.key: kwargs.get('returnReason', ''),
GovsWorkOrderReturnFormal.return_reason_name.key: kwargs.get('returnReasonName', ''),
GovsWorkOrderReturnFormal.return_auditor_name.key: kwargs.get('returnAuditorName', ''),
GovsWorkOrderReturnFormal.return_auditor_id.key: kwargs.get('returnAuditorId', ''),
GovsWorkOrderReturnFormal.deal_opinion.key: kwargs.get('dealOpinion', ''),
GovsWorkOrderReturnFormal.reason.key: kwargs.get('reason', ''),
GovsWorkOrderReturnFormal.remark.key: kwargs.get('remark', ''),
GovsWorkOrderReturnFormal.file_id_str.key: kwargs.get('fileIdStr', ''),
GovsWorkOrderReturnFormal.process_instance_id.key: kwargs.get('processInstanceId', ''),
GovsWorkOrderReturnFormal.action_name.key: kwargs.get('actionName', ''),
GovsWorkOrderReturnFormal.order_id.key: kwargs.get('orderId', ''),
GovsWorkOrderReturnFormal.task_id.key: kwargs.get('taskId', ''),
GovsWorkOrderReturnFormal.order_no.key: kwargs.get('orderNo', ''),
GovsWorkOrderReturnFormal.case_accord_type_one_name.key: kwargs.get('caseAccordTypeOneName', ''),
GovsWorkOrderReturnFormal.case_accord_type_two_name.key: kwargs.get('caseAccordTypeTwoName', ''),
GovsWorkOrderReturnFormal.case_accord_type_three_name.key: kwargs.get('caseAccordTypeThreeName', '')
}
async def create_return(self, **kwargs) -> dict:
# 必填参数校验
required_keys = [
'gdId', 'flowToken', 'returnReason', 'returnReasonName', 'dealOpinion', 'reason'
]
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
# 读取待办任务对象
govs_task_id = kwargs.get('gdId', '')
self.govs_order = await GovsOrderMaster.async_find_by_id(govs_task_id)
# 保存请求数据
params = self._params_for_db(**kwargs)
self.govs_return = GovsWorkOrderReturnFormal().copy_from_dict(params)
self.govs_return.status = 0
await self.govs_return.async_save()
# 后台执行提交申请延期请求到省12345
await aio_pool.run_background_task(
govs_create_order_return.create_return(self.govs_return, self.govs_order)
)
return {
'msg': '申请退回成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 申请退回接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.create_return(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+102
View File
@@ -0,0 +1,102 @@
from typing import Optional
import logging
from apps.api import govs
from apps.app_handler import AppHandler
from paste.web.decorators import route
from paste.core import aio_pool
from paste.core.logging import echo_log
from dock.govs import govs_create_reply
from models.govs_order_master import GovsOrderMaster
from models.govs_create_reply import GovsReplyFormal
@route(f'{govs.ApiPrefix}/reply-formal/create')
class CreateDelayHandler(AppHandler):
"""
答复办结接口。
对接省12345的答复办结接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.govs_order: Optional[GovsOrderMaster] = None
self.govs_reply: Optional[GovsReplyFormal] = None
def _params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
GovsReplyFormal.master_id.key: kwargs.get('gdId', ''),
GovsReplyFormal.flow_token.key: kwargs.get('flowToken', ''),
GovsReplyFormal.gd_id.key: kwargs.get('gdId', ''),
GovsReplyFormal.is_contact.key: kwargs.get('isContact', ''),
GovsReplyFormal.contact_name.key: kwargs.get('contactName', ''),
GovsReplyFormal.contact_time.key: kwargs.get('contactTime', ''),
GovsReplyFormal.contact_type.key: kwargs.get('contactType', ''),
GovsReplyFormal.advice.key: kwargs.get('advice', ''),
GovsReplyFormal.reason.key: kwargs.get('reason', ''),
GovsReplyFormal.remarks.key: kwargs.get('remarks', ''),
GovsReplyFormal.file_id_str.key: kwargs.get('fileIdStr', ''),
GovsReplyFormal.save_id.key: kwargs.get('saveId', ''),
GovsReplyFormal.process_instance_id.key: kwargs.get('processInstanceId', ''),
GovsReplyFormal.business_key.key: kwargs.get('businessKey', ''),
GovsReplyFormal.order_no.key: kwargs.get('orderNo', ''),
GovsReplyFormal.action_name.key: kwargs.get('actionName', ''),
GovsReplyFormal.case_accord_type_one_name.key: kwargs.get('caseAccordTypeOneName', ''),
GovsReplyFormal.case_accord_type_two_name.key: kwargs.get('caseAccordTypeTwoName', ''),
GovsReplyFormal.case_accord_type_three_name.key: kwargs.get('caseAccordTypeThreeName', ''),
}
async def create_delay(self, **kwargs) -> dict:
# 必填参数校验
required_keys = [
'gdId', 'flowToken', 'isContact', 'contactType', 'advice', 'reason'
]
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
# 读取待办任务对象
govs_task_id = kwargs.get('gdId', '')
self.govs_order = await GovsOrderMaster.async_find_by_id(govs_task_id)
# 保存请求数据
params = self._params_for_db(**kwargs)
self.govs_reply = GovsReplyFormal().copy_from_dict(params)
self.govs_reply.status = 0
await self.govs_reply.async_save()
# 后台执行提交答复办结请求到省12345
await aio_pool.run_background_task(
govs_create_reply.create_reply(self.govs_reply, self.govs_order)
)
return {
'msg': '答复办结成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 答复办结接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.create_delay(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+101
View File
@@ -0,0 +1,101 @@
from typing import Optional
import logging
from apps.api import govs
from apps.app_handler import AppHandler
from paste.web.decorators import route
from paste.core import aio_pool
from paste.core.logging import echo_log
from dock.govs import govs_phase_wise_completion
from models.govs_order_master import GovsOrderMaster
from models.govs_phase_wise_completion import GovsPhaseWiseCompletion
@route(f'{govs.ApiPrefix}/phase-wise-completion/create')
class CreateDelayHandler(AppHandler):
"""
阶段性办结接口。
对接省12345的阶段性办结接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.govs_order: Optional[GovsOrderMaster] = None
self.phase_wise_completion: Optional[GovsPhaseWiseCompletion] = None
def _params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
GovsPhaseWiseCompletion.master_id.key: kwargs.get('gdId', ''),
GovsPhaseWiseCompletion.flow_token.key: kwargs.get('flowToken', ''),
GovsPhaseWiseCompletion.gd_id.key: kwargs.get('gdId', ''),
GovsPhaseWiseCompletion.is_contact.key: kwargs.get('isContact', ''),
GovsPhaseWiseCompletion.contact_name.key: kwargs.get('contactName', ''),
GovsPhaseWiseCompletion.contact_time.key: kwargs.get('contactTime', ''),
GovsPhaseWiseCompletion.contact_type.key: kwargs.get('contactType', ''),
GovsPhaseWiseCompletion.next_feedback_time.key: kwargs.get('nextFeedbackTime', ''),
GovsPhaseWiseCompletion.advice.key: kwargs.get('advice', ''),
GovsPhaseWiseCompletion.reason.key: kwargs.get('reason', ''),
GovsPhaseWiseCompletion.remark.key: kwargs.get('remark', ''),
GovsPhaseWiseCompletion.action_name.key: kwargs.get('actionName', ''),
GovsPhaseWiseCompletion.case_accord_type_one_name.key: kwargs.get('caseAccordTypeOneName', ''),
GovsPhaseWiseCompletion.case_accord_type_two_name.key: kwargs.get('caseAccordTypeTwoName', ''),
GovsPhaseWiseCompletion.case_accord_type_three_name.key: kwargs.get('caseAccordTypeThreeName', ''),
GovsPhaseWiseCompletion.order_id.key: kwargs.get('orderId', ''),
GovsPhaseWiseCompletion.task_id.key: kwargs.get('taskId', '')
}
async def create_delay(self, **kwargs) -> dict:
# 必填参数校验
required_keys = [
'gdId', 'flowToken', 'isContact', 'contactName', 'contactTime', 'contactType', 'nextFeedbackTime', 'advice',
'reason'
]
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
# 读取待办任务对象
govs_task_id = kwargs.get('gdId', '')
self.govs_order = await GovsOrderMaster.async_find_by_id(govs_task_id)
# 保存请求数据
params = self._params_for_db(**kwargs)
self.phase_wise_completion = GovsPhaseWiseCompletion().copy_from_dict(params)
self.phase_wise_completion.status = 0
await self.phase_wise_completion.async_save()
# 后台执行提交阶段性办结请求到省12345
await aio_pool.run_background_task(
govs_phase_wise_completion.create_phase_wise_completion(self.phase_wise_completion, self.govs_order)
)
return {
'msg': '阶段性办结成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 阶段性办结接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.create_delay(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+91
View File
@@ -0,0 +1,91 @@
from typing import Optional
import logging
from apps.api import govs
from apps.app_handler import AppHandler
from paste.web.decorators import route
from paste.core import aio_pool
from paste.core.logging import echo_log
from dock.govs import govs_save_sign
from models.govs_order_master import GovsOrderMaster
from models.govs_save_sign import GovsSaveSign
@route(f'{govs.ApiPrefix}/save-sign-for/create')
class CreateDelayHandler(AppHandler):
"""
申请延期接口。
对接省12345的申请延期接口,请求后本接口先将数据保存本地,然后响应客户端,然后开始后台启动推送。
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.govs_order: Optional[GovsOrderMaster] = None
self.govs_sign: Optional[GovsSaveSign] = None
def _params_for_db(self, **kwargs: dict) -> dict:
"""
提取数据库所需参数。
"""
return {
GovsSaveSign.gd_id.key: kwargs.get('gdId', ''),
GovsSaveSign.flow_token.key: kwargs.get('flowToken', ''),
GovsSaveSign.order_id.key: kwargs.get('orderId', ''),
GovsSaveSign.order_no.key: kwargs.get('orderNo', ''),
GovsSaveSign.master_id.key: kwargs.get('gdId', ''),
GovsSaveSign.order_process_id.key: kwargs.get('orderProcessId', ''),
GovsSaveSign.task_id.key: kwargs.get('taskId', ''),
GovsSaveSign.flag.key: kwargs.get('flag', '')
}
async def create_delay(self, **kwargs) -> dict:
# 必填参数校验
required_keys = [
'gdId', 'flowToken'
]
missing = [
k for k in required_keys
if k not in kwargs or kwargs[k] is None
]
if missing:
raise ValueError(f"缺少必要参数: {missing}")
# 读取待办任务对象
govs_task_id = kwargs.get('gdId', '')
self.govs_order = await GovsOrderMaster.async_find_by_id(govs_task_id)
# 保存请求数据
params = self._params_for_db(**kwargs)
self.govs_sign = GovsSaveSign().copy_from_dict(params)
self.govs_sign.status = 0
await self.govs_sign.async_save()
# 后台执行提交申请延期请求到省12345
await aio_pool.run_background_task(
govs_save_sign.sign_order(self.govs_sign, self.govs_order)
)
return {
'msg': '确认签收成功.'
}
# @auth_token
async def post(self):
"""
处理 POST 请求。
---
tags:
- D3I API
summary: 申请延期接口
"""
try:
echo_log(self.request.body.decode())
_, params = self.get_request_params()
_result = await self.create_delay(**params)
self.response_ok(code=0, data=_result)
except Exception as e:
self.response_error(e, status_code=200, api_status_code=500)
self.log(msg=e, level=logging.ERROR, is_log_exc=True)
+183
View File
@@ -0,0 +1,183 @@
import datetime
import json
import os
from abc import ABC
from typing import Optional, Callable, Awaitable
from paste.rbac.rbac_user import RbacUser
from paste.util.encoder import JsonDumpsEncoder
from paste.web.handler import RequestHandler
from paste.web.param_aware_loader import ParamAwareLoader
class AppHandler(RequestHandler, ABC):
"""
控制器基类。
"""
commands: dict[str, Callable] = {}
"""
API 接口命令字典,其结构为命令名称指向对应的方法。
其结构如下::
{
command_name: method
}
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user: Optional[RbacUser] = None
"""
当前登录用户对象。
"""
self.start_at = datetime.datetime.now()
"""
实例初始化时间。
"""
self.command = ""
"""
命令。
"""
self.request_params = {}
"""
命令参数。
"""
async def after_auth_token(self, token_payload: dict):
"""
初始化登录用户信息。
"""
from paste.security import token
if token_payload != token.PRIVATE_ISS:
from jwt import InvalidTokenError
raise InvalidTokenError()
async def run_command(self):
"""
根据请求参数运行命令方法,返回命令执行结果。
"""
self.get_request_params()
assert self.command in self.commands, '请提供正确的命令参数.'
# 读取命令方法对象,并执行
_cmd_func = self.commands[self.command]
_result = _cmd_func(self, **self.request_params)
# 处理异步方法执行
if isinstance(_result, Awaitable):
_result = await _result
return _result
async def gen_html(self, template_file: str, **kwargs):
"""
生成 HTML 内容。
:param template_file: 模板文件
:param kwargs: 参数数据字典
:return: 返回生成的 HTML 文件内容
"""
# 将参数字典转换为 namedtuple,名称固定
template_data_obj = self.dict_to_namedtuple('TemplateData', {**kwargs})
# 手动构建完整命名空间,加入自定义参数,传给生成器
namespace = self.get_template_namespace()
namespace.update({'td': template_data_obj})
# 获取模板文件
template_file = f"{self.application.settings.get('template_path')}/{template_file}"
# 用参数感知模板加载器,加载模板文件,并传入 namespace 以便在加载完成后,执行数据准备
loader = ParamAwareLoader(os.path.dirname(template_file), namespace=namespace)
# 从文件中加载模板,同步完成数据准备
template = await loader.load_with_prepare(os.path.basename(template_file))
# 渲染模板,传入需要的数据
output = template.generate(**namespace)
return output
def response_ok(self, **kwargs):
self.log_request_end()
super().response_ok(**kwargs)
def response_error(self, e: Exception, status_code: int = 200, api_status_code: int = None, **kwargs):
self.log_request_end()
if api_status_code is None:
api_status_code = status_code
self.set_status(status_code=status_code)
chunk = {'code': api_status_code, 'status': 'error'}
chunk.update(kwargs)
if len(e.args) > 0 and isinstance(e.args[0], str):
chunk['msg'] = e.args[0]
if len(e.args) > 1:
if isinstance(e.args[1], dict):
chunk.update(e.args[1])
elif isinstance(e.args[1], list):
chunk['errors'] = e.args[1]
self.write(json.dumps(chunk, cls=JsonDumpsEncoder, ensure_ascii=False))
self.set_header('Content-Type', 'application/json')
def get_request_params(self):
"""
读取命令名称及请求参数。注意,参数命名应当避开 cmd 和 params。
该方法自动合并参数,并输出请求开始日志。
支持通过 Form 或 Json 两种方式提交请求并读取相应参数。
如使用 Form 方式,则应当在 form-data 中包含名为 cmd 的输入项,其值为对应的命令,其他输入项为命令参数。
注意:不会自动读取上传的文件数据,可通过::
self.request.files
方法读取上传的文件。
如使用 Json 方式,则应当遵循以下结构::
{
cmd: command_name,
params:
{
key: value
}
}
:return: 命令,命令对应的参数
"""
_arguments = self.request_arguments()
_cmd = _arguments.get('cmd', None)
_params = _arguments.get('params', None)
if _params is None:
_arguments.pop('cmd', None)
_params = _arguments
self.command = _cmd
self.request_params = _params
# 合成规则参数到参数字典,规则参数可在相应规则中修改
self.request_params.update(self.rule_kwargs)
# 取得命令和参数之后,记录请求开始日志
self.log_request_start()
return self.command, self.request_params
def log_request_end(self):
end_at = datetime.datetime.now()
total_delta = (end_at - self.start_at).total_seconds()
_spend = f"耗时:{total_delta:f} 秒."
_user_name = self.user.username if self.user else 'Unknown'
_log = f"O 用户:{_user_name} 完成 {self.request.uri}"
_log = f"{_log} 接口命令 {self.command}{_spend}" if self.command else f"{_log} 请求,{_spend}"
self.log(_log)
def log_request_start(self):
"""
收到请求时记录的日志
"""
_user_name = self.user.username if self.user else 'Unknown'
_log = f"I 用户:{_user_name} 请求 {self.request.uri}"
_log = f"{_log} 接口命令 {self.command}." if self.command else f"{_log}."
self.log(_log)