Commit 4079af86 authored by 张晓彤's avatar 张晓彤

1.dispatcher.py 拆分-> schedule.py 2. 数据库部分字段修正 3. 解决循环调用问题 4. DispatchInfo 全局数据更新…

1.dispatcher.py 拆分-> schedule.py 2. 数据库部分字段修正 3. 解决循环调用问题 4. DispatchInfo 全局数据更新 in realtime_dispatch.py
parent dc367fbe
...@@ -8,13 +8,8 @@ ...@@ -8,13 +8,8 @@
from para_config import * from para_config import *
from equipment import ExcavatorInfo, DumpInfo, TruckInfo from equipment import ExcavatorInfo, DumpInfo, TruckInfo
from core.group import Group # from core.group import Group
from core.dispatcher import PreSchedule from core.schedule import PreSchedule
dump = DumpInfo()
excavator = ExcavatorInfo()
truck = TruckInfo(dump, excavator)
pre_sch = PreSchedule(truck, excavator, dump)
class AlgorithmBase: class AlgorithmBase:
...@@ -37,7 +32,7 @@ class Congestion(AlgorithmBase): ...@@ -37,7 +32,7 @@ class Congestion(AlgorithmBase):
class for congestion alg. class for congestion alg.
""" """
def __init__(self, group: Group): def __init__(self, group):
super().__init__() super().__init__()
self.group = group self.group = group
self.logger = get_logger("zxt.algorithm.congestion") self.logger = get_logger("zxt.algorithm.congestion")
...@@ -135,7 +130,7 @@ class ExpectedTime(AlgorithmBase): ...@@ -135,7 +130,7 @@ class ExpectedTime(AlgorithmBase):
class for expected traveling time alg. class for expected traveling time alg.
""" """
def __init__(self, group: Group): def __init__(self, group):
super().__init__() super().__init__()
self.group = group self.group = group
......
This diff is collapsed.
...@@ -6,25 +6,38 @@ ...@@ -6,25 +6,38 @@
# @File : group.py # @File : group.py
# @Software: PyCharm # @Software: PyCharm
#!E:\Pycharm Projects\Waytous
# -*- coding: utf-8 -*-
# @Time : 2022/5/30 15:35
# @Author : Opfer
# @Site :
# @File : group.py
# @Software: PyCharm
from data.dispatchInfo import DispatchInfo from data.dispatchInfo import DispatchInfo
from bidict import bidict from bidict import bidict
from alg.algorithm import AlgorithmBase, Congestion from alg.algorithm import AlgorithmBase
class Group: class Group:
""" """
class for group instance. class for group instance.
""" """
def __init__(self, group_id, truck, dump, excavator): def __init__(self, group_id, truck):
""" Generate a group obj. """ Generate a group obj.
:param group_id: (uuid) group_id :param group_id: (uuid) group_id
""" """
self.to_dump_congestion = None
self.group_id = group_id self.group_id = group_id
self.group_mode = 1
self.truck = truck
# group devices # group devices
self.excavator_dict = {} # excavator_id -> load_area_id self.excavator_dict = {} # excavator_id -> unload_area_id
self.dump_dict = {} # dump_id -> unload_area_id self.dump_dict = {} # dump_id -> load_area_id
self.truck_set = set() # truck_id self.truck_set = set() # truck_id
# road network info. # road network info.
...@@ -32,61 +45,157 @@ class Group: ...@@ -32,61 +45,157 @@ class Group:
self.to_dump_distance = None self.to_dump_distance = None
self.park_to_excavator_distance = None self.park_to_excavator_distance = None
self.to_excavator_congestion = None # self.to_excavator_congestion = None
self.to_dump_congestion = None # self.to_dump_congestion = None
self.park_to_excavator_congestion = None # self.park_to_excavator_congestion = None
# device map # device map
self.truck_uuid_index_dict = bidict() self.truck_uuid_index_dict = bidict()
self.excavator_uuid_index_dict = bidict() self.excavator_uuid_index_dict = bidict()
self.dump_uuid_index_dict = bidict() self.dump_uuid_index_dict = bidict()
# device obj.
self.truck = truck
self.dump =dump
self.excavator = excavator
def update_xx_(self): def update_group_mode(self):
""" """
update above parameters. update group mode.
:param group_mode:
:return: :return:
""" """
pass # DispatchInfo.update_group_mode()
self.group_mode = DispatchInfo.get_group_mode(self.group_id)
def update_device_map(self): def update_group_device(self):
""" """
update above parameters. update group devices.
:return: :return:
""" """
self.truck_uuid_index_dict = DispatchInfo.dump_group_dict # update group devices
pass # DispatchInfo.update_device_group_structure()
self.excavator_dict = DispatchInfo.get_excavator_dict(self.group_id)
self.dump_dict = DispatchInfo.get_dump_dict(self.group_id)
self.truck_set = DispatchInfo.get_truck_set(self.group_id)
def update_road_network_info(self, para): def update_group_road_network(self):
""" """
update group road network.
:return: :return:
""" """
pass # update group road network
return # DispatchInfo.update_route_distance()
self.to_excavator_distance = DispatchInfo.get_to_excavator_distance(self.group_id)
self.to_dump_distance = DispatchInfo.get_to_dump_distance(self.group_id)
self.park_to_excavator_distance = DispatchInfo.get_park_to_excavator_distance(self.group_id)
def group_dispatch(self, solver): def update_group_device_map(self):
""" """
Receive a alg obj. and output dispatch plan for trucks in this group. update group device map.
:param solver:
:return: :return:
dispatch plan: Dict({truck_id: match_id})
""" """
assert isinstance(solver, AlgorithmBase) # update device map
s = solver(self) # algorithm init excavator_index = 0
for truck_id in self.truck_set: for i in self.excavator_dict.keys():
value = s.solve(truck_id) # algorithm solve self.excavator_uuid_index_dict[i] = excavator_index + 1
return value dump_index = 0
for i in self.dump_dict.keys():
self.dump_uuid_index_dict[i] = dump_index + 1
def target_2_match_id(self, target): truck_index = 0
pass for i in self.truck_set:
self.truck_uuid_index_dict[i] = truck_index + 1
self.truck_uuid_index_dict = bidict(self.truck_uuid_index_dict)
self.excavator_uuid_index_dict = bidict(self.excavator_uuid_index_dict)
self.dump_uuid_index_dict = bidict(self.dump_uuid_index_dict)
group = Group("group123") # group_excavator_dict = {group_1: {excavator_1: load_area_1}, group_2: {excavator_2: load_area_2}}
group.group_dispatch(Congestion) def group_dispatch(self, solver: object):
"""
Receive a alg obj. and output dispatch plan for trucks in this group.
:param solver:
:return:
dispatch plan: Dict({truck_id: match_id})
"""
truck_dispatch = {}
assert issubclass(solver, AlgorithmBase)
s = solver(self) # algorithm init
# update truck task type
for i in self.truck_set:
truck_trip = self.truck.get_truck_current_trip(i)
truck_task = self.truck.get_truck_current_task(i)
if truck_task in [-2, 3, 4]:
next_excavator_list = s.solve(i)
min_index = next_excavator_list.index(min(next_excavator_list)) + 1
next_excavator_id = self.excavator_uuid_index_dict.inverse[min_index]
next_dump_id = truck_trip[-1]
truck_dispatch[i] = [next_excavator_id, next_dump_id]
if truck_task in [0, 1]:
next_dump_list = s.solve(i)
min_index = next_dump_list.index(min(next_dump_list)) + 1
next_dump_id = self.dump_uuid_index_dict.inverse[min_index]
next_excavator_id = truck_trip[-1]
truck_dispatch[i] = [next_excavator_id, next_dump_id]
# return dispatch plan
return truck_dispatch
# from data.dispatchInfo import DispatchInfo
# from bidict import bidict
# from alg.algorithm import AlgorithmBase
#
#
# class Group_0:
# """
# class for group instance.
# """
# def __init__(self, group_id):
# """ Generate a group obj.
# :param group_id: (uuid) group_id
# """
#
# self.group_id = group_id
#
# # group devices
# self.excavator_dict = {} # excavator_id -> unload_area_id
# self.dump_dict = {} # dump_id -> load_area_id
# self.truck_set = set() # truck_id
#
# # road network info.
# self.to_excavator_distance = None
# self.to_dump_distance = None
# self.park_to_excavator_distance = None
#
# self.to_excavator_congestion = None
# self.to_dump_congestion = None
# self.park_to_excavator_congestion = None
#
# # device map
# self.truck_uuid_index_dict = bidict()
# self.excavator_uuid_index_dict = bidict()
# self.dump_uuid_index_dict = bidict()
#
# def update_xx_(self):
# """
# update above parameters.
# :return:
# """
# pass
#
# def group_dispatch(self, solver):
# """
# Receive a alg obj. and output dispatch plan for trucks in this group.
# :param solver:
# :return:
# dispatch plan: Dict({truck_id: match_id})
# """
# assert isinstance(solver, AlgorithmBase)
# s = solver(self) # algorithm init
# return s.solve() # algorithm solve
This diff is collapsed.
...@@ -128,8 +128,8 @@ class DispatchInfo: ...@@ -128,8 +128,8 @@ class DispatchInfo:
""" """
try: try:
for value in session_postgre.query(DiggingWorkArea).all(): for value in session_postgre.query(DiggingWorkArea).all():
cls.load_exactor_dict[value.Id] = value.Exactorld cls.load_exactor_dict[value.Id] = value.ExactorId
cls.exactor_load_dict[value.Exactorld] = value.Id cls.exactor_load_dict[value.ExactorId] = value.Id
except Exception as es: except Exception as es:
logger.error("初始化数据更新异常") logger.error("初始化数据更新异常")
logger.error(es) logger.error(es)
...@@ -148,9 +148,11 @@ class DispatchInfo: ...@@ -148,9 +148,11 @@ class DispatchInfo:
for item in session_postgre.query(WalkTime).all(): for item in session_postgre.query(WalkTime).all():
temp = str(item.load_area_id), str(item.unload_area_id), item.to_load_distance, item.to_unload_distance temp = str(item.load_area_id), str(item.unload_area_id), item.to_load_distance, item.to_unload_distance
df = pd.concat([df, pd.DataFrame([temp])], axis=0, ignore_index=True) df = pd.concat([df, pd.DataFrame([temp])], axis=0, ignore_index=True)
for team_id in list(cls.group_dump_dict.keys()): for team_id in list(cls.group_dump_dict.keys()):
unload_nums = list(set(cls.group_dump_dict[team_id])) # 获取同一个team_id对应的卸载区列表 unload_nums = list(set(cls.group_dump_dict[team_id])) # 获取同一个team_id对应的卸载区列表
exactor_nums = list(set(cls.group_excavator_dict[team_id])) # 获取同一个team_id对应的电铲列表 exactor_nums = list(set(cls.group_excavator_dict[team_id])) # 获取同一个team_id对应的电铲列表
unload_exactor_matrix = np.zeros( unload_exactor_matrix = np.zeros(
(len(unload_nums), len(exactor_nums))) # 初始化距离矩阵,记录从卸载区-->>电铲的距离,即to_load_distance,空车模式 (len(unload_nums), len(exactor_nums))) # 初始化距离矩阵,记录从卸载区-->>电铲的距离,即to_load_distance,空车模式
load_exactor_matrix = np.array( load_exactor_matrix = np.array(
...@@ -170,3 +172,200 @@ class DispatchInfo: ...@@ -170,3 +172,200 @@ class DispatchInfo:
except Exception as es: except Exception as es:
logger.error("路网数据更新异常") logger.error("路网数据更新异常")
logger.error(es) logger.error(es)
@classmethod
def get_group_mode(cls, group_id):
return cls.group_mode[group_id]
@classmethod
def get_excavator_dict(cls, group_id):
return cls.group_excavator_dict[group_id]
@classmethod
def get_dump_dict(cls, group_id):
return cls.group_dump_dict[group_id]
@classmethod
def get_truck_set(cls, group_id):
return cls.group_truck_dict[group_id]
@classmethod
def get_to_excavator_distance(cls, group_id):
return cls.load_distance[group_id]
@classmethod
def get_to_dump_distance(cls, group_id):
return cls.unload_distance[group_id]
@classmethod
def get_park_to_excavator_distance(cls, group_id):
return cls.park_distance[group_id]
@classmethod
def get_park_to_excavator_distance(cls, group_id):
excavators = cls.group_excavator_dict[group_id]
park_matrix = np.zeros((1, len(excavators)))
for i in range(excavators):
load_area_id = cls.exactor_load_dict[excavators[i]]
distance = session_postgre.query(WalkTimePark).filter_by(load_area_id=load_area_id).first()
park_matrix[0][i] = distance
return park_matrix
# #!E:\Pycharm Projects\Waytous
# # -*- coding: utf-8 -*-
# # @Time : 2022/5/30 14:45
# # @Author : Opfer
# # @Site :
# # @File : dispatchInfo.py
# # @Software: PyCharm
# from settings import *
#
# logger = get_logger("mqc.dispatchInfo")
#
#
# class DispatchInfo:
# """
# class for dispatch group info.
# """
#
# # dispatch groups
# group_set = set()
#
# # device group structure
# group_dump_dict = {} # team_id -> dict {unload_area_id, unload_area_id, ...}
# # {group_id:unload_area_id,...}
# group_excavator_dict = {} # team_id -> dict {[excavator_id, load_area_id], ...}
# # {group_id: [excavator_id, unload_area_id], ...}
# group_truck_dict = {} # team_id -> dict {truck_id, ...}
# # {group_id:[truck_id,truck_id],...}
#
# dump_group_dict = {} # unload_area_id -> team_id
# excavator_group_dict = {} # excavator_id -> team_id
# truck_group_dict = {} # truck_id -> team_id
#
# # group feature
# group_mode = {} # 四种模式:全智能、空车智能、定铲定铲和分流配比模式
# # {mode_name:mode_code}
#
# # route_distance(路网距离)
# load_excavator_distance = {} # 装载区-挖机(电铲)的距离 数据格式 -->> {load_area_id:[excavator_uuid, to_load_distance],}
# unload_excavator_distance = {} # 卸载区-挖机(电铲)的距离 数据格式 -->> {unload_area_id:[excavator_uuid, to_unload_distance],}
#
# @classmethod
# def renew_set(cls):
# """
# @date:2022/6/2 19:50
# @author:maqc
# @desc:实例化对象,可直接访问
# """
# cls.group_dump_dict = {}
# cls.dump_group_dict = {}
#
# cls.group_excavator_dict = {}
# cls.excavator_group_dict = {}
#
# cls.group_truck_dict = {}
# cls.truck_group_dict = {}
#
# cls.group_mode = {}
# cls.load_excavator_distance = {}
# cls.unload_excavator_distance = {}
#
# @classmethod
# def update_device_group_structure(cls):
# """
# @date:2022/6/2 19:49
# @author:maqc
# @desc:分组与卸载区、挖机、矿卡的映射和反映射
# """
# logger = get_logger("mqc.update_device_group_structure")
# try:
# # group_dump_dict = {} -->> {group_id:unload_area_id,...}
# # dump_group_dict = {} # unload_area_id -> team_id
# group_code_dict = {} # group_code-->>team_id的映射
# for valve in session_mysql.query(DispatchMatch).filter_by(group_type=1).all():
# group_code_dict[valve.group_code] = valve.team_id
# if valve.team_id not in cls.group_dump_dict:
# cls.group_dump_dict[valve.team_id] = [valve.unload_area_id] # 注意:一个team_id可能对应多个unload_area_id
# else:
# cls.group_dump_dict[valve.team_id].append(valve.unload_area_id)
# cls.dump_group_dict[valve.unload_area_id] = valve.team_id # 一个unload_area_id只对应一个team_id
# # group_excavator_dict = {} -->> {group_id: [excavator_id, unload_area_id], ...} # 一个team_id对应一组excavator_id, unload_area_id
# # excavator_group_dict = {} -->> excavator_id -> team_id 一个excavator_id只对应一个team_id
# for item in session_mysql.query(DispatchMatch).filter_by(group_type=1).all():
# # cls.group_excavator_dict[item.team_id] = [item.exactor_id, item.unload_area_id]
# cls.group_excavator_dict[item.team_id] = item.exactor_id
# cls.excavator_group_dict[item.exactor_id] = item.team_id
# # group_truck_dict = {} -->> {group_id:[truck_id,truck_id],...}
# # truck_group_dict = {} -->> truck_id -> team_id
# for key in session_mysql.query(DispatchEquipment).filter_by(group_type=1).all():
# if key.group_code in group_code_dict:
# if key.group_code not in cls.group_truck_dict:
# cls.group_truck_dict[key.group_code] = [key.equipment_id]
# else:
# cls.group_truck_dict[key.group_code].append(key.equipment_id)
# cls.truck_group_dict[key.equipment_id] = group_code_dict[key.group_code]
# except Exception as es:
# logger.error("分组到卸载区的数据更新异常")
# logger.error(es)
#
# @classmethod
# def update_group_mode(cls):
# """
# @date:2022/6/2 19:49
# @author:maqc
# @desc:处理其它类型的数据
# """
# logger = get_logger("mqc.update_group_mode")
# try:
# for value in session_mysql.query(DispatchMode).all():
# cls.group_mode[value.mode_name] = value.mode_code
# except Exception as es:
# logger.error("派车模式数据更新异常")
# logger.error(es)
#
# @classmethod
# def dispatch_group_init(cls):
# """
# update basic paras (group_set, dict, num ...)
# :return:
# """
# pass
#
#
# @classmethod
# def get_group_road_info(cls,group_id, truck_info):
# if truck_info == 1:
# for i in group_excavator():
# pass
# for j in group_dump():
# pass
# if truck_info == 2:
# pass
# @classmethod
# # 距离-->>数据格式:矩阵-->>to_load_distance
# def update_route_distance(cls):
# """
# @date:2022/6/2 19:50
# @author:maqc
# @desc:更新路网距离,返回矩阵格式数据
# """
# load_exactor_dict = {} # 装载区id-->>电铲编号的映射
# logger = get_logger("mqc.update_route_distance")
# try:
# for value in session_postgre.query(DiggingWorkArea).all():
# load_exactor_dict[value.Id] = value.Exactorld
# for value in session_postgre.query(WalkTime).all():
# if value.load_area_id in load_exactor_dict:
# cls.load_excavator_distance[value.load_area_id] = [load_exactor_dict[value.load_area_id],
# value.to_load_distance]
# cls.unload_excavator_distance[value.unload_area_id] = [load_exactor_dict[value.load_area_id],
# value.to_unload_distance]
# except Exception as es:
# logger.error("路网数据更新异常")
# logger.error(es)
#
#
...@@ -14,7 +14,9 @@ from equipment.excavator import ExcavatorInfo ...@@ -14,7 +14,9 @@ from equipment.excavator import ExcavatorInfo
from equipment.dump import DumpInfo from equipment.dump import DumpInfo
import sched import sched
import time import time
from dispatcher import Dispatcher, PreSchedule from core.dispatcher import Dispatcher
from core.schedule import PreSchedule
from data.dispatchInfo import DispatchInfo
def process(dispatcher): def process(dispatcher):
...@@ -24,39 +26,52 @@ def process(dispatcher): ...@@ -24,39 +26,52 @@ def process(dispatcher):
:return: None :return: None
""" """
try: # try:
# 更新周期参数 # 更新周期参数
logger.info("#####################################周期更新开始#####################################") logger.info("#####################################周期更新开始#####################################")
global_period_para_update() global_period_para_update()
if get_value("dynamic_dump_num") * get_value("dynamic_excavator_num") == 0:
raise Exception("无动态派车计划可用")
return
if get_value("dynamic_truck_num") == 0:
raise Exception("无动态派车可用矿卡")
return
# 清空数据库缓存
session_mysql.commit()
session_mysql.flush()
# 清空数据库缓存
session_postgre.commit()
session_postgre.flush()
global_period_para_update()
# 更新数据
DispatchInfo.renew_set()
if get_value("dynamic_dump_num") * get_value("dynamic_excavator_num") == 0: DispatchInfo.dispatch_group_init()
raise Exception("无动态派车计划可用")
return
if get_value("dynamic_truck_num") == 0:
raise Exception("无动态派车可用矿卡")
return
# 清空数据库缓存 DispatchInfo.update_device_group_structure()
session_mysql.commit()
session_mysql.flush()
# 清空数据库缓存 DispatchInfo.update_route_distance()
session_postgre.commit()
session_postgre.flush()
# 周期更新 DispatchInfo.update_group_mode()
dispatcher.dispatcher_period_update()
# 调度计算 # 调度生成
dispatcher.schedule_construct() dispatcher.period_update()
dispatcher.group_generate()
logger.info("#####################################周期更新结束#####################################") dispatcher.group_dispatch()
except Exception as es: # logger.info("#####################################周期更新结束#####################################")
logger.error("最外层异常捕获") #
logger.error(es) # except Exception as es:
# logger.error("最外层异常捕获")
# logger.error(es)
def perform(inc, dispatcher): def perform(inc, dispatcher):
...@@ -103,7 +118,7 @@ if __name__ == "__main__": ...@@ -103,7 +118,7 @@ if __name__ == "__main__":
pre_sch = PreSchedule(truck, excavator, dump) pre_sch = PreSchedule(truck, excavator, dump)
# 实例化矿卡调度器 # 实例化矿卡调度器
dispatcher = Dispatcher(dump, excavator, truck, pre_sch, False) dispatcher = Dispatcher(truck, dump, excavator, pre_sch, False)
logger.info(" ") logger.info(" ")
logger.info("调度系统启动") logger.info("调度系统启动")
......
...@@ -60,15 +60,15 @@ def set_log(): ...@@ -60,15 +60,15 @@ def set_log():
# 创建日志目录 # 创建日志目录
if not os.path.exists(log_path): # if not os.path.exists(log_path):
os.mkdir(log_path) # os.mkdir(log_path)
# logging初始化工作 # logging初始化工作
logging.basicConfig() logging.basicConfig()
# timefilehandler = logging.handlers.TimedRotatingFileHandler(log_path + "/dispatch.log", when='M', interval=1, backupCount=60) # timefilehandler = logging.handlers.TimedRotatingFileHandler(log_path + "/dispatch.log", when='M', interval=1, backupCount=60)
filehandler = logging.handlers.RotatingFileHandler(log_path + "/dispatch.log", maxBytes=3*1024*1024, backupCount=10, encoding="utf-8") # filehandler = logging.handlers.RotatingFileHandler(log_path + "/dispatch.log", maxBytes=3*1024*1024, backupCount=10, encoding="utf-8")
# filehandler = logging.handlers.RotatingFileHandler("./Logs/dispatch.log", maxBytes=3 * 1024 * 1024, backupCount=10, encoding="utf-8") filehandler = logging.handlers.RotatingFileHandler("./Logs/dispatch.log", maxBytes=3 * 1024 * 1024, backupCount=10, encoding="utf-8")
# 设置后缀名称,跟strftime的格式一样 # 设置后缀名称,跟strftime的格式一样
filehandler.suffix = "%Y-%m-%d_%H-%M.log" filehandler.suffix = "%Y-%m-%d_%H-%M.log"
......
...@@ -472,16 +472,16 @@ class DumpArea(Base): ...@@ -472,16 +472,16 @@ class DumpArea(Base):
Disabled = Column(Integer) Disabled = Column(Integer)
Materials = Column(VARCHAR(36)) Materials = Column(VARCHAR(36))
Priority = Column(Integer) Priority = Column(Integer)
DumpEquipmentld = Column(VARCHAR(36)) DumpEquipmentId = Column(VARCHAR(36))
def __init__(self, Id, BindList, UnloadAbililty, Disabled, Materials, Priority, DumpEquipmentld): def __init__(self, Id, BindList, UnloadAbililty, Disabled, Materials, Priority, DumpEquipmentId):
self.Id = Id self.Id = Id
self.BindList = BindList self.BindList = BindList
self.UnloadAbililty = UnloadAbililty self.UnloadAbililty = UnloadAbililty
self.Disabled = Disabled self.Disabled = Disabled
self.Materials = Materials self.Materials = Materials
self.Priority = Priority self.Priority = Priority
self.DumpEquipmentld = DumpEquipmentld self.DumpEquipmentId = DumpEquipmentId
class DiggingWorkArea(Base): class DiggingWorkArea(Base):
...@@ -489,12 +489,12 @@ class DiggingWorkArea(Base): ...@@ -489,12 +489,12 @@ class DiggingWorkArea(Base):
Id = Column(VARCHAR(50), primary_key=True) Id = Column(VARCHAR(50), primary_key=True)
Material = Column(VARCHAR(36)) Material = Column(VARCHAR(36))
Exactorld = Column(VARCHAR(36)) ExactorId = Column(VARCHAR(36))
def __init__(self, Id, Material, Exactorld): def __init__(self, Id, Material, ExactorId):
self.Id = Id self.Id = Id
self.Material = Material self.Material = Material
self.Exactorld = Exactorld self.ExactorId = ExactorId
class DispatchRule(Base): class DispatchRule(Base):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment