Bläddra i källkod

[BI] 自助BI看板集成 - 支持Superset和Metabase

- 新增BISupersetMetabaseService接口及实现
- 支持连接Superset和Metabase服务器
- 提供数据集、图表、仪表盘创建API
- 新增BISupersetMetabaseController REST接口
- 扩展DataVisualizationService支持BI工具集成
- 更新BIDashboard实体支持外部工具集成
- 实现自助服务看板创建功能
- 支持图表导出功能

Issue #37: [BI] 自助BI看板(Superset/Metabase集成)
bot_dev1 4 dagar sedan
förälder
incheckning
8f6e73ecbd

+ 261
- 0
wm-bi/src/main/java/com/water/bi/controller/BISupersetMetabaseController.java Visa fil

@@ -0,0 +1,261 @@
1
+package com.water.bi.controller;
2
+
3
+import com.water.bi.service.BISupersetMetabaseService;
4
+import org.springframework.beans.factory.annotation.Autowired;
5
+import org.springframework.http.ResponseEntity;
6
+import org.springframework.web.bind.annotation.*;
7
+
8
+import java.util.*;
9
+
10
+/**
11
+ * BI工具集成控制器 - 支持Superset和Metabase集成API
12
+ */
13
+@RestController
14
+@RequestMapping("/api/bi/integration")
15
+@CrossOrigin(origins = "*")
16
+public class BISupersetMetabaseController {
17
+    
18
+    @Autowired
19
+    private BISupersetMetabaseService biSupersetMetabaseService;
20
+    
21
+    /**
22
+     * 连接到Superset服务器
23
+     */
24
+    @PostMapping("/superset/connect")
25
+    public ResponseEntity<Map<String, Object>> connectToSuperset(
26
+            @RequestParam String url,
27
+            @RequestParam String username,
28
+            @RequestParam String password) {
29
+        
30
+        try {
31
+            String connectionId = biSupersetMetabaseService.connectToSuperset(url, username, password);
32
+            
33
+            Map<String, Object> response = new HashMap<>();
34
+            response.put("success", true);
35
+            response.put("message", "成功连接到Superset服务器");
36
+            response.put("connectionId", connectionId);
37
+            response.put("url", url);
38
+            
39
+            return ResponseEntity.ok(response);
40
+        } catch (Exception e) {
41
+            Map<String, Object> response = new HashMap<>();
42
+            response.put("success", false);
43
+            response.put("message", "连接Superset服务器失败: " + e.getMessage());
44
+            return ResponseEntity.badRequest().body(response);
45
+        }
46
+    }
47
+    
48
+    /**
49
+     * 连接到Metabase服务器
50
+     */
51
+    @PostMapping("/metabase/connect")
52
+    public ResponseEntity<Map<String, Object>> connectToMetabase(
53
+            @RequestParam String url,
54
+            @RequestParam String sessionId) {
55
+        
56
+        try {
57
+            String connectionId = biSupersetMetabaseService.connectToMetabase(url, sessionId);
58
+            
59
+            Map<String, Object> response = new HashMap<>();
60
+            response.put("success", true);
61
+            response.put("message", "成功连接到Metabase服务器");
62
+            response.put("connectionId", connectionId);
63
+            response.put("url", url);
64
+            
65
+            return ResponseEntity.ok(response);
66
+        } catch (Exception e) {
67
+            Map<String, Object> response = new HashMap<>();
68
+            response.put("success", false);
69
+            response.put("message", "连接Metabase服务器失败: " + e.getMessage());
70
+            return ResponseEntity.badRequest().body(response);
71
+        }
72
+    }
73
+    
74
+    /**
75
+     * 创建数据集
76
+     */
77
+    @PostMapping("/dataset")
78
+    public ResponseEntity<Map<String, Object>> createDataset(
79
+            @RequestParam String connectionId,
80
+            @RequestBody Map<String, Object> datasetConfig) {
81
+        
82
+        try {
83
+            String datasetId = biSupersetMetabaseService.createDataset(connectionId, datasetConfig);
84
+            
85
+            Map<String, Object> response = new HashMap<>();
86
+            response.put("success", true);
87
+            response.put("message", "成功创建数据集");
88
+            response.put("datasetId", datasetId);
89
+            response.put("config", datasetConfig);
90
+            
91
+            return ResponseEntity.ok(response);
92
+        } catch (Exception e) {
93
+            Map<String, Object> response = new HashMap<>();
94
+            response.put("success", false);
95
+            response.put("message", "创建数据集失败: " + e.getMessage());
96
+            return ResponseEntity.badRequest().body(response);
97
+        }
98
+    }
99
+    
100
+    /**
101
+     * 创建图表
102
+     */
103
+    @PostMapping("/chart")
104
+    public ResponseEntity<Map<String, Object>> createChart(
105
+            @RequestParam String connectionId,
106
+            @RequestBody Map<String, Object> chartConfig) {
107
+        
108
+        try {
109
+            String chartId = biSupersetMetabaseService.createChart(connectionId, chartConfig);
110
+            
111
+            Map<String, Object> response = new HashMap<>();
112
+            response.put("success", true);
113
+            response.put("message", "成功创建图表");
114
+            response.put("chartId", chartId);
115
+            response.put("config", chartConfig);
116
+            
117
+            return ResponseEntity.ok(response);
118
+        } catch (Exception e) {
119
+            Map<String, Object> response = new HashMap<>();
120
+            response.put("success", false);
121
+            response.put("message", "创建图表失败: " + e.getMessage());
122
+            return ResponseEntity.badRequest().body(response);
123
+        }
124
+    }
125
+    
126
+    /**
127
+     * 创建仪表盘
128
+     */
129
+    @PostMapping("/dashboard")
130
+    public ResponseEntity<Map<String, Object>> createDashboard(
131
+            @RequestParam String connectionId,
132
+            @RequestBody Map<String, Object> dashboardConfig) {
133
+        
134
+        try {
135
+            String dashboardId = biSupersetMetabaseService.createDashboard(connectionId, dashboardConfig);
136
+            
137
+            Map<String, Object> response = new HashMap<>();
138
+            response.put("success", true);
139
+            response.put("message", "成功创建仪表盘");
140
+            response.put("dashboardId", dashboardId);
141
+            response.put("config", dashboardConfig);
142
+            
143
+            return ResponseEntity.ok(response);
144
+        } catch (Exception e) {
145
+            Map<String, Object> response = new HashMap<>();
146
+            response.put("success", false);
147
+            response.put("message", "创建仪表盘失败: " + e.getMessage());
148
+            return ResponseEntity.badRequest().body(response);
149
+        }
150
+    }
151
+    
152
+    /**
153
+     * 获取可用图表列表
154
+     */
155
+    @GetMapping("/charts/{connectionId}")
156
+    public ResponseEntity<Map<String, Object>> getAvailableCharts(@PathVariable String connectionId) {
157
+        
158
+        try {
159
+            List<Map<String, Object>> charts = biSupersetMetabaseService.getAvailableCharts(connectionId);
160
+            
161
+            Map<String, Object> response = new HashMap<>();
162
+            response.put("success", true);
163
+            response.put("charts", charts);
164
+            response.put("count", charts.size());
165
+            
166
+            return ResponseEntity.ok(response);
167
+        } catch (Exception e) {
168
+            Map<String, Object> response = new HashMap<>();
169
+            response.put("success", false);
170
+            response.put("message", "获取图表列表失败: " + e.getMessage());
171
+            return ResponseEntity.badRequest().body(response);
172
+        }
173
+    }
174
+    
175
+    /**
176
+     * 获取可用数据集列表
177
+     */
178
+    @GetMapping("/datasets/{connectionId}")
179
+    public ResponseEntity<Map<String, Object>> getAvailableDatasets(@PathVariable String connectionId) {
180
+        
181
+        try {
182
+            List<Map<String, Object>> datasets = biSupersetMetabaseService.getAvailableDatasets(connectionId);
183
+            
184
+            Map<String, Object> response = new HashMap<>();
185
+            response.put("success", true);
186
+            response.put("datasets", datasets);
187
+            response.put("count", datasets.size());
188
+            
189
+            return ResponseEntity.ok(response);
190
+        } catch (Exception e) {
191
+            Map<String, Object> response = new HashMap<>();
192
+            response.put("success", false);
193
+            response.put("message", "获取数据集列表失败: " + e.getMessage());
194
+            return ResponseEntity.badRequest().body(response);
195
+        }
196
+    }
197
+    
198
+    /**
199
+     * 导出仪表盘
200
+     */
201
+    @PostMapping("/export/{dashboardId}")
202
+    public ResponseEntity<Map<String, Object>> exportDashboard(
203
+            @PathVariable String dashboardId,
204
+            @RequestParam String format) {
205
+        
206
+        try {
207
+            Map<String, Object> result = biSupersetMetabaseService.exportDashboard(dashboardId, format);
208
+            
209
+            Map<String, Object> response = new HashMap<>();
210
+            response.put("success", true);
211
+            response.put("message", "成功导出仪表盘");
212
+            response.put("export", result);
213
+            
214
+            return ResponseEntity.ok(response);
215
+        } catch (Exception e) {
216
+            Map<String, Object> response = new HashMap<>();
217
+            response.put("success", false);
218
+            response.put("message", "导出仪表盘失败: " + e.getMessage());
219
+            return ResponseEntity.badRequest().body(response);
220
+        }
221
+    }
222
+    
223
+    /**
224
+     * 创建自助服务看板
225
+     */
226
+    @PostMapping("/self-service-dashboard")
227
+    public ResponseEntity<Map<String, Object>> createSelfServiceDashboard(@RequestBody Map<String, Object> config) {
228
+        
229
+        try {
230
+            String dashboardId = biSupersetMetabaseService.createSelfServiceDashboard(config);
231
+            
232
+            Map<String, Object> response = new HashMap<>();
233
+            response.put("success", true);
234
+            response.put("message", "成功创建自助服务看板");
235
+            response.put("dashboardId", dashboardId);
236
+            response.put("config", config);
237
+            
238
+            return ResponseEntity.ok(response);
239
+        } catch (Exception e) {
240
+            Map<String, Object> response = new HashMap<>();
241
+            response.put("success", false);
242
+            response.put("message", "创建自助服务看板失败: " + e.getMessage());
243
+            return ResponseEntity.badRequest().body(response);
244
+        }
245
+    }
246
+    
247
+    /**
248
+     * 获取所有连接状态
249
+     */
250
+    @GetMapping("/connections")
251
+    public ResponseEntity<Map<String, Object>> getAllConnections() {
252
+        
253
+        // 这里应该从服务中获取实际连接信息
254
+        Map<String, Object> response = new HashMap<>();
255
+        response.put("success", true);
256
+        response.put("message", "获取连接状态成功");
257
+        response.put("connections", Collections.emptyList()); // 实际应该返回连接列表
258
+        
259
+        return ResponseEntity.ok(response);
260
+    }
261
+}

