|
@@ -16,7 +16,6 @@ from datetime import datetime
|
|
|
from typing import Dict, Any
|
|
|
from uuid import uuid4
|
|
|
|
|
|
-from django.core import serializers
|
|
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|
|
from django.db import transaction
|
|
|
from django.db.models import Q
|
|
@@ -24,7 +23,7 @@ from django.http import QueryDict
|
|
|
from django.views import View
|
|
|
from openpyxl import load_workbook
|
|
|
|
|
|
-from AgentModel.models import BurnRecord, BurnEncryptedICUID
|
|
|
+from AgentModel.models import BurnRecord, BurnEncryptedICUID, BurnBatch
|
|
|
from Ansjer.config import LOGGER
|
|
|
from Object.RedisObject import RedisObject
|
|
|
from Object.ResponseObject import ResponseObject
|
|
@@ -80,16 +79,100 @@ class UIDBurnManageView(View):
|
|
|
elif operation == 'importBatchUids':
|
|
|
return self.import_batch_uids(request, response)
|
|
|
elif operation == 'addBurnRecord':
|
|
|
- return self.add_burn_record(request,request_dict, response)
|
|
|
- elif operation == 'getBurnUidsPage':
|
|
|
- return self.get_burn_uids_page(request_dict, response)
|
|
|
+ return self.add_burn_record(request, request_dict, response)
|
|
|
+ elif operation == 'batchPageUids':
|
|
|
+ return self.batch_page_uids(request_dict, response)
|
|
|
elif operation == 'getImportProgress':
|
|
|
return self.get_import_progress(request_dict, response)
|
|
|
elif operation == 'getImportTaskList':
|
|
|
return self.get_import_task_list(request_dict, response)
|
|
|
+ elif operation == 'getBatchRecordsPage':
|
|
|
+ return self.get_batch_records_page(request_dict, response)
|
|
|
else:
|
|
|
return response.json(414)
|
|
|
|
|
|
+ @classmethod
|
|
|
+ def get_batch_records_page(cls, request_dict: Dict[str, Any], response) -> Any:
|
|
|
+ """
|
|
|
+ 分页查询批次记录(带统计信息)
|
|
|
+ :param request_dict: 请求参数字典
|
|
|
+ :param response: 响应对象
|
|
|
+ :return: JSON响应
|
|
|
+ """
|
|
|
+ # 1. 分页参数处理
|
|
|
+ try:
|
|
|
+ page = int(request_dict.get('page', 1))
|
|
|
+ page_size = int(request_dict.get('pageSize', 10))
|
|
|
+ page = max(page, 1)
|
|
|
+ page_size = max(1, min(page_size, 100))
|
|
|
+ except (ValueError, TypeError):
|
|
|
+ return response.json(444, "分页参数错误(必须为整数)")
|
|
|
+
|
|
|
+ # 2. 构建查询条件
|
|
|
+ query = Q()
|
|
|
+ batch_number = request_dict.get('batch_number', '').strip()
|
|
|
+ if batch_number:
|
|
|
+ query &= Q(batch_number__icontains=batch_number)
|
|
|
+
|
|
|
+ # 3. 查询并分页
|
|
|
+ batch_qs = BurnBatch.objects.filter(query).order_by('-created_time').values(
|
|
|
+ 'id', 'batch_number', 'purpose', 'manager', 'total_uid', 'created_time'
|
|
|
+ )
|
|
|
+
|
|
|
+ paginator = Paginator(batch_qs, page_size)
|
|
|
+ try:
|
|
|
+ page_obj = paginator.page(page)
|
|
|
+ except PageNotAnInteger:
|
|
|
+ page_obj = paginator.page(1)
|
|
|
+ except EmptyPage:
|
|
|
+ page_obj = paginator.page(paginator.num_pages)
|
|
|
+
|
|
|
+ # 4. 获取统计信息并构建结果
|
|
|
+ redis_obj = RedisObject()
|
|
|
+ batch_list = []
|
|
|
+
|
|
|
+ for batch in page_obj:
|
|
|
+ batch_id = batch['id']
|
|
|
+ cache_key = f"batch_stats:{batch_id}"
|
|
|
+
|
|
|
+ # 尝试从缓存获取统计信息
|
|
|
+ cached_stats = redis_obj.get_data(cache_key)
|
|
|
+ if cached_stats:
|
|
|
+ stats = json.loads(cached_stats)
|
|
|
+ else:
|
|
|
+ # 查询数据库统计
|
|
|
+ burned_count = BurnEncryptedICUID.objects.filter(
|
|
|
+ batch_id=batch_id,
|
|
|
+ status=1
|
|
|
+ ).count()
|
|
|
+ unburned_count = BurnEncryptedICUID.objects.filter(
|
|
|
+ batch_id=batch_id,
|
|
|
+ status=0
|
|
|
+ ).count()
|
|
|
+
|
|
|
+ stats = {
|
|
|
+ 'burned_count': burned_count,
|
|
|
+ 'unburned_count': unburned_count
|
|
|
+ }
|
|
|
+ # 设置缓存,过期时间1小时
|
|
|
+ redis_obj.set_data(cache_key, json.dumps(stats), 3600)
|
|
|
+
|
|
|
+ # 合并批次信息和统计信息
|
|
|
+ batch_info = dict(batch)
|
|
|
+ batch_info.update(stats)
|
|
|
+ batch_list.append(batch_info)
|
|
|
+
|
|
|
+ return response.json(
|
|
|
+ 0,
|
|
|
+ {
|
|
|
+ 'list': batch_list,
|
|
|
+ 'total': paginator.count,
|
|
|
+ 'currentPage': page_obj.number,
|
|
|
+ 'totalPages': paginator.num_pages,
|
|
|
+ 'pageSize': page_size
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
@classmethod
|
|
|
def get_burn_records_page(cls, request_dict: Dict[str, Any], response) -> Any:
|
|
|
"""
|
|
@@ -142,11 +225,10 @@ class UIDBurnManageView(View):
|
|
|
}
|
|
|
)
|
|
|
|
|
|
-
|
|
|
@classmethod
|
|
|
def import_batch_uids(cls, request, response) -> Any:
|
|
|
"""
|
|
|
- 导入批次UID - 异步优化版
|
|
|
+ 导入批次UID - 异步优化版(适配新表结构)
|
|
|
:param request: HttpRequest对象(包含上传文件)
|
|
|
:param response: 响应对象
|
|
|
:return: JSON响应
|
|
@@ -214,7 +296,7 @@ class UIDBurnManageView(View):
|
|
|
|
|
|
@classmethod
|
|
|
def _process_import_batch_async(cls, task_id, file_path, redis_key, batch_number):
|
|
|
- """后台线程处理批量导入任务"""
|
|
|
+ """后台线程处理批量导入任务(适配新表结构)"""
|
|
|
|
|
|
redis_obj = RedisObject()
|
|
|
|
|
@@ -234,9 +316,21 @@ class UIDBurnManageView(View):
|
|
|
task_data['start_time'] = int(time.time())
|
|
|
redis_obj.set_data(redis_key, json.dumps(task_data))
|
|
|
|
|
|
- # 2. 分批处理UID数据(每批500条)
|
|
|
- batch_size = 500
|
|
|
+ # 2. 创建批次记录
|
|
|
current_time = int(time.time())
|
|
|
+ with transaction.atomic():
|
|
|
+ batch = BurnBatch(
|
|
|
+ batch_number=batch_number,
|
|
|
+ purpose='批次导入',
|
|
|
+ created_time=current_time,
|
|
|
+ manager='system', # 默认系统导入
|
|
|
+ total_uid=0 # 初始为0,处理完成后更新
|
|
|
+ )
|
|
|
+ batch.save()
|
|
|
+ batch_id = batch.id
|
|
|
+
|
|
|
+ # 3. 分批处理UID数据(每批500条)
|
|
|
+ batch_size = 500
|
|
|
processed = 0
|
|
|
success_count = 0
|
|
|
uids_batch = []
|
|
@@ -260,7 +354,7 @@ class UIDBurnManageView(View):
|
|
|
if len(uids_batch) >= batch_size:
|
|
|
success = cls._import_uids_batch(
|
|
|
uids_batch,
|
|
|
- batch_number,
|
|
|
+ batch_id,
|
|
|
current_time,
|
|
|
redis_key
|
|
|
)
|
|
@@ -271,12 +365,16 @@ class UIDBurnManageView(View):
|
|
|
if uids_batch:
|
|
|
success = cls._import_uids_batch(
|
|
|
uids_batch,
|
|
|
- batch_number,
|
|
|
+ batch_id,
|
|
|
current_time,
|
|
|
redis_key
|
|
|
)
|
|
|
success_count += success
|
|
|
|
|
|
+ # 更新批次总UID数
|
|
|
+ with transaction.atomic():
|
|
|
+ BurnBatch.objects.filter(id=batch_id).update(total_uid=success_count)
|
|
|
+
|
|
|
# 更新最终状态
|
|
|
task_data['status'] = 'completed'
|
|
|
task_data['progress'] = 100
|
|
@@ -303,8 +401,8 @@ class UIDBurnManageView(View):
|
|
|
redis_obj.set_data(redis_key, json.dumps(task_data))
|
|
|
|
|
|
@classmethod
|
|
|
- def _import_uids_batch(cls, uids_batch, batch_number, current_time, redis_key):
|
|
|
- """批量导入UID记录"""
|
|
|
+ def _import_uids_batch(cls, uids_batch, batch_id, current_time, redis_key):
|
|
|
+ """批量导入UID记录(适配新表结构)"""
|
|
|
|
|
|
redis_obj = RedisObject()
|
|
|
|
|
@@ -316,9 +414,8 @@ class UIDBurnManageView(View):
|
|
|
# 创建记录
|
|
|
records = [
|
|
|
BurnEncryptedICUID(
|
|
|
- batch_number=batch_number,
|
|
|
+ batch_id=batch_id,
|
|
|
uid=uid,
|
|
|
- purpose='批次导入',
|
|
|
created_time=current_time,
|
|
|
updated_time=current_time,
|
|
|
status=0 # 未烧录状态
|
|
@@ -333,6 +430,10 @@ class UIDBurnManageView(View):
|
|
|
task_data['success_count'] = task_data.get('success_count', 0) + len(records)
|
|
|
redis_obj.set_data(redis_key, json.dumps(task_data))
|
|
|
|
|
|
+ # 清除批次统计缓存
|
|
|
+ cache_key = f"batch_stats:{batch_id}"
|
|
|
+ redis_obj.del_data(cache_key)
|
|
|
+
|
|
|
return len(records)
|
|
|
|
|
|
except Exception as e:
|
|
@@ -344,7 +445,7 @@ class UIDBurnManageView(View):
|
|
|
return 0
|
|
|
|
|
|
@classmethod
|
|
|
- def add_burn_record(cls, request,request_dict, response) -> Any:
|
|
|
+ def add_burn_record(cls, request, request_dict, response) -> Any:
|
|
|
"""
|
|
|
新增烧录记录(带UID文件) - Redis字符串优化版
|
|
|
:param request_dict:
|
|
@@ -500,6 +601,15 @@ class UIDBurnManageView(View):
|
|
|
task_data['end_time'] = int(time.time())
|
|
|
redis_obj.set_data(redis_key, json.dumps(task_data))
|
|
|
|
|
|
+ # 查询受影响的批次ID并清除缓存
|
|
|
+ batch_ids = BurnEncryptedICUID.objects.filter(
|
|
|
+ burn_id=burn_record.id
|
|
|
+ ).values_list('batch_id', flat=True).distinct()
|
|
|
+
|
|
|
+ for batch_id in batch_ids:
|
|
|
+ cache_key = f"batch_stats:{batch_id}"
|
|
|
+ redis_obj.del_data(cache_key)
|
|
|
+
|
|
|
LOGGER.info(f"处理烧录记录完成,任务ID: {task_id}, 处理UID数量: {processed}")
|
|
|
|
|
|
# 清理临时文件
|
|
@@ -524,6 +634,11 @@ class UIDBurnManageView(View):
|
|
|
|
|
|
try:
|
|
|
with transaction.atomic():
|
|
|
+ # 先查询出受影响的批次ID
|
|
|
+ batch_ids = BurnEncryptedICUID.objects.filter(
|
|
|
+ uid__in=uids_batch
|
|
|
+ ).values_list('batch_id', flat=True).distinct()
|
|
|
+
|
|
|
updated = BurnEncryptedICUID.objects.filter(
|
|
|
uid__in=uids_batch
|
|
|
).update(
|
|
@@ -536,6 +651,11 @@ class UIDBurnManageView(View):
|
|
|
task_data['processed'] = task_data.get('processed', 0) + len(uids_batch)
|
|
|
redis_obj.set_data(redis_key, json.dumps(task_data))
|
|
|
|
|
|
+ # 清除受影响批次的统计缓存
|
|
|
+ for batch_id in batch_ids:
|
|
|
+ cache_key = f"batch_stats:{batch_id}"
|
|
|
+ redis_obj.del_data(cache_key)
|
|
|
+
|
|
|
except Exception as e:
|
|
|
LOGGER.error(f"批量更新UID失败: {str(e)}")
|
|
|
raise
|
|
@@ -555,34 +675,34 @@ class UIDBurnManageView(View):
|
|
|
task_id = request_dict.get('task_id')
|
|
|
if not task_id:
|
|
|
return response.json(444, "缺少task_id参数")
|
|
|
-
|
|
|
+
|
|
|
task_type = request_dict.get('type', 'import').lower()
|
|
|
if task_type not in ['import', 'burn']:
|
|
|
return response.json(444, "type参数必须是'import'或'burn'")
|
|
|
-
|
|
|
+
|
|
|
# 2. 构建Redis key
|
|
|
redis_key = f"{task_type}_task:{task_id}"
|
|
|
-
|
|
|
+
|
|
|
try:
|
|
|
# 3. 从Redis获取任务数据
|
|
|
redis_obj = RedisObject()
|
|
|
task_data_str = redis_obj.get_data(redis_key)
|
|
|
-
|
|
|
+
|
|
|
if not task_data_str:
|
|
|
return response.json(173, "任务不存在或已过期")
|
|
|
-
|
|
|
+
|
|
|
# 4. 解析任务数据
|
|
|
if isinstance(task_data_str, bytes):
|
|
|
task_data_str = task_data_str.decode('utf-8')
|
|
|
task_data = json.loads(task_data_str)
|
|
|
-
|
|
|
+
|
|
|
# 5. 计算耗时(秒)
|
|
|
current_time = int(time.time())
|
|
|
start_time = task_data.get('start_time', current_time)
|
|
|
elapsed = current_time - start_time
|
|
|
if task_data.get('end_time'):
|
|
|
elapsed = task_data['end_time'] - start_time
|
|
|
-
|
|
|
+
|
|
|
# 6. 构建基础响应数据
|
|
|
result = {
|
|
|
'status': task_data.get('status', 'unknown'),
|
|
@@ -595,13 +715,33 @@ class UIDBurnManageView(View):
|
|
|
'error': task_data.get('error'),
|
|
|
'task_type': task_type
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
# 7. 根据任务类型添加特定字段
|
|
|
if task_type == 'import':
|
|
|
- result.update({
|
|
|
- 'batch_number': task_data.get('batch_number', ''),
|
|
|
- 'success_count': task_data.get('success_count', 0)
|
|
|
- })
|
|
|
+ # 从Redis获取批次号并查询批次信息
|
|
|
+ batch_number = task_data.get('batch_number', '')
|
|
|
+ if batch_number:
|
|
|
+ try:
|
|
|
+ batch = BurnBatch.objects.filter(batch_number=batch_number).first()
|
|
|
+ if batch:
|
|
|
+ result.update({
|
|
|
+ 'batch_number': batch_number,
|
|
|
+ 'success_count': task_data.get('success_count', 0),
|
|
|
+ 'purpose': batch.purpose,
|
|
|
+ 'manager': batch.manager,
|
|
|
+ 'total_uid': batch.total_uid
|
|
|
+ })
|
|
|
+ else:
|
|
|
+ result.update({
|
|
|
+ 'batch_number': batch_number,
|
|
|
+ 'success_count': task_data.get('success_count', 0)
|
|
|
+ })
|
|
|
+ except Exception as e:
|
|
|
+ LOGGER.error(f"查询批次信息失败: {str(e)}")
|
|
|
+ result.update({
|
|
|
+ 'batch_number': batch_number,
|
|
|
+ 'success_count': task_data.get('success_count', 0)
|
|
|
+ })
|
|
|
else: # burn task
|
|
|
result.update({
|
|
|
'order_number': task_data.get('order_number', ''),
|
|
@@ -609,9 +749,9 @@ class UIDBurnManageView(View):
|
|
|
'burn_count': task_data.get('burn_count', 0),
|
|
|
'burn_record_id': task_data.get('burn_record_id')
|
|
|
})
|
|
|
-
|
|
|
+
|
|
|
return response.json(0, result)
|
|
|
-
|
|
|
+
|
|
|
except json.JSONDecodeError:
|
|
|
LOGGER.error(f"任务数据解析失败, redis_key: {redis_key}")
|
|
|
return response.json(500, "任务数据格式错误")
|
|
@@ -677,24 +817,13 @@ class UIDBurnManageView(View):
|
|
|
return response.json(500, "获取任务列表失败")
|
|
|
|
|
|
@classmethod
|
|
|
- def get_burn_uids_page(cls, request_dict: Dict[str, Any], response) -> Any:
|
|
|
+ def batch_page_uids(cls, request_dict: Dict[str, Any], response) -> Any:
|
|
|
"""
|
|
|
根据burn_id分页查询烧录UID记录
|
|
|
:param request_dict: 请求参数字典
|
|
|
:param response: 响应对象
|
|
|
:return: JSON响应
|
|
|
"""
|
|
|
- # 1. 参数验证
|
|
|
- burn_id = request_dict.get('burn_id')
|
|
|
- if not burn_id:
|
|
|
- return response.json(444, "缺少burn_id参数")
|
|
|
-
|
|
|
- try:
|
|
|
- burn_id = int(burn_id)
|
|
|
- except ValueError:
|
|
|
- return response.json(444, "burn_id必须是整数")
|
|
|
-
|
|
|
- # 2. 分页参数处理
|
|
|
try:
|
|
|
page = int(request_dict.get('page', 1))
|
|
|
page_size = int(request_dict.get('pageSize', 10))
|
|
@@ -703,9 +832,22 @@ class UIDBurnManageView(View):
|
|
|
except (ValueError, TypeError):
|
|
|
return response.json(444, "分页参数错误(必须为整数)")
|
|
|
|
|
|
- # 3. 查询并分页
|
|
|
- query = Q(burn_id=burn_id)
|
|
|
- uid_qs = BurnEncryptedICUID.objects.filter(query).order_by('-created_time')
|
|
|
+ # 3. 构建查询条件
|
|
|
+ query = Q()
|
|
|
+
|
|
|
+ # 添加batch_id筛选条件
|
|
|
+ batch_id = request_dict.get('batch_id')
|
|
|
+ if batch_id:
|
|
|
+ try:
|
|
|
+ batch_id = int(batch_id)
|
|
|
+ query &= Q(batch_id=batch_id)
|
|
|
+ except ValueError:
|
|
|
+ return response.json(444, "batch_id必须是整数")
|
|
|
+
|
|
|
+ # 4. 查询并分页
|
|
|
+ uid_qs = BurnEncryptedICUID.objects.filter(query).order_by('-created_time').values(
|
|
|
+ 'id', 'uid', 'batch_id', 'status', 'created_time', 'updated_time'
|
|
|
+ )
|
|
|
|
|
|
paginator = Paginator(uid_qs, page_size)
|
|
|
try:
|
|
@@ -715,11 +857,8 @@ class UIDBurnManageView(View):
|
|
|
except EmptyPage:
|
|
|
page_obj = paginator.page(paginator.num_pages)
|
|
|
|
|
|
- uid_list = serializers.serialize(
|
|
|
- 'python',
|
|
|
- page_obj,
|
|
|
- fields=['id', 'uid', 'batch_number', 'status', 'created_time', 'updated_time']
|
|
|
- )
|
|
|
+ # 转换为列表
|
|
|
+ uid_list = list(page_obj)
|
|
|
|
|
|
return response.json(
|
|
|
0,
|