浏览代码

更新优化产品方案二维码功能

zhangdongming 2 周之前
父节点
当前提交
06768faa44
共有 2 个文件被更改,包括 203 次插入38 次删除
  1. 170 31
      AdminController/ProductsSchemeManageController.py
  2. 33 7
      Controller/IncomeProductsController.py

+ 170 - 31
AdminController/ProductsSchemeManageController.py

@@ -14,13 +14,14 @@ import time
 from io import BytesIO
 
 import qrcode
+from PIL import Image, ImageDraw, ImageFont
 from django.core.paginator import Paginator, EmptyPage
 from django.db import transaction, IntegrityError
 from django.db.models import Q
 from django.http import QueryDict, HttpResponse
 from django.views import View
 
-from Ansjer.config import LOGGER
+from Ansjer.config import LOGGER, BASE_DIR
 from Model.models import ProductsScheme, DeviceScheme, DeviceTypeModel, CompanySerialModel
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
@@ -78,7 +79,10 @@ class ProductsSchemeManageView(View):
             'edit': self.edit_scheme,  # 编辑方案
             'delete': self.delete_scheme,  # 删除方案
             'generateQR': self.generate_qr_code,  # 生成二维码
-            'deviceSchemeList': self.device_scheme_list
+            'deviceSchemeList': self.device_scheme_list,  # 设备方案列表
+            'batchAddScheme': self.batch_add_scheme,  # 批量添加
+            'getSkuList': self.get_sku_list,  # 获取SKU列表'
+            'getSchemeBySku': self.get_scheme_by_sku,  # 根据SKU获取方案
         }
 
         handler = operation_handlers.get(operation)
@@ -188,7 +192,7 @@ class ProductsSchemeManageView(View):
                 'remark': request_dict.get('remark', ''),
                 'sku': request_dict.get('sku', ''),
                 'scheme_code': request_dict.get('schemeCode', ''),
-                'hw_version':request_dict.get('hwVersion', ''),
+                'hw_version': request_dict.get('hwVersion', ''),
                 'created_time': int(time.time()),
                 'updated_time': int(time.time()),
                 'created_by': user_id,
@@ -210,6 +214,88 @@ class ProductsSchemeManageView(View):
             LOGGER.exception(f"添加方案异常:{repr(e)}")
             return response.json(500, "生成编码失败")
 
+    def batch_add_scheme(self, user_id, request_dict, response):
+        """批量新增方案(支持批量处理,集成自动编码生成)"""
+        try:
+            # 获取批量方案数据数组
+            schemes_array = request_dict.get('schemes', [])
+            order_number = request_dict.get('orderNumber', '')
+            if not order_number:
+                return response.json(444, "请提供有效的方案数据数组")
+
+            # 准备批量创建的数据列表
+            batch_data = []
+            result_ids = []
+            current_time = int(time.time())
+            schemes_array = json.loads(schemes_array)
+            for item in schemes_array:
+                # 确保每个项都是字典
+                if not isinstance(item, dict):
+                    continue
+
+                # 生成唯一storage_code
+                device_type = int(item.get('deviceType', 0))
+                storage_code = self.generate_timestamp_code(device_type)
+
+                # 构造单个方案数据
+                scheme_data = {
+                    'storage_code': storage_code,
+                    'order_number': order_number,
+                    'device_type': device_type,
+                    'product_model': int(item.get('productModel', 0)),
+                    'flash': item.get('flash', ''),
+                    'ddr': item.get('ddr', ''),
+                    'main_controller': item.get('mainController', ''),
+                    'wifi': item.get('wifi', ''),
+                    'four_g': item.get('fourG', ''),
+                    'ad': item.get('ad', ''),
+                    'sensor': item.get('sensor', ''),
+                    'order_quantity': int(item.get('orderQuantity', 0)),
+                    'customer_code': item.get('customerCode', ''),
+                    'phy': item.get('phy', ''),
+                    'remark': item.get('remark', ''),
+                    'sku': item.get('sku', ''),
+                    'scheme_code': item.get('schemeCode', ''),
+                    'hw_version': item.get('hwVersion', ''),
+                    'created_time': current_time,
+                    'updated_time': current_time,
+                    'created_by': user_id,
+                    'updated_by': user_id
+                }
+
+                batch_data.append(ProductsScheme(**scheme_data))
+
+            if not batch_data:
+                return response.json(444, "没有有效的方案数据可添加")
+
+            # 批量创建记录
+            created_schemes = ProductsScheme.objects.bulk_create(batch_data)
+
+            # 收集结果
+            result = {
+                'success_count': len(created_schemes),
+                'total_count': len(schemes_array),
+                'schemes': [
+                    {
+                        'id': scheme.id,
+                        'storageCode': scheme.storage_code,
+                        'orderNumber': scheme.order_number
+                    }
+                    for scheme in created_schemes
+                ]
+            }
+
+            return response.json(0, result)
+
+        except IntegrityError as e:
+            LOGGER.error(f"唯一性冲突: {str(e)}")
+            return response.json(173, "部分数据已存在,批量添加失败")
+        except ValueError as e:
+            return response.json(444, f"参数类型错误: {str(e)}")
+        except Exception as e:
+            LOGGER.exception(f"批量添加方案异常:{repr(e)}")
+            return response.json(500, "批量生成编码失败")
+
         # 可编辑字段白名单(前端字段名: 模型字段名)
 
     EDITABLE_FIELDS = {
@@ -229,7 +315,7 @@ class ProductsSchemeManageView(View):
         'sku': 'sku',
         'schemeCode': 'scheme_code',
         'productModel': 'product_model',
-        'hwVersion':'hw_version'
+        'hwVersion': 'hw_version'
     }
 
     # 需要类型转换的字段配置(字段名: 转换函数)
