## Sprint 9 Implementation (100% Complete) ### New Features 1. **Behavioral Recommendation Engine** - Priority scoring algorithm: (Severity × 0.5) + (Feasibility × 0.3) + (User Attention × 0.2) - 4 recommendation strategies: Exercise, Sleep, Diet, Attention - Top 5 prioritized recommendations per user - Automatic behavioral profile generation (scheduled daily 03:30) 2. **Trend Analysis System** - 30-day trend analysis with linear regression - Trend classification: IMPROVING/STABLE/DECLINING - Time series data extraction for visualization - Milestone identification (best/worst dates) ### New APIs (6 endpoints) - POST /api/health/behavioral-recommendations/generate - GET /api/health/behavioral-recommendations/query - POST /api/health/behavioral-recommendations/batch-generate - GET /api/health/behavioral-trends/query ### Deliverables - 20 new files: 4 DTOs, 5 strategies, 3 services, 3 controllers, 5 test files - 3,800+ lines of production code - 62+ unit test cases, 10 integration test cases - Architecture documentation (450 lines) - Sprint 9 completion summary (700+ lines) ## Compilation Fixes (Pre-existing Code) ### Fixed Errors 1. **Java 11+ Compatibility** - Replaced deprecated @Resource with @Autowired (8 files) - Fixed javax.annotation.Resource → org.springframework.beans.factory.annotation.Autowired 2. **Import Path Corrections** - Fixed SysUserMapper path: com.ljwx.modules.system.mapper → com.ljwx.modules.system.repository.mapper - Fixed SysUser entity path: com.ljwx.modules.system.entity → com.ljwx.modules.system.domain.entity 3. **Result API Alignment** - Fixed Result.ok() method calls in RiskProfileController - Updated import: com.ljwx.common.api.Result → com.ljwx.common.api.vo.Result - Aligned Sprint 9 controllers with correct Result API 4. **User Entity Field Mapping** - Calculated age from birthday instead of using non-existent getAge() - Used position field instead of non-existent getPositionType() 5. **Dependency Injection** - Added BehavioralProfileService as @Autowired field in HealthBaselineScoreTasks - Removed manual bean lookup via non-existent ApplicationContextProvider ### Modified Files (Compilation Fixes) - RiskProfileService.java - RiskProfileController.java - RiskProfileServiceTest.java - CardiovascularRiskAssessor.java - RespiratoryRiskAssessor.java - SleepRiskAssessor.java - ExerciseRiskAssessor.java - RiskTrendAnalysisService.java - HealthBaselineScoreTasks.java - BehavioralProfileController.java - BehavioralRecommendationController.java - BehavioralTrendController.java ## Test Results - ✅ Compilation: SUCCESS (Java 21) - ✅ Application: Started successfully on port 9998 - ✅ OpenAPI: Exported (458 endpoints, 550 schemas) ## Reference - Sprint 9 Summary: docs/02-architecture/sprint9-completion-summary.md - Architecture Doc: docs/02-architecture/phase2-behavioral-recommendation-architecture.md Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
234 lines
6.1 KiB
JavaScript
234 lines
6.1 KiB
JavaScript
// ============================================
|
|
// LJWX BigScreen - 应用初始化模块
|
|
// 从 main.html 提取 (Phase 7 优化)
|
|
// ============================================
|
|
|
|
/**
|
|
* 应用初始化管理器
|
|
* 统一管理所有事件监听器和初始化流程
|
|
*/
|
|
const AppInitializer = {
|
|
// 初始化标志
|
|
initialized: false,
|
|
|
|
// 全局变量引用
|
|
globalCharts: null,
|
|
currentDept: '',
|
|
currentUser: '',
|
|
|
|
/**
|
|
* 主初始化函数
|
|
* 在 DOMContentLoaded 事件中调用
|
|
*/
|
|
init() {
|
|
if (this.initialized) {
|
|
console.warn('⚠️ AppInitializer 已经初始化,跳过重复初始化');
|
|
return;
|
|
}
|
|
|
|
console.log('🚀 开始应用初始化...');
|
|
|
|
// 1. 初始化租户信息
|
|
this.initTenantInfo();
|
|
|
|
// 2. 初始化筛选面板
|
|
this.initFilterPanel();
|
|
|
|
// 3. 初始化日期选择器
|
|
this.initDatePicker();
|
|
|
|
// 4. 初始化健康卡片
|
|
this.initHealthCards();
|
|
|
|
// 5. 延迟初始化图表和数据
|
|
setTimeout(() => {
|
|
this.initChartsAndData();
|
|
}, 100);
|
|
|
|
// 6. 绑定全局事件
|
|
this.bindGlobalEvents();
|
|
|
|
this.initialized = true;
|
|
console.log('✅ 应用初始化完成');
|
|
},
|
|
|
|
/**
|
|
* 初始化租户信息显示
|
|
*/
|
|
initTenantInfo() {
|
|
const tenantIdElement = document.getElementById('tenantId');
|
|
if (tenantIdElement && window.GLOBAL_CUSTOMER_ID) {
|
|
tenantIdElement.textContent = window.GLOBAL_CUSTOMER_ID;
|
|
console.log('✅ 租户信息初始化完成:', window.GLOBAL_CUSTOMER_ID);
|
|
}
|
|
|
|
// 调用全局初始化租户信息函数(如果存在)
|
|
if (typeof window.initializeTenantInfo === 'function') {
|
|
window.initializeTenantInfo();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 初始化筛选面板
|
|
*/
|
|
initFilterPanel() {
|
|
const filterToggle = document.getElementById('filterToggle');
|
|
if (filterToggle && typeof window.toggleFilter === 'function') {
|
|
filterToggle.addEventListener('click', window.toggleFilter);
|
|
console.log('✅ 筛选面板初始化完成');
|
|
}
|
|
|
|
// 初始化搜索筛选器
|
|
if (typeof window.initSearchFilter === 'function') {
|
|
window.initSearchFilter();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 初始化日期选择器
|
|
*/
|
|
initDatePicker() {
|
|
if (typeof window.initStatsDatePicker === 'function') {
|
|
window.initStatsDatePicker();
|
|
console.log('✅ 日期选择器初始化完成');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 初始化健康卡片
|
|
*/
|
|
initHealthCards() {
|
|
if (typeof window.initializeHealthCards === 'function') {
|
|
window.initializeHealthCards();
|
|
console.log('✅ 健康卡片初始化完成');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 初始化图表和数据
|
|
*/
|
|
initChartsAndData() {
|
|
console.log('📊 开始初始化图表和数据...');
|
|
|
|
// 1. 初始化图表
|
|
if (typeof window.initCharts === 'function') {
|
|
this.globalCharts = window.initCharts();
|
|
window.globalCharts = this.globalCharts; // 暴露到全局
|
|
console.log('✅ 图表初始化完成');
|
|
}
|
|
|
|
// 2. 初始化地图(延迟执行,避免阻塞)
|
|
setTimeout(() => {
|
|
this.initMap();
|
|
}, 200);
|
|
|
|
// 3. 等待地图初始化后刷新数据
|
|
setTimeout(() => {
|
|
this.refreshData();
|
|
|
|
// 4. 设置定时刷新(每60秒)
|
|
setInterval(() => {
|
|
if (typeof window.refreshData === 'function') {
|
|
window.refreshData();
|
|
}
|
|
}, 60000);
|
|
|
|
console.log('✅ 定时数据刷新已启动(60秒间隔)');
|
|
}, 1500);
|
|
},
|
|
|
|
/**
|
|
* 初始化地图
|
|
*/
|
|
initMap() {
|
|
console.log('🗺️ 开始初始化地图...');
|
|
|
|
if (typeof window.initializeMap === 'function') {
|
|
try {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const userId = urlParams.get('userId') || null;
|
|
window.initializeMap(window.GLOBAL_CUSTOMER_ID, userId);
|
|
console.log('✅ 地图初始化完成');
|
|
} catch (error) {
|
|
console.error('❌ 地图初始化失败:', error);
|
|
}
|
|
} else {
|
|
console.warn('⚠️ initializeMap 函数未定义,跳过地图初始化');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 刷新数据
|
|
*/
|
|
refreshData() {
|
|
if (typeof window.refreshData === 'function') {
|
|
window.refreshData();
|
|
console.log('✅ 初始数据加载完成');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 绑定全局事件
|
|
*/
|
|
bindGlobalEvents() {
|
|
// 1. 全局点击事件 - 筛选面板自动收起
|
|
document.addEventListener('click', (event) => {
|
|
const filterPanel = document.querySelector('.filter-panel');
|
|
const filterToggle = document.querySelector('.filter-toggle');
|
|
|
|
if (filterPanel && filterToggle) {
|
|
// 如果点击的不是筛选面板内的元素且面板是展开的
|
|
if (!filterPanel.contains(event.target) &&
|
|
!filterToggle.contains(event.target) &&
|
|
filterPanel.classList.contains('expanded')) {
|
|
if (typeof window.toggleFilter === 'function') {
|
|
window.toggleFilter();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// 2. 阻止筛选面板内的点击事件冒泡
|
|
const filterPanel = document.querySelector('.filter-panel');
|
|
if (filterPanel) {
|
|
filterPanel.addEventListener('click', (event) => {
|
|
event.stopPropagation();
|
|
});
|
|
}
|
|
|
|
// 3. 快捷键 - Ctrl+I 切换信息面板
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'i' && e.ctrlKey) {
|
|
if (typeof window.toggleInfoPanel === 'function') {
|
|
window.toggleInfoPanel();
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log('✅ 全局事件绑定完成');
|
|
},
|
|
|
|
/**
|
|
* 获取全局图表实例
|
|
*/
|
|
getGlobalCharts() {
|
|
return this.globalCharts;
|
|
}
|
|
};
|
|
|
|
// ============================================
|
|
// 自动初始化
|
|
// ============================================
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
AppInitializer.init();
|
|
});
|
|
|
|
// ============================================
|
|
// 模块导出 - 暴露到全局作用域
|
|
// ============================================
|
|
window.AppInitializer = AppInitializer;
|
|
|
|
// 设置模块加载完成标志
|
|
window.appInitializerModuleLoaded = true;
|
|
console.log('✅ app-initializer.js 应用初始化模块加载完成');
|