#!/usr/bin/env python3 """只读侦查(生产读,本单 dama-entity-isolation-sweep-20260923 §一/§二 前置) 只 SELECT,无任何写。用于: 1. system_configs / role_permissions 全量键实况(含 kpi_alert_higher_better / budget_mode / budget_driver_mode / current_tenant / cash.current_balance.* / alignment_config.*) 2. operation_logs 实况(action 分布、switch_entity / switch_tenant_state 行数、最近行) 3. entities 实况(账套清单) 4. kpi_definitions 列面(是否有自身方向字段)+ 逐账套 KPI 分布 用法: python3 [--json out.json] """ import json import os import sys from pathlib import Path BACKEND = Path("/srv/hermes/shared/cma-management/backend") os.chdir(BACKEND) sys.path.insert(0, str(BACKEND)) from sqlalchemy import text # noqa: E402 from app.database import get_engine # noqa: E402 out = {} eng = get_engine() with eng.connect() as c: out["db"] = c.execute(text("SELECT DATABASE()")).scalar() out["system_configs"] = [ {"id": r[0], "config_key": r[1], "config_value": r[2], "description": r[3], "updated_at": str(r[4])} for r in c.execute(text( "SELECT id, config_key, config_value, description, updated_at " "FROM system_configs ORDER BY config_key")) ] out["role_permissions"] = [ {"id": r[0], "key": r[1], "value": r[2], "updated_at": str(r[3])} for r in c.execute(text("SELECT id, `key`, `value`, updated_at FROM role_permissions ORDER BY `key`")) ] out["entities"] = [ {"id": r[0], "name": r[1], "short_name": r[2], "status": r[3]} for r in c.execute(text("SELECT id, name, short_name, status FROM entities ORDER BY id")) ] out["op_logs_actions"] = [ {"action": r[0], "n": r[1], "last": str(r[2])} for r in c.execute(text( "SELECT action, COUNT(*) n, MAX(created_at) last FROM operation_logs " "GROUP BY action ORDER BY n DESC")) ] out["op_logs_switch_rows"] = [ {"id": r[0], "user_id": r[1], "action": r[2], "target_type": r[3], "target_id": r[4], "detail": (r[5] or "")[:300], "created_at": str(r[6])} for r in c.execute(text( "SELECT id, user_id, action, target_type, target_id, detail, created_at " "FROM operation_logs WHERE action LIKE '%switch%' OR action LIKE '%tenant%' " "ORDER BY id DESC LIMIT 10")) ] out["op_logs_recent"] = [ {"id": r[0], "user_id": r[1], "action": r[2], "target_type": r[3], "target_id": r[4], "created_at": str(r[5])} for r in c.execute(text( "SELECT id, user_id, action, target_type, target_id, created_at " "FROM operation_logs ORDER BY id DESC LIMIT 12")) ] out["system_configs_cols"] = [ {"col": r[0], "type": r[1], "null": r[2], "key": r[3], "default": str(r[4])} for r in c.execute(text( "SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT " "FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() " "AND TABLE_NAME IN ('system_configs','role_permissions','operation_logs') " "ORDER BY TABLE_NAME, ORDINAL_POSITION")) ] out["kpi_def_cols"] = [ r[0] for r in c.execute(text( "SELECT COLUMN_NAME FROM information_schema.COLUMNS " "WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='kpi_definitions' " "ORDER BY ORDINAL_POSITION")) ] out["kpi_by_entity"] = [ {"entity_id": r[0], "n": r[1]} for r in c.execute(text( "SELECT entity_id, COUNT(*) n FROM kpi_definitions GROUP BY entity_id ORDER BY entity_id")) ] out["budgetplan_by_entity"] = [ {"entity_id": r[0], "n": r[1]} for r in c.execute(text( "SELECT kd.entity_id, COUNT(*) n FROM budget_plans bp " "JOIN kpi_definitions kd ON kd.id=bp.kpi_id GROUP BY kd.entity_id ORDER BY kd.entity_id")) ] print(json.dumps(out, ensure_ascii=False, indent=1, default=str)) if "--json" in sys.argv: p = sys.argv[sys.argv.index("--json") + 1] Path(p).write_text(json.dumps(out, ensure_ascii=False, indent=1, default=str)) print("WROTE", p)