77 lines
2.7 KiB
Python
77 lines
2.7 KiB
Python
|
|
# ============================================================
|
|||
|
|
# 通用 Excel 现场导入器(moduleId: importers-excel, 可重生 ✅)
|
|||
|
|
# 列名映射/工厂命名/工时推断等客户差异 → profiles/*.json;
|
|||
|
|
# 解析逻辑复用 domain-kangni-intake(首个 profile 实现),
|
|||
|
|
# 导入结果同时落 world dict 与 SQLite(项目隔离)。
|
|||
|
|
# ============================================================
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
from pathlib import Path
|
|||
|
|
from typing import Any
|
|||
|
|
|
|||
|
|
PROFILES_DIR = Path(__file__).parent / "profiles"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def list_profiles() -> list[dict[str, Any]]:
|
|||
|
|
"""列出可用导入 profile(id/名称/描述)。"""
|
|||
|
|
out = []
|
|||
|
|
for f in sorted(PROFILES_DIR.glob("*.json")):
|
|||
|
|
try:
|
|||
|
|
p = json.loads(f.read_text(encoding="utf-8"))
|
|||
|
|
out.append({"profileId": p.get("profileId") or f.stem,
|
|||
|
|
"projectName": p.get("projectName") or f.stem,
|
|||
|
|
"description": p.get("description") or ""})
|
|||
|
|
except (json.JSONDecodeError, OSError):
|
|||
|
|
continue
|
|||
|
|
return out
|
|||
|
|
|
|||
|
|
|
|||
|
|
def load_profile(profile_id: str = "kangni") -> dict[str, Any]:
|
|||
|
|
"""加载导入 profile;不存在时返回空 dict(调用方走内置默认)。"""
|
|||
|
|
path = PROFILES_DIR / f"{profile_id}.json"
|
|||
|
|
if not path.exists():
|
|||
|
|
return {}
|
|||
|
|
try:
|
|||
|
|
return json.loads(path.read_text(encoding="utf-8"))
|
|||
|
|
except (json.JSONDecodeError, OSError):
|
|||
|
|
return {}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def import_site_excel(
|
|||
|
|
world: dict[str, Any],
|
|||
|
|
*,
|
|||
|
|
profile_id: str = "kangni",
|
|||
|
|
route_path: str | Path | None = None,
|
|||
|
|
data_dir: str | Path | None = None,
|
|||
|
|
include_sibling_orders: bool = False,
|
|||
|
|
station_count: int | None = None,
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""按 profile 导入现场 Excel → world + SQLite(激活对应项目)。"""
|
|||
|
|
from server.aps_domain.kangni_intake import load_site_into_world
|
|||
|
|
|
|||
|
|
profile = load_profile(profile_id)
|
|||
|
|
meta = load_site_into_world(
|
|||
|
|
world,
|
|||
|
|
route_path=route_path,
|
|||
|
|
data_dir=data_dir,
|
|||
|
|
include_sibling_orders=include_sibling_orders,
|
|||
|
|
station_count=station_count or int(profile.get("stationCount") or 4),
|
|||
|
|
profile=profile,
|
|||
|
|
)
|
|||
|
|
# 导入结果入库:激活该客户项目并替换其主数据
|
|||
|
|
if not os.environ.get("APS_DB_DISABLED"):
|
|||
|
|
try:
|
|||
|
|
from server.db.sync import set_active_project, world_to_db
|
|||
|
|
set_active_project(
|
|||
|
|
profile.get("projectCode") or profile_id,
|
|||
|
|
profile.get("projectName") or profile_id,
|
|||
|
|
profile.get("industry") or "machining",
|
|||
|
|
)
|
|||
|
|
world_to_db(world)
|
|||
|
|
meta["dbSynced"] = True
|
|||
|
|
except Exception:
|
|||
|
|
meta["dbSynced"] = False
|
|||
|
|
return meta
|