自定义字段

This commit is contained in:
jeremygan2021
2026-03-26 20:15:10 +08:00
parent cc46eb03cd
commit 1b5faf00cc
4 changed files with 926 additions and 86 deletions

186
main.py
View File

@@ -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
# ==========================================