From da6cd31ce840ff0d826d1977d37aee13a553541f Mon Sep 17 00:00:00 2001 From: shijing Date: Fri, 20 Mar 2026 16:44:55 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E8=81=94=E7=B3=BB=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E5=AE=BD=E5=BA=A6=E8=B0=83=E6=95=B4=EF=BC=8C=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E6=97=B6=E6=97=A0=E8=B4=A6=E5=8F=B7=E7=9A=84=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/apps/material/importers.py | 33 +++++++++++++++++++++++++++ frontend/src/views/MaterialManage.vue | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/backend/apps/material/importers.py b/backend/apps/material/importers.py index bba15ef..d8fe82a 100644 --- a/backend/apps/material/importers.py +++ b/backend/apps/material/importers.py @@ -2,6 +2,7 @@ import re from typing import Any, Dict, List, Optional, Tuple import openpyxl +from django.contrib.auth import get_user_model from apps.factory.models import Factory from apps.material.models import Material @@ -18,6 +19,7 @@ MAJOR_CATEGORY_MAP = { STAGE_VALUES = {choice[0] for choice in Material.STAGE_CHOICES} IMPORTANCE_LEVEL_VALUES = {choice[0] for choice in Material.IMPORTANCE_LEVEL_CHOICES} UNIT_SPLIT_RE = re.compile(r"[\s,,、/;;]+") +INITIAL_PASSWORD = "abc!0000" def _cell(value: Any) -> str: @@ -41,6 +43,33 @@ def _parse_choice(value: Any, allowed_values: set) -> Optional[str]: return text if text in allowed_values else None +def _unique_username(user_model, base: str) -> str: + if not user_model.objects.filter(username=base).exists(): + return base + for index in range(2, 10000): + candidate = f"{base}{index}" + if not user_model.objects.filter(username=candidate).exists(): + return candidate + raise RuntimeError(f"无法为账号分配唯一用户名: {base}") + + +def _ensure_factory_user(factory: Factory, unit_name: str) -> bool: + user_model = get_user_model() + existing_user = user_model.objects.filter(role="user", factory_id=factory.id).order_by("id").first() + if existing_user: + return False + + username_base = _single_line(unit_name, max_len=150) or f"factory{factory.id}" + username = _unique_username(user_model, username_base) + user_model.objects.create_user( + username=username, + password=INITIAL_PASSWORD, + role="user", + factory=factory, + ) + return True + + def _resolve_factory(unit_name: str, factory_cache: Dict[str, Optional[Factory]], unrecognized_factory: Factory) -> Tuple[Factory, bool, bool]: if not unit_name: return unrecognized_factory, True, False @@ -79,6 +108,7 @@ def _resolve_factory(unit_name: str, factory_cache: Dict[str, Optional[Factory]] city="北京", district="北京", ) + _ensure_factory_user(created_factory, unit_name) factory_cache[unit_name] = created_factory return created_factory, False, True @@ -120,6 +150,7 @@ def import_materials_plan_excel(file_obj) -> Dict[str, int]: skipped = 0 unresolved_factory = 0 created_factory = 0 + created_user = 0 factory_cache: Dict[str, Optional[Factory]] = {} current_major_category = "" @@ -147,6 +178,7 @@ def import_materials_plan_excel(file_obj) -> Dict[str, int]: unresolved_factory += 1 if is_created_factory: created_factory += 1 + created_user += 1 defaults = { "stage": _parse_choice(get(row, "阶段"), STAGE_VALUES), @@ -179,4 +211,5 @@ def import_materials_plan_excel(file_obj) -> Dict[str, int]: "skipped": skipped, "unresolved_factory": unresolved_factory, "created_factory": created_factory, + "created_user": created_user, } diff --git a/frontend/src/views/MaterialManage.vue b/frontend/src/views/MaterialManage.vue index cc41fbc..b1b1e97 100644 --- a/frontend/src/views/MaterialManage.vue +++ b/frontend/src/views/MaterialManage.vue @@ -26,7 +26,7 @@ - +