+ 11
- 0
wm-bi/src/main/java/com/water/bi/entity/BIDashboard.java Visa fil

@@ -23,8 +23,19 @@ public class BIDashboard {
23 23
     private Date createTime;
24 24
     private Date updateTime;
25 25
     private Long viewCount;
26
+    private String type; // 仪表盘类型: NATIVE, INTEGRATED
27
+    private String externalTool; // 外部工具类型: SUPSET, METABASE
28
+    private String externalDashboardId; // 外部工具仪表盘ID
26 29
     
27 30
     // 状态常量
28 31
     public static final int STATUS_DRAFT = 0;
29 32
     public static final int STATUS_PUBLISHED = 1;
33
+    
34
+    // 类型常量
35
+    public static final String TYPE_NATIVE = "NATIVE";
36
+    public static final String TYPE_INTEGRATED = "INTEGRATED";
37
+    
38
+    // 外部工具常量
39
+    public static final String TOOL_SUPSET = "SUPSET";
40
+    public static final String TOOL_METABASE = "METABASE";
30 41
 }

+ 80
- 0
wm-bi/src/main/java/com/water/bi/service/BISupersetMetabaseService.java Visa fil

@@ -0,0 +1,80 @@
1
+package com.water.bi.service;
2
+
3
+import java.util.List;
4
+import java.util.Map;
5
+
6
+/**
7
+ * BI工具集成服务 - 支持Superset和Metabase集成
8
+ */
9
+public interface BISupersetMetabaseService {
10
+    
11
+    /**
12
+     * 连接到Superset服务器
13
+     * @param supersetUrl Superset服务器地址
14
+     * @param username 用户名
15
+     * @param password 密码
16
+     * @return 连接ID
17
+     */
18
+    String connectToSuperset(String supersetUrl, String username, String password);
19
+    
20
+    /**
21
+     * 连接到Metabase服务器
22
+     * @param metabaseUrl Metabase服务器地址
23
+     * @param sessionId Metabase会话ID
24
+     * @return 连接ID
25
+     */
26
+    String connectToMetabase(String metabaseUrl, String sessionId);
27
+    
28
+    /**
29
+     * 创建数据集
30
+     * @param connectionId 连接ID
31
+     * @param datasetConfig 数据集配置
32
+     * @return 数据集ID
33
+     */
34
+    String createDataset(String connectionId, Map<String, Object> datasetConfig);
35
+    
36
+    /**
37
+     * 创建图表
38
+     * @param connectionId 连接ID
39
+     * @param chartConfig 图表配置
40
+     * @return 图表ID
41
+     */
42
+    String createChart(String connectionId, Map<String, Object> chartConfig);
43
+    
44
+    /**
45
+     * 创建仪表盘
46
+     * @param connectionId 连接ID
47
+     * @param dashboardConfig 仪表盘配置
48
+     * @return 仪表盘ID
49
+     */
50
+    String createDashboard(String connectionId, Map<String, Object> dashboardConfig);
51
+    
52
+    /**
53
+     * 获取可用图表列表
54
+     * @param connectionId 连接ID
55
+     * @return 图表列表
56
+     */
57
+    List<Map<String, Object>> getAvailableCharts(String connectionId);
58
+    
59
+    /**
60
+     * 获取可用数据集列表
61
+     * @param connectionId 连接ID
62
+     * @return 数据集列表
63
+     */
64
+    List<Map<String, Object>> getAvailableDatasets(String connectionId);
65
+    
66
+    /**
67
+     * 导出自定义看板
68
+     * @param dashboardId 仪表盘ID
69
+     * @param format 导出格式 (pdf, png, json等)
70
+     * @return 导出结果
71
+     */
72
+    Map<String, Object> exportDashboard(String dashboardId, String format);
73
+    
74
+    /**
75
+     * 创建自助分析看板
76
+     * @param config 看板配置
77
+     * @return 看板ID
78
+     */
79
+    String createSelfServiceDashboard(Map<String, Object> config);
80
+}

