Merge branch 'main' of https://gitea.yuxindazhineng.com/admin/railway_cloud
This commit is contained in:
@@ -9,7 +9,12 @@ from ..schemas.account import (
|
||||
AccountApiResponse, AccountListResponse,AccountGetRequestYH
|
||||
)
|
||||
from ..services.account import AccountService
|
||||
|
||||
import json
|
||||
from typing import List, Optional
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib import request as urllib_request
|
||||
from urllib.parse import urlencode
|
||||
from socket import timeout
|
||||
router = APIRouter(prefix="/accounts", tags=["账号管理"])
|
||||
|
||||
@router.post("/create", response_model=AccountApiResponse, status_code=status.HTTP_201_CREATED)
|
||||
@@ -112,6 +117,7 @@ def update_account(request: AccountUpdateRequest, db: Session = Depends(get_db))
|
||||
|
||||
@router.post("/delete", response_model=AccountApiResponse)
|
||||
def delete_account(request: AccountDeleteRequest, db: Session = Depends(get_db)):
|
||||
|
||||
"""删除账号"""
|
||||
if not AccountService.delete_account(db, request.account_id):
|
||||
return AccountApiResponse(
|
||||
@@ -124,3 +130,101 @@ def delete_account(request: AccountDeleteRequest, db: Session = Depends(get_db))
|
||||
message="账号删除成功",
|
||||
data=None
|
||||
)
|
||||
# 获取今日上传的数据接口
|
||||
@router.post("/get_uplaod_data", response_model=AccountListResponse)
|
||||
def get_uplaod_data(request: AccountGetRequest, db: Session = Depends(get_db)):
|
||||
"""根据多种条件查询账号,并合并外部接口的 is_ok 字段(仅返回 today_data 中存在的账号)"""
|
||||
# 1. 从数据库查询账号列表(原有逻辑不变)
|
||||
accounts = AccountService.search_accounts(
|
||||
db,
|
||||
account_id=request.account_id,
|
||||
username=request.username,
|
||||
project_name=request.project_name,
|
||||
status=request.status,
|
||||
today_updated=request.today_updated,
|
||||
yh_id=request.yh_id,
|
||||
cl_name=request.cl_name
|
||||
)
|
||||
|
||||
# 2. 调用外部接口构建 user_is_ok_map(替换为 urllib 实现,修复命名冲突和超时异常)
|
||||
user_is_ok_map = {}
|
||||
api_url = "https://engineering.yuxindazhineng.com/index/index/get_over_data"
|
||||
payload = {"user_id": "68c0dbfdb7cbcd616e7c5ab5"}
|
||||
|
||||
try:
|
||||
# 步骤1:将表单 payload 转为 URL 编码的字节流(urllib POST 要求数据为字节流)
|
||||
payload_bytes = urlencode(payload).encode("utf-8")
|
||||
|
||||
# 步骤2:构造 Request 对象(使用重命名后的 urllib_request,避免冲突)
|
||||
req = urllib_request.Request(
|
||||
url=api_url,
|
||||
data=payload_bytes,
|
||||
method="POST" # 显式指定 POST 方法
|
||||
)
|
||||
|
||||
# 步骤3:发送请求并读取响应(设置 10 秒超时,避免接口挂起)
|
||||
with urllib_request.urlopen(req, timeout=10) as resp:
|
||||
# 读取响应字节流并解码为 UTF-8 字符串
|
||||
response_str = resp.read().decode("utf-8")
|
||||
|
||||
# 步骤4:将 JSON 字符串解析为字典
|
||||
api_response = json.loads(response_str)
|
||||
|
||||
# 步骤5:验证接口返回格式并构建 user_is_ok_map 映射
|
||||
if api_response.get("code") == 0:
|
||||
today_data = api_response.get("data", []) # 给默认值,避免 KeyError
|
||||
for item in today_data:
|
||||
# 安全获取字段并校验类型
|
||||
if 'user_name' in item and 'is_ok' in item:
|
||||
user_is_ok_map[item['user_name']] = item['is_ok']
|
||||
|
||||
except HTTPError as e:
|
||||
# 捕获 HTTP 状态码错误(4xx/5xx)
|
||||
print(f"外部接口 HTTP 错误:{e.code} - {e.reason}")
|
||||
except TimeoutError: # 修复:正确的超时异常名称(首字母大写,原 timeout 会未定义报错)
|
||||
# 捕获请求超时异常
|
||||
print(f"外部接口调用超时(超过 10 秒)")
|
||||
except URLError as e:
|
||||
# 捕获 URL 解析错误、网络连接错误等
|
||||
print(f"外部接口网络错误:{e.reason}")
|
||||
except json.JSONDecodeError:
|
||||
# 捕获非合法 JSON 格式响应
|
||||
print(f"外部接口返回数据格式错误,非合法 JSON 字符串")
|
||||
except Exception as e:
|
||||
# 捕获其他未知异常
|
||||
print(f"外部接口处理未知异常:{str(e)}")
|
||||
|
||||
# 3. 关键修改:仅保留 today_data 中存在的账号(核心过滤逻辑)
|
||||
accounts_with_is_ok = []
|
||||
for account in accounts:
|
||||
# 步骤1:将 AccountResponse 对象转为字典(Pydantic 模型自带 dict() 方法)
|
||||
account_dict = account.dict()
|
||||
|
||||
# 步骤2:获取当前账号 username,判断是否在 user_is_ok_map 中(不存在则跳过)
|
||||
current_username = account_dict.get("username", "")
|
||||
if current_username not in user_is_ok_map:
|
||||
continue # 核心:过滤掉 today_data 中没有的账号
|
||||
|
||||
# 步骤3:给字典添加 is_ok 字段(仅处理存在的账号,无需默认值 0)
|
||||
account_dict['is_ok'] = user_is_ok_map[current_username]
|
||||
|
||||
# 步骤4:将处理后的字典加入新列表
|
||||
accounts_with_is_ok.append(account_dict)
|
||||
|
||||
# 4. 处理空结果返回(原有逻辑不变)
|
||||
if not accounts_with_is_ok:
|
||||
return AccountListResponse(
|
||||
code=ResponseCode.ACCOUNT_NOT_FOUND,
|
||||
message=ResponseMessage.ACCOUNT_NOT_FOUND,
|
||||
total=0,
|
||||
data=[]
|
||||
)
|
||||
|
||||
# 5. 正常返回:数据传入新列表 accounts_with_is_ok(仅包含 today_data 中的账号)
|
||||
# print(accounts_with_is_ok)
|
||||
return AccountListResponse(
|
||||
code=ResponseCode.SUCCESS,
|
||||
message="查询成功",
|
||||
total=len(accounts_with_is_ok),
|
||||
data=accounts_with_is_ok
|
||||
)
|
||||
|
||||
@@ -17,6 +17,10 @@ class Account(Base):
|
||||
max_variation = Column(Integer, default=1, comment="变化量的绝对值,单位是毫米")
|
||||
yh_id = Column(String(1000), comment="宇恒一号用户id")
|
||||
cl_name = Column(String(100), nullable=True, comment="测量人员")
|
||||
device_name = Column(String(1000), comment="设备名称")
|
||||
device_port = Column(String(1000), comment="设备端口")
|
||||
device_ip = Column(String(1000), comment="设备局域网内ip地址")
|
||||
is_ok = Column(Integer, default=0, comment="是否可以上传")
|
||||
|
||||
|
||||
# 模型转字典
|
||||
|
||||
@@ -12,6 +12,10 @@ class AccountBase(BaseModel):
|
||||
max_variation: Optional[int] = None
|
||||
yh_id: Optional[str] = None
|
||||
cl_name: Optional[str] = None
|
||||
device_name: Optional[str] = None
|
||||
device_port: Optional[str] = None
|
||||
device_ip: Optional[str] = None
|
||||
is_ok: Optional[int] = None
|
||||
|
||||
class AccountCreate(AccountBase):
|
||||
pass
|
||||
@@ -24,6 +28,10 @@ class AccountUpdate(BaseModel):
|
||||
project_name: Optional[str] = None
|
||||
update_time: Optional[str] = None
|
||||
cl_name: Optional[str] = None
|
||||
device_name: Optional[str] = None
|
||||
device_port: Optional[str] = None
|
||||
device_ip: Optional[str] = None
|
||||
is_ok: Optional[int] = None
|
||||
|
||||
class AccountResponse(AccountBase):
|
||||
account_id: int
|
||||
@@ -49,7 +57,11 @@ class AccountResponse(AccountBase):
|
||||
update_time=account.update_time,
|
||||
max_variation=account.max_variation,
|
||||
yh_id=account.yh_id,
|
||||
cl_name=account.cl_name
|
||||
cl_name=account.cl_name,
|
||||
device_name=account.device_name,
|
||||
device_port=account.device_port,
|
||||
device_ip=account.device_ip,
|
||||
is_ok = account.is_ok
|
||||
)
|
||||
|
||||
class AccountListRequest(BaseModel):
|
||||
@@ -90,4 +102,5 @@ class AccountListResponse(BaseModel):
|
||||
code: int = 0
|
||||
message: str
|
||||
total: int
|
||||
data: List[AccountResponse] = []
|
||||
data: List[AccountResponse] = []
|
||||
|
||||
|
||||
@@ -11,7 +11,12 @@ class ConstructionMonitorUtils:
|
||||
def __init__(self):
|
||||
# 原始工况周期映射表(保持不变)
|
||||
self.base_periods = {
|
||||
"路基或预压土填筑,连续填筑":1,
|
||||
"路基或预压土填筑,两次填筑间隔时间较长":7,
|
||||
"预压土或路基填筑完成,第1~3个月":7,
|
||||
"预压土或路基填筑完成,第4~6个月":14,
|
||||
"仰拱(底板)施工完成后,第1个月": 7,
|
||||
"预压土或路基填筑完成,6个月以后":30,
|
||||
"仰拱(底板)施工完成后,第2至3个月": 14,
|
||||
"仰拱(底板)施工完成后,3个月以后": 30,
|
||||
"仰拱(底板)施工完成后,第1个月": 7, # 原:仰拱(底板)施工完成后,第1个月
|
||||
@@ -27,7 +32,7 @@ class ConstructionMonitorUtils:
|
||||
"预制梁桥,预制梁架设后": 7, # 原:预制梁桥,预制梁架设后
|
||||
"桥位施工桥梁,制梁前": 30, # 原:桥位施工桥梁,制梁前
|
||||
"桥位施工桥梁,上部结构施工中": 1, # 原:桥位施工桥梁,上部结构施工中
|
||||
"架桥机(运梁车)通过": 7, # 无格式差异,保留原样
|
||||
# "架桥机(运梁车)通过": 7, # 无格式差异,保留原样
|
||||
"桥梁主体工程完工后,第1至3个月": 7, # 原:桥梁主体工程完工后,第1至3个月
|
||||
"桥梁主体工程完工后,第4至6个月": 14, # 原:桥梁主体工程完工后,第4至6个月
|
||||
"桥梁主体工程完工后,6个月以后": 30, # 原:桥梁主体工程完工后,6个月以后 ''
|
||||
@@ -50,7 +55,40 @@ class ConstructionMonitorUtils:
|
||||
"架桥机(运梁车) 首次通过后": 7, # 原:架桥机(运梁车)首次通过后(仅加空格)
|
||||
"轨道板(道床)铺设后,第1个月": 14, # 原:轨道板(道床)铺设后,第1个月
|
||||
"轨道板(道床)铺设后,第2至3个月": 30, # 原:轨道板(道床)铺设后,第2至3个月
|
||||
"轨道板(道床)铺设后,3个月以后": 90 # 未出现在待处理集,保留原始格式
|
||||
"轨道板(道床)铺设后,3个月以后": 90,
|
||||
"架桥机(运梁车)首次通过前": 1,
|
||||
"架桥机(运梁车)首次通过后,前3天": 1,
|
||||
"架桥机(运梁车)首次通过后": 7,
|
||||
"轨道板铺设前": 14,
|
||||
"轨道板(道床)铺设后,第1至3个月": 14,
|
||||
"轨道板(道床)铺设后,第4至6个月": 30,
|
||||
"轨道板(道床)铺设后,6个月以后": 90,
|
||||
"站场填方路基段填筑完成至静态验收": 14,
|
||||
"桥墩(台)地面处拆模后": 30,
|
||||
"敦身混凝土施工": 30,
|
||||
# "预制梁桥,架梁前": 30,
|
||||
# "预制梁桥,预制梁架设前": 1,
|
||||
"预制梁桥预制梁架设后": 7,
|
||||
"现浇梁,浇筑前": 30,
|
||||
"现浇梁上部结构施工中": 1,
|
||||
"架桥机(运梁车)通过": 2,
|
||||
"桥梁主体工程完工后,第1至3个月": 7,
|
||||
# "桥梁主体工程完工后,第4至6个月": 14,
|
||||
"侨梁主体工程完工后,6个月以后": 30,
|
||||
"轨道铺设,前": 30,
|
||||
"轨道铺设,后": 14,
|
||||
# "轨道铺设完成后,第1个月": 14,
|
||||
# "轨道铺设完成后,2至3个月": 30,
|
||||
# "轨道铺设完成后,4至12个月": 90,
|
||||
# "轨道铺设完成后,12个月以后": 180,
|
||||
# "仰拱(底板)施工完成后,第1个月": 7,
|
||||
# "仰拱(底板)施工完成后,第2至3个月": 14,
|
||||
# "仰拱(底板)施工完成后,3个月以后": 30,
|
||||
# "轨道板铺设前": 14,
|
||||
# "无砟轨道铺设后,第1至3个月": 30,
|
||||
# "无砟轨道铺设后,4至12个月": 90,
|
||||
# "无砟轨道铺设后,12个月以后": 180,
|
||||
"特殊地段隧道施工完成后至静态验收": 14
|
||||
}
|
||||
# 构建中英文括号+逗号兼容映射表
|
||||
self.compatible_periods = self._build_compatible_brackets_map()
|
||||
|
||||
@@ -7,145 +7,246 @@ class OperatingModePredictor:
|
||||
特性:
|
||||
1. 输入为二维列表,每个内嵌列表对应一个point_id,且为倒序排列(最新记录在索引0)
|
||||
2. 输出为一维列表,仅保留每个内嵌列表的最新记录,新增工况推导结果字段
|
||||
3. 无需切换工况时,next_workinfo返回当前工况名称;需要切换时返回目标工况名称
|
||||
3. 推导规则:有等效映射返回新工况,无等效保留旧工况;切换下一工况以base_periods为准
|
||||
4. 时间计算仅按日期(天)维度,忽略时分秒
|
||||
5. 冬休场景:仅以冬休前上一有效工况为判断基准,切换规则与非冬休完全一致
|
||||
6. 适配中英文括号、逗号、空格,内部标准化匹配,外部返回规范名称
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化类,加载内置的工况配置、分组规则和切换触发规则"""
|
||||
# 基础工况配置(键:工况名称,值:基础监测周期参考)
|
||||
"""初始化类,加载核心配置"""
|
||||
# 1. 基础工况配置(最终返回的规范名称,含所有新旧工况)
|
||||
self.base_periods = self._load_base_periods()
|
||||
# 工况分组(将同义不同格式的工况归类,共用切换规则)
|
||||
# 2. 旧→新等效映射(优先返回新工况)
|
||||
self.old_to_new_map = self._load_old_to_new_map()
|
||||
# 3. 工况分组(同义工况归为同一分组,复用切换规则)
|
||||
self.condition_group = self._load_condition_group()
|
||||
# 工况切换触发规则(键:分组ID,值:触发天数+目标工况候选)
|
||||
self.group_transition_rules = self._load_group_transition_rules()
|
||||
# 4. 切换触发规则(沿用原逻辑,触发天数+目标工况)
|
||||
self.transition_rules = self._load_transition_rules()
|
||||
# 5. 冬休标识
|
||||
self.winter_break_labels = {"冬休"}
|
||||
|
||||
# 辅助映射:标准化名称→base_periods中的规范名称(用于最终返回)
|
||||
self.std_to_canonical = {
|
||||
self._standardize_name(name): name for name in self.base_periods.keys()
|
||||
}
|
||||
# 辅助映射:标准化名称→分组ID
|
||||
self.std_to_group = {
|
||||
self._standardize_name(name): group_id
|
||||
for name, group_id in self.condition_group.items()
|
||||
}
|
||||
|
||||
def _standardize_name(self, name):
|
||||
"""
|
||||
标准化工况名称(内部匹配用):去空格、统一中英文符号
|
||||
:param name: 原始工况名称
|
||||
:return: 标准化后的名称
|
||||
"""
|
||||
if not name:
|
||||
return ""
|
||||
# 去所有空格
|
||||
std_name = name.replace(" ", "").strip()
|
||||
# 统一中英文符号
|
||||
replace_map = {
|
||||
"(": "(", ")": ")", ",": ",", "。": ",", "~": "至",
|
||||
";": ";", ":": ":", "'": "'", """: "\""
|
||||
}
|
||||
for old, new in replace_map.items():
|
||||
std_name = std_name.replace(old, new)
|
||||
return std_name
|
||||
|
||||
def _load_base_periods(self):
|
||||
"""加载基础工况配置(私有方法,内部使用)"""
|
||||
"""加载基础工况配置(最终返回的规范名称,无多余数字)"""
|
||||
return {
|
||||
"仰拱(底板)施工完成后,第1个月": 7,
|
||||
"仰拱(底板)施工完成后,第2至3个月": 14,
|
||||
"仰拱(底板)施工完成后,3个月以后": 30,
|
||||
# 路基工况(新工况优先)
|
||||
"路基或预压土填筑,连续填筑": 1,
|
||||
"路基或预压土填筑,两次填筑间隔时间较长": 7,
|
||||
"预压土或路基填筑完成,第1~3个月": 7,
|
||||
"预压土或路基填筑完成,第4~6个月": 14,
|
||||
"预压土或路基填筑完成,6个月以后": 30,
|
||||
"架桥机(运梁车)首次通过前": 1,
|
||||
"架桥机(运梁车)首次通过后,前3天": 1,
|
||||
"架桥机(运梁车)首次通过后": 7,
|
||||
"轨道板(道床)铺设后,第1至3个月": 14,
|
||||
"轨道板(道床)铺设后,第4至6个月": 30,
|
||||
"轨道板(道床)铺设后,6个月以后": 90,
|
||||
|
||||
# 路基旧工况(保留,无等效则返回)
|
||||
"填筑或堆载,一般情况": 1,
|
||||
"填筑或堆载,两次填筑间隔时间较长情况": 7,
|
||||
"堆载预压或路基填筑完成,6个月以后": 30,
|
||||
"轨道板(道床)铺设后,第1个月": 14,
|
||||
"轨道板(道床)铺设后,第2至3个月": 30,
|
||||
"轨道板(道床)铺设后,3个月以后": 90,
|
||||
|
||||
# 桥梁工况(新工况优先)
|
||||
"桥墩(台)地面处拆模后": 30,
|
||||
"敦身混凝土施工": 30,
|
||||
"预制梁桥,预制梁架设前": 1,
|
||||
"预制梁桥,预制梁架设后": 7,
|
||||
"现浇梁,浇筑前": 30,
|
||||
"现浇梁上部结构施工中": 1,
|
||||
"架桥机(运梁车)通过": 2,
|
||||
"桥梁主体工程完工后,第1至3个月": 7,
|
||||
"桥梁主体工程完工后,第4至6个月": 14,
|
||||
"桥梁主体工程完工后,6个月以后": 30,
|
||||
"轨道铺设,前": 30,
|
||||
"轨道铺设,后": 14,
|
||||
"轨道铺设完成后,第1个月": 14,
|
||||
"轨道铺设完成后,2至3个月": 30,
|
||||
"轨道铺设完成后,4至12个月": 90,
|
||||
"轨道铺设完成后,12个月以后": 180,
|
||||
|
||||
# 桥梁旧工况(保留,无等效则返回)
|
||||
"墩台施工到一定高度": 30,
|
||||
"墩台混凝土施工": 30,
|
||||
"预制梁桥,架梁前": 30,
|
||||
"桥位施工桥梁,制梁前": 30,
|
||||
"桥位施工桥梁,上部结构施工中": 1,
|
||||
"桥梁主体工程完工后,第1至3个月": 7,
|
||||
"轨道铺设期间,前": 30,
|
||||
"轨道铺设期间,后": 14,
|
||||
|
||||
# 隧道工况
|
||||
"仰拱(底板)施工完成后,第1个月": 7,
|
||||
"仰拱(底板)施工完成后,第2至3个月": 14,
|
||||
"仰拱(底板)施工完成后,3个月以后": 30,
|
||||
"无砟轨道铺设后,第1至3个月": 30,
|
||||
"无砟轨道铺设后,4至12个月": 90,
|
||||
"无砟轨道铺设后,12个月以后": 180,
|
||||
"墩台施工到一定高度": 30,
|
||||
"墩台混凝土施工": 30,
|
||||
"预制梁桥,架梁前": 30,
|
||||
"预制梁桥,预制梁架设前": 1,
|
||||
"预制梁桥,预制梁架设后": 7,
|
||||
"桥位施工桥梁,制梁前": 30,
|
||||
"桥位施工桥梁,上部结构施工中": 1,
|
||||
"架桥机(运梁车)通过": 7,
|
||||
"桥梁主体工程完工后,第1至3个月": 7,
|
||||
"桥梁主体工程完工后,第4至6个月": 14,
|
||||
"桥梁主体工程完工后,6个月以后": 30,
|
||||
"轨道铺设期间,前": 30,
|
||||
"轨道铺设期间,后": 14,
|
||||
"轨道铺设完成后,第1个月": 14,
|
||||
"轨道铺设完成后,2至3个月": 30,
|
||||
"轨道铺设完成后,4至12个月": 90,
|
||||
"轨道铺设完成后,12个月以后": 180,
|
||||
"铺路或堆载,一般情况": 1,
|
||||
"填筑或堆载,一般情况": 1,
|
||||
"铺路或堆载,沉降量突变情况": 1,
|
||||
"填筑或堆载,两次填筑间隔时间较长情况": 3,
|
||||
"铺路或堆载,两次铺路间隔时间较长情况": 3,
|
||||
"堆载预压或路基填筑完成,第1至3个月": 7,
|
||||
"堆载预压或路基填筑完成,第4至6个月": 14,
|
||||
"堆载预压或路基填筑完成,6个月以后": 30,
|
||||
"架桥机(运梁车) 首次通过前": 1,
|
||||
"架桥机(运梁车) 首次通过后,前3天": 1,
|
||||
"架桥机(运梁车) 首次通过后": 7,
|
||||
"轨道板(道床)铺设后,第1个月": 14,
|
||||
"轨道板(道床)铺设后,第2至3个月": 30,
|
||||
"轨道板(道床)铺设后,3个月以后": 90
|
||||
|
||||
# 特殊工况
|
||||
"冬休": 0
|
||||
}
|
||||
|
||||
def _load_old_to_new_map(self):
|
||||
"""加载旧→新等效映射(优先返回新工况)"""
|
||||
return {
|
||||
# 路基等效
|
||||
"填筑或堆载,一般情况": "路基或预压土填筑,连续填筑",
|
||||
"填筑或堆载,两次填筑间隔时间较长情况": "路基或预压土填筑,两次填筑间隔时间较长",
|
||||
"预压土或路基填筑完成。第1~3个月": "预压土或路基填筑完成,第1~3个月",
|
||||
"堆载预压或路基填筑完成,6个月以后": "预压土或路基填筑完成,6个月以后",
|
||||
"轨道板(道床)铺设后,第1个月": "轨道板(道床)铺设后,第1至3个月",
|
||||
"轨道板(道床)铺设后,第2至3个月": "轨道板(道床)铺设后,第4至6个月",
|
||||
"轨道板(道床)铺设后,3个月以后": "轨道板(道床)铺设后,6个月以后",
|
||||
|
||||
# 桥梁等效
|
||||
"墩台施工到一定高度": "桥墩(台)地面处拆模后",
|
||||
"墩台混凝土施工": "敦身混凝土施工",
|
||||
"桥位施工桥梁,制梁前": "现浇梁,浇筑前",
|
||||
"桥位施工桥梁,上部结构施工中": "现浇梁上部结构施工中",
|
||||
"桥梁主体工程完工后,第1至3个月": "桥梁主体工程完工后,第1至3个月",
|
||||
"轨道铺设期间,前": "轨道铺设,前",
|
||||
"轨道铺设期间,后": "轨道铺设,后"
|
||||
}
|
||||
|
||||
def _load_condition_group(self):
|
||||
"""加载工况分组规则(私有方法,内部使用)"""
|
||||
return {
|
||||
"仰拱(底板)施工完成后,第1个月": "YG_DIBAN_1",
|
||||
"仰拱(底板)施工完成后,第1个月": "YG_DIBAN_1",
|
||||
"仰拱(底板)施工完成后,第2至3个月": "YG_DIBAN_2_3",
|
||||
"仰拱(底板)施工完成后,第2至3个月": "YG_DIBAN_2_3",
|
||||
"仰拱(底板)施工完成后,3个月以后": "YG_DIBAN_AFTER_3",
|
||||
"仰拱(底板)施工完成后,3个月以后": "YG_DIBAN_AFTER_3",
|
||||
"架桥机(运梁车) 首次通过前": "JQJ_FIRST_BEFORE",
|
||||
"架桥机(运梁车) 首次通过后,前3天": "JQJ_FIRST_AFTER_3D",
|
||||
"架桥机(运梁车) 首次通过后": "JQJ_FIRST_AFTER",
|
||||
"堆载预压或路基填筑完成,第1至3个月": "DZYY_1_3",
|
||||
"堆载预压或路基填筑完成,第4至6个月": "DZYY_4_6",
|
||||
"堆载预压或路基填筑完成,6个月以后": "DZYY_AFTER_6",
|
||||
"轨道板(道床)铺设后,第1个月": "GDB_1",
|
||||
"轨道板(道床)铺设后,第2至3个月": "GDB_2_3",
|
||||
"轨道板(道床)铺设后,3个月以后": "GDB_AFTER_3",
|
||||
"""加载工况分组(同义工况归为同一分组)"""
|
||||
group_map = {
|
||||
# 路基分组
|
||||
"路基或预压土填筑,连续填筑": "DZ_CONTINUE",
|
||||
"路基或预压土填筑,两次填筑间隔时间较长": "DZ_INTERVAL",
|
||||
"预压土或路基填筑完成,第1~3个月": "DZ_FINISH_1_3",
|
||||
"预压土或路基填筑完成,第4~6个月": "DZ_FINISH_4_6",
|
||||
"预压土或路基填筑完成,6个月以后": "DZ_FINISH_AFTER_6",
|
||||
"架桥机(运梁车)首次通过前": "JQJ_FIRST_BEFORE",
|
||||
"架桥机(运梁车)首次通过后,前3天": "JQJ_FIRST_AFTER_3D",
|
||||
"架桥机(运梁车)首次通过后": "JQJ_FIRST_AFTER",
|
||||
"轨道板(道床)铺设后,第1至3个月": "GDB_FINISH_1_3",
|
||||
"轨道板(道床)铺设后,第4至6个月": "GDB_FINISH_4_6",
|
||||
"轨道板(道床)铺设后,6个月以后": "GDB_FINISH_AFTER_6",
|
||||
|
||||
# 路基旧工况分组(复用新工况分组)
|
||||
"填筑或堆载,一般情况": "DZ_CONTINUE",
|
||||
"填筑或堆载,两次填筑间隔时间较长情况": "DZ_INTERVAL",
|
||||
"堆载预压或路基填筑完成,6个月以后": "DZ_FINISH_AFTER_6",
|
||||
"轨道板(道床)铺设后,第1个月": "GDB_FINISH_1_3",
|
||||
"轨道板(道床)铺设后,第2至3个月": "GDB_FINISH_4_6",
|
||||
"轨道板(道床)铺设后,3个月以后": "GDB_FINISH_AFTER_6",
|
||||
|
||||
# 桥梁分组
|
||||
"桥墩(台)地面处拆模后": "STATIC",
|
||||
"敦身混凝土施工": "STATIC",
|
||||
"预制梁桥,架梁前": "STATIC",
|
||||
"预制梁桥,预制梁架设前": "YZLQ_BEFORE_JS",
|
||||
"预制梁桥,预制梁架设后": "YZLQ_AFTER_JS",
|
||||
"桥梁主体工程完工后,第1至3个月": "QL_ZHUTI_1_3",
|
||||
"现浇梁,浇筑前": "STATIC",
|
||||
"现浇梁上部结构施工中": "STATIC",
|
||||
"架桥机(运梁车)通过": "STATIC",
|
||||
"桥梁主体工程完工后,第1至3个月": "QL_ZHUTI_1_3",
|
||||
"桥梁主体工程完工后,第4至6个月": "QL_ZHUTI_4_6",
|
||||
"桥梁主体工程完工后,6个月以后": "QL_ZHUTI_AFTER_6",
|
||||
"轨道铺设完成后,第1个月": "GD_1",
|
||||
"轨道铺设完成后,2至3个月": "GD_2_3",
|
||||
"轨道铺设完成后,4至12个月": "GD_4_12",
|
||||
"轨道铺设完成后,12个月以后": "GD_AFTER_12",
|
||||
"桥梁主体工程完工后,6个月以后": "QL_ZHUTI_AFTER_6",
|
||||
"轨道铺设,前": "STATIC",
|
||||
"轨道铺设,后": "STATIC",
|
||||
"轨道铺设完成后,第1个月": "GD_FINISH_1",
|
||||
"轨道铺设完成后,2至3个月": "GD_FINISH_2_3",
|
||||
"轨道铺设完成后,4至12个月": "GD_FINISH_4_12",
|
||||
"轨道铺设完成后,12个月以后": "GD_FINISH_AFTER_12",
|
||||
|
||||
# 桥梁旧工况分组(复用新工况分组)
|
||||
"墩台施工到一定高度": "STATIC",
|
||||
"墩台混凝土施工": "STATIC",
|
||||
"桥位施工桥梁,制梁前": "STATIC",
|
||||
"桥位施工桥梁,上部结构施工中": "STATIC",
|
||||
"桥梁主体工程完工后,第1至3个月": "QL_ZHUTI_1_3",
|
||||
"轨道铺设期间,前": "STATIC",
|
||||
"轨道铺设期间,后": "STATIC",
|
||||
|
||||
# 隧道分组
|
||||
"仰拱(底板)施工完成后,第1个月": "YG_DIBAN_1",
|
||||
"仰拱(底板)施工完成后,第2至3个月": "YG_DIBAN_2_3",
|
||||
"仰拱(底板)施工完成后,3个月以后": "YG_DIBAN_AFTER_3",
|
||||
"无砟轨道铺设后,第1至3个月": "WZGD_1_3",
|
||||
"无砟轨道铺设后,4至12个月": "WZGD_4_12",
|
||||
"无砟轨道铺设后,12个月以后": "WZGD_AFTER_12",
|
||||
"墩台施工到一定高度": "STATIC",
|
||||
"墩台混凝土施工": "STATIC",
|
||||
"预制梁桥,架梁前": "STATIC",
|
||||
"桥位施工桥梁,制梁前": "STATIC",
|
||||
"桥位施工桥梁,上部结构施工中": "STATIC",
|
||||
"架桥机(运梁车)通过": "STATIC",
|
||||
"轨道铺设期间,前": "STATIC",
|
||||
"轨道铺设期间,后": "STATIC",
|
||||
"铺路或堆载,一般情况": "STATIC",
|
||||
"填筑或堆载,一般情况": "STATIC",
|
||||
"铺路或堆载,沉降量突变情况": "STATIC",
|
||||
"填筑或堆载,两次填筑间隔时间较长情况": "STATIC",
|
||||
"铺路或堆载,两次铺路间隔时间较长情况": "STATIC"
|
||||
}
|
||||
|
||||
def _load_group_transition_rules(self):
|
||||
"""加载工况切换触发规则(私有方法,内部使用)"""
|
||||
# 特殊工况
|
||||
"冬休": "STATIC"
|
||||
}
|
||||
return group_map
|
||||
|
||||
def _load_transition_rules(self):
|
||||
"""加载切换触发规则(沿用原逻辑,以base_periods为准)"""
|
||||
return {
|
||||
"YG_DIBAN_1": {"trigger_days": 30, "next_candidates": ["仰拱(底板)施工完成后,第2至3个月", "仰拱(底板)施工完成后,第2至3个月"]},
|
||||
"YG_DIBAN_2_3": {"trigger_days": 60, "next_candidates": ["仰拱(底板)施工完成后,3个月以后", "仰拱(底板)施工完成后,3个月以后"]},
|
||||
"YG_DIBAN_AFTER_3": {"trigger_days": None, "next_candidates": None},
|
||||
"JQJ_FIRST_BEFORE": {"trigger_days": 1, "next_candidates": ["架桥机(运梁车) 首次通过后,前3天"]},
|
||||
"JQJ_FIRST_AFTER_3D": {"trigger_days": 3, "next_candidates": ["架桥机(运梁车) 首次通过后"]},
|
||||
"JQJ_FIRST_AFTER": {"trigger_days": None, "next_candidates": None},
|
||||
"DZYY_1_3": {"trigger_days": 90, "next_candidates": ["堆载预压或路基填筑完成,第4至6个月"]},
|
||||
"DZYY_4_6": {"trigger_days": 90, "next_candidates": ["堆载预压或路基填筑完成,6个月以后"]},
|
||||
"DZYY_AFTER_6": {"trigger_days": None, "next_candidates": None},
|
||||
"GDB_1": {"trigger_days": 30, "next_candidates": ["轨道板(道床)铺设后,第2至3个月"]},
|
||||
"GDB_2_3": {"trigger_days": 30, "next_candidates": ["轨道板(道床)铺设后,3个月以后"]},
|
||||
"GDB_AFTER_3": {"trigger_days": None, "next_candidates": None},
|
||||
"YZLQ_BEFORE_JS": {"trigger_days": 1, "next_candidates": ["架桥机(运梁车)通过"]},
|
||||
"YZLQ_AFTER_JS": {"trigger_days": 7, "next_candidates": ["桥梁主体工程完工后,第1至3个月"]},
|
||||
"QL_ZHUTI_1_3": {"trigger_days": 90, "next_candidates": ["桥梁主体工程完工后,第4至6个月"]},
|
||||
"QL_ZHUTI_4_6": {"trigger_days": 90, "next_candidates": ["桥梁主体工程完工后,6个月以后"]},
|
||||
"QL_ZHUTI_AFTER_6": {"trigger_days": None, "next_candidates": None},
|
||||
"GD_1": {"trigger_days": 30, "next_candidates": ["轨道铺设完成后,2至3个月"]},
|
||||
"GD_2_3": {"trigger_days": 60, "next_candidates": ["轨道铺设完成后,4至12个月"]},
|
||||
"GD_4_12": {"trigger_days": 240, "next_candidates": ["轨道铺设完成后,12个月以后"]},
|
||||
"GD_AFTER_12": {"trigger_days": None, "next_candidates": None},
|
||||
"WZGD_1_3": {"trigger_days": 90, "next_candidates": ["无砟轨道铺设后,4至12个月"]},
|
||||
"WZGD_4_12": {"trigger_days": 240, "next_candidates": ["无砟轨道铺设后,12个月以后"]},
|
||||
"WZGD_AFTER_12": {"trigger_days": None, "next_candidates": None},
|
||||
"STATIC": {"trigger_days": None, "next_candidates": None}
|
||||
# 路基切换规则
|
||||
"DZ_FINISH_1_3": {"trigger_days": 90, "next": ["预压土或路基填筑完成,第4~6个月"]},
|
||||
"DZ_FINISH_4_6": {"trigger_days": 90, "next": ["预压土或路基填筑完成,6个月以后"]},
|
||||
"DZ_FINISH_AFTER_6": {"trigger_days": None, "next": None},
|
||||
"JQJ_FIRST_BEFORE": {"trigger_days": 1, "next": ["架桥机(运梁车)首次通过后,前3天"]},
|
||||
"JQJ_FIRST_AFTER_3D": {"trigger_days": 3, "next": ["架桥机(运梁车)首次通过后"]},
|
||||
"JQJ_FIRST_AFTER": {"trigger_days": None, "next": None},
|
||||
"GDB_FINISH_1_3": {"trigger_days": 30, "next": ["轨道板(道床)铺设后,第4至6个月"]},
|
||||
"GDB_FINISH_4_6": {"trigger_days": 30, "next": ["轨道板(道床)铺设后,6个月以后"]},
|
||||
"GDB_FINISH_AFTER_6": {"trigger_days": None, "next": None},
|
||||
|
||||
# 桥梁切换规则
|
||||
"YZLQ_BEFORE_JS": {"trigger_days": 1, "next": ["架桥机(运梁车)通过"]},
|
||||
"YZLQ_AFTER_JS": {"trigger_days": 7, "next": ["桥梁主体工程完工后,第1至3个月"]},
|
||||
"QL_ZHUTI_1_3": {"trigger_days": 90, "next": ["桥梁主体工程完工后,第4至6个月"]},
|
||||
"QL_ZHUTI_4_6": {"trigger_days": 90, "next": ["桥梁主体工程完工后,6个月以后"]},
|
||||
"QL_ZHUTI_AFTER_6": {"trigger_days": None, "next": None},
|
||||
"GD_FINISH_1": {"trigger_days": 30, "next": ["轨道铺设完成后,2至3个月"]},
|
||||
"GD_FINISH_2_3": {"trigger_days": 60, "next": ["轨道铺设完成后,4至12个月"]},
|
||||
"GD_FINISH_4_12": {"trigger_days": 240, "next": ["轨道铺设完成后,12个月以后"]},
|
||||
"GD_FINISH_AFTER_12": {"trigger_days": None, "next": None},
|
||||
|
||||
# 隧道切换规则
|
||||
"YG_DIBAN_1": {"trigger_days": 30, "next": ["仰拱(底板)施工完成后,第2至3个月"]},
|
||||
"YG_DIBAN_2_3": {"trigger_days": 60, "next": ["仰拱(底板)施工完成后,3个月以后"]},
|
||||
"YG_DIBAN_AFTER_3": {"trigger_days": None, "next": None},
|
||||
"WZGD_1_3": {"trigger_days": 90, "next": ["无砟轨道铺设后,4至12个月"]},
|
||||
"WZGD_4_12": {"trigger_days": 240, "next": ["无砟轨道铺设后,12个月以后"]},
|
||||
"WZGD_AFTER_12": {"trigger_days": None, "next": None},
|
||||
|
||||
# 静态分组(无切换)
|
||||
"DZ_CONTINUE": {"trigger_days": None, "next": None},
|
||||
"DZ_INTERVAL": {"trigger_days": None, "next": None},
|
||||
"STATIC": {"trigger_days": None, "next": None}
|
||||
}
|
||||
|
||||
def _parse_to_date(self, time_str):
|
||||
"""
|
||||
私有辅助方法:将时间字符串解析为日期对象,仅保留年月日,忽略时分秒
|
||||
:param time_str: 时间字符串,格式为 "YYYY-MM-DD HH:MM:SS"
|
||||
:return: date对象 / None(解析失败时)
|
||||
"""
|
||||
"""解析时间字符串为date对象(仅保留年月日)"""
|
||||
if not time_str:
|
||||
return None
|
||||
try:
|
||||
@@ -154,66 +255,49 @@ class OperatingModePredictor:
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def _get_time_statistics_from_reversed(self, data, workinfo):
|
||||
"""
|
||||
私有辅助方法:从倒序数据中提取时间统计信息
|
||||
:param data: 单个point_id的倒序数据列表
|
||||
:param workinfo: 当前工况名称
|
||||
:return: 元组 (首次测量日期date对象, 首次到末次持续天数, 今日与首次测量天数差)
|
||||
"""
|
||||
# 筛选当前工况的有效记录
|
||||
reversed_records = [d for d in data if d.get("workinfoname") == workinfo]
|
||||
if not reversed_records:
|
||||
def _get_time_statistics(self, data, target_workinfo):
|
||||
"""从倒序数据中提取目标工况的时间统计信息"""
|
||||
# 筛选目标工况的有效记录
|
||||
target_records = [
|
||||
d for d in data
|
||||
if self._standardize_name(d.get("workinfoname")) == self._standardize_name(target_workinfo)
|
||||
and d.get("workinfoname") not in self.winter_break_labels
|
||||
]
|
||||
if not target_records:
|
||||
return None, 0, 0
|
||||
|
||||
# 解析所有有效记录的日期
|
||||
reversed_dates = []
|
||||
for item in reversed_records:
|
||||
# 解析日期
|
||||
target_dates = []
|
||||
for item in target_records:
|
||||
d = self._parse_to_date(item.get("MTIME_W"))
|
||||
if d:
|
||||
reversed_dates.append(d)
|
||||
if not reversed_dates:
|
||||
target_dates.append(d)
|
||||
if not target_dates:
|
||||
return None, 0, 0
|
||||
|
||||
# 提取倒序数据的最新、最旧日期
|
||||
last_date = reversed_dates[0]
|
||||
first_date = reversed_dates[-1]
|
||||
|
||||
# 计算累计天数和今日与首次测量的天数差
|
||||
# 计算时间差(倒序数据:最新在0,最早在-1)
|
||||
last_date = target_dates[0]
|
||||
first_date = target_dates[-1]
|
||||
cumulative_days = (last_date - first_date).days
|
||||
today = date.today()
|
||||
days_to_today = (today - first_date).days if first_date else 0
|
||||
|
||||
return first_date, cumulative_days, days_to_today
|
||||
|
||||
def _match_next_condition(self, current_name, candidates):
|
||||
"""
|
||||
私有辅助方法:按符号风格匹配下一个工况名称(全角/半角括号对应)
|
||||
:param current_name: 当前工况名称
|
||||
:param candidates: 目标工况候选列表
|
||||
:return: 匹配的工况名称 / 当前工况名称(无候选时)
|
||||
"""
|
||||
if not candidates:
|
||||
return current_name
|
||||
# 优先匹配全角括号工况
|
||||
if "(" in current_name:
|
||||
for cand in candidates:
|
||||
if "(" in cand:
|
||||
return cand
|
||||
# 再匹配半角括号工况
|
||||
if "(" in current_name:
|
||||
for cand in candidates:
|
||||
if "(" in cand:
|
||||
return cand
|
||||
# 无对应符号时,返回第一个候选工况
|
||||
return candidates[0]
|
||||
def _get_pre_winter_break_workinfo(self, inner_data_list):
|
||||
"""提取冬休前的上一个有效工况"""
|
||||
if not inner_data_list:
|
||||
return None
|
||||
# 倒序遍历,跳过冬休,找第一个有效工况
|
||||
for record in inner_data_list:
|
||||
current_work = record.get("workinfoname")
|
||||
if current_work and current_work not in self.winter_break_labels:
|
||||
# 优先返回等效新工况
|
||||
return self.old_to_new_map.get(current_work, current_work)
|
||||
return None
|
||||
|
||||
def _validate_point_id(self, inner_list):
|
||||
"""
|
||||
私有辅助方法:校验内嵌列表内所有元素的point_id是否一致
|
||||
:param inner_list: 单个point_id的倒序数据列表
|
||||
:return: point_id / None(校验失败或列表为空时)
|
||||
"""
|
||||
"""校验内嵌列表内point_id是否一致"""
|
||||
if not inner_list:
|
||||
return None
|
||||
base_point_id = inner_list[0].get("point_id")
|
||||
@@ -224,23 +308,21 @@ class OperatingModePredictor:
|
||||
|
||||
def predict(self, data_2d_list):
|
||||
"""
|
||||
公有核心方法:执行工况预测,处理二维输入数据,返回一维结果列表
|
||||
公有核心方法:执行工况预测
|
||||
:param data_2d_list: 二维倒序数据列表,格式 [[{},{},{}], [{},{},{}]]
|
||||
:return: 一维结果列表,格式 [{}, {}, {}],每个元素为对应内嵌列表的最新记录+推导字段
|
||||
:return: 一维结果列表,格式 [{}, {}, {}]
|
||||
"""
|
||||
final_result_1d = []
|
||||
final_result = []
|
||||
|
||||
# 遍历二维列表,逐个处理每个point_id的内嵌数据
|
||||
for inner_data_list in data_2d_list:
|
||||
# 跳过空列表
|
||||
if not isinstance(inner_data_list, list) or len(inner_data_list) == 0:
|
||||
continue
|
||||
|
||||
# 1. 提取当前内嵌列表的最新记录(倒序数据索引0为最新)
|
||||
# 取最新记录并复制(避免修改原数据)
|
||||
latest_record = inner_data_list[0].copy()
|
||||
|
||||
# 2. 校验point_id一致性
|
||||
point_id = self._validate_point_id(inner_data_list)
|
||||
|
||||
# 校验point_id
|
||||
if not point_id:
|
||||
latest_record.update({
|
||||
"status": "fail",
|
||||
@@ -248,55 +330,80 @@ class OperatingModePredictor:
|
||||
"first_measure_date": None,
|
||||
"days_from_first_to_today": None,
|
||||
"next_workinfo": None,
|
||||
"judge_based_workinfo": None,
|
||||
"error_msg": "point_id不一致或缺失"
|
||||
})
|
||||
final_result_1d.append(latest_record)
|
||||
final_result.append(latest_record)
|
||||
continue
|
||||
|
||||
# 3. 提取并校验当前工况
|
||||
# 获取当前工况并标准化
|
||||
current_workinfo = latest_record.get("workinfoname")
|
||||
if not current_workinfo or current_workinfo not in self.base_periods:
|
||||
if not current_workinfo or self._standardize_name(current_workinfo) not in self.std_to_canonical:
|
||||
latest_record.update({
|
||||
"status": "fail",
|
||||
"current_workinfo": None,
|
||||
"first_measure_date": None,
|
||||
"days_from_first_to_today": None,
|
||||
"next_workinfo": None,
|
||||
"judge_based_workinfo": None,
|
||||
"error_msg": "工况无效或缺失"
|
||||
})
|
||||
final_result_1d.append(latest_record)
|
||||
final_result.append(latest_record)
|
||||
continue
|
||||
|
||||
# 4. 提取时间统计信息
|
||||
first_dt, cumulative_days, days_to_today = self._get_time_statistics_from_reversed(
|
||||
inner_data_list, current_workinfo
|
||||
# 冬休逻辑:取冬休前工况作为判断基准
|
||||
if current_workinfo in self.winter_break_labels:
|
||||
judge_based_workinfo = self._get_pre_winter_break_workinfo(inner_data_list)
|
||||
if not judge_based_workinfo:
|
||||
latest_record.update({
|
||||
"status": "fail",
|
||||
"current_workinfo": current_workinfo,
|
||||
"first_measure_date": None,
|
||||
"days_from_first_to_today": None,
|
||||
"next_workinfo": None,
|
||||
"judge_based_workinfo": None,
|
||||
"error_msg": "冬休前未找到有效工况"
|
||||
})
|
||||
final_result.append(latest_record)
|
||||
continue
|
||||
else:
|
||||
# 非冬休:优先使用等效新工况作为判断基准
|
||||
judge_based_workinfo = self.old_to_new_map.get(current_workinfo, current_workinfo)
|
||||
|
||||
# 计算时间统计信息
|
||||
first_dt, cumulative_days, days_to_today = self._get_time_statistics(
|
||||
inner_data_list, judge_based_workinfo
|
||||
)
|
||||
first_measure_date = first_dt.strftime("%Y-%m-%d") if first_dt else None
|
||||
|
||||
# 5. 判断工况切换条件,推导下一工况
|
||||
group_id = self.condition_group.get(current_workinfo, "STATIC")
|
||||
rule = self.group_transition_rules.get(group_id, {})
|
||||
# 推导下一工况(以base_periods中的名称为准)
|
||||
std_judge_work = self._standardize_name(judge_based_workinfo)
|
||||
group_id = self.std_to_group.get(std_judge_work, "STATIC")
|
||||
rule = self.transition_rules.get(group_id, {})
|
||||
trigger_days = rule.get("trigger_days")
|
||||
next_candidates = rule.get("next_candidates", [])
|
||||
next_candidates = rule.get("next", [])
|
||||
|
||||
if trigger_days is not None and cumulative_days >= trigger_days:
|
||||
# 满足切换条件:返回目标工况
|
||||
next_workname = self._match_next_condition(current_workinfo, next_candidates)
|
||||
if trigger_days is not None and cumulative_days >= trigger_days and next_candidates:
|
||||
# 切换工况:取base_periods中的规范名称
|
||||
next_workinfo = next_candidates[0]
|
||||
else:
|
||||
# 不满足切换条件:返回当前工况
|
||||
next_workname = current_workinfo
|
||||
# 不切换:有等效则返回新工况,无则返回旧工况
|
||||
next_workinfo = self.old_to_new_map.get(judge_based_workinfo, judge_based_workinfo)
|
||||
|
||||
# 6. 组装结果字段,更新最新记录
|
||||
# 组装最终结果
|
||||
latest_record.update({
|
||||
"status": "success",
|
||||
"current_workinfo": current_workinfo,
|
||||
"current_workinfo": current_workinfo, # 保留原始输入工况
|
||||
"judge_based_workinfo": judge_based_workinfo, # 实际判断用的工况(新工况优先)
|
||||
"first_measure_date": first_measure_date,
|
||||
"days_from_first_to_today": days_to_today,
|
||||
"next_workinfo": next_workname,
|
||||
"point_id": point_id
|
||||
"next_workinfo": next_workinfo, # 推导结果:有等效返回新工况,无则返回旧工况
|
||||
"point_id": point_id,
|
||||
"error_msg": ""
|
||||
})
|
||||
|
||||
# 7. 加入最终结果列表
|
||||
final_result_1d.append(latest_record)
|
||||
final_result.append(latest_record)
|
||||
|
||||
return final_result
|
||||
|
||||
|
||||
return final_result_1d
|
||||
Reference in New Issue
Block a user