@@ -347,7 +433,7 @@ class ProductsSchemeManageView(View):
         """方案对象序列化(优化点:集中管理序列化逻辑)"""
         # 定义需要包含在str_schema中的字段
         schema_fields = [
-            'order_number','hw_version', 'main_controller', 'sensor', 'ad', 'wifi', 'four_g',
+            'order_number', 'hw_version', 'main_controller', 'sensor', 'ad', 'wifi', 'four_g',
             'flash', 'ddr', 'phy'
         ]
 
@@ -384,12 +470,11 @@ class ProductsSchemeManageView(View):
         }
 
     def generate_qr_code(self, user_id, request_dict, response):
-        """生成方案二维码"""
+        """生成方案二维码并附带明文"""
         try:
             scheme_id = int(request_dict.get('scheme_id'))
             scheme = ProductsScheme.objects.get(id=scheme_id, deleted=False)
 
-            # 创建二维码(示例生成包含方案ID+名称)
             qr = qrcode.QRCode(
                 version=1,
                 error_correction=qrcode.constants.ERROR_CORRECT_L,
@@ -397,39 +482,43 @@ class ProductsSchemeManageView(View):
                 border=4,
             )
 
-            # 组织二维码内容(根据业务需求自定义)
-            qr_data = json.dumps({
-                "sc": scheme.storage_code,
-                "t": 'NVR' if scheme.device_type == 1 else 'IPC',
-                "hw": scheme.hw_version,
-                "mc": scheme.main_controller,
-                "s": scheme.sensor,
-                "ad": scheme.ad,
-                "wifi": scheme.wifi,
-                "mode4G": scheme.four_g,
-                "f": scheme.flash,
-                "ddr": scheme.ddr,
-                'uc': scheme.customer_code,
-                'phy': scheme.phy,
-                "num": scheme.order_quantity,
-                "ct": scheme.created_time
-            })
-            qr.add_data(qr_data)
+            qr.add_data(scheme.order_number)
             qr.make(fit=True)
+            img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
 
-            # 生成图片
-            img = qr.make_image(fill_color="black", back_color="white")
+            # 要显示的明文(比如 storage_code)
+            text = scheme.order_number
+
+            # 设置字体(如果服务器没有 ttf,可以用默认字体)
+            try:
+                path = BASE_DIR + '/Ansjer/file/font/simhei.ttf'
+                font = ImageFont.truetype(path, 40, encoding="unic")  # 需要系统有 Arial.ttf
+            except IOError:
+                font = ImageFont.load_default()
+
+            # 计算文字大小
+            draw = ImageDraw.Draw(img)
+            text_width, text_height = draw.textsize(text, font=font)
+
+            # 创建一个新图像(比二维码高一些,给文字留空间)
+            new_height = img.height + text_height + 20
+            new_img = Image.new("RGB", (img.width, new_height), "white")
+            new_img.paste(img, (0, 0))
+
+            # 在底部居中绘制文字
+            draw = ImageDraw.Draw(new_img)
+            text_x = (img.width - text_width) // 2
+            text_y = img.height + 10
+            draw.text((text_x, text_y), text, font=font, fill="black")
 
-            # 将图片转为字节流
             buffer = BytesIO()
-            img.save(buffer, format="PNG")
+            new_img.save(buffer, format="PNG")
 
-            # 返回文件响应
             return HttpResponse(
                 buffer.getvalue(),
                 content_type="image/png",
                 headers={
-                    'Content-Disposition': f'attachment; filename="scheme_{scheme.id}_qr.png"'
+                    'Content-Disposition': f'attachment; filename="scheme_{scheme.order_number}_qr.png"'
                 }
             )
 
@@ -576,3 +665,53 @@ class ProductsSchemeManageView(View):
             })
 
         return device_data
