Bladeren bron

feat: historical data

工业检测 3 dagen geleden
bovenliggende
commit
8f7f14db75

+ 6 - 3
REDEME.md

@@ -13,7 +13,10 @@
 
 ## 项目成员
  ```bash
- git config --global user.name "工业检测"
- git config --global user.email "19870555569@163.com"
+        -组长:徐福静  0235668  18370353938
+  -成员:曾露 0235699 19870555569
+        陈飞羽 0235635 13970419048
+        张喆  0224986  15070059526
+        刘家昊 0230791 15122906621
  ```
- ng g component page-ai --standalone --style=scss
+

+ 41 - 17
industry-monitor-web/src/app/pages/factory-overview/factory-overview.component.html

@@ -18,7 +18,7 @@
         <p class="metric-label">运行设备数/总设备数</p>
       </div>
     </div>
-    
+
     <div class="metric-card">
       <div class="metric-icon orange">
         <i class="fa fa-exclamation-triangle"></i>
@@ -29,7 +29,7 @@
         <p class="metric-label">预警总数</p>
       </div>
     </div>
-    
+
     <div class="metric-card">
       <div class="metric-icon green">
         <i class="fa fa-heartbeat"></i>
@@ -40,7 +40,7 @@
         <p class="metric-label">整体设备健康</p>
       </div>
     </div>
-    
+
     <div class="metric-card">
       <div class="metric-icon purple">
         <i class="fa fa-tachometer-alt"></i>
@@ -70,7 +70,7 @@
         </div>
       </div>
     </div>
-    
+
     <div class="alert-card">
       <h3><i class="fa fa-bell"></i> 实时警报</h3>
       <div class="alert-list">
@@ -79,8 +79,8 @@
           <div class="alert-content">
             <strong>设备 #A23 温度过高</strong>
             <span>车间B - 产线2 | 15:23:45</span>
-            <comp-star-rating 
-              [star]="rating" 
+            <comp-star-rating
+              [star]="rating"
               (onStarChange)="ratingChange($event)"
             ></comp-star-rating>
             <p>当前评分: {{rating}}</p>
@@ -106,17 +106,41 @@
       </div>
     </div>
   </div>
-  
+
   <div class="trend-card">
-    <h3><i class="fa fa-chart-line"></i> 健康指数趋势 (24小时)</h3>
-    <div class="trend-graph">
-      <div class="graph-bar" style="--height: 60;"></div>
-      <div class="graph-bar" style="--height: 65;"></div>
-      <div class="graph-bar" style="--height: 70;"></div>
-      <div class="graph-bar" style="--height: 82;"></div>
-      <div class="graph-bar" style="--height: 88;"></div>
-      <div class="graph-bar" style="--height: 92;"></div>
-      <div class="graph-bar" style="--height: 90;"></div>
+  <h3><i class="fa fa-chart-line"></i> 健康指数趋势 (24小时)</h3>
+
+  <div class="trend-description">
+    过去24小时内设备健康指数变化趋势,当前平均健康指数为82,较昨日上升5.2%。
+  </div>
+
+  <div class="trend-graph">
+    <div class="graph-bar" style="--height: 60;" data-value="60"></div>
+    <div class="graph-bar" style="--height: 65;" data-value="65"></div>
+    <div class="graph-bar" style="--height: 70;" data-value="70"></div>
+    <div class="graph-bar" style="--height: 82;" data-value="82"></div>
+    <div class="graph-bar" style="--height: 88;" data-value="88"></div>
+    <div class="graph-bar" style="--height: 92;" data-value="92"></div>
+    <div class="graph-bar" style="--height: 90;" data-value="90"></div>
+  </div>
+
+  <div class="time-labels">
+    <span>00:00</span>
+    <span>04:00</span>
+    <span>08:00</span>
+    <span>12:00</span>
+    <span>16:00</span>
+    <span>20:00</span>
+    <span>24:00</span>
+  </div>
+
+  <div class="trend-footer">
+    <div class="trend-summary">
+      数据更新时间: {{currentTime | date:'yyyy-MM-dd HH:mm:ss'}}
+    </div>
+    <div class="trend-change positive">
+      <i class="fa fa-arrow-up"></i> 5.2%
     </div>
   </div>
-</div>
+</div>
+</div>

+ 22 - 1
industry-monitor-web/src/app/pages/factory-overview/factory-overview.component.ts

@@ -14,9 +14,30 @@ import { TokPipe } from '../../pipes/tok-pipe/tok.pipe';
     DatePipe,TokPipe,
     CompStarRatingComponent
   ]
-  
+
 })
 export class FactoryOverviewComponent {
+  // 在组件类中添加以下属性
+
+  // 设备状态数据
+  deviceStatus = {
+    total: 24,
+    normal: { count: 19, percentage: 80 },
+    warning: { count: 4, percentage: 15 },
+    danger: { count: 1, percentage: 5 }
+  };
+
+  // 饼图角度计算
+  get pieChartStyle() {
+    return {
+      'background': `conic-gradient(
+        #27ae60 0% ${this.deviceStatus.normal.percentage}%,
+        #f39c12 ${this.deviceStatus.normal.percentage}% ${this.deviceStatus.normal.percentage + this.deviceStatus.warning.percentage}%,
+        #e74c3c ${this.deviceStatus.normal.percentage + this.deviceStatus.warning.percentage}% 100%
+      )`
+    };
+
+}
   rating:number = 0
   ratingChange(rating: number) {
     this.rating = rating;

+ 145 - 1
industry-monitor-web/src/app/pages/factory-overview/factory-overview.css

@@ -239,4 +239,148 @@
   border-radius: 8px;
   padding: 20px;
   box-shadow: 0 2px 8px rgba(0,0,0,0.1);
-}
+}
+/* 健康指数趋势卡片样式 */
+.trend-card {
+  background: white;
+  border-radius: 12px;
+  padding: 20px;
+  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
+  transition: all 0.3s ease;
+  border: 1px solid #eaeef2;
+  position: relative;
+  overflow: hidden;
+}
+
+.trend-card:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 8px 20px rgba(0,0,0,0.12);
+  border-color: #3498db;
+}
+
+.trend-card h3 {
+  margin: 0 0 15px 0;
+  font-size: 18px;
+  color: #2c3e50;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.trend-card h3 i {
+  color: #3498db;
+  font-size: 20px;
+}
+
+.trend-description {
+  font-size: 14px;
+  color: #718096;
+  margin-bottom: 20px;
+  line-height: 1.5;
+}
+
+.trend-graph {
+  display: flex;
+  align-items: flex-end;
+  gap: 12px;
+  height: 200px;
+  padding: 20px;
+  background: #f8fafc;
+  border-radius: 8px;
+  margin-top: 15px;
+  position: relative;
+}
+
+.graph-bar {
+  flex: 1;
+  background: linear-gradient(to top, #3498db, #67b7f5);
+  height: calc(var(--height) * 1.8px);
+  border-radius: 6px 6px 0 0;
+  position: relative;
+  transition: all 0.4s ease;
+  cursor: pointer;
+  min-width: 30px;
+}
+
+.graph-bar:hover {
+  transform: scaleY(1.05);
+  box-shadow: 0 -4px 8px rgba(52, 152, 219, 0.3);
+}
+
+.graph-bar::after {
+  content: attr(data-value);
+  position: absolute;
+  top: -25px;
+  left: 50%;
+  transform: translateX(-50%);
+  background: #2c3e50;
+  color: white;
+  padding: 3px 8px;
+  border-radius: 12px;
+  font-size: 12px;
+  font-weight: 600;
+  opacity: 0;
+  transition: opacity 0.3s ease;
+}
+
+.graph-bar:hover::after {
+  opacity: 1;
+}
+
+.time-labels {
+  display: flex;
+  justify-content: space-between;
+  margin-top: 8px;
+  font-size: 12px;
+  color: #95a5a6;
+  padding: 0 10px;
+}
+
+.trend-footer {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-top: 20px;
+  padding-top: 15px;
+  border-top: 1px solid #eaeef2;
+}
+
+.trend-summary {
+  font-size: 14px;
+  color: #718096;
+}
+
+.trend-change {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+  font-weight: 600;
+  font-size: 14px;
+}
+
+.trend-change.positive {
+  color: #27ae60;
+}
+
+.trend-change.negative {
+  color: #e74c3c;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .trend-card {
+    padding: 15px;
+  }
+
+  .trend-graph {
+    height: 160px;
+    padding: 15px;
+    gap: 8px;
+  }
+
+  .graph-bar {
+    min-width: 20px;
+  }
+}
+
+

