Commit 1dacccb9d0ad0ba0649b6de19cc12badad0ce8c3

Authored by yiming
1 parent dd8cd26f

信号异常报表

src/main/java/com/bsth/controller/gps/GpsController.java
... ... @@ -9,13 +9,19 @@ import com.bsth.data.kl.KlData;
9 9 import com.bsth.data.schedule.e_state_check.ScheduleStationCodeChecker;
10 10 import com.bsth.data.schedule.e_state_check.entity.SCodeInfo;
11 11 import com.bsth.service.gps.GpsService;
  12 +import com.bsth.service.gps.entity.GpsOutbound_DTO;
12 13 import com.bsth.service.gps.entity.GpsSpeed;
  14 +import com.bsth.service.gps.entity.GpsSpeed_DTO;
13 15 import com.google.common.base.Splitter;
14 16 import org.springframework.beans.factory.annotation.Autowired;
15 17 import org.springframework.web.bind.annotation.*;
16 18  
17 19 import javax.servlet.http.HttpServletResponse;
18 20 import java.text.ParseException;
  21 +import java.time.LocalDate;
  22 +import java.time.LocalDateTime;
  23 +import java.time.ZoneOffset;
  24 +import java.time.format.DateTimeFormatter;
19 25 import java.util.ArrayList;
20 26 import java.util.HashMap;
21 27 import java.util.List;
... ... @@ -233,5 +239,39 @@ public class GpsController {
233 239 public Map<String, Object> allCarsByLine(String lineCode){
234 240 return gpsService.allCarsByLine(lineCode);
235 241 }
236   -
  242 +
  243 +
  244 + @RequestMapping(value = "/abnormalSpeeds")
  245 + public List<GpsSpeed_DTO> abnormalSpeeds(@RequestParam Map<String, Object> map){
  246 + String dateS = (String) map.get("date");
  247 + LocalDateTime localDateTime= LocalDate.parse(dateS, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
  248 + long st = localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
  249 + String dateE= (String) map.get("date2");
  250 + LocalDateTime localDateTime2= LocalDate.parse(dateE, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
  251 + long et =localDateTime2.plusDays(1).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
  252 + String line= (String) map.get("line");
  253 + return gpsService.abnormalSpeeds(line, st, et);
  254 + }
  255 +
  256 + @RequestMapping(value = "/abnormalOutbounds")
  257 + public List<GpsOutbound_DTO> abnormalOutbounds(@RequestParam Map<String, Object> map){
  258 + String dateS = (String) map.get("date");
  259 + LocalDateTime localDateTime = LocalDate.parse(dateS, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
  260 + long st = localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
  261 + String dateE = (String) map.get("date2");
  262 + LocalDateTime localDateTime2 = LocalDate.parse(dateE, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
  263 + long et = localDateTime2.plusDays(1).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
  264 + String line = (String) map.get("line");
  265 + return gpsService.abnormalOutbounds(line, st, et);
  266 + }
  267 +
  268 + @RequestMapping(value = "/abnormalGPSExcel/{line}")
  269 + public void abnormalGPSExcel(@PathVariable("line") String line, @RequestParam String dateS, @RequestParam String dateE, HttpServletResponse resp){
  270 + LocalDateTime localDateTime = LocalDate.parse(dateS, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
  271 + long st = localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
  272 + LocalDateTime localDateTime2 = LocalDate.parse(dateE, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
  273 + long et = localDateTime2.plusDays(1).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
  274 + gpsService.abnormalGPS(line, st, et, resp);
  275 + }
  276 +
237 277 }
... ...
src/main/java/com/bsth/entity/realcontrol/ScheduleRealInfo.java
... ... @@ -1131,7 +1131,7 @@ public class ScheduleRealInfo implements Cloneable{
1131 1131 }else if(this.getBcType().equals("venting")){
1132 1132 return "放空班次";
1133 1133 }else if(this.getBcType().equals("major")){
1134   - return "站班次";
  1134 + return "站班次";
1135 1135 }else if(this.getBcType().equals("ldks")){
1136 1136 return "两点间空驶";
1137 1137 }else {
... ...
src/main/java/com/bsth/service/gps/GpsService.java
... ... @@ -47,4 +47,10 @@ public interface GpsService {
47 47 Map<String, Object> Pagequery(Map<String, Object> map);
48 48  
49 49 Map<String,Object> allCarsByLine(String lineCode);
  50 +
  51 + void abnormalGPS(String lineCode, long st, long et, HttpServletResponse resp);
  52 +
  53 + List<GpsSpeed_DTO> abnormalSpeeds(String lineCode, long st, long et);
  54 +
  55 + List<GpsOutbound_DTO> abnormalOutbounds(String lineCode, long st, long et);
50 56 }
... ...
src/main/java/com/bsth/service/gps/GpsServiceImpl.java
... ... @@ -25,9 +25,11 @@ import java.util.LinkedList;
25 25 import java.util.List;
26 26 import java.util.Map;
27 27 import java.util.Set;
  28 +import java.util.stream.Collectors;
28 29  
29 30 import javax.servlet.http.HttpServletResponse;
30 31  
  32 +import com.bsth.service.gps.entity.*;
31 33 import org.apache.commons.lang3.StringUtils;
32 34 import org.apache.poi.hssf.usermodel.HSSFCellStyle;
33 35 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
... ... @@ -69,13 +71,6 @@ import com.bsth.repository.LsSectionRouteRepository;
69 71 import com.bsth.repository.LsStationRouteRepository;
70 72 import com.bsth.repository.StationRepository;
71 73 import com.bsth.repository.realcontrol.ScheduleRealInfoRepository;
72   -import com.bsth.service.gps.entity.DeviceChange;
73   -import com.bsth.service.gps.entity.GpsOutbound_DTO;
74   -import com.bsth.service.gps.entity.GpsSpeed;
75   -import com.bsth.service.gps.entity.GpsSpeed_DTO;
76   -import com.bsth.service.gps.entity.HistoryGps_DTO;
77   -import com.bsth.service.gps.entity.HistoryGps_DTOV3;
78   -import com.bsth.service.gps.entity.Road_DTO;
79 74 import com.bsth.util.CoordinateConverter;
80 75 import com.bsth.util.CoordinateConverter.Location;
81 76 import com.bsth.util.db.DBUtils_MS;
... ... @@ -298,7 +293,7 @@ public class GpsServiceImpl implements GpsService {
298 293 for(Map<String, Object> rs : dataList) {
299 294 if(rs.get("LINE_ID").toString().equals("0"))
300 295 continue;
301   -
  296 +
302 297 Object lineCode = rs.get("LINE_ID");
303 298 // 线路ID发生变化时补全线路切换信息 并新加入一个
304 299 if (oldLineId != (Integer)lineCode) {
... ... @@ -1045,7 +1040,7 @@ public class GpsServiceImpl implements GpsService {
1045 1040 for(int i = 0; i < outboundList.size(); i++){
1046 1041 outbound = outboundList.get(i);
1047 1042 row = sheet.createRow(i + 1);
1048   - row.createCell(0).setCellValue("超速");
  1043 + row.createCell(0).setCellValue("越界");
1049 1044 row.createCell(1).setCellValue(fmtHHmmss.print(outbound.getSt()));
1050 1045 row.createCell(2).setCellValue(fmtHHmmss.print(outbound.getEt()));
1051 1046 if(outbound.getEt() != 0)
... ... @@ -1673,4 +1668,150 @@ public class GpsServiceImpl implements GpsService {
1673 1668 return list;
1674 1669 }
1675 1670  
  1671 + @Override
  1672 + public void abnormalGPS(String lineCode, long st, long et, HttpServletResponse resp) {
  1673 + //超速数据
  1674 + List<GpsSpeed_DTO> speedList = abnormalSpeeds(lineCode, st, et);
  1675 + //越界数据
  1676 + List<GpsOutbound_DTO> outboundList = abnormalOutbounds(lineCode, st, et);
  1677 +
  1678 + //创建excel工作簿
  1679 + Workbook wb = new HSSFWorkbook();
  1680 +
  1681 + DateTimeFormatter fmtHHmmss = DateTimeFormat.forPattern("HH:mm.ss"),
  1682 + fmt = DateTimeFormat.forPattern("yyyyMMddHHmm");
  1683 + if(speedList.size() > 0){
  1684 + Sheet sheet = wb.createSheet("超速");
  1685 + //表头
  1686 + Row row = sheet.createRow(0);
  1687 + row.setHeight((short) (1.5 * 256));
  1688 + row.createCell(0).setCellValue("线路");
  1689 + row.createCell(1).setCellValue("自编号");
  1690 + row.createCell(2).setCellValue("异常信息");
  1691 + row.createCell(3).setCellValue("最大速度");
  1692 + row.createCell(4).setCellValue("开始时间");
  1693 + row.createCell(5).setCellValue("结束时间");
  1694 + row.createCell(6).setCellValue("持续(秒)");
  1695 +
  1696 +
  1697 + GpsSpeed_DTO speed;
  1698 + for(int i = 0; i < speedList.size(); i++){
  1699 + speed = speedList.get(i);
  1700 + row = sheet.createRow(i + 1);
  1701 + row.createCell(0).setCellValue(speed.getLineName());
  1702 + row.createCell(1).setCellValue(speed.getNbbm());
  1703 + row.createCell(2).setCellValue("超速");
  1704 + row.createCell(3).setCellValue(speed.getSpeed());
  1705 + row.createCell(4).setCellValue(fmtHHmmss.print(speed.getSt()));
  1706 + row.createCell(5).setCellValue(fmtHHmmss.print(speed.getEt()));
  1707 + if(speed.getEt() != 0)
  1708 + row.createCell(6).setCellValue((speed.getEt() - speed.getSt()) / 1000);
  1709 + }
  1710 + }
  1711 +
  1712 + if(outboundList.size() > 0){
  1713 + Sheet sheet = wb.createSheet("越界");
  1714 + //表头
  1715 + Row row = sheet.createRow(0);
  1716 + row.setHeight((short) (1.5 * 256));
  1717 + row.createCell(0).setCellValue("线路");
  1718 + row.createCell(1).setCellValue("自编号");
  1719 + row.createCell(2).setCellValue("异常信息");
  1720 + row.createCell(3).setCellValue("开始时间");
  1721 + row.createCell(4).setCellValue("结束时间");
  1722 + row.createCell(5).setCellValue("持续(秒)");
  1723 + /*row.createCell(6).setCellValue("所在路段");*/
  1724 + row.createCell(6).setCellValue("路径");
  1725 +
  1726 + GpsOutbound_DTO outbound;
  1727 + //设置路径单元格 水平对齐 填充
  1728 + CellStyle cs = wb.createCellStyle();
  1729 + cs.setAlignment(HSSFCellStyle.ALIGN_FILL);
  1730 + for(int i = 0; i < outboundList.size(); i++){
  1731 + outbound = outboundList.get(i);
  1732 + row = sheet.createRow(i + 1);
  1733 + row.createCell(0).setCellValue(outbound.getLineName());
  1734 + row.createCell(1).setCellValue(outbound.getNbbm());
  1735 + row.createCell(2).setCellValue("越界");
  1736 + row.createCell(3).setCellValue(fmtHHmmss.print(outbound.getSt()));
  1737 + row.createCell(4).setCellValue(fmtHHmmss.print(outbound.getEt()));
  1738 + if(outbound.getEt() != 0)
  1739 + row.createCell(5).setCellValue((outbound.getEt() - outbound.getSt()) / 1000);
  1740 + /*row.createCell(6).setCellValue("");*/
  1741 + row.createCell(6).setCellValue(outbound.getLocations());
  1742 +
  1743 + row.getCell(6).setCellStyle(cs);
  1744 + }
  1745 + }
  1746 +
  1747 + String filename = "异常信息" + fmt.print(st) + "至" + fmt.print(et) + ".xls";
  1748 + try {
  1749 + resp.setContentType("application/x-msdownload");
  1750 + resp.addHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
  1751 +
  1752 + OutputStream out=resp.getOutputStream();
  1753 + wb.write(out);
  1754 + out.flush();
  1755 + out.close();
  1756 + } catch (UnsupportedEncodingException e) {
  1757 + logger.error("", e);
  1758 + } catch (IOException e) {
  1759 + logger.error("", e);
  1760 + }
  1761 + }
  1762 +
  1763 + @Override
  1764 + public List<GpsSpeed_DTO> abnormalSpeeds(String lineCode, long st, long et) {
  1765 + //按周分区
  1766 + Calendar sCal = Calendar.getInstance();
  1767 + sCal.setTime(new Date(st));
  1768 + int sWeekYear = sCal.get(Calendar.WEEK_OF_YEAR);
  1769 + Calendar eCal = Calendar.getInstance();
  1770 + eCal.setTime(new Date(et));
  1771 + int eWeekYear = eCal.get(Calendar.WEEK_OF_YEAR);
  1772 + //按年分表
  1773 + String tableName = "bsth_c_speeding_" + fmtyyyy.print(st);
  1774 + //按线路查询
  1775 + String sql =" select vehicle, line, up_down, lon, lat, speed,timestamp from "+tableName+" where "+
  1776 + " weeks_year in ("+sWeekYear+", "+eWeekYear+") and line='"+lineCode+"' and timestamp>="+st+" and timestamp<" + et +" ORDER BY vehicle,timestamp";
  1777 + logger.info("speed sql : " + sql);
  1778 + List<GpsSpeed> list= new JdbcTemplate(DBUtils_MS.getDataSource()).query(sql, BeanPropertyRowMapper.newInstance(GpsSpeed.class));
  1779 + //设备修改记录
  1780 + Map<String,List<DeviceChange>> deviceChangeLogs = findDeviceChangeLogs();
  1781 + return GpsSpeed_DTO.init(list,deviceChangeLogs);
  1782 + }
  1783 +
  1784 + @Override
  1785 + public List<GpsOutbound_DTO> abnormalOutbounds(String lineCode, long st, long et) {
  1786 + //按周分区
  1787 + Calendar sCal = Calendar.getInstance();
  1788 + sCal.setTime(new Date(st));
  1789 + int sWeekYear = sCal.get(Calendar.WEEK_OF_YEAR);
  1790 + Calendar eCal = Calendar.getInstance();
  1791 + eCal.setTime(new Date(et));
  1792 + int eWeekYear = eCal.get(Calendar.WEEK_OF_YEAR);
  1793 + //按年分表
  1794 + String tableName = "bsth_c_outbound_" + fmtyyyy.print(st);
  1795 + //按线路查询
  1796 + String sql ="select vehicle,line,up_down,lon,lat,timestamp from "+tableName+" where " +
  1797 + " weeks_year in ("+sWeekYear+", "+eWeekYear+") and line='"+lineCode+"' and timestamp>="+st+" and timestamp<" + et +" ORDER BY vehicle,timestamp";
  1798 + logger.info("outbound sql : " + sql);
  1799 + List<GpsOutbound> list= new JdbcTemplate(DBUtils_MS.getDataSource()).query(sql, BeanPropertyRowMapper.newInstance(GpsOutbound.class));
  1800 + //设备修改记录
  1801 + Map<String,List<DeviceChange>> deviceChangeLogs = findDeviceChangeLogs();
  1802 + return GpsOutbound_DTO.init(list,deviceChangeLogs);
  1803 + }
  1804 +
  1805 + private Map<String,List<DeviceChange>> findDeviceChangeLogs(){
  1806 + Map<String,List<DeviceChange>> stringListMap = new HashMap<>();
  1807 + try{
  1808 + List<DeviceChange> dcs = jdbcTemplate.query("select cl_zbh as nbbm,new_device_no as device,old_device_no as old_device,UNIX_TIMESTAMP(qyrq) * 1000 as st from bsth_c_car_device where is_cancel=0 order by qyrq"
  1809 + , BeanPropertyRowMapper.newInstance(DeviceChange.class));
  1810 + stringListMap=dcs.stream().collect(Collectors.groupingBy(DeviceChange::getDevice));
  1811 + }catch (Exception e){
  1812 + logger.error("", e);
  1813 + }
  1814 + return stringListMap;
  1815 + }
  1816 +
1676 1817 }
1677 1818 \ No newline at end of file
... ...
src/main/java/com/bsth/service/gps/entity/GpsOutbound.java
... ... @@ -18,6 +18,9 @@ public class GpsOutbound {
18 18  
19 19 private long timestamp;
20 20  
  21 + private String nbbm;
  22 +
  23 +
21 24 public String location(){
22 25 return lon + "," + lat;
23 26 }
... ... @@ -69,4 +72,12 @@ public class GpsOutbound {
69 72 public void setTimestamp(long timestamp) {
70 73 this.timestamp = timestamp;
71 74 }
  75 +
  76 + public void setNbbm(String nbbm) {
  77 + this.nbbm = nbbm;
  78 + }
  79 +
  80 + public String getNbbm() {
  81 + return nbbm;
  82 + }
72 83 }
... ...
src/main/java/com/bsth/service/gps/entity/GpsOutbound_DTO.java
... ... @@ -3,8 +3,11 @@ package com.bsth.service.gps.entity;
3 3 import com.alibaba.fastjson.JSON;
4 4 import com.alibaba.fastjson.JSONObject;
5 5 import com.bsth.data.BasicData;
  6 +import org.joda.time.format.DateTimeFormat;
  7 +import org.joda.time.format.DateTimeFormatter;
6 8  
7 9 import java.util.*;
  10 +import java.util.stream.Collectors;
8 11  
9 12 /**
10 13 * 越界异常 dto
... ... @@ -25,7 +28,7 @@ public class GpsOutbound_DTO {
25 28 }
26 29 });
27 30  
28   - int space = 1000 * 60;
  31 + int space = 1000 * 20;
29 32 int size = list.size();
30 33 StringBuffer locations = new StringBuffer("");
31 34  
... ... @@ -41,23 +44,88 @@ public class GpsOutbound_DTO {
41 44 dto.setNbbm(BasicData.deviceId2NbbmMap.get(outbound.getVehicle()));
42 45 dto.setSt(outbound.getTimestamp());
43 46 }
44   - else{
  47 + //越界结束
  48 + if((i < size - 1 && list.get(i + 1).getTimestamp() - outbound.getTimestamp() > space)){
  49 + dto.setEt(outbound.getTimestamp()+space);
  50 + dto.setLocations(locations.toString());
  51 + rsList.add(dto);
  52 + dto = null;
  53 + locations = new StringBuffer("");
  54 + continue;
  55 + }
  56 + if(i == size - 1)
  57 + {
  58 + dto.setEt(outbound.getTimestamp()+space);
  59 + dto.setLocations(locations.toString());
  60 + rsList.add(dto);
  61 + }
  62 + }
  63 +
  64 + return rsList;
  65 + }
  66 +
  67 + public static List<GpsOutbound_DTO> init(List<GpsOutbound> outboundList,Map<String,List<DeviceChange>> deviceChangeLogs){
  68 + List<GpsOutbound_DTO> rsList = new ArrayList<>();
  69 + //先按设备分组
  70 + Map<String,List<GpsOutbound>> om=outboundList.stream().collect(Collectors.groupingBy(GpsOutbound::getVehicle));
  71 + //默认都是一辆车的数据
  72 + om.forEach((k,outbounds)->{
  73 + for (GpsOutbound outbound : outbounds) {
  74 + List<DeviceChange> dcs=deviceChangeLogs.get(outbound.getVehicle());
  75 + if(dcs==null){
  76 + outbound.setNbbm(BasicData.deviceId2NbbmMap.get(outbound.getVehicle()));
  77 + continue;
  78 + }
  79 + for (DeviceChange dc : dcs) {//确定每个超时的车辆自编号
  80 + if(outbound.getTimestamp()>dc.getSt()){
  81 + outbound.setNbbm(dc.getNbbm());
  82 + break;
  83 + }
  84 + }
  85 + }
  86 + GpsOutbound outbound;
  87 + //排序
  88 + Collections.sort(outbounds, new Comparator<GpsOutbound>() {
  89 + @Override
  90 + public int compare(GpsOutbound o1, GpsOutbound o2) {
  91 + return (int) (o1.getTimestamp() - o2.getTimestamp());
  92 + }
  93 + });
  94 +
  95 + int space = 1000 * 20;
  96 + int size = outbounds.size();
  97 + StringBuffer locations = new StringBuffer("");
  98 + GpsOutbound_DTO dto = null;
  99 +
  100 + for(int i = 0; i < size; i++){
  101 + outbound = outbounds.get(i);
  102 + locations.append(outbound.location() + ";");
  103 + if(dto == null){
  104 + dto = new GpsOutbound_DTO();
  105 + dto.setLineName(BasicData.lineCode2NameMap.get(outbound.getLine()));
  106 + dto.setDeviceId(outbound.getVehicle());
  107 + dto.setNbbm(outbound.getNbbm());
  108 + dto.setSt(outbound.getTimestamp());
  109 + }
  110 +
45 111 //越界结束
46   - if((i < size - 1 && list.get(i + 1).getTimestamp() - outbound.getTimestamp() > space)){
47   - dto.setEt(outbound.getTimestamp());
  112 + if((i < size - 1 && outbounds.get(i + 1).getTimestamp() - outbound.getTimestamp() > space)){
  113 + dto.setEt(outbound.getTimestamp()+space);
48 114 dto.setLocations(locations.toString());
49   -
50 115 rsList.add(dto);
51 116 dto = null;
52 117 locations = new StringBuffer("");
53 118 continue;
54 119 }
55   -
56 120 if(i == size - 1)
  121 + {
  122 + dto.setEt(outbound.getTimestamp()+space);
  123 + dto.setLocations(locations.toString());
57 124 rsList.add(dto);
58   - }
59   - }
  125 + }
60 126  
  127 + }
  128 + });
61 129 return rsList;
62 130 }
63 131  
... ... @@ -93,6 +161,22 @@ public class GpsOutbound_DTO {
93 161  
94 162 private String abnormalType = "outbound";
95 163  
  164 + private String lineName;
  165 +
  166 + private String startTime;
  167 +
  168 + private String endTime;
  169 +
  170 + DateTimeFormatter fmtHHmmss = DateTimeFormat.forPattern("HH:mm.ss");
  171 +
  172 + public String getLineName() {
  173 + return lineName;
  174 + }
  175 +
  176 + public void setLineName(String lineName) {
  177 + this.lineName = lineName;
  178 + }
  179 +
96 180 public String getDeviceId() {
97 181 return deviceId;
98 182 }
... ... @@ -148,4 +232,20 @@ public class GpsOutbound_DTO {
148 232 public void setSectionName(String sectionName) {
149 233 this.sectionName = sectionName;
150 234 }
  235 +
  236 + public String getStartTime() {
  237 + return fmtHHmmss.print(st);
  238 + }
  239 +
  240 + public void setStartTime(String startTime) {
  241 + this.startTime = startTime;
  242 + }
  243 +
  244 + public String getEndTime() {
  245 + return fmtHHmmss.print(et);
  246 + }
  247 +
  248 + public void setEndTime(String endTime) {
  249 + this.endTime = endTime;
  250 + }
151 251 }
... ...
src/main/java/com/bsth/service/gps/entity/GpsSpeed.java
1   -package com.bsth.service.gps.entity;
2   -
3   -import javax.persistence.Transient;
4   -
5   -/**
6   - * 超速异常 -ms数据库格式
7   - * Created by panzhao on 2017/4/7.
8   - */
9   -public class GpsSpeed {
10   -
11   - private String vehicle;
12   -
13   - private String line;
14   -
15   - private int up_down;
16   -
17   - private float lon;
18   -
19   - private float lat;
20   -
21   - private String lineName;
22   -
23   - /**
24   - * 超速结束时的纬度
25   - */
26   - @Transient
27   - private Float endlat;
28   -
29   - /**
30   - * 超速结束时的经度
31   - */
32   - @Transient
33   - private Float endlon;
34   -
35   - private float speed;
36   -
37   - private long timestamp;
38   -
39   - @Transient
40   - private String timestampDate;
41   -
42   - public String getTimestampDate() {
43   - return timestampDate;
44   - }
45   -
46   - public void setTimestampDate(String timestampDate) {
47   - this.timestampDate = timestampDate;
48   - }
49   -
50   - public Long getEndtimestamp() {
51   - return endtimestamp;
52   - }
53   -
54   - public void setEndtimestamp(Long endtimestamp) {
55   - this.endtimestamp = endtimestamp;
56   - }
57   -
58   - public String getEndtimestampDate() {
59   - return endtimestampDate;
60   - }
61   -
62   - public void setEndtimestampDate(String endtimestampDate) {
63   - this.endtimestampDate = endtimestampDate;
64   - }
65   -
66   - //结束时间,单位:秒/s
67   - @Transient
68   - private Long endtimestamp;
69   -
70   - @Transient
71   - private String endtimestampDate;
72   -
73   - public String getVehicle() {
74   - return vehicle;
75   - }
76   -
77   - public void setVehicle(String vehicle) {
78   - this.vehicle = vehicle;
79   - }
80   -
81   - public String getLine() {
82   - return line;
83   - }
84   -
85   - public void setLine(String line) {
86   - this.line = line;
87   - }
88   -
89   - public int getUp_down() {
90   - return up_down;
91   - }
92   -
93   - public void setUp_down(int up_down) {
94   - this.up_down = up_down;
95   - }
96   -
97   - public float getLon() {
98   - return lon;
99   - }
100   -
101   - public void setLon(float lon) {
102   - this.lon = lon;
103   - }
104   -
105   - public float getLat() {
106   - return lat;
107   - }
108   -
109   - public void setLat(float lat) {
110   - this.lat = lat;
111   - }
112   -
113   - public float getSpeed() {
114   - return speed;
115   - }
116   -
117   - public void setSpeed(float speed) {
118   - this.speed = speed;
119   - }
120   -
121   - public long getTimestamp() {
122   - return timestamp;
123   - }
124   -
125   - public void setTimestamp(long timestamp) {
126   - this.timestamp = timestamp;
127   - }
128   -
129   - public Float getEndlon() {
130   - return endlon;
131   - }
132   -
133   - public void setEndlon(Float endlon) {
134   - this.endlon = endlon;
135   - }
136   -
137   - public Float getEndlat() {
138   - return endlat;
139   - }
140   -
141   - public void setEndlat(Float endlat) {
142   - this.endlat = endlat;
143   - }
144   -
145   - public String getLineName() {
146   - return lineName;
147   - }
148   -
149   - public void setLineName(String lineName) {
150   - this.lineName = lineName;
151   - }
152   -}
  1 +package com.bsth.service.gps.entity;
  2 +
  3 +import javax.persistence.Transient;
  4 +
  5 +/**
  6 + * 超速异常 -ms数据库格式
  7 + * Created by panzhao on 2017/4/7.
  8 + */
  9 +public class GpsSpeed {
  10 +
  11 + private String vehicle;
  12 +
  13 + private String line;
  14 +
  15 + private int up_down;
  16 +
  17 + private float lon;
  18 +
  19 + private float lat;
  20 +
  21 + private String lineName;
  22 +
  23 + /**
  24 + * 超速结束时的纬度
  25 + */
  26 + @Transient
  27 + private Float endlat;
  28 +
  29 + /**
  30 + * 超速结束时的经度
  31 + */
  32 + @Transient
  33 + private Float endlon;
  34 +
  35 + private float speed;
  36 +
  37 + private long timestamp;
  38 +
  39 + @Transient
  40 + private String timestampDate;
  41 +
  42 + private String nbbm;
  43 +
  44 + public String getTimestampDate() {
  45 + return timestampDate;
  46 + }
  47 +
  48 + public void setTimestampDate(String timestampDate) {
  49 + this.timestampDate = timestampDate;
  50 + }
  51 +
  52 + public Long getEndtimestamp() {
  53 + return endtimestamp;
  54 + }
  55 +
  56 + public void setEndtimestamp(Long endtimestamp) {
  57 + this.endtimestamp = endtimestamp;
  58 + }
  59 +
  60 + public String getEndtimestampDate() {
  61 + return endtimestampDate;
  62 + }
  63 +
  64 + public void setEndtimestampDate(String endtimestampDate) {
  65 + this.endtimestampDate = endtimestampDate;
  66 + }
  67 +
  68 + //结束时间,单位:秒/s
  69 + @Transient
  70 + private Long endtimestamp;
  71 +
  72 + @Transient
  73 + private String endtimestampDate;
  74 +
  75 + public String getVehicle() {
  76 + return vehicle;
  77 + }
  78 +
  79 + public void setVehicle(String vehicle) {
  80 + this.vehicle = vehicle;
  81 + }
  82 +
  83 + public String getLine() {
  84 + return line;
  85 + }
  86 +
  87 + public void setLine(String line) {
  88 + this.line = line;
  89 + }
  90 +
  91 + public int getUp_down() {
  92 + return up_down;
  93 + }
  94 +
  95 + public void setUp_down(int up_down) {
  96 + this.up_down = up_down;
  97 + }
  98 +
  99 + public float getLon() {
  100 + return lon;
  101 + }
  102 +
  103 + public void setLon(float lon) {
  104 + this.lon = lon;
  105 + }
  106 +
  107 + public float getLat() {
  108 + return lat;
  109 + }
  110 +
  111 + public void setLat(float lat) {
  112 + this.lat = lat;
  113 + }
  114 +
  115 + public float getSpeed() {
  116 + return speed;
  117 + }
  118 +
  119 + public void setSpeed(float speed) {
  120 + this.speed = speed;
  121 + }
  122 +
  123 + public long getTimestamp() {
  124 + return timestamp;
  125 + }
  126 +
  127 + public void setTimestamp(long timestamp) {
  128 + this.timestamp = timestamp;
  129 + }
  130 +
  131 + public Float getEndlon() {
  132 + return endlon;
  133 + }
  134 +
  135 + public void setEndlon(Float endlon) {
  136 + this.endlon = endlon;
  137 + }
  138 +
  139 + public Float getEndlat() {
  140 + return endlat;
  141 + }
  142 +
  143 + public void setEndlat(Float endlat) {
  144 + this.endlat = endlat;
  145 + }
  146 +
  147 + public String getLineName() {
  148 + return lineName;
  149 + }
  150 +
  151 + public void setLineName(String lineName) {
  152 + this.lineName = lineName;
  153 + }
  154 +
  155 + public String getNbbm() {
  156 + return nbbm;
  157 + }
  158 +
  159 + public void setNbbm(String nbbm) {
  160 + this.nbbm = nbbm;
  161 + }
  162 +}
... ...
src/main/java/com/bsth/service/gps/entity/GpsSpeed_DTO.java
... ... @@ -3,8 +3,11 @@ package com.bsth.service.gps.entity;
3 3 import com.alibaba.fastjson.JSON;
4 4 import com.alibaba.fastjson.JSONObject;
5 5 import com.bsth.data.BasicData;
  6 +import org.joda.time.format.DateTimeFormat;
  7 +import org.joda.time.format.DateTimeFormatter;
6 8  
7 9 import java.util.*;
  10 +import java.util.stream.Collectors;
8 11  
9 12 /**
10 13 * 超速异常 dto
... ... @@ -58,6 +61,69 @@ public class GpsSpeed_DTO {
58 61 return rsList;
59 62 }
60 63  
  64 + public static List<GpsSpeed_DTO> init(List<GpsSpeed> speedList,Map<String,List<DeviceChange>> deviceChangeLogs){
  65 + List<GpsSpeed_DTO> rsList = new ArrayList<>();
  66 + //先按设备分组
  67 + Map<String,List<GpsSpeed>> sm=speedList.stream().collect(Collectors.groupingBy(GpsSpeed::getVehicle));
  68 + sm.forEach((k,speeds)->{
  69 + for (GpsSpeed speed : speeds) {
  70 + List<DeviceChange> dcs=deviceChangeLogs.get(speed.getVehicle());
  71 + if(dcs==null){
  72 + speed.setNbbm(BasicData.deviceId2NbbmMap.get(speed.getVehicle()));
  73 + continue;
  74 + }
  75 + for (DeviceChange dc : dcs) {//确定每个超速的车辆自编号
  76 + if(speed.getTimestamp()>dc.getSt()){
  77 + speed.setNbbm(dc.getNbbm());
  78 + break;
  79 + }
  80 + }
  81 + }
  82 + GpsSpeed gs;
  83 + //排序
  84 + Collections.sort(speeds, new Comparator<GpsSpeed>() {
  85 + @Override
  86 + public int compare(GpsSpeed o1, GpsSpeed o2) {
  87 + return (int) (o1.getTimestamp() - o2.getTimestamp());
  88 + }
  89 + });
  90 +
  91 + int space = 1000 * 20;
  92 + int size = speeds.size();
  93 + GpsSpeed_DTO dto = null;
  94 +
  95 + for(int i = 0; i < size; i++){
  96 + gs = speeds.get(i);
  97 + if(dto == null){
  98 + dto = new GpsSpeed_DTO();
  99 + dto.setLineName(BasicData.lineCode2NameMap.get(gs.getLine()));
  100 + dto.setDeviceId(gs.getVehicle());
  101 + dto.setNbbm(gs.getNbbm());
  102 + dto.setSt(gs.getTimestamp());
  103 + dto.setSpeed(gs.getSpeed());
  104 + }
  105 + //记录最大速度
  106 + if(gs.getSpeed() > dto.getSpeed())
  107 + dto.setSpeed(gs.getSpeed());
  108 +
  109 + //超速结束
  110 + if((i < size - 1 && speeds.get(i + 1).getTimestamp() - gs.getTimestamp() > space)){
  111 + dto.setEt(gs.getTimestamp()+space);
  112 + rsList.add(dto);
  113 + dto = null;
  114 + continue;
  115 + }
  116 + if(i == size - 1){//最后一条数据
  117 + dto.setEt(gs.getTimestamp()+space);
  118 + rsList.add(dto);
  119 + }
  120 +
  121 + }
  122 + });
  123 +
  124 + return rsList;
  125 + }
  126 +
61 127 /**
62 128 * 设备号
63 129 */
... ... @@ -90,6 +156,13 @@ public class GpsSpeed_DTO {
90 156  
91 157 private String abnormalType = "speed";
92 158  
  159 + private String lineName;
  160 +
  161 + private String startTime;
  162 +
  163 + private String endTime;
  164 + DateTimeFormatter fmtHHmmss = DateTimeFormat.forPattern("HH:mm.ss");
  165 +
93 166 public String getDeviceId() {
94 167 return deviceId;
95 168 }
... ... @@ -145,4 +218,28 @@ public class GpsSpeed_DTO {
145 218 public void setSectionName(String sectionName) {
146 219 this.sectionName = sectionName;
147 220 }
  221 +
  222 + public String getLineName() {
  223 + return lineName;
  224 + }
  225 +
  226 + public void setLineName(String lineName) {
  227 + this.lineName = lineName;
  228 + }
  229 +
  230 + public String getStartTime() {
  231 + return fmtHHmmss.print(st);
  232 + }
  233 +
  234 + public void setStartTime(String startTime) {
  235 + this.startTime = startTime;
  236 + }
  237 +
  238 + public String getEndTime() {
  239 + return fmtHHmmss.print(et);
  240 + }
  241 +
  242 + public void setEndTime(String endTime) {
  243 + this.endTime = endTime;
  244 + }
148 245 }
... ...
src/main/resources/static/pages/report/abnormalGPS.html 0 → 100644
  1 +<style type="text/css">
  2 + .table-bordered {
  3 + border: 1px solid; }
  4 + .table-bordered > thead > tr > th,
  5 + .table-bordered > thead > tr > td,
  6 + .table-bordered > tbody > tr > th,
  7 + .table-bordered > tbody > tr > td,
  8 + .table-bordered > tfoot > tr > th,
  9 + .table-bordered > tfoot > tr > td {
  10 + border: 1px solid; }
  11 + .table-bordered > thead > tr > th,
  12 + .table-bordered > thead > tr > td {
  13 + border-bottom-width: 2px; }
  14 +
  15 + .table > tbody + tbody {
  16 + border-top: 1px solid; }
  17 +
  18 + #forms > thead > tr> td >span{
  19 + width: 5px;
  20 + word-wrap: break-word;
  21 + letter-spacing: 20px;
  22 + }
  23 +
  24 + #forms > thead > tr> td >label{
  25 + word-break: keep-all;white-space:nowrap;
  26 + }
  27 +</style>
  28 +
  29 +<div class="page-head">
  30 + <div class="page-title">
  31 + <h1>异常数据报表</h1>
  32 + </div>
  33 +</div>
  34 +
  35 +<!-- <div class="row"> -->
  36 + <div class="col-md-12 portlet light porttlet-fit bordered" style="height:calc(100% - 56px)">
  37 +<!-- <div> -->
  38 + <div class="portlet-title">
  39 + <form class="form-inline" action="">
  40 + <div style="display: inline-block;margin-left: 29px; " id="gsdmDiv">
  41 + <span class="item-label" style="width: 80px;">公司: </span>
  42 + <select class="form-control" name="company" id="gsdm" style="width: 180px;"></select>
  43 + </div>
  44 + <div style="display: inline-block; margin-left: 29px;" id="fgsdmDiv">
  45 + <span class="item-label" style="width: 80px;">分公司: </span>
  46 + <select class="form-control" name="subCompany" id="fgsdm" style="width: 180px;"></select>
  47 + </div>
  48 + <div style="display: inline-block;margin-left: 42px;">
  49 + <span class="item-label" style="width: 80px;">线路: </span>
  50 + <select class="form-control" name="line" id="line" style="width: 180px;"></select>
  51 + </div>
  52 + <div style="display: inline-block; margin-left: 33px;">
  53 + <span class="item-label" style="width: 80px;">异常类型: </span>
  54 + <select class="form-control" name="yclx" id="yclx" style="width: 180px;">
  55 + <option value="0">超速</option>
  56 + <option value="1">越界</option>
  57 + </select>
  58 + </div>
  59 + <div style="margin-top: 3px"></div>
  60 + <div style="display: inline-block;margin-left: 15px;">
  61 + <span class="item-label" style="width: 80px;">开始时间: </span>
  62 + <input class="form-control" type="text" id="date" style="width: 180px;"/>
  63 + </div>
  64 + <div style="display: inline-block;margin-left: 15px;">
  65 + <span class="item-label" style="width: 80px;">结束时间: </span>
  66 + <input class="form-control" type="text" id="date2" style="width: 180px;"/>
  67 + </div>
  68 + <div class="form-group">
  69 + <input class="btn btn-default" type="button" id="query" value="查询"/>
  70 + <input class="btn btn-default" type="button" id="export" value="导出"/>
  71 + </div>
  72 + </form>
  73 + </div>
  74 + <div class="portlet-body" id="tjrbBody" style="overflow:auto;height: calc(100% - 80px)">
  75 + <div class="table-container" style="margin-top: 10px;min-width: 906px">
  76 + <table class="table table-bordered table-hover table-checkable" id="forms">
  77 + <thead>
  78 + <tr>
  79 + <th colspan="46"><label id="tjrq"></label> 异常数据报表</th>
  80 + </tr>
  81 + <tr>
  82 + <td rowspan="3"><label >路线</label></td>
  83 + <td rowspan="3"><label >自编号</label></td>
  84 + <td rowspan="3" id="speed"><label >速度</label></td>
  85 + <td rowspan="3"><label >开始时间</label></td>
  86 + <td rowspan="3"><label >结束时间</label></td>
  87 + </tr>
  88 + </thead>
  89 + <tbody class="abnormalSpeeds">
  90 + </tbody>
  91 + <tbody class="abnormalOutbounds">
  92 + </tbody>
  93 + </table>
  94 + </div>
  95 + </div>
  96 + </div>
  97 +
  98 +<script>
  99 + $(function(){
  100 + $('#export').attr('disabled', "true");
  101 +
  102 + // 关闭左侧栏
  103 + if (!$('body').hasClass('page-sidebar-closed'))
  104 + $('.menu-toggler.sidebar-toggler').click();
  105 +
  106 + var d = new Date();
  107 + d.setTime(d.getTime() - 4*1000*60*60*24);
  108 + var year = d.getFullYear();
  109 + var month = d.getMonth() + 1;
  110 + var day = d.getDate();
  111 + if(month < 10)
  112 + month = "0" + month;
  113 + if(day < 10)
  114 + day = "0" + day;
  115 + var dateTime = year + "-" + month + "-" + day;
  116 + $("#date").datetimepicker({
  117 + format : 'YYYY-MM-DD',
  118 + locale : 'zh-cn',
  119 + maxDate : dateTime
  120 + });
  121 + $("#date2").datetimepicker({
  122 + format : 'YYYY-MM-DD',
  123 + locale : 'zh-cn',
  124 + maxDate : dateTime
  125 + });
  126 + $("#date").val(dateTime);
  127 + $("#date2").val(dateTime);
  128 +
  129 +
  130 + var fage=true;
  131 + var obj = [];
  132 + var xlList;
  133 + $.get('/report/lineList',function(result){
  134 + xlList=result;
  135 + $.get('/user/companyData', function(result){
  136 + obj = result;
  137 + var options = '';
  138 + for(var i = 0; i < obj.length; i++){
  139 + options += '<option value="'+obj[i].companyCode+'">'+obj[i].companyName+'</option>';
  140 + }
  141 +
  142 + if(obj.length ==0){
  143 + $("#gsdmDiv").css('display','none');
  144 + }else if(obj.length ==1){
  145 + $("#gsdmDiv").css('display','none');
  146 + if(obj[0].children.length == 1 || obj[0].children.length ==0){
  147 + fage=false;
  148 + $('#fgsdmDiv').css('display','none');
  149 + }
  150 + }
  151 + $('#gsdm').html(options);
  152 + updateCompany();
  153 + });
  154 + })
  155 + $("#gsdm").on("change",updateCompany);
  156 + function updateCompany(){
  157 + var company = $('#gsdm').val();
  158 + var options = '';
  159 + if(fage){
  160 + options = '<option value="">请选择</option>';
  161 + }
  162 + for(var i = 0; i < obj.length; i++){
  163 + if(obj[i].companyCode == company){
  164 + var children = obj[i].children;
  165 + for(var j = 0; j < children.length; j++){
  166 + options += '<option value="'+children[j].code+'">'+children[j].name+'</option>';
  167 + }
  168 + }
  169 + }
  170 + $('#fgsdm').html(options);
  171 +// initXl();
  172 + }
  173 +
  174 + var tempData = {};
  175 + $.get('/report/lineList',function(xlList){
  176 + var data = [];
  177 + data.push({id: " ", text: "全部线路"});
  178 + $.get('/user/companyData', function(result){
  179 + for(var i = 0; i < result.length; i++){
  180 + var companyCode = result[i].companyCode;
  181 + var children = result[i].children;
  182 + for(var j = 0; j < children.length; j++){
  183 + var code = children[j].code;
  184 + for(var k=0;k < xlList.length;k++ ){
  185 + if(xlList[k]["fgsbm"]==code && xlList[k]["gsbm"]==companyCode){
  186 + data.push({id: xlList[k]["xlbm"], text: xlList[k]["xlname"]});
  187 + tempData[xlList[k]["xlbm"]] = companyCode+":"+code;
  188 + }
  189 + }
  190 + }
  191 + }
  192 + initPinYinSelect2('#line',data,'');
  193 +
  194 + });
  195 + });
  196 +
  197 + $("#line").on("change", function(){
  198 + if($("#line").val() == " "){
  199 + $("#gsdm").attr("disabled", false);
  200 + $("#fgsdm").attr("disabled", false);
  201 + } else {
  202 + var temp = tempData[$("#line").val()].split(":");
  203 + $("#gsdm").val(temp[0]);
  204 + updateCompany();
  205 + $("#fgsdm").val(temp[1]);
  206 + $("#gsdm").attr("disabled", true);
  207 + $("#fgsdm").attr("disabled", true);
  208 + }
  209 + });
  210 +
  211 +
  212 + var line ="";
  213 + var xlName ="";
  214 + var date = "";
  215 + var date2 ="";
  216 + var gsdm="";
  217 + var fgsdm="";
  218 + var yclx="";
  219 + $("#query").on("click",function(){
  220 + if($("#date").val() == null || $("#date").val().trim().length == 0){
  221 + layer.msg("请选择时间范围!");
  222 + return;
  223 + }
  224 + if($("#date2").val() == null || $("#date2").val().trim().length == 0){
  225 + layer.msg("请选择时间范围!");
  226 + return;
  227 + }
  228 + xlName = $("#select2-line-container").html();
  229 + if(xlName == "全部线路"){
  230 + layer.msg("请选择线路!");
  231 + return;
  232 + }
  233 + line = $("#line").val();
  234 + date = $("#date").val();
  235 + date2 =$("#date2").val();
  236 + gsdm =$("#gsdm").val();
  237 + fgsdm=$("#fgsdm").val();
  238 + yclx=$("#yclx").val();
  239 + if(xlName == "全部线路")
  240 + xlName = $('#fgsdm option:selected').text();
  241 + if(xlName =='请选择')
  242 + xlName = $('#gsdm option:selected').text();
  243 + if(line=="请选择"){
  244 + line="";
  245 + }
  246 + if(date==null || date =="" ||date2==null || date2 ==""){
  247 + layer.msg('请选择时间段.');
  248 + }else{
  249 + $("#tjrq").html(date+"至"+date2);
  250 + var params = {};
  251 + params['gsdm'] = gsdm;
  252 + params['fgsdm'] =fgsdm ;
  253 + params['line'] = line;
  254 + params['date'] = date;
  255 + params['date2'] = date2;
  256 + params['xlName'] = xlName;
  257 + var i = layer.load(2);
  258 + if(yclx=='0'){
  259 + $('#forms .abnormalOutbounds').html('');
  260 + $("#speed").show();
  261 + $get('/gps/abnormalSpeeds',params,function(result){
  262 + // 把数据填充到模版中
  263 + var tbodyHtml = template('abnormalSpeeds',{list:result});
  264 + // 把渲染好的模版html文本追加到表格中
  265 + $('#forms .abnormalSpeeds').html(tbodyHtml);
  266 + layer.close(i);
  267 + if(result.length == 0)
  268 + $("#export").attr('disabled',"true");
  269 + else
  270 + $("#export").removeAttr("disabled");
  271 + });
  272 + }else if (yclx==1){
  273 + $("#speed").hide();
  274 + $('#forms .abnormalSpeeds').html('');
  275 + $get('/gps/abnormalOutbounds',params,function(result){
  276 + // 把数据填充到模版中
  277 + var tbodyHtml = template('abnormalOutbounds',{list:result});
  278 + // 把渲染好的模版html文本追加到表格中
  279 + $('#forms .abnormalOutbounds').html(tbodyHtml);
  280 + layer.close(i);
  281 + if(result.length == 0)
  282 + $("#export").attr('disabled',"true");
  283 + else
  284 + $("#export").removeAttr("disabled");
  285 + });
  286 + }
  287 +
  288 + }
  289 +
  290 + });
  291 +
  292 + $("#export").on("click",function(){
  293 + var params = {};
  294 + params['gsdm'] = gsdm;
  295 + params['fgsdm'] =fgsdm ;
  296 + params['line'] = line;
  297 + params['date'] = date;
  298 + params['date2'] = date2;
  299 + params['xlName'] = xlName;
  300 + var i = layer.load(2);
  301 + window.open('/gps/abnormalGPSExcel/' + line + "?dateS=" + date + "&dateE=" + date2);
  302 + layer.close(i);
  303 + });
  304 +
  305 + });
  306 +</script>
  307 +<script type="text/html" id="abnormalSpeeds">
  308 + {{each list as obj i}}
  309 + <tr>
  310 + <td>{{obj.lineName}}</td>
  311 + <td>{{obj.nbbm}}</td>
  312 + <td>{{obj.speed}}</td>
  313 + <td>{{obj.startTime}}</td>
  314 + <td>{{obj.endTime}}</td>
  315 + </tr>
  316 + {{/each}}
  317 + {{if list.length == 0}}
  318 + <tr>
  319 + <td colspan="46"><h6 class="muted">没有找到相关数据</h6></td>
  320 + </tr>
  321 + {{/if}}
  322 +</script>
  323 +
  324 +<script type="text/html" id="abnormalOutbounds">
  325 + {{each list as obj i}}
  326 + <tr>
  327 + <td>{{obj.lineName}}</td>
  328 + <td>{{obj.nbbm}}</td>
  329 + <td>{{obj.startTime}}</td>
  330 + <td>{{obj.endTime}}</td>
  331 + </tr>
  332 + {{/each}}
  333 + {{if list.length == 0}}
  334 + <tr>
  335 + <td colspan="46"><h6 class="muted">没有找到相关数据</h6></td>
  336 + </tr>
  337 + {{/if}}
  338 +</script>
0 339 \ No newline at end of file
... ...