gen_table_excel.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/env python3
  2. """从 aidopdev 数据库导出全部表结构到 Excel,按业务分类分 Sheet。"""
  3. import pymysql
  4. from pathlib import Path
  5. from openpyxl import Workbook
  6. from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
  7. from collections import OrderedDict
  8. DB_CFG = dict(
  9. host="123.60.180.165", port=3306,
  10. user="aidopremote", password="1234567890aiDOP#",
  11. database="information_schema", charset="utf8mb4",
  12. )
  13. CATEGORY_ORDER = OrderedDict([
  14. ("系统基础(Sys)", lambda t: t.startswith("Sys")),
  15. ("审批流程(Approval)", lambda t: t.startswith("Approval")),
  16. ("钉钉集成(DingTalk)", lambda t: t.startswith("DingTalk") or t.startswith("ding_talk")),
  17. ("GoView可视化", lambda t: t.startswith("GoView")),
  18. ("S0 基础主数据", lambda t: t.startswith("ado_s0_")),
  19. ("S1 产销协同", lambda t: t.startswith("ado_s1_")),
  20. ("S2 生产计划", lambda t: t.startswith("ado_s2_")),
  21. ("S3 物料计划", lambda t: t.startswith("ado_s3_")),
  22. ("S4 采购", lambda t: t.startswith("ado_s4_")),
  23. ("S5 仓储来料", lambda t: t.startswith("ado_s5_")),
  24. ("S6 生产执行", lambda t: t.startswith("ado_s6_")),
  25. ("S7 成品管理", lambda t: t.startswith("ado_s7_")),
  26. ("S8 预警异常", lambda t: t.startswith("ado_s8_")),
  27. ("S9 管理看板KPI", lambda t: t.startswith("ado_s9_")),
  28. ("智慧运营(SmartOps)", lambda t: t.startswith("ado_smart_ops_")),
  29. ("主数据(MD)", lambda t: t.startswith("ado_md_")),
  30. ("集成(Intg)", lambda t: t.startswith("ado_intg_")),
  31. ("移动端(Mobile)", lambda t: t.startswith("ado_mobile_")),
  32. ("Demo表", lambda t: t in ("ado_orders", "ado_plans", "ado_work_orders")),
  33. ("其他", lambda t: True),
  34. ])
  35. HEADER_FILL = PatternFill("solid", fgColor="4472C4")
  36. HEADER_FONT = Font(name="微软雅黑", bold=True, color="FFFFFF", size=10)
  37. BODY_FONT = Font(name="微软雅黑", size=9)
  38. TBL_FILL = PatternFill("solid", fgColor="D9E2F3")
  39. TBL_FONT = Font(name="微软雅黑", bold=True, size=10)
  40. THIN_BORDER = Border(
  41. left=Side(style="thin"), right=Side(style="thin"),
  42. top=Side(style="thin"), bottom=Side(style="thin"),
  43. )
  44. WRAP = Alignment(wrap_text=True, vertical="center")
  45. def fetch_data():
  46. conn = pymysql.connect(**DB_CFG)
  47. cur = conn.cursor()
  48. cur.execute(
  49. "SELECT TABLE_NAME, TABLE_COMMENT, TABLE_ROWS "
  50. "FROM TABLES WHERE TABLE_SCHEMA='aidopdev' ORDER BY TABLE_NAME"
  51. )
  52. tables = {r[0]: {"comment": r[1] or "", "rows": r[2]} for r in cur.fetchall()}
  53. cur.execute(
  54. "SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, "
  55. "COLUMN_DEFAULT, COLUMN_COMMENT "
  56. "FROM COLUMNS WHERE TABLE_SCHEMA='aidopdev' "
  57. "ORDER BY TABLE_NAME, ORDINAL_POSITION"
  58. )
  59. columns = {}
  60. for row in cur.fetchall():
  61. columns.setdefault(row[0], []).append(row[1:])
  62. cur.close()
  63. conn.close()
  64. return tables, columns
  65. def classify(tables):
  66. result = OrderedDict((k, []) for k in CATEGORY_ORDER)
  67. assigned = set()
  68. for cat, pred in CATEGORY_ORDER.items():
  69. for tname in tables:
  70. if tname not in assigned and pred(tname):
  71. result[cat].append(tname)
  72. assigned.add(tname)
  73. return result
  74. def write_overview(ws, tables, classified):
  75. headers = ["序号", "分类", "表名", "表说明", "记录数"]
  76. widths = [6, 22, 42, 36, 10]
  77. for ci, (h, w) in enumerate(zip(headers, widths), 1):
  78. c = ws.cell(row=1, column=ci, value=h)
  79. c.font = HEADER_FONT
  80. c.fill = HEADER_FILL
  81. c.alignment = WRAP
  82. c.border = THIN_BORDER
  83. ws.column_dimensions[c.column_letter].width = w
  84. idx = 0
  85. for cat, tnames in classified.items():
  86. for tname in tnames:
  87. idx += 1
  88. info = tables[tname]
  89. vals = [idx, cat, tname, info["comment"], info["rows"]]
  90. for ci, v in enumerate(vals, 1):
  91. c = ws.cell(row=idx + 1, column=ci, value=v)
  92. c.font = BODY_FONT
  93. c.alignment = WRAP
  94. c.border = THIN_BORDER
  95. ws.auto_filter.ref = f"A1:E{idx + 1}"
  96. def write_detail_sheet(ws, cat, tnames, tables, columns):
  97. headers = ["字段名", "类型", "可空", "默认值", "说明"]
  98. widths = [28, 22, 6, 14, 36]
  99. for ci, w in enumerate(widths, 1):
  100. ws.column_dimensions[ws.cell(row=1, column=ci).column_letter].width = w
  101. row = 1
  102. for tname in tnames:
  103. info = tables[tname]
  104. c = ws.cell(row=row, column=1,
  105. value=f"{tname} — {info['comment']} (约{info['rows'] or 0}行)")
  106. c.font = TBL_FONT
  107. c.fill = TBL_FILL
  108. c.border = THIN_BORDER
  109. for ci in range(2, 6):
  110. cc = ws.cell(row=row, column=ci)
  111. cc.fill = TBL_FILL
  112. cc.border = THIN_BORDER
  113. ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=5)
  114. row += 1
  115. for ci, (h, w) in enumerate(zip(headers, widths), 1):
  116. c = ws.cell(row=row, column=ci, value=h)
  117. c.font = HEADER_FONT
  118. c.fill = HEADER_FILL
  119. c.alignment = WRAP
  120. c.border = THIN_BORDER
  121. row += 1
  122. for col_info in columns.get(tname, []):
  123. col_name, col_type, nullable, default, comment = col_info
  124. vals = [col_name, col_type, nullable, str(default) if default is not None else "", comment or ""]
  125. for ci, v in enumerate(vals, 1):
  126. c = ws.cell(row=row, column=ci, value=v)
  127. c.font = BODY_FONT
  128. c.alignment = WRAP
  129. c.border = THIN_BORDER
  130. row += 1
  131. row += 1
  132. def main():
  133. tables, columns = fetch_data()
  134. classified = classify(tables)
  135. wb = Workbook()
  136. ws_overview = wb.active
  137. ws_overview.title = "总览"
  138. write_overview(ws_overview, tables, classified)
  139. for cat, tnames in classified.items():
  140. if not tnames:
  141. continue
  142. safe_title = cat[:31]
  143. ws = wb.create_sheet(title=safe_title)
  144. write_detail_sheet(ws, cat, tnames, tables, columns)
  145. out = Path(__file__).resolve().parent / "aidopdev_表结构汇总.xlsx"
  146. wb.save(out)
  147. print(f"Done → {out}")
  148. if __name__ == "__main__":
  149. main()