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)
|
||
|