Accept Merge Request #1248: (feature/优化制造功能 -> develop)
Merge Request: 优化运行信息接口、优化次数接口;增加oee接口 Created By: @马广威 Accepted By: @马广威 URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1248?initial=true
This commit is contained in:
@@ -173,49 +173,6 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
res['message'] = '前端请求机床数据失败,原因:%s' % e
|
res['message'] = '前端请求机床数据失败,原因:%s' % e
|
||||||
return json.JSONEncoder().encode(res)
|
return json.JSONEncoder().encode(res)
|
||||||
|
|
||||||
# @http.route('/api/logs/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
|
|
||||||
# cors="*")
|
|
||||||
# def logs_list(self, **kw):
|
|
||||||
# """
|
|
||||||
# 拿到日志数据返回给大屏展示
|
|
||||||
# :param kw:
|
|
||||||
# :return:
|
|
||||||
# """
|
|
||||||
# res = {'status': 1, 'message': '成功', 'data': []}
|
|
||||||
# logging.info('前端请求日志数据的参数为:%s' % kw)
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# # 获取请求的日志数据
|
|
||||||
# logs_obj = request.env['maintenance.equipment.oee.log.detail'].sudo()
|
|
||||||
# # 获取请求的机床数据
|
|
||||||
# machine_list = ast.literal_eval(kw['machine_list'])
|
|
||||||
# begin_time_str = kw['begin_time'].strip('"')
|
|
||||||
# end_time_str = kw['end_time'].strip('"')
|
|
||||||
#
|
|
||||||
# begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
|
|
||||||
# end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
|
|
||||||
#
|
|
||||||
# print('begin_time: %s' % begin_time)
|
|
||||||
# for item in machine_list:
|
|
||||||
# log_datas = logs_obj.search(
|
|
||||||
# [('equipment_code', '=', item), ('time', '>=', begin_time), ('time', '<=', end_time)])
|
|
||||||
# print('log_datas: %s' % log_datas)
|
|
||||||
# for log_data in log_datas:
|
|
||||||
# res['data'].append({
|
|
||||||
# 'equipment_code': log_data.equipment_code,
|
|
||||||
# 'time': log_data.time.strftime('%Y-%m-%d %H:%M:%S'),
|
|
||||||
# 'state': log_data.state
|
|
||||||
#
|
|
||||||
# })
|
|
||||||
#
|
|
||||||
# return json.JSONEncoder().encode(res)
|
|
||||||
#
|
|
||||||
# except Exception as e:
|
|
||||||
# logging.info('前端请求日志数据失败,原因:%s' % e)
|
|
||||||
# res['status'] = -1
|
|
||||||
# res['message'] = '前端请求日志数据失败,原因:%s' % e
|
|
||||||
# return json.JSONEncoder().encode(res)
|
|
||||||
|
|
||||||
@http.route('/api/logs/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
@http.route('/api/logs/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
def logs_list(self, **kw):
|
def logs_list(self, **kw):
|
||||||
"""
|
"""
|
||||||
@@ -227,9 +184,9 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
logging.info('前端请求日志数据的参数为:%s' % kw)
|
logging.info('前端请求日志数据的参数为:%s' % kw)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 获取请求的日志数据
|
# 连接数据库
|
||||||
logs_obj = request.env['maintenance.equipment.oee.log.detail'].sudo()
|
conn = psycopg2.connect(**db_config)
|
||||||
# 获取请求的机床数据
|
cur = conn.cursor()
|
||||||
machine_list = ast.literal_eval(kw['machine_list'])
|
machine_list = ast.literal_eval(kw['machine_list'])
|
||||||
begin_time_str = kw['begin_time'].strip('"')
|
begin_time_str = kw['begin_time'].strip('"')
|
||||||
end_time_str = kw['end_time'].strip('"')
|
end_time_str = kw['end_time'].strip('"')
|
||||||
@@ -240,19 +197,25 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
print('begin_time: %s' % begin_time)
|
print('begin_time: %s' % begin_time)
|
||||||
|
|
||||||
for item in machine_list:
|
for item in machine_list:
|
||||||
log_datas = logs_obj.search(
|
sql = '''
|
||||||
[('equipment_code', '=', item), ('time', '>=', begin_time), ('time', '<=', end_time)])
|
SELECT time, device_state, program_name
|
||||||
print('log_datas: %s' % log_datas)
|
FROM device_data
|
||||||
|
WHERE device_name = %s AND time >= %s AND time <= %s
|
||||||
|
ORDER BY time ASC;
|
||||||
|
'''
|
||||||
|
# 执行SQL命令,使用参数绑定
|
||||||
|
cur.execute(sql, (item, begin_time, end_time))
|
||||||
|
results = cur.fetchall()
|
||||||
|
|
||||||
# 将数据按照 equipment_code 进行分组
|
# 将数据按照 equipment_code 进行分组
|
||||||
if item not in res['data']:
|
if item not in res['data']:
|
||||||
res['data'][item] = []
|
res['data'][item] = []
|
||||||
|
|
||||||
for log_data in log_datas:
|
for result in results:
|
||||||
res['data'][item].append({
|
res['data'][item].append({
|
||||||
'time': log_data.time.strftime('%Y-%m-%d %H:%M:%S'),
|
'time': result[0].strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
'state': log_data.state,
|
'state': result[1],
|
||||||
'production_name': log_data.production_name,
|
'production_name': result[2],
|
||||||
})
|
})
|
||||||
|
|
||||||
return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode()
|
return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode()
|
||||||
@@ -624,7 +587,7 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
|
|
||||||
# 查询pg库来获得待机次数
|
# 查询pg库来获得待机次数
|
||||||
@http.route('/api/IdleAlarmCount', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
@http.route('/api/IdleAlarmCount', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
def idle_count(self, **kw):
|
def idle_alarm_count(self, **kw):
|
||||||
"""
|
"""
|
||||||
查询设备的待机次数
|
查询设备的待机次数
|
||||||
"""
|
"""
|
||||||
@@ -637,69 +600,50 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
try:
|
try:
|
||||||
# 获取请求的机床数据
|
# 获取请求的机床数据
|
||||||
machine_list = ast.literal_eval(kw['machine_list'])
|
machine_list = ast.literal_eval(kw['machine_list'])
|
||||||
idle_times = []
|
total_alarm_time = 0
|
||||||
idle_dict = {}
|
alarm_count_num = 0
|
||||||
|
|
||||||
for item in machine_list:
|
for item in machine_list:
|
||||||
sql = '''
|
sql = '''
|
||||||
SELECT idle_start_time,alarm_time,alarm_repair_time FROM device_data WHERE device_name = %s;
|
SELECT COUNT(*)
|
||||||
|
FROM (
|
||||||
|
SELECT DISTINCT ON (idle_start_time) idle_start_time
|
||||||
|
FROM device_data
|
||||||
|
WHERE device_name = %s AND idle_start_time IS NOT NULL
|
||||||
|
ORDER BY idle_start_time, time
|
||||||
|
) subquery;
|
||||||
|
'''
|
||||||
|
|
||||||
|
sql2 = '''
|
||||||
|
SELECT DISTINCT ON (alarm_time) alarm_time, alarm_repair_time
|
||||||
|
FROM device_data
|
||||||
|
WHERE device_name = %s AND alarm_time IS NOT NULL
|
||||||
|
ORDER BY alarm_time, time;
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# 执行SQL命令
|
# 执行SQL命令
|
||||||
cur.execute(sql, (item,))
|
cur.execute(sql, (item,))
|
||||||
result = cur.fetchall()
|
result = cur.fetchall()
|
||||||
# # print('result', result)
|
print('result========', result)
|
||||||
#
|
|
||||||
# # 将查询结果添加到idle_times列表中
|
|
||||||
# idle_times = [row[0] for row in result if row[0] is not None]
|
|
||||||
#
|
|
||||||
# # 对结果去重
|
|
||||||
# unique_idle_times = set(idle_times)
|
|
||||||
# # print('unique_idle_times', unique_idle_times)
|
|
||||||
#
|
|
||||||
# # 统计去重后的数量
|
|
||||||
# idle_count = len(unique_idle_times)
|
|
||||||
# # idle_dict[item] = idle_count
|
|
||||||
#
|
|
||||||
# res['data'][item] = idle_count
|
|
||||||
|
|
||||||
total_alarm_time = 0
|
|
||||||
alarm_count = 0
|
|
||||||
alarm_time_list = []
|
|
||||||
idle_times = []
|
|
||||||
alarm_times = []
|
|
||||||
|
|
||||||
|
cur.execute(sql2, (item,))
|
||||||
|
result2 = cur.fetchall()
|
||||||
|
print('result2========', result2)
|
||||||
|
#
|
||||||
for row in result:
|
for row in result:
|
||||||
idle_start_time = row[0]
|
res['data'][item] = {'idle_count': row[0]}
|
||||||
alarm_time = row[1]
|
alarm_count = []
|
||||||
alarm_repair_time = row[2]
|
for row in result2:
|
||||||
|
alarm_count.append(row[0])
|
||||||
alarm_time_list.append(alarm_time) # 将时长累加,以秒为单位
|
total_alarm_time += abs(float(row[0]))
|
||||||
idle_times.append(idle_start_time)
|
if len(list(set(alarm_count))) == 1:
|
||||||
# if alarm_repair_time is not None:
|
if list(set(alarm_count))[0] is None:
|
||||||
# alarm_times.append(alarm_repair_time)
|
alarm_count_num = 0
|
||||||
alarm_times.append(alarm_repair_time)
|
else:
|
||||||
|
alarm_count_num = 1
|
||||||
# 对结果去重
|
else:
|
||||||
unique_total_alarm_time = set(alarm_time_list)
|
alarm_count_num = len(list(set(alarm_count)))
|
||||||
unique_idle_times = set(idle_times)
|
res['data'][item]['total_alarm_time'] = total_alarm_time / 3600
|
||||||
unique_alarm_times = set(alarm_times)
|
res['data'][item]['alarm_count_num'] = alarm_count_num
|
||||||
|
|
||||||
# 统计去重后的数量
|
|
||||||
idle_count = len(unique_idle_times)
|
|
||||||
|
|
||||||
for alarm_time in unique_total_alarm_time:
|
|
||||||
if alarm_time is not None:
|
|
||||||
total_alarm_time += abs(float(alarm_time))
|
|
||||||
|
|
||||||
alarm_count = len(unique_alarm_times) if unique_alarm_times else 0
|
|
||||||
alarm_count = alarm_count if total_alarm_time else 0
|
|
||||||
|
|
||||||
# 存储待机次数和总待机时长(单位:秒)
|
|
||||||
res['data'][item] = {
|
|
||||||
'idle_count': idle_count,
|
|
||||||
'total_alarm_time': total_alarm_time / 3600, # 以秒为单位
|
|
||||||
'alarm_count': alarm_count
|
|
||||||
}
|
|
||||||
|
|
||||||
# 返回统计结果
|
# 返回统计结果
|
||||||
return json.dumps(res)
|
return json.dumps(res)
|
||||||
@@ -712,7 +656,7 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
|
|
||||||
# 查询pg库来获得异常情况
|
# 查询pg库来获得异常情况
|
||||||
@http.route('/api/alarm/logs', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
@http.route('/api/alarm/logs', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
def idle_count(self, **kw):
|
def alarm_logs(self, **kw):
|
||||||
"""
|
"""
|
||||||
查询设备的异常情况
|
查询设备的异常情况
|
||||||
"""
|
"""
|
||||||
@@ -764,3 +708,110 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
finally:
|
finally:
|
||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
# 设备oee
|
||||||
|
@http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
|
def OEE(self, **kw):
|
||||||
|
"""
|
||||||
|
获取产线等oee
|
||||||
|
"""
|
||||||
|
res = {'status': 1, 'message': '成功', 'data': {}}
|
||||||
|
logging.info('前端请求oee数据的参数为:%s' % kw)
|
||||||
|
|
||||||
|
try:
|
||||||
|
count_oee = 1
|
||||||
|
workcenter_obj = request.env['mrp.workcenter'].sudo()
|
||||||
|
workcenter_list = ast.literal_eval(kw['workcenter_list'])
|
||||||
|
print('workcenter_list: %s' % workcenter_list)
|
||||||
|
for line in workcenter_list:
|
||||||
|
res['data'][line] = workcenter_obj.search([('name', '=', line)]).oee
|
||||||
|
count_oee *= workcenter_obj.search([('name', '=', line)]).oee
|
||||||
|
res['data']['综合oee'] = count_oee / 1000000
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An error occurred: {e}")
|
||||||
|
|
||||||
|
return json.dumps(res)
|
||||||
|
|
||||||
|
# # 查询某段时间的设备oee
|
||||||
|
# @http.route('/api/OEEByTime', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
|
# def OEEByTime(self, **kw):
|
||||||
|
# """
|
||||||
|
# 获取某段时间的oee
|
||||||
|
# """
|
||||||
|
# res = {'status': 1, 'message': '成功', 'data': {}}
|
||||||
|
# logging.info('前端请求获取某段时间的oee的参数为:%s' % kw)
|
||||||
|
# workcenter_list = ast.literal_eval(kw['workcenter_list'])
|
||||||
|
# begin_time_str = kw['begin_time'].strip('"')
|
||||||
|
# end_time_str = kw['end_time'].strip('"')
|
||||||
|
# begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
|
||||||
|
# end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
|
||||||
|
# print('workcenter_list: %s' % workcenter_list)
|
||||||
|
# # 连接数据库
|
||||||
|
# conn = psycopg2.connect(**db_config)
|
||||||
|
# cur = conn.cursor()
|
||||||
|
# # 查询并计算OEE平均值
|
||||||
|
# oee_data = {}
|
||||||
|
# for workcenter in workcenter_list:
|
||||||
|
# cur.execute("""
|
||||||
|
# SELECT AVG(oee) as avg_oee
|
||||||
|
# FROM oee_data
|
||||||
|
# WHERE workcenter_name = %s
|
||||||
|
# AND time BETWEEN %s AND %s
|
||||||
|
# """, (workcenter, begin_time, end_time))
|
||||||
|
#
|
||||||
|
# result = cur.fetchone()
|
||||||
|
# avg_oee = result[0] if result else 0.0
|
||||||
|
# oee_data[workcenter] = avg_oee
|
||||||
|
#
|
||||||
|
# # 返回数据
|
||||||
|
# res['data'] = oee_data
|
||||||
|
# return json.dumps(res)
|
||||||
|
|
||||||
|
@http.route('/api/OEEByTime', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
|
def OEEByTime(self, **kw):
|
||||||
|
"""
|
||||||
|
获取某段时间的oee,根据用户指定的时间单位(day或hour)返回对应的平均值
|
||||||
|
"""
|
||||||
|
res = {'status': 1, 'message': '成功', 'data': {}}
|
||||||
|
logging.info('前端请求获取某段时间的oee的参数为:%s' % kw)
|
||||||
|
|
||||||
|
# 获取并解析参数
|
||||||
|
workcenter_list = ast.literal_eval(kw['workcenter_list'])
|
||||||
|
begin_time_str = kw['begin_time'].strip('"')
|
||||||
|
end_time_str = kw['end_time'].strip('"')
|
||||||
|
time_unit = kw.get('time_unit', 'day') # 默认单位为天
|
||||||
|
begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
|
||||||
|
end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
# 连接数据库
|
||||||
|
conn = psycopg2.connect(**db_config)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# 根据时间单位选择不同的时间格式
|
||||||
|
if time_unit == 'hour':
|
||||||
|
time_format = 'YYYY-MM-DD HH24:00:00'
|
||||||
|
else: # 默认为'day'
|
||||||
|
time_format = 'YYYY-MM-DD'
|
||||||
|
|
||||||
|
# 查询并计算OEE平均值
|
||||||
|
oee_data = {}
|
||||||
|
for workcenter in workcenter_list:
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT to_char(time, '{time_format}') as time_unit, AVG(oee) as avg_oee
|
||||||
|
FROM oee_data
|
||||||
|
WHERE workcenter_name = %s
|
||||||
|
AND time BETWEEN %s AND %s
|
||||||
|
GROUP BY time_unit
|
||||||
|
ORDER BY time_unit
|
||||||
|
""", (workcenter, begin_time, end_time))
|
||||||
|
|
||||||
|
results = cur.fetchall()
|
||||||
|
oee_data[workcenter] = {row[0]: row[1] for row in results}
|
||||||
|
|
||||||
|
# 关闭数据库连接
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# 返回数据
|
||||||
|
res['data'] = oee_data
|
||||||
|
return json.dumps(res)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class ResWorkcenter(models.Model):
|
|||||||
|
|
||||||
oee_target = fields.Float(
|
oee_target = fields.Float(
|
||||||
string='OEE Target', help="Overall Effective Efficiency Target in percentage", default=90, tracking=True)
|
string='OEE Target', help="Overall Effective Efficiency Target in percentage", default=90, tracking=True)
|
||||||
|
oee = fields.Float(compute='_compute_oee', help='Overall Equipment Effectiveness, based on the last month', store=True)
|
||||||
|
|
||||||
time_start = fields.Float('Setup Time', tracking=True)
|
time_start = fields.Float('Setup Time', tracking=True)
|
||||||
time_stop = fields.Float('Cleanup Time', tracking=True)
|
time_stop = fields.Float('Cleanup Time', tracking=True)
|
||||||
|
|||||||
@@ -1159,10 +1159,10 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
def button_finish(self):
|
def button_finish(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.routing_type == '装夹预调':
|
if record.routing_type == '装夹预调':
|
||||||
if not record.material_center_point or record.X_deviation_angle <= 0:
|
|
||||||
raise UserError("请对前置三元检测定位参数进行计算定位")
|
|
||||||
if not record.rfid_code and record.is_rework is False:
|
if not record.rfid_code and record.is_rework is False:
|
||||||
raise UserError("请扫RFID码进行绑定")
|
raise UserError("请扫RFID码进行绑定")
|
||||||
|
if not record.material_center_point or record.X_deviation_angle <= 0:
|
||||||
|
raise UserError("请对前置三元检测定位参数进行计算定位")
|
||||||
record.process_state = '待加工'
|
record.process_state = '待加工'
|
||||||
# record.write({'process_state': '待加工'})
|
# record.write({'process_state': '待加工'})
|
||||||
record.production_id.process_state = '待加工'
|
record.production_id.process_state = '待加工'
|
||||||
|
|||||||
Reference in New Issue
Block a user