| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- #!/usr/bin/env python3
- """从 aidopdev 数据库导出全部表结构到 Excel,按业务分类分 Sheet。"""
- import pymysql
- from openpyxl import Workbook
- from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
- from collections import OrderedDict
- DB_CFG = dict(
- host="123.60.180.165", port=3306,
- user="aidopremote", password="1234567890aiDOP#",
- database="information_schema", charset="utf8mb4",
- )
- CATEGORY_ORDER = OrderedDict([
- ("系统基础(Sys)", lambda t: t.startswith("Sys")),
- ("审批流程(Approval)", lambda t: t.startswith("Approval")),
- ("钉钉集成(DingTalk)", lambda t: t.startswith("DingTalk") or t.startswith("ding_talk")),
- ("GoView可视化", lambda t: t.startswith("GoView")),
- ("S0 基础主数据", lambda t: t.startswith("ado_s0_")),
- ("S1 产销协同", lambda t: t.startswith("ado_s1_")),
- ("S2 生产计划", lambda t: t.startswith("ado_s2_")),
- ("S3 物料计划", lambda t: t.startswith("ado_s3_")),
- ("S4 采购", lambda t: t.startswith("ado_s4_")),
- ("S5 仓储来料", lambda t: t.startswith("ado_s5_")),
- ("S6 生产执行", lambda t: t.startswith("ado_s6_")),
- ("S7 成品管理", lambda t: t.startswith("ado_s7_")),
- ("S8 预警异常", lambda t: t.startswith("ado_s8_")),
- ("S9 管理看板KPI", lambda t: t.startswith("ado_s9_")),
- ("智慧运营(SmartOps)", lambda t: t.startswith("ado_smart_ops_")),
- ("主数据(MD)", lambda t: t.startswith("ado_md_")),
- ("集成(Intg)", lambda t: t.startswith("ado_intg_")),
- ("移动端(Mobile)", lambda t: t.startswith("ado_mobile_")),
- ("Demo表", lambda t: t in ("ado_orders", "ado_plans", "ado_work_orders")),
- ("其他", lambda t: True),
- ])
- HEADER_FILL = PatternFill("solid", fgColor="4472C4")
- HEADER_FONT = Font(name="微软雅黑", bold=True, color="FFFFFF", size=10)
- BODY_FONT = Font(name="微软雅黑", size=9)
- TBL_FILL = PatternFill("solid", fgColor="D9E2F3")
- TBL_FONT = Font(name="微软雅黑", bold=True, size=10)
- THIN_BORDER = Border(
- left=Side(style="thin"), right=Side(style="thin"),
- top=Side(style="thin"), bottom=Side(style="thin"),
- )
- WRAP = Alignment(wrap_text=True, vertical="center")
- def fetch_data():
- conn = pymysql.connect(**DB_CFG)
- cur = conn.cursor()
- cur.execute(
- "SELECT TABLE_NAME, TABLE_COMMENT, TABLE_ROWS "
- "FROM TABLES WHERE TABLE_SCHEMA='aidopdev' ORDER BY TABLE_NAME"
- )
- tables = {r[0]: {"comment": r[1] or "", "rows": r[2]} for r in cur.fetchall()}
- cur.execute(
- "SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, "
- "COLUMN_DEFAULT, COLUMN_COMMENT "
- "FROM COLUMNS WHERE TABLE_SCHEMA='aidopdev' "
- "ORDER BY TABLE_NAME, ORDINAL_POSITION"
- )
- columns = {}
- for row in cur.fetchall():
- columns.setdefault(row[0], []).append(row[1:])
- cur.close()
- conn.close()
- return tables, columns
- def classify(tables):
- result = OrderedDict((k, []) for k in CATEGORY_ORDER)
- assigned = set()
- for cat, pred in CATEGORY_ORDER.items():
- for tname in tables:
- if tname not in assigned and pred(tname):
- result[cat].append(tname)
- assigned.add(tname)
- return result
- def write_overview(ws, tables, classified):
- headers = ["序号", "分类", "表名", "表说明", "记录数"]
- widths = [6, 22, 42, 36, 10]
- for ci, (h, w) in enumerate(zip(headers, widths), 1):
- c = ws.cell(row=1, column=ci, value=h)
- c.font = HEADER_FONT
- c.fill = HEADER_FILL
- c.alignment = WRAP
- c.border = THIN_BORDER
- ws.column_dimensions[c.column_letter].width = w
- idx = 0
- for cat, tnames in classified.items():
- for tname in tnames:
- idx += 1
- info = tables[tname]
- vals = [idx, cat, tname, info["comment"], info["rows"]]
- for ci, v in enumerate(vals, 1):
- c = ws.cell(row=idx + 1, column=ci, value=v)
- c.font = BODY_FONT
- c.alignment = WRAP
- c.border = THIN_BORDER
- ws.auto_filter.ref = f"A1:E{idx + 1}"
- def write_detail_sheet(ws, cat, tnames, tables, columns):
- headers = ["字段名", "类型", "可空", "默认值", "说明"]
- widths = [28, 22, 6, 14, 36]
- for ci, w in enumerate(widths, 1):
- ws.column_dimensions[ws.cell(row=1, column=ci).column_letter].width = w
- row = 1
- for tname in tnames:
- info = tables[tname]
- c = ws.cell(row=row, column=1,
- value=f"{tname} — {info['comment']} (约{info['rows'] or 0}行)")
- c.font = TBL_FONT
- c.fill = TBL_FILL
- c.border = THIN_BORDER
- for ci in range(2, 6):
- cc = ws.cell(row=row, column=ci)
- cc.fill = TBL_FILL
- cc.border = THIN_BORDER
- ws.merge_cells(start_row=row, start_column=1, end_row=row, end_column=5)
- row += 1
- for ci, (h, w) in enumerate(zip(headers, widths), 1):
- c = ws.cell(row=row, column=ci, value=h)
- c.font = HEADER_FONT
- c.fill = HEADER_FILL
- c.alignment = WRAP
- c.border = THIN_BORDER
- row += 1
- for col_info in columns.get(tname, []):
- col_name, col_type, nullable, default, comment = col_info
- vals = [col_name, col_type, nullable, str(default) if default is not None else "", comment or ""]
- for ci, v in enumerate(vals, 1):
- c = ws.cell(row=row, column=ci, value=v)
- c.font = BODY_FONT
- c.alignment = WRAP
- c.border = THIN_BORDER
- row += 1
- row += 1
- def main():
- tables, columns = fetch_data()
- classified = classify(tables)
- wb = Workbook()
- ws_overview = wb.active
- ws_overview.title = "总览"
- write_overview(ws_overview, tables, classified)
- for cat, tnames in classified.items():
- if not tnames:
- continue
- safe_title = cat[:31]
- ws = wb.create_sheet(title=safe_title)
- write_detail_sheet(ws, cat, tnames, tables, columns)
- out = "/root/aidopdemo/docs/db/aidopdev_表结构汇总.xlsx"
- wb.save(out)
- print(f"Done → {out}")
- if __name__ == "__main__":
- main()
|