自定义字段
This commit is contained in:
186
main.py
186
main.py
@@ -3,6 +3,7 @@ from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from pydantic import BaseModel
|
||||
from contextlib import asynccontextmanager
|
||||
import psycopg2
|
||||
from psycopg2 import pool
|
||||
from psycopg2.extras import RealDictCursor
|
||||
@@ -13,6 +14,7 @@ import random
|
||||
import uuid
|
||||
import os
|
||||
import json
|
||||
import re
|
||||
import shutil
|
||||
import difflib
|
||||
import time
|
||||
@@ -117,13 +119,12 @@ CONFIG = load_config()
|
||||
# SMS Verification Storage (In-memory)
|
||||
SMS_CODES = {} # phone -> {code: str, expires_at: datetime}
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# 进程池全局变量
|
||||
process_pool = None
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""应用生命周期管理:启动时初始化进程池,关闭时释放资源"""
|
||||
import sys
|
||||
print(f"DEBUG: Running from {__file__}")
|
||||
print(f"DEBUG: Python executable: {sys.executable}")
|
||||
@@ -141,18 +142,20 @@ async def startup_event():
|
||||
else:
|
||||
print(f"{route.path}")
|
||||
print("=========================")
|
||||
|
||||
yield
|
||||
|
||||
# 关闭时清理进程池
|
||||
if process_pool:
|
||||
process_pool.shutdown()
|
||||
print("ProcessPoolExecutor shutdown")
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
@app.post("/api/test-sms")
|
||||
async def test_sms_simple():
|
||||
return {"message": "Test SMS route is working"}
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
if process_pool:
|
||||
process_pool.shutdown()
|
||||
print("ProcessPoolExecutor shutdown")
|
||||
|
||||
# Database connection parameters - Moved to CONFIG
|
||||
|
||||
# 商业领域同义词库 (Business Thesaurus) - 用于解决模糊语义匹配
|
||||
@@ -1548,6 +1551,167 @@ def init_database():
|
||||
conn.close()
|
||||
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
|
||||
|
||||
class FieldAddRequest(BaseModel):
|
||||
"""添加字段请求模型"""
|
||||
table: str # 'ticket' or 'checkin'
|
||||
key: str # 字段标识
|
||||
label: str # 显示名称
|
||||
show: bool = True
|
||||
required: bool = False
|
||||
|
||||
class FieldDeleteRequest(BaseModel):
|
||||
"""删除字段请求模型"""
|
||||
table: str # 'ticket' or 'checkin'
|
||||
key: str # 字段标识
|
||||
|
||||
@app.post("/api/admin/field/add")
|
||||
async def add_field(req: FieldAddRequest):
|
||||
"""
|
||||
添加自定义字段:
|
||||
1. 在数据库表中添加新列
|
||||
2. 在 config.json 中更新字段配置
|
||||
"""
|
||||
global CONFIG
|
||||
|
||||
try:
|
||||
# 确定表名
|
||||
table_name = 'gsdh_data' if req.table == 'ticket' else 'checkin_info'
|
||||
|
||||
# 验证字段标识格式
|
||||
if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', req.key):
|
||||
return JSONResponse(
|
||||
content={"success": False, "message": "字段标识格式不正确(只能包含字母、数字和下划线,不能以数字开头)"},
|
||||
status_code=400
|
||||
)
|
||||
|
||||
# 防止删除锁定字段
|
||||
locked_fields = ['name', 'phone', 'new_id', 'gsdh_id']
|
||||
if req.key.lower() in locked_fields:
|
||||
return JSONResponse(
|
||||
content={"success": False, "message": f"不能添加锁定字段 {req.key}"},
|
||||
status_code=400
|
||||
)
|
||||
|
||||
# 获取当前配置
|
||||
CONFIG = load_config()
|
||||
|
||||
# 获取当前字段配置
|
||||
field_config_key = 'ticket_field_config' if req.table == 'ticket' else 'checkin_field_config'
|
||||
current_fields = CONFIG.get(field_config_key, {})
|
||||
|
||||
# 检查字段是否已存在
|
||||
if req.key in current_fields:
|
||||
return JSONResponse(
|
||||
content={"success": False, "message": f"字段 {req.key} 已存在"},
|
||||
status_code=400
|
||||
)
|
||||
|
||||
# 在数据库中添加列
|
||||
conn = get_db_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
try:
|
||||
# 添加新列(使用 TEXT 类型)
|
||||
cur.execute(f'ALTER TABLE {table_name} ADD COLUMN IF NOT EXISTS {req.key} TEXT')
|
||||
conn.commit()
|
||||
except Exception as db_e:
|
||||
conn.rollback()
|
||||
cur.close()
|
||||
release_db_connection(conn)
|
||||
return JSONResponse(
|
||||
content={"success": False, "message": f"数据库操作失败: {str(db_e)}"},
|
||||
status_code=500
|
||||
)
|
||||
|
||||
cur.close()
|
||||
release_db_connection(conn)
|
||||
|
||||
# 更新配置
|
||||
current_fields[req.key] = {
|
||||
"label": req.label,
|
||||
"show": req.show,
|
||||
"required": req.required
|
||||
}
|
||||
CONFIG[field_config_key] = current_fields
|
||||
save_config(CONFIG)
|
||||
|
||||
return {"success": True, "message": f"字段 '{req.label}' 添加成功"}
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
|
||||
|
||||
@app.post("/api/admin/field/delete")
|
||||
async def delete_field(req: FieldDeleteRequest):
|
||||
"""
|
||||
删除自定义字段:
|
||||
1. 从 config.json 中移除字段配置
|
||||
2. 从数据库表中删除列
|
||||
"""
|
||||
global CONFIG
|
||||
|
||||
try:
|
||||
# 确定表名
|
||||
table_name = 'gsdh_data' if req.table == 'ticket' else 'checkin_info'
|
||||
|
||||
# 防止删除锁定字段
|
||||
locked_fields = ['name', 'phone', 'new_id', 'gsdh_id']
|
||||
if req.key.lower() in locked_fields:
|
||||
return JSONResponse(
|
||||
content={"success": False, "message": f"不能删除锁定字段 {req.key}"},
|
||||
status_code=400
|
||||
)
|
||||
|
||||
# 获取当前配置
|
||||
CONFIG = load_config()
|
||||
|
||||
# 获取当前字段配置
|
||||
field_config_key = 'ticket_field_config' if req.table == 'ticket' else 'checkin_field_config'
|
||||
current_fields = CONFIG.get(field_config_key, {})
|
||||
|
||||
# 检查字段是否存在
|
||||
if req.key not in current_fields:
|
||||
return JSONResponse(
|
||||
content={"success": False, "message": f"字段 {req.key} 不存在"},
|
||||
status_code=400
|
||||
)
|
||||
|
||||
# 获取字段标签(用于返回消息)
|
||||
field_label = current_fields[req.key].get('label', req.key)
|
||||
|
||||
# 从数据库中删除列
|
||||
conn = get_db_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
try:
|
||||
# 删除列
|
||||
cur.execute(f'ALTER TABLE {table_name} DROP COLUMN IF EXISTS {req.key}')
|
||||
conn.commit()
|
||||
except Exception as db_e:
|
||||
conn.rollback()
|
||||
cur.close()
|
||||
release_db_connection(conn)
|
||||
return JSONResponse(
|
||||
content={"success": False, "message": f"数据库操作失败: {str(db_e)}"},
|
||||
status_code=500
|
||||
)
|
||||
|
||||
cur.close()
|
||||
release_db_connection(conn)
|
||||
|
||||
# 更新配置(移除字段)
|
||||
del current_fields[req.key]
|
||||
CONFIG[field_config_key] = current_fields
|
||||
save_config(CONFIG)
|
||||
|
||||
return {"success": True, "message": f"字段 '{field_label}' 已删除"}
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return JSONResponse(content={"success": False, "message": str(e)}, status_code=500)
|
||||
|
||||
# ==========================================
|
||||
# WeChat Pay V3 & Ticket Logic
|
||||
# ==========================================
|
||||
|
||||
Reference in New Issue
Block a user