Merge branch 'master-500-dev-lzc' into 'master-500-dev'
aj导入导出 See merge request !100
Showing
7 changed files
with
318 additions
and
0 deletions
@@ -2,10 +2,15 @@ | @@ -2,10 +2,15 @@ | ||
2 | package com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity; | 2 | package com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity; |
3 | 3 | ||
4 | import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; | 4 | import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; |
5 | +import com.anjiplus.template.gaea.business.modules.dataset.dao.entity.DataSet; | ||
6 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
5 | import com.baomidou.mybatisplus.annotation.TableName; | 7 | import com.baomidou.mybatisplus.annotation.TableName; |
6 | import io.swagger.annotations.ApiModelProperty; | 8 | import io.swagger.annotations.ApiModelProperty; |
7 | import lombok.Data; | 9 | import lombok.Data; |
8 | 10 | ||
11 | +import java.util.ArrayList; | ||
12 | +import java.util.List; | ||
13 | + | ||
9 | /** | 14 | /** |
10 | * @description 大屏看板数据渲染 entity | 15 | * @description 大屏看板数据渲染 entity |
11 | * @author Raod | 16 | * @author Raod |
@@ -46,5 +51,9 @@ public class ReportDashboardWidget extends GaeaBaseEntity { | @@ -46,5 +51,9 @@ public class ReportDashboardWidget extends GaeaBaseEntity { | ||
46 | @ApiModelProperty(value = "排序,图层的概念") | 51 | @ApiModelProperty(value = "排序,图层的概念") |
47 | private Long sort; | 52 | private Long sort; |
48 | 53 | ||
54 | + @TableField(exist = false) | ||
55 | + private String setCode; | ||
49 | 56 | ||
57 | + @TableField(exist = false) | ||
58 | + private List<DataSet> dataSetList = new ArrayList<>(); | ||
50 | } | 59 | } |
@@ -4,10 +4,17 @@ package com.anjiplus.template.gaea.business.modules.dataset.dao.entity; | @@ -4,10 +4,17 @@ package com.anjiplus.template.gaea.business.modules.dataset.dao.entity; | ||
4 | import com.anji.plus.gaea.annotation.Unique; | 4 | import com.anji.plus.gaea.annotation.Unique; |
5 | import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; | 5 | import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; |
6 | import com.anjiplus.template.gaea.business.code.ResponseCode; | 6 | import com.anjiplus.template.gaea.business.code.ResponseCode; |
7 | +import com.anjiplus.template.gaea.business.modules.datasetparam.dao.entity.DataSetParam; | ||
8 | +import com.anjiplus.template.gaea.business.modules.datasettransform.dao.entity.DataSetTransform; | ||
9 | +import com.anjiplus.template.gaea.business.modules.datasource.dao.entity.DataSource; | ||
10 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
7 | import com.baomidou.mybatisplus.annotation.TableName; | 11 | import com.baomidou.mybatisplus.annotation.TableName; |
8 | import io.swagger.annotations.ApiModelProperty; | 12 | import io.swagger.annotations.ApiModelProperty; |
9 | import lombok.Data; | 13 | import lombok.Data; |
10 | 14 | ||
15 | +import java.util.ArrayList; | ||
16 | +import java.util.List; | ||
17 | + | ||
11 | /** | 18 | /** |
12 | * @description 数据集 entity | 19 | * @description 数据集 entity |
13 | * @author Raod | 20 | * @author Raod |
@@ -44,5 +51,15 @@ public class DataSet extends GaeaBaseEntity { | @@ -44,5 +51,15 @@ public class DataSet extends GaeaBaseEntity { | ||
44 | @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") | 51 | @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") |
45 | private Integer deleteFlag; | 52 | private Integer deleteFlag; |
46 | 53 | ||
54 | + @TableField(exist = false) | ||
55 | + List<DataSetTransform> dataSetTransformList = new ArrayList<>(); | ||
56 | + | ||
57 | + @TableField(exist = false) | ||
58 | + List<DataSetParam> dataSetParamList = new ArrayList<>(); | ||
59 | + | ||
60 | + @TableField(exist = false) | ||
61 | + List<DataSource> dataSourceList = new ArrayList<>(); | ||
47 | 62 | ||
63 | + @TableField(exist = false) | ||
64 | + private String sourceCodeChange; | ||
48 | } | 65 | } |
1 | +package com.anjiplus.template.gaea.business.modules.export.controller; | ||
2 | + | ||
3 | +import com.alibaba.fastjson.JSON; | ||
4 | +import com.alibaba.fastjson.JSONObject; | ||
5 | +import com.alibaba.fastjson.serializer.SerializerFeature; | ||
6 | +import com.anjiplus.template.gaea.business.modules.export.service.impl.ExportServiceImpl; | ||
7 | +import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; | ||
8 | +import org.springframework.web.bind.annotation.GetMapping; | ||
9 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
10 | +import org.springframework.web.bind.annotation.RequestParam; | ||
11 | +import org.springframework.web.bind.annotation.RestController; | ||
12 | +import org.springframework.web.multipart.MultipartFile; | ||
13 | + | ||
14 | +import javax.servlet.http.HttpServletResponse; | ||
15 | +import java.io.IOException; | ||
16 | +import java.io.InputStream; | ||
17 | +import java.io.InputStreamReader; | ||
18 | +import java.nio.charset.StandardCharsets; | ||
19 | +import java.util.List; | ||
20 | + | ||
21 | +/** | ||
22 | + * 导出 | ||
23 | + * | ||
24 | + * @author lzc | ||
25 | + * @version 1.0 | ||
26 | + * @date 2022-06-21 11:02 | ||
27 | + */ | ||
28 | +@RestController | ||
29 | +public class ExportController { | ||
30 | + | ||
31 | + private final ExportServiceImpl exportService; | ||
32 | + | ||
33 | + public ExportController(ExportServiceImpl exportService) { | ||
34 | + this.exportService = exportService; | ||
35 | + } | ||
36 | + | ||
37 | + @GetMapping("/export") | ||
38 | + public void export(HttpServletResponse response, @RequestParam List<String> reportCodeList) { | ||
39 | + List<Report> export = exportService.export(reportCodeList); | ||
40 | + exportJson(response, export, "AJ大屏报表"); | ||
41 | + } | ||
42 | + | ||
43 | + private void exportJson(HttpServletResponse response, List<Report> export, String fileName) { | ||
44 | + try { | ||
45 | + String jsonString = JSON.toJSONString(export, | ||
46 | + SerializerFeature.PrettyFormat, | ||
47 | + SerializerFeature.WriteMapNullValue, | ||
48 | + SerializerFeature.WriteDateUseDateFormat); | ||
49 | + response.setContentType("application/octet-stream"); | ||
50 | + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".json"); | ||
51 | + response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8)); | ||
52 | + } catch (Exception e) { | ||
53 | + throw new RuntimeException("导出错误"); | ||
54 | + } | ||
55 | + } | ||
56 | + | ||
57 | + @RequestMapping("/import") | ||
58 | + public void importE(MultipartFile file) throws IOException { | ||
59 | + byte[] bytes = file.getBytes(); | ||
60 | + Object parse = JSONObject.parse(bytes); | ||
61 | + List<Report> reportList = JSONObject.parseArray(JSONObject.toJSONString(parse), Report.class); | ||
62 | + exportService.importE(reportList); | ||
63 | + } | ||
64 | +} |
1 | +package com.anjiplus.template.gaea.business.modules.export.service; | ||
2 | + | ||
3 | +import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; | ||
4 | + | ||
5 | +import java.util.List; | ||
6 | + | ||
7 | +/** | ||
8 | + * @author lzc | ||
9 | + * @version 1.0 | ||
10 | + * @date 2022-06-21 11:03 | ||
11 | + */ | ||
12 | +public interface ExportService { | ||
13 | + List<Report> export(List<String> reportCodeList); | ||
14 | + | ||
15 | + void importE(List<Report> reportList); | ||
16 | +} |
1 | +package com.anjiplus.template.gaea.business.modules.export.service.impl; | ||
2 | + | ||
3 | +import com.anjiplus.template.gaea.business.modules.dashboard.dao.entity.ReportDashboard; | ||
4 | +import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashboardService; | ||
5 | +import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity.ReportDashboardWidget; | ||
6 | +import com.anjiplus.template.gaea.business.modules.dashboardwidget.service.ReportDashboardWidgetService; | ||
7 | +import com.anjiplus.template.gaea.business.modules.dataset.dao.entity.DataSet; | ||
8 | +import com.anjiplus.template.gaea.business.modules.dataset.service.DataSetService; | ||
9 | +import com.anjiplus.template.gaea.business.modules.datasetparam.dao.entity.DataSetParam; | ||
10 | +import com.anjiplus.template.gaea.business.modules.datasetparam.service.DataSetParamService; | ||
11 | +import com.anjiplus.template.gaea.business.modules.datasettransform.dao.entity.DataSetTransform; | ||
12 | +import com.anjiplus.template.gaea.business.modules.datasettransform.service.DataSetTransformService; | ||
13 | +import com.anjiplus.template.gaea.business.modules.datasource.dao.entity.DataSource; | ||
14 | +import com.anjiplus.template.gaea.business.modules.datasource.service.DataSourceService; | ||
15 | +import com.anjiplus.template.gaea.business.modules.export.service.ExportService; | ||
16 | +import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; | ||
17 | +import com.anjiplus.template.gaea.business.modules.report.service.ReportService; | ||
18 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||
19 | +import org.apache.commons.lang3.StringUtils; | ||
20 | +import org.springframework.stereotype.Service; | ||
21 | + | ||
22 | +import java.util.ArrayList; | ||
23 | +import java.util.List; | ||
24 | +import java.util.Map; | ||
25 | +import java.util.stream.Collectors; | ||
26 | + | ||
27 | +/** | ||
28 | + * @author lzc | ||
29 | + * @version 1.0 | ||
30 | + * @date 2022-06-21 11:03 | ||
31 | + */ | ||
32 | +@Service | ||
33 | +public class ExportServiceImpl implements ExportService { | ||
34 | + | ||
35 | + private final ReportService reportService; | ||
36 | + private final ReportDashboardService reportDashboardService; | ||
37 | + private final ReportDashboardWidgetService reportDashboardWidgetService; | ||
38 | + private final DataSetService dataSetService; | ||
39 | + private final DataSetParamService dataSetParamService; | ||
40 | + private final DataSetTransformService dataSetTransformService; | ||
41 | + private final DataSourceService dataSourceService; | ||
42 | + | ||
43 | + public ExportServiceImpl(ReportService reportService, ReportDashboardService reportDashboardService, ReportDashboardWidgetService reportDashboardWidgetService, DataSetService dataSetService, DataSetParamService dataSetParamService, DataSetTransformService dataSetTransformService, DataSourceService dataSourceService) { | ||
44 | + this.reportService = reportService; | ||
45 | + this.reportDashboardService = reportDashboardService; | ||
46 | + this.reportDashboardWidgetService = reportDashboardWidgetService; | ||
47 | + this.dataSetService = dataSetService; | ||
48 | + this.dataSetParamService = dataSetParamService; | ||
49 | + this.dataSetTransformService = dataSetTransformService; | ||
50 | + this.dataSourceService = dataSourceService; | ||
51 | + } | ||
52 | + | ||
53 | + @Override | ||
54 | + public List<Report> export(List<String> reportCodeList) { | ||
55 | + //大屏 | ||
56 | + List<Report> reportList = reportService.list(new LambdaQueryWrapper<Report>() | ||
57 | + .in(Report::getReportCode, reportCodeList)); | ||
58 | + if (reportList == null || reportList.size() == 0) { | ||
59 | + return reportList; | ||
60 | + } | ||
61 | + //大屏配置 | ||
62 | + reportCodeList = reportList.stream().map(Report::getReportCode).collect(Collectors.toList()); | ||
63 | + List<ReportDashboard> reportDashboardList = reportDashboardService.list(new LambdaQueryWrapper<ReportDashboard>() | ||
64 | + .in(ReportDashboard::getReportCode, reportCodeList)); | ||
65 | + //大屏组件 | ||
66 | + List<ReportDashboardWidget> reportDashboardWidgetList = reportDashboardWidgetService.list(new LambdaQueryWrapper<ReportDashboardWidget>() | ||
67 | + .in(ReportDashboardWidget::getReportCode, reportCodeList)); | ||
68 | + //组件中的接口地址 | ||
69 | + List<String> setCodeList = new ArrayList<>(); | ||
70 | + reportDashboardWidgetList.stream().filter(item -> item.getData().contains("setCode")).forEach(item -> { | ||
71 | + String data = item.getData(); | ||
72 | + int startIndex = data.indexOf("setCode"); | ||
73 | + int endIndex = data.indexOf(",", startIndex); | ||
74 | + String setCode = data.substring(startIndex + 10, endIndex - 1); | ||
75 | + setCodeList.add(setCode); | ||
76 | + item.setSetCode(setCode); | ||
77 | + }); | ||
78 | + if (setCodeList.size() == 0) { | ||
79 | + return reportList; | ||
80 | + } | ||
81 | + //接口地址 | ||
82 | + List<DataSet> dataSetList = dataSetService.list(new LambdaQueryWrapper<DataSet>() | ||
83 | + .in(DataSet::getSetCode, setCodeList)); | ||
84 | + if (dataSetList == null || dataSetList.size() == 0) { | ||
85 | + return reportList; | ||
86 | + } | ||
87 | + //接口参数 | ||
88 | + List<String> setCodes = dataSetList.stream().map(DataSet::getSetCode).collect(Collectors.toList()); | ||
89 | + List<DataSetParam> dataSetParamList = dataSetParamService.list(new LambdaQueryWrapper<DataSetParam>() | ||
90 | + .in(DataSetParam::getSetCode, setCodes)); | ||
91 | + //数据转换 | ||
92 | + List<DataSetTransform> dataSetTransformList = dataSetTransformService.list(new LambdaQueryWrapper<DataSetTransform>() | ||
93 | + .in(DataSetTransform::getSetCode, setCodes)); | ||
94 | + //数据源 | ||
95 | + List<String> sourceCodeList = dataSetList.stream().map(DataSet::getSourceCode).distinct().collect(Collectors.toList()); | ||
96 | + List<DataSource> dataSourceList = dataSourceService.list(new LambdaQueryWrapper<DataSource>() | ||
97 | + .in(DataSource::getSourceCode, sourceCodeList)); | ||
98 | + //组合大屏组件 | ||
99 | + Map<String, List<ReportDashboard>> reportDashboardMap = reportDashboardList.stream().collect(Collectors.groupingBy(ReportDashboard::getReportCode)); | ||
100 | + Map<String, List<ReportDashboardWidget>> reportDashboardWidgetMap = reportDashboardWidgetList.stream().collect(Collectors.groupingBy(ReportDashboardWidget::getReportCode)); | ||
101 | + for (Report report : reportList) { | ||
102 | + if (reportDashboardMap.get(report.getReportCode()) != null) { | ||
103 | + report.setReportDashboardList(reportDashboardMap.get(report.getReportCode())); | ||
104 | + } | ||
105 | + if (reportDashboardWidgetMap.get(report.getReportCode()) != null) { | ||
106 | + report.setReportDashboardWidgetList(reportDashboardWidgetMap.get(report.getReportCode())); | ||
107 | + } | ||
108 | + } | ||
109 | + //组合组件接口 | ||
110 | + Map<String, List<DataSet>> dataSetMap = dataSetList.stream().collect(Collectors.groupingBy(DataSet::getSetCode)); | ||
111 | + reportDashboardWidgetList.stream().filter(item -> item.getData().contains("setCode")).forEach(reportDashboardWidget -> { | ||
112 | + if (dataSetMap.get(reportDashboardWidget.getSetCode()) != null) { | ||
113 | + reportDashboardWidget.getDataSetList().addAll(dataSetMap.get(reportDashboardWidget.getSetCode())); | ||
114 | + } | ||
115 | + }); | ||
116 | + //组合接口参数转换数据源 | ||
117 | + Map<String, List<DataSetTransform>> dataSetTransformMap = dataSetTransformList.stream().collect(Collectors.groupingBy(DataSetTransform::getSetCode)); | ||
118 | + Map<String, List<DataSetParam>> dataSetParamMap = dataSetParamList.stream().collect(Collectors.groupingBy(DataSetParam::getSetCode)); | ||
119 | + Map<String, List<DataSource>> dataSourceMap = dataSourceList.stream().collect(Collectors.groupingBy(DataSource::getSourceCode)); | ||
120 | + for (DataSet dataSet : dataSetList) { | ||
121 | + if (dataSetTransformMap.get(dataSet.getSetCode()) != null) { | ||
122 | + dataSet.getDataSetTransformList().addAll(dataSetTransformMap.get(dataSet.getSetCode())); | ||
123 | + } | ||
124 | + if (dataSetParamMap.get(dataSet.getSetCode()) != null) { | ||
125 | + dataSet.getDataSetParamList().addAll(dataSetParamMap.get(dataSet.getSetCode())); | ||
126 | + } | ||
127 | + if (dataSourceMap.get(dataSet.getSourceCode()) != null) { | ||
128 | + dataSet.getDataSourceList().addAll(dataSourceMap.get(dataSet.getSourceCode())); | ||
129 | + } | ||
130 | + } | ||
131 | + return reportList; | ||
132 | + } | ||
133 | + | ||
134 | + @Override | ||
135 | + public void importE(List<Report> reportList) { | ||
136 | + | ||
137 | + //新增大屏 | ||
138 | + if (reportList == null || reportList.size() == 0) { | ||
139 | + return; | ||
140 | + } | ||
141 | + List<String> reportCodeList = reportList.stream().map(Report::getReportCode).collect(Collectors.toList()); | ||
142 | + reportService.delete(new LambdaQueryWrapper<Report>().in(Report::getReportCode, reportCodeList)); | ||
143 | + reportService.insertBatch(reportList); | ||
144 | + | ||
145 | + //新增大屏配置 | ||
146 | + List<ReportDashboard> reportDashboardList = new ArrayList<>(); | ||
147 | + reportList.stream().map(Report::getReportDashboardList).forEach(reportDashboardList::addAll); | ||
148 | + if (reportDashboardList.size() != 0) { | ||
149 | + reportDashboardService.delete(new LambdaQueryWrapper<ReportDashboard>().in(ReportDashboard::getReportCode, reportCodeList)); | ||
150 | + reportDashboardService.insertBatch(reportDashboardList); | ||
151 | + } | ||
152 | + | ||
153 | + //新增大屏组件 | ||
154 | + List<ReportDashboardWidget> reportDashboardWidgetList = new ArrayList<>(); | ||
155 | + reportList.stream().map(Report::getReportDashboardWidgetList).forEach(reportDashboardWidgetList::addAll); | ||
156 | + if (reportDashboardWidgetList.size() == 0) { | ||
157 | + return; | ||
158 | + } | ||
159 | + reportDashboardWidgetService.delete(new LambdaQueryWrapper<ReportDashboardWidget>().in(ReportDashboardWidget::getReportCode, reportCodeList)); | ||
160 | + reportDashboardWidgetService.insertBatch(reportDashboardWidgetList); | ||
161 | + | ||
162 | + //新增数据集 | ||
163 | + List<String> setCodeList = reportDashboardWidgetList.stream().map(ReportDashboardWidget::getSetCode).distinct().collect(Collectors.toList()); | ||
164 | + List<DataSet> dataSetList = new ArrayList<>(); | ||
165 | + reportDashboardWidgetList.stream().map(ReportDashboardWidget::getDataSetList).forEach(dataSetList::addAll); | ||
166 | + if (dataSetList.size() != 0) { | ||
167 | + dataSetService.delete(new LambdaQueryWrapper<DataSet>().in(DataSet::getSetCode, setCodeList)); | ||
168 | + for (DataSet dataSet : dataSetList) { | ||
169 | + if (StringUtils.isNotBlank(dataSet.getSourceCodeChange())) { | ||
170 | + dataSet.setSourceCode(dataSet.getSourceCodeChange()); | ||
171 | + } | ||
172 | + } | ||
173 | + dataSetService.insertBatch(dataSetList); | ||
174 | + } | ||
175 | + | ||
176 | + //新增数据集参数 | ||
177 | + List<DataSetParam> dataSetParamList = new ArrayList<>(); | ||
178 | + dataSetList.stream().map(DataSet::getDataSetParamList).forEach(dataSetParamList::addAll); | ||
179 | + if (dataSetParamList.size() != 0) { | ||
180 | + dataSetParamService.delete(new LambdaQueryWrapper<DataSetParam>().in(DataSetParam::getSetCode, setCodeList)); | ||
181 | + dataSetParamService.insertBatch(dataSetParamList); | ||
182 | + } | ||
183 | + | ||
184 | + //新增数据源转换 | ||
185 | + List<DataSetTransform> dataSetTransformList = new ArrayList<>(); | ||
186 | + dataSetList.stream().map(DataSet::getDataSetTransformList).forEach(dataSetTransformList::addAll); | ||
187 | + if (dataSetTransformList.size() != 0) { | ||
188 | + dataSetTransformService.delete(new LambdaQueryWrapper<DataSetTransform>().in(DataSetTransform::getSetCode, setCodeList)); | ||
189 | + dataSetTransformService.insertBatch(dataSetTransformList); | ||
190 | + } | ||
191 | + } | ||
192 | +} |
@@ -3,10 +3,15 @@ package com.anjiplus.template.gaea.business.modules.report.dao.entity; | @@ -3,10 +3,15 @@ package com.anjiplus.template.gaea.business.modules.report.dao.entity; | ||
3 | import com.anji.plus.gaea.annotation.Unique; | 3 | import com.anji.plus.gaea.annotation.Unique; |
4 | import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; | 4 | import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; |
5 | import com.anjiplus.template.gaea.business.code.ResponseCode; | 5 | import com.anjiplus.template.gaea.business.code.ResponseCode; |
6 | +import com.anjiplus.template.gaea.business.modules.dashboard.dao.entity.ReportDashboard; | ||
7 | +import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity.ReportDashboardWidget; | ||
8 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
6 | import com.baomidou.mybatisplus.annotation.TableName; | 9 | import com.baomidou.mybatisplus.annotation.TableName; |
7 | import io.swagger.annotations.ApiModelProperty; | 10 | import io.swagger.annotations.ApiModelProperty; |
8 | import lombok.Data; | 11 | import lombok.Data; |
9 | 12 | ||
13 | +import java.util.List; | ||
14 | + | ||
10 | /** | 15 | /** |
11 | * TODO | 16 | * TODO |
12 | * | 17 | * |
@@ -41,4 +46,10 @@ public class Report extends GaeaBaseEntity { | @@ -41,4 +46,10 @@ public class Report extends GaeaBaseEntity { | ||
41 | 46 | ||
42 | @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") | 47 | @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") |
43 | private Integer deleteFlag; | 48 | private Integer deleteFlag; |
49 | + | ||
50 | + @TableField(exist = false) | ||
51 | + private List<ReportDashboard> reportDashboardList; | ||
52 | + | ||
53 | + @TableField(exist = false) | ||
54 | + private List<ReportDashboardWidget> reportDashboardWidgetList; | ||
44 | } | 55 | } |
-
Please register or login to post a comment