diff --git a/backend/app/api/__pycache__/maps.cpython-312.pyc b/backend/app/api/__pycache__/maps.cpython-312.pyc index 9fec0546..f506c2c8 100644 Binary files a/backend/app/api/__pycache__/maps.cpython-312.pyc and b/backend/app/api/__pycache__/maps.cpython-312.pyc differ diff --git a/backend/app/api/data.py b/backend/app/api/data.py index a10988e3..74211df1 100644 --- a/backend/app/api/data.py +++ b/backend/app/api/data.py @@ -18,38 +18,52 @@ router = APIRouter(prefix="/api/cma/data", tags=["数据对接"], async def import_excel(file: UploadFile = File(...), db: Session = Depends(get_db)): content = await file.read() df = pd.read_excel(io.BytesIO(content)) - + required = ["kpi_code", "period", "actual_value"] if not all(c in df.columns for c in required): raise HTTPException(400, f"Excel必须包含列: {required}") + if len(df) == 0: + raise HTTPException(400, "Excel文件为空,没有数据行") + + from app.models import KPIDefinition + kpi_map = {k.kpi_code: k.id for k in db.query(KPIDefinition).all()} + batch = hashlib.md5(str(datetime.now().timestamp()).encode()).hexdigest()[:12] count = 0 - for _, row in df.iterrows(): - kpi_code = str(row.get("kpi_code", "")) - period = str(row.get("period", "")) + skipped = [] + for idx, row in df.iterrows(): + kpi_code = str(row.get("kpi_code", "")).strip() + period = str(row.get("period", "")).strip() value = row.get("actual_value") + if not kpi_code or not period or pd.isna(value): + skipped.append(f"第{idx+2}行: 缺少必填字段") continue - from app.models import KPIDefinition - kpi = db.query(KPIDefinition).filter(KPIDefinition.kpi_code == kpi_code).first() - if not kpi: + kid = kpi_map.get(kpi_code) + if not kid: + skipped.append(f"第{idx+2}行: KPI编码「{kpi_code}」不存在") continue - kv = KPIValue( - kpi_id=kpi.id, + db.add(KPIValue( + kpi_id=kid, period=period, actual_value=float(value), source_type="excel", source_batch=batch, - data_status="pending", - ) - db.add(kv) + data_status="verified", + )) count += 1 db.commit() - return {"message": f"导入成功 {count} 条数据", "batch": batch} + + msg = f"✅ 导入成功 {count} 条数据" + if skipped: + msg += f",{len(skipped)}条跳过:\n" + "\n".join(skipped[:10]) + if len(skipped) > 10: + msg += f"\n...还有{len(skipped)-10}条" + return {"message": msg, "batch": batch, "total": count, "skipped": len(skipped)} @router.get("/sources") def list_sources(db: Session = Depends(get_db)):