298 lines
12 KiB
Python
Executable File
298 lines
12 KiB
Python
Executable File
from flask import jsonify, request, send_file, session, current_app
|
|
from flask_login import login_required, current_user
|
|
from scripts.update.zte import LoginClient
|
|
from scripts.models import db, Device, WorkOrder, Channel
|
|
from datetime import datetime
|
|
from sqlalchemy import text, create_engine
|
|
import hashlib
|
|
import pymysql
|
|
import io
|
|
import os
|
|
|
|
|
|
def init_device_routes(app):
|
|
@app.route('/sync_offline_devices', methods=['POST'])
|
|
@login_required
|
|
def sync_offline_devices():
|
|
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
|
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
|
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试同步离线设备')
|
|
return jsonify({'success': False, 'message': '没有权限执行此操作'})
|
|
|
|
try:
|
|
app.logger.info(f'用户 {current_user.name} 开始同步离线设备')
|
|
# 从配置中获取数据库连接信息
|
|
db_config = current_app.config['KEY110_DB']
|
|
conn = pymysql.connect(**db_config)
|
|
|
|
cursor = conn.cursor()
|
|
|
|
# 获取所有教学点的状态
|
|
cursor.execute("""
|
|
SELECT 教学点名称, 连通状态
|
|
FROM IP数据
|
|
""")
|
|
|
|
schools = cursor.fetchall()
|
|
|
|
# 分别处理在线和离线的教学点
|
|
offline_school_names = [school[0].strip().replace(' ', ' ') for school in schools if school[1] == '离线']
|
|
online_school_names = [school[0].strip().replace(' ', ' ') for school in schools if school[1] == '在线']
|
|
|
|
# 关闭1key110数据库连接
|
|
cursor.close()
|
|
conn.close()
|
|
|
|
# 处理恢复在线的设备
|
|
online_devices = Device.query.filter(
|
|
Device.device_id.in_(online_school_names),
|
|
Device.is_normal == False # 当前状态为故障的设备
|
|
).all()
|
|
|
|
# 删除恢复在线设备的在途工单
|
|
recovered_count = 0
|
|
for device in online_devices:
|
|
# 查找并删除该设备的在途工单
|
|
pending_orders = WorkOrder.query.filter_by(
|
|
device_id=device.device_id,
|
|
status='待处理'
|
|
).all()
|
|
|
|
for order in pending_orders:
|
|
db.session.delete(order)
|
|
recovered_count += 1
|
|
|
|
# 更新设备状态为正常
|
|
device.is_normal = True
|
|
db.session.add(device)
|
|
|
|
# 处理离线设备
|
|
offline_devices = Device.query.filter(
|
|
Device.device_id.in_(offline_school_names),
|
|
Device.in_use == True,
|
|
Device.is_normal == True
|
|
).all()
|
|
|
|
# 生成工单号
|
|
today = datetime.now().strftime('%Y%m%d')
|
|
last_work_order = WorkOrder.query.filter(
|
|
WorkOrder.order_id.like(f'{today}%')
|
|
).order_by(WorkOrder.order_id.desc()).first()
|
|
|
|
start_number = int(last_work_order.order_id[-4:]) + 1 if last_work_order else 1
|
|
|
|
# 创建工单
|
|
created_count = 0
|
|
for index, device in enumerate(offline_devices):
|
|
# 检查是否已有在途工单
|
|
existing_order = WorkOrder.query.filter_by(
|
|
device_id=device.device_id,
|
|
status='待处理'
|
|
).first()
|
|
|
|
if existing_order:
|
|
continue
|
|
|
|
current_number = start_number + index
|
|
new_number = f"{today}{str(current_number).zfill(4)}"
|
|
|
|
work_order = WorkOrder(
|
|
order_id=new_number,
|
|
device_id=device.device_id,
|
|
dispatch_time=datetime.now(),
|
|
status='待处理',
|
|
branch=device.branch
|
|
)
|
|
|
|
db.session.add(work_order)
|
|
device.is_normal = False
|
|
db.session.add(device)
|
|
created_count += 1
|
|
|
|
db.session.commit()
|
|
|
|
app.logger.info(f'同步完成:创建了 {created_count} 个工单,恢复了 {recovered_count} 个设备')
|
|
return jsonify({
|
|
'success': True,
|
|
'count': created_count
|
|
})
|
|
|
|
except Exception as e:
|
|
app.logger.error(f'同步离线设备失败:{str(e)}')
|
|
return jsonify({
|
|
'success': False,
|
|
'message': str(e)
|
|
})
|
|
|
|
@app.route('/check_existing_orders', methods=['POST'])
|
|
@login_required
|
|
def check_existing_orders():
|
|
device_ids = request.json.get('device_ids', [])
|
|
app.logger.info(f'用户 {current_user.name} 检查设备工单状态,设备数量:{len(device_ids)}')
|
|
|
|
# 查询设备状态
|
|
existing_devices = Device.query.filter(
|
|
Device.device_id.in_(device_ids),
|
|
Device.is_normal == False # 检查设备是否处于故障状态
|
|
).with_entities(Device.device_id).all()
|
|
|
|
# 提取设备ID列表
|
|
existing_device_ids = [device.device_id for device in existing_devices]
|
|
app.logger.info(f'发现 {len(existing_device_ids)} 个设备存在故障工单')
|
|
|
|
return jsonify({'existing_devices': existing_device_ids})
|
|
|
|
@app.route('/get_captcha', methods=['GET'])
|
|
def get_captcha():
|
|
app.logger.info('用户请求验证码')
|
|
try:
|
|
client = LoginClient()
|
|
cid = client.get_captcha()
|
|
# 将 cid 存储在 session 中供后续使用
|
|
session['zte_cid'] = cid
|
|
|
|
# 读取验证码图片并返回给前端
|
|
captcha_path = os.path.join(os.path.dirname(os.path.dirname(__file__)),
|
|
'static', 'captcha.png')
|
|
with open(captcha_path, "rb") as f:
|
|
app.logger.info('验证码获取成功')
|
|
return send_file(
|
|
io.BytesIO(f.read()),
|
|
mimetype='image/png'
|
|
)
|
|
except Exception as e:
|
|
app.logger.error(f'获取验证码失败:{str(e)}')
|
|
return jsonify({'success': False, 'message': '获取验证码失败'})
|
|
|
|
@app.route('/sync_camera_step1', methods=['POST'])
|
|
def sync_camera_step1():
|
|
try:
|
|
app.logger.info(f'用户 {current_user.name if current_user else "未登录"} 开始同步摄像头第一步')
|
|
data = request.get_json()
|
|
captcha = data.get('captcha')
|
|
cid = session.get('zte_cid')
|
|
|
|
if not captcha or not cid:
|
|
app.logger.warning('同步摄像头失败:验证码或会话ID缺失')
|
|
return jsonify({'success': False, 'message': 'Invalid request'})
|
|
|
|
client = LoginClient()
|
|
# 登录
|
|
app.logger.info('尝试登录中兴平台')
|
|
login_result = client.login(
|
|
account="DHDX001",
|
|
password=hashlib.sha256("Root1234#".encode()).hexdigest(),
|
|
validcode=captcha,
|
|
cid=cid
|
|
)
|
|
|
|
if login_result.get("result") != 0:
|
|
app.logger.warning('登录中兴平台失败:验证码错误')
|
|
return jsonify({'success': False, 'message': 'INVALID_CAPTCHA'})
|
|
|
|
token = login_result.get("token")
|
|
app.logger.info('登录成功,开始获取在线信息')
|
|
# 获取在线信息
|
|
online_info = client.get_online_info(token)
|
|
|
|
if online_info.get("result") == 0:
|
|
rows = online_info.get("rows", [])
|
|
updated_count = 0
|
|
offline_count = 0
|
|
|
|
app.logger.info(f'获取到 {len(rows)} 个设备信息,开始更新数据库')
|
|
# 更新 channels 表
|
|
for row in rows:
|
|
db.session.execute(
|
|
text("""
|
|
INSERT INTO channels (puid, pu_name, status)
|
|
VALUES (:puid, :pu_name, :status)
|
|
ON DUPLICATE KEY UPDATE
|
|
pu_name = :pu_name, status = :status
|
|
"""),
|
|
{
|
|
'puid': row['puid'],
|
|
'pu_name': row['pu_name'],
|
|
'status': row['status']
|
|
}
|
|
)
|
|
updated_count += 1
|
|
if row['status'] != 'online':
|
|
offline_count += 1
|
|
|
|
db.session.commit()
|
|
app.logger.info(f'数据库更新完成,更新了 {updated_count} 条记录,其中离线设备 {offline_count} 个')
|
|
return jsonify({
|
|
'success': True,
|
|
'updated_count': updated_count,
|
|
'offline_count': offline_count
|
|
})
|
|
|
|
app.logger.error('获取在线信息失败')
|
|
return jsonify({'success': False, 'message': 'Failed to get online info'})
|
|
|
|
except Exception as e:
|
|
app.logger.error(f'同步摄像头步骤1失败:{str(e)}')
|
|
return jsonify({'success': False, 'message': str(e)})
|
|
|
|
@app.route('/sync_camera_step2', methods=['POST'])
|
|
def sync_camera_step2():
|
|
try:
|
|
app.logger.info(f'用户 {current_user.name if current_user else "未登录"} 开始同步摄像头第二步')
|
|
# 更新设备状态
|
|
devices = Device.query.filter(
|
|
Device.puid.isnot(None),
|
|
Device.in_use == True # 添加这个条件,只检查在用设备
|
|
).all()
|
|
app.logger.info(f'查询到 {len(devices)} 个需要同步的设备')
|
|
offline_devices = []
|
|
|
|
for device in devices:
|
|
channel = db.session.query(Channel).filter_by(puid=device.puid).first()
|
|
if channel and channel.status != 'online':
|
|
device.is_normal = 0
|
|
# 检查是否已有在途工单
|
|
existing_order = WorkOrder.query.filter_by(
|
|
device_id=device.device_id,
|
|
status='待处理'
|
|
).first()
|
|
|
|
if not existing_order: # 只添加没有在途工单的设备
|
|
offline_devices.append(device)
|
|
|
|
db.session.commit()
|
|
app.logger.info(f'发现 {len(offline_devices)} 个离线设备需要创建工单')
|
|
|
|
# 为离线设备创建工单
|
|
created_count = 0
|
|
if offline_devices:
|
|
today = datetime.now().strftime('%Y%m%d')
|
|
last_work_order = WorkOrder.query.filter(
|
|
WorkOrder.order_id.like(f'{today}%')
|
|
).order_by(WorkOrder.order_id.desc()).first()
|
|
|
|
start_number = int(last_work_order.order_id[-4:]) + 1 if last_work_order else 1
|
|
|
|
for index, device in enumerate(offline_devices):
|
|
order_id = f"{today}{str(start_number + index).zfill(4)}"
|
|
work_order = WorkOrder(
|
|
order_id=order_id,
|
|
device_id=device.device_id,
|
|
status='待处理',
|
|
dispatch_time=datetime.now(),
|
|
branch=device.branch # 添加支局信息
|
|
)
|
|
db.session.add(work_order)
|
|
created_count += 1
|
|
|
|
db.session.commit()
|
|
app.logger.info(f'成功创建 {created_count} 个工单')
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'count': created_count
|
|
})
|
|
|
|
except Exception as e:
|
|
app.logger.error(f'同步摄像头步骤2失败:{str(e)}')
|
|
return jsonify({'success': False, 'message': str(e)}) |