+ 28 - 6
industry-monitor-web/src/app/pages/historical-data/historical-data.component.html

@@ -84,7 +84,7 @@
       </thead>
       <tbody>
         <tr>
-          <td>2023-07-15</td>
+          <td>{{currentDate}}</td>
           <td>CNC 铣床 #01</td>
           <td>0.58</td>
           <td>68</td>
@@ -93,7 +93,7 @@
           <td><span class="status-badge normal">正常</span></td>
         </tr>
         <tr>
-          <td>2023-07-15</td>
+         <td>{{currentDate}}</td>
           <td>注塑机 #05</td>
           <td>0.72</td>
           <td>71</td>
@@ -102,7 +102,7 @@
           <td><span class="status-badge warning">警告</span></td>
         </tr>
         <tr>
-          <td>2023-07-14</td>
+        <td>{{currentDate}}</td>
           <td>CNC 铣床 #01</td>
           <td>0.62</td>
           <td>70</td>
@@ -111,7 +111,7 @@
           <td><span class="status-badge normal">正常</span></td>
         </tr>
         <tr>
-          <td>2023-07-14</td>
+         <td>{{currentDate}}</td>
           <td>装配机器人 #03</td>
           <td>0.48</td>
           <td>65</td>
@@ -120,7 +120,7 @@
           <td><span class="status-badge critical">严重</span></td>
         </tr>
         <tr>
-          <td>2023-07-13</td>
+          <td>{{currentDate}}</td>
           <td>CNC 铣床 #01</td>
           <td>0.92</td>
           <td>75</td>
@@ -132,6 +132,28 @@
     </table>
   </div>
 
+<script>
+  // 获取当前日期并格式化为YYYY-MM-DD
+  function getCurrentDate() {
+    const now = new Date();
+    const year = now.getFullYear();
+    const month = String(now.getMonth() + 1).padStart(2, '0');
+    const day = String(now.getDate()).padStart(2, '0');
+    return `${year}-${month}-${day}`;
+  }
+
+  // 更新表格中的日期
+  document.addEventListener('DOMContentLoaded', function() {
+    const currentDate = getCurrentDate();
+    for (let i = 1; i <= 5; i++) {
+      const element = document.getElementById(`currentDate${i}`);
+      if (element) {
+        element.textContent = currentDate;
+      }
+    }
+  });
+</script>
+
   <div class="report-section">
     <h3><i class="fa fa-file-alt"></i> 报表生成</h3>
     <div class="report-options">
@@ -140,4 +162,4 @@
       <button class="btn primary"><i class="fa fa-stethoscope"></i> 生成健康诊断报告</button>
     </div>
   </div>
-</div>
+</div>

+ 9 - 0
industry-monitor-web/src/app/pages/historical-data/historical-data.component.ts

@@ -11,6 +11,14 @@ import { DatePipe } from '@angular/common';
   encapsulation: ViewEncapsulation.None
 })
 export class HistoricalDataComponent {
+  // 在组件类中
+currentDate: string;
+
+constructor() {
+  const now = new Date();
+  this.currentDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
+}
+
 currentTime: Date = new Date();
    ngOnInit(): void {
     // 更新时间,每秒更新一次
@@ -20,3 +28,4 @@ currentTime: Date = new Date();
 
    }
 }
