ProductsSchemeManageController.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @File : ProductsSchemeManageController.py
  4. @Time : 2025/5/13 11:52
  5. @Author : stephen
  6. @Email : zhangdongming@asj6.wecom.work
  7. @Software: PyCharm
  8. """
  9. import datetime
  10. import json
  11. import secrets
  12. import string
  13. import time
  14. from io import BytesIO
  15. import qrcode
  16. from PIL import Image, ImageDraw, ImageFont
  17. from django.core.paginator import Paginator, EmptyPage
  18. from django.db import transaction, IntegrityError
  19. from django.db.models import Q
  20. from django.http import QueryDict, HttpResponse
  21. from django.views import View
  22. from Ansjer.config import LOGGER, BASE_DIR
  23. from Model.models import ProductsScheme, DeviceScheme, DeviceTypeModel, CompanySerialModel
  24. from Object.ResponseObject import ResponseObject
  25. from Object.TokenObject import TokenObject
  26. class ProductsSchemeManageView(View):
  27. def get(self, request, *args, **kwargs):
  28. request.encoding = 'utf-8'
  29. operation = kwargs.get('operation')
  30. return self.validation(request.GET, request, operation)
  31. def post(self, request, *args, **kwargs):
  32. request.encoding = 'utf-8'
  33. operation = kwargs.get('operation')
  34. return self.validation(request.POST, request, operation)
  35. def delete(self, request, *args, **kwargs):
  36. request.encoding = 'utf-8'
  37. operation = kwargs.get('operation')
  38. delete = QueryDict(request.body)
  39. if not delete:
  40. delete = request.GET
  41. return self.validation(delete, request, operation)
  42. def put(self, request, *args, **kwargs):
  43. request.encoding = 'utf-8'
  44. operation = kwargs.get('operation')
  45. put = QueryDict(request.body)
  46. return self.validation(put, request, operation)
  47. def validation(self, request_dict, request, operation):
  48. """请求验证路由"""
  49. # 初始化响应对象
  50. language = request_dict.get('language', 'cn')
  51. response = ResponseObject(language, 'pc')
  52. # Token验证
  53. try:
  54. tko = TokenObject(
  55. request.META.get('HTTP_AUTHORIZATION'),
  56. returntpye='pc')
  57. if tko.code != 0:
  58. return response.json(tko.code)
  59. response.lang = tko.lang
  60. user_id = tko.userID
  61. except Exception as e:
  62. LOGGER.error(f"Token验证失败: {str(e)}")
  63. return response.json(444)
  64. # 操作路由映射
  65. operation_handlers = {
  66. 'queryList': self.query_list, # 查询列表
  67. 'add': self.add_scheme, # 添加方案
  68. 'edit': self.edit_scheme, # 编辑方案
  69. 'delete': self.delete_scheme, # 删除方案
  70. 'generateQR': self.generate_qr_code, # 生成二维码
  71. 'deviceSchemeList': self.device_scheme_list, # 设备方案列表
  72. 'batchAddScheme': self.batch_add_scheme, # 批量添加
  73. 'getSkuList': self.get_sku_list, # 获取SKU列表'
  74. 'getSchemeBySku': self.get_scheme_by_sku, # 根据SKU获取方案
  75. }
  76. handler = operation_handlers.get(operation)
  77. if not handler:
  78. return response.json(444, 'operation')
  79. try:
  80. return handler(user_id, request_dict, response)
  81. except Exception as e:
  82. LOGGER.error(f"操作{operation}执行异常:{repr(e)}")
  83. return response.json(500, "服务器内部错误")
  84. def query_list(self, user_id, request_dict, response):
  85. """查询方案列表(优化点:分页封装/字段映射)"""
  86. # 参数处理与验证
  87. try:
  88. page = int(request_dict.get('page', 1))
  89. page_size = min(int(request_dict.get('pageSize', 10)), 100) # 限制最大分页大小
  90. except ValueError:
  91. return response.json(444, "分页参数错误")
  92. # 构建查询条件
  93. query = Q(deleted=False)
  94. # 特殊字段处理示例(如果需要)
  95. if order_number := request_dict.get('orderNumber'):
  96. query &= Q(order_number__icontains=order_number)
  97. if storage_code := request_dict.get('storageCode'):
  98. query &= Q(storage_code__icontains=storage_code)
  99. if device_type := request_dict.get('deviceType'):
  100. query &= Q(device_type=int(device_type))
  101. if flash := request_dict.get('flash'):
  102. query &= Q(flash__icontains=flash)
  103. if ddr := request_dict.get('ddr'):
  104. query &= Q(ddr__icontains=ddr)
  105. if main_controller := request_dict.get('mainController'):
  106. query &= Q(main_controller__icontains=main_controller)
  107. if wifi := request_dict.get('wifi'):
  108. query &= Q(wifi__icontains=wifi)
  109. if four_g := request_dict.get('fourG'):
  110. query &= Q(four_g__icontains=four_g)
  111. if ad := request_dict.get('ad'):
  112. query &= Q(ad__icontains=ad)
  113. if sensor := request_dict.get('sensor'):
  114. query &= Q(sensor__icontains=sensor)
  115. # 使用分页器
  116. queryset = ProductsScheme.objects.filter(query).order_by('-created_time')
  117. paginator = Paginator(queryset, page_size)
  118. try:
  119. page_obj = paginator.page(page)
  120. except EmptyPage:
  121. return response.json(444, "页码超出范围")
  122. # 序列化数据
  123. data = [self._scheme_to_dict(scheme) for scheme in page_obj]
  124. return response.json(0, {
  125. 'list': data,
  126. 'total': paginator.count,
  127. 'currentPage': page_obj.number,
  128. 'totalPages': paginator.num_pages
  129. })
  130. @staticmethod
  131. def generate_timestamp_code(device_type: int = 0) -> str:
  132. """
  133. 方案1:基于时间戳的编码
  134. 格式:PC+设备类型+年月日+时分秒+6位随机大写字符
  135. 示例:PC020250519143022-ABCDEF
  136. """
  137. try:
  138. current_time = datetime.datetime.now()
  139. date_part = current_time.strftime("%Y%m%d%H%M%S")
  140. # 使用string.ascii_uppercase生成大写随机字符
  141. random_part = ''.join(secrets.choice(string.ascii_uppercase) for _ in range(3))
  142. return f"{date_part}-{device_type}-{random_part}"
  143. except Exception as e:
  144. LOGGER.error(f"生成编码失败: {repr(e)}")
  145. raise
  146. def add_scheme(self, user_id, request_dict, response):
  147. """新增方案(集成自动编码生成)"""
  148. try:
  149. device_type = int(request_dict.get('deviceType', 0))
  150. # 生成唯一storage_code
  151. storage_code = self.generate_timestamp_code(device_type)
  152. # 构造方案数据
  153. scheme_data = {
  154. 'storage_code': storage_code, # 使用生成的编码
  155. 'order_number': request_dict.get('orderNumber', ''),
  156. 'device_type': device_type,
  157. 'product_model': int(request_dict.get('productModel', 0)),
  158. 'flash': request_dict.get('flash', ''),
  159. 'ddr': request_dict.get('ddr', ''),
  160. 'main_controller': request_dict.get('mainController', ''),
  161. 'wifi': request_dict.get('wifi', ''),
  162. 'four_g': request_dict.get('fourG', ''),
  163. 'ad': request_dict.get('ad', ''),
  164. 'sensor': request_dict.get('sensor', ''),
  165. 'order_quantity': int(request_dict.get('orderQuantity', 0)),
  166. 'customer_code': request_dict.get('customerCode', ''),
  167. 'phy': request_dict.get('phy', ''),
  168. 'remark': request_dict.get('remark', ''),
  169. 'sku': request_dict.get('sku', ''),
  170. 'scheme_code': request_dict.get('schemeCode', ''),
  171. 'hw_version': request_dict.get('hwVersion', ''),
  172. 'created_time': int(time.time()),
  173. 'updated_time': int(time.time()),
  174. 'created_by': user_id,
  175. 'updated_by': user_id
  176. }
  177. scheme = ProductsScheme.objects.create(**scheme_data)
  178. return response.json(0, {
  179. 'id': scheme.id,
  180. 'storageCode': storage_code # 返回生成的编码
  181. })
  182. except IntegrityError as e:
  183. LOGGER.error(f"唯一性冲突: {str(e)}")
  184. return response.json(173, "数据已存在")
  185. except ValueError as e:
  186. return response.json(444, "参数类型错误")
  187. except Exception as e:
  188. LOGGER.exception(f"添加方案异常:{repr(e)}")
  189. return response.json(500, "生成编码失败")
  190. def batch_add_scheme(self, user_id, request_dict, response):
  191. """批量新增方案(支持批量处理,集成自动编码生成)"""
  192. try:
  193. # 获取批量方案数据数组
  194. schemes_array = request_dict.get('schemes', [])
  195. order_number = request_dict.get('orderNumber', '')
  196. if not order_number:
  197. return response.json(444, "请提供有效的方案数据数组")
  198. # 准备批量创建的数据列表
  199. batch_data = []
  200. result_ids = []
  201. current_time = int(time.time())
  202. schemes_array = json.loads(schemes_array)
  203. for item in schemes_array:
  204. # 确保每个项都是字典
  205. if not isinstance(item, dict):
  206. continue
  207. # 生成唯一storage_code
  208. device_type = int(item.get('deviceType', 0))
  209. storage_code = self.generate_timestamp_code(device_type)
  210. # 构造单个方案数据
  211. scheme_data = {
  212. 'storage_code': storage_code,
  213. 'order_number': order_number,
  214. 'device_type': device_type,
  215. 'product_model': int(item.get('productModel', 0)),
  216. 'flash': item.get('flash', ''),
  217. 'ddr': item.get('ddr', ''),
  218. 'main_controller': item.get('mainController', ''),
  219. 'wifi': item.get('wifi', ''),
  220. 'four_g': item.get('fourG', ''),
  221. 'ad': item.get('ad', ''),
  222. 'sensor': item.get('sensor', ''),
  223. 'order_quantity': int(item.get('orderQuantity', 0)),
  224. 'customer_code': item.get('customerCode', ''),
  225. 'phy': item.get('phy', ''),
  226. 'remark': item.get('remark', ''),
  227. 'sku': item.get('sku', ''),
  228. 'scheme_code': item.get('schemeCode', ''),
  229. 'hw_version': item.get('hwVersion', ''),
  230. 'created_time': current_time,
  231. 'updated_time': current_time,
  232. 'created_by': user_id,
  233. 'updated_by': user_id
  234. }
  235. batch_data.append(ProductsScheme(**scheme_data))
  236. if not batch_data:
  237. return response.json(444, "没有有效的方案数据可添加")
  238. # 批量创建记录
  239. created_schemes = ProductsScheme.objects.bulk_create(batch_data)
  240. # 收集结果
  241. result = {
  242. 'success_count': len(created_schemes),
  243. 'total_count': len(schemes_array),
  244. 'schemes': [
  245. {
  246. 'id': scheme.id,
  247. 'storageCode': scheme.storage_code,
  248. 'orderNumber': scheme.order_number
  249. }
  250. for scheme in created_schemes
  251. ]
  252. }
  253. return response.json(0, result)
  254. except IntegrityError as e:
  255. LOGGER.error(f"唯一性冲突: {str(e)}")
  256. return response.json(173, "部分数据已存在,批量添加失败")
  257. except ValueError as e:
  258. return response.json(444, f"参数类型错误: {str(e)}")
  259. except Exception as e:
  260. LOGGER.exception(f"批量添加方案异常:{repr(e)}")
  261. return response.json(500, "批量生成编码失败")
  262. # 可编辑字段白名单(前端字段名: 模型字段名)
  263. EDITABLE_FIELDS = {
  264. 'orderNumber': 'order_number',
  265. 'deviceType': 'device_type',
  266. 'flash': 'flash',
  267. 'ddr': 'ddr',
  268. 'mainController': 'main_controller',
  269. 'wifi': 'wifi',
  270. 'fourG': 'four_g',
  271. 'ad': 'ad',
  272. 'sensor': 'sensor',
  273. 'orderQuantity': 'order_quantity',
  274. 'customerCode': 'customer_code',
  275. 'phy': 'phy',
  276. 'remark': 'remark',
  277. 'sku': 'sku',
  278. 'schemeCode': 'scheme_code',
  279. 'productModel': 'product_model',
  280. 'hwVersion': 'hw_version'
  281. }
  282. # 需要类型转换的字段配置(字段名: 转换函数)
  283. FIELD_CONVERTERS = {
  284. 'deviceType': int,
  285. 'orderQuantity': int,
  286. 'productModel': int
  287. }
  288. @transaction.atomic
  289. def edit_scheme(self, user_id, request_dict, response):
  290. """
  291. 方案编辑接口(事务原子性保证)
  292. 优化特性:
  293. 1. 前端字段到模型字段的自动映射
  294. 2. 字段级白名单过滤
  295. 3. 智能类型转换
  296. 4. 最小化更新字段
  297. 5. 并发安全控制
  298. """
  299. # ================= 参数校验阶段 =================
  300. if 'id' not in request_dict:
  301. return response.json(444, "缺少方案ID")
  302. try:
  303. scheme_id = int(request_dict['id'])
  304. except (ValueError, TypeError):
  305. LOGGER.warning(f"非法方案ID: {request_dict.get('id')}")
  306. return response.json(444, "方案ID格式错误")
  307. # ================= 数据获取阶段 =================
  308. try:
  309. # 使用select_for_update锁定记录,防止并发修改
  310. scheme = ProductsScheme.objects.select_for_update().get(
  311. id=scheme_id,
  312. deleted=False
  313. )
  314. except ProductsScheme.DoesNotExist:
  315. LOGGER.info(f"方案不存在: {scheme_id}")
  316. return response.json(173, "方案不存在")
  317. except Exception as e:
  318. LOGGER.error(f"数据库查询异常: {str(e)}")
  319. return response.json(500, "系统错误")
  320. # ================= 数据处理阶段 =================
  321. update_fields = []
  322. update_data = {'updated_time': int(time.time()), 'updated_by': user_id}
  323. # 遍历所有请求参数
  324. for frontend_field, value in request_dict.items():
  325. # 1. 白名单校验
  326. if frontend_field not in self.EDITABLE_FIELDS:
  327. continue
  328. # 2. 获取对应的模型字段名
  329. model_field = self.EDITABLE_FIELDS[frontend_field]
  330. # 3. 类型转换处理
  331. if frontend_field in self.FIELD_CONVERTERS:
  332. try:
  333. value = self.FIELD_CONVERTERS[frontend_field](value)
  334. except (ValueError, TypeError):
  335. LOGGER.warning(f"字段类型错误 {frontend_field}={value}")
  336. return response.json(444, f"{frontend_field}类型不合法")
  337. # 4. 值变更检查(避免无意义更新)
  338. if getattr(scheme, model_field) != value:
  339. update_data[model_field] = value
  340. update_fields.append(model_field)
  341. # 无实际修改时快速返回
  342. if not update_fields:
  343. LOGGER.debug("无字段变更")
  344. return response.json(0)
  345. # ================= 数据持久化阶段 =================
  346. try:
  347. # 动态生成更新SQL:UPDATE ... SET field1=%s, field2=%s
  348. ProductsScheme.objects.filter(id=scheme_id).update(**update_data)
  349. LOGGER.info(f"方案更新成功: {scheme_id} 修改字段: {update_fields}")
  350. return response.json(0)
  351. except IntegrityError as e:
  352. LOGGER.error(f"数据唯一性冲突: {str(e)}")
  353. return response.json(177)
  354. except Exception as e:
  355. LOGGER.exception("方案更新异常")
  356. return response.json(500, "系统错误")
  357. def delete_scheme(self, user_id, request_dict, response):
  358. """删除方案(优化点:逻辑删除优化)"""
  359. # 参数校验
  360. if 'id' not in request_dict:
  361. return response.json(444, "缺少方案ID")
  362. try:
  363. # 使用update直接进行逻辑删除,提高效率
  364. rows = ProductsScheme.objects.filter(
  365. id=request_dict['id'],
  366. deleted=False
  367. ).update(
  368. deleted=True,
  369. updated_by=user_id,
  370. updated_time=int(time.time())
  371. )
  372. if rows == 0:
  373. return response.json(173, "方案不存在")
  374. return response.json(0)
  375. except ValueError:
  376. return response.json(500, "方案ID格式错误")
  377. def _scheme_to_dict(self, scheme):
  378. """方案对象序列化(优化点:集中管理序列化逻辑)"""
  379. # 定义需要包含在str_schema中的字段
  380. schema_fields = [
  381. 'order_number', 'hw_version', 'main_controller', 'sensor', 'ad', 'wifi', 'four_g',
  382. 'flash', 'ddr', 'phy'
  383. ]
  384. # 获取字段值,过滤掉空值
  385. schema_values = [getattr(scheme, field, '') for field in schema_fields]
  386. valid_values = [v for v in schema_values if v] # 过滤空字符串
  387. # 拼接字符串模式,不保留空值位置
  388. str_schema = '+'.join(valid_values)
  389. return {
  390. 'id': scheme.id,
  391. 'orderNumber': scheme.order_number,
  392. 'storageCode': scheme.storage_code,
  393. 'deviceType': scheme.device_type,
  394. 'flash': scheme.flash,
  395. 'ddr': scheme.ddr,
  396. 'mainController': scheme.main_controller,
  397. 'wifi': scheme.wifi,
  398. 'fourG': scheme.four_g,
  399. 'ad': scheme.ad,
  400. 'sensor': scheme.sensor,
  401. 'orderQuantity': scheme.order_quantity,
  402. 'customerCode': scheme.customer_code,
  403. 'phy': scheme.phy,
  404. 'remark': scheme.remark,
  405. 'strSchema': str_schema,
  406. 'productModel': scheme.product_model,
  407. 'sku': scheme.sku,
  408. 'schemeCode': scheme.scheme_code,
  409. 'hwVersion': scheme.hw_version,
  410. 'createdTime': scheme.created_time,
  411. 'createdBy': scheme.created_by
  412. }
  413. def generate_qr_code(self, user_id, request_dict, response):
  414. """生成方案二维码并附带明文"""
  415. try:
  416. scheme_id = int(request_dict.get('scheme_id'))
  417. scheme = ProductsScheme.objects.get(id=scheme_id, deleted=False)
  418. qr = qrcode.QRCode(
  419. version=1,
  420. error_correction=qrcode.constants.ERROR_CORRECT_L,
  421. box_size=10,
  422. border=4,
  423. )
  424. qr.add_data(scheme.order_number)
  425. qr.make(fit=True)
  426. img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
  427. # 要显示的明文(比如 storage_code)
  428. text = scheme.order_number
  429. # 设置字体(如果服务器没有 ttf,可以用默认字体)
  430. try:
  431. path = BASE_DIR + '/Ansjer/file/font/simhei.ttf'
  432. font = ImageFont.truetype(path, 40, encoding="unic") # 需要系统有 Arial.ttf
  433. except IOError:
  434. font = ImageFont.load_default()
  435. # 计算文字大小
  436. draw = ImageDraw.Draw(img)
  437. text_width, text_height = draw.textsize(text, font=font)
  438. # 创建一个新图像(比二维码高一些,给文字留空间)
  439. new_height = img.height + text_height + 20
  440. new_img = Image.new("RGB", (img.width, new_height), "white")
  441. new_img.paste(img, (0, 0))
  442. # 在底部居中绘制文字
  443. draw = ImageDraw.Draw(new_img)
  444. text_x = (img.width - text_width) // 2
  445. text_y = img.height + 10
  446. draw.text((text_x, text_y), text, font=font, fill="black")
  447. buffer = BytesIO()
  448. new_img.save(buffer, format="PNG")
  449. return HttpResponse(
  450. buffer.getvalue(),
  451. content_type="image/png",
  452. headers={
  453. 'Content-Disposition': f'attachment; filename="scheme_{scheme.order_number}_qr.png"'
  454. }
  455. )
  456. except ProductsScheme.DoesNotExist:
  457. return response.json(173, "方案不存在")
  458. except Exception as e:
  459. LOGGER.error(f"生成二维码失败: {str(e)}")
  460. return response.json(500, "生成失败")
  461. @staticmethod
  462. def device_scheme_list(user_id, request_dict, response):
  463. """
  464. 查询设备方案列表
  465. @param request_dict: 请求参数
  466. @param response: 响应对象
  467. @return: 响应对象包含设备方案列表
  468. """
  469. # 提取请求参数并提供默认值
  470. filters = {
  471. 'serial_number': request_dict.get("serialNumber"),
  472. 'storage_code': request_dict.get("storageCode"),
  473. 'device_type': request_dict.get("deviceType"),
  474. 'phone_model': request_dict.get("phoneModel"),
  475. }
  476. page = int(request_dict.get("page", 1))
  477. page_size = int(request_dict.get("pageSize", 20))
  478. try:
  479. # 构建基础查询集
  480. queryset = DeviceScheme.objects.all().order_by('-created_time')
  481. # 应用过滤条件
  482. if filters['serial_number']:
  483. queryset = queryset.filter(serial_number=filters['serial_number'])
  484. if filters['storage_code']:
  485. queryset = queryset.filter(storage_code__icontains=filters['storage_code'])
  486. if filters['device_type']:
  487. queryset = queryset.filter(device_type=filters['device_type'])
  488. if filters['phone_model']:
  489. queryset = queryset.filter(phone_model__icontains=filters['phone_model'])
  490. # 分页处理
  491. paginator = Paginator(queryset, page_size)
  492. try:
  493. current_page = paginator.page(page)
  494. except EmptyPage:
  495. current_page = paginator.page(paginator.num_pages)
  496. # 批量预取关联数据
  497. device_list = []
  498. if current_page.object_list:
  499. # 准备批量查询所需数据
  500. storage_codes = {device.storage_code for device in current_page}
  501. serial_prefixes = {device.serial_number[:6] for device in current_page}
  502. device_types = {device.device_type for device in current_page}
  503. # 批量获取关联数据
  504. product_schemes_map = {
  505. ps.storage_code: ps
  506. for ps in ProductsScheme.objects.filter(storage_code__in=storage_codes)
  507. }
  508. device_type_names = {
  509. dt['type']: dt['name']
  510. for dt in DeviceTypeModel.objects.filter(type__in=device_types).values('type', 'name')
  511. }
  512. serial_statuses = {
  513. cs.serial_number: cs
  514. for cs in CompanySerialModel.objects.filter(serial_number__in=serial_prefixes)
  515. }
  516. # 构建设备数据
  517. device_list = [
  518. ProductsSchemeManageView.build_device_data(
  519. device,
  520. product_schemes_map.get(device.storage_code),
  521. device_type_names.get(device.device_type, device.device_type),
  522. serial_statuses.get(device.serial_number[:6])
  523. )
  524. for device in current_page
  525. ]
  526. return response.json(0, {
  527. 'list': device_list,
  528. 'total': paginator.count
  529. })
  530. except Exception as e:
  531. LOGGER.error("设备方案列表查询异常")
  532. return response.json(500, f'服务器错误: {str(e)}')
  533. @staticmethod
  534. def build_device_data(device, product_scheme, device_type_name, serial_status):
  535. """构建单个设备数据字典"""
  536. # 设备基础数据
  537. device_data = {
  538. 'id': device.id,
  539. 'serialNumber': device.serial_number,
  540. 'deviceType': device_type_name,
  541. 'phoneModel': device.phone_model,
  542. 'storageCode': device.storage_code,
  543. 'createdTime': device.created_time,
  544. 'updatedTime': device.updated_time,
  545. 'snStatus': 'N/A',
  546. 'aTime': 'N/A',
  547. }
  548. # 序列号激活信息
  549. if device.device_type != 0 and serial_status:
  550. device_data['snStatus'] = '已激活' if serial_status.status > 1 else '未激活'
  551. device_data['aTime'] = datetime.datetime.fromtimestamp(
  552. serial_status.update_time
  553. ).strftime('%Y-%m-%d %H:%M:%S')
  554. # 添加产品方案信息
  555. if product_scheme:
  556. # 构建方案数据字符串
  557. scheme_parts = [
  558. product_scheme.flash,
  559. product_scheme.ddr,
  560. product_scheme.main_controller,
  561. product_scheme.wifi,
  562. product_scheme.four_g,
  563. product_scheme.ad,
  564. product_scheme.phy,
  565. product_scheme.sensor
  566. ]
  567. scheme_data = '+'.join(filter(None, map(str, scheme_parts)))
  568. device_data.update({
  569. 'orderNumber': product_scheme.order_number or '',
  570. 'type': 'NVR' if product_scheme.device_type == 1 else 'IPC',
  571. 'flash': product_scheme.flash or '',
  572. 'ddr': product_scheme.ddr or '',
  573. 'mainController': product_scheme.main_controller or '',
  574. 'wifi': product_scheme.wifi or '',
  575. 'fourG': product_scheme.four_g or '',
  576. 'ad': product_scheme.ad or '',
  577. 'phy': product_scheme.phy or '',
  578. 'sensor': product_scheme.sensor or '',
  579. 'orderQuantity': product_scheme.order_quantity or '',
  580. 'customerCode': product_scheme.customer_code or '',
  581. 'schemeData': scheme_data,
  582. 'remark': product_scheme.remark or ''
  583. })
  584. return device_data
  585. def get_sku_list(self, user_id, request_dict, response):
  586. """获取历史SKU列表"""
  587. try:
  588. sku_list = (
  589. ProductsScheme.objects
  590. .exclude(sku__isnull=True)
  591. .exclude(sku__exact='')
  592. .exclude(deleted = True)
  593. .values_list('sku', flat=True)
  594. .distinct()
  595. )
  596. return response.json(0, list(sku_list))
  597. except Exception as e:
  598. LOGGER.exception(f"获取 SKU 列表异常: {repr(e)}")
  599. return response.json(500, "获取 SKU 列表失败")
  600. def get_scheme_by_sku(self, user_id, request_dict, response):
  601. """根据SKU获取方案"""
  602. try:
  603. sku = request_dict.get('sku', '')
  604. if not sku:
  605. return response.json(444, "请提供有效的 SKU")
  606. scheme = ProductsScheme.objects.filter(sku=sku).order_by('-created_time').first()
  607. if not scheme:
  608. return response.json(0, {})
  609. scheme_data = {
  610. 'deviceType': scheme.device_type,
  611. 'productModel': scheme.product_model,
  612. 'flash': scheme.flash,
  613. 'ddr': scheme.ddr,
  614. 'mainController': scheme.main_controller,
  615. 'wifi': scheme.wifi,
  616. 'fourG': scheme.four_g,
  617. 'ad': scheme.ad,
  618. 'sensor': scheme.sensor,
  619. 'phy': scheme.phy,
  620. 'sku': scheme.sku,
  621. 'schemeCode': scheme.scheme_code,
  622. 'hwVersion': scheme.hw_version
  623. }
  624. return response.json(0, scheme_data)
  625. except Exception as e:
  626. LOGGER.exception(f"获取方案详情异常: {repr(e)}")
  627. return response.json(500, "获取方案详情失败")