初始化项目

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
+197
View File
@@ -0,0 +1,197 @@
"""
数字城管文件上传。
"""
import asyncio
import datetime
import io
import json
import logging
from typing import Optional
from tornado.httpclient import HTTPResponse, HTTPRequest
import dock
from dock.dcm import dcm_api
from dock.oa import PushException
from models.dcm_task import DcmTask
from paste.core.logging import echo_log
from paste.util import udict
from paste.web import requests
ApplyPostponeTmp = "apply_postpone_tmp"
ApplyRollbackTmp = "apply_rollback_tmp"
RollbackTmp = "rollback_tmp"
TransitTmp = "transit_tmp"
MediaUsage = [ApplyPostponeTmp, ApplyRollbackTmp, RollbackTmp, TransitTmp]
"""
可用媒体对象。
"""
async def get_upload_request(dcm_task: DcmTask, media_usage: str, files: dict[str, io.IOBase],
relation_sub_id: Optional[int] = None,
relation_main_id: Optional[int] = 45):
"""
创建文件上传请求。因数字城管服务器仅接受单文档上传,因此返回的是请求对象列表。
:param dcm_task: 待办工单
:param media_usage: 媒体使用
:param files: 要上传的文件数据
:param relation_sub_id: 可选参数
:param relation_main_id: 可选参数
:return: 上传请求列表
"""
api_url = f"/media/upload"
assert media_usage in MediaUsage, f"参数错误,须为:{MediaUsage} 之一."
request_list = []
_id = 0
for key, value in files.items():
request_body = {
"relationTypeID": 10,
"mediaUsage": media_usage,
"checkExist": True,
"relationID": dcm_task.rec_id,
"relationSubID": relation_sub_id if relation_sub_id is not None else dcm_task.act_id,
"relationMainID": relation_main_id,
"tempUsage": media_usage,
"id": f"WU_FILE_{_id}",
"name": key,
"type": 'image/png',
"lastModifiedDate": datetime.datetime.now().strftime("%a %b %d %Y %H:%M:%S %z").replace(
"+0800", "GMT+0800"
),
"size": len(value.read()),
key: value,
}
_id += 1
# 构造 API 请求
request = await dcm_api.new_api_request(api_url, request_body)
setattr(request, 'dcm_task', dcm_task)
setattr(request, 'media_usage', media_usage)
setattr(request, 'file_name', key)
request_list.append(request)
# 返回请求列表
return request_list
async def get_media_request(dcm_task: DcmTask, media_usage: str):
"""
创建读取 MediaID 请求。
:param dcm_task: 待办工单
:param media_usage: 媒体使用
:return: 上传请求列表
"""
api_url = f"/media/get"
assert media_usage in MediaUsage, f"参数错误,须为:{MediaUsage} 之一."
request_body = {
"relationTypeID": 10,
"mediaUsage": media_usage,
"relationID": dcm_task.rec_id,
"relationSubID": dcm_task.act_id,
"relationMainID": 45,
}
# 构造 API 请求
request = await dcm_api.new_api_request(api_url, request_body, method="GET")
setattr(request, 'dcm_task', dcm_task)
setattr(request, 'media_usage', media_usage)
return request
async def on_upload_error(request: HTTPRequest, exc: Exception, retry_queue: asyncio.Queue = None):
"""
下载附件时的出错处理。
:param request: 请求对象
:param exc: 异常对象
:param retry_queue:
:return:
"""
retry = getattr(request, 'retry', 0)
max_retry = getattr(request, 'max_retry', 0)
if retry < max_retry - 1:
# 非最后一次尝试,不处理
return
dcm_task: DcmTask = getattr(request, 'dcm_task')
media_usage = getattr(request, 'media_usage')
file_name = getattr(request, 'file_name')
message = f'工单ID{dcm_task.id},类型为:{media_usage},文件名为:{file_name} 的附件上传失败.'
echo_log(message)
echo_log(exc, logging.ERROR, is_log_exc=True)
# 保存异常
exc_list = getattr(dcm_task, 'exc_list')
exc_list.append(PushException(message))
async def after_upload_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
"""
提交数字城管后的处理程序。
:param response: 响应对象
:param retry_queue: 重试队列
"""
dcm_task: DcmTask = getattr(response.request, 'dcm_task')
media_usage = getattr(response.request, 'media_usage')
file_name = getattr(response.request, 'file_name')
echo_log(response.body.decode())
echo_log(f'工单ID{dcm_task.id},类型为:{media_usage},文件名为:{file_name} 的附件上传成功.')
async def push_upload(dcm_task: DcmTask, media_usage: str, files: dict[str, io.IOBase],
relation_sub_id: Optional[int] = None,
relation_main_id: Optional[int] = 45):
"""
向数字城管上传文件。
:param dcm_task: 待办工单
:param media_usage: 媒体使用
:param files: 要上传的文件数据
:param relation_sub_id: 可选参数
:param relation_main_id: 可选参数
:return:
"""
echo_log(f"正在准备上传队列...")
request_list = await get_upload_request(dcm_task, media_usage, files, relation_sub_id, relation_main_id)
upload_request_queue = asyncio.Queue()
for req in request_list:
await upload_request_queue.put(req)
# 并发提交上传请求
await requests.async_concurrency(
upload_request_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
after_request=after_upload_request, on_error=on_upload_error
)
# 上传后,读取文件 MediaID
media_request = await get_media_request(dcm_task, media_usage)
media_request_queue = asyncio.Queue()
await media_request_queue.put(media_request)
media_response_list: list[HTTPResponse] = await requests.async_concurrency(
media_request_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT
)
# 从响应列表中取得媒体ID和媒体类型ID
media_id_list: list = []
media_type_list: list = []
media_num = 0
if media_response_list:
response = media_response_list[0]
response_body = response.body.decode()
response_data = json.loads(response_body)
media_list = udict.get_by_path(response_data, 'data.mediaList')
media_num = len(media_list)
for media in media_list:
media_id_list.append(f"{media.get('mediaID')}")
media_type_list.append(media.get('mediaType'))
# 用英文逗号拼接后返回
return ",".join(media_id_list), ",".join(media_type_list), media_num
if __name__ == "__main__":
from paste.core import aio_pool
_runner = aio_pool.get_aio_runner()