diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index fb783666..1f65c884 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -231,6 +231,95 @@ class Sf_Dashboard_Connect(http.Controller): res['message'] = '前端请求日志数据失败,原因:%s' % e return json.dumps(res) + @http.route('/api/logs/page_data', type='http', auth='public', methods=['GET', 'POST'], + csrf=False, cors="*") + def logs_page_data(self, **kw): + """ + 拿到日志数据返回给大屏展示(支持时间戳分页) + :param kw: + :return: + """ + res = {'status': 1, 'message': '成功', 'data': {}} + logging.info('前端请求日志数据的参数为:%s' % kw) + + try: + # 连接数据库 + conn = psycopg2.connect(**db_config) + cur = conn.cursor() + + # 获取并解析传递的参数 + machine_list = ast.literal_eval(kw.get('machine_list', '[]')) + begin_time_str = kw.get('begin_time', '').strip('"') + end_time_str = kw.get('end_time', '').strip('"') + page = int(kw.get('page', 1)) # 默认页码为1 + page_size = int(kw.get('page_size', 80)) # 默认每页条数为10 + + 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') + + # 计算分页的 offset + offset = (page - 1) * page_size + + # 先查询符合条件的总记录数 + total_records = 0 + for item in machine_list: + count_sql = ''' + SELECT COUNT(*) + FROM device_data + WHERE device_name = %s AND time >= %s AND time <= %s; + ''' + # 执行总记录数查询 + cur.execute(count_sql, (item, begin_time, end_time)) + record_count = cur.fetchone()[0] # 获取总记录数 + total_records += record_count + + # 计算总页数 + if total_records > 0: + total_pages = (total_records + page_size - 1) // page_size # 向上取整 + else: + total_pages = 0 + + # 将总页数和总记录数返回到响应中 + res['total_records'] = total_records + res['total_pages'] = total_pages + + for item in machine_list: + sql = ''' + SELECT time, device_state, program_name + FROM device_data + WHERE device_name = %s AND time >= %s AND time <= %s + ORDER BY time DESC + LIMIT %s OFFSET %s; + ''' + # 执行SQL命令,使用参数绑定 + cur.execute(sql, (item, begin_time, end_time, page_size, offset)) + results = cur.fetchall() + + # 将数据按照 equipment_code 进行分组 + if item not in res['data']: + res['data'][item] = [] + + for result in results: + res['data'][item].append({ + 'time': result[0].strftime('%Y-%m-%d %H:%M:%S'), + 'state': result[1], + 'production_name': result[2], + }) + + return json.dumps(res) # 返回分页数据 + + except Exception as e: + logging.info('前端请求日志数据失败,原因:%s' % e) + res['status'] = -1 + res['message'] = '前端请求日志数据失败,原因:%s' % e + return json.dumps(res) + + finally: + if cur: + cur.close() + if conn: + conn.close() + # 返回CNC机床列表 @http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") @@ -378,7 +467,8 @@ class Sf_Dashboard_Connect(http.Controller): pass_rate = 1 if pass_nums: pass_rate = round( - (len(pass_nums) / detection_data if len(plan_data_finish_orders) > 0 else 0), 3) + # (len(pass_nums) / detection_data if len(plan_data_finish_orders) > 0 else 0), 3) + (len(pass_nums) / len(plan_data_finish_orders) if len(plan_data_finish_orders) > 0 else 0), 3) # 返工率 rework_rate = round( @@ -418,8 +508,9 @@ class Sf_Dashboard_Connect(http.Controller): 'plan_data_progress_deviation': plan_data_progress_deviation, 'plan_data_rework_counts': plan_data_rework_counts, 'on_time_rate': on_time_rate, - 'detection_data': detection_data, - 'pass_rate': pass_rate + # 'detection_data': detection_data, + 'detection_data': plan_data_finish_counts, + 'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts } res['data'][line] = data @@ -718,7 +809,8 @@ class Sf_Dashboard_Connect(http.Controller): 'material': material, 'dimensions': dimensions, 'order_qty': finish_order.product_qty, - 'finish_time': finish_order.actual_end_time.strftime('%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' + 'finish_time': finish_order.actual_end_time.strftime( + '%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' } done_data.append(line_dict) @@ -802,54 +894,27 @@ class Sf_Dashboard_Connect(http.Controller): """ 查询设备的异常情况 """ - res = {'status': 1, 'message': '成功', 'data': {}} + res = {'status': 1, 'message': '成功', 'data': []} logging.info('前端请求机床数据的参数为:%s' % kw) - # 连接数据库 - conn = psycopg2.connect(**db_config) - cur = conn.cursor() try: - # 获取请求的机床数据 + maintenance_logs_obj = request.env['sf.maintenance.logs'].sudo() + # # 获取请求的机床数据 # machine_list = ast.literal_eval(kw['machine_list']) - # idle_times = [] - # idle_dict = {} - # for item in machine_list: - sql = ''' - SELECT DISTINCT ON (alarm_time) alarm_time, alarm_message, system_date, system_time, alarm_repair_time - FROM device_data - WHERE alarm_time IS NOT NULL - ORDER BY alarm_time, time; + # machine_data = equipment_obj.search([('code', '=', item)]) + for log in maintenance_logs_obj.search([]): + res['data'].append({ + 'name': log.name, + 'alarm_time': log.alarm_time.strftime('%Y-%m-%d %H:%M:%S'), + 'fault_alarm_info': log.fault_alarm_info if log.fault_alarm_info else ' ', + 'fault_process': log.fault_process if log.fault_process else ' ', + }) - ''' - # 执行SQL命令 - cur.execute(sql) - result = cur.fetchall() - # print('result', result) - - # 将查询结果转换为字典列表 - data = [] - for row in result: - record = { - 'alarm_time': row[0], - 'alarm_message': row[1], - 'system_date': row[2], - 'system_time': row[3], - 'alarm_repair_time': row[4] - } - data.append(record) - - # 将数据填充到返回结果中 - res['data'] = data - - # 返回统计结果 - return json.dumps(res, ensure_ascii=False) except Exception as e: - print(f"An error occurred: {e}") - return json.dumps(res) - finally: - cur.close() - conn.close() + logging.error(f"An error occurred: {e}") + + return json.dumps(res) # 设备oee @http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") @@ -1166,6 +1231,7 @@ class Sf_Dashboard_Connect(http.Controller): conn = psycopg2.connect(**db_config) # 获取请求的机床数据 machine_list = ast.literal_eval(kw['machine_list']) + time_threshold = datetime.now() - timedelta(days=1) def fetch_result_as_dict(cursor): """辅助函数:将查询结果转为字典""" @@ -1175,18 +1241,29 @@ class Sf_Dashboard_Connect(http.Controller): for item in machine_list: with conn.cursor() as cur: cur.execute(""" - SELECT * FROM device_data - WHERE device_name = %s - AND device_state != '离线' - ORDER BY time DESC - LIMIT 1; - """, (item,)) + SELECT * FROM device_data + WHERE device_name = %s + AND device_state != '离线' + ORDER BY time DESC + LIMIT 1; + """, (item,)) last_all_time = fetch_result_as_dict(cur) + with conn.cursor() as cur: + cur.execute(""" + SELECT * FROM device_data + WHERE device_name = %s + AND device_state != '离线' AND time >= %s + ORDER BY time ASC + LIMIT 1; + """, (item, time_threshold)) + last_24_time = fetch_result_as_dict(cur) # 返回数据 res['data'][item] = { 'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0, 'cut_time': last_all_time['process_time'] if last_all_time['process_time'] is not None else 0, - 'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0 + 'cut_24_time': last_24_time['process_time'] if last_24_time['process_time'] is not None else 0, + 'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0, + 'power_on_24_time': last_24_time['power_on_time'] if last_24_time['power_on_time'] is not None else 0 } conn.close() diff --git a/sf_maintenance/models/sf_maintenance_logs.py b/sf_maintenance/models/sf_maintenance_logs.py index 7f80e163..c1a82a1b 100644 --- a/sf_maintenance/models/sf_maintenance_logs.py +++ b/sf_maintenance/models/sf_maintenance_logs.py @@ -1,13 +1,14 @@ # -*-coding:utf-8-*- -from odoo import fields, models +from odoo import fields, models, api class SfMaintenanceLogs(models.Model): _name = 'sf.maintenance.logs' _description = '设备故障日志' + _order = 'alarm_time desc' - code = fields.Char(string='编码') - name = fields.Char(string='名称') + code = fields.Char(string='编码', readonly=True) + name = fields.Char(string='名称', compute='_compute_name') type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型') brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌') maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='机台号') @@ -28,3 +29,13 @@ class SfMaintenanceLogs(models.Model): fault_duration = fields.Float(string='故障时长') note = fields.Text(string='备注') active = fields.Boolean('Active', default=True) + + @api.depends('code') + def _compute_name(self): + for record in self: + if record.code: + record.name = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).name + record.maintenance_equipment_id = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).id + else: + record.name = '' + diff --git a/sf_maintenance/models/sf_maintenance_oee.py b/sf_maintenance/models/sf_maintenance_oee.py index 1a2e4f10..ee2c209c 100644 --- a/sf_maintenance/models/sf_maintenance_oee.py +++ b/sf_maintenance/models/sf_maintenance_oee.py @@ -66,11 +66,14 @@ class SfMaintenanceEquipmentOEE(models.Model): if result['status'] == 1: logs_list = result['data'][self.equipment_code] logs_detail = '' + log_state = '' for log in logs_list: - print('loooooooooooooooooooogs', log) - production_name = log['production_name'] if log['production_name'] else ' ' - logs_detail += '' + log['time'] + '' + log[ - 'state'] + '' + production_name + '' + if log['state'] != log_state: + print('loooooooooooooooooooogs', log) + production_name = log['production_name'] if log['production_name'] else ' ' + logs_detail += '' + log['time'] + '' + log[ + 'state'] + '' + production_name + '' + log_state = log['state'] # self.day_logs_detail = '' + logs_detail + '
时间事件/状态加工工单
' self.day_logs_detail = ''' @@ -119,10 +122,13 @@ class SfMaintenanceEquipmentOEE(models.Model): if result['status'] == 1: logs_list = result['data'][self.equipment_code] logs_detail = '' + log_state = '' for log in logs_list: - production_name = log['production_name'] if log['production_name'] else ' ' - logs_detail += '' + if log['state'] != log_state: + production_name = log['production_name'] if log['production_name'] else ' ' + logs_detail += '' + log_state = log['state'] # self.day_logs_detail = '
' + log['time'] + '' + log[ - 'state'] + '' + production_name + '
' + log['time'] + '' + log[ + 'state'] + '' + production_name + '
' + logs_detail + '
时间事件/状态加工工单
' self.history_logs_detail = ''' diff --git a/sf_maintenance/views/maintenance_equipment_oee_views.xml b/sf_maintenance/views/maintenance_equipment_oee_views.xml index 33749809..b798b0ab 100644 --- a/sf_maintenance/views/maintenance_equipment_oee_views.xml +++ b/sf_maintenance/views/maintenance_equipment_oee_views.xml @@ -55,7 +55,31 @@