Files
oneos-backend/sql/rebuild/rebuild_all.py
kkfluous 2f38a703f9 refactor(energy): 简化事件驱动系统(7个→3个)
- 删除旧事件:BillApprovedEvent, BillCreatedEvent, DeductionCompletedEvent, DetailAuditedEvent, DetailCreatedEvent, RecordMatchedEvent
- 新增事件:BillAuditPassedEvent, DetailAuditPassedEvent
- 保留事件:RecordImportedEvent
- 更新监听器:AccountEventListener, BillEventListener, DetailEventListener
- 清理代码中的旧事件引用和注释

优化原则:前端简单,后端健壮
事件流程:导入→匹配→生成明细→审核→扣款→生成账单→结算
2026-03-16 12:53:14 +08:00

222 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
重建 Asset 和 Energy 模块数据表并插入 Mock 数据
- Asset 表 → oneos_asset 数据库
- Energy 表 → oneos_energy 数据库
- 使用 pymysql 连接远程 MySQL规避本地 mysql 客户端 auth plugin 问题)
"""
import os
import sys
import re
try:
import pymysql
except ImportError:
print("pymysql 未安装,正在安装...")
os.system(f"{sys.executable} -m pip install pymysql")
import pymysql
# 数据库连接配置
DB_CONFIG = {
"host": "47.103.115.36",
"port": 3306,
"user": "root",
"password": "Passw0rd2026",
"charset": "utf8mb4",
}
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
def read_sql_file(filename):
"""读取 SQL 文件内容"""
filepath = os.path.join(SCRIPT_DIR, filename)
with open(filepath, "r", encoding="utf-8") as f:
return f.read()
def split_statements(sql_text):
"""
将 SQL 文本拆分为独立语句。
处理 CREATE VIEW 等多行语句,跳过注释和空行。
"""
statements = []
current = []
for line in sql_text.split("\n"):
stripped = line.strip()
# 跳过纯注释行和空行(但保留语句中间的注释)
if not stripped or stripped.startswith("--"):
if current:
# 如果当前语句已经开始,保留注释行(可能是语句内的注释)
pass
continue
current.append(line)
if stripped.endswith(";"):
stmt = "\n".join(current).strip()
if stmt:
statements.append(stmt)
current = []
# 处理没有分号结尾的最后一条语句
if current:
stmt = "\n".join(current).strip()
if stmt:
statements.append(stmt)
return statements
def execute_sql(cursor, sql_text, label=""):
"""执行一段 SQL可包含多条语句"""
statements = split_statements(sql_text)
success = 0
errors = 0
for i, stmt in enumerate(statements, 1):
# 提取语句摘要用于日志
first_line = stmt.split("\n")[0][:80]
try:
cursor.execute(stmt)
success += 1
except pymysql.err.OperationalError as e:
code = e.args[0]
# 1051: Unknown table (DROP 不存在的表) - 忽略
if code == 1051:
success += 1
else:
errors += 1
print(f" ❌ [{label}] 语句 {i} 失败: {e}")
print(f" SQL: {first_line}...")
except Exception as e:
errors += 1
print(f" ❌ [{label}] 语句 {i} 失败: {e}")
print(f" SQL: {first_line}...")
return success, errors
def main():
print("=" * 60)
print("ONE-OS 数据表重建工具")
print("=" * 60)
# 读取 SQL 文件
print("\n📄 读取 SQL 文件...")
asset_ddl = read_sql_file("asset_ddl.sql")
energy_ddl = read_sql_file("energy_ddl.sql")
mock_data = read_sql_file("mock_data.sql")
# 拆分 mock_data 为 asset 和 energy 部分
parts = mock_data.split("-- ===================== PART 2: ENERGY =====================")
if len(parts) != 2:
print("❌ mock_data.sql 格式错误:找不到 PART 2 分隔符")
sys.exit(1)
asset_mock = parts[0]
energy_mock = parts[1]
# 从 asset_mock 中去掉文件头注释和 PART 1 标记
# 保留实际的 INSERT 语句
total_success = 0
total_errors = 0
# ========== 1. 处理 Asset 数据库 ==========
print("\n" + "=" * 60)
print("🔧 [1/3] 重建 oneos_asset 数据库表...")
print("=" * 60)
conn_asset = pymysql.connect(**DB_CONFIG, database="oneos_asset")
conn_asset.autocommit(True)
cursor_asset = conn_asset.cursor()
# 创建 Asset 表
print("\n📋 执行 Asset DDL29张表 + 1个视图...")
s, e = execute_sql(cursor_asset, asset_ddl, "Asset DDL")
total_success += s
total_errors += e
print(f" ✅ Asset DDL: {s} 成功, {e} 失败")
# 插入 Asset Mock 数据
print("\n📋 插入 Asset Mock 数据...")
s, e = execute_sql(cursor_asset, asset_mock, "Asset Mock")
total_success += s
total_errors += e
print(f" ✅ Asset Mock: {s} 成功, {e} 失败")
cursor_asset.close()
conn_asset.close()
# ========== 2. 处理 Energy 数据库 ==========
print("\n" + "=" * 60)
print("🔧 [2/3] 重建 oneos_energy 数据库表...")
print("=" * 60)
# 先确保 oneos_energy 数据库存在
conn_init = pymysql.connect(**DB_CONFIG)
conn_init.autocommit(True)
cursor_init = conn_init.cursor()
cursor_init.execute("CREATE DATABASE IF NOT EXISTS `oneos_energy` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")
cursor_init.close()
conn_init.close()
conn_energy = pymysql.connect(**DB_CONFIG, database="oneos_energy")
conn_energy.autocommit(True)
cursor_energy = conn_energy.cursor()
# 创建 Energy 表
print("\n📋 执行 Energy DDL9张表...")
s, e = execute_sql(cursor_energy, energy_ddl, "Energy DDL")
total_success += s
total_errors += e
print(f" ✅ Energy DDL: {s} 成功, {e} 失败")
# 插入 Energy Mock 数据
print("\n📋 插入 Energy Mock 数据...")
s, e = execute_sql(cursor_energy, energy_mock, "Energy Mock")
total_success += s
total_errors += e
print(f" ✅ Energy Mock: {s} 成功, {e} 失败")
cursor_energy.close()
conn_energy.close()
# ========== 3. 验证 ==========
print("\n" + "=" * 60)
print("🔍 [3/3] 验证表结构和数据...")
print("=" * 60)
# 验证 Asset
conn_v = pymysql.connect(**DB_CONFIG, database="oneos_asset")
cursor_v = conn_v.cursor()
cursor_v.execute("SELECT TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'oneos_asset' AND TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME")
asset_tables = cursor_v.fetchall()
print(f"\n📊 oneos_asset 数据库: {len(asset_tables)} 张表")
for table_name, row_count in asset_tables:
cursor_v.execute(f"SELECT COUNT(*) FROM `{table_name}`")
actual_count = cursor_v.fetchone()[0]
print(f" {table_name}: {actual_count}")
cursor_v.close()
conn_v.close()
# 验证 Energy
conn_v2 = pymysql.connect(**DB_CONFIG, database="oneos_energy")
cursor_v2 = conn_v2.cursor()
cursor_v2.execute("SELECT TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'oneos_energy' AND TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME")
energy_tables = cursor_v2.fetchall()
print(f"\n📊 oneos_energy 数据库: {len(energy_tables)} 张表")
for table_name, row_count in energy_tables:
cursor_v2.execute(f"SELECT COUNT(*) FROM `{table_name}`")
actual_count = cursor_v2.fetchone()[0]
print(f" {table_name}: {actual_count}")
cursor_v2.close()
conn_v2.close()
# ========== 总结 ==========
print("\n" + "=" * 60)
print(f"🎉 完成! 总计: {total_success} 成功, {total_errors} 失败")
print("=" * 60)
if total_errors > 0:
sys.exit(1)
if __name__ == "__main__":
main()