当自动爬取的时候前端没有传输设备绑定和iccid的关系,导致后端没有接收到,现在修改逻辑
This commit is contained in:
@ -7,7 +7,9 @@ from sqlalchemy import desc, or_
|
|||||||
from extensions import db
|
from extensions import db
|
||||||
from models import Device, DeviceHistory, MaintenanceLog
|
from models import Device, DeviceHistory, MaintenanceLog
|
||||||
|
|
||||||
# --- 尝试导入服务模块 ---
|
# =========================================================
|
||||||
|
# 模块动态导入 (防止循环引用或缺失报错)
|
||||||
|
# =========================================================
|
||||||
try:
|
try:
|
||||||
from services.core import execute_monitor_task
|
from services.core import execute_monitor_task
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -28,6 +30,7 @@ api_bp = Blueprint('api', __name__, url_prefix='/api')
|
|||||||
def calculate_offset(latest_time_str):
|
def calculate_offset(latest_time_str):
|
||||||
"""
|
"""
|
||||||
计算时间滞后天数
|
计算时间滞后天数
|
||||||
|
用于前端展示设备数据是否过时
|
||||||
"""
|
"""
|
||||||
if not latest_time_str or latest_time_str == "N/A":
|
if not latest_time_str or latest_time_str == "N/A":
|
||||||
return "从未同步"
|
return "从未同步"
|
||||||
@ -44,6 +47,7 @@ def calculate_offset(latest_time_str):
|
|||||||
def check_data_quality(content_data, source_type, data_time_str=None):
|
def check_data_quality(content_data, source_type, data_time_str=None):
|
||||||
"""
|
"""
|
||||||
数据质量分析算法 (融合版:旧版核心规则 + 新版夜间/IoT过滤)
|
数据质量分析算法 (融合版:旧版核心规则 + 新版夜间/IoT过滤)
|
||||||
|
用于判断设备状态颜色 (绿色ok/黄色warning/红色error)
|
||||||
"""
|
"""
|
||||||
if not content_data:
|
if not content_data:
|
||||||
return 'ok'
|
return 'ok'
|
||||||
@ -169,49 +173,61 @@ def check_data_quality(content_data, source_type, data_time_str=None):
|
|||||||
|
|
||||||
def save_iot_cards_to_db(card_list):
|
def save_iot_cards_to_db(card_list):
|
||||||
"""
|
"""
|
||||||
[新功能] IoT数据入库逻辑
|
[核心修复] IoT数据入库逻辑 - 增量更新模式
|
||||||
1. 只操作 source='iot_card' 的记录。
|
1. 只操作 source='iot_card' 的记录。
|
||||||
2. 必须保留 is_whitelist 状态,防止被自动同步覆盖。
|
2. 核心:使用 'update' 逻辑而不是 'replace' 逻辑。
|
||||||
|
即使自动任务运行,也不会弄丢白名单 (is_whitelist) 或其他已存在的数据。
|
||||||
"""
|
"""
|
||||||
if not card_list: return 0, None
|
if not card_list: return 0, None
|
||||||
update_count = 0
|
update_count = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for card in card_list:
|
for card in card_list:
|
||||||
iccid = card.get('iccid')
|
iccid = card.get('iccid') or card.get('card_id') # 兼容字段名
|
||||||
if not iccid: continue
|
if not iccid: continue
|
||||||
|
|
||||||
# 1. 查找是否存在
|
# 1. 查找是否存在该 SIM 卡记录
|
||||||
sim_record = Device.query.filter_by(name=iccid, source='iot_card').first()
|
sim_record = Device.query.filter_by(name=iccid, source='iot_card').first()
|
||||||
current_whitelist = False
|
|
||||||
|
# 初始化旧数据容器
|
||||||
|
old_json = {}
|
||||||
|
|
||||||
if not sim_record:
|
if not sim_record:
|
||||||
# 插入新数据
|
# 插入新卡片
|
||||||
sim_record = Device(name=iccid, source='iot_card', install_site="IoT库")
|
sim_record = Device(name=iccid, source='iot_card', install_site="IoT库")
|
||||||
db.session.add(sim_record)
|
db.session.add(sim_record)
|
||||||
db.session.flush()
|
db.session.flush() # 立即获取ID
|
||||||
else:
|
else:
|
||||||
# 旧卡:读取并保留旧的白名单设置
|
# 旧卡:尝试读取现有 JSON,确保不丢失之前的数据
|
||||||
try:
|
try:
|
||||||
old_json = json.loads(sim_record.json_data)
|
if sim_record.json_data:
|
||||||
current_whitelist = old_json.get('is_whitelist', False)
|
old_json = json.loads(sim_record.json_data)
|
||||||
except:
|
except:
|
||||||
current_whitelist = False
|
old_json = {}
|
||||||
|
|
||||||
# 2. 更新字段
|
# 2. 准备需要更新的 API 数据 (只更新变动的字段)
|
||||||
sim_record.status = str(card.get('cardStatus', ''))
|
api_updates = {
|
||||||
|
|
||||||
card_data = {
|
|
||||||
"iccid": iccid,
|
"iccid": iccid,
|
||||||
"usedTraffic": str(card.get('usedTraffic') or '0'),
|
"usedTraffic": str(card.get('usedTraffic') or '0'),
|
||||||
"stopDate": card.get('stopDate', 'N/A'),
|
"stopDate": card.get('stopDate', 'N/A'),
|
||||||
"cardStatus": card.get('cardStatus'),
|
"cardStatus": card.get('cardStatus'),
|
||||||
"tag": card.get('tag', ''),
|
"tag": card.get('tag', '')
|
||||||
"is_whitelist": current_whitelist # 写回保留的状态
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sim_record.json_data = json.dumps(card_data, ensure_ascii=False)
|
# 3. [关键步骤] 合并数据
|
||||||
|
# 如果 old_json 里有 is_whitelist,update 不会覆盖它,因为 api_updates 里没有这个key
|
||||||
|
old_json.update(api_updates)
|
||||||
|
|
||||||
|
# 4. 兜底保障:如果这是新卡,或者旧卡丢失了 whitelist 字段,默认设为 False
|
||||||
|
if 'is_whitelist' not in old_json:
|
||||||
|
old_json['is_whitelist'] = False
|
||||||
|
|
||||||
|
# 5. 更新数据库字段
|
||||||
|
sim_record.status = str(card.get('cardStatus', ''))
|
||||||
|
# 序列化并写回
|
||||||
|
sim_record.json_data = json.dumps(old_json, ensure_ascii=False)
|
||||||
sim_record.check_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
sim_record.check_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
update_count += 1
|
update_count += 1
|
||||||
|
|
||||||
return update_count, None
|
return update_count, None
|
||||||
@ -429,15 +445,19 @@ def run_monitor():
|
|||||||
device.latest_time = target_time
|
device.latest_time = target_time
|
||||||
device.check_time = current_time
|
device.check_time = current_time
|
||||||
|
|
||||||
# [新代码逻辑] 合并模式 (update),防止覆盖掉 bound_iccid
|
# [关键逻辑] 合并模式 (update),防止覆盖掉 bound_iccid
|
||||||
|
# 先读取数据库里已有的 json_data
|
||||||
old_json = {}
|
old_json = {}
|
||||||
try:
|
try:
|
||||||
old_json = json.loads(device.json_data)
|
if device.json_data:
|
||||||
|
old_json = json.loads(device.json_data)
|
||||||
except:
|
except:
|
||||||
pass
|
old_json = {}
|
||||||
|
|
||||||
|
# 只有当 raw_json 是字典时才进行合并
|
||||||
new_json = d_raw if isinstance(d_raw, dict) else item.get('raw_json', {})
|
new_json = d_raw if isinstance(d_raw, dict) else item.get('raw_json', {})
|
||||||
if isinstance(new_json, dict):
|
if isinstance(new_json, dict):
|
||||||
|
# 使用 update 方法,这样 old_json 里存在的 bound_iccid 不会被删掉
|
||||||
old_json.update(new_json)
|
old_json.update(new_json)
|
||||||
|
|
||||||
device.json_data = json.dumps(old_json, ensure_ascii=False)
|
device.json_data = json.dumps(old_json, ensure_ascii=False)
|
||||||
@ -461,6 +481,7 @@ def run_monitor():
|
|||||||
# --- B. 执行 IoT 同步 (写入数据库) ---
|
# --- B. 执行 IoT 同步 (写入数据库) ---
|
||||||
if sync_iot_data_service:
|
if sync_iot_data_service:
|
||||||
iot_list = sync_iot_data_service()
|
iot_list = sync_iot_data_service()
|
||||||
|
# 复用已修复的 save_iot_cards_to_db,确保不会丢失数据
|
||||||
c, e = save_iot_cards_to_db(iot_list)
|
c, e = save_iot_cards_to_db(iot_list)
|
||||||
if e:
|
if e:
|
||||||
msg_list.append(f"IoT错: {e}")
|
msg_list.append(f"IoT错: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user