| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372 | #!/usr/bin/env python3# -*- coding: utf-8 -*-import ioimport jsonimport operatorimport osimport threadingimport timeimport csvimport oss2import requestsfrom obs import ObsClientfrom django.core.paginator import Paginatorfrom django.db import transactionfrom django.db.models import Q, F, Sum, OuterRef, Min, Subqueryfrom django.forms.models import model_to_dictfrom django.views.generic.base import Viewfrom Ansjer.config import LOGGER, SERIAL_DOMAIN_NAME, HUAWEICLOUD_AK, HUAWEICLOUD_SK, HUAWEICLOUD_OBS_SERVER, \    HUAWEICLOUD_BAIDU_BIG_MODEL_LICENSE_BUKET,CONFIG_INFO, CONFIG_TEST, CONFIG_CN, CONFIG_US, CONFIG_EURfrom Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, \    AWS_SES_ACCESS_REGIONfrom Ansjer.config import SERVER_DOMAIN_TEST, SERVER_DOMAIN_CN, SERVER_DOMAIN_US, SERVER_DOMAIN_EURfrom Model.models import Device_Info, UidSetModel, LogModel, UID_Bucket, Unused_Uid_Meal, StsCrdModel, \    VodHlsModel, ExperienceContextModel, DeviceTypeModel, UidUserModel, ExperienceAiModel, AiService, \    AppBundle, App_Info, AppDeviceType, DeviceNameLanguage, UIDCompanySerialModel, UidPushModel, \    CustomCustomerOrderInfo, CustomCustomerDevice, DeviceVersionInfo, VoicePromptModel, DeviceAlgorithmExplain, BaiduBigModelLicense, \    Instavisionfrom Object.AWS.AmazonS3Util import AmazonS3Utilfrom Object.Enums.RedisKeyConstant import RedisKeyConstantfrom Object.RedisObject import RedisObjectfrom Object.ResponseObject import ResponseObjectfrom Object.TokenObject import TokenObjectfrom Service.CommonService import CommonServicefrom Service.EquipmentInfoService import EquipmentInfoServicefrom Service.ModelService import ModelServicefrom Service.VodHlsService import SplitVodHlsObjectclass DeviceManagement(View):    def get(self, request, *args, **kwargs):        request.encoding = 'utf-8'        operation = kwargs.get('operation')        return self.validation(request.GET, request, operation)    def post(self, request, *args, **kwargs):        request.encoding = 'utf-8'        operation = kwargs.get('operation')        return self.validation(request.POST, request, operation)    def validation(self, request_dict, request, operation):        language = request_dict.get('language', 'en')        response = ResponseObject(language, 'pc')        if operation == 'addDeviceType':            return self.addDeviceType(request, request_dict, response)        elif operation == 'delDeviceData':  # 删除设备数据            return self.del_device_data(request, request_dict, response)        elif operation == 'getDeviceIcon':  # app获取设备图标            response = ResponseObject(language)            return self.get_device_icon(request_dict, response)        elif operation == 'addAppDeviceType':  # 添加app设备类型数据并上传图标            return self.add_app_device_type(request_dict, response, request)        elif operation == 'getUidPush':  # 查询推送信息            return self.get_uid_push(request_dict, response)        elif operation == 'checkDeviceInfo':            return self.query_device_user(request, request_dict, response)        else:            tko = TokenObject(                request.META.get('HTTP_AUTHORIZATION'),                returntpye='pc')            if tko.code != 0:                return response.json(tko.code)            response.lang = tko.lang            userID = tko.userID            if not userID:                return response.json(444, 'userID')            if operation == 'getDeviceInfoList':  # 获取设备信息数据                return self.get_device_info_list(request_dict, response)            elif operation == 'deleteDevice':  # 删除设备                return self.deleteDevice(request, request_dict, response, userID)            elif operation == 'delDeviceDataV2':  # 后台设备删除数据                return self.del_device_data(request, request_dict, response, userID)            elif operation == 'resetVod':  # 重置云存                return self.resetVod(request, request_dict, response)            elif operation == 'resetAi':  # 重置AI                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':                return self.deleteDeviceType(request_dict, response)            elif operation == 'getAppDeviceTypeList':  # 获取app设备类型数据                return self.get_app_device_type_list(request_dict, response)            elif operation == 'getAppBundleIdList':  # 获取app包id数据                return self.get_app_bundle_id_list(response)            elif operation == 'editAppDeviceType':  # 编辑app设备类型数据                return self.edit_app_device_type(request_dict, request, response)            elif operation == 'batchEditAppDeviceType':  # 批量编辑app设备类型数据                return self.batch_edit_app_device_type(request_dict, request, response)            elif operation == 'deleteAppDeviceType':  # 删除app设备类型数据                return self.delete_app_device_type(request_dict, response)            elif operation == 'getAppBundle':  # 获取app版本包                return self.get_app_bundle(response)            elif operation == 'resetAll':  # 重置设备主用户/云存/AI                return self.reset_all(request, request_dict, response)            elif operation == 'getAppNameList':  # 获取app版本包                return self.get_app_name_list(response)            elif operation == 'callAddAppDeviceType':  # 可选服添加app设备类型数据并上传图标                return self.call_add_app_device_type(request_dict, response, request)            elif operation == 'getCustomerDeviceList':  # 查询扫码添加设备列表                return self.get_customer_device_list(request_dict, response)            # 设备型号版本            elif operation == 'getDeviceVerInfo':  # 查询设备型号版本列表                return self.get_device_ver_info(request_dict, response)            elif operation == 'addDeviceVerInfo':  # 添加设备型号版本                return self.add_device_ver_info(request_dict, response)            elif operation == 'editDeviceVerInfo':  # 编辑设备型号版本                return self.edit_device_ver_info(request_dict, response)            elif operation == 'delDeviceVerInfo':  # 删除设备型号版本                return self.del_device_ver_info(request_dict, response)            elif operation == 'syncDeviceVersion':  # 一键同步                return self.sync_device_version(request_dict, response)            # 设备语音设置            elif operation == 'getDeviceVoice':  # 获取设备音频                return self.get_device_voice(request_dict, response)            elif operation == 'algorithmTypeList':  # 添加设备型号版本                return self.algorithm_type_list(response)            elif operation == 'addDeviceVoice':  # 获取设备音频列表                return self.add_device_voice(request, request_dict, response)            elif operation == 'editDeviceVoice':                return self.edit_device_voice(request_dict, response)            elif operation == 'delDeviceVoice':                return self.del_device_voice(request_dict, response)            elif operation == 'deviceTypeList':                return self.device_type_list(response)            # 百度大模型            elif operation == 'getBaiduBigModelLicense':  # 查询大模型许可证                return self.get_baidu_big_model_license(request_dict, response)            elif operation == 'addBaiduBigModelLicense':  # 添加大模型许可证                return self.add_baidu_big_model_license(request, response)            elif operation == 'editBaiduBigModelLicense':  # 编辑大模型许可证                return self.edit_baidu_big_model_license(request, request_dict, response)            elif operation == 'delBaiduBigModelLicense':   # 删除大模型许可证                return self.del_baidu_big_model_license(request_dict, response)            # Instavision即时视觉            elif operation == 'getInstavision':  # 查询即时视觉列表                return self.get_instavision(request_dict, response)            elif operation == 'addInstavision':  # 添加即时视觉                return self.add_instavision(request, response)            elif operation == 'editInstavision':  # 编辑即时视觉                return self.edit_instavision(request_dict, response)            elif operation == 'delInstavision':   # 删除即时视觉                return self.del_instavision(request_dict, response)            elif operation == 'devicePowerDisplay':                return self.device_power_display(request_dict, response)            else:                return response.json(444, 'operation')    @classmethod    def get_app_bundle(cls, response):        """        获取app版本id        """        app_bundle_qs = AppBundle.objects.all().values('id', 'app_bundle_id')        if not app_bundle_qs.exists():            return response.json(0)        app_bundle_list = []        for app_bundle in app_bundle_qs:            app_bundle_qs.exists()            app_bundle_list.append(app_bundle)        return response.json(0, app_bundle_list)    @classmethod    def get_device_info_list(cls, request_dict, response):        pageNo = request_dict.get('pageNo', None)        pageSize = request_dict.get('pageSize', None)        UID = request_dict.get('UID', None)        serialNumber = request_dict.get('serialNumber', None)        NickName = request_dict.get('NickName', None)        username = request_dict.get('username', None)        version = request_dict.get('version', None)        Type = request_dict.get('Type', None)        if not all([pageNo, pageSize]):            return response.json(444)        page = int(pageNo)        line = int(pageSize)        try:            if any([UID, serialNumber, NickName, username, version, Type]):  # 条件查询                if UID:                    device_info_qs = Device_Info.objects.filter(UID__icontains=UID)                if serialNumber:                    device_info_qs = Device_Info.objects.filter(serial_number__icontains=serialNumber[:9])                if NickName:                    device_info_qs = Device_Info.objects.filter(NickName__icontains=NickName)                if username:                    device_info_qs = Device_Info.objects.filter(Q(userID__username__icontains=username) |                                                                Q(userID__userEmail__icontains=username) |                                                                Q(userID__phone__icontains=username))                if version:                    uid_list = UidSetModel.objects.filter(version__icontains=version).values_list('uid', flat=True)                    device_info_qs = Device_Info.objects.filter(UID__in=uid_list)                if Type:                    type_list = DeviceTypeModel.objects.filter(name=Type).values_list('type', flat=True)                    device_info_qs = Device_Info.objects.filter(Type__in=type_list)                total = device_info_qs.count()                if not total:                    return response.json(0, {'list': {}, 'total': 0})                device_info_qs = device_info_qs[(page - 1) * line:page * line]            else:  # 查询全部                total = Device_Info.objects.filter().count()                device_info_qs = Device_Info.objects.filter()[(page - 1) * line:page * line]                if not device_info_qs.exists():                    return response.json(0, {'list': {}, 'total': 0})            device_info_list = CommonService.qs_to_dict(device_info_qs)            for k, v in enumerate(device_info_list["datas"]):                for device_info in device_info_qs:                    if v['pk'] == device_info.id:                        # 设备的用户名和主用户                        username = ModelService.get_user_name(device_info_list["datas"][k]['fields']['userID'])                        device_info_list["datas"][k]['fields']['username'] = username                        device_info_list["datas"][k]['fields']['vodPrimaryMaster'] = \                            device_info_list["datas"][k]['fields']['vodPrimaryMaster']                        # 设备类型,是否支持Alexa和ip                        type = device_info_list["datas"][k]['fields']['Type']                        device_type_qs = DeviceTypeModel.objects.filter(type=type).values('name')                        if device_type_qs.exists():                            device_info_list["datas"][k]['fields']['Type'] = device_type_qs[0]['name']                        uid_set_qs = UidSetModel.objects.filter(                            uid=device_info_list["datas"][k]['fields']['UID']). \                            values('detect_status', 'is_alexa', 'ip', 'version', 'is_ai', 'is_human', 'cloud_vod',                                   'ucode', 'device_type')                        if uid_set_qs.exists():                            # 移动侦测                            iSNotification = '开' if uid_set_qs[0]['detect_status'] else '关'                            device_info_list["datas"][k]['fields']['iSNotification'] = iSNotification                            isAlexa = '是' if uid_set_qs[0]['is_alexa'] else '否'                            isHuman = '是' if uid_set_qs[0]['is_human'] else '否'                            cloud_vod = CommonService.is_cloud_device(uid_set_qs[0]['ucode'],                                                                      uid_set_qs[0]['device_type'])                            if cloud_vod:                                cloud_vod = '支持'                            else:                                cloud_vod = '不支持'                            if uid_set_qs[0]['is_ai'] == 2:                                isAI = '不支持'                            else:                                isAI = '支持'                            device_info_list["datas"][k]['fields']['isHuman'] = isHuman                            device_info_list["datas"][k]['fields']['isAI'] = isAI                            device_info_list["datas"][k]['fields']['isAlexa'] = isAlexa                            device_info_list["datas"][k]['fields']['cloudVod'] = cloud_vod                            device_info_list["datas"][k]['fields']['ip'] = uid_set_qs[0]['ip']                            device_info_list["datas"][k]['fields']['version'] = uid_set_qs[0]['version']                        uid_bucket_qs = UID_Bucket.objects.filter(                            uid=device_info_list["datas"][k]['fields']['UID']).values('status')                        #  0是关闭,1是开启                        if uid_bucket_qs.exists():                            res = []                            for uid_bucket in uid_bucket_qs:                                status = uid_bucket['status']                                res.append(status)                            if 1 in res:                                device_info_list["datas"][k]['fields']['status'] = 1                            else:                                device_info_list["datas"][k]['fields']['status'] = 0                        else:                            device_info_list["datas"][k]['fields']['status'] = 0                        # AI开关状态                        ai_service = AiService.objects.filter(uid=device_info_list["datas"][k]['fields']['UID']).values(                            'detect_status')                        if ai_service.exists():                            if ai_service[0]['detect_status']:                                device_info_list["datas"][k]['fields']['ai_status'] = 1                            else:                                device_info_list["datas"][k]['fields']['ai_status'] = 0                        else:                            device_info_list["datas"][k]['fields']['ai_status'] = 0            return response.json(0, {'list': device_info_list, 'total': total})        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    # 根据id删除设备    def deleteDevice(self, request, request_dict, response, user_id):        deviceID = request_dict.get('deviceID', None)        userID = request_dict.get('userID', None)        uid = request_dict.get('uid', None)        if not all([deviceID, userID, uid]):            return response.json(444)        try:            redis = RedisObject(3)            with transaction.atomic():                Device_Info.objects.filter(id=deviceID).delete()                UidPushModel.objects.filter(uid_set__uid=uid).delete()                # 删除推送消息                EquipmentInfoService.delete_all_equipment_info(device_user_id=userID, device_uid=uid)                # 构建Redis键                device_key = f"{RedisKeyConstant.BASIC_USER.value}{userID}:UID:{uid}"                redis.del_data(device_key)                content = json.loads(json.dumps(request_dict))                ip = CommonService.get_ip_address(request)                log = {                    'user_id': 2,                    'status': 200,                    'time': int(time.time()),                    'url': 'deviceManagement/deleteDevice',                    'content': user_id,                    'ip': ip,                    'operation': '删除设备和配置记录:{}'.format(json.dumps(content)),                }                LogModel.objects.create(**log)            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    # 重置设备主用户    def resetPrimaryUser(self, request, request_dict, response):        uid = request_dict.get('uid', None)        if not uid:            return response.json(404)        try:            # 记录操作日志            ip = CommonService.get_ip_address(request)            content = json.loads(json.dumps(request_dict))            log = {                'ip': ip,                'user_id': 2,                'status': 200,                'time': int(time.time()),                'url': 'deviceManagement/resetPrimaryUser',                'content': json.dumps(content),                'operation': '{}重置设备主用户'.format(uid),            }            LogModel.objects.create(**log)            Device_Info.objects.filter(UID=uid).update(vodPrimaryUserID='', vodPrimaryMaster='')            return response.json(0)        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    # 重置设备云存    def resetVod(self, request, request_dict, response):        uid = request_dict.get('uid', None)        if not uid:            return response.json(444)        try:            # 记录操作日志            ip = CommonService.get_ip_address(request)            content = json.loads(json.dumps(request_dict))            log = {                'ip': ip,                'user_id': 2,                'status': 200,                'time': int(time.time()),                'url': 'deviceManagement/resetVod',                'content': json.dumps(content),                'operation': '{}重置云存'.format(uid),            }            with transaction.atomic():                LogModel.objects.create(**log)                # 删除和更新设备云存相关数据                UID_Bucket.objects.filter(uid=uid).delete()                AiService.objects.filter(uid=uid).delete()                Unused_Uid_Meal.objects.filter(uid=uid).delete()                # Order_Model.objects.filter(UID=uid, order_type=0).delete()                StsCrdModel.objects.filter(uid=uid).delete()                VodHlsModel.objects.filter(uid=uid).delete()                # 删除vod_hls分表数据                split_vod_hls_obj = SplitVodHlsObject()                split_vod_hls_obj.del_vod_hls_data(uid=uid)                ExperienceContextModel.objects.filter(uid=uid).delete()                Device_Info.objects.filter(UID=uid).update(vodPrimaryUserID='', vodPrimaryMaster='')            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def reset_ai(request, request_dict, response):        uid = request_dict.get('uid', None)        if not uid:            return response.json(444)        try:            # 记录操作日志            ip = CommonService.get_ip_address(request)            content = json.loads(json.dumps(request_dict))            log = {                'ip': ip,                'user_id': 2,                'status': 200,                'time': int(time.time()),                'url': 'deviceManagement/resetAi',                'content': json.dumps(content),                'operation': '{}重置AI'.format(uid),            }            with transaction.atomic():                LogModel.objects.create(**log)                # 删除和更新设备AI相关数据                ExperienceAiModel.objects.filter(uid=uid).delete()                AiService.objects.filter(uid=uid).delete()            return response.json(0)        except Exception as e:            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)        pageNo = request_dict.get('pageNo', None)        pageSize = request_dict.get('pageSize', None)        if not all([pageNo, pageSize]):            return response.json(444)        page = int(pageNo)        line = int(pageSize)        try:            if name:                device_type_qs = DeviceTypeModel.objects.filter(name__contains=name).values()                total = len(device_type_qs)            else:                device_type_qs = DeviceTypeModel.objects.filter().values()[(page - 1) * line:page * line]                total = DeviceTypeModel.objects.filter().count()            if not device_type_qs.exists():                return response.json(173)            device_type_list = []            for device_type in device_type_qs:                auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)                bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'ansjer-static-resources')                icon = device_type['icon']                url = 'device_type/' + icon                device_type['icon'] = bucket.sign_url('GET', url, 3600)                device_type_list.append(device_type)            return response.json(0, {'list': device_type_list, 'total': total})        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    # 删除设备类型    def deleteDeviceType(self, request_dict, response):        deviceTypeID = request_dict.get('deviceTypeID', None)        if not deviceTypeID:            return response.json(444)        try:            DeviceTypeModel.objects.filter(id=deviceTypeID).delete()            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    # 添加设备类型    def addDeviceType(self, request, request_dict, response):        iconFile = request.FILES.get('iconFile', None)        name = request_dict.get('name', None)        model = request_dict.get('model', None)        type = request_dict.get('type', None)        ptz_type = request_dict.get('ptz_type', None)        if not all([iconFile, name, model, type, ptz_type]):            return response.json(444)        try:            model = int(model)            ptz_type = int(ptz_type)            icon = iconFile.name            now_time = int(time.time())            # 上传文件到阿里云OSS            auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)            bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'ansjer-static-resources')            key = 'device_type/' + icon  # 图片文件存放于 device_type 目录下            # https://oss.console.aliyun.com/bucket/oss-cn-shenzhen/ansjer-static-resources/object?path=device_type%2F            bucket.put_object(key=key, data=iconFile)            DeviceTypeModel.objects.create(name=name, model=model, type=type, ptz_type=ptz_type, icon=icon,                                           add_time=now_time, update_time=now_time)            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def del_device_data(request, request_dict, response, user_id=''):        uidList = request_dict.get('uidList', None)        delDataOptions = request_dict.get('delDataOptions', None)        serialNumberList = request_dict.get('serialNumberList', None)        if not all([uidList or serialNumberList, delDataOptions]):            return response.json(444)        # 记录日志        content = json.loads(json.dumps(request_dict))        ip = CommonService.get_ip_address(request)        log = {            'user_id': 2,            'status': 200,            'time': int(time.time()),            'url': 'deviceManagement/delDeviceData',            'content': delDataOptions,            'ip': ip,            'operation': '上传文件设备重置删除前:user:{},{}'.format(user_id, json.dumps(content)),        }        LogModel.objects.create(**log)        try:            with transaction.atomic():                if uidList:                    #  uid                    uidList = uidList.splitlines()  # 按行('\r', '\r\n', \n')切割字符串返回列表                    uid_list = []                    for uid in uidList:                        uid_val = uid.replace(" ", "")                        if not uid_val:                            continue                        uid_list.append(uid_val)                    uidList = uid_list                else:                    #  序列号                    serialNumberList = serialNumberList.splitlines()  # 按行('\r', '\r\n', \n')切割字符串返回列表                    serial_number_list = []                    for serial_number in serialNumberList:                        serial_number = serial_number.replace(" ", "")                        if not serial_number:                            continue                        serial_number_list.append(serial_number[0:6])                    uid_company_serial_qs = UIDCompanySerialModel.objects.filter(                        company_serial__serial_number__in=serial_number_list).values('uid__uid')                    uidList = [item[key] for item in uid_company_serial_qs for key in item]                # 根据删除项删除相关数据                if '设备信息数据' in delDataOptions:                    # 删除用户UID缓存                    user_list = list(Device_Info.objects.filter(UID__in=uidList).values('userID_id', 'UID'))                    thread = threading.Thread(target=DeviceManagement.deleteDeviceCache, args=(user_list,))                    thread.start()                    Device_Info.objects.filter(UID__in=uidList).delete()                    UidPushModel.objects.filter(uid_set__uid__in=uidList).delete()                if '设备配置数据' in delDataOptions:                    UidSetModel.objects.filter(uid__in=uidList).delete()                if '设备推送数据' in delDataOptions:                    EquipmentInfoService.delete_all_equipment_info(device_uid__in=uidList)                if '设备AP信息数据' in delDataOptions:                    UidUserModel.objects.filter(UID__in=uidList).delete()                if '设备AI数据' in delDataOptions:                    ExperienceAiModel.objects.filter(uid__in=uidList).delete()                    # Order_Model.objects.filter(UID__in=uidList, order_type=1).delete()                if '设备云存数据' in delDataOptions:                    UID_Bucket.objects.filter(uid__in=uidList).delete()                    AiService.objects.filter(uid__in=uidList).delete()                    StsCrdModel.objects.filter(uid__in=uidList).delete()                    VodHlsModel.objects.filter(uid__in=uidList).delete()                    # 删除vod_hls分表数据                    split_vod_hls_obj = SplitVodHlsObject()                    split_vod_hls_obj.del_vod_hls_data(uid__in=uidList)                    Unused_Uid_Meal.objects.filter(uid__in=uidList).delete()                    ExperienceContextModel.objects.filter(uid__in=uidList).delete()                    # Order_Model.objects.filter(UID__in=uidList, order_type=0).delete()                    Device_Info.objects.filter(UID__in=uidList).update(vodPrimaryUserID='', vodPrimaryMaster='')                # 上传序列号文件且选中序列号解绑uid                # if serialNumberList is not None and '序列号解绑uid' in delDataOptions:                #     # 解绑uid数据                #     UIDModel.objects.filter(uid__in=uidList, status=2).update(status=0)                #     UIDCompanySerialModel.objects.filter(uid__uid__in=uidList).delete()                #     CompanySerialModel.objects.filter(serial_number__in=serial_number_list).update(status=1)                #     UidPushModel.objects.filter(uid_set__uid__in=uidList).delete()                #     # 序列号加入重置状态redis列表                #     redis_obj = RedisObject()                #     for serial in serial_number_list:                #         redis_obj.rpush(UNUSED_SERIAL_REDIS_LIST, serial)                device_list = uidList if serialNumberList is None else serial_number_list                log = {                    'user_id': 2,                    'status': 200,                    'time': int(time.time()),                    'url': 'deviceManagement/delDeviceData',                    'content': json.dumps(content),                    'ip': ip,                    'operation': '删除数据的设备列表:{}'.format(device_list),                }                LogModel.objects.create(**log)            return response.json(0)        except Exception as e:            log = {                'user_id': 2,                'status': 500,                'time': int(time.time()),                'url': 'deviceManagement/delDeviceData',                'content': json.dumps(content),                'ip': ip,                'operation': '删除数据失败的设备列表:{},{},{}'.format(device_list, e.__traceback__.tb_lineno, repr(e)),            }            LogModel.objects.create(**log)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def deleteDeviceCache(uid_list):        """        翻新重置时清楚验证用户UID缓存        """        try:            redis = RedisObject(3)            for item in uid_list:                # 构建Redis键                device_key = f"{RedisKeyConstant.BASIC_USER.value}{item['userID_id']}:UID:{item['UID']}"                redis.del_data(device_key)        except Exception as e:            error_line = e.__traceback__.tb_lineno            LOGGER.error(f'翻新重置异步清缓存异常:error_line:{error_line}, error_msg:{repr(e)}')    def get_app_device_type_list(self, request_dict, response):        app_bundle_name = request_dict.get('appBundleName', None)        lang = request_dict.get('lang', None)        model = request_dict.get('model', None)        type = request_dict.get('type', None)        name = request_dict.get('name', None)        pageNo = request_dict.get('pageNo', None)        pageSize = request_dict.get('pageSize', None)        if not all([pageNo, pageSize]):            return response.json(444)        page = int(pageNo)        line = int(pageSize)        try:            app_bundle_qs = AppBundle.objects.all()            if app_bundle_name:                app_bundle_id = self.app_name_convert_id([app_bundle_name])                print(app_bundle_id)                app_bundle_qs = app_bundle_qs.filter(id__in=app_bundle_id)            if lang:                app_bundle_qs = app_bundle_qs.filter(app_device_type__devicenamelanguage__lang=lang)            app_bundle_qs = app_bundle_qs.annotate(                model=F('app_device_type__model'), type=F('app_device_type__type'), icon=F('app_device_type__icon'),                lang=F('app_device_type__devicenamelanguage__lang'), iconV2=F('app_device_type__iconV2'),                name=F('app_device_type__devicenamelanguage__name'),                sort=F('app_device_type__devicenamelanguage__sort')).values('id', 'app_device_type__id', 'model',                                                                            'type', 'icon', 'iconV2', 'app_bundle_id',                                                                            'app_device_type__devicenamelanguage__id',                                                                            'lang', 'name', 'sort',                                                                            'app_device_type__app_version_number_id',                                                                            'app_device_type__config').order_by(                'app_device_type__devicenamelanguage__sort')            if not app_bundle_qs.exists():                return response.json(0)            if name:                app_bundle_qs = app_bundle_qs.filter(name=name)            if model:                app_bundle_qs = app_bundle_qs.filter(model=model)            if type:                app_bundle_qs = app_bundle_qs.filter(type=type)            total = app_bundle_qs.count()            app_bundle_qs = app_bundle_qs[(page - 1) * line:page * line]            app_device_type_list = []            for app_bundle in app_bundle_qs:                app_bundle['version_number'] = app_bundle.pop('app_device_type__app_version_number_id')                app_device_type_list.append(app_bundle)            return response.json(0, {'list': app_device_type_list, 'total': total})        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def get_app_bundle_id_list(response):        try:            app_info_qs = App_Info.objects.filter().values('id', 'appBundleId', 'appName')            appBundleIdList = list(app_info_qs)            return response.json(0, {'list': appBundleIdList})        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def batch_edit_app_device_type(request_dict, request, response):        # app_device_type表数据        app_device_type_id = request_dict.get('app_device_type__id', None)        model = request_dict.get('model', None)        type = request_dict.get('type', None)        icon = request.FILES.get('icon', None)        iconV2 = request.FILES.get('iconV2', None)        # device_name_language表数据        device_name_language_id = request_dict.get('app_device_type__devicenamelanguage__id', None)        sort = request_dict.get('sort', None)        version_number = request_dict.get('version_number', None)        config = request_dict.get('config', None)        now_time = int(time.time())        if not all([app_device_type_id, device_name_language_id, model, type, sort, version_number]):            return response.json(444)        # 强制类型转换        list_app_device_type_id = [int(item) for item in eval(app_device_type_id)]        list_device_name_language_id = [int(item) for item in eval(device_name_language_id)]        try:            with transaction.atomic():                if icon or iconV2:                    bucket_name = 'ansjerfilemanager'                    s3 = AmazonS3Util(AWS_ACCESS_KEY_ID[1], AWS_SECRET_ACCESS_KEY[1], AWS_SES_ACCESS_REGION)                    icon_path = ""                    icon_v2_path = ""                    # 处理 icon                    if icon:                        file_key = f'app/device_type_images/{now_time}_{icon.name}'                        icon_path = f'https://{bucket_name}.s3.amazonaws.com/{file_key}'                        s3.upload_file_obj(                            bucket_name,                            file_key,                            icon,                            {'ContentType': icon.content_type, 'ACL': 'public-read'}                        )                    # 处理 iconV2                    if iconV2:                        file_v2_key = f'app/device_type_images/{now_time}_v2_{iconV2.name}'                        icon_v2_path = f'https://{bucket_name}.s3.amazonaws.com/{file_v2_key}'                        s3.upload_file_obj(                            bucket_name,                            file_v2_key,                            iconV2,                            {'ContentType': iconV2.content_type, 'ACL': 'public-read'}                        )                    # 更新数据库                    update_fields = {                        'model': model,                        'type': type,                        'app_version_number_id': version_number,                    }                    if config:                        try:                            config = json.loads(config)                            update_fields['config'] = config                        except ValueError:                            return response.json(444, 'config必须是一个json数据')                    if icon_path:                        update_fields['icon'] = icon_path                    if icon_v2_path:                        update_fields['iconV2'] = icon_v2_path                    AppDeviceType.objects.filter(id__in=list_app_device_type_id).update(**update_fields)                else:                    # 没有上传文件的情况,只更新配置或基本信息                    update_fields = {                        'model': model,                        'type': type,                        'app_version_number_id': version_number,                    }                    if config:                        try:                            config = json.loads(config)                            update_fields['config'] = config                        except ValueError:                            return response.json(444, 'config必须是一个json数据')                    AppDeviceType.objects.filter(id__in=list_app_device_type_id).update(**update_fields)                DeviceNameLanguage.objects.filter(id__in=list_device_name_language_id).update(sort=sort)            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def edit_app_device_type(request_dict, request, response):        # app_device_type表数据        app_device_type_id = request_dict.get('app_device_type__id', None)        model = request_dict.get('model', None)        type = request_dict.get('type', None)        icon = request.FILES.get('icon', None)        iconV2 = request.FILES.get('iconV2', None)        # device_name_language表数据        device_name_language_id = request_dict.get('app_device_type__devicenamelanguage__id', None)        lang = request_dict.get('lang', None)        name = request_dict.get('name', None)        sort = request_dict.get('sort', None)        version_number = request_dict.get('version_number', None)        config = request_dict.get('config', None)        now_time = int(time.time())        if not all([app_device_type_id, model, type, device_name_language_id, lang, name, sort]):            return response.json(444)        try:            with transaction.atomic():                app_device_type = AppDeviceType.objects.filter(id=app_device_type_id).first()                if icon or iconV2:                    bucket_name = 'ansjerfilemanager'                    s3 = AmazonS3Util(AWS_ACCESS_KEY_ID[1], AWS_SECRET_ACCESS_KEY[1], AWS_SES_ACCESS_REGION)                    icon_path = app_device_type.icon                    icon_v2_path = app_device_type.iconV2                    if icon:                        icon_path = f'https://ansjerfilemanager.s3.amazonaws.com/app/device_type_images/{now_time}_{icon.name}'                        file_key = f'app/device_type_images/{now_time}_{icon.name}'                        s3.upload_file_obj(                            bucket_name,                            file_key,                            icon,                            {'ContentType': icon.content_type, 'ACL': 'public-read'})                    if iconV2:                        icon_v2_path = f'https://ansjerfilemanager.s3.amazonaws.com/app/device_type_images/{now_time}_v2_{iconV2.name}'                        file_v2_key = f'app/device_type_images/{now_time}_v2_{iconV2.name}'                        s3.upload_file_obj(                            bucket_name,                            file_v2_key,                            iconV2,                            {'ContentType': iconV2.content_type, 'ACL': 'public-read'})                    if config:                        try:                            config = json.loads(config)                        except:                            return response.json(444, 'config必须是一个json数据')                        AppDeviceType.objects.filter(id=app_device_type_id) \                            .update(model=model, type=type, icon=icon_path, iconV2=icon_v2_path,                                    app_version_number_id=version_number, config=config)                    else:                        AppDeviceType.objects.filter(id=app_device_type_id) \                            .update(model=model, type=type, icon=icon_path, iconV2=icon_v2_path,                                    app_version_number_id=version_number)                else:                    if config:                        try:                            config = json.loads(config)                        except:                            return response.json(444, 'config必须是一个json数据')                        AppDeviceType.objects.filter(id=app_device_type_id) \                            .update(model=model, type=type, app_version_number_id=version_number,                                    config=config)                    else:                        AppDeviceType.objects.filter(id=app_device_type_id) \                            .update(model=model, type=type, app_version_number_id=version_number)                DeviceNameLanguage.objects.filter(id=device_name_language_id).update(lang=lang, name=name, sort=sort)            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def delete_app_device_type(request_dict, response):        app_bundle_id = request_dict.get('appBundleId', None)        app_device_type_id = request_dict.get('appDeviceTypeId', None)        if not all([app_bundle_id, app_device_type_id]):            return response.json(444)        try:            # 删除语言表            DeviceNameLanguage.objects.filter(app_device_type_id=app_device_type_id).delete()            # 删除多对多关系            app_bundle_qs = AppBundle.objects.get(id=app_bundle_id)            app_bundle_qs.app_device_type.remove(app_device_type_id)            # 删除app类型表            AppDeviceType.objects.filter(id=app_device_type_id).delete()            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def reset_all(request, request_dict, response):        uid = request_dict.get('uid', None)        if not uid:            return response.json(444)        try:            # 记录操作日志            ip = CommonService.get_ip_address(request)            content = json.loads(json.dumps(request_dict))            with transaction.atomic():                # 删除主用户                Device_Info.objects.filter(UID=uid).update(vodPrimaryUserID='', vodPrimaryMaster='')                # 删除云存                UID_Bucket.objects.filter(uid=uid).delete()                Unused_Uid_Meal.objects.filter(uid=uid).delete()                # Order_Model.objects.filter(UID=uid, order_type=0).delete()                StsCrdModel.objects.filter(uid=uid).delete()                VodHlsModel.objects.filter(uid=uid).delete()                # 删除vod_hls分表数据                split_vod_hls_obj = SplitVodHlsObject()                split_vod_hls_obj.del_vod_hls_data(uid=uid)                ExperienceContextModel.objects.filter(uid=uid).delete()                # 删除AI                ExperienceAiModel.objects.filter(uid=uid).delete()                AiService.objects.filter(uid=uid).delete()                log = {                    'ip': ip,                    'user_id': 2,                    'status': 200,                    'time': int(time.time()),                    'url': 'deviceManagement/resetAll',                    'content': json.dumps(content),                    'operation': '{}重置所有'.format(uid),                }                LogModel.objects.create(**log)                return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    def add_app_device_type(self, request_dict, response, request):        """        添加设备类型        @param request_dict: 请求参数        @request_dict appBundleName: app包名        @request_dict versionNumber: app版本号        @request_dict model: 设备类型        @request_dict type: 设备型号        @request_dict name: 设备名称        @request_dict sort: 排序        @request.FILES iconFile: 上传图标        @param response: 响应对象        """        # app包名称        app_bundle_name = request_dict.get('appBundleName', None)        # 版本号        version_number = request_dict.get('versionNumber', None)        # app_device_type表数据        model = request_dict.get('model', None)        type = request_dict.get('type', None)        # device_name_language表数据        name = request_dict.get('name', None)        sort = request_dict.get('sort', None)        config = request_dict.get('config', None)        # 上传图标        file = request.FILES.get('iconFile', None)        file_v2 = request.FILES.get('iconV2File', None)        if config:            config = json.loads(config)        try:            type = int(type)            data_name = eval(name)            app_bundle_name_list = app_bundle_name.split(',')            app_bundle_id = self.app_name_convert_id(app_bundle_name_list)            existing_records = []            success_records = []            need_upload = False  # 标记是否需要上传文件            # 先检查所有数据是否存在            with transaction.atomic():                for app_id in app_bundle_id:                    for k, v in data_name.items():                        app_bundle_qs = AppBundle.objects.filter(id=app_id,                                                                 app_device_type__devicenamelanguage__lang=k,                                                                 app_device_type__app_version_number_id=version_number,                                                                 app_device_type__type=type,                                                                 app_device_type__model=model)                        if app_bundle_qs.exists():                            app_bundle = app_bundle_qs.values("app_bundle_id").first()                            existing_record = {"app_bundle_id": app_bundle["app_bundle_id"], "type": type,                                               "version_number": version_number, "lang": k, "model": model}                            existing_records.append(existing_record)                        else:                            need_upload = True  # 发现至少一条记录不存在,需要上传文件            # 如果需要上传文件            if need_upload:                with transaction.atomic():                    if file:                        fileName = file.name                        now_time = int(time.time())                        icon = f'https://ansjerfilemanager.s3.amazonaws.com/app/device_type_images/{now_time}_{fileName}'                        bucket_name = 'ansjerfilemanager'                        file_key = f'app/device_type_images/{now_time}_{fileName}'                        s3 = AmazonS3Util(AWS_ACCESS_KEY_ID[1], AWS_SECRET_ACCESS_KEY[1], AWS_SES_ACCESS_REGION)                        s3.upload_file_obj(bucket_name, file_key, file,                                           {'ContentType': file.content_type, 'ACL': 'public-read'})                    if file_v2:                        fileV2Name = file_v2.name                        now_time = int(time.time())                        iconV2 = f'https://ansjerfilemanager.s3.amazonaws.com/app/device_type_images/{now_time}_v2_{fileV2Name}'                        bucket_name = 'ansjerfilemanager'                        file_v2_key = f'app/device_type_images/{now_time}_v2_{fileV2Name}'                        s3 = AmazonS3Util(AWS_ACCESS_KEY_ID[1], AWS_SECRET_ACCESS_KEY[1], AWS_SES_ACCESS_REGION)                        s3.upload_file_obj(bucket_name, file_v2_key, file_v2,                                           {'ContentType': file_v2.content_type, 'ACL': 'public-read'})                    for app_id in app_bundle_id:                        for k, v in data_name.items():                            record_key = {"app_bundle_id": app_id, "type": type, "version_number": version_number,                                          "lang": k, "model": model}                            # 检查这个组合的记录是否存在                            if not any(rec == record_key for rec in existing_records):                                app_bundle = AppBundle.objects.filter(id=app_id).values('id', 'app_bundle_id').first()                                app_device_type_qs = AppDeviceType.objects.create(model=model, type=type,                                                                                  icon=icon if file else "",                                                                                  iconV2=iconV2 if file_v2 else "",                                                                                  app_version_number_id=version_number,                                                                                  config=config)                                DeviceNameLanguage.objects.create(lang=k, name=v, sort=sort,                                                                  app_device_type_id=app_device_type_qs.id)                                app_device_type_qs.appbundle_set.add(app_bundle["id"])                                success_records.append(                                    {"app_bundle_id": app_bundle["app_bundle_id"], "type": type,                                     "version_number": version_number,                                     "lang": k, "model": model}                                )            response_data = {                'success_records': success_records,                'existing_records': existing_records            }            return response.json(0, response_data)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def get_device_icon(request_dict, response):        """        查询设备信息图标        @param request_dict: 请求参数        @request_dict lang: 语言        @request_dict app_bundle_id: app版本id        @request_dict version_number: app版本号        @param response: 响应对象        @return:        """        lang = request_dict.get('lang', 'en')        app_bundle_id = request_dict.get('appBundleId', None)        version_number = request_dict.get('versionNumber', None)        # 查询设备信息图标        api_version = request_dict.get('apiVersion', None)        if not all([lang, app_bundle_id, version_number]):            return response.json(444)        try:            # tc是ios繁体字语言类型            if lang == 'tc':                lang = 'cn_tw'            app_bundle_qs = AppBundle.objects.filter(app_bundle_id=app_bundle_id).values(                'app_device_type__app_version_number_id').distinct().order_by('app_device_type__app_version_number_id')            #  判断版本是否存在, 不存在则获取输入版本范围内最接近的输入版本            version_number_list = []            app_bundle_list = []            for version in app_bundle_qs:                version_number_list.append(version['app_device_type__app_version_number_id'])            new_version_number = CommonService.compare_version_number(version_number, version_number_list)            app_device_qs = DeviceNameLanguage.objects.filter(lang=lang)            if not app_device_qs.exists():                lang = 'en'            # 版本号对应的设备信息图标            for version_number in new_version_number:                app_bundle_qs = AppBundle.objects.filter(app_bundle_id=app_bundle_id,                                                         app_device_type__devicenamelanguage__lang=lang,                                                         app_device_type__app_version_number_id=version_number). \                    annotate(                    model=F('app_device_type__model'), type=F('app_device_type__type'), icon=F('app_device_type__icon'),                    name=F('app_device_type__devicenamelanguage__name'), iconV2=F('app_device_type__iconV2'),                    sort=F('app_device_type__devicenamelanguage__sort'),                    config=F('app_device_type__config'),                    app_version_number_id=F('app_device_type__app_version_number_id')).values('model', 'type', 'icon',                                                                                              'name', 'sort', 'config',                                                                                              'iconV2',                                                                                              'app_device_type__app_version_number_id')                # 使用lang="en"来补全缺失的数据                en_lang_qs = AppBundle.objects.filter(                    app_bundle_id=app_bundle_id,                    app_device_type__devicenamelanguage__lang="en",                    app_device_type__app_version_number_id=version_number                ).annotate(                    model=F('app_device_type__model'),                    type=F('app_device_type__type'),                    icon=F('app_device_type__icon'),                    name=F('app_device_type__devicenamelanguage__name'),                    iconV2=F('app_device_type__iconV2'),                    sort=F('app_device_type__devicenamelanguage__sort'),                    config=F('app_device_type__config'),                    app_version_number_id=F('app_device_type__app_version_number_id')                ).values('model', 'type', 'icon', 'name', 'sort', 'config', 'iconV2',                         'app_device_type__app_version_number_id')                # 转换查询集为字典                current_lang_data = {item['type']: item for item in app_bundle_qs}                en_lang_data = {item['type']: item for item in en_lang_qs}                # 合并数据,优先使用当前语言的数据,缺少的字段用英文补充                for type, en_data in en_lang_data.items():                    current_data = current_lang_data.get(type, {})                    merged_data = {                        'type': en_data['type'],                        'model': current_data.get('model', en_data['model']),                        'icon': current_data.get('icon', en_data['icon']),                        'name': current_data.get('name', en_data['name']),                        'sort': current_data.get('sort', en_data['sort']),                        'config': current_data.get('config', en_data['config']),                        'iconV2': current_data.get('iconV2', en_data['iconV2']),                        'app_device_type__app_version_number_id': current_data.get(                            'app_device_type__app_version_number_id',                            en_data['app_device_type__app_version_number_id']),                    }                    if api_version == "V2":                        app_bundle_list.append({                            'model': merged_data['model'],                            'type': merged_data['type'],                            'icon': merged_data['iconV2'] if merged_data['iconV2'] != "" else merged_data['icon'],                            'name': merged_data['name'],                            'sort': merged_data['sort'],                            'config': merged_data['config'],                            'app_device_type__app_version_number_id': merged_data['app_device_type__app_version_number_id'],                        })                    else:                        app_bundle_list.append({                            'model': merged_data['model'],                            'type': merged_data['type'],                            'icon': merged_data['icon'],                            'name': merged_data['name'],                            'sort': merged_data['sort'],                            'config': merged_data['config'],                            'app_device_type__app_version_number_id': merged_data[                                'app_device_type__app_version_number_id'],                        })            dvr_list = [app_bundle for app_bundle in app_bundle_list if app_bundle['model'] == 1]            ipc_list = [app_bundle for app_bundle in app_bundle_list if app_bundle['model'] == 2]            res = {                'deviceDvr': sorted(dvr_list, key=operator.itemgetter('sort')),                'deviceIpc': sorted(ipc_list, key=operator.itemgetter('sort')),            }            return response.json(0, res)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def get_uid_push(request_dict, response):        """        查询设备信息详情信息        @param request_dict: 请求参数        @request_dict UID: UID        @param response: 响应对象        @return:        """        uid = request_dict.get('UID', None)        if not uid:            return response.json(444)        try:            uid_set_qs = UidSetModel.objects.filter(uid=uid).first()            data = model_to_dict(uid_set_qs)            ALGORITHM_COMBO_TYPES = ['移动', '人形', '车型', '宠物', '人脸', '异响', '闯入', '离开', '徘徊',                                     '无人', '往来', '哭声', '手势', '火焰', '婴儿', '包裹']            if data['ai_type'] > 0:                num = data['ai_type']                result = ""                while num != 0:                    ret = num % 2                    num //= 2                    result = str(ret) + result                types = []                event_type = result                len_type = len(event_type)                for i in range(len_type):                    e_type = event_type[len_type - 1 - i]                    if e_type == '1':                        types.append(str(ALGORITHM_COMBO_TYPES[i]))                data['ai_type'] = types            # uid_set查uid_push            uid_pushes_qs = UidPushModel.objects.filter(uid_set_id=uid_set_qs.id).select_related('userID')            uid_push_data = []            # 保存uid_pushes_qs列表            for item in uid_pushes_qs:                item_dict = model_to_dict(item)                # 添加 username 字段                item_dict['username'] = item.userID.username if item.userID else None                uid_push_data.append(item_dict)            data["uid_push"] = uid_push_data            return response.json(0, data)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def get_app_name_list(response):        """        查询APP包名称列表        @param response: 响应对象        @return:        """        try:            app_bundle_qs = AppBundle.objects.all().values_list('app_bundle_id')            app_info = App_Info.objects.filter(appBundleId__in=app_bundle_qs).values('appName')            app_name_list = []            for app_name in app_info:                app_name_list.append(app_name['appName'])            app_name_list = list(set(app_name_list))            return response.json(0, app_name_list)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def app_name_convert_id(app_name_list):        """        app_name_list 转 app_id_list        @param app_name_list: app名字列表        @return app_id_list: app id列表        """        try:            app_bundle_id_list = App_Info.objects.filter(appName__in=app_name_list).values_list('appBundleId',                                                                                                flat=True)            app_id_list = AppBundle.objects.filter(app_bundle_id__in=app_bundle_id_list).values_list('id', flat=True)            return list(set(app_id_list))        except Exception as e:            print(e)            return []    @staticmethod    def call_add_app_device_type(request_dict, response, request):        """        添加设备类型        @param request_dict: 请求参数        @request_dict appBundleName: app包名        @request_dict versionNumber: app版本号        @request_dict model: 设备类型        @request_dict type: 设备型号        @request_dict name: 设备名字        @request_dict sort: 排序        @request_dict region: 地区        @request.FILES iconFile: 上传图标        @param response: 响应对象        """        # app包名称        app_bundle_name = request_dict.get('appBundleName', None)        # 版本号        version_number = request_dict.get('versionNumber', None)        # app_device_type表数据        model = request_dict.get('model', None)        type = request_dict.get('type', None)        # device_name_language表数据        name = request_dict.get('name', None)        sort = request_dict.get('sort', None)        config = request_dict.get('config', None)        # 上传图标        files = request.FILES.get('iconFile', None)        # 上传图标        files_v2 = request.FILES.get('iconV2File', None)        # 需要添加到哪一个服        region = request_dict.get("region", None)  # 获取需要同步的区域        # 检查必需参数        if not all([model, type, name, sort, version_number, app_bundle_name, region]):            return response.json(444, 'Missing required parameters')        if files is None and files_v2 is None:            return response.json(444, 'Missing required parameters')        regions = region.split(",")  # 将同步区域拆分为列表        return_value_list = []        for region in regions:            if region == 'test':                url = SERVER_DOMAIN_TEST            elif region == 'cn':                url = SERVER_DOMAIN_CN            elif region == 'us':                url = SERVER_DOMAIN_US            elif region == 'eu':                url = SERVER_DOMAIN_EUR            else:                return response.json(444, 'Invalid region')            try:                form_data = {                    'name': name,                    'type': type,                    'sort': sort,                    'model': model,                    'versionNumber': version_number,                    'appBundleName': app_bundle_name,                }                if config:                    try:                        config = json.loads(config)                    except:                        return response.json(444, 'config必须是一个json数据')                    form_data["config"] = json.dumps(config)                # 每次循环都重新读取文件内容并构造新的文件对象                if files:                    files.seek(0)                    file_content = files.read()                    files_for_post = {'iconFile': ('icon.png', io.BytesIO(file_content), files.content_type)}                else:                    files_for_post = {}                if files_v2:                    files_v2.seek(0)                    file_content_v2 = files_v2.read()                    files_for_post['iconV2File'] = ('iconV2.png', io.BytesIO(file_content_v2), files_v2.content_type)                # 发送 POST 请求调用 add_app_device_type 方法                response_value = requests.post(url + "/deviceManagement/addAppDeviceType",                                               data=form_data,                                               files=files_for_post)                return_value = {region: response_value.json()["data"]}                return_value_list.append(return_value)            except Exception as e:                return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))        return response.json(0, {"list": return_value_list})    @classmethod    def query_device_user(cls, request, request_dict, response):        try:            # 从请求中检索文件            file = request.FILES.get('deviceFile')            file_type = int(request_dict.get('type', 1))            uid_list = []            if not file:                return response.json(444)            device_info_list = []            # 处理文件内容并生成设备信息列表            # 序列号            if file_type == 2:                for item in file:                    item = item.decode().strip().replace(" ", "")                    serial = item[:6]                    # 请求序列号系统查询获取序列号记录                    url = 'http://{}/serialNumber/checkSerialLog'.format(SERIAL_DOMAIN_NAME)                    params = {'serial': serial}                    r = requests.get(url=url, params=params, timeout=5)                    assert r.status_code == 200                    result = eval(r.content)                    is_reset = 0 if result['code'] == 0 else 1                    uid = CommonService.get_uid_by_serial_number(serial)                    # 序列号没绑定uid,需要重置                    if uid == serial:                        is_reset = 1                        uid, device_name, ip, username = '', '', '', ''                    else:                        # 根据uid查询设备信息                        device_name, ip, username = cls.get_device_info(uid)                    device_info_data = {                        'isReset': is_reset,                        'uid': uid,                        'serialNumber': item,                        'deviceName': device_name,                        'ip': ip,                        'uName': username                    }                    device_info_list.append(device_info_data)            # uid            else:                for item in file:                    uid = item.decode().strip().replace(" ", "")                    is_reset = 0                    serial_number = CommonService.get_serial_number_by_uid(uid)                    if serial_number == uid:                        serial_number = ''                    device_name, ip, username = cls.get_device_info(uid)                    device_info_data = {                        'isReset': is_reset,                        'uid': uid,                        'serialNumber': serial_number,                        'deviceName': device_name,                        'ip': ip,                        'uName': username                    }                    device_info_list.append(device_info_data)            # 返回带有用户信息的响应            return response.json(0, {'userInfo': device_info_list})        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def get_device_info(uid):        """        根据uid查询设备信息        :param uid:        :return: device_name, ip, username        """        device_name, ip, username = '', '', ''        device_info_qs = Device_Info.objects.filter(UID=uid).values('NickName', 'ip', 'userID__username')        if device_info_qs.exists():            device_name = device_info_qs[0]['NickName']            ip = device_info_qs[0]['ip']            username = device_info_qs[0]['userID__username']        return device_name, ip, username    @staticmethod    def get_customer_device_list(request_dict, response):        """        查询扫码添加设备列表        :param request_dict:        :param response:        :return:        """        order_number = request_dict.get('orderNumber')        name = request_dict.get('name')        email = request_dict.get('email')        serial_number = request_dict.get('serialNumber')        uid = request_dict.get('uid')        page = int(request_dict.get('pageNo', 0))  # 默认值设为 0        page_size = int(request_dict.get('pageSize', 0))  # 默认值设为 0        try:            # 构建查询条件            custom_customer_qs = CustomCustomerOrderInfo.objects.all()            if order_number:                custom_customer_qs = custom_customer_qs.filter(order_number__icontains=order_number)            if name:                custom_customer_qs = custom_customer_qs.filter(name__icontains=name)            if email:                custom_customer_qs = custom_customer_qs.filter(email__icontains=email)            # 获取所需的ID和数量            c_id_list = custom_customer_qs.values_list("id", flat=True)            total_quantity = custom_customer_qs.aggregate(total_quantity=Sum('quantity'))['total_quantity']            # 查询设备列表            customer_device_qs = CustomCustomerDevice.objects.filter(c_id__in=c_id_list).order_by('-created_time')            # 通过serial_number和uid进行过滤            if serial_number:                customer_device_qs = customer_device_qs.filter(serial_number__icontains=serial_number)            if uid:                customer_device_qs = customer_device_qs.filter(uid=uid)            # 分页处理            if page > 0 and page_size > 0:                paginator = Paginator(customer_device_qs, page_size)                customer_device_page = paginator.get_page(page)                customer_device_list = customer_device_page.object_list                total = paginator.count            else:                customer_device_list = list(customer_device_qs)                total = customer_device_qs.count()            # 创建一个字典来映射 c_id 到 CustomCustomerOrderInfo 对象            customer_order_map = {order.id: order for order in custom_customer_qs}            # 构建设备列表            result_list = []            for device in customer_device_list:                customer_order = customer_order_map.get(device.c_id)                if customer_order:                    result_list.append({                        'id': device.id,                        'serialNumber': device.serial_number,                        'uid': device.uid,                        'deviceType': device.type,                        'fullCode': device.full_code,                        'addTime': device.created_time,                        'orderNumber': customer_order.order_number,                        'name': customer_order.name,                        'email': customer_order.email,                    })                else:                    result_list.append({                        'id': device.id,                        'serialNumber': device.serial_number,                        'uid': device.uid,                        'deviceType': device.type,                        'fullCode': device.full_code,                        'addTime': device.created_time,                        'orderNumber': "",                        'name': "",                        'email': "",                    })            # 构造返回数据            data = {                'total': total,                'orderDeviceQuantity': total_quantity or 0,  # 防止为None                'list': result_list,            }            return response.json(0, data)        except Exception as e:            return response.json(500, f'error_line:{e.__traceback__.tb_lineno}, error_msg:{repr(e)}')    @staticmethod    def get_device_ver_info(request_dict, response):        d_code = request_dict.get('dCode', None)        software_ver = request_dict.get('softwareVer', None)        device_type = request_dict.get('deviceType', None)        page = request_dict.get('pageNo', 1)  # 当前页码,默认为1        page_size = request_dict.get('pageSize', 10)  # 每页显示的记录数,默认为10        if not all([page, page_size]):            return response.json(444)        try:            device_ver_info_qs = DeviceVersionInfo.objects.all()            if d_code:                device_ver_info_qs = device_ver_info_qs.filter(d_code__icontains=d_code)            if software_ver:                device_ver_info_qs = device_ver_info_qs.filter(software_ver__icontains=software_ver)            if device_type:                device_ver_info_qs = device_ver_info_qs.filter(device_type=device_type)            # 对TimeAlbum结果进行分页            paginator = Paginator(device_ver_info_qs.order_by("-id"), page_size)            device_ver_infos = paginator.page(page)  # 获取当前页的数据            device_ver_info_list = []            # 对每个TimeAlbum,查询相关的AlbumMedia            for device_ver_info in device_ver_infos:                device_ver_info_list.append(                    {                        'deviceVerId': device_ver_info.id,                        'dCode': device_ver_info.d_code,                        'softwareVer': device_ver_info.software_ver,                        'firmwareVer': device_ver_info.firmware_ver,                        'videoCode': device_ver_info.video_code,                        'regionAlexa': device_ver_info.region_alexa,                        'supportsHumanTracking': device_ver_info.supports_human_tracking,                        'supportsCustomVoice': device_ver_info.supports_custom_voice,                        'supportsDualBandWifi': device_ver_info.supports_dual_band_wifi,                        'supportsFourPoint': device_ver_info.supports_four_point,                        'supports4g': device_ver_info.supports_4g,                        'supportsPTZ': device_ver_info.supports_ptz,                        'supportsAi': device_ver_info.supports_ai,                        'supportsCloudStorage': device_ver_info.supports_cloud_storage,                        'supportsAlexa': device_ver_info.supports_alexa,                        'deviceType': device_ver_info.device_type,                        'resolution': device_ver_info.resolution,                        'aiType': device_ver_info.ai_type,                        'supportsAlarm': device_ver_info.supports_alarm,                        'supportsNightVision': device_ver_info.supports_night_vision,                        'screenChannels': device_ver_info.screen_channels,                        'networkType': device_ver_info.network_type,                        'otherFeatures': device_ver_info.other_features,                        'electricityStatistics': device_ver_info.electricity_statistics,                        'supportsPetTracking': device_ver_info.supports_pet_tracking,                        'has4gCloud': device_ver_info.has_4g_cloud,                        'createdTime': device_ver_info.created_time,                        'updatedTime': device_ver_info.updated_time                    }                )            return response.json(0, {                'total': paginator.count,                'list': device_ver_info_list,            })        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def add_device_ver_info(request_dict, response):        d_code = request_dict.get('dCode', None)        software_ver = request_dict.get('softwareVer', None)        firmware_ver = request_dict.get('firmwareVer', "")        video_code = request_dict.get('videoCode', None)        region_alexa = request_dict.get('regionAlexa', "")        supports_human_tracking = request_dict.get('supportsHumanTracking', 0)        supports_custom_voice = request_dict.get('supportsCustomVoice', 0)        supports_dual_band_wifi = request_dict.get('supportsDualBandWifi', 0)        supports_four_point = request_dict.get('supportsFourPoint', 0)        supports_4g = request_dict.get('supports4g', 0)        supports_ptz = request_dict.get('supportsPTZ', 0)        supports_ai = request_dict.get('supportsAi', 0)        supports_cloud_storage = request_dict.get('supportsCloudStorage', 0)        supports_alexa = request_dict.get('supportsAlexa', 0)        device_type = request_dict.get('deviceType', None)        resolution = request_dict.get('resolution', "")        ai_type = request_dict.get('aiType', 0)        supports_alarm = request_dict.get('supportsAlarm', None)        supports_night_vision = request_dict.get('supportsNightVision', 0)        screen_channels = request_dict.get('screenChannels', None)        network_type = request_dict.get('networkType', None)        other_features = request_dict.get('otherFeatures', None)        electricity_statistics = request_dict.get('electricityStatistics', 0)        supports_pet_tracking = request_dict.get('supportsPetTracking', 0)        has_4g_cloud = request_dict.get('has4gCloud', -1)        if not all([d_code, software_ver, video_code,                    device_type, supports_alarm,                    screen_channels, network_type]                   ):            return response.json(444)        try:            now_time = int(time.time())            ai_type = int(ai_type)            if other_features:                other_features = json.loads(other_features)            else:                other_features = None            if DeviceVersionInfo.objects.filter(d_code=d_code, software_ver=software_ver).exists():                return response.json(174)            DeviceVersionInfo.objects.create(                d_code=d_code,                software_ver=software_ver,                firmware_ver=firmware_ver,                video_code=video_code,                region_alexa=region_alexa,                supports_human_tracking=supports_human_tracking,                supports_custom_voice=supports_custom_voice,                supports_dual_band_wifi=supports_dual_band_wifi,                supports_four_point=supports_four_point,                supports_4g=supports_4g,                supports_ptz=supports_ptz,                supports_ai=supports_ai,                supports_cloud_storage=supports_cloud_storage,                supports_alexa=supports_alexa,                device_type=device_type,                resolution=resolution,                ai_type=ai_type,                supports_alarm=supports_alarm,                supports_night_vision=supports_night_vision,                screen_channels=screen_channels,                network_type=network_type,                other_features=other_features,                electricity_statistics=electricity_statistics,                supports_pet_tracking=supports_pet_tracking,                has_4g_cloud=has_4g_cloud,                created_time=now_time,                updated_time=now_time            )        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))        return response.json(0)    @staticmethod    def edit_device_ver_info(request_dict, response):        device_ver_id = request_dict.get('deviceVerId', None)        firmware_ver = request_dict.get('firmwareVer', "")        video_code = request_dict.get('videoCode', None)        region_alexa = request_dict.get('regionAlexa', "")        supports_human_tracking = request_dict.get('supportsHumanTracking', 0)        supports_custom_voice = request_dict.get('supportsCustomVoice', 0)        supports_dual_band_wifi = request_dict.get('supportsDualBandWifi', 0)        supports_four_point = request_dict.get('supportsFourPoint', 0)        supports_4g = request_dict.get('supports4g', 0)        supports_ptz = request_dict.get('supportsPTZ', 0)        supports_ai = request_dict.get('supportsAi', 0)        supports_cloud_storage = request_dict.get('supportsCloudStorage', 0)        supports_alexa = request_dict.get('supportsAlexa', 0)        device_type = request_dict.get('deviceType', None)        resolution = request_dict.get('resolution', "")        ai_type = request_dict.get('aiType', 0)        supports_alarm = request_dict.get('supportsAlarm', None)        supports_night_vision = request_dict.get('supportsNightVision', 0)        screen_channels = request_dict.get('screenChannels', None)        network_type = request_dict.get('networkType', None)        other_features = request_dict.get('otherFeatures', None)        electricity_statistics = request_dict.get('electricityStatistics', 0)        supports_pet_tracking = request_dict.get('supportsPetTracking', 0)        has_4g_cloud = request_dict.get('has4gCloud', -1)        if not all([device_ver_id, video_code, device_type, supports_alarm, screen_channels, network_type]):            return response.json(444)        try:            now_time = int(time.time())            ai_type = int(ai_type)            device_version_info_qs = DeviceVersionInfo.objects.filter(id=device_ver_id).values('d_code', 'software_ver')            if not device_version_info_qs.exists():                return response.json(173)            if other_features:                other_features = json.loads(other_features)            else:                other_features = None            d_code = device_version_info_qs[0]['d_code']            software_ver = device_version_info_qs[0]['software_ver']            version_key = RedisKeyConstant.ZOSI_DEVICE_VERSION_INFO.value + software_ver + d_code            # 创建Redis对象            redis = RedisObject()            # 尝试从Redis中获取数据            version_info = redis.get_data(version_key)            if version_info:                # 如果在Redis中找到了数据,删除缓存                redis.del_data(version_key)            device_version_info_qs.update(                firmware_ver=firmware_ver,                video_code=video_code,                region_alexa=region_alexa,                supports_human_tracking=supports_human_tracking,                supports_custom_voice=supports_custom_voice,                supports_dual_band_wifi=supports_dual_band_wifi,                supports_four_point=supports_four_point,                supports_4g=supports_4g,                supports_ptz=supports_ptz,                supports_ai=supports_ai,                supports_cloud_storage=supports_cloud_storage,                supports_alexa=supports_alexa,                device_type=device_type,                resolution=resolution,                ai_type=ai_type,                supports_alarm=supports_alarm,                supports_night_vision=supports_night_vision,                screen_channels=screen_channels,                network_type=network_type,                other_features=other_features,                electricity_statistics=electricity_statistics,                supports_pet_tracking=supports_pet_tracking,                has_4g_cloud=has_4g_cloud,                created_time=now_time,                updated_time=now_time            )            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def del_device_ver_info(request_dict, response):        device_ver_id = request_dict.get('deviceVerId', None)        if not device_ver_id:            return response.json(444)        device_version_info_qs = DeviceVersionInfo.objects.filter(id=device_ver_id)        if not device_version_info_qs.exists():            return response.json(174)        device_version_info = device_version_info_qs.first()  # Get the first instance        d_code = device_version_info.d_code        software_ver = device_version_info.software_ver        version_key = RedisKeyConstant.ZOSI_DEVICE_VERSION_INFO.value + software_ver + d_code        # 创建Redis对象        redis = RedisObject()        # 尝试从Redis中获取数据        version_info = redis.get_data(version_key)        if version_info:            # 如果在Redis中找到了数据,删除缓存            redis.del_data(version_key)        device_version_info_qs.delete()        return response.json(0)    @classmethod    def sync_device_version(cls, request_dict, response):        """        同步设备版本信息        @param user_id: 用户ID        @param request: 请求对象        @param request_dict: 请求参数        @param response: 响应对象        @return: 响应结果        """        try:            # 从请求字典中获取设备码和版本号            version = request_dict.get('softwareVer')            d_code = request_dict.get('dCode')            # 查询设备版本配置            version_config_qs = DeviceVersionInfo.objects.filter(                d_code=d_code,                software_ver=version            )            # 检查是否存在匹配的配置            if not version_config_qs.exists():                return response.json(173)  # 设备版本配置不存在            # 获取第一条匹配的记录(通常应该只有一条)            version_config = version_config_qs.first()            # 直接使用数据库字段,不需要json.loads            other_features = ''            if version_config.other_features:                other_features = json.dumps(version_config.other_features)            # 将数据库字段映射为驼峰命名的响应数据            req_data = {                'dCode': version_config.d_code,                'softwareVer': version_config.software_ver,                'firmwareVer': version_config.firmware_ver,                'videoCode': version_config.video_code,                'regionAlexa': version_config.region_alexa,                # 布尔字段转换为int                'supportsHumanTracking': int(version_config.supports_human_tracking),                'supportsCustomVoice': int(version_config.supports_custom_voice),                'supportsDualBandWifi': int(version_config.supports_dual_band_wifi),                'supportsFourPoint': int(version_config.supports_four_point),                'supports4g': int(version_config.supports_4g),                'supportsPTZ': int(version_config.supports_ptz),                'supportsAi': int(version_config.supports_ai),                'supportsCloudStorage': int(version_config.supports_cloud_storage),                'supportsAlexa': int(version_config.supports_alexa),                # 其他非布尔字段保持不变                'deviceType': version_config.device_type,                'resolution': version_config.resolution,                'aiType': version_config.ai_type,                'supportsAlarm': version_config.supports_alarm,                'supportsNightVision': version_config.supports_night_vision,                'screenChannels': version_config.screen_channels,                'networkType': version_config.network_type,                'otherFeatures': other_features,                'electricityStatistics': version_config.electricity_statistics,                'supportsPetTracking': version_config.supports_pet_tracking            }            config_thread = threading.Thread(target=DeviceManagement.sync_device_version_config, kwargs=req_data)            config_thread.start()            # 返回成功响应,包含设备版本配置信息            return response.json(0)        except Exception as e:            # 通用异常处理(建议替换为具体异常类型)            LOGGER.exception("同步设备配置失败")            return response.json(500, f'Server error: {str(e)}')    @staticmethod    def sync_device_version_config(**req_data):        """           同步设备版本信息到本地数据库及外部服务器(含异常跳过逻辑)           """        try:            target_servers = []            if CONFIG_INFO == CONFIG_TEST:                target_servers = [                    "https://www.zositechc.cn/open/device/configuration/syncVerConfig",                    "https://www.dvema.com/open/device/configuration/syncVerConfig",                    "https://api.zositeche.com/open/device/configuration/syncVerConfig"                ]            elif CONFIG_INFO == CONFIG_CN:                target_servers = [                    "https://test.zositechc.cn/open/device/configuration/syncVerConfig",                    "https://www.dvema.com/open/device/configuration/syncVerConfig",                    "https://api.zositeche.com/open/device/configuration/syncVerConfig"                ]            elif CONFIG_INFO == CONFIG_US:                target_servers = [                    "https://test.zositechc.cn/open/device/configuration/syncVerConfig",                    "https://www.zositechc.cn/open/device/configuration/syncVerConfig",                    "https://api.zositeche.com/open/device/configuration/syncVerConfig"                ]            elif CONFIG_INFO == CONFIG_EUR:                target_servers = [                    "https://test.zositechc.cn/open/device/configuration/syncVerConfig",                    "https://www.zositechc.cn/open/device/configuration/syncVerConfig",                    "https://www.dvema.com/open/device/configuration/syncVerConfig"                ]            for server_url in target_servers:                try:                    # 发送请求并设置超时(10秒)                    resp = requests.post(                        url=server_url,                        data=req_data,                        timeout=10  # 超时时间                    )                    resp.raise_for_status()  # 抛出HTTP错误(如400/500)                    LOGGER.info(f"[{server_url}] 同步成功,响应:{resp.json()}")                except requests.exceptions.ConnectTimeout:                    LOGGER.error(f"[{server_url}] 连接超时,跳过")                    continue                except requests.exceptions.ReadTimeout:                    LOGGER.error(f"[{server_url}] 读取超时,跳过")                    continue                except requests.exceptions.RequestException as e:                    LOGGER.error(f"[{server_url}] 同步失败:{str(e)}")                    continue  # 跳过当前服务器            return True        except Exception as e:            LOGGER.exception("同步设备版本信息失败error{}".format(repr(e)))            return False    @staticmethod    def get_device_voice(request_dict, response):        """        获取设备音频        @param request_dict:        @param response:        @return:        """        title = request_dict.get('title', None)        voice_type = request_dict.get('voiceType', None)        classification = request_dict.get('classification', None)        uid = request_dict.get('uid', None)        algorithm_type = request_dict.get('algorithmType', None)        status = request_dict.get('status', None)        page = request_dict.get('page', 1)        page_size = request_dict.get('pageSize', 20)        try:            voice_prompt_qs = VoicePromptModel.objects.all()            if title:                voice_prompt_qs = voice_prompt_qs.filter(title__icontains=title)            if voice_type:                voice_prompt_qs = voice_prompt_qs.filter(type=voice_type)            if classification:                voice_prompt_qs = voice_prompt_qs.filter(classification=classification)            if uid:                voice_prompt_qs = voice_prompt_qs.filter(uid=uid)            if algorithm_type:                voice_prompt_qs = voice_prompt_qs.filter(algorithm_type=algorithm_type)            if status:                voice_prompt_qs = voice_prompt_qs.filter(status=status)            # 分页            paginator = Paginator(voice_prompt_qs.order_by("-add_time"), page_size)  # 每页显示 page_size 条            voice_prompt_page = paginator.get_page(page)  # 获取当前页的数据            # 上传文件到阿里云OSS            auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)            bucket = oss2.Bucket(auth, 'https://oss-cn-shenzhen.aliyuncs.com', 'ansjer-static-resources')            voice_prompt_list = []            for voice_prompt in voice_prompt_page:                filename = voice_prompt.filename                obj = 'voice_prompt/system/' + filename                filename_url = bucket.sign_url('GET', obj, 3600)                voice_prompt_list.append({                    "id": voice_prompt.id,                    "title": voice_prompt.title,                    "type": voice_prompt.type,                    "classification": voice_prompt.classification,                    "filename": filename,                    "filenameUrl": filename_url,                    "language": voice_prompt.language,                    "status": voice_prompt.status,                    "addTime": voice_prompt.add_time,                    "algorithmType": voice_prompt.algorithm_type,                    "uid": voice_prompt.uid,                    "device_types": voice_prompt.device_types                })            return response.json(0, {'list': voice_prompt_list, 'total': paginator.count})        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def algorithm_type_list(response):        """        算法类型列表        @param response:        @return:        """        try:            device_algorithm_explain_qs = DeviceAlgorithmExplain.objects.filter(lang='cn').values('title', 'algorithm_type__type')            device_algorithm_explain = list(device_algorithm_explain_qs)            for item in device_algorithm_explain:                item['algorithm_type_id'] = item.pop('algorithm_type__type')            device_algorithm_explain.append({"title": "无", "algorithm_type_id": 99})            return response.json(0, device_algorithm_explain)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def add_device_voice(request, request_dict, response):        """        添加设备音频        @param request        @param request_dict:        @param response:        @return:        """        title = request_dict.get('title', None)        voice_type = request_dict.get('voiceType', None)        classification = request_dict.get('classification', None)        algorithm_type = request_dict.get('algorithmType', None)        status = request_dict.get('status', None)        language = request_dict.get('language', None)        uid = request_dict.get('uid', None)        channel = request_dict.get('channel', 1)        device_types = request_dict.get('deviceTypes', None)        voice_file = request.FILES.get('voiceFile', None)        if not all([title, voice_type, classification, algorithm_type, status, language, voice_file]):            return response.json(444)        try:            if device_types:                device_type_list = device_types.split(',')                device_type_list = list(map(int, device_type_list))            else:                device_type_list = []            classification = int(classification)            auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)            bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'ansjer-static-resources')            file_name = voice_file.name            file_extension = os.path.splitext(file_name)[1]            filename = CommonService.createOrderID() + file_extension            voice_prompt_dict = {                "title": title,                "type": voice_type,                "classification": classification,                "filename": filename,                "language": language,                "status": status,                "algorithm_type": algorithm_type,                "add_time": int(time.time()),                "device_types": device_type_list            }            if uid and classification == 1:                voice_prompt_dict["uid"] = uid                obj = 'voice_prompt/{uid}/{channel}/'.format(uid=uid, channel=channel) + filename                bucket.put_object(obj, voice_file)            elif uid and classification == 0:                return response.json(178)            else:                obj = 'voice_prompt/system/' + filename                bucket.put_object(obj, voice_file)            VoicePromptModel.objects.create(**voice_prompt_dict)            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def edit_device_voice(request_dict, response):        """        添加设备音频        @param request:        @param request_dict:        @param response:        @return:        """        device_voice_id = request_dict.get('deviceVoiceId', None)        title = request_dict.get('title', None)        voice_type = request_dict.get('voiceType', None)        classification = request_dict.get('classification', None)        algorithm_type = request_dict.get('algorithmType', None)        status = request_dict.get('status', None)        language = request_dict.get('language', None)        device_types = request_dict.get('deviceTypes', "")        try:            voice_prompt = VoicePromptModel.objects.get(pk=device_voice_id)            if title:                voice_prompt.title = title            if voice_type:                voice_prompt.type = voice_type            if classification:                voice_prompt.classification = classification            if algorithm_type:                voice_prompt.algorithm_type = algorithm_type            if status:                voice_prompt.status = status            if language:                voice_prompt.language = language            if device_types:                device_type_list = device_types.split(',')                device_type_list = list(map(int, device_type_list))                voice_prompt.device_types = device_type_list            voice_prompt.save()            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def del_device_voice(request_dict, response):        """        删除设备音频        @param request_dict:        @param response:        @return:        """        device_voice_id = request_dict.get('deviceVoiceId', None)        try:            voice_prompt_qs = VoicePromptModel.objects.filter(id=device_voice_id)            filename = voice_prompt_qs[0].filename            classification = voice_prompt_qs[0].classification            uid = voice_prompt_qs[0].uid            channel = voice_prompt_qs[0].channel            auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)            bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'ansjer-static-resources')            if classification == 1 and uid:                obj = 'voice_prompt/{uid}/{channel}/'.format(uid=uid, channel=channel) + filename                bucket.delete_object(obj)            else:                obj = 'voice_prompt/system/' + filename                bucket.delete_object(obj)            voice_prompt_qs.delete()            return response.json(0)        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def device_type_list(response):        """        获取设备类型        @param response:        @return:        """        try:            subquery = DeviceTypeModel.objects.filter(                type=OuterRef('type')            ).values('type').annotate(                min_id=Min('id')            ).values('min_id')            # 根据最小 id 获取对应的 name 和 type            device_type_qs = DeviceTypeModel.objects.filter(                id__in=Subquery(subquery)            ).values("name", "type")            return response.json(0, list(device_type_qs))        except Exception as e:            print(e)            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def get_baidu_big_model_license(request_dict, response):        """查询百度大模型许可证列表"""        page_no = request_dict.get('pageNo')        page_size = request_dict.get('pageSize')        serial = request_dict.get('serial', '')        license_name = request_dict.get('licenseName', '')        use_status = request_dict.get('useStatus')        if not all([page_no, page_size]):            return response.json(444)        try:            query = BaiduBigModelLicense.objects.all()            if serial:                query = query.filter(serial__contains=serial)            if license_name:                query = query.filter(license_name__contains=license_name)            if use_status:                query = query.filter(use_status=use_status)            total = query.count()            licenses = query.order_by('-id')[                (int(page_no)-1)*int(page_size):int(page_no)*int(page_size)            ].values('id', 'serial', 'license_name', 'use_status', 'created_time', 'updated_time')            return response.json(0, {                'list': list(licenses),                'total': total            })        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def add_baidu_big_model_license(request, response):        """添加百度大模型许可证"""        file = request.FILES.get('file', None)        if not file:            return response.json(444)        try:            license_name = str(file)            now_time = int(time.time())            # 上传文件到华为云OBS            obs_client = ObsClient(                access_key_id=HUAWEICLOUD_AK,                secret_access_key=HUAWEICLOUD_SK,                server=HUAWEICLOUD_OBS_SERVER            )            resp = obs_client.putObject(                bucketName=HUAWEICLOUD_BAIDU_BIG_MODEL_LICENSE_BUKET,                objectKey=license_name,                content=file            )            assert resp.status < 300            # 更新或创建数据            license_qs = BaiduBigModelLicense.objects.filter(license_name=license_name)            if license_qs.exists():                license_qs.update(updated_time=now_time)            else:                BaiduBigModelLicense.objects.create(                    license_name=license_name,                    created_time=now_time,                    updated_time=now_time                )            return response.json(0)        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def edit_baidu_big_model_license(request, request_dict, response):        """编辑百度大模型许可证"""        license_id = request_dict.get('id')        serial = request_dict.get('serial')        use_status = request_dict.get('useStatus')        if not license_id:            return response.json(444)        try:            update_data = {                'updated_time': int(time.time())            }            if serial:                update_data['serial'] = serial            if use_status is not None:                update_data['use_status'] = int(use_status)            BaiduBigModelLicense.objects.filter(id=license_id).update(**update_data)            return response.json(0)        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def del_baidu_big_model_license(request_dict, response):        """删除百度大模型许可证"""        license_id = request_dict.get('id')        if not license_id:            return response.json(444)        try:            # 先查询出license_name            baidu_license = BaiduBigModelLicense.objects.filter(id=license_id).first()            if not baidu_license:                return response.json(444)            license_name = baidu_license.license_name            # 删除数据库记录            BaiduBigModelLicense.objects.filter(id=license_id).delete()            # 删除华为云上的文件            obs_client = ObsClient(                access_key_id=HUAWEICLOUD_AK,                secret_access_key=HUAWEICLOUD_SK,                server=HUAWEICLOUD_OBS_SERVER            )            obs_client.deleteObject(                bucketName=HUAWEICLOUD_BAIDU_BIG_MODEL_LICENSE_BUKET,                objectKey=license_name            )            return response.json(0)        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def get_instavision(request_dict, response):        """查询即时视觉列表"""        page_no = request_dict.get('pageNo')        page_size = request_dict.get('pageSize')        device_id = request_dict.get('deviceId', '')        mac = request_dict.get('mac', '')        access_key = request_dict.get('accessKey', '')        use_status = request_dict.get('useStatus')        if not all([page_no, page_size]):            return response.json(444)        try:            query = Instavision.objects.all()            if device_id:                query = query.filter(device_id__contains=device_id)            if mac:                query = query.filter(mac__contains=mac)            if access_key:                query = query.filter(access_key__contains=access_key)            if use_status is not None:                query = query.filter(use_status=use_status)            total = query.count()            instavisions = query.order_by('-id')[                (int(page_no)-1)*int(page_size):int(page_no)*int(page_size)            ].values('id', 'mac', 'device_id', 'access_key', 'use_status', 'created_time', 'updated_time')            return response.json(0, {                'list': list(instavisions),                'total': total            })        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def add_instavision(request, response):        """添加即时视觉        仅支持CSV批量导入        """        file = request.FILES.get('file', None)        if not file:            return response.json(444, '请上传CSV文件')        try:            # 读取CSV文件内容            csv_content = io.StringIO(file.read().decode('utf-8'))            csv_reader = csv.DictReader(csv_content)            now_time = int(time.time())            # 获取所有已存在的device_id            existing_device_ids = set(Instavision.objects.values_list('device_id', flat=True))            # 准备批量创建的对象列表            instavision_objects = []            for row in csv_reader:                # 获取Device Id和Access Key列的数据                device_id = row.get('Device Id', '')                access_key = row.get('Access Key', '')                if not device_id or not access_key:                    continue                # 检查是否已存在相同的device_id                if device_id in existing_device_ids:                    continue                # 添加到待创建列表                instavision_objects.append(Instavision(                    device_id=device_id,                    access_key=access_key,                    created_time=now_time,                    updated_time=now_time                ))                # 将此device_id添加到已存在集合中,防止CSV中有重复                existing_device_ids.add(device_id)            # 使用bulk_create批量创建记录            if instavision_objects:                Instavision.objects.bulk_create(instavision_objects)            return response.json(0)        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def edit_instavision(request_dict, response):        """编辑即时视觉"""        instavision_id = request_dict.get('id')        device_id = request_dict.get('deviceId')        access_key = request_dict.get('accessKey')        mac = request_dict.get('mac')        use_status = request_dict.get('useStatus')        if not instavision_id:            return response.json(444)        try:            update_data = {                'updated_time': int(time.time())            }            if device_id:                # 检查是否与其他记录的device_id冲突                if Instavision.objects.exclude(id=instavision_id).filter(device_id=device_id).exists():                    return response.json(444, '设备ID已存在')                update_data['device_id'] = device_id            if access_key:                update_data['access_key'] = access_key            if mac:                update_data['mac'] = mac            if use_status is not None:                update_data['use_status'] = int(use_status)            Instavision.objects.filter(id=instavision_id).update(**update_data)            return response.json(0)        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))    @staticmethod    def del_instavision(request_dict, response):        """删除即时视觉"""        instavision_id = request_dict.get('id')        if not instavision_id:            return response.json(444)        try:            # 删除数据库记录            Instavision.objects.filter(id=instavision_id).delete()            return response.json(0)        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
 |