初始化项目

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
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+140
View File
@@ -0,0 +1,140 @@
"""
待办工单附件数据上传。
对应文档接口:7、推送附件信息
"""
import asyncio
import json
from typing import Optional, Union
import pandas as pd
from sqlalchemy import select, desc
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
import models
from dock.oa import oa_api_request
from models.dcm_push_status import DcmPushStatus
from models.dcm_task import DcmTask
from models.dcm_task_attachment import DcmTaskAttachment
from models.dcm_task_file_upload import DcmTaskFileUpload
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
DcmTaskAttachmentMapping = {
DcmTaskAttachment.id.key: 'id',
DcmTaskFileUpload.oa_media_id.key: 'mediaId',
DcmTaskAttachment.media_usage.key: 'mediaUsage',
DcmTaskAttachment.act_def_name.key: 'actDefName',
DcmTaskAttachment.upload_time.key: 'uploadCreateTime',
}
"""
附件数据推送映射关系。
"""
async def after_push_attachment_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
工单推送请求响应后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
code = udict.get_by_path(body_data, 'code')
message = udict.get_by_path(body_data, 'msg')
if code==200:
dcm_task_id = getattr(response.request, "dcm_task_id")
await DcmPushStatus.set_push_task_attachment_status(dcm_task_id)
echo_log(f"推送企业待办附件成功.")
else:
echo_log(f"推送企业待办附件失败:{message}")
if retry_queue:
echo_log(f"企业待办附件重试队列中有:{retry_queue.qsize()} 个请求在等待.")
async def push_attachment(fetch_size: int = 50,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
"""
推送待办附件数据及其数据。
:param fetch_size: 本次推送数量
:param task_id: 待办任务 ID 可选
"""
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
task_query = select(DcmTask.id).order_by(desc(DcmTask.act_id))
if task_id:
if isinstance(task_id, list):
task_query = task_query.where(DcmTask.id.in_(task_id))
echo_log(f"本次推送待办列表:{task_id} 的附件数据...")
else:
task_query = task_query.where(DcmTask.id == task_id)
echo_log(f"本次推送待办:{task_id} 的附件数据...")
else:
task_query = task_query.limit(fetch_size)
echo_log(f"本次推送前 {fetch_size} 条待办附件数据...")
dcm_task_df = await DcmTask.query_as_df(task_query)
# 格式化为字符串
dcm_task_df[DcmTask.id.key] = dcm_task_df[DcmTask.id.key].astype(str)
# 预处理数据方法
def preprocess(df: pd.DataFrame):
# 更名,并仅保留需要的列
df = df.rename(columns=DcmTaskAttachmentMapping)
df = df[list(DcmTaskAttachmentMapping.values()) + [DcmTaskAttachment.dcm_task_id.key]]
return df
# 填充附件数据
await DcmTaskAttachment.fill_attachment(dcm_task_df, column_name='attachmentList', preprocessing=preprocess)
# 处理无附件待办状态
empty_dcm_task_df = dcm_task_df[dcm_task_df['attachmentList'].apply(lambda x: len(x) == 0)]
empty_dcm_task_df[DcmPushStatus.dcm_task_id.key] = empty_dcm_task_df[DcmTask.id.key]
empty_dcm_task_df[DcmPushStatus.push_task_attachment_status.key] = 1
empty_dcm_task_df = empty_dcm_task_df[[DcmPushStatus.dcm_task_id.key, DcmPushStatus.push_task_attachment_status.key]]
await DcmPushStatus.save_batch(empty_dcm_task_df)
# 过滤空数组
full_dcm_task_df = dcm_task_df[dcm_task_df['attachmentList'].apply(lambda x: len(x) > 0)]
# 删除 DcmTaskAttachment.dcm_task_id.key 字段
def remove_dcm_task_id(attachment_list):
for item in attachment_list:
if isinstance(item, dict) and DcmTaskAttachment.dcm_task_id.key in item:
del item[DcmTaskAttachment.dcm_task_id.key]
return attachment_list
# 执行替换
full_dcm_task_df['attachmentList'] = full_dcm_task_df['attachmentList'].apply(remove_dcm_task_id)
# 处理数据映射,适应接口推送
mapped_df = full_dcm_task_df.rename(columns={DcmTask.id.key: 'gdId'})
# 这里把空数据都换成 None,以便存入数据库时是 null
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
echo_log(f"正在准备请求队列...")
# 构建请求队列
dcm_push_queue = asyncio.Queue()
# 向队列中填充请求对象
for _h, row in mapped_df.iterrows():
push_request = await oa_api_request.get_push_attachment_request(**row.to_dict())
setattr(push_request, "dcm_task_id", row.get('gdId'))
await dcm_push_queue.put(push_request)
# 并发提交推送请求
echo_log(f"开始推送待办附件数据...")
await requests.async_concurrency(
dcm_push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_push_attachment_request
)
echo_log(f"待办附件数据推送已经完成...")
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(push_attachment(task_id=2054174091237265408))
+135
View File
@@ -0,0 +1,135 @@
"""
待办工单扩展数据推送。
对应文档接口:9、推送扩展信息
"""
import asyncio
import json
from typing import Optional, Union
import pandas as pd
from sqlalchemy import select, desc
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
import models
from dock.oa import oa_api_request
from models.dcm_push_status import DcmPushStatus
from models.dcm_task import DcmTask
from models.dcm_task_extend_info import DcmTaskExtendedInfo
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
DcmTaskExtendedInfoMapping = {
DcmTaskExtendedInfo.id.key: 'id',
DcmTaskExtendedInfo.display_name.key: 'fieldName',
DcmTaskExtendedInfo.field_value.key: 'fieldValue'
}
async def after_push_extend_info_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
工单推送请求响应后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
code = udict.get_by_path(body_data, 'code')
message = udict.get_by_path(body_data, 'msg')
if code == 200:
dcm_task_id = getattr(response.request, "dcm_task_id")
await DcmPushStatus.set_push_task_extend_info_status(dcm_task_id)
echo_log(f"推送企业待办扩展信息成功.")
else:
echo_log(f"推送企业待办扩展信息失败:{message}")
if retry_queue:
echo_log(f"企业待办扩展信息重试队列中有:{retry_queue.qsize()} 个请求在等待.")
async def push_extend_info(fetch_size: int = 50,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
"""
推送待办扩展信息数据及其数据。
:param fetch_size: 本次推送数量
:param task_id: 待办任务 ID 可选
"""
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
task_query = select(DcmTask.id).order_by(desc(DcmTask.act_id))
if task_id:
if isinstance(task_id, list):
task_query = task_query.where(DcmTask.id.in_(task_id))
echo_log(f"本次推送待办列表:{task_id} 的扩展信息数据...")
else:
task_query = task_query.where(DcmTask.id == task_id)
echo_log(f"本次推送待办:{task_id} 的扩展信息数据...")
else:
task_query = task_query.limit(fetch_size)
echo_log(f"本次推送待办前 {fetch_size} 条扩展信息数据...")
dcm_task_df = await DcmTask.query_as_df(task_query)
# 格式化为字符串
dcm_task_df[DcmTask.id.key] = dcm_task_df[DcmTask.id.key].astype(str)
# 预处理数据方法
def preprocess(df: pd.DataFrame):
# 更名,并仅保留需要的列
df = df.rename(columns=DcmTaskExtendedInfoMapping)
df = df[list(DcmTaskExtendedInfoMapping.values())+[DcmTaskExtendedInfo.dcm_task_id.key]]
return df
# 填充表单数据
await DcmTaskExtendedInfo.fill_extend_info(dcm_task_df, column_name='extendList', preprocessing=preprocess)
# 处理无待办工单扩展信息状态
empty_dcm_task_df = dcm_task_df[dcm_task_df['extendList'].apply(lambda x: len(x) == 0)]
empty_dcm_task_df[DcmPushStatus.dcm_task_id.key] = empty_dcm_task_df[DcmTask.id.key]
empty_dcm_task_df[DcmPushStatus.push_task_extend_info_status.key] = 1
empty_dcm_task_df = empty_dcm_task_df[[DcmPushStatus.dcm_task_id.key, DcmPushStatus.push_task_extend_info_status.key]]
await DcmPushStatus.save_batch(empty_dcm_task_df)
# 过滤空数组
full_dcm_task_df = dcm_task_df[dcm_task_df['extendList'].apply(lambda x: len(x) > 0)]
# 删除 DcmTaskExtendedInfo.dcm_task_id.key 字段
def remove_dcm_task_id(attachment_list):
for item in attachment_list:
if isinstance(item, dict) and DcmTaskExtendedInfo.dcm_task_id.key in item:
del item[DcmTaskExtendedInfo.dcm_task_id.key]
return attachment_list
# 执行替换
full_dcm_task_df['extendList'] = full_dcm_task_df['extendList'].apply(remove_dcm_task_id)
# 处理数据映射,适应接口推送
mapped_df = full_dcm_task_df.rename(columns={DcmTask.id.key: 'gdId'})
# 这里把空数据都换成 None,以便存入数据库时是 null
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
echo_log(f"正在准备请求队列...")
# 构建请求队列
dcm_push_queue = asyncio.Queue()
# 向队列中填充请求对象
for _h, row in mapped_df.iterrows():
push_request = await oa_api_request.get_push_extend_info_request(**row.to_dict())
setattr(push_request, "dcm_task_id", row.get('gdId'))
await dcm_push_queue.put(push_request)
# 并发提交推送请求
echo_log(f"开始推送代办扩展信息数据...")
await requests.async_concurrency(
dcm_push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_push_extend_info_request
)
echo_log(f"待办扩展信息推送已经完成...")
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(push_extend_info(task_id=2054174091237265408))
+139
View File
@@ -0,0 +1,139 @@
"""
待办工单更多信息推送。
对应文档接口:8、推送更多信息
"""
import asyncio
import json
from typing import Optional, Union
import pandas as pd
from sqlalchemy import select, desc
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
import models
from dock.oa import oa_api_request
from models.dcm_push_status import DcmPushStatus
from models.dcm_task import DcmTask
from models.dcm_task_more_info import DcmTaskMoreInfo
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
DcmTaskMoreInfoMapping = {
DcmTaskMoreInfo.id.key: 'id',
DcmTaskMoreInfo.create_time.key: 'time'
}
"""
表单数据-更多信息推送映射关系。
"""
async def after_push_more_info_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
工单推送请求响应后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
code = udict.get_by_path(body_data, 'code')
message = udict.get_by_path(body_data, 'msg')
if code == 200:
dcm_task_id = getattr(response.request, "dcm_task_id")
await DcmPushStatus.set_push_task_more_info_status(dcm_task_id)
echo_log(f"推送企业待办更多信息成功.")
else:
echo_log(f"推送企业待办更多信息失败:{message}")
if retry_queue:
echo_log(f"企业待办更多信息重试队列中有:{retry_queue.qsize()} 个请求在等待.")
async def push_more_info(fetch_size: int = 50,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
"""
推送待办更多信息数据及其数据。
:param fetch_size: 本次推送数量
:param task_id: 待办任务 ID 可选
"""
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
task_query = select(DcmTask.id).order_by(desc(DcmTask.act_id))
if task_id:
if isinstance(task_id, list):
task_query = task_query.where(DcmTask.id.in_(task_id))
echo_log(f"本次推送待办列表:{task_id} 的更多信息数据...")
else:
task_query = task_query.where(DcmTask.id == task_id)
echo_log(f"本次推送待办:{task_id} 的更多信息数据...")
else:
task_query = task_query.limit(fetch_size)
echo_log(f"本次推送前 {fetch_size} 条更多信息数据...")
dcm_task_df = await DcmTask.query_as_df(task_query)
# 格式化为字符串
dcm_task_df[DcmTask.id.key] = dcm_task_df[DcmTask.id.key].astype(str)
# 预处理数据方法
def preprocess(df: pd.DataFrame):
# 更名,并仅保留需要的列
df = df.rename(columns=DcmTaskMoreInfoMapping)
df['content'] = df['time'].fillna("") + ' ' + df['human_name'].fillna("") + df['msg_type'].fillna("")
df = df[list(DcmTaskMoreInfoMapping.values()) + ['content',DcmTaskMoreInfo.dcm_task_id.key]]
return df
# 填充表单数据
await DcmTaskMoreInfo.fill_more_info(dcm_task_df, column_name='moreInfoList', preprocessing=preprocess)
# 处理无待办工单更多信息状态
empty_dcm_task_df = dcm_task_df[dcm_task_df['moreInfoList'].apply(lambda x: len(x) == 0)]
empty_dcm_task_df[DcmPushStatus.dcm_task_id.key] = empty_dcm_task_df[DcmTask.id.key]
empty_dcm_task_df[DcmPushStatus.push_task_more_info_status.key] = 1
empty_dcm_task_df = empty_dcm_task_df[[DcmPushStatus.dcm_task_id.key, DcmPushStatus.push_task_more_info_status.key]]
await DcmPushStatus.save_batch(empty_dcm_task_df)
# 过滤空数组
full_dcm_task_df = dcm_task_df[dcm_task_df['moreInfoList'].apply(lambda x: len(x) > 0)]
# 删除 DcmTaskMoreInfo.dcm_task_id.key 字段
def remove_dcm_task_id(attachment_list):
for item in attachment_list:
if isinstance(item, dict) and DcmTaskMoreInfo.dcm_task_id.key in item:
del item[DcmTaskMoreInfo.dcm_task_id.key]
return attachment_list
# 执行替换
full_dcm_task_df['moreInfoList'] = full_dcm_task_df['moreInfoList'].apply(remove_dcm_task_id)
# 处理数据映射,适应接口推送
mapped_df = full_dcm_task_df.rename(columns={DcmTask.id.key: 'gdId'})
# 这里把空数据都换成 None,以便存入数据库时是 null
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
echo_log(f"正在准备请求队列...")
# 构建请求队列
dcm_push_queue = asyncio.Queue()
# 向队列中填充请求对象
for _h, row in mapped_df.iterrows():
push_request = await oa_api_request.get_push_more_info_request(**row.to_dict())
setattr(push_request, "dcm_task_id", row.get('gdId'))
await dcm_push_queue.put(push_request)
# 并发提交推送请求
echo_log(f"开始推送更多信息数据...")
await requests.async_concurrency(
dcm_push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_push_more_info_request
)
echo_log(f"更多信息数据推送已经完成...")
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(push_more_info(task_id=2054174091237265408))
+241
View File
@@ -0,0 +1,241 @@
"""
待办工单推送。
对应文档接口:2、推送待办工单列表
"""
import asyncio
import json
from typing import Optional, Union
import pandas as pd
from sqlalchemy import select, desc
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
import models
from dock.oa import oa_api_request
from models.dcm_push_status import DcmPushStatus
from models.dcm_task import DcmTask
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
DcmTaskMapping = {
DcmTask.id.key: 'gdId',
DcmTask.task_num.key: 'taskNum',
DcmTask.other_task_num.key: 'otherTaskNum',
DcmTask.bundle_deadline_time.key: 'bundleDeadlineTimeStr',
DcmTask.rollback_deadline.key: 'rollbackDeadlineStr',
DcmTask.event_src_name.key: 'eventSrcName',
DcmTask.rec_type_name.key: 'recTypeName',
DcmTask.event_type_name.key: 'eventTypeName',
DcmTask.main_type_name.key: 'mainTypeName',
DcmTask.sub_type_name.key: 'subTypeName',
DcmTask.urgency_level.key: 'urgencyLevel',
DcmTask.event_desc.key: 'eventDesc',
DcmTask.address.key: 'address',
DcmTask.processing_deadline.key: 'disposalTimeLimit',
DcmTask.district_name.key: 'districtName',
DcmTask.new_inst_cond_name.key: 'newInstCondName',
DcmTask.case_closure_condition.key: 'closingConditions',
DcmTask.reporter_name.key: 'reporterName',
DcmTask.reporter_contact.key: 'reporterContact',
DcmTask.reply_intime.key: 'replyIntime',
DcmTask.first_depart_name.key: 'firstDepartName',
DcmTask.second_depart_name.key: 'secondDepartName',
DcmTask.bundle_warning_time.key: 'bundleWarningTimeStr',
DcmTask.act_ard_state_name.key: 'actArdStateName',
DcmTask.operation.key: 'operateType',
}
"""
数据推送映射关系。
"""
async def after_push_order_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
工单推送请求响应后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
code = udict.get_by_path(body_data, 'code')
message = udict.get_by_path(body_data, 'msg')
if code == 200:
dcm_task_id_list = getattr(response.request, "dcm_task_id_list", [])
dcm_task_push_data = [
{
DcmPushStatus.dcm_task_id.key: dcm_task_id,
DcmPushStatus.push_task_status.key: 1
}
for dcm_task_id in dcm_task_id_list
]
dcm_task_push_df = pd.DataFrame(dcm_task_push_data)
await DcmPushStatus.save_batch(dcm_task_push_df)
echo_log(f"推送企业待办成功.")
else:
echo_log(f"推送企业待办失败:{message}")
if retry_queue:
echo_log(f"企业待办重试队列中有:{retry_queue.qsize()} 个请求在等待.")
async def push_order(fetch_size: int = 50, batch_size: int = 10,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
"""
推送待办数据及其数据。
:param fetch_size: 本次推送数量
:param batch_size: 分批时,每批大小
:param task_id: 待办任务 ID 可选
"""
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
task_query = select(
DcmTask.id,
DcmTask.task_num, DcmTask.other_task_num,
DcmTask.bundle_deadline_time, DcmTask.rollback_deadline,
DcmTask.event_src_name, DcmTask.rec_type_name,
DcmTask.event_type_name, DcmTask.main_type_name,
DcmTask.sub_type_name, DcmTask.urgency_level,
DcmTask.event_desc, DcmTask.address,
DcmTask.processing_deadline, DcmTask.district_name,
DcmTask.new_inst_cond_name, DcmTask.case_closure_condition,
DcmTask.reporter_name, DcmTask.reporter_contact,
DcmTask.reply_intime, DcmTask.first_depart_name,
DcmTask.second_depart_name, DcmTask.bundle_warning_time,
DcmTask.act_ard_state_name, DcmTask.operation
).order_by(
desc(DcmTask.act_id)
)
if task_id:
if isinstance(task_id, list):
task_query = task_query.where(DcmTask.id.in_(task_id))
echo_log(f"本次推送待办列表:{task_id} 的数据...")
else:
task_query = task_query.where(DcmTask.id == task_id)
echo_log(f"本次推送待办:{task_id} 的数据...")
else:
task_query = task_query.limit(fetch_size)
echo_log(f"本次推送前 {fetch_size} 条待办数据...")
# if apps.get_active_env() == 'prod':
# # 生产环境只推送 DcmTaskProcessInfo.action_time > 2026-05-18 00:00:00 的待办工单
# # 构建子查询:查找满足条件的 DcmTaskProcessInfo
# subquery = select(DcmTaskProcessInfo.dcm_task_id).where(
# DcmTaskProcessInfo.dcm_task_id == DcmTask.id,
# DcmTaskProcessInfo.action_time > '2026-05-18 00:00:00'
# ).group_by(
# DcmTaskProcessInfo.dcm_task_id
# ).order_by(
# desc(DcmTaskProcessInfo.action_time)
# )
# task_query = task_query.where(exists(subquery))
dcm_task_df = await DcmTask.query_as_df(task_query)
# 格式化三个时间字段为 yyyy-MM-dd HH:mm:ss
dcm_task_df[DcmTask.bundle_deadline_time.key] = (
pd.to_datetime(
dcm_task_df[DcmTask.bundle_deadline_time.key], unit='ms', errors='coerce'
).dt.strftime('%Y-%m-%d %H:%M:%S')
)
dcm_task_df[DcmTask.rollback_deadline.key] = (
pd.to_datetime(
dcm_task_df[DcmTask.rollback_deadline.key], unit='ms', errors='coerce'
).dt.strftime('%Y-%m-%d %H:%M:%S'))
dcm_task_df[DcmTask.bundle_warning_time.key] = (
pd.to_datetime(
dcm_task_df[DcmTask.bundle_warning_time.key], unit='ms', errors='coerce'
).dt.strftime('%Y-%m-%d %H:%M:%S'))
# 格式化为字符串
dcm_task_df[DcmTask.id.key] = dcm_task_df[DcmTask.id.key].astype(str)
# 代码转义
reply_intime_map = {
'0': '无需回复',
'1': '待回复',
'2': '已回复',
'3': '超时未回复',
'4': '无需回复已恢复',
}
dcm_task_df[DcmTask.reply_intime.key] = dcm_task_df[DcmTask.reply_intime.key].astype(str).map(
lambda x: reply_intime_map.get(x, x)
)
urgency_level_map = {
'0': '正常',
'1': '紧急',
}
dcm_task_df[DcmTask.urgency_level.key] = dcm_task_df[DcmTask.urgency_level.key].astype(str).map(
lambda x: urgency_level_map.get(x, x)
)
dcm_task_df[DcmTask.operation.key] = dcm_task_df[DcmTask.operation.key].str.split(',')
# 处理数据映射,适应接口推送
mapped_df = dcm_task_df.rename(columns=DcmTaskMapping)
# 这里把空数据都换成 None,以便存入数据库时是 null
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
echo_log(f"正在准备请求队列...")
# 构建请求队列
dcm_push_queue = asyncio.Queue()
# 向队列中填充请求对象
for start in range(0, len(mapped_df), batch_size):
batch_df: pd.DataFrame = mapped_df.iloc[start:start + batch_size]
push_list = batch_df.to_dict('records')
push_request = await oa_api_request.get_push_order_request(push_list)
setattr(push_request, "dcm_task_id_list", batch_df['gdId'].unique().tolist())
await dcm_push_queue.put(push_request)
# 并发提交推送请求
echo_log(f"开始推送待办数据...")
await requests.async_concurrency(
dcm_push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_push_order_request
)
echo_log(f"待办数据推送已经完成...")
async def push_full_order(fetch_size: int = 50, batch_size: int = 10,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
from dock.oa_dcm import oa_push_order_detail, oa_push_process_info, oa_push_attachment, \
oa_push_more_info, oa_push_extend_info, oa_upload
await push_order(fetch_size, batch_size, task_id)
await oa_push_order_detail.push_order_detail(fetch_size, task_id)
await oa_push_process_info.push_process_info(fetch_size, task_id)
await oa_upload.upload_with_attachment(fetch_size, task_id)
await oa_push_attachment.push_attachment(fetch_size, task_id)
await oa_push_more_info.push_more_info(fetch_size, task_id)
await oa_push_extend_info.push_extend_info(fetch_size, task_id)
async def push_sign_order():
"""
推送并签收工单。
"""
from dock.oa_dcm import oa_push_order_detail, oa_push_process_info, oa_push_attachment, \
oa_push_more_info, oa_push_extend_info, oa_upload, oa_sign_task
# TODO: 查询得到要推送的工单ID列表
task_id_list = []
if task_id_list:
await push_order(task_id=task_id_list)
await oa_push_order_detail.push_order_detail(task_id=task_id_list)
await oa_push_process_info.push_process_info(task_id=task_id_list)
await oa_upload.upload_with_attachment(task_id=task_id_list)
await oa_push_attachment.push_attachment(task_id=task_id_list)
await oa_push_more_info.push_more_info(task_id=task_id_list)
await oa_push_extend_info.push_extend_info(task_id=task_id_list)
# 推送结束后,签收工单
await oa_sign_task.sign_task(task_id=task_id_list)
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(push_order(task_id=2054174091254042627))
+165
View File
@@ -0,0 +1,165 @@
"""
待办工单明细推送。
对应文档接口:5、推送工单详情
"""
import asyncio
import json
from typing import Optional, Union
import pandas as pd
from sqlalchemy import select, desc
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
import models
from dock.oa import oa_api_request
from models.dcm_push_status import DcmPushStatus
from models.dcm_task import DcmTask
from models.dcm_task_form_datum import DcmTaskFormDatum
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
DcmTaskMapping = {
DcmTask.id.key: 'gdId',
DcmTask.part_code.key: 'partCode',
DcmTaskFormDatum.func_limit_char.key: 'funcLimitChar',
DcmTask.reporter_name.key: 'reporterName',
DcmTaskFormDatum.media_upload_total_num.key: 'mediaUploadTotalNum',
DcmTask.return_visit_flag.key:'returnVisitFlag',
DcmTask.func_forbid_reporter_info_flag.key:'funcForbidReporterInfoFlag',
DcmTaskFormDatum.tell_num.key:'contactNumberDd',
DcmTask.reporter_contact.key: 'reportNumberDd',
DcmTaskFormDatum.deal_person_org.key: 'dealPersonOrg',
DcmTaskFormDatum.undertake_user_name.key: 'undertakeUserName',
}
"""
数据推送映射关系。
"""
async def after_push_order_detail_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
工单推送请求响应后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
code = udict.get_by_path(body_data, 'code')
message = udict.get_by_path(body_data, 'msg')
if code==200:
dcm_task_id = getattr(response.request, "dcm_task_id")
await DcmPushStatus.set_push_task_detail_status(dcm_task_id)
echo_log(f"推送工单详情成功.")
else:
echo_log(f"推送工单详情失败:{message}")
if retry_queue:
echo_log(f"工单详情重试队列中有:{retry_queue.qsize()} 个请求在等待.")
async def push_order_detail(fetch_size: int = 50,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
"""
推送待办数据及其数据。
:param fetch_size: 本次推送数量
:param task_id: 待办任务 ID 可选
"""
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
task_query = select(DcmTask.id).order_by(desc(DcmTask.act_id))
if task_id:
if isinstance(task_id, list):
task_query = task_query.where(DcmTask.id.in_(task_id))
echo_log(f"本次推送待办列表:{task_id} 的详细数据...")
else:
task_query = task_query.where(DcmTask.id == task_id)
echo_log(f"本次推送待办:{task_id} 的详细数据...")
else:
task_query = task_query.limit(fetch_size)
echo_log(f"本次推送前 {fetch_size} 条待办的详细数据...")
task_id_list = (await DcmTask.orm_execute_scalars(task_query)).all()
task_id_list = [f"{id}" for id in task_id_list]
# 查询属于这些任务的所有详细数据
datum_query = select(
DcmTask.id, DcmTask.part_code, DcmTask.reporter_name, DcmTask.reporter_contact,
DcmTask.return_visit_flag, DcmTask.func_forbid_reporter_info_flag,
DcmTaskFormDatum.media_upload_total_num, DcmTaskFormDatum.func_limit_char,
DcmTaskFormDatum.tell_num, DcmTaskFormDatum.undertake_user_name,
DcmTaskFormDatum.deal_person_org
).join(
DcmTaskFormDatum, DcmTask.id==DcmTaskFormDatum.dcm_task_id
).where(
DcmTask.id.in_(task_id_list)
)
dcm_task_df = await DcmTask.query_as_df(datum_query)
# 格式化为字符串
dcm_task_df[DcmTask.id.key] = dcm_task_df[DcmTask.id.key].astype(str)
dcm_task_df[DcmTaskFormDatum.media_upload_total_num.key] = dcm_task_df[DcmTaskFormDatum.media_upload_total_num.key].fillna(0).astype(int)
# 代码转义
return_visit_flag_map = {
'0': '无需回访',
'1': '待回访',
'2': '已回访',
}
dcm_task_df[DcmTask.return_visit_flag.key] = dcm_task_df[DcmTask.return_visit_flag.key].astype(str).map(
lambda x: return_visit_flag_map.get(x, x)
)
func_forbid_reporter_info_flag_map = {
'0': '',
'1': '',
}
dcm_task_df[DcmTask.func_forbid_reporter_info_flag.key] = dcm_task_df[DcmTask.func_forbid_reporter_info_flag.key].astype(str).map(
lambda x: func_forbid_reporter_info_flag_map.get(x, x)
)
# 未爬取的字段暂时填空值
dcm_task_df['violationTaskNoDd'] = ''
dcm_task_df['telReply'] = ''
# 处理无待办工单详情状态
empty_task_ids = set(task_id_list) - set(dcm_task_df[DcmTask.id.key].unique().tolist())
empty_task_data = [
{
DcmPushStatus.dcm_task_id.key: dcm_task_id,
DcmPushStatus.push_task_status.key: 1
}
for dcm_task_id in list(empty_task_ids)
]
empty_task_df = pd.DataFrame(empty_task_data)
await DcmPushStatus.save_batch(empty_task_df)
# 处理数据映射,适应接口推送
mapped_df = dcm_task_df.rename(columns=DcmTaskMapping)
# 这里把空数据都换成 None,以便存入数据库时是 null
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
echo_log(f"正在准备请求队列...")
# 构建请求队列
dcm_push_queue = asyncio.Queue()
# 向队列中填充请求对象
for _h, row in mapped_df.iterrows():
push_request = await oa_api_request.get_push_order_detail_request(**row.to_dict())
setattr(push_request, "dcm_task_id", row.get('gdId'))
await dcm_push_queue.put(push_request)
# 并发提交推送请求
echo_log(f"开始推送工单详情数据...")
await requests.async_concurrency(
dcm_push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_push_order_detail_request
)
echo_log(f"工单详情推送已经完成...")
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(push_order_detail(task_id=2054174091254042627))
+164
View File
@@ -0,0 +1,164 @@
"""
推送办理经过。
对应文档接口:6、推送办理经过
"""
import asyncio
import json
from typing import Optional, Union
import pandas as pd
from sqlalchemy import select, desc
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
import models
from dock.oa import oa_api_request
from models.dcm_push_status import DcmPushStatus
from models.dcm_task import DcmTask
from models.dcm_task_process_info import DcmTaskProcessInfo
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
DcmTaskProcessInfoMapping = {
DcmTaskProcessInfo.id.key: 'id',
DcmTaskProcessInfo.action_time.key: 'actionTime',
DcmTaskProcessInfo.act_def_name.key: 'actDefName',
DcmTaskProcessInfo.human_name.key: 'humanName',
DcmTaskProcessInfo.unit_name.key: 'unitName',
DcmTaskProcessInfo.action_name.key: 'actionName',
DcmTaskProcessInfo.next_act_def_name.key: 'nextActDefName',
DcmTaskProcessInfo.detail.key: 'detail',
}
async def after_push_process_info_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
工单推送请求响应后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
code = udict.get_by_path(body_data, 'code')
message = udict.get_by_path(body_data, 'msg')
if code==200:
dcm_task_id = getattr(response.request, "dcm_task_id")
await DcmPushStatus.set_push_task_process_info_status(dcm_task_id)
echo_log(f"推送企业待办过程成功.")
else:
echo_log(f"推送企业待办过程失败:{message}")
if retry_queue:
echo_log(f"企业待办过程重试队列中有:{retry_queue.qsize()} 个请求在等待.")
async def push_process_info(fetch_size: int = 50,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
"""
推送待办附件数据及其数据。
:param fetch_size: 本次推送数量
:param task_id: 待办任务 ID 可选
"""
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
task_query = select(DcmTask.id).order_by(desc(DcmTask.act_id))
if task_id:
if isinstance(task_id, list):
task_query = task_query.where(DcmTask.id.in_(task_id))
echo_log(f"本次推送待办列表:{task_id} 的过程数据...")
else:
task_query = task_query.where(DcmTask.id == task_id)
echo_log(f"本次推送待办:{task_id} 的过程数据...")
else:
task_query = task_query.limit(fetch_size)
echo_log(f"本次推送前 {fetch_size} 条待办过程数据...")
dcm_task_df = await DcmTask.query_as_df(task_query)
# 格式化为字符串
dcm_task_df[DcmTask.id.key] = dcm_task_df[DcmTask.id.key].astype(str)
dcm_task_ids = dcm_task_df[DcmTask.id.key].unique().tolist()
dcm_task_check_info = {f'{tid}': '' for tid in dcm_task_ids}
# 预处理数据方法
def preprocess(df: pd.DataFrame):
# 格式化时间字段为 yyyy-MM-dd HH:mm:ss
df[DcmTaskProcessInfo.action_time.key] = (
pd.to_datetime(
df[DcmTaskProcessInfo.action_time.key], unit='ms', errors='coerce'
).dt.strftime('%Y-%m-%d %H:%M:%S')
)
# 设置 check_info
for tid in dcm_task_ids:
filtered = df[df[DcmTaskProcessInfo.dcm_task_id.key] == tid].copy()
if not filtered.empty:
min_row = filtered.loc[filtered[DcmTaskProcessInfo.item_id.key].idxmin()].iloc[0]
dcm_task_check_info[tid] = (
f"{min_row[DcmTaskProcessInfo.action_time.key]}"
f"{min_row[DcmTaskProcessInfo.human_name.key]}"
f"{min_row[DcmTaskProcessInfo.act_def_name.key]}阶段"
f"{min_row[DcmTaskProcessInfo.action_name.key]}"
)
# 更名,并仅保留需要的列
df = df.rename(columns=DcmTaskProcessInfoMapping)
df = df[list(DcmTaskProcessInfoMapping.values()) + [DcmTaskProcessInfo.dcm_task_id.key]]
return df
# 填充处理过程
await DcmTaskProcessInfo.fill_process_info(dcm_task_df, column_name='handlingProcessList', preprocessing=preprocess)
# 处理无待办工单处理过程状态
empty_dcm_task_df = dcm_task_df[dcm_task_df['handlingProcessList'].apply(lambda x: len(x) == 0)]
empty_dcm_task_df[DcmPushStatus.dcm_task_id.key] = empty_dcm_task_df[DcmTask.id.key]
empty_dcm_task_df[DcmPushStatus.push_task_process_info_status.key] = 1
empty_dcm_task_df = empty_dcm_task_df[[DcmPushStatus.dcm_task_id.key, DcmPushStatus.push_task_process_info_status.key]]
await DcmPushStatus.save_batch(empty_dcm_task_df)
# 过滤空数组
full_dcm_task_df = dcm_task_df[dcm_task_df['handlingProcessList'].apply(lambda x: len(x) > 0)]
# 删除 DcmTaskAttachment.dcm_task_id.key 字段
def remove_dcm_task_id(attachment_list):
for item in attachment_list:
if isinstance(item, dict) and DcmTaskProcessInfo.dcm_task_id.key in item:
del item[DcmTaskProcessInfo.dcm_task_id.key]
return attachment_list
# 执行替换
full_dcm_task_df['handlingProcessList'] = full_dcm_task_df['handlingProcessList'].apply(remove_dcm_task_id)
# 增加 checkContent 字段,来自办理流程数据合并
full_dcm_task_df['checkContent'] = full_dcm_task_df[DcmTask.id.key].apply(
lambda x: dcm_task_check_info.get(x, '')
)
# 处理数据映射,适应接口推送
mapped_df = full_dcm_task_df.rename(columns={DcmTask.id.key: 'gdId'})
# 这里把空数据都换成 None,以便存入数据库时是 null
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
echo_log(f"正在准备请求队列...")
# 构建请求队列
dcm_push_queue = asyncio.Queue()
# 向队列中填充请求对象
for _h, row in mapped_df.iterrows():
push_request = await oa_api_request.get_push_process_info_request(**row.to_dict())
setattr(push_request, "dcm_task_id", row.get('gdId'))
await dcm_push_queue.put(push_request)
# 并发提交推送请求
echo_log(f"开始推送待办过程数据...")
await requests.async_concurrency(
dcm_push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_push_process_info_request
)
echo_log(f"待办过程数据推送已经完成...")
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(push_process_info(task_id=2054174091237265408))
+98
View File
@@ -0,0 +1,98 @@
"""
向 OA 平台上报数据已经完整推送。
对应文档接口:11、签收
"""
import asyncio
import json
from typing import Optional, Union
from sqlalchemy import select, desc
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
from dock.oa import oa_api_request
from models.dcm_push_status import DcmPushStatus
from models.dcm_task import DcmTask
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
async def after_sign_task_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
签收工单请求响应后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
code = udict.get_by_path(body_data, 'code')
message = udict.get_by_path(body_data, 'msg')
if code == 200:
echo_log(f"签收工单成功.")
else:
echo_log(f"签收工单失败:{message}")
if retry_queue:
echo_log(f"签收工单重试队列中有:{retry_queue.qsize()} 个请求在等待.")
async def sign_task(fetch_size: int = 50,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
"""
签收指定数量的工单任务
:param fetch_size: 本次签收的任务数量
:param task_id: 待办任务 ID 可选
"""
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
task_query = select(DcmTask.id).join(
DcmPushStatus, DcmPushStatus.dcm_task_id == DcmTask.id
).where(
DcmPushStatus.push_task_status == 1,
DcmPushStatus.push_task_detail_status == 1,
DcmPushStatus.push_task_attachment_status == 1,
DcmPushStatus.push_task_extend_info_status == 1,
DcmPushStatus.push_task_file_upload_status == 1,
DcmPushStatus.push_task_more_info_status == 1,
DcmPushStatus.push_task_process_info_status == 1,
).order_by(
desc(DcmTask.act_id)
)
if task_id:
if isinstance(task_id, list):
task_query = task_query.where(DcmTask.id.in_(task_id))
echo_log(f"本次签收待办列表:{task_id} 的工单...")
else:
task_query = task_query.where(DcmTask.id == task_id)
echo_log(f"本次签收待办:{task_id} 的工单...")
else:
task_query = task_query.limit(fetch_size)
echo_log(f"本次签收前 {fetch_size} 条待办工单...")
dcm_task_df = await DcmTask.query_as_df(task_query)
# 格式化为字符串
dcm_task_df[DcmTask.id.key] = dcm_task_df[DcmTask.id.key].astype(str)
echo_log(f"正在准备请求队列...")
# 构建请求队列
sign_request_queue = asyncio.Queue()
task_id_list = dcm_task_df[DcmTask.id.key].unique().tolist()
for task_id in task_id_list:
request = await oa_api_request.get_sign_task_request(task_id)
await sign_request_queue.put(request)
echo_log(f"开始签收工单...")
await requests.async_concurrency(
sign_request_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_sign_task_request
)
echo_log(f"签收工单完成...")
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(sign_task(task_id=2054174091228876801))
+88
View File
@@ -0,0 +1,88 @@
"""
操作数字城管的工单延期接口后,向OA推送更新后的工单时间信息
对应文档接口:12、更新流程延期信息
"""
import asyncio
import json
from datetime import datetime
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
from dock.dcm import dcm_scrape
from dock.oa import oa_api, oa_api_request
from models.dcm_task import DcmTask
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
async def get_update_process_delay_request(data: dict):
api_url = '/externalWorkOrder/digitalCM/updateProcessDelayInfo'
request_body = data
# 构造 API 请求
return await oa_api.new_api_request(api_url, request_body)
async def after_update_process_delay_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
更新流程延期请求响应后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
code = udict.get_by_path(body_data, 'code')
message = udict.get_by_path(body_data, 'msg')
if code == 200:
echo_log(f"更新流程延期成功.")
else:
echo_log(f"更新流程延期失败:{message}")
if retry_queue:
echo_log(f"更新流程延期重试队列中有:{retry_queue.qsize()} 个请求在等待.")
async def update_process_delay(task_id: int):
"""
流程延期更新之后,推送最新的时间信息
:param task_id: 对应的工单ID
"""
echo_log(f"本次更新{task_id}的最新时间信息...")
dcm_task = await DcmTask.async_find_by_id(task_id)
echo_log(f"开始更新流程延期...")
await dcm_scrape.fetch_single_dcm_task(dcm_task)
# 重新获取更新后的任务对象
dcm_task: DcmTask = await DcmTask.async_find_by_id(task_id)
if dcm_task is not None:
bundle_deadline_time_str = datetime.fromtimestamp(
dcm_task.bundle_deadline_time // 1000
).strftime("%Y-%m-%d %H:%M:%S") if dcm_task.bundle_deadline_time else ''
rollback_deadline_str = datetime.fromtimestamp(
dcm_task.rollback_deadline // 1000
).strftime("%Y-%m-%d %H:%M:%S") if dcm_task.rollback_deadline else ''
request = await oa_api_request.get_update_process_delay_request(
str(task_id), bundle_deadline_time_str, rollback_deadline_str
)
queue = asyncio.Queue()
await queue.put(request)
await requests.async_concurrency(
queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_update_process_delay_request
)
echo_log(f"更新流程延期完成...")
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(update_process_delay(task_id=2054174091228876801))
+204
View File
@@ -0,0 +1,204 @@
"""
待办工单附件文件上传。
对应文档接口:3、文件上传接口
"""
import asyncio
import hashlib
import io
import json
from typing import Union, Optional
from urllib.parse import urlparse
import pandas as pd
from sqlalchemy import select, desc, exists
from tornado.httpclient import HTTPResponse, HTTPRequest
import apps
import dock
from dock.oa import oa_api_request
from models.dcm_push_status import DcmPushStatus
from models.dcm_task import DcmTask
from models.dcm_task_attachment import DcmTaskAttachment
from models.dcm_task_file_upload import DcmTaskFileUpload
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
file_url_column_name = '_file_url'
"""
文件路径列名。
"""
async def done_attachment_download(response_list: list[HTTPResponse]):
"""
下载全部完成后处理程序。
:param response_list: 响应列表
:return:
"""
echo_log(f"文件下载全部完成...")
async def after_attachment_upload(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
附件上传请求后处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
task_file_upload_id = getattr(response.request, 'dcm_task_file_upload_id')
dcm_task_id = getattr(response.request, 'dcm_task_id')
body = response.body.decode()
echo_log(body)
body_data = json.loads(body)
nas = udict.get_by_path(body_data, 'n_a_s')
if nas:
oa_media_id = body_data.get('atts', [])[0].get('fileUrl')
file_upload: DcmTaskFileUpload = await DcmTaskFileUpload.async_find_by_id(task_file_upload_id)
file_upload.oa_media_id = oa_media_id
file_upload.status = 1
await file_upload.async_save()
dcm_task_id = getattr(response.request, "dcm_task_id")
await DcmPushStatus.set_push_task_file_upload_status(dcm_task_id)
echo_log(f"待办:{dcm_task_id} 的附件上传成功.")
else:
echo_log(f"待办:{dcm_task_id} 的附件上传失败.")
async def after_attachment_download(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
附件下载请求后处理程序。
:param response: 请求对象
:param retry_queue: 重试队列
:return:
"""
dcm_task_id = getattr(response.request, 'dcm_task_id')
dcm_task_attachment_id = getattr(response.request, 'dcm_task_attachment_id')
dcm_media_id = getattr(response.request, 'dcm_media_id')
# 计算文件哈希
file_content = response.body
file_hash = hashlib.md5(file_content).hexdigest()
echo_log(f"待办:{dcm_task_id} 的附件:{dcm_task_attachment_id} 已经下载完成,附件 HASH 值:{file_hash}.")
echo_log(f"附件下载重试队列中有:{retry_queue.qsize()} 项在等待.")
# 保存文件上传记录数据
file_upload_data = {
DcmTaskFileUpload.dcm_task_id.key: dcm_task_id,
DcmTaskFileUpload.dcm_task_attachment_id.key: dcm_task_attachment_id,
DcmTaskFileUpload.dcm_media_id.key: dcm_media_id,
DcmTaskFileUpload.file_hash.key: file_hash,
}
file_upload = await DcmTaskFileUpload.is_exist(dcm_task_id, dcm_task_attachment_id)
if file_upload:
file_upload.copy_from_dict(file_upload_data)
else:
file_upload = DcmTaskFileUpload(**file_upload_data)
await file_upload.async_save()
file_obj = io.BytesIO(response.body)
file_name = urlparse(response.request.url).path.split('/')[-1]
upload_request = await oa_api_request.get_upload_request(file_obj, file_name=file_name)
setattr(upload_request, 'dcm_task_file_upload_id', file_upload.id)
setattr(upload_request, "dcm_task_id", dcm_task_id)
upload_queue = asyncio.Queue()
await upload_queue.put(upload_request)
echo_log(f"开始推送待办:{dcm_task_id} 的附件数据...")
await requests.async_concurrency(
upload_queue, con_count=1, retry=dock.MAX_RETRY_COUNT,
after_request=after_attachment_upload
)
async def upload_with_attachment(fetch_size: int = 50,
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
"""
推送附件数据。
:param fetch_size: 本次推送数量
:param task_id: 待办任务 ID 可选
:return:
"""
from dock.dcm import dcm_api
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
task_query = select(DcmTask.id).order_by(desc(DcmTask.act_id))
if task_id:
if isinstance(task_id, list):
task_query = task_query.where(DcmTask.id.in_(task_id))
echo_log(f"本次上传待办列表:{task_id} 的附件...")
else:
task_query = task_query.where(DcmTask.id == task_id)
echo_log(f"本次上传待办:{task_id} 的附件...")
else:
task_query = task_query.limit(fetch_size)
echo_log(f"本次上传前 {fetch_size} 条附件...")
task_id_list = (await DcmTask.orm_execute_scalars(task_query)).all()
task_id_list = [f"{id}" for id in task_id_list]
# 查询属于这些任务的所有附件信息
query = select(
DcmTaskAttachment.id, DcmTaskAttachment.dcm_task_id,
DcmTaskAttachment.media_id, DcmTaskAttachment.media_url
).where(
DcmTaskAttachment.dcm_task_id.in_(task_id_list)
)
# 生产环境过滤掉已成功上传的附件(避免重复上传)
if apps.get_active_env() == 'prod':
# 生产环境,不上传已经成功上传的附件文件
query = query.where(~exists().where(
(DcmTaskFileUpload.dcm_task_attachment_id == DcmTaskAttachment.id) &
(DcmTaskFileUpload.status == 1)
))
else:
echo_log(f"非生产环境,上传所有附件.")
attachment_df = await DcmTaskAttachment.query_as_df(query)
# 格式化为字符串
attachment_df[DcmTaskAttachment.id.key] = attachment_df[DcmTaskAttachment.id.key].astype(str)
attachment_df[DcmTaskAttachment.dcm_task_id.key] = attachment_df[DcmTaskAttachment.dcm_task_id.key].astype(str)
# 增加文件下载路径列
attachment_df[file_url_column_name] = attachment_df.apply(
lambda x: f"/{x.get(DcmTaskAttachment.media_url.key).lstrip('/')}"
if pd.notna(x.media_url) and str(x.media_url).strip() else "",
axis=1
)
# 处理无待办工单上传状态
empty_task_ids = set(task_id_list) - set(attachment_df[DcmTaskAttachment.dcm_task_id.key].unique().tolist())
empty_task_data = [
{
DcmPushStatus.dcm_task_id.key: dcm_task_id,
DcmPushStatus.push_task_file_upload_status.key: 1
}
for dcm_task_id in list(empty_task_ids)
]
empty_task_df = pd.DataFrame(empty_task_data)
await DcmPushStatus.save_batch(empty_task_df)
echo_log(f"正在准备下载队列...")
# 创建下载请求,填充请求队列
attachment_download_queue = asyncio.Queue()
for _h, _row in attachment_df.iterrows():
download_request = await dcm_api.new_api_request(_row.get(file_url_column_name), {}, method='GET')
setattr(download_request, 'dcm_task_id', _row.get(DcmTaskAttachment.dcm_task_id.key))
setattr(download_request, 'dcm_task_attachment_id', _row.get(DcmTaskAttachment.id.key))
setattr(download_request, 'dcm_media_id', _row.get(DcmTaskAttachment.media_id.key))
await attachment_download_queue.put(download_request)
# 提交附件下载请求
await requests.async_concurrency(
attachment_download_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_attachment_download, after_done=done_attachment_download
)
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()
_runner(upload_with_attachment(task_id=2059900525595328517))