import json import logging from odoo import fields, models, api _logger = logging.getLogger(__name__) def _strip_face_template(message_data_str): """移除 message_data JSON 中的 face_template 字段(图片base64太长)""" if not message_data_str: return message_data_str try: data = json.loads(message_data_str) if isinstance(data, dict) and 'face_template' in data: data.pop('face_template') _logger.info("已移除 face_template 字段") return json.dumps(data, ensure_ascii=False) if isinstance(data, list): changed = False for item in data: if isinstance(item, dict) and 'face_template' in item: item.pop('face_template') changed = True if changed: _logger.info("已移除列表中的 face_template 字段") return json.dumps(data, ensure_ascii=False) return message_data_str except (json.JSONDecodeError, TypeError): return message_data_str class IotMessage(models.Model): _name = 'iot.message' _description = 'mqtt 消息,发送和接收' name = fields.Char(string='消息') topic = fields.Char(string='设备订阅主题') device_sn = fields.Char(string='设备编码') model = fields.Many2one('ir.model', string='模型') id = fields.Integer(string='模型id') message_data = fields.Text(string='message 数据') state = fields.Selection( [('draft', '待下发'), ('waiting', '下发完成等待结果'), ('done', '完成'), ('exception', '异常')], string='状态', default='draft') # 响应信息 res_data = fields.Text(string='发送后的响应信息') face_data = fields.Text(string='照片数据') @api.model_create_multi def create(self, vals_list): # 保留全部数据(含 face_template),MQTT 下发时需要原样发给设备 records = super().create(vals_list) # 从 message_data 提取 face_template 存入单独字段,并在 message_data 中移除 for rec in records: if rec.message_data: try: data = json.loads(rec.message_data) if isinstance(data, dict) and 'face_template' in data: face_tpl = data.pop('face_template') rec.write({ 'face_data': face_tpl, 'message_data': json.dumps(data, ensure_ascii=False), }) except (json.JSONDecodeError, TypeError): pass # 创建设备日志时同步更新关联设备的最后更新时间 if rec.device_sn: devices = self.env['attendance.iot'].sudo().search([('name', '=', rec.device_sn)], limit=1) if devices: devices.touch_last_update() return records def write(self, vals): return super().write(vals) def action_clear_face_template(self): """批量清除已有记录的 face_template 参数""" count = 0 for record in self: if not record.message_data: continue try: data = json.loads(record.message_data) changed = False if isinstance(data, dict) and 'face_template' in data: data.pop('face_template') changed = True elif isinstance(data, list): for item in data: if isinstance(item, dict) and 'face_template' in item: item.pop('face_template') changed = True if changed: record.write({'message_data': json.dumps(data, ensure_ascii=False)}) count += 1 except (json.JSONDecodeError, TypeError): continue _logger.info(f"已清理 {count} 条记录的 face_template") return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': '完成', 'message': f'已清理 {count} 条记录的 face_template', 'sticky': False, 'type': 'success', } } @api.model def to_reply(self, data): _logger.info(f'返回消息:{data}') id = int(data.get('to')) if id: record = self.browse(id) if record: if data.get('data').get('code') == 0: record.write({ 'state': 'done', 'res_data': json.dumps(data, ensure_ascii=False) }) else: record.write({ 'state': 'exception', 'res_data': json.dumps(data, ensure_ascii=False) }) return data @api.model def get_draft_records(self): records = self.search([('state', '=', 'draft')], offset=0, limit=10) result = [] for record in records: msg_data = record.message_data # 如果有独立存的面部照片,重新拼回去下发 if record.face_data: try: data = json.loads(msg_data) if msg_data else {} if isinstance(data, dict): data['face_template'] = record.face_data msg_data = json.dumps(data, ensure_ascii=False) except (json.JSONDecodeError, TypeError): pass result.append({ 'id': record.id, 'topic': record.topic, 'message_data': msg_data }) records.write({'state': 'waiting'}) return result