775 lines
36 KiB
Python
775 lines
36 KiB
Python
import sqlite3
|
||
from flask import jsonify, request, g, json, Flask
|
||
import serial.tools.list_ports
|
||
from flask_cors import CORS, cross_origin
|
||
import threading, os, sys, platform
|
||
import time, datetime
|
||
|
||
# 0--每个方向含 跌落高度 和 跌落周期,单独存放在TestReq中, 1-- 只包含所有的方向代码,存储在DutList中
|
||
# 2--跌落方向在PLC设置,上位机负责读取,产品系列号,项目代号,阶段,测试周次上位机传给PLC
|
||
# 3--基本同2,只是用于测试,testReqList由方式1产生
|
||
dutDirectionMode = 2
|
||
dtMachineService = None
|
||
# 在全局或应用上下文中缓存表结构(示例使用全局字典)
|
||
TABLE_SCHEMA_CACHE = {}
|
||
|
||
app = Flask(__name__, static_folder='web')
|
||
app.config['SECRET_KEY'] = 'secret!'
|
||
# 关闭所有的日志记录
|
||
app.logger.disabled = True
|
||
|
||
CORS(app) # 这会让所有的资源都支持跨域访问
|
||
CORS(app, resources=r"/*")
|
||
|
||
|
||
def set_machine_service(machine_service):
|
||
global dtMachineService
|
||
dtMachineService = machine_service
|
||
|
||
|
||
def is_json_serializable(value):
|
||
try:
|
||
json.dumps(value)
|
||
return True
|
||
except (TypeError, OverflowError):
|
||
print(TypeError, OverflowError)
|
||
return False
|
||
|
||
|
||
def get_cached_table_schema(table_name, db_conn):
|
||
"""带缓存的表结构获取"""
|
||
if table_name not in TABLE_SCHEMA_CACHE:
|
||
# 未缓存时从数据库读取
|
||
cursor = db_conn.execute(f"PRAGMA table_info({table_name})")
|
||
schema = {}
|
||
for row in cursor.fetchall():
|
||
schema[row[1]] = {
|
||
'type': row[2].upper(),
|
||
'is_pk': row[5] > 0
|
||
}
|
||
TABLE_SCHEMA_CACHE[table_name] = schema
|
||
return TABLE_SCHEMA_CACHE[table_name]
|
||
|
||
|
||
# 设置跌落机的试验参数
|
||
@app.route('/machine_control', methods=['POST'])
|
||
@cross_origin()
|
||
def machine_control():
|
||
global dtm_machines, dtMachineService
|
||
params = request.json
|
||
value_return = {"status": "error"}
|
||
actionParam = {}
|
||
dtMachineService.setMachineBusyFlag(True)
|
||
# 检测键是否存在
|
||
if 'setParams' in params: # 设置工作站(台)测试执行参数
|
||
value_return = {"status": "error", "msg": "setParams error"}
|
||
setParams = params['setParams']
|
||
actionParam = setParams
|
||
print("machine_control setParams", setParams) # cyx
|
||
# 使用 set 检测多个键是否存在
|
||
for setParam in setParams:
|
||
required_keys = {'machine', 'com', 'station'}
|
||
if required_keys.issubset(setParam.keys()):
|
||
if 'dropHeight' in setParam:
|
||
try:
|
||
dtMachineSN = setParam['machine']
|
||
result = dtMachineService.set_station_dropheight(dtMachineSN, setParam['station'],
|
||
int(setParam['dropHeight']))
|
||
except Exception as error:
|
||
value_return = {'status': "error", "message": "set station dropHeght ", "error": error}
|
||
if 'status' in result and result['status'] == 'success':
|
||
value_return = {'status': "success", 'message': "set station dropHeight success"}
|
||
pass
|
||
if 'dropCycles' in setParam:
|
||
try:
|
||
dtMachineSN = setParam['machine']
|
||
result = dtMachineService.set_station_cycles(dtMachineSN, setParam['station'],
|
||
setParam['dropCycles'])
|
||
print("machine_control setParams set cycles return ", result) # cyx
|
||
except Exception as error:
|
||
value_return = {'status': "error", "message": "set station dropCycles ", "error": error}
|
||
if 'status' in result and result['status'] == 'success':
|
||
value_return = {'status': "success", 'message': "set station dropCycles success"}
|
||
if 'cyclesFinished' in setParam:
|
||
try:
|
||
dtMachineSN = setParam['machine']
|
||
result = dtMachineService.set_station_finished(dtMachineSN, setParam['station'],
|
||
setParam['cyclesFinished'])
|
||
except Exception as error:
|
||
value_return = {'status': "error", "message": "set station cyclesFinished ",
|
||
"error": error}
|
||
if 'status' in result and result['status'] == 'success':
|
||
value_return = {'status': "success", 'message': "set station cyclesFinished success"}
|
||
pass
|
||
# return value_return
|
||
|
||
if 'start' in params or 'stop' in params or 'resume' in params or 'pause' in params or 'cancel' in params \
|
||
or 'reset' in params:
|
||
# 启动 停止 继续 取消 暂停 工作站(台)
|
||
value_return = {'status': "error", 'message': "station start stop resume error"}
|
||
param = None
|
||
if 'start' in params:
|
||
param = params['start']
|
||
if 'stop' in params:
|
||
param = params['stop']
|
||
if 'cancel' in params:
|
||
param = params['cancel']
|
||
if 'resume' in params:
|
||
param = params['resume']
|
||
if 'pause' in params:
|
||
param = params['pause']
|
||
if 'reset' in params:
|
||
param = params['reset']
|
||
actionParam = param
|
||
# 使用 set 检测多个键是否存在
|
||
required_keys = {'machine', 'station'}
|
||
if required_keys.issubset(param.keys()):
|
||
# 将前端发送的 start resume stop cancel pause 等命令统一按照dtStationAttachDut 处理,以便
|
||
# 统一处理工位 机台 试验样品 试验要求的状态
|
||
if 'start' in params:
|
||
return dtMachineService.dtStationAttachDut(param['machine'], param['station'], 'start', None, True)
|
||
|
||
if 'resume' in params:
|
||
return dtMachineService.dtStationAttachDut(param['machine'], param['station'], 'resume', None, True)
|
||
|
||
if 'stop' in params:
|
||
return dtMachineService.dtStationDetachDut(param['machine'], param['station'], 'stop')
|
||
|
||
if 'cancel' in params:
|
||
return dtMachineService.dtStationDetachDut(param['machine'], param['station'], 'cancel')
|
||
|
||
if 'pause' in params:
|
||
return dtMachineService.dtStationAttachDut(param['machine'], param['station'], 'pause', None, True)
|
||
|
||
if 'reset' in params:
|
||
return dtMachineService.dtStationDetachDut(param['machine'], param['station'], 'reset')
|
||
else:
|
||
# print("键 'machine', 'com', 'station', 'params' 不完全存在于 JSON 中")
|
||
pass
|
||
# return jsonify(value_return)
|
||
|
||
if 'getParams' in params:
|
||
value_return = {'status': "error", 'message': "get station params error"}
|
||
param = params['getParams']
|
||
print("machine_control post", params)
|
||
# 使用 set 检测多个键是否存在q
|
||
required_keys = {'machine', 'com', 'station'}
|
||
if required_keys.issubset(param.keys()):
|
||
if 'all' not in param and 'machine' in param:
|
||
try:
|
||
dtMachineSN = param['machine']
|
||
result = dtMachineService.read_station_cyclesFinished(dtMachineSN, param['station'])
|
||
if 'status' in result and result['status'] == 'success' and 'value' in result:
|
||
value_return["status"] = "success"
|
||
value_return["action"] = "getParams"
|
||
value_return["finished"] = result['value']
|
||
value_return["message"] = "get station params success"
|
||
except Exception as error:
|
||
value_return["error"] = error
|
||
pass
|
||
# return jsonify(value_return)
|
||
|
||
if 'getStationValue' in params: # 获取机器工作站(台)的状态与数据
|
||
value_return = {'status': "error", 'message': "get station params error"}
|
||
param = params['getStationValue']
|
||
# 使用 set 检测多个键是否存在q
|
||
required_keys = {'machine', 'station'}
|
||
if 'station' in param and 'machine' in param:
|
||
if dtMachineService:
|
||
result = dtMachineService.get_station_value(param['machine'], param['station'])
|
||
value_return = result
|
||
else:
|
||
value_return = {"status": "error", "msg": "machine service is not available"}
|
||
# print("键 'machine', 'com', 'station', 'params' 不完全存在于 JSON 中")
|
||
pass
|
||
|
||
# return jsonify(value_return)
|
||
|
||
if 'getMachinesValue' in params: # 获取机器的状态与数据
|
||
|
||
value_return = {'status': "error", 'message': "get station params error"}
|
||
param = params['getMachinesValue']
|
||
# print("/machine_control getMachinesValue", dtMachineService, param)
|
||
if 'machines' in param:
|
||
if dtMachineService:
|
||
result = dtMachineService.get_machines_value(param['machines'])
|
||
value_return = result
|
||
else:
|
||
value_return = {"status": "error", "msg": "machine service is not available"}
|
||
# print("键 'machine', 'com', 'station', 'params' 不完全存在于 JSON 中")
|
||
pass
|
||
current_time = datetime.datetime.now().strftime('%H:%M:%S.%f')[:-3]
|
||
# return jsonify(value_return)
|
||
|
||
if 'attachDut' in params: # 将测试样品与机器的工作站(台)关联
|
||
value_return = {'status': "error", 'message': "station attach dut error"}
|
||
param = params['attachDut']
|
||
if 'machine' in param and 'station' in param and 'dut' in param and 'action' in param:
|
||
station_sn = param['station']
|
||
machine_sn = param['machine']
|
||
dut_sn = param['dut']
|
||
action = param['action']
|
||
updateTableFlag = param['updateTableFlag']
|
||
userid = param.get('userid', None) # 安排试验的用户id
|
||
result = dtMachineService.dtStationAttachDut(machine_sn, station_sn, action, dut_sn, updateTableFlag,
|
||
userid)
|
||
# print("machine control attachDut",params)
|
||
if 'status' in result and result['status'] == 'success':
|
||
value_return = {'status': "success", 'message': "station attach dut success"}
|
||
if 'station' in result:
|
||
value_return['station'] = result['station']
|
||
# return jsonify(value_return)
|
||
|
||
if 'detachDut' in params: # 测试样品与机器的工作站(台)断开关联
|
||
value_return = {'status': "error", 'message': "station detach dut error"}
|
||
param = params['detachDut']
|
||
if 'machine' in param and 'station' in param and 'action' in param:
|
||
station_sn = param['station']
|
||
machine_sn = param['machine']
|
||
action = param['action']
|
||
result = dtMachineService.dtStationDetachDut(machine_sn, station_sn, action)
|
||
if 'status' in result and result['status'] == 'success':
|
||
value_return = {'status': "success", 'message': "station detach dut success"}
|
||
if 'station' in result:
|
||
value_return['station'] = result['station']
|
||
# return jsonify(value_return)
|
||
|
||
if 'assignTestReq' in params: # 设置测试要求
|
||
value_return = {'status': "error", 'message': "station assign testReq error"}
|
||
param = params['assignTestReq']
|
||
if 'machine' in param and 'station' in param and 'dut' in param and 'testReqIndex' in param:
|
||
station_sn = param['station']
|
||
machine_sn = param['machine']
|
||
dut_sn = param['dut']
|
||
testReqIndex = param['testReqIndex'] # 测试样件的测试项目index
|
||
result = dtMachineService.dtStationAssignTestReq(machine_sn, station_sn, dut_sn, testReqIndex)
|
||
if 'status' in result and result['status'] == 'success':
|
||
value_return = {'status': "success", 'message': "station assign testReq success"}
|
||
if 'station' in result:
|
||
value_return['station'] = result['station']
|
||
return value_return
|
||
if 'registerTest' in params: # PLC 寄存器测试
|
||
value_return = {'status': "error", 'message': "register read or write test error"}
|
||
param = params['registerTest']
|
||
# 使用 set 检测多个键是否存在q
|
||
required_keys = {'machine', 'station'}
|
||
if 'machine' in param and 'action' in param and 'address' in param:
|
||
if dtMachineService:
|
||
result = dtMachineService.register_test(param['machine'], param['action'], param['address'],
|
||
param.get('value', None))
|
||
value_return = result
|
||
print("register_test result:", result) # cyx
|
||
else:
|
||
value_return = {"status": "error", "msg": "machine service is not available"}
|
||
# print("键 'machine', 'com', 'station', 'params' 不完全存在于 JSON 中")
|
||
pass
|
||
# return jsonify(value_return)
|
||
dtMachineService.setMachineBusyFlag(False)
|
||
|
||
return jsonify(value_return)
|
||
|
||
|
||
# 设置跌落机的试验参数
|
||
@app.route('/get_machine_config', methods=['GET'])
|
||
@cross_origin()
|
||
def get_machine_config():
|
||
global dtm_machines, dtMachineService
|
||
json_return = {"status": "error"}
|
||
print("get machine_config")
|
||
if dtMachineService:
|
||
json_return = {"status": "success", "data": dtMachineService.get_machine_com_config()}
|
||
return jsonify(json_return)
|
||
|
||
|
||
# 设置跌落机的试验参数
|
||
@app.route('/get_com_list', methods=['POST'])
|
||
@cross_origin()
|
||
def get_com_list():
|
||
json_return = {"status": "error"}
|
||
ports = []
|
||
try:
|
||
for port in serial.tools.list_ports.comports():
|
||
ports.append(port.name)
|
||
json_return = {"status": "success", "data": ports}
|
||
except Exception as error:
|
||
json_return = {"status": "error", "message": "get com ports list error" + error}
|
||
return jsonify(json_return)
|
||
|
||
|
||
@app.route('/dbTableAccess', methods=['GET', 'POST'])
|
||
@cross_origin()
|
||
def access_table_data():
|
||
global date_span_str
|
||
table = request.args.get('table')
|
||
pageSize = request.args.get('pageSize', default=None, type=int)
|
||
currentPage = request.args.get('currentPage', default=None, type=int)
|
||
# print(f"/dbTableAccess table={table} method ={request.method} pageSize={pageSize} currentPage={currentPage}")
|
||
db_path = os.path.join('db', 'dtmgtDb.db')
|
||
if table is None:
|
||
return jsonify({"error": "Table parameter is missing"}), 400
|
||
if g is None:
|
||
db = sqlite3.connect(db_path)
|
||
elif hasattr(g, 'db') == False:
|
||
db = sqlite3.connect(db_path)
|
||
else:
|
||
db = g.db
|
||
if request.method == 'GET':
|
||
sql_condition_str = ""
|
||
sql_params = []
|
||
parameters_to_check = []
|
||
if table == 'dutList':
|
||
parameters_to_check = ['name', 'SN', 'description', 'status', 'stationAssigned', 'machineAssigned']
|
||
if table == 'dropDirection':
|
||
parameters_to_check = ['code', 'label']
|
||
if table == 'testReq':
|
||
parameters_to_check = ['SN', 'dropItem', 'dropHeight', 'dropCycles', 'description', 'status']
|
||
if table == 'project':
|
||
parameters_to_check = ['name', 'key', 'manager', 'type', 'description']
|
||
if table == 'projectPhase':
|
||
parameters_to_check = ['name', 'PN', 'description']
|
||
if table == 'dtMachine':
|
||
parameters_to_check = ['label', 'SN', 'status', 'type', 'color', 'description', 'plc_address']
|
||
if table == 'testReqResult':
|
||
parameters_to_check = ['SN', 'id', 'dropItem', 'dropHeight', 'dropCycles', 'description', 'status',
|
||
'userid', 'workOrder', 'inspector']
|
||
|
||
def get_parameter(param):
|
||
param_sql = ""
|
||
param_value = request.args.getlist(param)
|
||
if param in ["SN", "id", 'status'] and table == "testReqResult":
|
||
param = f"testReq.{param}"
|
||
if param in ["workOrder", "inspector"] and table == "testReqResult":
|
||
param = f"dutList.{param}"
|
||
"""
|
||
if param_value and param == "workOrder" and table == "testReqResult":
|
||
param_sql = (
|
||
f'AND dutList.workOrder IS NOT NULL '
|
||
f"AND dutList.{param} IN ({','.join(['?'] * len(param_value))})"
|
||
)
|
||
elif param_value and param == "inspector" and table == "testReqResult":
|
||
param_sql = (
|
||
f'AND dutList.inspector IS NOT NULL '
|
||
f"AND dutList.{param} IN ({','.join(['?'] * len(param_value))})"
|
||
)
|
||
|
||
"""
|
||
if param_value and param != 'stationAssigned':
|
||
param_sql = f" AND {param} IN ({','.join(['?'] * len(param_value))})"
|
||
else:
|
||
pass
|
||
if param_value and param == 'stationAssigned':
|
||
# param_sql = f" AND json_extract({param}, '$.dtMachine') IN ({','.join(['?'] * len(param_value))})" # cyx 2024 11 07 修改
|
||
try:
|
||
station_data = json.loads(param_value[0])
|
||
# 将传入的 JSON 字符串解析为 Python 字典
|
||
if 'dtMachine' in station_data and 'station' in station_data:
|
||
# 同时匹配 JSON 和其他情况
|
||
param_sql = (
|
||
f" AND (CASE WHEN json_valid({param}) THEN "
|
||
f"(json_extract({param}, '$.dtMachine') = ? AND json_extract({param}, '$.station') = ?) "
|
||
f"ELSE 1 END)"
|
||
)
|
||
param_value = [station_data['dtMachine'], station_data['station']]
|
||
elif 'dtMachine' in station_data:
|
||
# 仅匹配 JSON 的 dtMachine
|
||
param_sql = (
|
||
f" AND (CASE WHEN json_valid({param}) THEN "
|
||
f"json_extract({param}, '$.dtMachine') = ? ELSE 1 END)"
|
||
)
|
||
param_value = [station_data['dtMachine']]
|
||
elif 'station' in station_data:
|
||
# 仅匹配 JSON 的 station
|
||
param_sql = (
|
||
f" AND (CASE WHEN json_valid({param}) THEN "
|
||
f"json_extract({param}, '$.station') = ? ELSE 1 END)"
|
||
)
|
||
param_value = [station_data['station']]
|
||
finally:
|
||
pass
|
||
if param_value and param == 'machineAssigned':
|
||
param = 'stationAssigned'
|
||
try:
|
||
# 动态构建 IN 子句
|
||
placeholders = ','.join(['?'] * len(param_value))
|
||
param_sql = (
|
||
f" AND (CASE WHEN json_valid({param}) THEN "
|
||
f"json_extract({param}, '$.dtMachine') IN ({placeholders}) "
|
||
f"ELSE 1 END)"
|
||
)
|
||
except (json.JSONDecodeError, TypeError):
|
||
# 如果解析 JSON 失败,则生成默认匹配条件
|
||
param_sql = " AND 1 = 1"
|
||
param_value = []
|
||
# param_sql = f" AND json_extract({param}, '$.dtMachine') IN ({','.join(['?'] * len(param_value))})" # cyx 2024 11 07 修改
|
||
return param_sql, param_value
|
||
|
||
current_time = datetime.datetime.now().strftime('%H:%M:%S.%f')[:-3]
|
||
for param in parameters_to_check:
|
||
param_sql, param_value = get_parameter(param)
|
||
sql_condition_str += param_sql
|
||
sql_params.extend(param_value)
|
||
|
||
current_time = datetime.datetime.now().strftime('%H:%M:%S.%f')[:-3]
|
||
try:
|
||
total_count = 0
|
||
if table == 'testReqResult':
|
||
"""select_sql_str = (
|
||
f'SELECT testReq.* , dutList.project, dutList.phase , dutList.stationAssigned, '
|
||
f'dutList.name ,dutList.SN as dutSN, dutList.weeks, dutList.workOrder,dutList.inspector, '
|
||
f'dutList.projectType as projectType,project.name as ProjectName, projectPhase.name as projectPhase '
|
||
f'FROM testReq LEFT JOIN dutList ON testReq.SN = dutList.SN '
|
||
f'LEFT JOIN project ON dutList.project = project.key '
|
||
f'LEFT JOIN projectPhase ON dutList.phase = projectPhase.PN '
|
||
f'WHERE testReq.id > 0 '
|
||
)"""
|
||
select_sql_str = (
|
||
f'SELECT * from TestReq '
|
||
f'WHERE TestReq.id > 0 '
|
||
)
|
||
|
||
elif table == 'dutList' or table == 'DUTList':
|
||
select_sql_str = (
|
||
f'SELECT dutList.* , project.name AS projectName, projectPhase.name AS projectPhase '
|
||
f'FROM DUTList '
|
||
f'LEFT JOIN '
|
||
f'project ON dutList.project = project.key '
|
||
f'LEFT JOIN '
|
||
f'projectPhase ON dutList.phase = projectPhase.PN '
|
||
f'WHERE {table}.id>0 '
|
||
)
|
||
else:
|
||
select_sql_str = f"SELECT * FROM {table} WHERE {table}.id > 0 "
|
||
|
||
if table == 'testReqResult':
|
||
date_span_str = ""
|
||
if request.args.get('date1') and request.args.get('date2'):
|
||
try:
|
||
# 将这些字符串转化为日期对象
|
||
# 前端传入类似 date1: '2023/11/10 10:10:00', date2: '2024/6/11 10:10:00'
|
||
start_date_obj = datetime.datetime.strptime(request.args.get('date1'), "%Y/%m/%d %H:%M:%S")
|
||
end_date_obj = datetime.datetime.strptime(request.args.get('date2'), "%Y/%m/%d %H:%M:%S")
|
||
|
||
# 然后,将这些日期对象转化为字符串,以符合数据库中日期字段的格式
|
||
formatted_start_date = start_date_obj.strftime('%Y-%m-%d %H:%M:%S')
|
||
formatted_end_date = end_date_obj.strftime('%Y-%m-%d %H:%M:%S')
|
||
date_span_str = f" AND STRFTIME('%Y-%m-%d %H:%M:%S',TestReq.endTime) BETWEEN '{formatted_start_date}' AND '{formatted_end_date}'"
|
||
except Exception as error:
|
||
print("error=", error)
|
||
finally:
|
||
sql_condition_str = sql_condition_str + date_span_str
|
||
|
||
if pageSize and currentPage:
|
||
cursor = db.cursor()
|
||
if table == 'testReqResult':
|
||
sql_count = (
|
||
f"SELECT COUNT(*) FROM TestReq LEFT JOIN dutList ON testReq.SN = dutList.SN WHERE testReq.id >0 " + sql_condition_str
|
||
)
|
||
cursor.execute(sql_count, sql_params)
|
||
else:
|
||
cursor.execute(f"SELECT COUNT(*) FROM {table} WHERE id >0 " + sql_condition_str, sql_params)
|
||
total_count = cursor.fetchone()[0]
|
||
if pageSize and currentPage:
|
||
sql_condition_str = sql_condition_str + f' LIMIT {pageSize} OFFSET {pageSize * (currentPage - 1)}'
|
||
if table == 'dutList' or table == 'DUTList':
|
||
# sql_str = sql_str + f" ORDER BY date(createdate) DESC"
|
||
pass
|
||
current_time = datetime.datetime.now().strftime('%H:%M:%S.%f')[:-3]
|
||
|
||
# print(f"{current_time} dbTableAccess {table} [select sql_str:]", select_sql_str,
|
||
# "[condition:]", sql_condition_str, "[sql_paramms:]", sql_params) # cyx
|
||
cursor = db.cursor()
|
||
cursor.execute(select_sql_str + sql_condition_str, sql_params)
|
||
"""
|
||
else:
|
||
if pageSize and currentPage:
|
||
sql_str = sql_str + f' LIMIT {pageSize} OFFSET {pageSize * (currentPage - 1)}'
|
||
print("dbTableAccess sql_str", sql_str, sql_params) # cyx
|
||
cursor = db.cursor()
|
||
cursor.execute(sql_str, sql_params)
|
||
"""
|
||
|
||
except sqlite3.Error as e:
|
||
print(f"dbTableAccess {table} error={e}") # cyx
|
||
return jsonify({"error": f"Database error: {e}"}), 500
|
||
|
||
rows = cursor.fetchall()
|
||
column_names = [description[0] for description in cursor.description]
|
||
result = []
|
||
|
||
for index,row in enumerate(rows):
|
||
dict_row = {col: row[idx] if row[idx] is not None else None for idx, col in enumerate(column_names)}
|
||
dict_row['mysequence'] = index + 1 # 添加序号
|
||
if 'stationAssigned' in dict_row:
|
||
try:
|
||
station_assigned_json = json.loads(dict_row['stationAssigned'])
|
||
if station_assigned_json:
|
||
dict_row['dtMachine'] = station_assigned_json['dtMachine']
|
||
dict_row['station'] = station_assigned_json['station']
|
||
if dict_row.get('direction_codes'):
|
||
dict_row['direction_codes'] = json.loads(dict_row['direction_codes'])
|
||
except Exception as e:
|
||
dict_row['dtMachine'] = ""
|
||
dict_row['station'] = ""
|
||
dict_row['stationAssigned'] = None
|
||
finally:
|
||
pass
|
||
result.append(dict_row)
|
||
|
||
return jsonify({'totalCount': total_count, 'length': len(rows), 'data': result})
|
||
|
||
elif request.method == 'POST':
|
||
data = request.get_json()
|
||
action = data['action']
|
||
records = data['records']
|
||
for record in records: # 将direction_codes 转换为字符串
|
||
if record.get('direction_codes'):
|
||
try:
|
||
record['direction_codes'] = json.dumps(record.get('direction_codes'))
|
||
except Exception as e:
|
||
record['direction_codes'] = '[]'
|
||
continue
|
||
|
||
if action is None:
|
||
return jsonify({"status": "error", "message": "action is not specified"})
|
||
"""
|
||
elif action == "insert":
|
||
try:
|
||
with db:
|
||
cursor = db.cursor()
|
||
current_date = datetime.datetime.now().strftime('%Y-%m-%d')
|
||
for record in records:
|
||
if 'id' in record:
|
||
del record['id']
|
||
columns = ', '.join(record.keys())
|
||
placeholders = ', '.join('?' for _ in record)
|
||
sql = f'INSERT INTO {table} ({columns}) VALUES ({placeholders})'
|
||
cursor.execute(sql, tuple(record.values()))
|
||
# db.commit()
|
||
return jsonify(
|
||
{"status": "success", "action": "insert", "message": f"insert records into {table} success",
|
||
"recordsCnt": len(records)})
|
||
except sqlite3.Error as error:
|
||
print(f'insert {table} error {error}')
|
||
return jsonify(
|
||
{"status": "error", "action": "insert", "message": f"insert records into {table} error"})
|
||
"""
|
||
if action == "insert":
|
||
try:
|
||
with db:
|
||
cursor = db.cursor()
|
||
# 从缓存获取表结构(首次访问时自动填充缓存)
|
||
table_schema = get_cached_table_schema(table, db)
|
||
# 数据清洗
|
||
sanitized_records = []
|
||
for record in records:
|
||
clean_record = {}
|
||
for key, value in record.items():
|
||
# 字段存在性检查
|
||
if key not in table_schema:
|
||
continue
|
||
|
||
# 自增主键跳过
|
||
if table_schema[key]['is_pk']:
|
||
continue
|
||
|
||
# 类型转换
|
||
try:
|
||
target_type = table_schema[key]['type']
|
||
if target_type == 'INTEGER':
|
||
clean_record[key] = int(value) if value not in (None, '') else None
|
||
elif target_type == 'TEXT':
|
||
clean_record[key] = str(value) if value is not None else None
|
||
elif target_type == 'REAL':
|
||
clean_record[key] = float(value) if value not in (None, '') else None
|
||
else:
|
||
clean_record[key] = value
|
||
except (ValueError, TypeError):
|
||
clean_record[key] = None # 转换失败设为NULL
|
||
sanitized_records.append(clean_record)
|
||
|
||
# 动态构建插入语句(所有记录取字段并集)
|
||
all_fields = set()
|
||
for rec in sanitized_records:
|
||
all_fields.update(rec.keys())
|
||
if not all_fields:
|
||
return jsonify({"status": "error", "message": "No valid fields to insert"})
|
||
|
||
# 按字段名排序保证参数顺序一致
|
||
sorted_fields = sorted(all_fields)
|
||
sql = f"INSERT INTO {table} ({','.join(sorted_fields)}) VALUES ({','.join(['?'] * len(sorted_fields))})"
|
||
|
||
# 准备参数列表
|
||
params = []
|
||
for rec in sanitized_records:
|
||
params.append(tuple(rec.get(field) for field in sorted_fields))
|
||
|
||
# 批量执行
|
||
cursor.executemany(sql, params)
|
||
|
||
return jsonify(
|
||
{"status": "success", "action": "insert", "message": f"insert records into {table} success",
|
||
"recordsCnt": len(records)})
|
||
except sqlite3.Error as error:
|
||
print(f'insert {table} error {error}')
|
||
return jsonify(
|
||
{"status": "error", "action": "insert", "message": f"insert records into {table} error"})
|
||
elif action == "update":
|
||
try:
|
||
update_key = 'PN'
|
||
if table == 'dutList':
|
||
update_key = 'SN'
|
||
if table == 'dropDirection':
|
||
update_key = 'code'
|
||
if table == 'testReq':
|
||
update_key = 'id'
|
||
if table == 'project':
|
||
update_key = 'key'
|
||
if table == 'projectPhase':
|
||
update_key = 'PN'
|
||
if table == 'dtMachine':
|
||
update_key = 'id' # 这里有bug,20251208 由 'SN'改成 'id'
|
||
if table == 'get_counter':
|
||
update_key = 'current_counter'
|
||
with db:
|
||
cursor = db.cursor()
|
||
for record in records:
|
||
pn_value = record.get(update_key, None)
|
||
if pn_value is not None:
|
||
cursor.execute(
|
||
f'UPDATE {table} SET {", ".join(["{} = ?".format(field) for field in record])} WHERE {update_key} = ?',
|
||
tuple(record.values()) + (record[update_key],))
|
||
# db.commit()
|
||
return jsonify(
|
||
{"status": "success", "action": "update", "message": f"update records into {table} success",
|
||
"recordsCnt": len(records)})
|
||
except sqlite3.Error as error:
|
||
print('update duts error', error)
|
||
return jsonify(
|
||
{"status": "error", "action": "update", "message": f"update records into {table} error{error}"})
|
||
|
||
elif action == "delete":
|
||
try:
|
||
with db:
|
||
cursor = db.cursor()
|
||
cursor.executemany(f"DELETE FROM {table} WHERE id = ?", [(record['id'],) for record in records])
|
||
# db.commit()
|
||
return jsonify(
|
||
{"status": "success", "action": "delete", "message": f"delete {table} records success",
|
||
"recordsCnt": len(records)})
|
||
except sqlite3.Error as error:
|
||
print('delete', error)
|
||
return jsonify(
|
||
{"status": "error", "action": "delete", "message": f"delete {table} records error{error}"})
|
||
|
||
|
||
# 添加一个全局错误处理器
|
||
@app.errorhandler(500)
|
||
def internal_error(error):
|
||
return jsonify({'error': 'Internal server error'}), 500
|
||
|
||
|
||
@app.route('/shutdown', methods=['POST'])
|
||
def shutdown_flask_Server():
|
||
print("flask http server Shutting down gracefully...")
|
||
"""
|
||
def stop(self):
|
||
Stop a running SocketIO web server.
|
||
This method must be called from a HTTP or SocketIO handler function
|
||
"""
|
||
shutdown_func = request.environ.get('werkzeug.server.shutdown')
|
||
if shutdown_func is None:
|
||
print("shutdown_func is None")
|
||
pass
|
||
else:
|
||
try:
|
||
shutdown_func()
|
||
except Exception as e:
|
||
print('Error shutting down server:', str(e))
|
||
else:
|
||
print('flask Server shutting down...')
|
||
return 'flask Server shutting down...'
|
||
|
||
|
||
@app.route('/login', methods=['POST'])
|
||
@cross_origin()
|
||
def login_validate():
|
||
json_return = {"status": "error"}
|
||
params = request.json
|
||
db_path = os.path.join('db', 'dtmgtDb.db')
|
||
print("/login", params) # cyx
|
||
if params.get('username') is None or params.get('password') is None:
|
||
return jsonify({"status": "error", "error": "username or password is missing"}), 400
|
||
if g is None:
|
||
db = sqlite3.connect(db_path)
|
||
elif hasattr(g, 'db') == False:
|
||
db = sqlite3.connect(db_path)
|
||
else:
|
||
db = g.db
|
||
if params.get('username') == 'topAdmin' and params.get('password') == 'topAdmin':
|
||
json_return = {"status": "success", "username": params.get('username'),
|
||
"userid": "top999999",
|
||
"role": 'super', "auth": ""}
|
||
return jsonify(json_return)
|
||
|
||
if params.get('username') == 'topAdmin123' and params.get('password') == 'topAdmin123':
|
||
json_return = {"status": "success", "username": params.get('username'),
|
||
"userid": "top888888",
|
||
"role": 'super', "auth": ""}
|
||
return jsonify(json_return)
|
||
|
||
sql_str = f"SELECT * FROM user WHERE id > 0 and username =? and password = ?"
|
||
sql_params = [params.get('username'), params.get('password')]
|
||
try:
|
||
cursor = db.cursor()
|
||
cursor.execute(sql_str, sql_params)
|
||
rows = cursor.fetchall()
|
||
column_names = [description[0] for description in cursor.description]
|
||
result = []
|
||
for row in rows:
|
||
dict_row = {col: row[idx] if row[idx] is not None else None for idx, col in enumerate(column_names)}
|
||
result.append(dict_row)
|
||
# print("login result",result)#cyx
|
||
if len(result) == 1:
|
||
json_return = {"status": "success", "username": result[0].get('username'),
|
||
"userid": result[0].get('userid'),
|
||
"role": result[0].get('role'), "auth": result[0].get('auth')}
|
||
except sqlite3.Error as e:
|
||
print("get user info error", e) # cyx
|
||
return jsonify(json_return)
|
||
|
||
|
||
@app.route('/dutDirectionMode', methods=['GET'])
|
||
@cross_origin()
|
||
def get_dutDirectionMode():
|
||
return jsonify({"status": "success", "data": dutDirectionMode})
|
||
|
||
|
||
@app.route('/modbusServerStarted', methods=['POST'])
|
||
@cross_origin()
|
||
def modbus_server_started():
|
||
json_return = {"status": "success"}
|
||
params = request.json
|
||
print("/modbusServerStarted", params) # cyx
|
||
dtMachineService.dtm_virt_machine_client_connect()
|
||
return jsonify(json_return)
|
||
|
||
|
||
@app.before_request
|
||
def before_request():
|
||
global dtMachineService, initialized
|
||
db_path = os.path.join('db', 'dtmgtDb.db')
|
||
g.db = sqlite3.connect(db_path)
|
||
# print("open database", g.db)
|
||
|
||
|
||
"""
|
||
@app.route('/<path:path>')
|
||
@cross_origin()
|
||
def send_file(path):
|
||
print("access ",path)
|
||
if path != "" and path.endswith(".html"):
|
||
return send_from_directory(app.static_folder, path)
|
||
else:
|
||
return send_from_directory(app.static_folder, path)
|
||
"""
|