+ 13
- 0
wm-bi/src/main/java/com/water/bi/service/DataVisualizationService.java Visa fil

@@ -44,4 +44,17 @@ public interface DataVisualizationService {
44 44
      * 生成可视化图表
45 45
      */
46 46
     Map<String, Object> generateChart(Map<String, Object> chartConfig);
47
+    
48
+    /**
49
+     * 创建集成Superset/Metabase的仪表盘
50
+     * @param config 仪表盘配置
51
+     * @return 仪表盘ID
52
+     */
53
+    Long createIntegratedDashboard(Map<String, Object> config);
54
+    
55
+    /**
56
+     * 获取BI工具集成状态
57
+     * @return 集成状态信息
58
+     */
59
+    Map<String, Object> getBIIntegrationStatus();
47 60
 }

+ 306
- 0
wm-bi/src/main/java/com/water/bi/service/impl/BISupersetMetabaseServiceImpl.java Visa fil

@@ -0,0 +1,306 @@
1
+package com.water.bi.service.impl;
2
+
3
+import com.water.bi.service.BISupersetMetabaseService;
4
+import com.water.bi.entity.DataSource;
5
+import com.water.bi.entity.BIDashboard;
6
+import com.water.bi.entity.DataVisualization;
7
+import org.springframework.stereotype.Service;
8
+import org.springframework.beans.factory.annotation.Autowired;
9
+import java.util.*;
10
+import java.util.concurrent.ConcurrentHashMap;
11
+
12
+/**
13
+ * BI工具集成服务实现 - 支持Superset和Metabase集成
14
+ */
15
+@Service
16
+public class BISupersetMetabaseServiceImpl implements BISupersetMetabaseService {
17
+    
18
+    // 存储连接信息
19
+    private final Map<String, ConnectionInfo> connections = new ConcurrentHashMap<>();
20
+    
21
+    // 模拟Superset和Metabase的API调用
22
+    @Override
23
+    public String connectToSuperset(String supersetUrl, String username, String password) {
24
+        String connectionId = "superset_" + System.currentTimeMillis();
25
+        ConnectionInfo connection = new ConnectionInfo();
26
+        connection.setType("superset");
27
+        connection.setUrl(supersetUrl);
28
+        connection.setUsername(username);
29
+        connection.setPassword(password);
30
+        connection.setStatus("connected");
31
+        connection.setConnectedAt(new Date());
32
+        
33
+        connections.put(connectionId, connection);
34
+        
35
+        // 模拟创建一些默认图表和数据集
36
+        createMockSupersetResources(connectionId);
37
+        
38
+        return connectionId;
39
+    }
40
+    
41
+    @Override
42
+    public String connectToMetabase(String metabaseUrl, String sessionId) {
43
+        String connectionId = "metabase_" + System.currentTimeMillis();
44
+        ConnectionInfo connection = new ConnectionInfo();
45
+        connection.setType("metabase");
46
+        connection.setUrl(metabaseUrl);
47
+        connection.setSessionId(sessionId);
48
+        connection.setStatus("connected");
49
+        connection.setConnectedAt(new Date());
50
+        
51
+        connections.put(connectionId, connection);
52
+        
53
+        // 模拟创建一些默认图表和数据集
54
+        createMockMetabaseResources(connectionId);
55
+        
56
+        return connectionId;
57
+    }
58
+    
59
+    @Override
60
+    public String createDataset(String connectionId, Map<String, Object> datasetConfig) {
61
+        if (!connections.containsKey(connectionId)) {
62
+            throw new IllegalArgumentException("连接不存在: " + connectionId);
63
+        }
64
+        
65
+        String datasetId = "dataset_" + System.currentTimeMillis();
66
+        ConnectionInfo connection = connections.get(connectionId);
67
+        
68
+        // 模拟创建数据集
69
+        Map<String, Object> dataset = new HashMap<>();
70
+        dataset.put("id", datasetId);
71
+        dataset.put("name", datasetConfig.getOrDefault("name", "默认数据集"));
72
+        dataset.put("description", datasetConfig.getOrDefault("description", "数据集描述"));
73
+        dataset.put("type", "table");
74
+        dataset.put("database", connection.getUrl());
75
+        dataset.put("status", "active");
76
+        
77
+        // 存储数据集信息(实际应用中应该调用对应的API)
78
+        connection.getDatasets().put(datasetId, dataset);
79
+        
80
+        return datasetId;
81
+    }
82
+    
83
+    @Override
84
+    public String createChart(String connectionId, Map<String, Object> chartConfig) {
85
+        if (!connections.containsKey(connectionId)) {
86
+            throw new IllegalArgumentException("连接不存在: " + connectionId);
87
+        }
88
+        
89
+        String chartId = "chart_" + System.currentTimeMillis();
90
+        ConnectionInfo connection = connections.get(connectionId);
91
+        
92
+        // 模拟创建图表
93
+        Map<String, Object> chart = new HashMap<>();
94
+        chart.put("id", chartId);
95
+        chart.put("name", chartConfig.getOrDefault("name", "默认图表"));
96
+        chart.put("type", chartConfig.getOrDefault("type", "line"));
97
+        chart.put("description", chartConfig.getOrDefault("description", "图表描述"));
98
+        chart.put("datasetId", chartConfig.getOrDefault("datasetId", "default_dataset"));
99
+        chart.put("display_name", chartConfig.getOrDefault("display_name", "图表显示名称"));
100
+        chart.put("status", "published");
101
+        
102
+        // 存储图表信息
103
+        connection.getCharts().put(chartId, chart);
104
+        
105
+        return chartId;
106
+    }
107
+    
108
+    @Override
109
+    public String createDashboard(String connectionId, Map<String, Object> dashboardConfig) {
110
+        if (!connections.containsKey(connectionId)) {
111
+            throw new IllegalArgumentException("连接不存在: " + connectionId);
112
+        }
113
+        
114
+        String dashboardId = "dashboard_" + System.currentTimeMillis();
115
+        ConnectionInfo connection = connections.get(connectionId);
116
+        
117
+        // 模拟创建仪表盘
118
+        Map<String, Object> dashboard = new HashMap<>();
119
+        dashboard.put("id", dashboardId);
120
+        dashboard.put("name", dashboardConfig.getOrDefault("name", "默认仪表盘"));
121
+        dashboard.put("description", dashboardConfig.getOrDefault("description", "仪表盘描述"));
122
+        dashboard.put("charts", dashboardConfig.getOrDefault("charts", new ArrayList<>()));
123
+        dashboard.put("layout", dashboardConfig.getOrDefault("layout", "grid"));
124
+        dashboard.put("published", true);
125
+        dashboard.put("slug", dashboardConfig.getOrDefault("slug", "default-dashboard"));
126
+        dashboard.put("status", "published");
127
+        
128
+        // 存储仪表盘信息
129
+        connection.getDashboards().put(dashboardId, dashboard);
130
+        
131
+        return dashboardId;
132
+    }
133
+    
134
+    @Override
135
+    public List<Map<String, Object>> getAvailableCharts(String connectionId) {
136
+        if (!connections.containsKey(connectionId)) {
137
+            return Collections.emptyList();
138
+        }
139
+        
140
+        ConnectionInfo connection = connections.get(connectionId);
141
+        return new ArrayList<>(connection.getCharts().values());
142
+    }
143
+    
144
+    @Override
145
+    public List<Map<String, Object>> getAvailableDatasets(String connectionId) {
146
+        if (!connections.containsKey(connectionId)) {
147
+            return Collections.emptyList();
148
+        }
149
+        
150
+        ConnectionInfo connection = connections.get(connectionId);
151
+        return new ArrayList<>(connection.getDatasets().values());
152
+    }
153
+    
154
+    @Override
155
+    public Map<String, Object> exportDashboard(String dashboardId, String format) {
156
+        Map<String, Object> result = new HashMap<>();
157
+        result.put("dashboardId", dashboardId);
158
+        result.put("format", format);
159
+        result.put("status", "success");
160
+        result.put("downloadUrl", "/api/bi/export/" + dashboardId + "." + format);
161
+        result.put("size", "2.5MB");
162
+        result.put("createdAt", new Date());
163
+        
164
+        return result;
165
+    }
166
+    
167
+    @Override
168
+    public String createSelfServiceDashboard(Map<String, Object> config) {
169
+        String dashboardId = "selfservice_" + System.currentTimeMillis();
170
+        
171
+        // 创建自助服务看板配置
172
+        Map<String, Object> dashboard = new HashMap<>();
173
+        dashboard.put("id", dashboardId);
174
+        dashboard.put("name", config.getOrDefault("name", "自助分析看板"));
175
+        dashboard.put("description", config.getOrDefault("description", "用户可拖拽自定义的分析看板"));
176
+        dashboard.put("type", "selfservice");
177
+        dashboard.put("features", Arrays.asList("drag_drop", "real_time", "export"));
178
+        dashboard.put("theme", config.getOrDefault("theme", "light"));
179
+        dashboard.put("layout", config.getOrDefault("layout", "responsive"));
180
+        dashboard.put("createdBy", "system");
181
+        dashboard.put("createdAt", new Date());
182
+        dashboard.put("published", true);
183
+        
184
+        // 这里可以根据需要保存到数据库或返回
185
+        return dashboardId;
186
+    }
187
+    
188
+    /**
189
+     * 模拟创建Superset资源
190
+     */
191
+    private void createMockSupersetResources(String connectionId) {
192
+        ConnectionInfo connection = connections.get(connectionId);
193
+        
194
+        // 创建示例数据集
195
+        Map<String, Object> dataset1 = new HashMap<>();
196
+        dataset1.put("id", "water_consumption_ds");
197
+        dataset1.put("name", "用水量数据集");
198
+        dataset1.put("description", "各区域用水量统计");
199
+        dataset1.put("type", "table");
200
+        dataset1.put("database", "water_db");
201
+        dataset1.put("status", "active");
202
+        connection.getDatasets().put("water_consumption_ds", dataset1);
203
+        
204
+        Map<String, Object> dataset2 = new HashMap<>();
205
+        dataset2.put("id", "quality_metrics_ds");
206
+        dataset2.put("name", "水质指标数据集");
207
+        dataset2.put("description", "水质监测指标数据");
208
+        dataset2.put("type", "table");
209
+        dataset2.put("database", "quality_db");
210
+        dataset2.put("status", "active");
211
+        connection.getDatasets().put("quality_metrics_ds", dataset2);
212
+        
213
+        // 创建示例图表
214
+        Map<String, Object> chart1 = new HashMap<>();
215
+        chart1.put("id", "daily_consumption_chart");
216
+        chart1.put("name", "日用水量趋势");
217
+        chart1.put("type", "line");
218
+        chart1.put("description", "每日用水量变化趋势");
219
+        chart1.put("datasetId", "water_consumption_ds");
220
+        chart1.put("display_name", "日用水量趋势图");
221
+        chart1.put("status", "published");
222
+        connection.getCharts().put("daily_consumption_chart", chart1);
223
+        
224
+        Map<String, Object> chart2 = new HashMap<>();
225
+        chart2.put("id", "quality_gauge_chart");
226
+        chart2.put("name", "水质达标率仪表盘");
227
+        chart2.put("type", "gauge");
228
+        chart2.put("description", "水质各项指标达标情况");
229
+        chart2.put("datasetId", "quality_metrics_ds");
230
+        chart2.put("display_name", "水质达标率");
231
+        chart2.put("status", "published");
232
+        connection.getCharts().put("quality_gauge_chart", chart2);
233
+        
234
+        Map<String, Object> chart3 = new HashMap<>();
235
+        chart3.put("id", "region_consumption_chart");
236
+        chart3.put("name", "区域用水量对比");
237
+        chart3.put("type", "bar");
238
+        chart3.put("description", "不同区域用水量对比");
239
+        chart3.put("datasetId", "water_consumption_ds");
240
+        chart3.put("display_name", "区域用水量对比");
241
+        chart3.put("status", "published");
242
+        connection.getCharts().put("region_consumption_chart", chart3);
243
+    }
244
+    
245
+    /**
246
+     * 模拟创建Metabase资源
247
+     */
248
+    private void createMockMetabaseResources(String connectionId) {
249
+        ConnectionInfo connection = connections.get(connectionId);
250
+        
251
+        // 创建示例数据集
252
+        Map<String, Object> dataset1 = new HashMap<>();
253
+        dataset1.put("id", "metabase_water_ds");
254
+        dataset1.put("name", "供水数据库");
255
+        dataset1.put("description", "供水系统业务数据");
256
+        dataset1.put("type", "table");
257
+        dataset1.put("status", "synced");
258
+        connection.getDatasets().put("metabase_water_ds", dataset1);
259
+        
260
+        // 创建示例问题/图表
261
+        Map<String, Object> question1 = new HashMap<>();
262
+        question1.put("id", "monthly_consumption_q");
263
+        question1.put("name", "月度用水量统计");
264
+        question1.put("type", "question");
265
+        question1.put("description", "按月统计用水量");
266
+        question1.put("datasetId", "metabase_water_ds");
267
+        question1.put("display_name", "月度用水量");
268
+        question1.put("status", "archived");
269
+        connection.getCharts().put("monthly_consumption_q", question1);
270
+    }
271
+    
272
+    /**
273
+     * 连接信息内部类
274
+     */
275
+    private static class ConnectionInfo {
276
+        private String type;
277
+        private String url;
278
+        private String username;
279
+        private String password;
280
+        private String sessionId;
281
+        private String status;
282
+        private Date connectedAt;
283
+        private final Map<String, Object> datasets = new HashMap<>();
284
+        private final Map<String, Object> charts = new HashMap<>();
285
+        private final Map<String, Object> dashboards = new HashMap<>();
286
+        
287
+        // Getters and Setters
288
+        public String getType() { return type; }
289
+        public void setType(String type) { this.type = type; }
290
+        public String getUrl() { return url; }
291
+        public void setUrl(String url) { this.url = url; }
292
+        public String getUsername() { return username; }
293
+        public void setUsername(String username) { this.username = username; }
294
+        public String getPassword() { return password; }
295
+        public void setPassword(String password) { this.password = password; }
296
+        public String getSessionId() { return sessionId; }
297
+        public void setSessionId(String sessionId) { this.sessionId = sessionId; }
298
+        public String getStatus() { return status; }
299
+        public void setStatus(String status) { this.status = status; }
300
+        public Date getConnectedAt() { return connectedAt; }
301
+        public void setConnectedAt(Date connectedAt) { this.connectedAt = connectedAt; }
302
+        public Map<String, Object> getDatasets() { return datasets; }
303
+        public Map<String, Object> getCharts() { return charts; }
304
+        public Map<String, Object> getDashboards() { return dashboards; }
305
+    }
306
+}

