Jelajahi Sumber

异常日志

locky 2 bulan lalu
induk
melakukan
a626abad19

+ 11 - 0
AdminController/DeviceManagementController.py

@@ -85,6 +85,8 @@ class DeviceManagement(View):
                 return self.reset_ai(request, request_dict, response)
             elif operation == 'resetPrimaryUser':
                 return self.resetPrimaryUser(request, request_dict, response)
+            elif operation == 'getDeviceType':
+                return self.getDeviceType(response)
             elif operation == 'getDeviceTypeList':
                 return self.getDeviceTypeList(request_dict, response)
             elif operation == 'deleteDeviceType':
@@ -391,6 +393,15 @@ class DeviceManagement(View):
             print(e)
             return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
 
+    @staticmethod
+    def getDeviceType(response):
+        try:
+            device_type_qs = DeviceTypeModel.objects.all().values('type', 'name')
+            print(list(device_type_qs))
+            return response.json(0, {'list': list(device_type_qs)})
+        except Exception as e:
+            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
     # 获取设备类型数据
     def getDeviceTypeList(self, request_dict, response):
         name = request_dict.get('name', None)

+ 299 - 2
AdminController/LogManagementController.py

@@ -11,7 +11,8 @@ from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
 from Model.models import Device_Info, RequestRecordModel, iotdeviceInfoModel, Access_Log, DeviceLogModel, LogModel, \
-    AppLogModel, AppScannedSerial, StsFrequency, DeviceDomainRegionModel, IPAddr, CountryModel, RegionModel
+    AppLogModel, AppScannedSerial, StsFrequency, DeviceDomainRegionModel, IPAddr, CountryModel, RegionModel, \
+    AbnormalEvent, DeviceTypeModel, AbnormalEventCode, DeviceScheme, ProductsScheme
 from Ansjer.config import REGION_NAME, ACCESS_KEY_ID, SECRET_ACCESS_KEY, LOG_BUCKET
 
 
@@ -62,8 +63,16 @@ class LogManagementView(View):
                 return self.getDomainLog(request_dict, response)
             elif operation == 'getDomainScanLog':  # 获取域名扫码日志
                 return self.getDomainScanLog(request_dict, response)
+            elif operation == 'getDeviceAbnormalEvent':  # 获取设备异常事件
+                return self.getDeviceAbnormalEvent(request_dict, response)
+            elif operation == 'getAbnormalEventValue':  # 获取设备异常事件编码/内容
+                return self.getAbnormalEventValue(response)
+            elif operation == 'getAbnormalPercentage':  # 获取异常百分比
+                return self.getAbnormalPercentage(request_dict, response)
+            elif operation == 'getAbnormalDetailsPercentage':  # 获取异常详情百分比
+                return self.getAbnormalDetailsPercentage(request_dict, response)
             else:
-                return response.json(404)
+                return response.json(414)
 
     def getRequestList(self, request_dict, response):
         pageNo = request_dict.get('pageNo', None)
@@ -532,3 +541,291 @@ class LogManagementView(View):
             return response.json(0, res)
         except Exception as e:
             return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+    @staticmethod
