TorqueWrench/backend/app.py

535 lines
16 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/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)