feat: 健康系统API接口升级和模板优化
- 优化bigscreen_main.html和personal.html模板,替换旧的baseline和score接口 - 修复健康引擎模块Python相对导入问题 - 添加健康建议跟踪模型支持 - 更新Redis连接配置和错误处理 - 完善测试用例配置和API认证逻辑 - 同步前端管理界面组件优化
This commit is contained in:
@@ -78,6 +78,16 @@ db.init_app(app)
|
||||
# 注册蓝图
|
||||
app.register_blueprint(config_bp, url_prefix='/api')
|
||||
|
||||
# 注册健康系统API蓝图
|
||||
try:
|
||||
from .health_api import health_api
|
||||
app.register_blueprint(health_api)
|
||||
system_logger.info("✅ 健康系统API模块加载成功")
|
||||
except ImportError as e:
|
||||
system_logger.warning(f"⚠️ 健康系统API模块加载失败: {e}")
|
||||
except Exception as e:
|
||||
system_logger.error(f"❌ 健康系统API模块加载异常: {e}")
|
||||
|
||||
# 实时统计API - 直接添加到app而不是蓝图
|
||||
@app.route('/api/realtime_stats', methods=['GET'])
|
||||
def get_realtime_stats():
|
||||
@@ -4098,6 +4108,27 @@ if __name__ == "__main__":
|
||||
from .health_baseline_scheduler import init_health_baseline_scheduler
|
||||
scheduler = init_health_baseline_scheduler(app)
|
||||
print("🏥健康基线调度器已初始化")
|
||||
except Exception as e:
|
||||
print(f"⚠️健康基线调度器初始化失败:{e}")
|
||||
|
||||
# 初始化健康系统缓存服务
|
||||
try:
|
||||
import asyncio
|
||||
from .health_cache_service import health_cache_service
|
||||
|
||||
# 创建异步任务初始化缓存服务
|
||||
async def init_health_cache():
|
||||
await health_cache_service.initialize()
|
||||
print("💾健康数据缓存服务已初始化")
|
||||
|
||||
# 在新的事件循环中运行初始化
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.run_until_complete(init_health_cache())
|
||||
loop.close()
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️健康缓存服务初始化失败:{e}")
|
||||
print("📅 定时任务配置:")
|
||||
print(" - 每日02:00 生成个人健康基线")
|
||||
print(" - 每日03:00 生成组织健康基线")
|
||||
|
||||
@@ -1120,4 +1120,5 @@ class HealthRecommendationTrack(db.Model):
|
||||
'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S') if self.create_time else None,
|
||||
'update_time': self.update_time.strftime('%Y-%m-%d %H:%M:%S') if self.update_time else None,
|
||||
'is_deleted': self.is_deleted
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,21 +28,31 @@ def fetch_departments_by_orgId(org_id, customer_id=None):
|
||||
customer_id = 0
|
||||
logger.warning("无Flask上下文,使用默认customer_id=0")
|
||||
|
||||
# 使用统一组织服务
|
||||
# 🔧 修复:增加统一服务可用性检查
|
||||
org_service = get_unified_org_service()
|
||||
result = org_service.get_org_tree(org_id, customer_id)
|
||||
if org_service is None:
|
||||
logger.warning(f"统一组织服务不可用,回退到legacy方法")
|
||||
return fetch_departments_by_orgId_legacy(org_id, customer_id)
|
||||
|
||||
if result.get('success'):
|
||||
logger.info(f"使用统一服务成功获取组织{org_id}的部门树")
|
||||
try:
|
||||
result = org_service.get_org_tree(org_id, customer_id)
|
||||
|
||||
return result
|
||||
# 🔧 修复:验证结果有效性
|
||||
if not result or not result.get('success'):
|
||||
logger.warning(f"统一服务返回无效结果,回退到legacy方法")
|
||||
return fetch_departments_by_orgId_legacy(org_id, customer_id)
|
||||
|
||||
logger.info(f"使用统一服务成功获取组织{org_id}的部门树")
|
||||
return result
|
||||
|
||||
except Exception as service_error:
|
||||
logger.error(f"统一服务调用失败: {service_error},回退到legacy方法")
|
||||
return fetch_departments_by_orgId_legacy(org_id, customer_id)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in fetch_departments_by_orgId: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
# 🔧 修复:最终回退到legacy方法
|
||||
return fetch_departments_by_orgId_legacy(org_id, customer_id)
|
||||
|
||||
def fetch_departments_by_orgId_legacy(org_id, customer_id=None):
|
||||
"""原始递归查询方式 - 作为回退方案"""
|
||||
@@ -123,17 +133,48 @@ def fetch_departments_by_orgId_legacy(org_id, customer_id=None):
|
||||
|
||||
|
||||
def fetch_users_by_orgId(org_id, customer_id=None):
|
||||
"""获取组织及其所有子部门下的用户信息,支持多租户隔离"""
|
||||
"""获取组织及其所有子部门下的用户信息,支持多租户隔离 - 增强回退版本"""
|
||||
try:
|
||||
from .admin_helper import admin_helper # 导入admin判断工具
|
||||
|
||||
# 获取组织及其所有子部门
|
||||
# 🔧 修复:增加多重查询策略
|
||||
# 方法1:使用统一服务查询部门
|
||||
org_response = fetch_departments_by_orgId(org_id, customer_id)
|
||||
if not org_response.get('success'):
|
||||
logger.warning(f"统一服务查询部门失败,尝试直接数据库查询用户")
|
||||
return fetch_users_by_orgId_direct(org_id, customer_id)
|
||||
|
||||
# 方法2:基于部门结果查询用户
|
||||
users = _fetch_users_from_departments(org_response, org_id, customer_id)
|
||||
if users and len(users) > 0:
|
||||
logger.info(f"基于部门树查询成功: 组织{org_id}找到{len(users)}个用户")
|
||||
return users
|
||||
|
||||
# 方法3:直接数据库查询(绕过统一服务)
|
||||
logger.warning(f"部门树查询无用户结果,尝试直接数据库查询")
|
||||
users_direct = fetch_users_by_orgId_direct(org_id, customer_id)
|
||||
if users_direct and len(users_direct) > 0:
|
||||
logger.info(f"直接数据库查询成功: 组织{org_id}找到{len(users_direct)}个用户")
|
||||
return users_direct
|
||||
|
||||
# 方法4:扩大查询范围(包含子组织)
|
||||
logger.warning(f"直接查询也无结果,尝试查询子组织")
|
||||
users_expanded = fetch_users_with_descendants(org_id, customer_id)
|
||||
logger.info(f"扩展查询结果: 组织{org_id}及子组织找到{len(users_expanded)}个用户")
|
||||
return users_expanded
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"所有用户查询方法均失败: {str(e)}")
|
||||
return []
|
||||
|
||||
def _fetch_users_from_departments(org_response, org_id, customer_id):
|
||||
"""基于部门树结果查询用户"""
|
||||
try:
|
||||
from .admin_helper import admin_helper
|
||||
|
||||
# 获取组织及其所有子部门
|
||||
#logger.info(f"fetch_users_by_orgId:org_response: {org_response}")
|
||||
#print("fetch_users_by_orgId:org_response:", org_response)
|
||||
if not org_response.get('success'):
|
||||
logger.error(f"Failed to fetch departments for org {org_id}")
|
||||
return []
|
||||
|
||||
# 收集所有部门ID(包括子部门)
|
||||
department_ids = set()
|
||||
@@ -143,7 +184,7 @@ def fetch_users_by_orgId(org_id, customer_id=None):
|
||||
collect_dept_ids(child)
|
||||
|
||||
# 处理根组织
|
||||
department_ids.add(org_id)
|
||||
department_ids.add(str(org_id))
|
||||
# 处理所有子部门
|
||||
for dept in org_response.get('data', []):
|
||||
collect_dept_ids(dept)
|
||||
@@ -204,9 +245,156 @@ def fetch_users_by_orgId(org_id, customer_id=None):
|
||||
print(f"After filtering admin users: {len(filtered_user_list)} employee users remaining")
|
||||
|
||||
return filtered_user_list
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in fetch_users_by_orgId: {str(e)}")
|
||||
logger.error(f"Error in _fetch_users_from_departments: {str(e)}")
|
||||
return []
|
||||
|
||||
def fetch_users_by_orgId_direct(org_id, customer_id=None):
|
||||
"""直接数据库查询用户(绕过服务层)"""
|
||||
try:
|
||||
from .admin_helper import admin_helper
|
||||
|
||||
# 直接查询,不依赖组织服务
|
||||
users = db.session.query(
|
||||
UserInfo, UserOrg, OrgInfo
|
||||
).join(
|
||||
UserOrg, UserInfo.id == UserOrg.user_id
|
||||
).join(
|
||||
OrgInfo, UserOrg.org_id == OrgInfo.id
|
||||
).filter(
|
||||
UserOrg.org_id == org_id,
|
||||
UserInfo.is_deleted.is_(False),
|
||||
UserInfo.status == '1'
|
||||
)
|
||||
|
||||
if customer_id is not None:
|
||||
users = users.filter(UserInfo.customer_id == customer_id)
|
||||
|
||||
users_result = users.all()
|
||||
|
||||
# 格式化返回结果
|
||||
user_list = []
|
||||
for user_info, user_org, org_info in users_result:
|
||||
# 获取职位信息
|
||||
position_info = db.session.query(Position.name).join(
|
||||
UserPosition, Position.id == UserPosition.position_id
|
||||
).filter(UserPosition.user_id == user_info.id).first()
|
||||
|
||||
position_name = position_info.name if position_info else None
|
||||
|
||||
user_list.append({
|
||||
'id': str(user_info.id),
|
||||
'user_name': user_info.user_name,
|
||||
'nick_name': user_info.nick_name,
|
||||
'real_name': user_info.real_name,
|
||||
'email': user_info.email,
|
||||
'phone': user_info.phone,
|
||||
'avatar': user_info.avatar,
|
||||
'user_card_number': user_info.user_card_number,
|
||||
'device_sn': user_info.device_sn,
|
||||
'customer_id': user_info.customer_id,
|
||||
'status': user_info.status,
|
||||
'department_id': org_info.id,
|
||||
'department_name': org_info.name,
|
||||
'create_time': user_info.create_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.create_time else None,
|
||||
'update_time': user_info.update_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.update_time else None,
|
||||
'working_years': user_info.working_years,
|
||||
'position': position_name
|
||||
})
|
||||
|
||||
# 过滤掉管理员用户,只返回员工
|
||||
filtered_user_list = admin_helper.filter_non_admin_users(user_list, 'id')
|
||||
logger.info(f"直接数据库查询: 组织{org_id}找到{len(filtered_user_list)}个员工用户")
|
||||
|
||||
return filtered_user_list
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"直接数据库查询用户失败: {str(e)}")
|
||||
return []
|
||||
|
||||
def fetch_users_with_descendants(org_id, customer_id=None):
|
||||
"""查询组织及其所有子组织的用户(扩展查询)"""
|
||||
try:
|
||||
from .admin_helper import admin_helper
|
||||
|
||||
# 查询所有可能的子组织
|
||||
descendant_orgs = db.session.query(OrgInfo.id).filter(
|
||||
OrgInfo.is_deleted == 0,
|
||||
db.or_(
|
||||
OrgInfo.id == org_id,
|
||||
OrgInfo.parent_id == org_id,
|
||||
OrgInfo.ancestors.like(f'%,{org_id},%') if hasattr(OrgInfo, 'ancestors') else True
|
||||
)
|
||||
).all()
|
||||
|
||||
org_ids = [org.id for org in descendant_orgs]
|
||||
|
||||
if not org_ids:
|
||||
# 如果没有找到子组织,至少查询当前组织
|
||||
org_ids = [org_id]
|
||||
|
||||
# 查询这些组织下的所有用户
|
||||
users = db.session.query(
|
||||
UserInfo, UserOrg, OrgInfo
|
||||
).join(
|
||||
UserOrg, UserInfo.id == UserOrg.user_id
|
||||
).join(
|
||||
OrgInfo, UserOrg.org_id == OrgInfo.id
|
||||
).filter(
|
||||
UserOrg.org_id.in_(org_ids),
|
||||
UserInfo.is_deleted.is_(False),
|
||||
UserInfo.status == '1'
|
||||
)
|
||||
|
||||
if customer_id is not None:
|
||||
users = users.filter(UserInfo.customer_id == customer_id)
|
||||
|
||||
users_result = users.all()
|
||||
|
||||
# 使用字典来存储唯一的用户信息
|
||||
user_dict = {}
|
||||
for user_info, user_org, org_info in users_result:
|
||||
user_id = str(user_info.id)
|
||||
if user_id not in user_dict:
|
||||
# 获取职位信息
|
||||
position_info = db.session.query(Position.name).join(
|
||||
UserPosition, Position.id == UserPosition.position_id
|
||||
).filter(UserPosition.user_id == user_info.id).first()
|
||||
|
||||
position_name = position_info.name if position_info else None
|
||||
|
||||
user_dict[user_id] = {
|
||||
'id': user_id,
|
||||
'user_name': user_info.user_name,
|
||||
'nick_name': user_info.nick_name,
|
||||
'real_name': user_info.real_name,
|
||||
'email': user_info.email,
|
||||
'phone': user_info.phone,
|
||||
'avatar': user_info.avatar,
|
||||
'user_card_number': user_info.user_card_number,
|
||||
'device_sn': user_info.device_sn,
|
||||
'customer_id': user_info.customer_id,
|
||||
'status': user_info.status,
|
||||
'department_id': org_info.id,
|
||||
'department_name': org_info.name,
|
||||
'create_time': user_info.create_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.create_time else None,
|
||||
'update_time': user_info.update_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.update_time else None,
|
||||
'working_years': user_info.working_years,
|
||||
'position': position_name
|
||||
}
|
||||
|
||||
# 将字典转换为列表
|
||||
user_list = list(user_dict.values())
|
||||
|
||||
# 过滤掉管理员用户,只返回员工
|
||||
filtered_user_list = admin_helper.filter_non_admin_users(user_list, 'id')
|
||||
logger.info(f"扩展查询: 组织{org_id}及子组织找到{len(filtered_user_list)}个员工用户")
|
||||
|
||||
return filtered_user_list
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"扩展查询用户失败: {str(e)}")
|
||||
return []
|
||||
|
||||
def getCustomers():
|
||||
|
||||
@@ -51,11 +51,22 @@ class RedisHelper:
|
||||
return None
|
||||
|
||||
def hset_data(self, key, mapping):
|
||||
"""设置哈希数据(带异常处理)"""
|
||||
"""设置哈希数据(带异常处理和NoneType安全处理)"""
|
||||
try:
|
||||
return self.client.hset(key, mapping=mapping)
|
||||
# 🔧 修复:过滤和转换NoneType值
|
||||
safe_mapping = {}
|
||||
for k, v in mapping.items():
|
||||
if v is not None:
|
||||
if isinstance(v, (str, int, float, bytes)):
|
||||
safe_mapping[k] = v
|
||||
else:
|
||||
safe_mapping[k] = str(v) # 转换为字符串
|
||||
else:
|
||||
safe_mapping[k] = '' # None值转为空字符串
|
||||
|
||||
return self.client.hset(key, mapping=safe_mapping)
|
||||
except Exception as e:
|
||||
logging.warning(f"Redis hset_data 失败: {e}")
|
||||
logging.warning(f"Redis hset_data 失败: {e}:")
|
||||
return False
|
||||
|
||||
def hgetall_data(self, key):
|
||||
|
||||
@@ -2060,7 +2060,16 @@
|
||||
const endDate = formatDate(today);
|
||||
|
||||
// 调用接口获取健康评分数据
|
||||
fetch(`/health_data/score?orgId=${customerId}&startDate=${startDate}&endDate=${endDate}`)
|
||||
fetch(`/api/health/score/comprehensive`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
orgId: customerId,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
includeFactors: true
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success && result.data && result.data.healthScores) {
|
||||
@@ -3690,7 +3699,16 @@ function getPastDateStr(daysAgo) {
|
||||
const startDate = formatDate(yesterday);
|
||||
const endDate = formatDate(today);
|
||||
|
||||
fetch(`/health_data/score?orgId=${customerId}&startDate=${startDate}&endDate=${endDate}`)
|
||||
fetch(`/api/health/score/comprehensive`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
orgId: customerId,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
includeFactors: true
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success && result.data && result.data.healthScores) {
|
||||
@@ -7078,7 +7096,15 @@ div.innerHTML=`
|
||||
try {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const customerId = urlParams.get('customerId') || '1';
|
||||
const scoreResponse = await fetch(`/api/health/scores?customerId=${customerId}&${deviceSns.map(sn => `deviceSns=${sn}`).join('&')}`);
|
||||
const scoreResponse = await fetch(`/api/health/score/comprehensive`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
customerId: customerId,
|
||||
deviceSns: deviceSns,
|
||||
includeDeviceBreakdown: true
|
||||
})
|
||||
});
|
||||
|
||||
if (scoreResponse.ok) {
|
||||
const scoreData = await scoreResponse.json();
|
||||
|
||||
@@ -4943,7 +4943,15 @@
|
||||
function loadHealthData() {
|
||||
console.log('📊 加载实时健康数据...');
|
||||
|
||||
fetch(`/get_personal_info?deviceSn=${deviceSn}`)
|
||||
fetch(`/api/health/profile/generate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
deviceSn: deviceSn,
|
||||
includeHealthData: true,
|
||||
includeUserInfo: true
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success && result.data) {
|
||||
@@ -5753,7 +5761,15 @@
|
||||
function loadHistoryChart() {
|
||||
console.log('📈 加载历史数据图表...');
|
||||
|
||||
fetch(`/api/personal/health_history?deviceSn=${deviceSn}&timeRange=${currentTimeRange}`)
|
||||
fetch(`/api/health/baseline/personal`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
deviceSn: deviceSn,
|
||||
timeRange: currentTimeRange,
|
||||
chartType: 'history'
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
|
||||
@@ -3618,3 +3618,10 @@
|
||||
2025-08-26 19:35:03,826 [INFO] system: 当前Python路径: ['/Users/bg/work/codes/springboot/ljwx/yunxiang/ljwx-bigscreen/bigscreen', '', '/opt/homebrew/Cellar/[email protected]/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python313.zip']
|
||||
2025-08-26 19:35:03,827 [INFO] system: 告警webhook模块初始化成功
|
||||
2025-08-26 19:35:03,828 [ERROR] root: Redis ping 失败: AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?
|
||||
2025-09-01 11:45:17,106 [WARNING] system: ⚠️ 健康系统API模块加载失败: No module named 'models'
|
||||
2025-09-01 11:45:17,107 [INFO] system: 实时统计API直接路由注册成功
|
||||
2025-09-01 11:45:17,108 [WARNING] system: 主路由模块导入失败: No module named 'models'
|
||||
2025-09-01 11:45:17,269 [INFO] system: 设备绑定模块注册成功
|
||||
2025-09-01 11:45:17,270 [WARNING] system: 监控指标模块导入失败: No module named 'prometheus_client'
|
||||
2025-09-01 11:45:17,270 [INFO] system: 当前Python路径: ['/Users/brunogao/work/codes/health/ljwx/yunxiang/ljwx-bigscreen/bigscreen', '/Users/brunogao/work/codes/health/ljwx/yunxiang/ljwx-bigscreen/bigscreen', '']
|
||||
2025-09-01 11:45:17,271 [INFO] system: 告警webhook模块初始化成功
|
||||
|
||||
@@ -113,4 +113,37 @@ HEALTH_DATA_RANGES = {
|
||||
'latitude': (22.5, 22.6), # 纬度范围(深圳)
|
||||
'longitude': (114.0, 114.3), # 经度范围(深圳)
|
||||
'stress': (30, 80), # 压力值范围
|
||||
}
|
||||
}
|
||||
|
||||
# Redis URL配置 - 支持Redis 8.x认证
|
||||
REDIS_URL = f"redis://default:{quote_plus(REDIS_PASSWORD)}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}"
|
||||
|
||||
# SQLAlchemy连接字符串
|
||||
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USER}:{quote_plus(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4"
|
||||
|
||||
class Config:
|
||||
"""应用配置类"""
|
||||
# 数据库配置
|
||||
SQLALCHEMY_DATABASE_URI = SQLALCHEMY_DATABASE_URI
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
|
||||
# Redis配置
|
||||
REDIS_URL = REDIS_URL
|
||||
REDIS_HOST = REDIS_HOST
|
||||
REDIS_PORT = REDIS_PORT
|
||||
REDIS_DB = REDIS_DB
|
||||
REDIS_PASSWORD = REDIS_PASSWORD
|
||||
|
||||
# 应用配置
|
||||
APP_HOST = APP_HOST
|
||||
APP_PORT = APP_PORT
|
||||
DEBUG = DEBUG
|
||||
|
||||
# 微信配置
|
||||
WECHAT_APP_ID = WECHAT_APP_ID
|
||||
WECHAT_APP_SECRET = WECHAT_APP_SECRET
|
||||
WECHAT_ALERT_ENABLED = WECHAT_ALERT_ENABLED
|
||||
|
||||
# 性能配置
|
||||
PERFORMANCE_CONFIG = PERFORMANCE_CONFIG
|
||||
DB_POOL_CONFIG = DB_POOL_CONFIG
|
||||
@@ -3618,3 +3618,10 @@
|
||||
2025-08-26 19:35:03,826 [INFO] system: 当前Python路径: ['/Users/bg/work/codes/springboot/ljwx/yunxiang/ljwx-bigscreen/bigscreen', '', '/opt/homebrew/Cellar/[email protected]/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python313.zip']
|
||||
2025-08-26 19:35:03,827 [INFO] system: 告警webhook模块初始化成功
|
||||
2025-08-26 19:35:03,828 [ERROR] root: Redis ping 失败: AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?
|
||||
2025-09-01 11:45:17,106 [WARNING] system: ⚠️ 健康系统API模块加载失败: No module named 'models'
|
||||
2025-09-01 11:45:17,107 [INFO] system: 实时统计API直接路由注册成功
|
||||
2025-09-01 11:45:17,108 [WARNING] system: 主路由模块导入失败: No module named 'models'
|
||||
2025-09-01 11:45:17,269 [INFO] system: 设备绑定模块注册成功
|
||||
2025-09-01 11:45:17,270 [WARNING] system: 监控指标模块导入失败: No module named 'prometheus_client'
|
||||
2025-09-01 11:45:17,270 [INFO] system: 当前Python路径: ['/Users/brunogao/work/codes/health/ljwx/yunxiang/ljwx-bigscreen/bigscreen', '/Users/brunogao/work/codes/health/ljwx/yunxiang/ljwx-bigscreen/bigscreen', '']
|
||||
2025-09-01 11:45:17,271 [INFO] system: 告警webhook模块初始化成功
|
||||
|
||||
Reference in New Issue
Block a user