From c86cc27510394a5981b4ac1cb8473db70a792081 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 21 Aug 2024 15:38:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B7=A5=E5=8D=95=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 257 +++++++++++++++++- 1 file changed, 255 insertions(+), 2 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index 4f926a5b..0a770f9d 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -2,8 +2,9 @@ import re import ast import json +import base64 import logging -from datetime import datetime +from datetime import datetime, timedelta from odoo import http from odoo.http import request @@ -151,9 +152,10 @@ class Sf_Dashboard_Connect(http.Controller): 'first_online_duration': first_online_duration, # 停机时间:关机时间 - 运行时间 # 停机时长:关机时间 - 初次上线时间 + 'img': base64.b64encode(machine_data.machine_tool_picture).decode('utf-8'), }) - return json.JSONEncoder().encode(res) + return json.dumps(res) except Exception as e: logging.info('前端请求机床数据失败,原因:%s' % e) res['status'] = -1 @@ -282,3 +284,254 @@ class Sf_Dashboard_Connect(http.Controller): res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} logging.info('CNCList error:%s' % e) return json.JSONEncoder().encode(res) + + # 返回产线列表 + + @http.route('/api/LineList', type='http', auth='public', methods=['GET', 'POST'], csrf=False, + + cors="*") + def LineList(self, **kw): + """ + 获取产线列表 + :param kw: + :return: + """ + + try: + res = {'Succeed': True} + line_list_obj = request.env['sf.production.line'].sudo().search([('name', 'ilike', 'CNC')]) + line_list = list(map(lambda x: x.name, line_list_obj)) + print('line_list: %s' % line_list) + res['LineList'] = line_list + + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + logging.info('LineList error:%s' % e) + + return json.JSONEncoder().encode(res) + + # 获取产线产量相关 + + @http.route('/api/LineProduct', type='http', auth='public', methods=['GET', 'POST'], csrf=False, + + cors="*") + def LineProduct(self, **kw): + """ + 获取产线产量相关 + :param kw: + :return: + """ + res = {'status': 1, 'message': '成功', 'data': {}} + logging.info('前端请求产线产量数据的参数为:%s' % kw) + + try: + plan_obj = request.env['sf.production.plan'].sudo() + line_list = ast.literal_eval(kw['line_list']) + print('line_list: %s' % line_list) + for line in line_list: + plan_data = plan_obj.search([('production_line_id.name', '=', line)]) + # 工单总量 + plan_data_total_counts = plan_obj.search_count([('production_line_id.name', '=', line)]) + # 工单完成量 + plan_data_finish_counts = plan_obj.search_count( + [('production_line_id.name', '=', line), ('state', 'not in', ['draft'])]) + # 工单计划量 + plan_data_plan_counts = plan_obj.search_count( + [('production_line_id.name', '=', line), ('state', 'not in', ['finished'])]) + # 工单不良累计 + plan_data_fault_counts = plan_obj.search_count( + [('production_line_id.name', '=', line), ('production_id.state', 'in', ['scrap', 'cancel'])]) + # 工单完成率 + finishe_rate = round( + (plan_data_finish_counts / plan_data_total_counts if plan_data_total_counts > 0 else 0), 3) + + # 工单进度偏差 + plan_data_progress_deviation = plan_data_finish_counts - plan_data_plan_counts + + if plan_data: + data = { + 'plan_data_total_counts': plan_data_total_counts, + 'plan_data_finish_counts': plan_data_finish_counts, + 'plan_data_plan_counts': plan_data_plan_counts, + 'plan_data_fault_counts': plan_data_fault_counts, + 'finishe_rate': finishe_rate, + 'plan_data_progress_deviation': plan_data_progress_deviation, + } + res['data'][line] = data + + return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode() + + except Exception as e: + logging.info('前端请求产线产量数据失败,原因:%s' % e) + res['status'] = -1 + res['message'] = '前端请求产线产量数据失败,原因:%s' % e + return json.dumps(res) + + # 日完成量统计 + class DailyFinishCount(http.Controller): + @http.route('/api/DailyFinishCount', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") + def DailyFinishCount(self, **kw): + """ + 获取日完成量统计 + :param kw: + :return: + """ + res = {'status': 1, 'message': '成功', 'data': []} + plan_obj = request.env['sf.production.plan'].sudo() + line_list = ast.literal_eval(kw['line_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('line_list: %s' % line_list) + + def get_date_list(start_date, end_date): + date_list = [] + current_date = start_date + while current_date <= end_date: + date_list.append(current_date) + current_date += timedelta(days=1) + return date_list + + for line in line_list: + date_list = get_date_list(begin_time, end_time) + order_counts = [] + + date_field_name = 'actual_end_time' # 替换为你模型中的实际字段名 + + for date in date_list: + next_day = date + timedelta(days=1) + orders = plan_obj.search([('production_line_id.name', '=', line), ('state', 'not in', ['draft']), + (date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')), + (date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00')) + ]) + order_counts.append({ + 'date': date.strftime('%Y-%m-%d'), + 'order_count': len(orders) + }) + + res['data'] = order_counts + return json.dumps(res) + + # # 实时产量 + # @http.route('/api/RealTimeProduct', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") + # def RealTimeProduct(self, **kw): + # """ + # 获取实时产量 + # :param kw: + # :return: + # """ + # + # def get_real_time_product(line_list): + # res = {'status': 1, 'message': '成功', 'data': []} + # plan_obj = request.env['sf.production.plan'].sudo() + # for line in line_list: + # plan_data = plan_obj.search([('production_line_id.name', '=', line)]) + + # 工单明细 + @http.route('/api/OrderDetail', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") + def OrderDetail(self, **kw): + """ + 获取工单明细 + :param kw: + :return: + """ + + res = {'status': 1, 'message': '成功', 'not_done_data': [], 'done_data': []} + plan_obj = request.env['sf.production.plan'].sudo() + line_list = ast.literal_eval(kw['line_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('line_list: %s' % line_list) + + for line in line_list: + # 未完成订单 + not_done_orders = plan_obj.search( + [('production_line_id.name', '=', line), ('state', 'not in', ['finished'])]) + print(not_done_orders) + # 完成订单 + finish_orders = plan_obj.search([('production_line_id.name', '=', line), ('state', 'in', ['finished'])]) + print(finish_orders) + + # 获取所有未完成订单的ID列表 + order_ids = [order.id for order in not_done_orders] + # 获取所有已完成订单的ID列表 + finish_order_ids = [order.id for order in finish_orders] + + # 对ID进行排序 + sorted_order_ids = sorted(order_ids) + + finish_sorted_order_ids = sorted(finish_order_ids) + + # 创建ID与序号的对应关系 + id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(sorted_order_ids)} + + finish_id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(finish_sorted_order_ids)} + + # # 输出结果或进一步处理 + # for order_id, sequence in id_to_sequence.items(): + # print(f"Order ID: {order_id} - Sequence: {sequence}") + + for order in not_done_orders: + blank_name = '' + try: + blank_name = order.production_id.move_raw_ids[0].product_id.name + except: + continue + # blank_name = 'R-S00109-1 [碳素结构钢 Q235-118.0 * 72.0 * 21.0]' + # 正则表达式 + material_pattern = r'\[(.*?)-' # 从 [ 开始,碰到 - 停止 + dimensions = blank_name.split('-')[-1].split(']')[0] + + # 匹配材料名称 + material_match = re.search(material_pattern, blank_name) + material = material_match.group(1) if material_match else 'No match found' + + state_dict = { + 'draft': '待排程', + 'done': '已排程', + 'processing': '生产中', + 'finished': '已完成' + } + + line_dict = { + 'sequence': id_to_sequence[order.id], + 'workorder_name': order.name, + 'blank_name': blank_name, + 'material': material, + 'dimensions': dimensions, + 'order_qty': order.product_qty, + 'state': state_dict[order.state], + + } + res['not_done_data'].append(line_dict) + + for finish_order in finish_orders: + blank_name = '' + try: + blank_name = finish_order.production_id.move_raw_ids[0].product_id.name + except: + continue + + material_pattern = r'\[(.*?)-' # 从 [ 开始,碰到 - 停止 + dimensions = blank_name.split('-')[-1].split(']')[0] + + # 匹配材料名称 + material_match = re.search(material_pattern, blank_name) + material = material_match.group(1) if material_match else 'No match found' + + line_dict = { + 'sequence': finish_id_to_sequence[finish_order.id], + 'workorder_name': finish_order.name, + 'blank_name': blank_name, + 'material': material, + 'dimensions': dimensions, + 'order_qty': finish_order.product_qty, + 'finish_time': finish_order.actual_end_time.strftime('%Y-%m-%d %H:%M:%S'), + + } + res['done_data'].append(line_dict) + + return json.dumps(res)