535 lines
16 KiB
Python
535 lines
16 KiB
Python
|
|
#!/usr/bin/env python
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
电动扳手后端API服务器
|
|||
|
|
提供工单查询、认领、数据提交等接口
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from flask import Flask, request, jsonify
|
|||
|
|
from flask_cors import CORS
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
from datetime import datetime
|
|||
|
|
from typing import Dict, List, Optional
|
|||
|
|
from database import Database
|
|||
|
|
|
|||
|
|
# 添加父目录到路径,以便导入wrench_controller
|
|||
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|||
|
|
from wrench_controller import WrenchController
|
|||
|
|
|
|||
|
|
app = Flask(__name__)
|
|||
|
|
CORS(app) # 允许跨域请求
|
|||
|
|
|
|||
|
|
# 初始化数据库
|
|||
|
|
# 确保使用正确的数据库路径(相对于app.py所在目录)
|
|||
|
|
import os
|
|||
|
|
db_path = os.path.join(os.path.dirname(__file__), "wrench.db")
|
|||
|
|
db = Database(db_path)
|
|||
|
|
print(f"[INFO] 数据库路径: {db_path}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/work-orders', methods=['GET'])
|
|||
|
|
def get_work_orders():
|
|||
|
|
"""
|
|||
|
|
查询工单列表
|
|||
|
|
如果不传参数,返回所有可用工单
|
|||
|
|
如果传trace_id和process_id,返回符合条件的工单
|
|||
|
|
"""
|
|||
|
|
trace_id = request.args.get('trace_id')
|
|||
|
|
process_id = request.args.get('process_id')
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 如果没有传参数,返回所有可用工单
|
|||
|
|
if not trace_id or not process_id:
|
|||
|
|
available_orders = db.get_all_available_work_orders()
|
|||
|
|
print(f"[DEBUG] 查询所有可用工单,结果数量: {len(available_orders)}")
|
|||
|
|
else:
|
|||
|
|
# 从数据库查询指定条件的可用工单
|
|||
|
|
available_orders = db.get_available_work_orders(trace_id, process_id)
|
|||
|
|
print(f"[DEBUG] 查询参数: trace_id={trace_id}, process_id={process_id}, 结果数量: {len(available_orders)}")
|
|||
|
|
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "查询成功",
|
|||
|
|
"data": available_orders
|
|||
|
|
})
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"[ERROR] 查询工单异常: {e}")
|
|||
|
|
import traceback
|
|||
|
|
traceback.print_exc()
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": f"查询失败: {str(e)}",
|
|||
|
|
"data": []
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/work-orders/claim', methods=['POST'])
|
|||
|
|
def claim_work_order():
|
|||
|
|
"""
|
|||
|
|
认领工单
|
|||
|
|
参数: trace_id (追溯号), process_id (工序号), operator (操作员)
|
|||
|
|
返回: 认领结果和工单详情
|
|||
|
|
"""
|
|||
|
|
data = request.get_json()
|
|||
|
|
trace_id = data.get('trace_id')
|
|||
|
|
process_id = data.get('process_id')
|
|||
|
|
operator = data.get('operator', '未知操作员')
|
|||
|
|
|
|||
|
|
if not trace_id or not process_id:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "追溯号和工序号不能为空"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 检查是否已被认领
|
|||
|
|
claimed = db.get_claimed_order(trace_id, process_id)
|
|||
|
|
if claimed:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "该工单已被认领"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 查找工单
|
|||
|
|
order = db.get_work_order(trace_id, process_id)
|
|||
|
|
if not order:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "未找到符合条件的工单"
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
# 认领工单
|
|||
|
|
if db.claim_work_order(trace_id, process_id, operator):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "认领成功",
|
|||
|
|
"data": order
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "认领失败"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/work-orders/submit', methods=['POST'])
|
|||
|
|
def submit_work_order():
|
|||
|
|
"""
|
|||
|
|
提交工单数据
|
|||
|
|
参数: trace_id, process_id, bolts (螺栓数据列表), device_sn, device_name
|
|||
|
|
返回: 提交结果
|
|||
|
|
"""
|
|||
|
|
data = request.get_json()
|
|||
|
|
trace_id = data.get('trace_id')
|
|||
|
|
process_id = data.get('process_id')
|
|||
|
|
bolts = data.get('bolts', [])
|
|||
|
|
device_sn = data.get('device_sn')
|
|||
|
|
device_name = data.get('device_name')
|
|||
|
|
|
|||
|
|
# 调试:打印接收到的数据
|
|||
|
|
print(f"[DEBUG] 接收提交工单数据:")
|
|||
|
|
print(f" trace_id: {trace_id}")
|
|||
|
|
print(f" process_id: {process_id}")
|
|||
|
|
print(f" device_sn: {device_sn}")
|
|||
|
|
print(f" device_name: {device_name}")
|
|||
|
|
print(f" bolts数量: {len(bolts)}")
|
|||
|
|
|
|||
|
|
if not trace_id or not process_id:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "追溯号和工序号不能为空"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 检查是否已被认领
|
|||
|
|
claimed = db.get_claimed_order(trace_id, process_id)
|
|||
|
|
if not claimed:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "该工单未被认领,无法提交"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 提交结果
|
|||
|
|
if db.submit_work_order(trace_id, process_id, bolts, device_sn, device_name):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "数据提交成功",
|
|||
|
|
"data": {
|
|||
|
|
"trace_id": trace_id,
|
|||
|
|
"process_id": process_id,
|
|||
|
|
"submitted_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "提交失败"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/work-orders/release', methods=['POST'])
|
|||
|
|
def release_work_order():
|
|||
|
|
"""
|
|||
|
|
释放工单(取消认领)
|
|||
|
|
参数: trace_id, process_id
|
|||
|
|
"""
|
|||
|
|
data = request.get_json()
|
|||
|
|
trace_id = data.get('trace_id')
|
|||
|
|
process_id = data.get('process_id')
|
|||
|
|
|
|||
|
|
if not trace_id or not process_id:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "追溯号和工序号不能为空"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
if db.release_work_order(trace_id, process_id):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "释放成功"
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "该工单未被认领"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/work-orders/create', methods=['POST'])
|
|||
|
|
def create_work_order():
|
|||
|
|
"""
|
|||
|
|
创建工单
|
|||
|
|
参数: trace_id, process_id, process_name, product_name, station, operator, bolts
|
|||
|
|
返回: 创建结果
|
|||
|
|
"""
|
|||
|
|
data = request.get_json()
|
|||
|
|
|
|||
|
|
# 验证必填字段
|
|||
|
|
required_fields = ['trace_id', 'process_id', 'bolts']
|
|||
|
|
for field in required_fields:
|
|||
|
|
if not data.get(field):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": f"字段 {field} 不能为空"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 构建工单数据
|
|||
|
|
order_data = {
|
|||
|
|
"trace_id": data.get('trace_id'),
|
|||
|
|
"process_id": data.get('process_id'),
|
|||
|
|
"process_name": data.get('process_name', ''),
|
|||
|
|
"product_name": data.get('product_name', ''),
|
|||
|
|
"operator": data.get('operator', ''),
|
|||
|
|
"status": data.get('status', 'pending'),
|
|||
|
|
"bolts": data.get('bolts', [])
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 创建工单
|
|||
|
|
if db.create_work_order(order_data):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "工单创建成功",
|
|||
|
|
"data": {
|
|||
|
|
"trace_id": order_data['trace_id'],
|
|||
|
|
"process_id": order_data['process_id']
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "工单创建失败"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/wrench-devices', methods=['GET'])
|
|||
|
|
def get_wrench_devices():
|
|||
|
|
"""获取所有扳手设备列表"""
|
|||
|
|
try:
|
|||
|
|
devices = db.get_wrench_devices()
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "查询成功",
|
|||
|
|
"data": devices
|
|||
|
|
})
|
|||
|
|
except Exception as e:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": f"查询失败: {str(e)}",
|
|||
|
|
"data": []
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/wrench-devices', methods=['POST'])
|
|||
|
|
def create_wrench_device():
|
|||
|
|
"""创建扳手设备"""
|
|||
|
|
data = request.get_json()
|
|||
|
|
|
|||
|
|
required_fields = ['device_name', 'ip_address']
|
|||
|
|
for field in required_fields:
|
|||
|
|
if not data.get(field):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": f"字段 {field} 不能为空"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
if db.create_wrench_device(data):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "设备创建成功"
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "设备创建失败"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/wrench-devices/<int:device_id>', methods=['PUT'])
|
|||
|
|
def update_wrench_device(device_id):
|
|||
|
|
"""更新扳手设备"""
|
|||
|
|
data = request.get_json()
|
|||
|
|
|
|||
|
|
if db.update_wrench_device(device_id, data):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "设备更新成功"
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "设备更新失败"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/wrench-devices/<int:device_id>', methods=['DELETE'])
|
|||
|
|
def delete_wrench_device(device_id):
|
|||
|
|
"""删除扳手设备"""
|
|||
|
|
if db.delete_wrench_device(device_id):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "设备删除成功"
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "设备删除失败"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/wrench-devices/<int:device_id>/status', methods=['POST'])
|
|||
|
|
def update_device_status(device_id):
|
|||
|
|
"""更新设备状态(用于心跳检测)"""
|
|||
|
|
data = request.get_json()
|
|||
|
|
status = data.get('status', 'offline')
|
|||
|
|
|
|||
|
|
if db.update_wrench_device_status(device_id, status):
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "状态更新成功"
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "状态更新失败"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/wrench-devices/<int:device_id>/check-status', methods=['POST'])
|
|||
|
|
def check_device_status(device_id):
|
|||
|
|
"""检测设备在线状态"""
|
|||
|
|
device = db.get_wrench_device(device_id)
|
|||
|
|
if not device:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "设备不存在"
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
device_config = {
|
|||
|
|
"ip_address": device.get('ip_address'),
|
|||
|
|
"port": device.get('port', 7888),
|
|||
|
|
"address_code": device.get('address_code', 1)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 尝试连接设备
|
|||
|
|
wrench = WrenchController(device_config=device_config)
|
|||
|
|
is_online = wrench.connect()
|
|||
|
|
|
|||
|
|
if is_online:
|
|||
|
|
wrench.disconnect()
|
|||
|
|
# 更新设备状态为在线
|
|||
|
|
db.update_wrench_device_status(device_id, 'online')
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "设备在线",
|
|||
|
|
"data": {
|
|||
|
|
"status": "online"
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
# 更新设备状态为离线
|
|||
|
|
db.update_wrench_device_status(device_id, 'offline')
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "设备离线",
|
|||
|
|
"data": {
|
|||
|
|
"status": "offline"
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
except Exception as e:
|
|||
|
|
# 连接失败,更新为离线
|
|||
|
|
db.update_wrench_device_status(device_id, 'offline')
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": f"检测失败: {str(e)}",
|
|||
|
|
"data": {
|
|||
|
|
"status": "offline"
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/wrench-devices/<int:device_id>/query-sn', methods=['POST'])
|
|||
|
|
def query_device_sn(device_id):
|
|||
|
|
"""查询设备SN码"""
|
|||
|
|
device = db.get_wrench_device(device_id)
|
|||
|
|
if not device:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "设备不存在"
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
device_config = {
|
|||
|
|
"ip_address": device.get('ip_address'),
|
|||
|
|
"port": device.get('port', 7888),
|
|||
|
|
"address_code": device.get('address_code', 1)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
wrench = WrenchController(device_config=device_config)
|
|||
|
|
if wrench.connect():
|
|||
|
|
sn = wrench.query_device_sn()
|
|||
|
|
wrench.disconnect()
|
|||
|
|
|
|||
|
|
if sn:
|
|||
|
|
# 更新设备SN码
|
|||
|
|
db.update_wrench_device_sn(device_id, sn)
|
|||
|
|
# 同时更新状态为在线
|
|||
|
|
db.update_wrench_device_status(device_id, 'online')
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "查询成功",
|
|||
|
|
"data": {
|
|||
|
|
"device_sn": sn,
|
|||
|
|
"status": "online"
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "查询SN码失败"
|
|||
|
|
}), 500
|
|||
|
|
else:
|
|||
|
|
db.update_wrench_device_status(device_id, 'offline')
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "无法连接到设备"
|
|||
|
|
}), 500
|
|||
|
|
except Exception as e:
|
|||
|
|
db.update_wrench_device_status(device_id, 'offline')
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": f"查询失败: {str(e)}"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/work-results', methods=['GET'])
|
|||
|
|
def get_work_results():
|
|||
|
|
"""
|
|||
|
|
查询工单执行结果
|
|||
|
|
参数: trace_id (追溯号), process_id (工序号)
|
|||
|
|
如果两个参数都提供,返回指定工单的结果
|
|||
|
|
如果只提供一个参数,返回符合该条件的所有结果
|
|||
|
|
如果都不提供,返回所有结果
|
|||
|
|
"""
|
|||
|
|
trace_id = request.args.get('trace_id')
|
|||
|
|
process_id = request.args.get('process_id')
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
if trace_id and process_id:
|
|||
|
|
# 查询指定追溯号和工序号的结果(返回单个结果)
|
|||
|
|
result = db.get_work_result(trace_id, process_id)
|
|||
|
|
if result:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "查询成功",
|
|||
|
|
"data": result
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": "未找到执行结果",
|
|||
|
|
"data": None
|
|||
|
|
}), 404
|
|||
|
|
else:
|
|||
|
|
# 查询结果列表
|
|||
|
|
results = db.get_work_results(trace_id, process_id)
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "查询成功",
|
|||
|
|
"data": results,
|
|||
|
|
"count": len(results)
|
|||
|
|
})
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"[ERROR] 查询执行结果异常: {e}")
|
|||
|
|
import traceback
|
|||
|
|
traceback.print_exc()
|
|||
|
|
return jsonify({
|
|||
|
|
"success": False,
|
|||
|
|
"message": f"查询失败: {str(e)}",
|
|||
|
|
"data": []
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@app.route('/api/health', methods=['GET'])
|
|||
|
|
def health_check():
|
|||
|
|
"""健康检查"""
|
|||
|
|
return jsonify({
|
|||
|
|
"success": True,
|
|||
|
|
"message": "服务运行正常",
|
|||
|
|
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
# 检查数据库是否为空,如果为空则从JSON导入数据
|
|||
|
|
orders = db.get_work_orders()
|
|||
|
|
if not orders and os.path.exists("work_orders.json"):
|
|||
|
|
print("检测到数据库为空,正在从JSON文件导入数据...")
|
|||
|
|
try:
|
|||
|
|
with open("work_orders.json", 'r', encoding='utf-8') as f:
|
|||
|
|
json_orders = json.load(f)
|
|||
|
|
count = 0
|
|||
|
|
for order in json_orders:
|
|||
|
|
if db.create_work_order(order):
|
|||
|
|
count += 1
|
|||
|
|
print(f"[OK] 成功导入 {count}/{len(json_orders)} 个工单")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"[FAIL] 导入失败: {e}")
|
|||
|
|
import traceback
|
|||
|
|
traceback.print_exc()
|
|||
|
|
|
|||
|
|
print("="*60)
|
|||
|
|
print("电动扳手后端API服务器")
|
|||
|
|
print("="*60)
|
|||
|
|
print("启动服务器...")
|
|||
|
|
print("API地址: http://localhost:5000")
|
|||
|
|
print("数据库: wrench.db")
|
|||
|
|
|
|||
|
|
# 显示当前工单数量
|
|||
|
|
total_orders = len(db.get_work_orders())
|
|||
|
|
print(f"当前工单数量: {total_orders}")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
|||
|
|
|