refactor: 员工同步数据库配置改为环境变量
All checks were successful
continuous-integration/drone/push Build is passing

- 前端隐藏数据库连接配置输入
- 只保留"启用开关"和"表名"配置
- 数据库连接从 EMPLOYEE_SYNC_DB_URL 环境变量读取
- 显示数据源配置状态
- 保留默认值用于向后兼容
This commit is contained in:
yuliang_guo
2026-01-31 17:07:55 +08:00
parent 78e1bb3dc3
commit 07638152fc
3 changed files with 64 additions and 169 deletions

View File

@@ -297,38 +297,27 @@ async def get_employee_sync_config(
获取员工同步配置
仅限管理员访问
数据库连接从环境变量读取,前端只能配置表名和开关
"""
check_admin_permission(current_user)
import os
tenant_id = await get_or_create_tenant_id(db)
# 获取配置
db_host = await get_system_config(db, tenant_id, 'employee_sync', 'DB_HOST')
db_port = await get_system_config(db, tenant_id, 'employee_sync', 'DB_PORT')
db_name = await get_system_config(db, tenant_id, 'employee_sync', 'DB_NAME')
db_user = await get_system_config(db, tenant_id, 'employee_sync', 'DB_USER')
db_password = await get_system_config(db, tenant_id, 'employee_sync', 'DB_PASSWORD')
# 从数据库获取表名和开关配置
table_name = await get_system_config(db, tenant_id, 'employee_sync', 'TABLE_NAME')
enabled = await get_feature_switch(db, tenant_id, 'employee_sync')
# 脱敏处理密码
password_masked = None
if db_password:
if len(db_password) > 4:
password_masked = '****' + db_password[-2:]
else:
password_masked = '****'
# 从环境变量检查数据源是否已配置
sync_db_url = os.environ.get('EMPLOYEE_SYNC_DB_URL', '')
configured = bool(sync_db_url)
return ResponseModel(
message="获取成功",
data={
"db_host": db_host,
"db_port": int(db_port) if db_port else None,
"db_name": db_name,
"db_user": db_user,
"db_password_masked": password_masked,
"table_name": table_name or "v_钉钉员工表",
"enabled": enabled,
"configured": configured, # 数据源是否已在环境变量配置
}
)
@@ -343,27 +332,13 @@ async def update_employee_sync_config(
更新员工同步配置
仅限管理员访问
只能配置表名和开关,数据库连接从环境变量读取
"""
check_admin_permission(current_user)
tenant_id = await get_or_create_tenant_id(db)
try:
if config.db_host is not None:
await set_system_config(db, tenant_id, 'employee_sync', 'DB_HOST', config.db_host)
if config.db_port is not None:
await set_system_config(db, tenant_id, 'employee_sync', 'DB_PORT', str(config.db_port))
if config.db_name is not None:
await set_system_config(db, tenant_id, 'employee_sync', 'DB_NAME', config.db_name)
if config.db_user is not None:
await set_system_config(db, tenant_id, 'employee_sync', 'DB_USER', config.db_user)
if config.db_password is not None:
await set_system_config(db, tenant_id, 'employee_sync', 'DB_PASSWORD', config.db_password)
if config.table_name is not None:
await set_system_config(db, tenant_id, 'employee_sync', 'TABLE_NAME', config.table_name)
@@ -398,32 +373,29 @@ async def test_employee_sync_connection(
测试员工同步数据库连接
仅限管理员访问
使用环境变量中的数据库连接配置
"""
check_admin_permission(current_user)
import os
tenant_id = await get_or_create_tenant_id(db)
# 获取配置
db_host = await get_system_config(db, tenant_id, 'employee_sync', 'DB_HOST')
db_port = await get_system_config(db, tenant_id, 'employee_sync', 'DB_PORT')
db_name = await get_system_config(db, tenant_id, 'employee_sync', 'DB_NAME')
db_user = await get_system_config(db, tenant_id, 'employee_sync', 'DB_USER')
db_password = await get_system_config(db, tenant_id, 'employee_sync', 'DB_PASSWORD')
table_name = await get_system_config(db, tenant_id, 'employee_sync', 'TABLE_NAME') or "v_钉钉员工表"
# 从环境变量获取数据库连接
sync_db_url = os.environ.get('EMPLOYEE_SYNC_DB_URL', '')
if not all([db_host, db_port, db_name, db_user, db_password]):
if not sync_db_url:
return ResponseModel(
code=400,
message="配置不完整,请先填写所有数据库连接信息"
message="数据源未配置,请联系系统管理员配置 EMPLOYEE_SYNC_DB_URL 环境变量"
)
# 获取表名配置
table_name = await get_system_config(db, tenant_id, 'employee_sync', 'TABLE_NAME') or "v_钉钉员工表"
try:
from sqlalchemy.ext.asyncio import create_async_engine
# 构建连接URL
db_url = f"mysql+aiomysql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}?charset=utf8mb4"
engine = create_async_engine(db_url, echo=False, pool_pre_ping=True)
engine = create_async_engine(sync_db_url, echo=False, pool_pre_ping=True)
async with engine.connect() as conn:
# 测试查询员工表
@@ -433,7 +405,7 @@ async def test_employee_sync_connection(
await engine.dispose()
return ResponseModel(
message=f"连接成功!员工表共有 {count}记录",
message=f"连接成功!员工表共有 {count}在职员工",
data={"employee_count": count}
)

View File

@@ -23,8 +23,7 @@ logger = get_logger(__name__)
class EmployeeSyncService:
"""员工同步服务"""
# 默认外部数据库连接配置(向后兼容)
DEFAULT_DB_URL = "mysql+aiomysql://neuron_new:NWxGM6CQoMLKyEszXhfuLBIIo1QbeK@120.77.144.233:29613/neuron_new?charset=utf8mb4"
# 默认外部数据库连接配置(向后兼容,从环境变量读取
DEFAULT_TABLE_NAME = "v_钉钉员工表"
def __init__(self, db: AsyncSession, tenant_id: int = 1):
@@ -34,46 +33,43 @@ class EmployeeSyncService:
self.table_name = self.DEFAULT_TABLE_NAME
self._db_url = None
async def _get_config_from_db(self) -> tuple:
"""从数据库获取员工同步配置"""
result = await self.db.execute(
text("""
SELECT config_key, config_value
FROM tenant_configs
WHERE tenant_id = :tenant_id AND config_group = 'employee_sync'
"""),
{"tenant_id": self.tenant_id}
)
rows = result.fetchall()
config = {}
for key, value in rows:
config[key] = value
return config
async def _get_table_name_from_db(self) -> str:
"""从数据库获取员工表名配置"""
try:
result = await self.db.execute(
text("""
SELECT config_value
FROM tenant_configs
WHERE tenant_id = :tenant_id
AND config_group = 'employee_sync'
AND config_key = 'TABLE_NAME'
"""),
{"tenant_id": self.tenant_id}
)
row = result.fetchone()
return row[0] if row else self.DEFAULT_TABLE_NAME
except Exception:
return self.DEFAULT_TABLE_NAME
async def _build_db_url(self) -> str:
"""构建数据库连接URL"""
config = await self._get_config_from_db()
def _get_db_url_from_env(self) -> str:
"""从环境变量获取数据库连接URL"""
import os
db_host = config.get('DB_HOST')
db_port = config.get('DB_PORT')
db_name = config.get('DB_NAME')
db_user = config.get('DB_USER')
db_password = config.get('DB_PASSWORD')
self.table_name = config.get('TABLE_NAME') or self.DEFAULT_TABLE_NAME
# 优先使用环境变量中的完整URL
db_url = os.environ.get('EMPLOYEE_SYNC_DB_URL', '')
# 如果配置完整使用配置的URL
if all([db_host, db_port, db_name, db_user, db_password]):
return f"mysql+aiomysql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}?charset=utf8mb4"
if db_url:
return db_url
# 否则使用默认配置
logger.warning(f"租户 {self.tenant_id} 未配置员工同步数据库,使用默认配置")
return self.DEFAULT_DB_URL
# 向后兼容:如果没有配置环境变量,使用默认
logger.warning("EMPLOYEE_SYNC_DB_URL 环境变量未配置,使用默认数据源")
return "mysql+aiomysql://neuron_new:NWxGM6CQoMLKyEszXhfuLBIIo1QbeK@120.77.144.233:29613/neuron_new?charset=utf8mb4"
async def __aenter__(self):
"""异步上下文管理器入口"""
self._db_url = await self._build_db_url()
self._db_url = self._get_db_url_from_env()
self.table_name = await self._get_table_name_from_db()
self.external_engine = create_async_engine(
self._db_url,
echo=False,