+
+    def get_sku_list(self, user_id, request_dict, response):
+        """获取历史SKU列表"""
+        try:
+            sku_list = (
+                ProductsScheme.objects
+                .exclude(sku__isnull=True)
+                .exclude(sku__exact='')
+                .exclude(deleted = True)
+                .values_list('sku', flat=True)
+                .distinct()
+            )
+            return response.json(0, list(sku_list))
+        except Exception as e:
+            LOGGER.exception(f"获取 SKU 列表异常: {repr(e)}")
+            return response.json(500, "获取 SKU 列表失败")
+
+    def get_scheme_by_sku(self, user_id, request_dict, response):
+        """根据SKU获取方案"""
+        try:
+            sku = request_dict.get('sku', '')
+            if not sku:
+                return response.json(444, "请提供有效的 SKU")
+
+            scheme = ProductsScheme.objects.filter(sku=sku).order_by('-created_time').first()
+
+            if not scheme:
+                return response.json(0, {})
+
+            scheme_data = {
+                'deviceType': scheme.device_type,
+                'productModel': scheme.product_model,
+                'flash': scheme.flash,
+                'ddr': scheme.ddr,
+                'mainController': scheme.main_controller,
+                'wifi': scheme.wifi,
+                'fourG': scheme.four_g,
+                'ad': scheme.ad,
+                'sensor': scheme.sensor,
+                'phy': scheme.phy,
+                'sku': scheme.sku,
+                'schemeCode': scheme.scheme_code,
+                'hwVersion': scheme.hw_version
+            }
+
+            return response.json(0, scheme_data)
+
+        except Exception as e:
+            LOGGER.exception(f"获取方案详情异常: {repr(e)}")
+            return response.json(500, "获取方案详情失败")

+ 33 - 7
Controller/IncomeProductsController.py

@@ -2,10 +2,10 @@ import time
 
 from django.views import View
 
-from Model.models import DeviceScheme
-from Object.RedisObject import RedisObject
-from Service.CommonService import CommonService
 from Ansjer.config import LOGGER
+from Model.models import DeviceScheme, ProductsScheme
+from Service.CommonService import CommonService
+
 
 class IncomeProductsView(View):
     def get(self, request, *args, **kwargs):
@@ -24,6 +24,8 @@ class IncomeProductsView(View):
             return self.income_device_scheme(request_dict, response)
         elif operation == 'statistics':
             return self.statistics_device_scheme(request_dict, response)
+        elif operation == 'getProductSchemeList':
+            return self.get_product_scheme_list(request_dict, response)
         else:
             return response.json(414)
 
@@ -53,7 +55,8 @@ class IncomeProductsView(View):
             device_scheme_qs = DeviceScheme.objects.filter(serial_number=serial_number)
             if device_scheme_qs.exists():
                 storage_code = device_scheme_qs.first().storage_code
-                LOGGER.info(f"设备关联产品方案, serialNumber已存在, storageCode: {storage_code}, serialNumber: {serial_number}")
+                LOGGER.info(
+                    f"设备关联产品方案, serialNumber已存在, storageCode: {storage_code}, serialNumber: {serial_number}")
                 return response.json(174, f"数据已存在, storage_code为: {storage_code}")
 
             now_time = int(time.time())
@@ -63,7 +66,8 @@ class IncomeProductsView(View):
                                         phone_model=phone_model, created_time=now_time,
                                         updated_time=now_time)
 
-            LOGGER.info(f"设备关联产品方案, serialNumber录入成功, storageCode: {storage_code}, serialNumber: {serial_number}")
+            LOGGER.info(
+                f"设备关联产品方案, serialNumber录入成功, storageCode: {storage_code}, serialNumber: {serial_number}")
 
             return response.json(0)
 
@@ -84,7 +88,29 @@ class IncomeProductsView(View):
             if not storage_code:
                 return response.json(444)
             device_num = DeviceScheme.objects.filter(storage_code=storage_code).count()
-            return response.json(0, {"storageCode": storage_code,"deviceNum": device_num})
+            return response.json(0, {"storageCode": storage_code, "deviceNum": device_num})
         except Exception as e:
             print(e)
-            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+    @staticmethod
+    def get_product_scheme_list(request_dict, response):
+        order_number = request_dict.get('orderNumber', None)
+        if not order_number:
+            # 缺少订单号,返回错误码
+            return response.json(444)
+
+        # 查询符合条件的方案,仅获取指定字段
+        scheme_qs = ProductsScheme.objects.filter(order_number=order_number).values(
+            'storage_code', 'sku', 'hw_version', 'product_model', 'order_quantity', 'remark'
+        )
+
+        if not scheme_qs.exists():
+            # 没有查询到数据,返回对应错误码
+            return response.json(173)
+
+        # 将QuerySet转换为列表(数组格式),便于前端解析
+        scheme_list = list(scheme_qs)
+
+        # 返回成功状态码(0)和数据数组
+        return response.json(0, scheme_list)