#!/usr/bin/env python3 """导入海外下单表到数据库""" import os, sys, re import openpyxl import pymysql from config import DB_CONFIG EXCEL_PATH = "/home/gxd/.openclaw/workspace-dingtalk-assistant/media/inbound/海外下单表(跟单)6-17-1781682944613.xlsx" # 58列字段定义 COLUMNS = [ ("日期", "DATE"), ("计划下单时间", "DATETIME"), ("产品编码", "VARCHAR(100)"), ("单价", "DECIMAL(12,4)"), ("是否审核价格", "VARCHAR(50)"), ("数量", "INT"), ("金额", "DECIMAL(14,2)"), ("供应商", "VARCHAR(200)"), ("仓库", "VARCHAR(200)"), ("货品名称", "VARCHAR(500)"), ("新旧品", "VARCHAR(50)"), ("是否已做采购单", "VARCHAR(50)"), ("是否做入库", "VARCHAR(50)"), ("采购员", "VARCHAR(500)"), ("下单人", "VARCHAR(100)"), ("进度", "VARCHAR(200)"), ("下单备注", "TEXT"), ("采购开发", "VARCHAR(200)"), ("旺店通生产单号", "VARCHAR(100)"), ("是否已录入到旺店通", "VARCHAR(50)"), ("实际到货日期", "VARCHAR(50)"), ("实际到货数量辅助", "INT"), ("辅助", "VARCHAR(100)"), ("实际到货数量", "INT"), ("预计到货日期", "VARCHAR(50)"), ("未到货数", "INT"), ("状态", "VARCHAR(50)"), ] # 1-31 到货日明细 for i in range(1, 32): COLUMNS.append((str(i), "INT")) CREATE_SQL = """ CREATE TABLE IF NOT EXISTS overseas_orders ( id INT AUTO_INCREMENT PRIMARY KEY, {fields}, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci """ def main(): conn = pymysql.connect(**DB_CONFIG) cur = conn.cursor() # 1. 建表 field_defs = ", ".join([f"`{name}` {dtype} DEFAULT NULL" for name, dtype in COLUMNS]) sql = CREATE_SQL.format(fields=field_defs) cur.execute(sql) print("✅ 表 overseas_orders 已就绪") # 2. 清空旧数据 cur.execute("TRUNCATE TABLE overseas_orders") print("✅ 已清空旧数据") # 3. 读 Excel wb = openpyxl.load_workbook(EXCEL_PATH, data_only=True) ws = wb.active # 验证表头 headers = [] for col in range(1, ws.max_column + 1): val = ws.cell(row=1, column=col).value headers.append(str(val).strip() if val else "") expected = [c[0] for c in COLUMNS] mismatch = [] for i, (h, e) in enumerate(zip(headers, expected)): if h != e: mismatch.append(f" 列{i+1}: 期望'{e}' 实际'{h}'") if mismatch: print("⚠️ 表头不匹配:") for m in mismatch: print(m) return # 4. 导入数据 col_types = [c[1] for c in COLUMNS] def clean_val(val, dtype): if val is None: return None s = str(val).strip() if not s: return None if dtype.startswith('INT'): nums = re.sub(r'[^0-9\-]', '', s) if nums and nums != '-': try: return int(nums) except: return None clean = re.sub(r'[^0-9]', '', s) if clean: try: return int(clean) except: return None return None if dtype.startswith('DECIMAL'): clean = re.sub(r'[^0-9\.\-]', '', s) if clean and clean != '.': try: return float(clean) except: return None return None if dtype == 'DATE': date_match = re.match(r'(\d{4})[\-\/](\d{1,2})[\-\/](\d{1,2})', s) if date_match: return f"{date_match.group(1)}-{int(date_match.group(2)):02d}-{int(date_match.group(3)):02d}" return None if not s else s if dtype == 'DATETIME': dt_match = re.match(r'(\d{4})[\-\/](\d{1,2})[\-\/](\d{1,2})\s+(\d{1,2}):(\d{1,2})(:(\d{1,2}))?', s) if dt_match: return f"{dt_match.group(1)}-{int(dt_match.group(2)):02d}-{int(dt_match.group(3)):02d} {int(dt_match.group(4)):02d}:{dt_match.group(5)}:00" return None if not s else s return s if s else None placeholders = ", ".join(["%s"] * len(COLUMNS)) col_names = ", ".join([f"`{c[0]}`" for c in COLUMNS]) insert_sql = f"INSERT INTO overseas_orders ({col_names}) VALUES ({placeholders})" total = 0 batch = [] for row_idx in range(2, ws.max_row + 1): row_data = [] has_data = False for col_idx in range(1, len(COLUMNS) + 1): val = ws.cell(row=row_idx, column=col_idx).value cleaned = clean_val(val, col_types[col_idx - 1]) row_data.append(cleaned) if cleaned is not None: has_data = True if not has_data: continue batch.append(tuple(row_data)) total += 1 if len(batch) >= 500: cur.executemany(insert_sql, batch) conn.commit() print(f" 已导入 {total} 行...") batch = [] if batch: cur.executemany(insert_sql, batch) conn.commit() print(f"✅ 导入完成,共 {total} 行") # 5. 验证 cur.execute("SELECT COUNT(*) FROM overseas_orders") cnt = cur.fetchone()[0] print(f"📊 数据库记录数: {cnt}") cur.execute("SELECT `日期`,`产品编码`,`货品名称`,`数量`,`供应商`,`状态` FROM overseas_orders WHERE `日期` IS NOT NULL ORDER BY `日期` DESC LIMIT 5") print("\n最新记录:") for r in cur.fetchall(): print(f" {r[0]} | {r[1]} | {r[2][:25]}... | {r[3]}件 | {r[4]} | {r[5]}") conn.close() if __name__ == "__main__": main()