+

+ 350 - 46
industry-monitor-web/src/app/pages/historical-data/historical-data.css

@@ -2,36 +2,44 @@
 :host {
   display: block;
   width: 100%;
-  padding: 15px;
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
 }
 
 .history-container {
   max-width: 1400px;
   margin: 0 auto;
-  padding: 20px;
+  padding: 25px;
   background: white;
-  border-radius: 8px;
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+  border-radius: 10px;
+  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.05);
 }
 
 .history-header {
-  margin-bottom: 24px;
-  padding-bottom: 16px;
-  border-bottom: 1px solid #eee;
+  margin-bottom: 30px;
+  padding-bottom: 20px;
+  border-bottom: 1px solid #eaeef2;
 }
 
 .history-header h2 {
   display: flex;
   align-items: center;
-  gap: 10px;
-  font-size: 24px;
+  gap: 12px;
+  font-size: 26px;
   color: #2c3e50;
+  font-weight: 600;
+  margin: 0;
+}
+
+.history-header h2 i {
+  color: #3498db;
 }
 
 .filter-row {
   display: flex;
   gap: 20px;
-  margin-bottom: 20px;
+  margin-bottom: 25px;
 }
 
 .filter-card,
@@ -40,7 +48,8 @@
   background: white;
   border-radius: 8px;
   padding: 20px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+  box-shadow: 0 3px 10px rgba(0,0,0,0.08);