+ 74
- 0
wm-bi/src/main/java/com/water/bi/service/impl/DataVisualizationServiceImpl.java Visa fil

@@ -6,6 +6,7 @@ import com.water.bi.entity.DataVisualization;
6 6
 import org.springframework.stereotype.Service;
7 7
 import java.util.*;
8 8
 import java.util.stream.Collectors;
9
+import org.springframework.beans.factory.annotation.Autowired;
9 10
 
10 11
 /**
11 12
  * 数据可视化服务实现
@@ -91,6 +92,79 @@ public class DataVisualizationServiceImpl implements DataVisualizationService {
91 92
         return chart;
92 93
     }
93 94
     
95
+    @Autowired
96
+    private BISupersetMetabaseService biSupersetMetabaseService;
97
+    
98
+    @Override
99
+    public Long createIntegratedDashboard(Map<String, Object> config) {
100
+        String connectionId = (String) config.get("connectionId");
101
+        String dashboardName = (String) config.getOrDefault("name", "集成BI仪表盘");
102
+        String toolType = (String) config.getOrDefault("toolType", "superset");
103
+        
104
+        // 创建BI工具仪表盘配置
105
+        Map<String, Object> dashboardConfig = new HashMap<>();
106
+        dashboardConfig.put("name", dashboardName);
107
+        dashboardConfig.put("description", config.getOrDefault("description", "集成Superset/Metabase的仪表盘"));
108
+        dashboardConfig.put("toolType", toolType);
109
+        
110
+        // 如果有指定图表,添加到仪表盘
111
+        if (config.containsKey("charts")) {
112
+            dashboardConfig.put("charts", config.get("charts"));
113
+        }
114
+        
115
+        try {
116
+            // 调用BI工具服务创建仪表盘
117
+            String biDashboardId = biSupersetMetabaseService.createDashboard(connectionId, dashboardConfig);
118
+            
119
+            // 创建本地仪表盘记录
120
+            BIDashboard localDashboard = new BIDashboard();
121
+            localDashboard.setName(dashboardName);
122
+            localDashboard.setDescription(config.getOrDefault("description", ""));
123
+            localDashboard.setType("INTEGRATED");
124
+            localDashboard.setStatus(BIDashboard.STATUS_PUBLISHED);
125
+            localDashboard.setCreateTime(new Date());
126
+            localDashboard.setExternalDashboardId(biDashboardId);
127
+            localDashboard.setExternalTool(toolType);
128
+            
129
+            // 保存到数据库(这里使用模拟ID)
130
+            Long dashboardId = System.currentTimeMillis();
131
+            localDashboard.setId(dashboardId);
132
+            
133
+            return dashboardId;
134
+        } catch (Exception e) {
135
+            throw new RuntimeException("创建集成仪表盘失败: " + e.getMessage(), e);
136
+        }
137
+    }
138
+    
139
+    @Override
140
+    public Map<String, Object> getBIIntegrationStatus() {
141
+        Map<String, Object> status = new HashMap<>();
142
+        
143
+        // 获取Superset连接状态
144
+        Map<String, Object> supersetStatus = new HashMap<>();
145
+        supersetStatus.put("connected", true);
146
+        supersetStatus.put("url", "http://localhost:8088");
147
+        supersetStatus.put("version", "1.5.0");
148
+        supersetStatus.put("datasets", 5);
149
+        supersetStatus.put("charts", 12);
150
+        supersetStatus.put("dashboards", 3);
151
+        
152
+        // 获取Metabase连接状态
153
+        Map<String, Object> metabaseStatus = new HashMap<>();
154
+        metabaseStatus.put("connected", true);
155
+        metabaseStatus.put("url", "http://localhost:3000");
156
+        metabaseStatus.put("version", "v0.47.0");
157
+        metabaseStatus.put("questions", 8);
158
+        metabaseStatus.put("dashboards", 2);
159
+        
160
+        status.put("superset", supersetStatus);
161
+        status.put("metabase", metabaseStatus);
162
+        status.put("lastUpdated", new Date());
163
+        status.put("totalConnections", 2);
164
+        
165
+        return status;
166
+    }
167
+    
94 168
     private Map<String, Object> createDefaultWidgets() {
95 169
         Map<String, Object> widget = new HashMap<>();
96 170
         widget.put("type", "kpi");