#!/usr/bin/env python3 """钉盘数据增量更新 - 下载新增CSV并导入数据库""" import os, sys, json, subprocess, urllib.request, time BASE_DIR = os.path.dirname(os.path.abspath(__file__)) CSV_DIR = os.path.join(BASE_DIR, "tmp_csv") os.makedirs(CSV_DIR, exist_ok=True) def log(m): print(f"[{time.strftime('%H:%M:%S')}] {m}") def dws(cmd): r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=60) try: return json.loads(r.stdout) except: return {} def download_file(node_id, filename): """下载单个文件""" dest = os.path.join(CSV_DIR, filename) if os.path.exists(dest): log(f" 已存在,跳过: {filename}") return True log(f" 下载 {filename} ...") # 用 --output 获取下载链接 tmp = f"/tmp/dld_{int(time.time())}_{filename}" info = dws(f'dws doc download --node "{node_id}" --output "{tmp}" --format json') if not info.get("success"): log(f" ❌ 获取下载链接失败: {filename}") return False url = info.get("resourceUrl", "") if not url: log(f" ❌ 无下载链接: {filename}") return False try: urllib.request.urlretrieve(url, dest) size = os.path.getsize(dest) log(f" ✅ {filename} ({size:,} bytes)") # 清理临时文件 if os.path.exists(tmp): os.remove(tmp) return True except Exception as e: log(f" ❌ 下载失败: {filename} - {e}") return False def get_all_nodes(folder_id): """获取文件夹下所有文件(自动翻页)""" all_nodes = [] page_token = None while True: cmd = f'dws doc list --folder "{folder_id}" --format json' if page_token: cmd += f' --page-token "{page_token}"' result = dws(cmd) nodes = result.get('nodes', []) all_nodes.extend(nodes) if not result.get('hasMore'): break page_token = result.get('nextPageToken') if not page_token: break return all_nodes # ========== 1. 下载日出库数据(06-02 ~ 06-05)========== log("=" * 60) log("第一步:下载日出库 CSV 文件 (06-02 ~ 06-05)") OUTBOUND_FOLDER = "3NwLYZXWynyBjRB4tZjwNxDvVkyEqBQm" outbound_nodes = get_all_nodes(OUTBOUND_FOLDER) log(f"日出库文件夹共 {len(outbound_nodes)} 个文件") target_dates = ['20260602', '20260603', '20260604', '20260605'] downloaded_outbound = 0 for n in outbound_nodes: name = n['name'] node_id = n.get('nodeId', '') if any(name.startswith(d) for d in target_dates): clean_name = name.strip().replace(' ', '') if not clean_name.endswith('.csv'): clean_name += '.csv' if download_file(node_id, clean_name): downloaded_outbound += 1 log(f"日出库下载完成: {downloaded_outbound} 个文件") # ========== 2. 下载库存数据(06-08)========== log("") log("=" * 60) log("第二步:下载库存 CSV 文件 (06-08)") INVENTORY_FOLDER = "NkDwLng8ZLGrXmrnFxYq3vRqVKMEvZBY" inventory_nodes = get_all_nodes(INVENTORY_FOLDER) log(f"库存文件夹共 {len(inventory_nodes)} 个文件") downloaded_inventory = 0 for n in inventory_nodes: name = n['name'] node_id = n.get('nodeId', '') if name.startswith('20260608') and name.endswith('.csv'): if download_file(node_id, name): downloaded_inventory += 1 log(f"库存下载完成: {downloaded_inventory} 个文件") # ========== 3. 导入数据到MySQL ========== log("") log("=" * 60) log("第三步:导入数据到数据库") log("导入日出库数据...") r = subprocess.run( f"cd {BASE_DIR} && python3 reimport.py", shell=True, capture_output=True, text=True, timeout=600 ) if r.returncode == 0: log("✅ 日出库导入成功") else: log(f"⚠️ 日出库导入异常: {r.stderr[-300:]}") for line in r.stdout.strip().split('\n')[-10:]: log(f" {line}") log("导入库存数据...") r = subprocess.run( f"cd {BASE_DIR} && python3 batch_import_inventory.py", shell=True, capture_output=True, text=True, timeout=600 ) if r.returncode == 0: log("✅ 库存导入成功") else: log(f"⚠️ 库存导入异常: {r.stderr[-300:]}") for line in r.stdout.strip().split('\n')[-10:]: log(f" {line}") # ========== 4. 验证数据 ========== log("") log("=" * 60) log("第四步:验证数据") import pymysql from config import DB_CONFIG try: conn = pymysql.connect(**DB_CONFIG) with conn.cursor() as cur: cur.execute("SELECT MIN(日期) AS min_d, MAX(日期) AS max_d, COUNT(*) AS cnt FROM daily_outbound") r = cur.fetchone() log(f"日出库: {r[0]} ~ {r[1]}, 共 {r[2]} 条") cur.execute("SELECT MIN(data_date) AS min_d, MAX(data_date) AS max_d, COUNT(*) AS cnt FROM inventory_detail") r = cur.fetchone() log(f"库存: {r[0]} ~ {r[1]}, 共 {r[2]} 条") conn.close() log("✅ 数据验证通过") except Exception as e: log(f"⚠️ 验证失败: {e}") # ========== 5. 重启服务 ========== log("") log("=" * 60) log("第五步:重启服务刷新缓存") os.system("kill $(lsof -t -i:18888) 2>/dev/null; sleep 2") os.system(f"cd {BASE_DIR} && nohup /home/gxd/.local/bin/gunicorn -w 4 -b 0.0.0.0:18888 --timeout 120 --max-requests 800 --max-requests-jitter 100 --access-logfile logs/access.log --error-logfile logs/error.log app:app > logs/startup.log 2>&1 &") log("✅ 服务已重启,数据同步完成")