Files
d3i-szct/models/dcm_task_form_datum.py
T
2026-06-02 17:46:38 +08:00

2420 lines
91 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import random
from typing import Union, Optional, Callable
import pandas as pd
from sqlalchemy import select, delete
from tornado_swagger.model import register_swagger_model
from wtforms import StringField, TextAreaField, IntegerField, FloatField
from wtforms.validators import Length
import models
from models.common_model import CommonModel
from models.db_models import TD3iDcmTaskFormDatum
from paste.core.logging import echo_log
from paste.util.pagination import Pagination
from paste.web.form import ModelForm
class DcmTaskFormDatumForm(ModelForm):
"""
企业待办表单数据验证类(完全映射 TD3iDcmTaskFormDatum 字段)。
用于验证和处理数字化城市管理信息系统中企业待办的表单数据。
字段完全对应数据库表 t_d3i_dcm_task_form_data 的结构。
"""
# 基础信息
id = IntegerField('主键ID')
rec_id = IntegerField('记录ID')
rec_disp_num = StringField('显示编号', validators=[Length(max=50, message='显示编号长度不能超过50字符')])
rec_type_id = IntegerField('类型ID')
rec_type_name = StringField('案件类型', validators=[Length(max=100, message='案件类型长度不能超过100字符')])
# 任务信息
task_num = StringField('任务号', validators=[Length(max=50, message='任务号长度不能超过50字符')])
other_task_num = StringField('第三方任务号', validators=[Length(max=100, message='第三方任务号长度不能超过100字符')])
act_property_id = IntegerField('任务属性ID')
# 业务信息
biz_id = IntegerField('业务ID')
biz_name = StringField('业务名称', validators=[Length(max=200, message='业务名称长度不能超过200字符')])
sys_id = IntegerField('系统ID')
# 地址与坐标
address = TextAreaField('地址描述', validators=[Length(max=65535, message='地址描述长度不能超过65535字符')])
district_name = StringField('所属区域', validators=[Length(max=50, message='所属区域长度不能超过50字符')])
coordinate_x = FloatField('经度')
coordinate_y = FloatField('纬度')
lonlat_x = FloatField('经纬度X')
lonlat_y = FloatField('经纬度Y')
# 事件信息
event_type_id = IntegerField('问题类型ID')
event_type_name = StringField('问题类型', validators=[Length(max=100, message='问题类型长度不能超过100字符')])
event_src_id = IntegerField('问题来源ID')
event_src_name = StringField('问题来源', validators=[Length(max=100, message='问题来源长度不能超过100字符')])
event_desc = TextAreaField('问题描述', validators=[Length(max=65535, message='问题描述长度不能超过65535字符')])
max_event_type_id = IntegerField('最大事件类型ID')
max_event_type_name = StringField('最大事件类型名称', validators=[Length(max=200, message='最大事件类型名称长度不能超过200字符')])
# 分类信息
main_type_id = IntegerField('大类ID')
main_type_name = StringField('大类名称', validators=[Length(max=100, message='大类名称长度不能超过100字符')])
sub_type_id = IntegerField('小类ID')
sub_type_name = StringField('小类名称', validators=[Length(max=100, message='小类名称长度不能超过100字符')])
third_type_id = IntegerField('第三级类型ID')
third_type_name = StringField('第三级类型名称', validators=[Length(max=100, message='第三级类型名称长度不能超过100字符')])
forth_type_id = IntegerField('第四级类型ID')
forth_type_name = StringField('第四级类型名称', validators=[Length(max=100, message='第四级类型名称长度不能超过100字符')])
fifth_type_id = IntegerField('第五级类型ID')
fifth_type_name = StringField('第五级类型名称', validators=[Length(max=100, message='第五级类型名称长度不能超过100字符')])
sixth_type_id = IntegerField('第六级类型ID')
sixth_type_name = StringField('第六级类型名称', validators=[Length(max=100, message='第六级类型名称长度不能超过100字符')])
seventh_type_id = IntegerField('第七级类型ID')
seventh_type_name = StringField('第七级类型名称', validators=[Length(max=100, message='第七级类型名称长度不能超过100字符')])
# 时间与状态
create_time = IntegerField('创建时间戳')
update_time = IntegerField('更新时间戳')
deadline_time = IntegerField('处理截止时间戳')
warning_time = IntegerField('处理预警时间戳')
occur_time = IntegerField('发生时间戳')
dispatch_time = IntegerField('派遣时间戳')
archive_time = IntegerField('归档时间戳')
cancel_time = IntegerField('取消时间戳')
refresh_time = IntegerField('刷新时间戳')
refresh_start_time = IntegerField('刷新开始时间戳')
check_send_time = IntegerField('核查发送时间戳')
check_reply_time = IntegerField('核查回复时间戳')
func_deadline = IntegerField('职能部门截止时间戳')
func_deal_time = IntegerField('职能部门处理时间戳')
proc_start_time = IntegerField('处理开始时间戳')
custom_deadline = IntegerField('自定义截止时间戳')
patroltask_deadline_time = IntegerField('巡查任务截止时间戳')
# 时限描述
deadline_char = StringField('时限描述', validators=[Length(max=50, message='时限描述长度不能超过50字符')])
func_limit_char = StringField('职能部门时限描述', validators=[Length(max=50, message='职能部门时限描述长度不能超过50字符')])
rec_remain_char = StringField('记录剩余时间描述', validators=[Length(max=50, message='记录剩余时间描述长度不能超过50字符')])
rec_used_char = StringField('记录已用时间描述', validators=[Length(max=50, message='记录已用时间描述长度不能超过50字符')])
# 数值型字段
rec_remain = FloatField('记录剩余时间')
rec_used = FloatField('记录已用时间')
rec_warning = FloatField('记录预警时间')
rec_deadline = FloatField('记录时限')
# 部门与网格
func_part_id = IntegerField('职能部门ID')
func_part_name = StringField('职能部门名称', validators=[Length(max=200, message='职能部门名称长度不能超过200字符')])
func_part_list_id = StringField('职能部门列表ID', validators=[Length(max=100, message='职能部门列表ID长度不能超过100字符')])
func_part_list_name = StringField('职能部门列表名称', validators=[Length(max=200, message='职能部门列表名称长度不能超过200字符')])
specify_func_id = IntegerField('指定职能部门ID')
specify_func_name = StringField('指定职能部门名称', validators=[Length(max=200, message='指定职能部门名称长度不能超过200字符')])
specify_competent_func_id = IntegerField('指定主管职能部门ID')
specify_competent_func_name = StringField('指定主管职能部门名称', validators=[Length(max=200, message='指定主管职能部门名称长度不能超过200字符')])
first_depart_name = StringField('一级专业部门', validators=[Length(max=100, message='一级专业部门长度不能超过100字符')])
second_depart_name = StringField('二级专业部门', validators=[Length(max=100, message='二级专业部门长度不能超过100字符')])
# 地理信息
district_id = IntegerField('区域ID')
street_id = IntegerField('街道ID')
street_name = StringField('街道名称', validators=[Length(max=200, message='街道名称长度不能超过200字符')])
community_id = IntegerField('社区ID')
community_name = StringField('社区名称', validators=[Length(max=200, message='社区名称长度不能超过200字符')])
duty_grid_id = IntegerField('责任网格ID')
duty_grid_name = StringField('责任网格名称', validators=[Length(max=200, message='责任网格名称长度不能超过200字符')])
duty_region_id = IntegerField('责任区域ID')
duty_region_name = StringField('责任区域名称', validators=[Length(max=200, message='责任区域名称长度不能超过200字符')])
duty_district_id = IntegerField('责任区域ID')
duty_district_name = StringField('责任区域名称', validators=[Length(max=200, message='责任区域名称长度不能超过200字符')])
duty_street_id = IntegerField('责任街道ID')
duty_street_name = StringField('责任街道名称', validators=[Length(max=200, message='责任街道名称长度不能超过200字符')])
duty_community_id = IntegerField('责任社区ID')
duty_community_name = StringField('责任社区名称', validators=[Length(max=200, message='责任社区名称长度不能超过200字符')])
law_duty_grid_id = IntegerField('法律责任网格ID')
law_duty_grid_name = StringField('法律责任网格名称', validators=[Length(max=200, message='法律责任网格名称长度不能超过200字符')])
deal_duty_grid_id = IntegerField('处置责任网格ID')
deal_duty_grid_name = StringField('处置责任网格名称', validators=[Length(max=200, message='处置责任网格名称长度不能超过200字符')])
# 人员信息
patrol_id = IntegerField('巡查员ID')
patrol_name = StringField('巡查员名称', validators=[Length(max=200, message='巡查员名称长度不能超过200字符')])
accepter_id = IntegerField('受理人ID')
accepter_name = StringField('受理人姓名', validators=[Length(max=100, message='受理人姓名长度不能超过100字符')])
human_id = IntegerField('操作人ID')
human_name = StringField('操作人名称', validators=[Length(max=255, message='操作人名称长度不能超过255字符')])
reporter_name = StringField('举报人姓名', validators=[Length(max=100, message='举报人姓名长度不能超过100字符')])
reporter_contact = StringField('举报电话', validators=[Length(max=50, message='举报电话长度不能超过50字符')])
tell_num = StringField('联系电话', validators=[Length(max=50, message='联系电话长度不能超过50字符')])
# 状态与标识
read_flag = IntegerField('是否已读(0未读,1已读)')
reply_intime = IntegerField('是否两小时回复(0无需回复,1待回复,2已回复,3超时,4无需回复已恢复)')
return_visit_flag = IntegerField('回访标识(0无需,1待回访,2已回访)')
urgency_level = IntegerField('紧急程度(0正常,1紧急)')
urgent_flag = IntegerField('紧急标识')
func_forbid_reporter_info_flag = IntegerField('是否禁止举报人信息')
public_flag = IntegerField('公开标志')
locked_flag = IntegerField('锁定标识')
transited_flag = IntegerField('转交标识')
split_rec_flag = IntegerField('拆分记录标识')
enable_check_msg = IntegerField('启用核查消息')
no_return_visit_flag = IntegerField('无需回访标识')
common_rec_type_flag = StringField('通用记录类型标识', validators=[Length(max=50, message='通用记录类型标识长度不能超过50字符')])
common_rec_attr_flag = StringField('通用记录属性标识', validators=[Length(max=50, message='通用记录属性标识长度不能超过50字符')])
send_pub_check_task_flag = IntegerField('发送公共核查任务标识')
reply_flag = StringField('回复标识', validators=[Length(max=50, message='回复标识长度不能超过50字符')])
whistle_flag = StringField('吹哨标识', validators=[Length(max=50, message='吹哨标识长度不能超过50字符')])
repeat_state = StringField('重复状态', validators=[Length(max=50, message='重复状态长度不能超过50字符')])
report_state = StringField('上报状态', validators=[Length(max=50, message='上报状态长度不能超过50字符')])
dispose_state = IntegerField('处置状态')
pre_dispose_state = StringField('预处置状态', validators=[Length(max=50, message='预处置状态长度不能超过50字符')])
undertake_user_name = StringField('承办人员', validators=[Length(max=50, message='承办人员长度不能超过50字符')])
undertake_phone = StringField('联系电话', validators=[Length(max=50, message='联系电话长度不能超过50字符')])
deal_person_org = StringField('承办部门', validators=[Length(max=50, message='承办部门长度不能超过50字符')])
# 媒体信息
media_upload_num = IntegerField('媒体上传数量')
media_upload_total_num = IntegerField('媒体上传总数')
media_upload_state = StringField('媒体上传状态', validators=[Length(max=50, message='媒体上传状态长度不能超过50字符')])
media_check_num = IntegerField('媒体核查数量')
media_check_total_num = IntegerField('媒体核查总数')
media_verify_num = IntegerField('媒体核实数量')
media_verify_total_num = IntegerField('媒体核实总数')
media_self_deal_num = IntegerField('自行处置媒体数量')
media_self_deal_total_num = IntegerField('自行处置媒体总数')
media_review_num = IntegerField('复核媒体数量')
media_review_total_num = IntegerField('复核媒体总数')
report_pic_num = IntegerField('上报图片数量')
report_pic_total_num = IntegerField('上报图片总数')
report_video_num = IntegerField('上报视频数量')
report_video_total_num = IntegerField('上报视频总数')
report_wav_num = IntegerField('上报音频数量')
report_wav_total_num = IntegerField('上报音频总数')
check_pic_num = IntegerField('核查图片数量')
check_pic_total_num = IntegerField('核查图片总数')
check_video_num = IntegerField('核查视频数量')
check_video_total_num = IntegerField('核查视频总数')
check_wav_num = IntegerField('核查音频数量')
check_wav_total_num = IntegerField('核查音频总数')
verify_pic_num = IntegerField('核实图片数量')
verify_pic_total_num = IntegerField('核实图片总数')
verify_video_num = IntegerField('核实视频数量')
verify_video_total_num = IntegerField('核实视频总数')
verify_wav_num = IntegerField('核实音频数量')
verify_wav_total_num = IntegerField('核实音频总数')
self_deal_pic_num = IntegerField('自行处置图片数量')
self_deal_pic_total_num = IntegerField('自行处置图片总数')
self_deal_video_num = IntegerField('自行处置视频数量')
self_deal_video_total_num = IntegerField('自行处置视频总数')
self_deal_wav_num = IntegerField('自行处置音频数量')
self_deal_wav_total_num = IntegerField('自行处置音频总数')
review_pic_num = IntegerField('复核图片数量')
review_video_total_num = IntegerField('复核视频总数')
review_wav_num = IntegerField('复核音频数量')
review_wav_total_num = IntegerField('复核音频总数')
# 媒体路径与属性
media_url = StringField('内部访问URL', validators=[Length(max=512, message='内部访问URL长度不能超过512字符')])
mms_pic_path = StringField('彩信图片路径', validators=[Length(max=500, message='彩信图片路径长度不能超过500字符')])
media_path = StringField('服务器存储路径', validators=[Length(max=512, message='服务器存储路径长度不能超过512字符')])
media_type = StringField('媒体类型', validators=[Length(max=50, message='媒体类型长度不能超过50字符')])
media_usage = StringField('使用场景', validators=[Length(max=100, message='使用场景长度不能超过100字符')])
media_server_name = StringField('媒体服务器名称', validators=[Length(max=100, message='媒体服务器名称长度不能超过100字符')])
media_property = IntegerField('媒体属性')
media_uploaded_name = StringField('上传时的原始文件名', validators=[Length(max=255, message='上传时的原始文件名长度不能超过255字符')])
media_shot = StringField('截图标识或路径', validators=[Length(max=255, message='截图标识或路径长度不能超过255字符')])
media_label_type_id = IntegerField('标签类型ID')
media_default_url = StringField('外部可访问URL', validators=[Length(max=512, message='外部可访问URL长度不能超过512字符')])
display_order = IntegerField('显示顺序')
store_type_id = IntegerField('存储类型ID')
special_item_image_type = StringField('特殊图片类型', validators=[Length(max=100, message='特殊图片类型长度不能超过100字符')])
height = IntegerField('图片高度')
width = IntegerField('图片宽度')
send_flag = IntegerField('发送标志')
public_flag = IntegerField('公开标志')
gen_thumb = IntegerField('是否生成缩略图')
can_delete = IntegerField('是否可删除')
delete_flag = IntegerField('删除标记')
delete_reason = TextAreaField('删除原因', validators=[Length(max=65535, message='删除原因长度不能超过65535字符')])
# 地理与位置
pos_type = StringField('位置类型', validators=[Length(max=50, message='位置类型长度不能超过50字符')])
view_angle = StringField('视角', validators=[Length(max=100, message='视角长度不能超过100字符')])
view_image_name = StringField('视图图片名称', validators=[Length(max=200, message='视图图片名称长度不能超过200字符')])
view_image_x = FloatField('视图图片X坐标')
view_image_y = FloatField('视图图片Y坐标')
view_pos_x = FloatField('视图位置X坐标')
view_pos_y = FloatField('视图位置Y坐标')
# 附件与标识
attach_rec_flag = StringField('附件记录标识', validators=[Length(max=50, message='附件记录标识长度不能超过50字符')])
gather_flag = StringField('汇总标识', validators=[Length(max=50, message='汇总标识长度不能超过50字符')])
link_field_value = StringField('关联字段值', validators=[Length(max=500, message='关联字段值长度不能超过500字符')])
link_field_display_value = StringField('关联字段显示值', validators=[Length(max=500, message='关联字段显示值长度不能超过500字符')])
unique_id = StringField('唯一标识', validators=[Length(max=100, message='唯一标识长度不能超过100字符')])
third_unique_id = StringField('第三方唯一标识', validators=[Length(max=100, message='第三方唯一标识长度不能超过100字符')])
equal_group_id = IntegerField('等值组ID')
rec_category_id = IntegerField('记录类别ID')
# 处置与审核
dispatch_opinion = StringField('派遣意见', validators=[Length(max=500, message='派遣意见长度不能超过500字符')])
revise_opinion = StringField('修订意见', validators=[Length(max=500, message='修订意见长度不能超过500字符')])
reply_opinion = StringField('回复意见', validators=[Length(max=500, message='回复意见长度不能超过500字符')])
new_inst_advise = StringField('立案建议', validators=[Length(max=500, message='立案建议长度不能超过500字符')])
new_inst_cond_id = IntegerField('立案条件ID')
new_inst_cond_name = StringField('立案条件', validators=[Length(max=200, message='立案条件长度不能超过200字符')])
case_closure_condition = StringField('结案条件', validators=[Length(max=200, message='结案条件长度不能超过200字符')])
# 特殊字段
event_marks = StringField('事件标记', validators=[Length(max=500, message='事件标记长度不能超过500字符')])
deduction = StringField('扣减', validators=[Length(max=100, message='扣减长度不能超过100字符')])
event_property_id = IntegerField('事件属性ID')
event_property_name = StringField('事件属性名称', validators=[Length(max=200, message='事件属性名称长度不能超过200字符')])
city_village_flag = StringField('城乡标识', validators=[Length(max=50, message='城乡标识长度不能超过50字符')])
force_handle_flag = StringField('强制处理标识', validators=[Length(max=50, message='强制处理标识长度不能超过50字符')])
auto_check_count = IntegerField('自动核查次数')
deal_evaluate_ids = StringField('处置评价ID列表', validators=[Length(max=200, message='处置评价ID列表长度不能超过200字符')])
newinst_no_transit = StringField('立案不转交', validators=[Length(max=50, message='立案不转交长度不能超过50字符')])
super_rec_id = IntegerField('上级记录ID')
site_num = StringField('站点编号', validators=[Length(max=50, message='站点编号长度不能超过50字符')])
difficult_type_id = IntegerField('困难类型ID')
event_district_grade_id = IntegerField('事件区域等级ID')
event_district_grade_name = StringField('事件区域等级名称', validators=[Length(max=100, message='事件区域等级名称长度不能超过100字符')])
cus_grid_code = StringField('自定义网格编码', validators=[Length(max=100, message='自定义网格编码长度不能超过100字符')])
site_id = IntegerField('站点ID')
shop_id = IntegerField('商铺ID')
shop_name = StringField('商铺名称', validators=[Length(max=200, message='商铺名称长度不能超过200字符')])
spec_type_id = IntegerField('特殊类型ID')
spec_type_name = StringField('特殊类型名称', validators=[Length(max=100, message='特殊类型名称长度不能超过100字符')])
proc_account_state_id = IntegerField('处理账户状态ID')
check_type_id = IntegerField('核查类型ID')
rec_analysis_type_id = IntegerField('记录分析类型ID')
proc_time_state_id = IntegerField('处理流程状态ID')
proc_ard_state_id = IntegerField('处理仲裁状态ID')
proc_enq_state_id = IntegerField('处理询问状态ID')
proc_sup_state_id = IntegerField('处理监督状态ID')
func_time_state_id = IntegerField('职能部门时间状态ID')
check_msg_state_id = IntegerField('核查消息状态ID')
verify_msg_state_id = IntegerField('核实消息状态ID')
regather_msg_state_id = IntegerField('重新采集消息状态ID')
supervision_check_state_id = IntegerField('监督核查状态ID')
self_deal_msg_state_id = IntegerField('自行处置消息状态ID')
review_msg_state_id = IntegerField('复核消息状态ID')
proc_press_state_id = IntegerField('处理压力状态ID')
hot_area = StringField('热点区域', validators=[Length(max=100, message='热点区域长度不能超过100字符')])
cg_area = StringField('城管区域', validators=[Length(max=100, message='城管区域长度不能超过100字符')])
hw_area = StringField('环卫区域', validators=[Length(max=100, message='环卫区域长度不能超过100字符')])
sz_area = StringField('市政区域', validators=[Length(max=100, message='市政区域长度不能超过100字符')])
device_guid = StringField('设备GUID', validators=[Length(max=100, message='设备GUID长度不能超过100字符')])
jx_id = IntegerField('警讯ID')
jx_jxmc = StringField('警讯名称', validators=[Length(max=200, message='警讯名称长度不能超过200字符')])
jx_design_type = StringField('警讯设计类型', validators=[Length(max=100, message='警讯设计类型长度不能超过100字符')])
report_time_segment_id = IntegerField('上报时段ID')
archive_cond_id = IntegerField('归档条件ID')
archive_cond = StringField('归档条件', validators=[Length(max=100, message='归档条件长度不能超过100字符')])
archive_type_id = IntegerField('归档类型ID')
road_type_id = IntegerField('道路类型ID')
road_name = StringField('道路名称', validators=[Length(max=200, message='道路名称长度不能超过200字符')])
road_id = IntegerField('道路ID')
road_type_name = StringField('道路类型名称', validators=[Length(max=100, message='道路类型名称长度不能超过100字符')])
area_type_id = IntegerField('区域类型ID')
duty_grid_type_id = IntegerField('责任网格类型ID')
deal_duty_grid_type_id = IntegerField('处置责任网格类型ID')
time_area_id = IntegerField('时段ID')
time_area_name = StringField('时段名称', validators=[Length(max=100, message='时段名称长度不能超过100字符')])
card_num = StringField('证件号码', validators=[Length(max=100, message='证件号码长度不能超过100字符')])
cell_id = IntegerField('单元格ID')
cell_name = StringField('单元格名称', validators=[Length(max=200, message='单元格名称长度不能超过200字符')])
damage_grade_id = IntegerField('损毁等级ID')
damage_grade_name = StringField('损毁等级名称', validators=[Length(max=100, message='损毁等级名称长度不能超过100字符')])
event_grade_id = IntegerField('事件等级ID')
event_grade_name = StringField('事件等级名称', validators=[Length(max=100, message='事件等级名称长度不能超过100字符')])
event_level_id = IntegerField('事件级别ID')
event_level_name = StringField('事件级别名称', validators=[Length(max=100, message='事件级别名称长度不能超过100字符')])
event_district_id = IntegerField('事件区域ID')
event_district_name = StringField('事件区域名称', validators=[Length(max=100, message='事件区域名称长度不能超过100字符')])
display_property = StringField('显示属性', validators=[Length(max=200, message='显示属性长度不能超过200字符')])
display_style_id = IntegerField('显示样式ID')
refresh_flag = IntegerField('刷新标识')
video_device_id = IntegerField('视频设备ID')
video_param = StringField('视频参数', validators=[Length(max=500, message='视频参数长度不能超过500字符')])
video_device_id = IntegerField('视频设备ID')
video_param = StringField('视频参数', validators=[Length(max=500, message='视频参数长度不能超过500字符')])
patrol_deal_flag = IntegerField('巡查处置标识')
send_from_type = StringField('发送来源类型', validators=[Length(max=50, message='发送来源类型长度不能超过50字符')])
reply_intime_deadline = IntegerField('两小时回复截止时间戳')
accept_status = StringField('受理状态', validators=[Length(max=50, message='受理状态长度不能超过50字符')])
squadron_id = IntegerField('中队ID')
squadron_name = StringField('中队名称', validators=[Length(max=200, message='中队名称长度不能超过200字符')])
property_company_id = IntegerField('物业公司ID')
act_record_id = IntegerField('操作记录ID')
main_rec_id = IntegerField('主记录ID')
force_handle_flag = StringField('强制处理标识', validators=[Length(max=50, message='强制处理标识长度不能超过50字符')])
func_custom_limit = StringField('职能部门自定义时限', validators=[Length(max=50, message='职能部门自定义时限长度不能超过50字符')])
def process(self, formdata=None, obj=None, **kwargs):
"""
处理表单数据,在数据绑定前进行预处理。
主要功能:
- 遍历所有表单字段
- 对字符串类型的值去除两端空白字符
- 调用父类的process方法继续处理
"""
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 DcmTaskFormDatumBase(TD3iDcmTaskFormDatum, CommonModel):
"""
企业待办表单数据基础类(完全映射 TD3iDcmTaskFormDatum 字段)。
封装所有与企业待办表单数据相关的通用操作方法。
"""
FieldMapping = {
'id': 'id',
'rec_id': 'rec_id',
'rec_disp_num': 'rec_disp_num',
'rec_type_id': 'rec_type_id',
'rec_type_name': 'rec_type_name',
'task_num': 'task_num',
'other_task_num': 'other_task_num',
'act_property_id': 'act_property_id',
'biz_id': 'biz_id',
'biz_name': 'biz_name',
'sys_id': 'sys_id',
'address': 'address',
'district_name': 'district_name',
'coordinate_x': 'coordinate_x',
'coordinate_y': 'coordinate_y',
'lonlat_x': 'lonlat_x',
'lonlat_y': 'lonlat_y',
'event_type_id': 'event_type_id',
'event_type_name': 'event_type_name',
'event_src_id': 'event_src_id',
'event_src_name': 'event_src_name',
'event_desc': 'event_desc',
'max_event_type_id': 'max_event_type_id',
'max_event_type_name': 'max_event_type_name',
'main_type_id': 'main_type_id',
'main_type_name': 'main_type_name',
'sub_type_id': 'sub_type_id',
'sub_type_name': 'sub_type_name',
'third_type_id': 'third_type_id',
'third_type_name': 'third_type_name',
'forth_type_id': 'forth_type_id',
'forth_type_name': 'forth_type_name',
'fifth_type_id': 'fifth_type_id',
'fifth_type_name': 'fifth_type_name',
'sixth_type_id': 'sixth_type_id',
'sixth_type_name': 'sixth_type_name',
'seventh_type_id': 'seventh_type_id',
'seventh_type_name': 'seventh_type_name',
'create_time': 'create_time',
'update_time': 'update_time',
'deadline_time': 'deadline_time',
'warning_time': 'warning_time',
'occur_time': 'occur_time',
'dispatch_time': 'dispatch_time',
'archive_time': 'archive_time',
'cancel_time': 'cancel_time',
'refresh_time': 'refresh_time',
'refresh_start_time': 'refresh_start_time',
'check_send_time': 'check_send_time',
'check_reply_time': 'check_reply_time',
'func_deadline': 'func_deadline',
'func_deal_time': 'func_deal_time',
'proc_start_time': 'proc_start_time',
'custom_deadline': 'custom_deadline',
'patroltask_deadline_time': 'patroltask_deadline_time',
'deadline_char': 'deadline_char',
'func_limit_char': 'func_limit_char',
'rec_remain_char': 'rec_remain_char',
'rec_used_char': 'rec_used_char',
'rec_remain': 'rec_remain',
'rec_used': 'rec_used',
'rec_warning': 'rec_warning',
'rec_deadline': 'rec_deadline',
'func_part_id': 'func_part_id',
'func_part_name': 'func_part_name',
'func_part_list_id': 'func_part_list_id',
'func_part_list_name': 'func_part_list_name',
'specify_func_id': 'specify_func_id',
'specify_func_name': 'specify_func_name',
'specify_competent_func_id': 'specify_competent_func_id',
'specify_competent_func_name': 'specify_competent_func_name',
'first_depart_name': 'first_depart_name',
'second_depart_name': 'second_depart_name',
'district_id': 'district_id',
'street_id': 'street_id',
'street_name': 'street_name',
'community_id': 'community_id',
'community_name': 'community_name',
'duty_grid_id': 'duty_grid_id',
'duty_grid_name': 'duty_grid_name',
'duty_region_id': 'duty_region_id',
'duty_region_name': 'duty_region_name',
'duty_district_id': 'duty_district_id',
'duty_district_name': 'duty_district_name',
'duty_street_id': 'duty_street_id',
'duty_street_name': 'duty_street_name',
'duty_community_id': 'duty_community_id',
'duty_community_name': 'duty_community_name',
'law_duty_grid_id': 'law_duty_grid_id',
'law_duty_grid_name': 'law_duty_grid_name',
'deal_duty_grid_id': 'deal_duty_grid_id',
'deal_duty_grid_name': 'deal_duty_grid_name',
'patrol_id': 'patrol_id',
'patrol_name': 'patrol_name',
'accepter_id': 'accepter_id',
'accepter_name': 'accepter_name',
'human_id': 'human_id',
'human_name': 'human_name',
'reporter_name': 'reporter_name',
'reporter_contact': 'reporter_contact',
'tell_num': 'tell_num',
'read_flag': 'read_flag',
'reply_intime': 'reply_intime',
'return_visit_flag': 'return_visit_flag',
'urgency_level': 'urgency_level',
'urgent_flag': 'urgent_flag',
'func_forbid_reporter_info_flag': 'func_forbid_reporter_info_flag',
'public_flag': 'public_flag',
'locked_flag': 'locked_flag',
'transited_flag': 'transited_flag',
'split_rec_flag': 'split_rec_flag',
'enable_check_msg': 'enable_check_msg',
'no_return_visit_flag': 'no_return_visit_flag',
'common_rec_type_flag': 'common_rec_type_flag',
'common_rec_attr_flag': 'common_rec_attr_flag',
'send_pub_check_task_flag': 'send_pub_check_task_flag',
'reply_flag': 'reply_flag',
'whistle_flag': 'whistle_flag',
'repeat_state': 'repeat_state',
'report_state': 'report_state',
'dispose_state': 'dispose_state',
'pre_dispose_state': 'pre_dispose_state',
'undertake_user_name': 'undertake_user_name',
'undertake_phone': 'undertake_phone',
'deal_person_org': 'deal_person_org',
'media_upload_num': 'media_upload_num',
'media_upload_total_num': 'media_upload_total_num',
'media_upload_state': 'media_upload_state',
'media_check_num': 'media_check_num',
'media_check_total_num': 'media_check_total_num',
'media_verify_num': 'media_verify_num',
'media_verify_total_num': 'media_verify_total_num',
'media_self_deal_num': 'media_self_deal_num',
'media_self_deal_total_num': 'media_self_deal_total_num',
'media_review_num': 'media_review_num',
'media_review_total_num': 'media_review_total_num',
'report_pic_num': 'report_pic_num',
'report_pic_total_num': 'report_pic_total_num',
'report_video_num': 'report_video_num',
'report_video_total_num': 'report_video_total_num',
'report_wav_num': 'report_wav_num',
'report_wav_total_num': 'report_wav_total_num',
'check_pic_num': 'check_pic_num',
'check_pic_total_num': 'check_pic_total_num',
'check_video_num': 'check_video_num',
'check_video_total_num': 'check_video_total_num',
'check_wav_num': 'check_wav_num',
'check_wav_total_num': 'check_wav_total_num',
'verify_pic_num': 'verify_pic_num',
'verify_pic_total_num': 'verify_pic_total_num',
'verify_video_num': 'verify_video_num',
'verify_video_total_num': 'verify_video_total_num',
'verify_wav_num': 'verify_wav_num',
'verify_wav_total_num': 'verify_wav_total_num',
'self_deal_pic_num': 'self_deal_pic_num',
'self_deal_pic_total_num': 'self_deal_pic_total_num',
'self_deal_video_num': 'self_deal_video_num',
'self_deal_video_total_num': 'self_deal_video_total_num',
'self_deal_wav_num': 'self_deal_wav_num',
'self_deal_wav_total_num': 'self_deal_wav_total_num',
'review_pic_num': 'review_pic_num',
'review_pic_total_num': 'review_pic_total_num',
'review_video_num': 'review_video_num',
'review_video_total_num': 'review_video_total_num',
'review_wav_num': 'review_wav_num',
'review_wav_total_num': 'review_wav_total_num',
'media_url': 'media_url',
'mms_pic_path': 'mms_pic_path',
'media_path': 'media_path',
'media_type': 'media_type',
'media_usage': 'media_usage',
'media_server_name': 'media_server_name',
'media_property': 'media_property',
'media_uploaded_name': 'media_uploaded_name',
'media_shot': 'media_shot',
'media_label_type_id': 'media_label_type_id',
'media_default_url': 'media_default_url',
'display_order': 'display_order',
'store_type_id': 'store_type_id',
'special_item_image_type': 'special_item_image_type',
'height': 'height',
'width': 'width',
'send_flag': 'send_flag',
'public_flag': 'public_flag',
'gen_thumb': 'gen_thumb',
'can_delete': 'can_delete',
'delete_flag': 'delete_flag',
'delete_reason': 'delete_reason',
'pos_type': 'pos_type',
'view_angle': 'view_angle',
'view_image_name': 'view_image_name',
'view_image_x': 'view_image_x',
'view_image_y': 'view_image_y',
'view_pos_x': 'view_pos_x',
'view_pos_y': 'view_pos_y',
'attach_rec_flag': 'attach_rec_flag',
'gather_flag': 'gather_flag',
'link_field_value': 'link_field_value',
'link_field_display_value': 'link_field_display_value',
'unique_id': 'unique_id',
'third_unique_id': 'third_unique_id',
'equal_group_id': 'equal_group_id',
'rec_category_id': 'rec_category_id',
'dispatch_opinion': 'dispatch_opinion',
'revise_opinion': 'revise_opinion',
'reply_opinion': 'reply_opinion',
'new_inst_advise': 'new_inst_advise',
'new_inst_cond_id': 'new_inst_cond_id',
'new_inst_cond_name': 'new_inst_cond_name',
'case_closure_condition': 'case_closure_condition',
'event_marks': 'event_marks',
'deduction': 'deduction',
'event_property_id': 'event_property_id',
'event_property_name': 'event_property_name',
'city_village_flag': 'city_village_flag',
'force_handle_flag': 'force_handle_flag',
'auto_check_count': 'auto_check_count',
'deal_evaluate_ids': 'deal_evaluate_ids',
'newinst_no_transit': 'newinst_no_transit',
'super_rec_id': 'super_rec_id',
'site_num': 'site_num',
'difficult_type_id': 'difficult_type_id',
'event_district_grade_id': 'event_district_grade_id',
'event_district_grade_name': 'event_district_grade_name',
'cus_grid_code': 'cus_grid_code',
'site_id': 'site_id',
'shop_id': 'shop_id',
'shop_name': 'shop_name',
'spec_type_id': 'spec_type_id',
'spec_type_name': 'spec_type_name',
'proc_account_state_id': 'proc_account_state_id',
'check_type_id': 'check_type_id',
'rec_analysis_type_id': 'rec_analysis_type_id',
'proc_time_state_id': 'proc_time_state_id',
'proc_ard_state_id': 'proc_ard_state_id',
'proc_enq_state_id': 'proc_enq_state_id',
'proc_sup_state_id': 'proc_sup_state_id',
'func_time_state_id': 'func_time_state_id',
'check_msg_state_id': 'check_msg_state_id',
'verify_msg_state_id': 'verify_msg_state_id',
'regather_msg_state_id': 'regather_msg_state_id',
'supervision_check_state_id': 'supervision_check_state_id',
'self_deal_msg_state_id': 'self_deal_msg_state_id',
'review_msg_state_id': 'review_msg_state_id',
'proc_press_state_id': 'proc_press_state_id',
'hot_area': 'hot_area',
'cg_area': 'cg_area',
'hw_area': 'hw_area',
'sz_area': 'sz_area',
'device_guid': 'device_guid',
'jx_id': 'jx_id',
'jx_jxmc': 'jx_jxmc',
'jx_design_type': 'jx_design_type',
'report_time_segment_id': 'report_time_segment_id',
'archive_cond_id': 'archive_cond_id',
'archive_cond': 'archive_cond',
'archive_type_id': 'archive_type_id',
'road_type_id': 'road_type_id',
'road_name': 'road_name',
'road_id': 'road_id',
'road_type_name': 'road_type_name',
'area_type_id': 'area_type_id',
'duty_grid_type_id': 'duty_grid_type_id',
'deal_duty_grid_type_id': 'deal_duty_grid_type_id',
'time_area_id': 'time_area_id',
'time_area_name': 'time_area_name',
'card_num': 'card_num',
'cell_id': 'cell_id',
'cell_name': 'cell_name',
'damage_grade_id': 'damage_grade_id',
'damage_grade_name': 'damage_grade_name',
'event_grade_id': 'event_grade_id',
'event_grade_name': 'event_grade_name',
'event_level_id': 'event_level_id',
'event_level_name': 'event_level_name',
'event_district_id': 'event_district_id',
'event_district_name': 'event_district_name',
'display_property': 'display_property',
'display_style_id': 'display_style_id',
'refresh_flag': 'refresh_flag',
'video_device_id': 'video_device_id',
'video_param': 'video_param',
'patrol_deal_flag': 'patrol_deal_flag',
'send_from_type': 'send_from_type',
'reply_intime_deadline': 'reply_intime_deadline',
'accept_status': 'accept_status',
'squadron_id': 'squadron_id',
'squadron_name': 'squadron_name',
'property_company_id': 'property_company_id',
'act_record_id': 'act_record_id',
'main_rec_id': 'main_rec_id',
'func_custom_limit': 'func_custom_limit',
}
@classmethod
async def exist_other(cls, id: Union[str, int], rec_id: Union[str, int]):
"""
检查是否存在除当前任务外的其他同记录ID的任务。
:param id: 当前任务ID
:param rec_id: 记录ID
:return: 存在返回任务对象,不存在返回None
"""
_query = select(cls).where(cls.id != id, cls.rec_id == rec_id)
_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))
_task_list: list[cls] = (await cls.orm_execute_scalars(_query)).all()
return _task_list
@classmethod
async def is_exist(cls, rec_id: Union[str, int]):
"""
检查任务是否已经存在(根据记录ID)。
"""
_query = select(cls).where(cls.rec_id == rec_id)
_task: cls = await cls.query_first(_query)
return _task
@classmethod
async def search_base(cls, is_paging=True, **kwargs):
"""
按参数搜索任务数据的基础方法。
支持字段:
- task_num, rec_disp_num, event_type_name, district_name, urgency_level, read_flag 等
- 支持模糊匹配:event_type_name, rec_type_name, event_src_name, first_depart_name, second_depart_name
- 支持精确匹配:biz_id, sys_id, urgency_level, read_flag, rec_type_id, deadline_time 等
:param is_paging: 是否分页
:param kwargs: 查询参数
:key int page_number: 页码(缺省随机1~100
:key int page_size: 每页数量(缺省20
:key dict sort_clause: 排序配置,如 {'task_num': 'asc'}
:key str task_num: 精确匹配任务号
:key str rec_disp_num: 精确匹配显示编号
:key str event_type_name: 模糊匹配问题类型
:key str district_name: 精确匹配区域
:key int urgency_level: 精确匹配紧急程度
:key int read_flag: 精确匹配是否已读
:key int biz_id: 精确匹配业务ID
:key int sys_id: 精确匹配系统ID
:key int rec_type_id: 精确匹配类型ID
:key int deadline_time: 精确匹配处理截止时间戳
:return: (DataFrame, Pagination)
"""
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.event_type_name.key: '%{}%',
cls.rec_type_name.key: '%{}%',
cls.event_src_name.key: '%{}%',
cls.first_depart_name.key: '%{}%',
cls.second_depart_name.key: '%{}%',
cls.district_name.key: '%{}%',
cls.street_name.key: '%{}%',
cls.community_name.key: '%{}%',
cls.func_part_name.key: '%{}%',
cls.specify_func_name.key: '%{}%',
cls.specify_competent_func_name.key: '%{}%',
cls.main_type_name.key: '%{}%',
cls.sub_type_name.key: '%{}%',
cls.third_type_name.key: '%{}%',
cls.forth_type_name.key: '%{}%',
cls.fifth_type_name.key: '%{}%',
cls.sixth_type_name.key: '%{}%',
cls.seventh_type_name.key: '%{}%',
cls.duty_grid_name.key: '%{}%',
cls.duty_region_name.key: '%{}%',
cls.duty_district_name.key: '%{}%',
cls.duty_street_name.key: '%{}%',
cls.duty_community_name.key: '%{}%',
cls.law_duty_grid_name.key: '%{}%',
cls.deal_duty_grid_name.key: '%{}%',
cls.patrol_name.key: '%{}%',
cls.accepter_name.key: '%{}%',
cls.human_name.key: '%{}%',
cls.reporter_name.key: '%{}%',
cls.shop_name.key: '%{}%',
cls.spec_type_name.key: '%{}%',
cls.squadron_name.key: '%{}%',
cls.road_name.key: '%{}%',
cls.time_area_name.key: '%{}%',
cls.hot_area.key: '%{}%',
cls.cg_area.key: '%{}%',
cls.hw_area.key: '%{}%',
cls.sz_area.key: '%{}%',
cls.event_district_grade_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.task_num, cls.rec_disp_num)
_task_df = await cls.query_as_df(_data_query)
if not _task_df.empty:
_task_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
_task_df[cls.id.key] = _task_df[cls.id.key].astype(str)
return _task_df, _paging
@classmethod
async def search(cls, **kwargs):
"""
按参数搜索任务数据,返回分页格式数据。
"""
_task_df, _paging = await cls.search_base(**kwargs)
return {
'total': _paging.row_count,
'rows': _task_df.to_dict('records'),
'pagination': {
'page_number': _paging.page_number,
'page_count': _paging.page_count,
'page_size': _paging.page_size,
},
}
@classmethod
async def exists_rec_id(cls, data_df: pd.DataFrame):
"""
查找 data_df 中在数据库中已存在和不存在的记录。根据 rec_id 字段判断。
:param data_df: 输入的数据框架,必须包含 rec_id 列
:return: (exists_df: pd.DataFrame, latest_df: pd.DataFrame)
- exists_df: 在数据库中存在的记录
- latest_df: 在数据库中不存在的记录
"""
if data_df.empty:
return pd.DataFrame(), pd.DataFrame()
# 获取待查询的 rec_id 列表(去重)
rec_ids = data_df[cls.rec_id.key].unique().tolist()
if not rec_ids:
return pd.DataFrame(), data_df.copy()
# 查询数据库中已存在的 rec_id
_query = select(cls.id, cls.rec_id).where(cls.rec_id.in_(rec_ids))
rec_ids_df = await cls.query_as_df(_query)
if rec_ids_df.empty:
return pd.DataFrame(), data_df.copy()
# 构建 rec_id -> id 的映射字典
rec_id_to_id_map = dict(zip(rec_ids_df[cls.rec_id.key], rec_ids_df[cls.id.key]))
# 根据 rec_id 是否在数据库中,划分数据
mask_exists = data_df[cls.rec_id.key].isin(rec_ids_df[cls.rec_id.key])
# 数据库已经有的记录
exists_df = data_df[mask_exists].copy()
# 自动补充从数据库查到的 id 字段
exists_df[cls.id.key] = exists_df[cls.rec_id.key].map(rec_id_to_id_map)
# 新的数据
latest_df = data_df[~mask_exists].copy()
return exists_df, latest_df
@classmethod
async def fill_form_datum(cls, data_df: pd.DataFrame, index_field: str = 'id',
column_name: str = 'datums',
preprocessing: Optional[Callable] = None):
"""
填充详细数据到数据框架。
用于在查询结果中添加关联的详细信息。
:param pandas.DataFrame data_df: 待填充的数据框架
:param str index_field: 索引字段,一般是任务ID
:param str column_name: 填充时,新增加的列名称,默认为`datums`
:param preprocessing: 预处理,注意预处理必须要返回处理后的结果
:return: 详细数据框架(已填充)
:rtype: pandas.DataFrame
"""
if data_df.empty:
return pd.DataFrame()
_task_ids = list(set(data_df[index_field].unique().tolist()))
if not _task_ids:
return pd.DataFrame()
_query = select(cls).where(cls.dcm_task_id.in_(_task_ids))
_datum_df: pd.DataFrame = await cls.query_as_df(_query)
if not _datum_df.empty:
_datum_df.replace(models.EmptyInDF+models.EmptyDatetimeInDF, '', inplace=True)
# 整理输出数据类型
_datum_df[cls.id.key] = _datum_df[cls.id.key].astype(str)
_datum_df[cls.dcm_task_id.key] = _datum_df[cls.dcm_task_id.key].astype(str)
# 设置索引
_datum_df['index_id'] = _datum_df[cls.id.key]
_datum_df.set_index(['index_id'], inplace=True)
# 对数据进行预处理
if isinstance(preprocessing, Callable):
_datum_df = preprocessing(_datum_df)
# 增加数据填充列
data_df[column_name] = data_df[index_field].apply(
lambda x: _datum_df.query(f"{cls.dcm_task_id.key}=='{x}'").to_dict('records')
)
else:
data_df[column_name] = [[] for _ in range(len(data_df))]
return _datum_df
@register_swagger_model
class DcmTaskFormDatum(DcmTaskFormDatumBase):
"""
企业待办表单数据主业务类(完全继承 TD3iDcmTaskFormDatum 字段)。
---
description: 数字化城市管理信息系统企业待办表单数据
type: object
properties:
id:
description: 主键ID
type: integer
example: 1001
readOnly: true
rec_id:
description: 记录ID
type: integer
example: 2001
rec_disp_num:
description: 显示编号
type: string
example: "D20240501001"
maxLength: 50
rec_type_id:
description: 类型ID
type: integer
example: 101
rec_type_name:
description: 案件类型
type: string
example: "市容环境"
maxLength: 100
task_num:
description: 任务号
type: string
example: "TASK20240501001"
maxLength: 50
other_task_num:
description: 第三方任务号
type: string
example: "THIRD-2024-001"
maxLength: 100
act_property_id:
description: 任务属性ID
type: integer
example: 5
biz_id:
description: 业务ID
type: integer
example: 10
biz_name:
description: 业务名称
type: string
example: "市容巡查"
maxLength: 200
sys_id:
description: 系统ID
type: integer
example: 1
address:
description: 地址描述
type: string
example: "中山路与解放路交叉口"
maxLength: 65535
district_name:
description: 所属区域
type: string
example: "鼓楼区"
maxLength: 50
coordinate_x:
description: 经度
type: number
format: decimal
example: 118.789012
coordinate_y:
description: 纬度
type: number
format: decimal
example: 32.045678
lonlat_x:
description: 经纬度X
type: number
format: decimal
example: 118.789012
lonlat_y:
description: 经纬度Y
type: number
format: decimal
example: 32.045678
event_type_id:
description: 问题类型ID
type: integer
example: 1001
event_type_name:
description: 问题类型
type: string
example: "道路破损"
maxLength: 100
event_src_id:
description: 问题来源ID
type: integer
example: 101
event_src_name:
description: 问题来源
type: string
example: "市民举报"
maxLength: 100
event_desc:
description: 问题描述
type: string
example: "中山路与解放路交叉口路面大面积破损"
maxLength: 65535
max_event_type_id:
description: 最大事件类型ID
type: integer
example: 1002
max_event_type_name:
description: 最大事件类型名称
type: string
example: "市政设施"
maxLength: 200
main_type_id:
description: 大类ID
type: integer
example: 101
main_type_name:
description: 大类名称
type: string
example: "市容环境"
maxLength: 100
sub_type_id:
description: 小类ID
type: integer
example: 10101
sub_type_name:
description: 小类名称
type: string
example: "道路破损"
maxLength: 100
third_type_id:
description: 第三级类型ID
type: integer
example: 1010101
third_type_name:
description: 第三级类型名称
type: string
example: "人行道破损"
maxLength: 100
forth_type_id:
description: 第四级类型ID
type: integer
example: 101010101
forth_type_name:
description: 第四级类型名称
type: string
example: "沥青路面破损"
maxLength: 100
fifth_type_id:
description: 第五级类型ID
type: integer
example: 10101010101
fifth_type_name:
description: 第五级类型名称
type: string
example: "裂缝"
maxLength: 100
sixth_type_id:
description: 第六级类型ID
type: integer
example: 1010101010101
sixth_type_name:
description: 第六级类型名称
type: string
example: "横向裂缝"
maxLength: 100
seventh_type_id:
description: 第七级类型ID
type: integer
example: 101010101010101
seventh_type_name:
description: 第七级类型名称
type: string
example: "细小横向裂缝"
maxLength: 100
create_time:
description: 创建时间戳
type: integer
example: 1714567890000
update_time:
description: 更新时间戳
type: integer
example: 1714578000000
deadline_time:
description: 处理截止时间戳
type: integer
example: 1714578000000
warning_time:
description: 处理预警时间戳
type: integer
example: 1714570000000
occur_time:
description: 发生时间戳
type: integer
example: 1714567800000
dispatch_time:
description: 派遣时间戳
type: integer
example: 1714568000000
archive_time:
description: 归档时间戳
type: integer
example: 1714580000000
cancel_time:
description: 取消时间戳
type: integer
example: 1714579000000
refresh_time:
description: 刷新时间戳
type: integer
example: 1714572000000
refresh_start_time:
description: 刷新开始时间戳
type: integer
example: 1714571000000
check_send_time:
description: 核查发送时间戳
type: integer
example: 1714570000000
check_reply_time:
description: 核查回复时间戳
type: integer
example: 1714571000000
func_deadline:
description: 职能部门截止时间戳
type: integer
example: 1714578000000
func_deal_time:
description: 职能部门处理时间戳
type: integer
example: 1714576000000
proc_start_time:
description: 处理开始时间戳
type: integer
example: 1714572000000
custom_deadline:
description: 自定义截止时间戳
type: integer
example: 1714579000000
patroltask_deadline_time:
description: 巡查任务截止时间戳
type: integer
example: 1714575000000
deadline_char:
description: 时限描述
type: string
example: "24小时"
maxLength: 50
func_limit_char:
description: 职能部门时限描述
type: string
example: "48小时"
maxLength: 50
rec_remain_char:
description: 记录剩余时间描述
type: string
example: "3天"
maxLength: 50
rec_used_char:
description: 记录已用时间描述
type: string
example: "1天"
maxLength: 50
rec_remain:
description: 记录剩余时间
type: number
format: decimal
example: 3.5
rec_used:
description: 记录已用时间
type: number
format: decimal
example: 1.2
rec_warning:
description: 记录预警时间
type: number
format: decimal
example: 0.5
rec_deadline:
description: 记录时限
type: number
format: decimal
example: 5.0
func_part_id:
description: 职能部门ID
type: integer
example: 101
func_part_name:
description: 职能部门名称
type: string
example: "市政工程处"
maxLength: 200
func_part_list_id:
description: 职能部门列表ID
type: string
example: "LIST-001"
maxLength: 100
func_part_list_name:
description: 职能部门列表名称
type: string
example: "市政处置组"
maxLength: 200
specify_func_id:
description: 指定职能部门ID
type: integer
example: 102
specify_func_name:
description: 指定职能部门名称
type: string
example: "城市管理局"
maxLength: 200
specify_competent_func_id:
description: 指定主管职能部门ID
type: integer
example: 103
specify_competent_func_name:
description: 指定主管职能部门名称
type: string
example: "市城管委"
maxLength: 200
first_depart_name:
description: 一级专业部门
type: string
example: "市政工程处"
maxLength: 100
second_depart_name:
description: 二级专业部门
type: string
example: "道路养护科"
maxLength: 100
district_id:
description: 区域ID
type: integer
example: 1001
street_id:
description: 街道ID
type: integer
example: 1002
street_name:
description: 街道名称
type: string
example: "中山路"
maxLength: 200
community_id:
description: 社区ID
type: integer
example: 1003
community_name:
description: 社区名称
type: string
example: "鼓楼社区"
maxLength: 200
duty_grid_id:
description: 责任网格ID
type: integer
example: 1004
duty_grid_name:
description: 责任网格名称
type: string
example: "鼓楼网格01"
maxLength: 200
duty_region_id:
description: 责任区域ID
type: integer
example: 1005
duty_region_name:
description: 责任区域名称
type: string
example: "鼓楼区"
maxLength: 200
duty_district_id:
description: 责任区域ID
type: integer
example: 1005
duty_district_name:
description: 责任区域名称
type: string
example: "鼓楼区"
maxLength: 200
duty_street_id:
description: 责任街道ID
type: integer
example: 1006
duty_street_name:
description: 责任街道名称
type: string
example: "中山路"
maxLength: 200
duty_community_id:
description: 责任社区ID
type: integer
example: 1007
duty_community_name:
description: 责任社区名称
type: string
example: "鼓楼社区"
maxLength: 200
law_duty_grid_id:
description: 法律责任网格ID
type: integer
example: 1008
law_duty_grid_name:
description: 法律责任网格名称
type: string
example: "执法网格01"
maxLength: 200
deal_duty_grid_id:
description: 处置责任网格ID
type: integer
example: 1009
deal_duty_grid_name:
description: 处置责任网格名称
type: string
example: "处置网格01"
maxLength: 200
patrol_id:
description: 巡查员ID
type: integer
example: 2001
patrol_name:
description: 巡查员名称
type: string
example: "张三"
maxLength: 200
accepter_id:
description: 受理人ID
type: integer
example: 2002
accepter_name:
description: 受理人姓名
type: string
example: "李四"
maxLength: 100
human_id:
description: 操作人ID
type: integer
example: 2003
human_name:
description: 操作人名称
type: string
example: "王五"
maxLength: 255
reporter_name:
description: 举报人姓名
type: string
example: "张三"
maxLength: 100
reporter_contact:
description: 举报电话
type: string
example: "13800138000"
maxLength: 50
tell_num:
description: 联系电话
type: string
example: "13800138000"
maxLength: 50
read_flag:
description: 是否已读(0未读,1已读)
type: integer
example: 1
reply_intime:
description: 是否两小时回复(0无需回复,1待回复,2已回复,3超时,4无需回复已恢复)
type: integer
example: 2
return_visit_flag:
description: 回访标识(0无需,1待回访,2已回访)
type: integer
example: 1
urgency_level:
description: 紧急程度(0正常,1紧急)
type: integer
example: 1
urgent_flag:
description: 紧急标识
type: integer
example: 1
func_forbid_reporter_info_flag:
description: 是否禁止举报人信息
type: integer
example: 0
public_flag:
description: 公开标志
type: integer
example: 1
locked_flag:
description: 锁定标识
type: integer
example: 0
transited_flag:
description: 转交标识
type: integer
example: 1
split_rec_flag:
description: 拆分记录标识
type: integer
example: 0
enable_check_msg:
description: 启用核查消息
type: integer
example: 1
no_return_visit_flag:
description: 无需回访标识
type: integer
example: 0
common_rec_type_flag:
description: 通用记录类型标识
type: string
example: "COMMON"
maxLength: 50
common_rec_attr_flag:
description: 通用记录属性标识
type: string
example: "AUTO"
maxLength: 50
send_pub_check_task_flag:
description: 发送公共核查任务标识
type: integer
example: 1
reply_flag:
description: 回复标识
type: string
example: "REPLIED"
maxLength: 50
whistle_flag:
description: 吹哨标识
type: string
example: "WHISTLE"
maxLength: 50
repeat_state:
description: 重复状态
type: string
example: "NOT_REPEAT"
maxLength: 50
report_state:
description: 上报状态
type: string
example: "SUBMITTED"
maxLength: 50
dispose_state:
description: 处置状态
type: integer
example: 1
pre_dispose_state:
description: 预处置状态
type: string
example: "PENDING"
maxLength: 50
undertake_user_name:
description: 承办人员
type: string
example: "张三"
maxLength: 50
undertake_phone:
description: 联系电话
type: string
example: "13800138000"
maxLength: 50
deal_person_org:
description: 承办部门
type: string
example: "部门名称"
maxLength: 50
media_upload_num:
description: 媒体上传数量
type: integer
example: 3
media_upload_total_num:
description: 媒体上传总数
type: integer
example: 5
media_upload_state:
description: 媒体上传状态
type: string
example: "SUCCESS"
maxLength: 50
media_check_num:
description: 媒体核查数量
type: integer
example: 2
media_check_total_num:
description: 媒体核查总数
type: integer
example: 5
media_verify_num:
description: 媒体核实数量
type: integer
example: 1
media_verify_total_num:
description: 媒体核实总数
type: integer
example: 5
media_self_deal_num:
description: 自行处置媒体数量
type: integer
example: 1
media_self_deal_total_num:
description: 自行处置媒体总数
type: integer
example: 3
media_review_num:
description: 复核媒体数量
type: integer
example: 1
media_review_total_num:
description: 复核媒体总数
type: integer
example: 3
report_pic_num:
description: 上报图片数量
type: integer
example: 2
report_pic_total_num:
description: 上报图片总数
type: integer
example: 3
report_video_num:
description: 上报视频数量
type: integer
example: 1
report_video_total_num:
description: 上报视频总数
type: integer
example: 1
report_wav_num:
description: 上报音频数量
type: integer
example: 0
report_wav_total_num:
description: 上报音频总数
type: integer
example: 0
check_pic_num:
description: 核查图片数量
type: integer
example: 2
check_pic_total_num:
description: 核查图片总数
type: integer
example: 3
check_video_num:
description: 核查视频数量
type: integer
example: 1
check_video_total_num:
description: 核查视频总数
type: integer
example: 1
check_wav_num:
description: 核查音频数量
type: integer
example: 0
check_wav_total_num:
description: 核查音频总数
type: integer
example: 0
verify_pic_num:
description: 核实图片数量
type: integer
example: 1
verify_pic_total_num:
description: 核实图片总数
type: integer
example: 1
verify_video_num:
description: 核实视频数量
type: integer
example: 0
verify_video_total_num:
description: 核实视频总数
type: integer
example: 0
verify_wav_num:
description: 核实音频数量
type: integer
example: 0
verify_wav_total_num:
description: 核实音频总数
type: integer
example: 0
self_deal_pic_num:
description: 自行处置图片数量
type: integer
example: 1
self_deal_pic_total_num:
description: 自行处置图片总数
type: integer
example: 2
self_deal_video_num:
description: 自行处置视频数量
type: integer
example: 0
self_deal_video_total_num:
description: 自行处置视频总数
type: integer
example: 1
self_deal_wav_num:
description: 自行处置音频数量
type: integer
example: 0
self_deal_wav_total_num:
description: 自行处置音频总数
type: integer
example: 0
review_pic_num:
description: 复核图片数量
type: integer
example: 1
review_pic_total_num:
description: 复核图片总数
type: integer
example: 1
review_video_num:
description: 复核视频数量
type: integer
example: 0
review_video_total_num:
description: 复核视频总数
type: integer
example: 0
review_wav_num:
description: 复核音频数量
type: integer
example: 0
review_wav_total_num:
description: 复核音频总数
type: integer
example: 0
media_url:
description: 内部访问URL
type: string
example: "http://internal/media/123.jpg"
maxLength: 512
mms_pic_path:
description: 彩信图片路径
type: string
example: "/mms/123.jpg"
maxLength: 500
media_path:
description: 服务器存储路径
type: string
example: "/storage/media/123.jpg"
maxLength: 512
media_type:
description: 媒体类型
type: string
example: "IMAGE"
maxLength: 50
media_usage:
description: 使用场景
type: string
example: "上报"
maxLength: 100
media_server_name:
description: 媒体服务器名称
type: string
example: "media-server-01"
maxLength: 100
media_property:
description: 媒体属性
type: integer
example: 1
media_uploaded_name:
description: 上传时的原始文件名
type: string
example: "IMG_20240501.jpg"
maxLength: 255
media_shot:
description: 截图标识或路径
type: string
example: "/shots/123.jpg"
maxLength: 255
media_label_type_id:
description: 标签类型ID
type: integer
example: 101
media_default_url:
description: 外部可访问URL
type: string
example: "https://external/media/123.jpg"
maxLength: 512
display_order:
description: 显示顺序
type: integer
example: 1
store_type_id:
description: 存储类型ID
type: integer
example: 1
special_item_image_type:
description: 特殊图片类型
type: string
example: "SIGNATURE"
maxLength: 100
height:
description: 图片高度
type: integer
example: 1080
width:
description: 图片宽度
type: integer
example: 1920
send_flag:
description: 发送标志
type: integer
example: 1
gen_thumb:
description: 是否生成缩略图
type: integer
example: 1
can_delete:
description: 是否可删除
type: integer
example: 1
delete_flag:
description: 删除标记
type: integer
example: 0
delete_reason:
description: 删除原因
type: string
example: "数据重复"
maxLength: 65535
pos_type:
description: 位置类型
type: string
example: "GPS"
maxLength: 50
view_angle:
description: 视角
type: string
example: "FRONT"
maxLength: 100
view_image_name:
description: 视图图片名称
type: string
example: "view_123.jpg"
maxLength: 200
view_image_x:
description: 视图图片X坐标
type: number
format: decimal
example: 0.5
view_image_y:
description: 视图图片Y坐标
type: number
format: decimal
example: 0.5
view_pos_x:
description: 视图位置X坐标
type: number
format: decimal
example: 0.5
view_pos_y:
description: 视图位置Y坐标
type: number
format: decimal
example: 0.5
attach_rec_flag:
description: 附件记录标识
type: string
example: "ATTACH"
maxLength: 50
gather_flag:
description: 汇总标识
type: string
example: "GATHERED"
maxLength: 50
link_field_value:
description: 关联字段值
type: string
example: "LINK-123"
maxLength: 500
link_field_display_value:
description: 关联字段显示值
type: string
example: "关联值显示"
maxLength: 500
unique_id:
description: 唯一标识
type: string
example: "UNIQ-20240501-001"
maxLength: 100
third_unique_id:
description: 第三方唯一标识
type: string
example: "THIRD-2024-001"
maxLength: 100
equal_group_id:
description: 等值组ID
type: integer
example: 1001
rec_category_id:
description: 记录类别ID
type: integer
example: 101
dispatch_opinion:
description: 派遣意见
type: string
example: "请尽快处理"
maxLength: 500
revise_opinion:
description: 修订意见
type: string
example: "建议补充图片"
maxLength: 500
reply_opinion:
description: 回复意见
type: string
example: "已处理完毕"
maxLength: 500
new_inst_advise:
description: 立案建议
type: string
example: "建议立案处理"
maxLength: 500
new_inst_cond_id:
description: 立案条件ID
type: integer
example: 101
new_inst_cond_name:
description: 立案条件
type: string
example: "破损面积大于0.5㎡"
maxLength: 200
case_closure_condition:
description: 结案条件
type: string
example: "修复完成并验收"
maxLength: 200
event_marks:
description: 事件标记
type: string
example: "HIGH_PRIORITY"
maxLength: 500
deduction:
description: 扣减
type: string
example: "扣2分"
maxLength: 100
event_property_id:
description: 事件属性ID
type: integer
example: 101
event_property_name:
description: 事件属性名称
type: string
example: "公共设施"
maxLength: 200
city_village_flag:
description: 城乡标识
type: string
example: "CITY"
maxLength: 50
force_handle_flag:
description: 强制处理标识
type: string
example: "FORCE"
maxLength: 50
auto_check_count:
description: 自动核查次数
type: integer
example: 2
deal_evaluate_ids:
description: 处置评价ID列表
type: string
example: "101,102,103"
maxLength: 200
newinst_no_transit:
description: 立案不转交
type: string
example: "NO_TRANSIT"
maxLength: 50
super_rec_id:
description: 上级记录ID
type: integer
example: 2001
site_num:
description: 站点编号
type: string
example: "SITE-001"
maxLength: 50
difficult_type_id:
description: 困难类型ID
type: integer
example: 101
event_district_grade_id:
description: 事件区域等级ID
type: integer
example: 101
event_district_grade_name:
description: 事件区域等级名称
type: string
example: "重点区域"
maxLength: 100
cus_grid_code:
description: 自定义网格编码
type: string
example: "CUST-GRID-001"
maxLength: 100
site_id:
description: 站点ID
type: integer
example: 101
shop_id:
description: 商铺ID
type: integer
example: 101
shop_name:
description: 商铺名称
type: string
example: "幸福便利店"
maxLength: 200
spec_type_id:
description: 特殊类型ID
type: integer
example: 101
spec_type_name:
description: 特殊类型名称
type: string
example: "紧急事件"
maxLength: 100
proc_account_state_id:
description: 处理账户状态ID
type: integer
example: 1
check_type_id:
description: 核查类型ID
type: integer
example: 1
rec_analysis_type_id:
description: 记录分析类型ID
type: integer
example: 1
proc_time_state_id:
description: 处理流程状态ID
type: integer
example: 1
proc_ard_state_id:
description: 处理仲裁状态ID
type: integer
example: 1
proc_enq_state_id:
description: 处理询问状态ID
type: integer
example: 1
proc_sup_state_id:
description: 处理监督状态ID
type: integer
example: 1
func_time_state_id:
description: 职能部门时间状态ID
type: integer
example: 1
check_msg_state_id:
description: 核查消息状态ID
type: integer
example: 1
verify_msg_state_id:
description: 核实消息状态ID
type: integer
example: 1
regather_msg_state_id:
description: 重新采集消息状态ID
type: integer
example: 1
supervision_check_state_id:
description: 监督核查状态ID
type: integer
example: 1
self_deal_msg_state_id:
description: 自行处置消息状态ID
type: integer
example: 1
review_msg_state_id:
description: 复核消息状态ID
type: integer
example: 1
proc_press_state_id:
description: 处理压力状态ID
type: integer
example: 1
hot_area:
description: 热点区域
type: string
example: "市中心"
maxLength: 100
cg_area:
description: 城管区域
type: string
example: "鼓楼区"
maxLength: 100
hw_area:
description: 环卫区域
type: string
example: "鼓楼区"
maxLength: 100
sz_area:
description: 市政区域
type: string
example: "鼓楼区"
maxLength: 100
device_guid:
description: 设备GUID
type: string
example: "A1B2-C3D4-E5F6"
maxLength: 100
jx_id:
description: 警讯ID
type: integer
example: 1001
jx_jxmc:
description: 警讯名称
type: string
example: "道路塌陷警讯"
maxLength: 200
jx_design_type:
description: 警讯设计类型
type: string
example: "自动触发"
maxLength: 100
report_time_segment_id:
description: 上报时段ID
type: integer
example: 101
archive_cond_id:
description: 归档条件ID
type: integer
example: 101
archive_cond:
description: 归档条件
type: string
example: "处理完成"
maxLength: 100
archive_type_id:
description: 归档类型ID
type: integer
example: 101
road_type_id:
description: 道路类型ID
type: integer
example: 101
road_name:
description: 道路名称
type: string
example: "中山路"
maxLength: 200
road_id:
description: 道路ID
type: integer
example: 101
road_type_name:
description: 道路类型名称
type: string
example: "主干道"
maxLength: 100
area_type_id:
description: 区域类型ID
type: integer
example: 101
duty_grid_type_id:
description: 责任网格类型ID
type: integer
example: 101
deal_duty_grid_type_id:
description: 处置责任网格类型ID
type: integer
example: 101
time_area_id:
description: 时段ID
type: integer
example: 101
time_area_name:
description: 时段名称
type: string
example: "早高峰"
maxLength: 100
card_num:
description: 证件号码
type: string
example: "110101199001012345"
maxLength: 100
cell_id:
description: 单元格ID
type: integer
example: 101
cell_name:
description: 单元格名称
type: string
example: "A01单元"
maxLength: 200
damage_grade_id:
description: 损毁等级ID
type: integer
example: 101
damage_grade_name:
description: 损毁等级名称
type: string
example: "严重"
maxLength: 100
event_grade_id:
description: 事件等级ID
type: integer
example: 101
event_grade_name:
description: 事件等级名称
type: string
example: "重大"
maxLength: 100
event_level_id:
description: 事件级别ID
type: integer
example: 101
event_level_name:
description: 事件级别名称
type: string
example: "一级"
maxLength: 100
event_district_id:
description: 事件区域ID
type: integer
example: 101
event_district_name:
description: 事件区域名称
type: string
example: "鼓楼区"
maxLength: 100
display_property:
description: 显示属性
type: string
example: "高亮显示"
maxLength: 200
display_style_id:
description: 显示样式ID
type: integer
example: 1
refresh_flag:
description: 刷新标识
type: integer
example: 1
video_device_id:
description: 视频设备ID
type: integer
example: 101
video_param:
description: 视频参数
type: string
example: "1080p,30fps"
maxLength: 500
patrol_deal_flag:
description: 巡查处置标识
type: integer
example: 1
send_from_type:
description: 发送来源类型
type: string
example: "APP"
maxLength: 50
reply_intime_deadline:
description: 两小时回复截止时间戳
type: integer
example: 1714568000000
accept_status:
description: 受理状态
type: string
example: "ACCEPTED"
maxLength: 50
squadron_id:
description: 中队ID
type: integer
example: 101
squadron_name:
description: 中队名称
type: string
example: "第一中队"
maxLength: 200
property_company_id:
description: 物业公司ID
type: integer
example: 101
act_record_id:
description: 操作记录ID
type: integer
example: 1001
main_rec_id:
description: 主记录ID
type: integer
example: 2001
func_custom_limit:
description: 职能部门自定义时限
type: string
example: "72小时"
maxLength: 50
created_at:
description: 创建时间,ISO格式的日期时间字符串
type: string
format: date-time
example: "2024-01-15 10:30:00"
readOnly: true
created_by:
description: 创建者用户名
type: string
example: "admin"
readOnly: true
updated_at:
description: 修改时间,ISO格式的日期时间字符串
type: string
format: date-time
example: "2024-01-16 14:25:00"
readOnly: true
updated_by:
description: 修改者用户名
type: string
example: "editor"
readOnly: true
"""
@classmethod
async def create(cls, **kwargs):
"""
创建新的任务表单数据。
业务流程:
1. 使用 HumanTaskFormDatumForm 验证表单数据完整性
2. 检查任务是否已存在(根据 rec_id)
3. 创建新任务对象
4. 设置创建者和更新者为当前用户
5. 保存到数据库
6. 返回创建的任务对象
:param kwargs: 任务参数字典
:return: 新建任务对象
:rtype: DcmTaskFormDatum
:raises AssertionError: 当任务已存在时抛出
:raises ValidationError: 当表单验证失败时抛出
"""
# 处理字符串字段去除空格
for _k, _v in kwargs.items():
if isinstance(_v, str):
kwargs[_k] = _v.strip()
_task_form = DcmTaskFormDatumForm(formdata=kwargs)
_task_form.validate_form()
# 检查是否存在同记录ID的任务
_task: cls = await cls.is_exist(_task_form.rec_id.data)
assert _task is None, "记录ID已存在,不能重复创建。"
# 创建任务对象
_task = cls().copy_from_dict(_task_form.data, skip_none=True).before_save()
await _task.async_save()
return _task
@classmethod
async def delete(cls, task_id: Union[str, int]):
"""
删除任务表单数据。
业务流程:
1. 根据ID查找任务
2. 验证任务存在性
3. 执行删除操作
:param task_id: 要删除的任务ID
:return: 删除的任务对象
:rtype: DcmTaskFormDatum
:raises AssertionError: 当任务不存在时抛出
"""
_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)
_del_count = (await cls.raw_execute(_del_query)).rowcount
echo_log(f'已删除任务表单数据(记录ID{_task.rec_id}ID{_task.id}.')
return _task
@classmethod
async def modify(cls, task_id: Union[str, int], **kwargs):
"""
修改已有任务表单数据。
业务流程:
1. 将 task_id 添加到参数中
2. 处理字符串字段去除首尾空格
3. 使用 HumanTaskFormDatumForm 验证表单数据
4. 检查是否有其他任务使用了相同的 rec_id
5. 查询原任务对象
6. 验证任务存在性
7. 更新字段并设置更新者
8. 保存到数据库
9. 返回更新后的任务对象
:param task_id: 要修改的任务ID
:param kwargs: 需要更新的字段
:return: 修改后的任务对象
:rtype: DcmTaskFormDatum
:raises AssertionError: 当任务不存在或信息重复时抛出
:raises ValidationError: 当表单验证失败时抛出
"""
# 处理字符串字段去除空格
for _k, _v in kwargs.items():
if isinstance(_v, str):
kwargs[_k] = _v.strip()
# 表单验证
_task_form = DcmTaskFormDatumForm(formdata=kwargs)
_task_form.validate_form()
# 检查是否与其他任务重复(排除自身)
_other = await cls.exist_other(task_id, _task_form.rec_id.data)
assert _other is None, "记录ID已存在,不能重复修改。"
# 查询原任务
_task: cls = await cls.async_find_by_id(task_id)
assert _task, f'查无此任务信息。'
# 更新字段
_task.copy_from_dict(_task_form.data, skip_none=True).before_save()
await _task.async_save()
return _task
@classmethod
async def create_batch(cls, data_df: pd.DataFrame):
"""
批量创建新任务表单数据(传入数据应为全新记录,无需校验是否存在)。
:param data_df: 包含任务数据的 DataFrame,字段需与模型属性匹配(如 rec_id, task_num 等)
:return: 成功创建的任务数量
:rtype: int
"""
if data_df.empty:
return 0
# 一次性转为字典列表(C 层高效)
records = data_df.to_dict('records')
# 用列表推导式构造对象
tasks = [cls().copy_from_dict(record, skip_none=True).before_save() 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):
"""
批量修改已有任务表单数据。
:param data_df: 包含任务数据的 DataFrame
:return: 成功更新的任务数量
:rtype: int
"""
if data_df.empty:
return 0
# 必须包含 id 列
if 'id' not in data_df.columns:
echo_log(f"错误:modify_batch 要求输入数据必须包含 '{cls.id.key}' 列(主键)")
return 0
# 转换为字典列表
update_data = data_df.to_dict('records')
# 使用 bulk_update_mappings
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):
"""
批量保存数据,自动处理新建和更新。
:param data_df: 要保存的数据框架
:return: 新建和更新的数量
"""
# 筛选数据状态
_exists_df, _latest_df = await DcmTaskFormDatum.exists_rec_id(data_df)
# 保存到数据库
_created_count = await DcmTaskFormDatum.create_batch(_latest_df)
_updated_count = await DcmTaskFormDatum.modify_batch(_exists_df)
return _created_count, _updated_count