+    def getDeviceAbnormalEvent(request_dict, response):
+        uid = request_dict.get('uid', None)
+        storage_code = request_dict.get('storageCode', None)
+        device_type = request_dict.get('deviceType', None)
+        version = request_dict.get('version', None)
+        event_type = request_dict.get('eventType', None)
+        report_type = request_dict.get('reportType', None)
+        event_time_range = request_dict.getlist('eventTimeRange[]', None)
+        page_no = request_dict.get('pageNo', None)
+        page_size = request_dict.get('pageSize', None)
+
+        is_page = False
+        if all([page_no, page_size]):
+            is_page = True
+            page = int(page_no)
+            line = int(page_size)
+
+        try:
+            query = Q()
+            if uid:
+                query &= Q(uid=uid)
+            if storage_code:
+                # 同一单号都为uid或序列号
+                uid_qs = DeviceScheme.objects.filter(storage_code=storage_code).\
+                    values_list('serial_number', flat=True)
+                uid_list = list(uid_qs)
+                # 序列号,查询uid
+                if uid_list and len(uid_list[0]) == 9:
+                    uid_list = CommonService.get_uids_by_serial_numbers(uid_list)
+                query &= Q(uid__in=uid_list)
+            if device_type:
+                # 处理多个deviceType参数
+                device_types = [int(t.strip()) for t in device_type.split(',') if t.strip().isdigit()]
+                query &= Q(device_type__in=device_types)
+            if version:
+                query &= Q(version=version)
+            if report_type:
+                query &= Q(report_type=int(report_type))
+            if event_time_range:
+                start_time, end_time = int(
+                    event_time_range[0][:-3]), int(event_time_range[1][:-3])
+                query &= Q(event_time__gte=start_time, event_time__lte=end_time)
+            if event_type:
+                # 通过event查询对应的event_code
+                event_codes_from_event = AbnormalEventCode.objects.filter(
+                    event_type__in=event_type.split(',')
+                ).values_list('event_code', flat=True)
+                if event_codes_from_event.exists():
+                    query &= Q(event_code__in=event_codes_from_event)
+
+            abnormal_events = AbnormalEvent.objects.filter(query)
+            count = abnormal_events.count()
+            event_list = abnormal_events.order_by('-event_time').values(
+                'id', 'uid', 'device_type', 'version', 'event_code',
+                'content', 'report_type', 'event_time', 'created_time'
+            )
+            # 分页
+            if is_page:
+                event_list = event_list[(page - 1) * line:page * line]
+
+            # 查询设备型号,异常信息,制作单信息
+            for event in event_list:
+                device_type = DeviceTypeModel.objects.filter(type=event['device_type']).first()
+                if device_type:
+                    event['device_type'] = device_type.name
+                else:
+                    event['device_type'] = ''
+
+                abnormal_event_code = AbnormalEventCode.objects.filter(event_code=event['event_code']).first()
+                if abnormal_event_code:
+                    event['event'] = abnormal_event_code.event
+                    event['event_type'] = abnormal_event_code.event_type
+                else:
+                    event['event'] = ''
+
+                # 根据uid查序列号
+                serial_number = CommonService.get_serial_number_by_uid(event['uid'])
+                device_scheme_qs = DeviceScheme.objects.filter(serial_number=serial_number).values('storage_code')
+                if device_scheme_qs.exists():
+                    storage_code = device_scheme_qs[0]['storage_code']
+                    event['storage_code'] = storage_code
+                    products_scheme_qs = ProductsScheme.objects.filter(
+                        storage_code=storage_code).values(
+                        'main_controller', 'wifi', 'sensor', 'order_quantity', 'created_time')
+                    if products_scheme_qs.exists():
+                        event['scheme'] = '{}+{}+{}'.format(
+                            products_scheme_qs[0]['main_controller'], products_scheme_qs[0]['wifi'], products_scheme_qs[0]['sensor'])
+                        event['order_quantity'] = products_scheme_qs[0]['order_quantity']
+                        event['shipping_date'] = products_scheme_qs[0]['created_time']
+
+            return response.json(0, {'list': list(event_list), 'total': count})
+        except Exception as e:
+            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+    @staticmethod
+    def getAbnormalEventValue(response):
+        try:
+            event_types = AbnormalEventCode.objects.values_list('event_type', flat=True)
+            # 使用Python的set去重
+            seen = set()
+            unique_event_types = [x for x in event_types if x not in seen and not seen.add(x)]
+            return response.json(0, {'list': unique_event_types})
+        except Exception as e:
+            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+    @staticmethod
+    def getAbnormalPercentage(request_dict, response):
+        uid = request_dict.get('uid', None)
+        storage_code = request_dict.get('storageCode', None)
+        device_type = request_dict.get('deviceType', None)
+        version = request_dict.get('version', None)
+        event_type = request_dict.get('eventType', None)
+        report_type = request_dict.get('reportType', None)
+        event_time_range = request_dict.getlist('eventTimeRange[]', None)
+
+        try:
+            query = Q()
+            if uid:
+                query &= Q(uid=uid)
+            if storage_code:
+                # 同一单号都为uid或序列号
+                uid_qs = DeviceScheme.objects.filter(storage_code=storage_code).\
+                    values_list('serial_number', flat=True)
+                uid_list = list(uid_qs)
+                # 序列号,查询uid
+                if uid_list and len(uid_list[0]) == 9:
+                    uid_list = CommonService.get_uids_by_serial_numbers(uid_list)
+                query &= Q(uid__in=uid_list)
+            if device_type:
+                # 处理多个deviceType参数
+                device_types = [int(t.strip()) for t in device_type.split(',') if t.strip().isdigit()]
+                query &= Q(device_type__in=device_types)
+            if version:
+                query &= Q(version=version)
+            if report_type:
+                query &= Q(report_type=int(report_type))
+            if event_time_range:
+                start_time, end_time = int(
+                    event_time_range[0][:-3]), int(event_time_range[1][:-3])
+                query &= Q(event_time__gte=start_time, event_time__lte=end_time)
+            if event_type:
+                # 通过event查询对应的event_code
+                event_codes_from_event = AbnormalEventCode.objects.filter(
+                    event_type__in=event_type.split(',')
+                ).values_list('event_code', flat=True)
+                if event_codes_from_event.exists():
+                    query &= Q(event_code__in=event_codes_from_event)
+
+            # 查询符合条件的异常事件
+            abnormal_events = AbnormalEvent.objects.filter(query)
+            total_count = abnormal_events.count()
+
+            # 获取所有异常类型及其数量
+            event_type_stats = {}
+            if total_count > 0:
+                # 获取所有事件的event_code
+                event_codes = abnormal_events.values_list('event_code', flat=True)
+
+                # 获取所有event_code对应的event_type
+                event_code_types = AbnormalEventCode.objects.filter(
+                    event_code__in=event_codes
+                ).values('event_code', 'event_type')
+
+                # 创建event_code到event_type的映射
+                event_code_to_type = {item['event_code']: item['event_type'] for item in event_code_types}
+
+                # 统计每个event_code的数量
+                for event in abnormal_events:
+                    event_type = event_code_to_type.get(event.event_code, '未知类型')
+                    if event_type in event_type_stats:
+                        event_type_stats[event_type] += 1
+                    else:
+                        event_type_stats[event_type] = 1
+
+            # 计算百分比并格式化结果(保留两位小数)
+            statistics = []
+            for name, value in event_type_stats.items():
+                percentage = round((value / total_count) * 100, 2) if total_count > 0 else 0.00
+                statistics.append({
+                    'name': name,
+                    'value': value,
+                    'percentage': percentage
+                })
+
+            # 按数量降序排序
+            statistics.sort(key=lambda x: x['value'], reverse=True)
+
+            return response.json(0, {
+                'total': total_count,
+                'statistics': statistics
+            })
+        except Exception as e:
+            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+    @staticmethod
+    def getAbnormalDetailsPercentage(request_dict, response):
+        uid = request_dict.get('uid', None)
+        storage_code = request_dict.get('storageCode', None)
+        device_type = request_dict.get('deviceType', None)
+        version = request_dict.get('version', None)
+        event_type = request_dict.get('eventType', None)
+        report_type = request_dict.get('reportType', None)
+        event_time_range = request_dict.getlist('eventTimeRange[]', None)
+
+        if not event_type:
+            return response.json(444)
+
+        try:
+            query = Q()
+            if uid:
+                query &= Q(uid=uid)
+            if storage_code:
+                # 同一单号都为uid或序列号
+                uid_qs = DeviceScheme.objects.filter(storage_code=storage_code). \
+                    values_list('serial_number', flat=True)
+                uid_list = list(uid_qs)
+                # 序列号,查询uid
+                if uid_list and len(uid_list[0]) == 9:
+                    uid_list = CommonService.get_uids_by_serial_numbers(uid_list)
+                query &= Q(uid__in=uid_list)
+            if device_type:
+                # 处理多个deviceType参数
+                device_types = [int(t.strip()) for t in device_type.split(',') if t.strip().isdigit()]
+                query &= Q(device_type__in=device_types)
+            if version:
+                query &= Q(version=version)
+            if report_type:
+                query &= Q(report_type=int(report_type))
+            if event_time_range:
+                start_time, end_time = int(
+                    event_time_range[0][:-3]), int(event_time_range[1][:-3])
+                query &= Q(event_time__gte=start_time, event_time__lte=end_time)
+
+            # 通过event查询对应的event_code
+            event_codes_from_event = AbnormalEventCode.objects.filter(event_type=event_type).\
+                values_list('event_code', flat=True)
+            if event_codes_from_event.exists():
+                query &= Q(event_code__in=event_codes_from_event)
+
+            # 查询符合条件的异常事件
+            abnormal_events = AbnormalEvent.objects.filter(query)
+            total_count = abnormal_events.count()
+
+            # 获取所有异常类型及其数量
+            event_type_stats = {}
+            if total_count > 0:
+                # 获取所有事件的event_code
+                event_codes = abnormal_events.values_list('event_code', flat=True)
+
+                # 获取所有event_code对应的event_type
+                event_code_types = AbnormalEventCode.objects.filter(
+                    event_type=event_type
+                ).values('event_code', 'event')
+
+                # 创建event_code到event_type的映射
+                event_code_to_type = {item['event_code']: item['event'] for item in event_code_types}
+
+                # 统计每个event_code的数量
+                for abnormal_event in abnormal_events:
+                    event = event_code_to_type.get(abnormal_event.event_code, '未知类型')
+                    if event in event_type_stats:
+                        event_type_stats[event] += 1
+                    else:
+                        event_type_stats[event] = 1
+
+            # 计算百分比并格式化结果(保留两位小数)
+            statistics = []
+            for name, value in event_type_stats.items():
+                percentage = round((value / total_count) * 100, 2) if total_count > 0 else 0.00
+                statistics.append({
+                    'name': name,
+                    'value': value,
+                    'percentage': percentage
+                })
+
+            # 按数量降序排序
+            statistics.sort(key=lambda x: x['value'], reverse=True)
+
+            return response.json(0, {
+                'category': event_type,  # 添加当前查看的异常类型
+                'total': total_count,
+                'statistics': statistics
+            })
+        except Exception as e:
+            print('error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))

+ 169 - 2
Model/models.py

@@ -1859,9 +1859,9 @@ class Order_Model(models.Model):
     addTime = models.IntegerField(verbose_name='添加时间', default=0)
     updTime = models.IntegerField(verbose_name='更新时间', default=0)
     isSelectDiscounts = models.SmallIntegerField(default=0, verbose_name=u'用户是否选择了第二年优惠 [0=否,1是]')
-    # 0: 待支付, 1:支付成功, 2: 取消支付, 4: 退款失败, 5: 全额退款, 6: 部分退款, 7: PayPal已退款, 9:处理中, 10:支付失败 11:客户申请退款
+    # 0: 待支付, 1:支付成功, 2: 取消支付, 4: 退款失败, 5: 全额退款, 6: 部分退款, 7: PayPal已退款, 9:处理中, 10:支付失败
     status = models.SmallIntegerField(default=0, verbose_name='付款状态')
-    # 1: PayPal, 2: 支付宝, 3: 微信, 5: 苹果内购, 10: 免费体验, 11: 激活码
+    # 1: PayPal, 2: 支付宝, 3: 微信, 4: 苹果支付, 5: 苹果内购, 10: 免费体验, 11: 激活码
     payType = models.SmallIntegerField(default=0, verbose_name='支付方式')
     payTime = models.IntegerField(verbose_name='支付成功时间', default=0)
     rank = models.ForeignKey(Store_Meal, to_field='id', default='', on_delete=models.CASCADE,
@@ -5536,3 +5536,170 @@ class DeviceDailyReport(models.Model):
         verbose_name = '设备日报记录表'
         verbose_name_plural = verbose_name
         app_label = 'PushModel'
+
+
+class AbnormalEvent(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    uid = models.CharField(default='', max_length=20, verbose_name='uid')
+    device_type = models.IntegerField(default=0, verbose_name='设备类型')
+    version = models.CharField(default='', max_length=64, verbose_name='设备版本')
+    event_code = models.CharField(default='', max_length=16, verbose_name='异常事件编码')
+    content = models.TextField(default='', verbose_name='异常内容')
+    # 上报类型, 0: 自动上报, 1: 手动上报
+    report_type = models.IntegerField(default=0, verbose_name='上报类型')
+    event_time = models.IntegerField(default=0, verbose_name='异常事件触发时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'abnormal_event'
+        verbose_name = '异常事件'
+        app_label = 'PushModel'
+
+
+class AbnormalEventCode(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    event_type = models.CharField(default='', max_length=16, verbose_name='异常类型')
+    event_code = models.CharField(default='', max_length=16, verbose_name='异常事件编码')
+    event = models.CharField(default='', max_length=16, verbose_name='异常事件')
+
+    class Meta:
+        db_table = 'abnormal_event_code'
+        verbose_name = '异常事件编码'
+        app_label = 'PushModel'
+
+
+class DictCategory(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    code = models.CharField(max_length=50, unique=True, verbose_name="类别编码")
+    # 1:表示后台 2:表示APP 3:表示其他程序
+    scenes = models.IntegerField(default=1, verbose_name="应用场景")
+    status = models.BooleanField(default=True, verbose_name="是否启用")
+    ext_data = models.JSONField(null=True, verbose_name='额外配置')
+    remark = models.TextField(blank=True, verbose_name="备注")
+
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    created_by = models.CharField(max_length=50, blank=True, verbose_name="创建人")
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    updated_by = models.CharField(max_length=50, blank=True, verbose_name="更新人")
+
+    class Meta:
+        db_table = 'dict_category'
+        verbose_name = '通用数据字典主表'
+
+
+class DictItem(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    category = models.ForeignKey(DictCategory, related_name='items', on_delete=models.CASCADE, verbose_name="类别id")
+    code = models.CharField(max_length=100, verbose_name="选项编码")
+    sort = models.IntegerField(default=0, verbose_name="排序")
+    status = models.BooleanField(default=True, verbose_name="是否启用")
+    remark = models.TextField(blank=True, verbose_name="备注")
+
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    created_by = models.CharField(max_length=50, blank=True, verbose_name="创建人")
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    updated_by = models.CharField(max_length=50, blank=True, verbose_name="更新人")
+
+    class Meta:
+        db_table = 'dict_item'
+        unique_together = ('category', 'code')
+        verbose_name = '通用数据字典子表'
+
+
+class DictCategoryI18n(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    category = models.ForeignKey(DictCategory, related_name='translations', on_delete=models.CASCADE,
+                                 verbose_name="类别id")
+    lang_code = models.CharField(max_length=10, verbose_name="语言代码")
+    name = models.CharField(max_length=100, verbose_name="类别名称")
+    remark = models.TextField(blank=True, verbose_name="备注")
+
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    created_by = models.CharField(max_length=50, blank=True, verbose_name="创建人")
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    updated_by = models.CharField(max_length=50, blank=True, verbose_name="更新人")
+
+    class Meta:
+        db_table = 'dict_category_i18n'
+        unique_together = ('category', 'lang_code')
+        verbose_name = "系统多语言表"
+
+
+class DictItemI18n(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    item = models.ForeignKey(DictItem, related_name='translations', on_delete=models.CASCADE, verbose_name="选项id")
+    lang_code = models.CharField(max_length=10, verbose_name="语言代码")
+    name = models.CharField(max_length=100, verbose_name="选项名称")
+    remark = models.TextField(blank=True, verbose_name="备注")
+
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    created_by = models.CharField(max_length=50, blank=True, verbose_name="创建人")
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    updated_by = models.CharField(max_length=50, blank=True, verbose_name="更新人")
+
+    class Meta:
+        db_table = 'dict_item_i18n'
+        unique_together = ('item', 'lang_code')
+        verbose_name = "字典项多语言表"
+
+
+class ProductsScheme(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    order_number = models.CharField(max_length=100, verbose_name='关联制作单号', blank=True)
+    storage_code = models.CharField(max_length=50, unique=True, verbose_name='入库编码')
+    # 1是NVR 2是IPC
+    device_type = models.SmallIntegerField(default=0, verbose_name='设备大类')
+    flash = models.CharField(max_length=50, verbose_name='闪存', blank=True)
+    ddr = models.CharField(max_length=50, verbose_name='DDR', blank=True)
+    main_controller = models.CharField(max_length=50, verbose_name='主控', blank=True)
+    wifi = models.CharField(max_length=50, verbose_name='Wifi', blank=True)
+    four_g = models.CharField(max_length=50, verbose_name='4G', blank=True)
+    ad = models.CharField(max_length=50, verbose_name='AD', blank=True)
+    sensor = models.CharField(max_length=50, verbose_name='传感器', blank=True)
+    order_quantity = models.IntegerField(verbose_name='订单数量', default=0)
+    customer_code = models.CharField(max_length=100, verbose_name='客户代码', blank=True)
+    phy = models.CharField(max_length=100, verbose_name='物理层器件', blank=True)
+    remark = models.TextField(blank=True, verbose_name="备注")
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    created_by = models.CharField(max_length=64, verbose_name='创建人')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    updated_by = models.CharField(max_length=64, blank=True, verbose_name="更新人")
+    deleted = models.BooleanField(default=False, verbose_name='逻辑删除')
+
+    class Meta:
+        db_table = 'products_scheme'
+        verbose_name = "产品方案"
+
+
+class DeviceScheme(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    serial_number = models.CharField(max_length=32, unique=True, default='', verbose_name='序列号')
+    full_serial_number = models.CharField(max_length=32, default='', verbose_name='全序列号')
+    # IPC型号,0是NVR
+    device_type = models.SmallIntegerField(default=0, verbose_name='设备型号')
+    phone_model = models.CharField(max_length=64, default='', verbose_name='手机型号')
+    storage_code = models.CharField(max_length=50, db_index=True, verbose_name='入库编码')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'device_scheme'
+        verbose_name = "设备方案"
+
+
+class ProductTroubleshoot(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    date_time = models.IntegerField(default=0, verbose_name='产品录入时间')
+    # 1是NVR 2是IPC
+    device_type = models.SmallIntegerField(default=0, verbose_name='设备大类')
+    device_id = models.CharField(blank=True, max_length=50, db_index=True, default='', verbose_name='序列号')
+    storage_code = models.CharField(max_length=50, default='', verbose_name='入库编码')
+    event_code = models.CharField(default='', max_length=16, verbose_name='异常事件编码')
+    status = models.SmallIntegerField(default=0, verbose_name='处理状态')
+    remark = models.TextField(blank=True, verbose_name="备注")
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'product_troubleshoot'
+        verbose_name = "产品异常记录"

+ 27 - 0
Service/CommonService.py

@@ -859,6 +859,33 @@ GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
         c_serial_info = c_serial_qs.values('uid__uid')
         return c_serial_info[0]['uid__uid']
 
+    @staticmethod
+    def get_uids_by_serial_numbers(serial_numbers):
+        """
+        根据多个序列号获取绑定uid列表
+        @param serial_numbers: 多个6位序列号列表
+        @return: uid列表
+        """
+        if not serial_numbers:
+            return []
+
+        # 确保所有序列号都是6位
+        serial_list = [serial[:6] for serial in serial_numbers if serial]
+        if not serial_list:
+            return []
+
+        # 查询所有匹配的序列号
+        c_serial_qs = UIDCompanySerialModel.objects.filter(company_serial__serial_number__in=serial_list)
+
+        # 如果没有匹配记录,返回原序列号列表
+        if not c_serial_qs.exists():
+            return serial_numbers
+
+        # 获取所有匹配的uid
+        uid_list = list(c_serial_qs.values_list('uid__uid', flat=True))
+
+        return uid_list
+
     @staticmethod
     def get_serial_number_by_uid(uid):
         """