运行日志数据接入
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
'views/machine_info_present.xml',
|
'views/machine_info_present.xml',
|
||||||
'views/delivery_record.xml',
|
'views/delivery_record.xml',
|
||||||
'views/res_config_settings_views.xml',
|
'views/res_config_settings_views.xml',
|
||||||
|
'views/maintenance_views.xml',
|
||||||
|
|
||||||
],
|
],
|
||||||
'assets': {
|
'assets': {
|
||||||
|
|||||||
@@ -1,11 +1,45 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import re
|
||||||
import ast
|
import ast
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
from odoo import http
|
from odoo import http
|
||||||
from odoo.http import request
|
from odoo.http import request
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_seconds(time_str):
|
||||||
|
# 修改正则表达式,使 H、M、S 部分可选
|
||||||
|
|
||||||
|
pattern = r"(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?"
|
||||||
|
match = re.match(pattern, time_str)
|
||||||
|
|
||||||
|
if match:
|
||||||
|
# 提取各时间单位,如果某个单位缺失则默认设为0
|
||||||
|
hours = int(match.group(1)) if match.group(1) else 0
|
||||||
|
minutes = int(match.group(2)) if match.group(2) else 0
|
||||||
|
seconds = int(match.group(3)) if match.group(3) else 0
|
||||||
|
|
||||||
|
# 计算总秒数
|
||||||
|
total_seconds = hours * 3600 + minutes * 60 + seconds
|
||||||
|
if total_seconds == 0:
|
||||||
|
# return None
|
||||||
|
pattern = r"(?:(\d+)小时)?(?:(\d+)分钟)?(?:(\d+)秒)?"
|
||||||
|
match = re.match(pattern, time_str)
|
||||||
|
if match:
|
||||||
|
# 提取各时间单位,如果某个单位缺失则默认设为0
|
||||||
|
hours = int(match.group(1)) if match.group(1) else 0
|
||||||
|
minutes = int(match.group(2)) if match.group(2) else 0
|
||||||
|
seconds = int(match.group(3)) if match.group(3) else 0
|
||||||
|
|
||||||
|
# 计算总秒数
|
||||||
|
total_seconds = hours * 3600 + minutes * 60 + seconds
|
||||||
|
return total_seconds
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
return total_seconds
|
||||||
|
|
||||||
|
|
||||||
class Sf_Dashboard_Connect(http.Controller):
|
class Sf_Dashboard_Connect(http.Controller):
|
||||||
|
|
||||||
@http.route('/api/get_machine_datas/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
|
@http.route('/api/get_machine_datas/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
|
||||||
@@ -18,6 +52,11 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
"""
|
"""
|
||||||
res = {'status': 1, 'message': '成功', 'data': []}
|
res = {'status': 1, 'message': '成功', 'data': []}
|
||||||
logging.info('前端请求机床数据的参数为:%s' % kw)
|
logging.info('前端请求机床数据的参数为:%s' % kw)
|
||||||
|
|
||||||
|
# 获取当前时间的时间戳
|
||||||
|
current_timestamp = datetime.now().timestamp()
|
||||||
|
print(current_timestamp)
|
||||||
|
|
||||||
# tem_list = [
|
# tem_list = [
|
||||||
# "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-1", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-3",
|
# "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-1", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-3",
|
||||||
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-4", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-5",
|
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-4", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-5",
|
||||||
@@ -33,8 +72,21 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
machine_list = ast.literal_eval(kw['machine_list'])
|
machine_list = ast.literal_eval(kw['machine_list'])
|
||||||
for item in machine_list:
|
for item in machine_list:
|
||||||
machine_data = equipment_obj.search([('code', '=', item)])
|
machine_data = equipment_obj.search([('code', '=', item)])
|
||||||
|
|
||||||
|
# 机床上线时间段
|
||||||
|
first_online_duration = current_timestamp - int(machine_data.first_online_time.timestamp())
|
||||||
|
|
||||||
|
power_off_time = None
|
||||||
|
power_off_rate = None
|
||||||
|
if machine_data.machine_power_on_time:
|
||||||
|
power_off_time = first_online_duration - convert_to_seconds(machine_data.machine_power_on_time)
|
||||||
|
power_off_rate = round((power_off_time / first_online_duration), 3)
|
||||||
|
else:
|
||||||
|
power_off_time = False
|
||||||
|
power_off_rate = False
|
||||||
if machine_data:
|
if machine_data:
|
||||||
res['data'].append({
|
res['data'].append({
|
||||||
|
'active': machine_data.status,
|
||||||
'id': machine_data.id,
|
'id': machine_data.id,
|
||||||
'name': machine_data.name,
|
'name': machine_data.name,
|
||||||
'brand': machine_data.type_id.name,
|
'brand': machine_data.type_id.name,
|
||||||
@@ -92,6 +144,13 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
# 计算出来的数据
|
# 计算出来的数据
|
||||||
# 开动率:运行时间/通电时间
|
# 开动率:运行时间/通电时间
|
||||||
'run_rate': machine_data.run_rate,
|
'run_rate': machine_data.run_rate,
|
||||||
|
# 关机时长:初次上线时间 - 通电时间
|
||||||
|
'power_off_time': power_off_time,
|
||||||
|
# 关机率:关机时长/初次上线时间
|
||||||
|
'power_off_rate': power_off_rate,
|
||||||
|
'first_online_duration': first_online_duration,
|
||||||
|
# 停机时间:关机时间 - 运行时间
|
||||||
|
# 停机时长:关机时间 - 初次上线时间
|
||||||
})
|
})
|
||||||
|
|
||||||
return json.JSONEncoder().encode(res)
|
return json.JSONEncoder().encode(res)
|
||||||
@@ -101,6 +160,95 @@ 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="*")
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 将数据按照 equipment_code 进行分组
|
||||||
|
if item not in res['data']:
|
||||||
|
res['data'][item] = []
|
||||||
|
|
||||||
|
for log_data in log_datas:
|
||||||
|
res['data'][item].append({
|
||||||
|
'time': log_data.time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
|
'state': log_data.state
|
||||||
|
})
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
# 返回CNC机床列表
|
# 返回CNC机床列表
|
||||||
@http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
|
@http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
|
||||||
cors="*")
|
cors="*")
|
||||||
|
|||||||
@@ -121,6 +121,13 @@ class Machine_ftp(models.Model):
|
|||||||
"""
|
"""
|
||||||
_inherit = 'maintenance.equipment'
|
_inherit = 'maintenance.equipment'
|
||||||
|
|
||||||
|
# 机床首次上线时间(默认取值2024年08月01日零点)
|
||||||
|
|
||||||
|
def _get_default_online_time(self):
|
||||||
|
return datetime(2024, 1, 1, 0, 0, 0)
|
||||||
|
|
||||||
|
first_online_time = fields.Datetime(string='首次上线时间', default=_get_default_online_time)
|
||||||
|
|
||||||
# workorder_ids = fields.One2many('mrp.workorder', 'machine_tool_id', string='工单')
|
# workorder_ids = fields.One2many('mrp.workorder', 'machine_tool_id', string='工单')
|
||||||
|
|
||||||
# # 机床配置项目
|
# # 机床配置项目
|
||||||
@@ -278,6 +285,26 @@ class Machine_ftp(models.Model):
|
|||||||
# # 开动率
|
# # 开动率
|
||||||
run_rate = fields.Char('开动率', readonly=True)
|
run_rate = fields.Char('开动率', readonly=True)
|
||||||
|
|
||||||
|
# 同步CNC设备到oee
|
||||||
|
def sync_oee(self):
|
||||||
|
"""
|
||||||
|
同步CNC设备到oee
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
for record in self:
|
||||||
|
record.ensure_one()
|
||||||
|
cnc_oee_dict = {
|
||||||
|
'equipment_id': record.id,
|
||||||
|
'type_id': record.type_id.id,
|
||||||
|
'machine_tool_picture': record.machine_tool_picture,
|
||||||
|
'equipment_code': record.code,
|
||||||
|
'function_type': record.function_type,
|
||||||
|
}
|
||||||
|
if self.env['maintenance.equipment.oee.logs'].search([('equipment_id', '=', record.id)]):
|
||||||
|
self.env['maintenance.equipment.oee.logs'].write(cnc_oee_dict)
|
||||||
|
else:
|
||||||
|
self.env['maintenance.equipment.oee.logs'].create(cnc_oee_dict)
|
||||||
|
|
||||||
|
|
||||||
class WorkCenterBarcode(models.Model):
|
class WorkCenterBarcode(models.Model):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
<field name="run_status"/>
|
<field name="run_status"/>
|
||||||
<field name="run_time"/>
|
<field name="run_time"/>
|
||||||
<field name="system_date"/>
|
<field name="system_date"/>
|
||||||
|
<field name="first_online_time"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="cut_status"/>
|
<field name="cut_status"/>
|
||||||
|
|||||||
17
sf_machine_connect/views/maintenance_views.xml
Normal file
17
sf_machine_connect/views/maintenance_views.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<odoo>
|
||||||
|
<!-- 修改设备列表视图-->
|
||||||
|
<record id="sf_machine_hr_equipment_view_tree_inherit" model="ir.ui.view">
|
||||||
|
<field name="name">sf.machine.hr.equipment.view.tree.inherit</field>
|
||||||
|
<field name="model">maintenance.equipment</field>
|
||||||
|
<field name="inherit_id" ref="maintenance.hr_equipment_view_tree"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//tree" position="inside">
|
||||||
|
<header>
|
||||||
|
<button name="sync_oee" type="object" string="同步设备至OEE"/>
|
||||||
|
</header>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -41,29 +41,32 @@ class SfMaintenanceEquipmentOEELog(models.Model):
|
|||||||
_name = 'maintenance.equipment.oee.logs'
|
_name = 'maintenance.equipment.oee.logs'
|
||||||
_description = '设备运行日志'
|
_description = '设备运行日志'
|
||||||
|
|
||||||
equipment_id = fields.Many2one('maintenance.equipment', '机台号')
|
equipment_id = fields.Many2one('maintenance.equipment', '机台号', readonly='True')
|
||||||
equipment_code = fields.Char('设备编码')
|
equipment_code = fields.Char('设备编码', readonly='True')
|
||||||
name = fields.Char('设备名称', readonly='True')
|
name = fields.Char('设备名称', readonly='True')
|
||||||
|
function_type = fields.Selection(
|
||||||
|
[("ZXJGZX", "钻铣加工中心"), ("CXJGZX", "车削加工中心"), ("FHJGZX", "复合加工中心")],
|
||||||
|
default="", string="功能类型")
|
||||||
machine_tool_picture = fields.Binary('设备图片')
|
machine_tool_picture = fields.Binary('设备图片')
|
||||||
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号')
|
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号', reaonly='True')
|
||||||
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
|
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
|
||||||
("检修", "检修"), ("保养", "保养")], default="", string="实时状态")
|
("检修", "检修"), ("保养", "保养")], default="", string="实时状态")
|
||||||
online_time = fields.Char('开机时长')
|
online_time = fields.Char('开机时长', reaonly='True')
|
||||||
|
|
||||||
offline_time = fields.Char('关机时长')
|
offline_time = fields.Char('关机时长', reaonly='True')
|
||||||
offline_nums = fields.Integer('关机次数')
|
offline_nums = fields.Integer('关机次数', reaonly='True')
|
||||||
# 待机时长
|
# 待机时长
|
||||||
|
|
||||||
idle_time = fields.Char('待机时长')
|
idle_time = fields.Char('待机时长', reaonly='True')
|
||||||
|
|
||||||
# 待机率
|
# 待机率
|
||||||
idle_rate = fields.Char('待机率')
|
idle_rate = fields.Char('待机率', reaonly='True')
|
||||||
|
|
||||||
work_time = fields.Char('加工时长')
|
work_time = fields.Char('加工时长', reaonly='True')
|
||||||
work_rate = fields.Char('可用率')
|
work_rate = fields.Char('可用率', reaonly='True')
|
||||||
fault_time = fields.Char('故障时长')
|
fault_time = fields.Char('故障时长', reaonly='True')
|
||||||
fault_rate = fields.Char('故障率')
|
fault_rate = fields.Char('故障率', reaonly='True')
|
||||||
fault_nums = fields.Integer('故障次数')
|
fault_nums = fields.Integer('故障次数', reaonly='True')
|
||||||
|
|
||||||
detail_ids = fields.One2many('maintenance.equipment.oee.log.detail', 'log_id', string='日志详情')
|
detail_ids = fields.One2many('maintenance.equipment.oee.log.detail', 'log_id', string='日志详情')
|
||||||
|
|
||||||
@@ -82,11 +85,13 @@ class SfMaintenanceEquipmentOEELogDetail(models.Model):
|
|||||||
_name = 'maintenance.equipment.oee.log.detail'
|
_name = 'maintenance.equipment.oee.log.detail'
|
||||||
_description = '设备运行日志详情'
|
_description = '设备运行日志详情'
|
||||||
|
|
||||||
sequence = fields.Integer('序号')
|
# sequence = fields.Integer('序号', related='id')
|
||||||
time = fields.Datetime('时间')
|
time = fields.Datetime('时间')
|
||||||
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
|
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
|
||||||
("检修", "检修"), ("保养", "保养")], default="", string="事件/状态")
|
("检修", "检修"), ("保养", "保养")], default="", string="事件/状态")
|
||||||
production_id = fields.Many2one('mrp.production', '加工工单')
|
production_id = fields.Many2one('mrp.production', '加工工单')
|
||||||
|
|
||||||
log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志')
|
log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志')
|
||||||
|
# equipment_code = fields.Char('设备编码', related='log_id.equipment_code')
|
||||||
|
equipment_code = fields.Char('设备编码', readonly='True')
|
||||||
|
|
||||||
|
|||||||
@@ -159,6 +159,8 @@
|
|||||||
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
|
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
|
||||||
<field name="type_id"/>
|
<field name="type_id"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
|
<field name="equipment_code"/>
|
||||||
|
<field name="function_type"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
@@ -202,7 +204,7 @@
|
|||||||
<!-- <field name="detail_ids" domain="[('time','<',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
|
<!-- <field name="detail_ids" domain="[('time','<',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
|
||||||
<field name="detail_ids" domain="[('state','ilike','加工')]">
|
<field name="detail_ids" domain="[('state','ilike','加工')]">
|
||||||
<tree>
|
<tree>
|
||||||
<field name="sequence"/>
|
<!-- <field name="sequence"/> -->
|
||||||
<field name="time"/>
|
<field name="time"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<field name="production_id"/>
|
<field name="production_id"/>
|
||||||
@@ -219,7 +221,7 @@
|
|||||||
<page string="历史日志详情">
|
<page string="历史日志详情">
|
||||||
<field name="detail_ids">
|
<field name="detail_ids">
|
||||||
<tree>
|
<tree>
|
||||||
<field name="sequence"/>
|
<!-- <field name="sequence"/> -->
|
||||||
<field name="time"/>
|
<field name="time"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<field name="production_id"/>
|
<field name="production_id"/>
|
||||||
@@ -263,7 +265,7 @@
|
|||||||
<field name="model">maintenance.equipment.oee.log.detail</field>
|
<field name="model">maintenance.equipment.oee.log.detail</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree>
|
<tree>
|
||||||
<field name="sequence"/>
|
<!-- <field name="sequence"/> -->
|
||||||
<field name="time"/>
|
<field name="time"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
<field name="production_id"/>
|
<field name="production_id"/>
|
||||||
@@ -283,7 +285,7 @@
|
|||||||
<field name="production_id"/>
|
<field name="production_id"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="sequence"/>
|
<!-- <field name="sequence"/> -->
|
||||||
<field name="time"/>
|
<field name="time"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
Reference in New Issue
Block a user