This commit is contained in:
jeremygan2021
2026-03-20 15:55:02 +08:00
parent a770fbfd2a
commit 3bdb055b83
4 changed files with 1062 additions and 185 deletions

235
main.py
View File

@@ -1661,6 +1661,241 @@ async def success_page(request: Request):
CONFIG = load_config()
return templates.TemplateResponse("success.html", {"request": request, "config": CONFIG})
@app.get("/data-base", response_class=HTMLResponse)
async def data_base_page(request: Request):
"""
渲染数据库管理页面。
"""
return templates.TemplateResponse("data_base.html", {"request": request})
@app.get("/api/db/tables")
def get_db_tables():
"""
获取数据库中所有的表。
"""
try:
conn = get_db_connection()
cur = conn.cursor(cursor_factory=RealDictCursor)
cur.execute("""
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_type = 'BASE TABLE'
ORDER BY table_name
""")
rows = cur.fetchall()
tables = [row['table_name'] for row in rows]
cur.close()
release_db_connection(conn)
return {"success": True, "tables": tables}
except Exception as e:
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
@app.get("/api/db/table/{table_name}")
def get_table_data(table_name: str, page: int = 1, page_size: int = 50):
"""
获取指定表的数据。
"""
try:
conn = get_db_connection()
cur = conn.cursor(cursor_factory=RealDictCursor)
# 获取主键
cur.execute("""
SELECT a.attname AS column_name
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = %s::regclass
AND i.indisprimary
""", (table_name,))
pk_result = cur.fetchone()
primary_key = pk_result['column_name'] if pk_result else ''
# 获取总行数
cur.execute(f'SELECT COUNT(*) as count FROM "{table_name}"')
total = cur.fetchone()['count']
# 分页查询
offset = (page - 1) * page_size
query = f'SELECT * FROM "{table_name}" ORDER BY "{primary_key}" LIMIT %s OFFSET %s'
cur.execute(query, (page_size, offset))
rows = cur.fetchall()
# 转换为普通字典
result_rows = []
for row in rows:
result_rows.append(dict(row))
# 获取列名
columns = list(result_rows[0].keys()) if result_rows else []
cur.close()
release_db_connection(conn)
return {
"success": True,
"rows": result_rows,
"columns": columns,
"total": total,
"primary_key": primary_key,
"page": page,
"page_size": page_size
}
except Exception as e:
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
@app.get("/api/db/table/{table_name}/columns")
def get_table_columns(table_name: str):
"""
获取指定表的列信息。
"""
try:
conn = get_db_connection()
cur = conn.cursor(cursor_factory=RealDictCursor)
cur.execute("""
SELECT
column_name,
data_type,
is_nullable,
column_default
FROM information_schema.columns
WHERE table_name = %s
AND table_schema = 'public'
ORDER BY ordinal_position
""", (table_name,))
rows = cur.fetchall()
cur.close()
release_db_connection(conn)
return {"success": True, "columns": rows}
except Exception as e:
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
@app.post("/api/db/table/{table_name}/insert")
async def insert_table_data(table_name: str, request: Request):
"""
向指定表插入数据。
"""
try:
body = await request.json()
data = body.get('data', {})
if not data:
return JSONResponse(content={"success": False, "message": "没有数据"}, status_code=400)
conn = get_db_connection()
cur = conn.cursor()
columns = list(data.keys())
values = list(data.values())
placeholders = ','.join(['%s'] * len(columns))
column_names = ','.join([f'"{col}"' for col in columns])
query = f'INSERT INTO "{table_name}" ({column_names}) VALUES ({placeholders})'
cur.execute(query, values)
conn.commit()
cur.close()
release_db_connection(conn)
return {"success": True, "message": "添加成功"}
except Exception as e:
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
@app.put("/api/db/table/{table_name}/update")
async def update_table_data(table_name: str, request: Request):
"""
更新指定表的数据。
"""
try:
body = await request.json()
data = body.get('data', {})
record_id = body.get('id')
if not data or not record_id:
return JSONResponse(content={"success": False, "message": "缺少参数"}, status_code=400)
conn = get_db_connection()
cur = conn.cursor(cursor_factory=RealDictCursor)
# 获取主键
cur.execute("""
SELECT a.attname AS column_name
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = %s::regclass
AND i.indisprimary
""", (table_name,))
pk_result = cur.fetchone()
primary_key = pk_result['column_name'] if pk_result else None
if not primary_key:
return JSONResponse(content={"success": False, "message": "表没有主键,无法更新"}, status_code=400)
# 构建更新语句
set_clause = ','.join([f'"{col}" = %s' for col in data.keys()])
values = list(data.values())
values.append(record_id)
query = f'UPDATE "{table_name}" SET {set_clause} WHERE "{primary_key}" = %s'
cur.execute(query, values)
conn.commit()
cur.close()
release_db_connection(conn)
return {"success": True, "message": "更新成功"}
except Exception as e:
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
@app.delete("/api/db/table/{table_name}/delete")
async def delete_table_data(table_name: str, request: Request):
"""
删除指定表的数据。
"""
try:
body = await request.json()
ids = body.get('ids', [])
if not ids:
return JSONResponse(content={"success": False, "message": "没有要删除的记录"}, status_code=400)
conn = get_db_connection()
cur = conn.cursor(cursor_factory=RealDictCursor)
# 获取主键
cur.execute("""
SELECT a.attname AS column_name
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = %s::regclass
AND i.indisprimary
""", (table_name,))
pk_result = cur.fetchone()
primary_key = pk_result['column_name'] if pk_result else None
if not primary_key:
return JSONResponse(content={"success": False, "message": "表没有主键,无法删除"}, status_code=400)
# 删除 ids 中的记录
placeholders = ','.join(['%s'] * len(ids))
query = f'DELETE FROM "{table_name}" WHERE "{primary_key}" IN ({placeholders})'
cur.execute(query, ids)
conn.commit()
cur.close()
release_db_connection(conn)
return {"success": True, "message": f"成功删除 {cur.rowcount} 条记录"}
except Exception as e:
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
class TicketPaymentRequest(BaseModel):
name: str
phone: str