+  border: 1px solid #eaeef2;
 }
 
 .date-controls {
@@ -52,17 +61,25 @@
 
 .date-input label {
   display: block;
-  margin-bottom: 6px;
+  margin-bottom: 8px;
   font-size: 14px;
-  color: #2c3e50;
+  color: #4a5568;
+  font-weight: 500;
 }
 
 .date-input input {
   width: 100%;
-  padding: 8px 12px;
-  border-radius: 4px;
-  border: 1px solid #ddd;
+  padding: 10px 12px;
+  border-radius: 6px;
+  border: 1px solid #e2e8f0;
   font-size: 14px;
+  transition: border-color 0.3s;
+}
+
+.date-input input:focus {
+  outline: none;
+  border-color: #3498db;
+  box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
 }
 
 .device-controls {
@@ -73,10 +90,18 @@
 
 .device-controls select {
   flex: 1;
-  padding: 8px 12px;
-  border-radius: 4px;
-  border: 1px solid #ddd;
+  padding: 10px 12px;
+  border-radius: 6px;
+  border: 1px solid #e2e8f0;
   font-size: 14px;
+  background-color: white;
+  transition: border-color 0.3s;
+}
+
+.device-controls select:focus {
+  outline: none;
+  border-color: #3498db;
+  box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
 }
 
 .checkbox-container {
@@ -85,6 +110,7 @@
   cursor: pointer;
   font-size: 14px;
   user-select: none;
+  color: #4a5568;
 }
 
 .checkbox-container input {
@@ -96,12 +122,17 @@
 .checkmark {
   height: 20px;
   width: 20px;
-  background-color: #eee;
+  background-color: #edf2f7;
   border-radius: 4px;
   margin-left: 10px;
   display: flex;
   align-items: center;
   justify-content: center;
+  transition: background-color 0.2s;
+}
+
+.checkbox-container:hover .checkmark {
+  background-color: #e2e8f0;
 }
 
 .checkbox-container input:checked ~ .checkmark {
@@ -122,28 +153,114 @@
   display: block;
 }
 
+.data-table-card {
+  margin-top: 30px;
+  background: white;
+  border-radius: 8px;
+  box-shadow: 0 3px 10px rgba(0,0,0,0.08);
+  border: 1px solid #eaeef2;
+  overflow: hidden;
+}
+
+.data-table-card h3 {
+  padding: 18px 20px;
+  margin: 0;
+  font-size: 18px;
+  color: #2c3e50;
+  background-color: #f8fafc;
+  border-bottom: 1px solid #eaeef2;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.data-table-card h3 i {
+  color: #718096;
+}
+
+.data-table {
+  width: 100%;
+  border-collapse: collapse;
+  font-size: 14px;
+}
+
+.data-table th {
+  background-color: #f8fafc;
+  color: #4a5568;
+  font-weight: 600;
+  padding: 12px 15px;
+  text-align: left;
+  border-bottom: 1px solid #eaeef2;
+}
+
+.data-table td {
+  padding: 12px 15px;
+  border-bottom: 1px solid #eaeef2;
+  color: #4a5568;
+}
+
+.data-table tr:last-child td {
+  border-bottom: none;
+}
+
+.data-table tr:hover td {
+  background-color: #f8fafc;
+}
+
+.status-badge {
+  display: inline-block;
+  padding: 4px 10px;
+  border-radius: 12px;
+  font-size: 12px;
+  font-weight: 500;
+}
+
+.status-badge.normal {
+  background-color: #e6fffa;
+  color: #38b2ac;
+}
+
+.status-badge.warning {
+  background-color: #fffaf0;
+  color: #dd6b20;
+}
+
+.status-badge.critical {
+  background-color: #fff5f5;
+  color: #e53e3e;
+}
+
 .chart-container {
-  margin-bottom: 20px;
+  margin-bottom: 25px;
 }
 
 .chart-card {
   background: white;
   border-radius: 8px;
   padding: 20px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+  box-shadow: 0 3px 10px rgba(0,0,0,0.08);
+  border: 1px solid #eaeef2;
 }
 
 .chart-header {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  margin-bottom: 15px;
+  margin-bottom: 20px;
+}
+
+.chart-header h4 {
+  margin: 0;
+  font-size: 16px;
+  color: #2c3e50;
+  font-weight: 600;
 }
 
 .chart-legend {
   display: flex;
   gap: 20px;
   font-size: 14px;
+  color: #4a5568;
 }
 
 .color-dot {
@@ -152,6 +269,7 @@
   height: 12px;
   border-radius: 50%;
   margin-right: 8px;
+  vertical-align: middle;
 }
 
 .color-dot.primary { background: #3498db; }
@@ -163,59 +281,245 @@
   border-radius: 6px;
   position: relative;
   padding: 30px 40px;
+  border: 1px solid #eaeef2;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .filter-row {
+    flex-direction: column;
+    gap: 15px;
+  }
+
+  .date-controls {
+    grid-template-columns: 1fr;
+  }
+
+  .device-controls {
+    flex-direction: column;
+    align-items: flex-start;
+  }
+
+  .data-table {
+    display: block;
+    overflow-x: auto;
+  }
+}
+.chart-container {
+  margin-bottom: 25px;
+}
+
+.chart-card {
+  background: white;
+  border-radius: 8px;
+  padding: 20px;
+  box-shadow: 0 3px 10px rgba(0,0,0,0.08);
+  border: 1px solid #eaeef2;
+}
+
+.chart-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+
+.chart-header h3 {
+  margin: 0;
+  font-size: 16px;
+  color: #2c3e50;
+  font-weight: 600;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.chart-header h3 i {
+  color: #3498db;
+}
+
+.chart-legend {
+  display: flex;
+  gap: 20px;
+  font-size: 14px;
+  color: #4a5568;
+}
+
+.color-dot {
+  display: inline-block;
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+  margin-right: 8px;
+  vertical-align: middle;
+}
+
+.color-dot.primary { background: #3498db; }
+.color-dot.secondary { background: #9b59b6; }
+
+#vibrationChart {
+  width: 100%;
+  border-radius: 6px;
+  background: #f8fafc;
+  border: 1px solid #eaeef2;
+}
+/* 振动图表专用样式 */
+.chart-container {
+  margin-bottom: 25px;
+}
+
+.chart-card {
+  background: white;
+  border-radius: 8px;
+  padding: 20px;
+  box-shadow: 0 3px 10px rgba(0,0,0,0.08);
+  border: 1px solid #eaeef2;
+}
+
+.chart-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+
+.chart-header h3 {
+  margin: 0;
+  font-size: 16px;
+  color: #2c3e50;
+  font-weight: 600;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.chart-header h3 i {
+  color: #3498db;
+}
+
+.chart-legend {
+  display: flex;
+  gap: 20px;
+  font-size: 14px;
+  color: #4a5568;
+}
+
+.color-dot {
+  display: inline-block;
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+  margin-right: 8px;
+  vertical-align: middle;
+}
+
+.color-dot.primary { background: #3498db; }
+.color-dot.secondary { background: #9b59b6; }
+
+.chart-content {
+  height: 400px;
+  background: #f8fafc;
+  border-radius: 6px;
+  position: relative;
+  border: 1px solid #eaeef2;
+  overflow: hidden;
 }
 
 .trend-chart {
   width: 100%;
   height: 100%;
   position: relative;
+  padding: 20px 30px 40px 40px;
 }
 
 .grid-lines {
   position: absolute;
   top: 0;
   left: 0;
-  right: 0;
-  bottom: 0;
+  width: 100%;
+  height: calc(100% - 30px);
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  padding: 20px 30px 0 40px;
 }
 
 .grid-line {
-  position: absolute;
-  width: 100%;
   height: 1px;
-  background: rgba(0, 0, 0, 0.05);
+  background-color: #eaeef2;
+  width: 100%;
 }
 
-.grid-line:nth-child(1) { top: 0%; }
-.grid-line:nth-child(2) { top: 25%; }
-.grid-line:nth-child(3) { top: 50%; }
-.grid-line:nth-child(4) { top: 75%; }
-.grid-line:nth-child(5) { top: 100%; }
-
 .data-line {
   position: absolute;
-  height: 3px;
-  border-radius: 3px;
-  bottom: 0;
+  height: 2px;
+  border-radius: 2px;
+  left: 40px;
+  right: 30px;
 }
 
 .data-line.primary {
-  background: #3498db;
-  width: 70%;
+  background-color: #3498db;
+  top: 30%;
 }
 
 .data-line.secondary {
-  background: #9b59b6;
-  width: 60%;
+  background-color: #9b59b6;
+  top: 60%;
 }
 
 .x-axis {
   position: absolute;
-  bottom: -30px;
-  left: 0;
-  right: 0;
+  bottom: 10px;
+  left: 40px;
+  right: 30px;
+  display: flex;
+  justify-content: space-between;
+  font-size: 12px;
+  color: #718096;
+}
+
+.y-axis {
+  position: absolute;
+  left: 10px;
+  top: 20px;
+  bottom: 40px;
   display: flex;
+  flex-direction: column;
   justify-content: space-between;
   font-size: 12px;
-  color: white;
-}
+  color: #718096;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .chart-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 10px;
+  }
+
+  .chart-legend {
+    width: 100%;
+    justify-content: space-between;
+    gap: 10px;
+  }
+
+  .trend-chart {
+    padding: 15px 20px 30px 30px;
+  }
+
+  .grid-lines {
+    padding: 15px 20px 0 30px;
+  }
+
+  .data-line {
+    left: 30px;
+    right: 20px;
+  }
+
+  .x-axis {
+    left: 30px;
+    right: 20px;
+  }
+}

+ 1 - 0
industry-monitor-web/src/app/pages/historical-data/historical-data.spec.ts

@@ -21,3 +21,4 @@ describe('HistoricalData', () => {
     expect(component).toBeTruthy();
   });
 });
+

+ 6 - 0
package-lock.json

@@ -0,0 +1,6 @@
+{
+  "name": "industry-monitor",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {}
+}